Class: Money
- Inherits:
-
Object
show all
- Extended by:
- Forwardable
- Includes:
- Comparable
- Defined in:
- lib/money/money.rb,
lib/money/config.rb,
lib/money/errors.rb,
lib/money/helpers.rb,
lib/money/railtie.rb,
lib/money/version.rb,
lib/money/currency.rb,
lib/money/splitter.rb,
lib/money/allocator.rb,
lib/money/parser/fuzzy.rb,
lib/money/null_currency.rb,
lib/money/parser/simple.rb,
lib/money/currency/loader.rb,
lib/money/parser/accounting.rb,
lib/money/parser/locale_aware.rb,
lib/money/rails/job_argument_serializer.rb
Defined Under Namespace
Modules: Helpers, Parser, Rails
Classes: Allocator, Config, Currency, Error, IncompatibleCurrencyError, NullCurrency, Railtie, ReverseOperationProxy, Splitter
Constant Summary
collapse
- NULL_CURRENCY =
NullCurrency.new.freeze
- VERSION =
"2.2.0"
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.
122
123
124
125
126
127
|
# File 'lib/money/money.rb', line 122
def initialize(value, currency)
raise ArgumentError if value.nan?
@currency = Helpers.value_to_currency(currency)
@value = BigDecimal(value.round(@currency.minor_units))
freeze
end
|
Class Attribute Details
.config ⇒ Object
Returns the value of attribute config.
39
40
41
|
# File 'lib/money/money.rb', line 39
def config
@config
end
|
Instance Attribute Details
#currency ⇒ Object
Returns the value of attribute currency.
10
11
12
|
# File 'lib/money/money.rb', line 10
def currency
@currency
end
|
#value ⇒ Object
Returns the value of attribute value.
10
11
12
|
# File 'lib/money/money.rb', line 10
def value
@value
end
|
Class Method Details
42
43
44
45
|
# File 'lib/money/money.rb', line 42
def configure
self.config ||= Config.new
yield(config) if block_given?
end
|
.current_currency ⇒ Object
84
85
86
|
# File 'lib/money/money.rb', line 84
def current_currency
Thread.current[:money_currency]
end
|
.current_currency=(currency) ⇒ Object
88
89
90
|
# File 'lib/money/money.rb', line 88
def current_currency=(currency)
Thread.current[:money_currency] = currency
end
|
.from_subunits(subunits, currency_iso, format: :iso4217) ⇒ Object
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
# File 'lib/money/money.rb', line 62
def from_subunits(subunits, currency_iso, format: :iso4217)
currency = Helpers.value_to_currency(currency_iso)
subunit_to_unit_value = if format == :iso4217
currency.subunit_to_unit
elsif format == :stripe
Helpers::STRIPE_SUBUNIT_OVERRIDE.fetch(currency.iso_code, currency.subunit_to_unit)
else
raise ArgumentError, "unknown format #{format}"
end
value = Helpers.value_to_decimal(subunits) / subunit_to_unit_value
new(value, currency)
end
|
.new(value = 0, currency = nil) ⇒ Object
Also known as:
from_amount
47
48
49
50
51
52
53
54
55
56
57
58
59
|
# File 'lib/money/money.rb', line 47
def new(value = 0, currency = nil)
return new_from_money(value, currency) if value.is_a?(Money)
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
|
.rational(money1, money2) ⇒ Object
77
78
79
80
81
82
|
# File 'lib/money/money.rb', line 77
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.
Instance Method Details
#*(numeric) ⇒ Object
179
180
181
182
183
184
|
# File 'lib/money/money.rb', line 179
def *(numeric)
raise ArgumentError, "Money objects can only be multiplied by a Numeric" unless numeric.is_a?(Numeric)
return self if numeric == 1
Money.new(value.to_r * numeric, currency)
end
|
#+(other) ⇒ Object
165
166
167
168
169
170
|
# File 'lib/money/money.rb', line 165
def +(other)
arithmetic(other) do |money|
return self if money.value.zero? && !no_currency?
Money.new(value + money.value, calculated_currency(money.currency))
end
end
|
#-(other) ⇒ Object
172
173
174
175
176
177
|
# File 'lib/money/money.rb', line 172
def -(other)
arithmetic(other) do |money|
return self if money.value.zero? && !no_currency?
Money.new(value - money.value, calculated_currency(money.currency))
end
end
|
#-@ ⇒ Object
154
155
156
|
# File 'lib/money/money.rb', line 154
def -@
Money.new(-value, currency)
end
|
#/(numeric) ⇒ Object
186
187
188
|
# File 'lib/money/money.rb', line 186
def /(numeric)
raise "[Money] Dividing money objects can lose pennies. Use #split instead"
end
|
#<=>(other) ⇒ Object
158
159
160
161
162
163
|
# File 'lib/money/money.rb', line 158
def <=>(other)
return unless other.respond_to?(:to_money)
arithmetic(other) do |money|
value <=> money.value
end
end
|
#==(other) ⇒ Object
194
195
196
|
# File 'lib/money/money.rb', line 194
def ==(other)
eql?(other)
end
|
#abs ⇒ Object
276
277
278
279
280
|
# File 'lib/money/money.rb', line 276
def abs
abs = value.abs
return self if value == abs
Money.new(abs, currency)
end
|
#allocate(splits, strategy = :roundrobin) ⇒ Object
302
303
304
|
# File 'lib/money/money.rb', line 302
def allocate(splits, strategy = :roundrobin)
Money::Allocator.new(self).allocate(splits, strategy)
end
|
#allocate_max_amounts(maximums) ⇒ Object
307
308
309
|
# File 'lib/money/money.rb', line 307
def allocate_max_amounts(maximums)
Money::Allocator.new(self).allocate_max_amounts(maximums)
end
|
#as_json(options = nil) ⇒ Object
268
269
270
271
272
273
274
|
# File 'lib/money/money.rb', line 268
def as_json(options = nil)
if (options.is_a?(Hash) && options.delete(:legacy_format)) || Money.config.legacy_json_format
to_s
else
{ value: to_s(:amount), currency: currency.to_s }
end
end
|
#calculate_splits(num) ⇒ Hash<Money, Integer>
Calculate the splits evenly without losing pennies. Returns the number of high and low splits and the value of the high and low splits. Where high represents the Money value with the extra penny and low a Money without the extra penny.
334
335
336
|
# File 'lib/money/money.rb', line 334
def calculate_splits(num)
Splitter.new(self, num).split.dup
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.
346
347
348
349
350
351
352
353
354
355
356
357
|
# File 'lib/money/money.rb', line 346
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
205
206
207
208
|
# File 'lib/money/money.rb', line 205
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
133
134
135
136
|
# File 'lib/money/money.rb', line 133
def encode_with(coder)
coder['value'] = @value.to_s('F')
coder['currency'] = @currency.iso_code
end
|
#eql?(other) ⇒ Boolean
TODO: Remove once cross-currency mathematical operations are no longer allowed
199
200
201
202
203
|
# File 'lib/money/money.rb', line 199
def eql?(other)
return false unless other.is_a?(Money)
return false unless currency.compatible?(other.currency)
value == other.value
end
|
#floor ⇒ Object
282
283
284
285
286
|
# File 'lib/money/money.rb', line 282
def floor
floor = value.floor
return self if floor == value
Money.new(floor, currency)
end
|
#fraction(rate) ⇒ Object
294
295
296
297
298
299
|
# File 'lib/money/money.rb', line 294
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
129
130
131
|
# File 'lib/money/money.rb', line 129
def init_with(coder)
initialize(Helpers.value_to_decimal(coder['value']), coder['currency'])
end
|
#inspect ⇒ Object
190
191
192
|
# File 'lib/money/money.rb', line 190
def inspect
"#<#{self.class} value:#{self} currency:#{self.currency}>"
end
|
#no_currency? ⇒ Boolean
150
151
152
|
# File 'lib/money/money.rb', line 150
def no_currency?
currency.is_a?(NullCurrency)
end
|
#round(ndigits = 0) ⇒ Object
288
289
290
291
292
|
# File 'lib/money/money.rb', line 288
def round(ndigits=0)
round = value.round(ndigits)
return self if round == value
Money.new(round, currency)
end
|
Split money amongst parties evenly without losing pennies.
319
320
321
|
# File 'lib/money/money.rb', line 319
def split(num)
Splitter.new(self, num)
end
|
#subunits(format: :iso4217) ⇒ Object
138
139
140
141
142
143
144
145
146
147
148
|
# File 'lib/money/money.rb', line 138
def subunits(format: :iso4217)
subunit_to_unit_value = if format == :iso4217
@currency.subunit_to_unit
elsif format == :stripe
Helpers::STRIPE_SUBUNIT_OVERRIDE.fetch(@currency.iso_code, @currency.subunit_to_unit)
else
raise ArgumentError, "unknown format #{format}"
end
(@value * subunit_to_unit_value).to_i
end
|
#to_d ⇒ Object
231
232
233
|
# File 'lib/money/money.rb', line 231
def to_d
value
end
|
#to_fs(style = nil) ⇒ Object
Also known as:
to_s, to_formatted_s
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
|
# File 'lib/money/money.rb', line 235
def to_fs(style = nil)
units = case style
when :legacy_dollars
2
when :amount, nil
currency.minor_units
else
raise ArgumentError, "Unexpected format: #{style}"
end
rounded_value = value.round(units)
if units == 0
sprintf("%d", rounded_value)
else
formatted = rounded_value.to_s("F")
decimal_digits = formatted.size - formatted.index(".") - 1
(units - decimal_digits).times do
formatted << '0'
end
formatted
end
end
|
#to_json(options = nil) ⇒ Object
260
261
262
263
264
265
266
|
# File 'lib/money/money.rb', line 260
def to_json(options = nil)
if (options.is_a?(Hash) && options.delete(:legacy_format)) || Money.config.legacy_json_format
to_s
else
as_json(options).to_json
end
end
|
#to_money(new_currency = nil) ⇒ Object
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
|
# File 'lib/money/money.rb', line 210
def to_money(new_currency = nil)
if new_currency.nil?
return self
end
if no_currency?
return Money.new(value, new_currency)
end
unless currency.compatible?(Helpers.value_to_currency(new_currency))
msg = "to_money is attempting to change currency of an existing money object from #{currency} to #{new_currency}"
if Money.config.legacy_deprecations
Money.deprecate("#{msg}. A Money::IncompatibleCurrencyError will raise in the next major release")
else
raise Money::IncompatibleCurrencyError, msg
end
end
self
end
|