Class: Money
- Inherits:
-
Object
show all
- Extended by:
- Forwardable
- Includes:
- Comparable
- Defined in:
- lib/money/money.rb,
lib/money/helpers.rb,
lib/money/version.rb,
lib/money/currency.rb,
lib/money/null_currency.rb,
lib/money/currency/loader.rb
Defined Under Namespace
Modules: Helpers
Classes: Currency, NullCurrency, ReverseOperationProxy
Constant Summary
collapse
- NULL_CURRENCY =
NullCurrency.new.freeze
- VERSION =
"0.11.3"
Class Attribute Summary collapse
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
Constructor Details
#initialize(value, currency) ⇒ Money
Returns a new instance of Money.
81
82
83
84
85
86
|
# File 'lib/money/money.rb', line 81
def initialize(value, currency)
raise ArgumentError if value.nan?
@currency = Helpers.value_to_currency(currency)
@value = value.round(@currency.minor_units)
freeze
end
|
Class Attribute Details
.default_currency ⇒ Object
Returns the value of attribute default_currency.
11
12
13
|
# File 'lib/money/money.rb', line 11
def default_currency
@default_currency
end
|
.parser ⇒ Object
Returns the value of attribute parser.
11
12
13
|
# File 'lib/money/money.rb', line 11
def parser
@parser
end
|
Instance Attribute Details
#currency ⇒ Object
Returns the value of attribute currency.
7
8
9
|
# File 'lib/money/money.rb', line 7
def currency
@currency
end
|
#value ⇒ Object
Returns the value of attribute value.
7
8
9
|
# File 'lib/money/money.rb', line 7
def value
@value
end
|
Class Method Details
.current_currency ⇒ Object
52
53
54
|
# File 'lib/money/money.rb', line 52
def current_currency
Thread.current[:money_currency]
end
|
.current_currency=(currency) ⇒ Object
56
57
58
|
# File 'lib/money/money.rb', line 56
def current_currency=(currency)
Thread.current[:money_currency] = currency
end
|
.default_settings ⇒ Object
.from_cents(cents, currency = nil) ⇒ Object
35
36
37
|
# File 'lib/money/money.rb', line 35
def from_cents(cents, currency = nil)
new(cents.round.to_f / 100, currency)
end
|
.from_subunits(subunits, currency_iso) ⇒ Object
39
40
41
42
43
|
# File 'lib/money/money.rb', line 39
def from_subunits(subunits, currency_iso)
currency = Helpers.value_to_currency(currency_iso)
value = Helpers.value_to_decimal(subunits) / currency.subunit_to_unit
new(value, currency)
end
|
.new(value = 0, currency = nil) ⇒ Object
Also known as:
from_amount
13
14
15
16
17
18
19
20
21
22
23
|
# File 'lib/money/money.rb', line 13
def new(value = 0, currency = nil)
value = Helpers.value_to_decimal(value)
currency = Helpers.value_to_currency(currency)
if value.zero?
@@zero_money ||= {}
@@zero_money[currency.iso_code] ||= super(Helpers::DECIMAL_ZERO, currency)
else
super(value, currency)
end
end
|
.parse(*args) ⇒ Object
31
32
33
|
# File 'lib/money/money.rb', line 31
def parse(*args)
parser.parse(*args)
end
|
.rational(money1, money2) ⇒ Object
45
46
47
48
49
50
|
# File 'lib/money/money.rb', line 45
def rational(money1, money2)
money1.send(:arithmetic, money2) do
factor = money1.currency.subunit_to_unit * money2.currency.subunit_to_unit
Rational((money1.value * factor).to_i, (money2.value * factor).to_i)
end
end
|
.with_currency(new_currency) ⇒ Object
Set Money.default_currency inside the supplied block, resets it to the previous value when done to prevent leaking state. Similar to I18n.with_locale and ActiveSupport’s Time.use_zone. This won’t affect instances being created with explicitly set currency.
.zero(currency = NULL_CURRENCY) ⇒ Object
Also known as:
empty
26
27
28
|
# File 'lib/money/money.rb', line 26
def zero(currency = NULL_CURRENCY)
new(0, currency)
end
|
Instance Method Details
#*(numeric) ⇒ Object
132
133
134
135
136
137
|
# File 'lib/money/money.rb', line 132
def *(numeric)
unless numeric.is_a?(Numeric)
Money.deprecate("Multiplying Money with #{numeric.class.name} is deprecated and will be removed in the next major release.")
end
Money.new(value.to_r * numeric, currency)
end
|
#+(other) ⇒ Object
120
121
122
123
124
|
# File 'lib/money/money.rb', line 120
def +(other)
arithmetic(other) do |money|
Money.new(value + money.value, calculated_currency(money.currency))
end
end
|
#-(other) ⇒ Object
126
127
128
129
130
|
# File 'lib/money/money.rb', line 126
def -(other)
arithmetic(other) do |money|
Money.new(value - money.value, calculated_currency(money.currency))
end
end
|
#-@ ⇒ Object
110
111
112
|
# File 'lib/money/money.rb', line 110
def -@
Money.new(-value, currency)
end
|
#/(numeric) ⇒ Object
139
140
141
|
# File 'lib/money/money.rb', line 139
def /(numeric)
raise "[Money] Dividing money objects can lose pennies. Use #split instead"
end
|
#<=>(other) ⇒ Object
114
115
116
117
118
|
# File 'lib/money/money.rb', line 114
def <=>(other)
arithmetic(other) do |money|
value <=> money.value
end
end
|
#==(other) ⇒ Object
147
148
149
|
# File 'lib/money/money.rb', line 147
def ==(other)
eql?(other)
end
|
#abs ⇒ Object
224
225
226
|
# File 'lib/money/money.rb', line 224
def abs
Money.new(value.abs, currency)
end
|
#allocate(splits) ⇒ Object
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
|
# File 'lib/money/money.rb', line 266
def allocate(splits)
if all_rational?(splits)
allocations = splits.inject(0) { |sum, n| sum + n }
else
allocations = splits.inject(0) { |sum, n| sum + Helpers.value_to_decimal(n) }
end
if (allocations - BigDecimal("1")) > Float::EPSILON
raise ArgumentError, "splits add to more than 100%"
end
amounts, left_over = amounts_from_splits(allocations, splits)
left_over.to_i.times { |i| amounts[i % amounts.length] += 1 }
amounts.collect { |subunits| Money.from_subunits(subunits, currency) }
end
|
#allocate_max_amounts(maximums) ⇒ Object
Allocates money between different parties up to the maximum amounts specified. Left over pennies will be assigned round-robin up to the maximum specified. Pennies are dropped when the maximums are attained.
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
|
# File 'lib/money/money.rb', line 303
def allocate_max_amounts(maximums)
allocation_currency = (maximums + [self])
maximums = maximums.map { |max| max.to_money(allocation_currency) }
maximums_total = maximums.reduce(Money.new(0, allocation_currency), :+)
splits = maximums.map do |max_amount|
next(0) if maximums_total.zero?
Money.rational(max_amount, maximums_total)
end
total_allocatable = [
value * allocation_currency.subunit_to_unit,
maximums_total.value * allocation_currency.subunit_to_unit
].min
subunits_amounts, left_over = amounts_from_splits(1, splits, total_allocatable)
subunits_amounts.each_with_index do |amount, index|
break unless left_over > 0
max_amount = maximums[index].value * allocation_currency.subunit_to_unit
next unless amount < max_amount
left_over -= 1
subunits_amounts[index] += 1
end
subunits_amounts.map { |cents| Money.from_subunits(cents, allocation_currency) }
end
|
#as_json(*args) ⇒ Object
220
221
222
|
# File 'lib/money/money.rb', line 220
def as_json(*args)
to_s
end
|
#cents ⇒ Object
97
98
99
100
|
# File 'lib/money/money.rb', line 97
def cents
(value * 100).to_i
end
|
#clamp(min, max) ⇒ Object
Clamps the value to be within the specified minimum and maximum. Returns self if the value is within bounds, otherwise a new Money object with the closest min or max value.
365
366
367
368
369
370
371
372
373
374
375
376
|
# File 'lib/money/money.rb', line 365
def clamp(min, max)
raise ArgumentError, 'min cannot be greater than max' if min > max
clamped_value = min if self.value < min
clamped_value = max if self.value > max
if clamped_value.nil?
self
else
Money.new(clamped_value, self.currency)
end
end
|
#coerce(other) ⇒ Object
181
182
183
184
|
# File 'lib/money/money.rb', line 181
def coerce(other)
raise TypeError, "Money can't be coerced into #{other.class}" unless other.is_a?(Numeric)
[ReverseOperationProxy.new(other), self]
end
|
#encode_with(coder) ⇒ Object
92
93
94
95
|
# File 'lib/money/money.rb', line 92
def encode_with(coder)
coder['value'] = @value.to_s('F')
coder['currency'] = @currency.iso_code
end
|
#eql?(other) ⇒ Boolean
151
152
153
154
155
|
# File 'lib/money/money.rb', line 151
def eql?(other)
return false unless other.is_a?(Money)
return false unless currency.compatible?(other.currency)
value == other.value
end
|
#floor ⇒ Object
228
229
230
|
# File 'lib/money/money.rb', line 228
def floor
Money.new(value.floor, currency)
end
|
#fraction(rate) ⇒ Object
236
237
238
239
240
241
|
# File 'lib/money/money.rb', line 236
def fraction(rate)
raise ArgumentError, "rate should be positive" if rate < 0
result = value / (1 + rate)
Money.new(result, currency)
end
|
#init_with(coder) ⇒ Object
88
89
90
|
# File 'lib/money/money.rb', line 88
def init_with(coder)
initialize(Helpers.value_to_decimal(coder['value']), coder['currency'])
end
|
#inspect ⇒ Object
143
144
145
|
# File 'lib/money/money.rb', line 143
def inspect
"#<#{self.class} value:#{self} currency:#{self.currency}>"
end
|
#no_currency? ⇒ Boolean
106
107
108
|
# File 'lib/money/money.rb', line 106
def no_currency?
currency.is_a?(NullCurrency)
end
|
#round(ndigits = 0) ⇒ Object
232
233
234
|
# File 'lib/money/money.rb', line 232
def round(ndigits=0)
Money.new(value.round(ndigits), currency)
end
|
Split money amongst parties evenly without losing pennies.
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
|
# File 'lib/money/money.rb', line 341
def split(num)
raise ArgumentError, "need at least one party" if num < 1
subunits = self.subunits
low = Money.from_subunits(subunits / num, currency)
high = Money.from_subunits(low.subunits + 1, currency)
remainder = subunits % num
result = []
num.times do |index|
result[index] = index < remainder ? high : low
end
return result
end
|
#subunits ⇒ Object
102
103
104
|
# File 'lib/money/money.rb', line 102
def subunits
(@value * @currency.subunit_to_unit).to_i
end
|
#to_d ⇒ Object
199
200
201
|
# File 'lib/money/money.rb', line 199
def to_d
value
end
|
#to_json(options = {}) ⇒ Object
216
217
218
|
# File 'lib/money/money.rb', line 216
def to_json(options = {})
to_s
end
|
#to_liquid ⇒ Object
212
213
214
|
# File 'lib/money/money.rb', line 212
def to_liquid
cents
end
|
#to_money(curr = nil) ⇒ Object
186
187
188
189
190
191
192
193
194
195
196
197
|
# File 'lib/money/money.rb', line 186
def to_money(curr = nil)
if !curr.nil? && no_currency?
return Money.new(value, curr)
end
curr = Helpers.value_to_currency(curr)
unless currency.compatible?(curr)
Money.deprecate("mathematical operation not permitted for Money objects with different currencies #{curr} and #{currency}.")
end
self
end
|
#to_s(style = nil) ⇒ Object
203
204
205
206
207
208
209
210
|
# File 'lib/money/money.rb', line 203
def to_s(style = nil)
case style
when :legacy_dollars
sprintf("%.2f", value)
when :amount, nil
sprintf("%.#{currency.minor_units}f", value)
end
end
|