money 7.0.2 → 7.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +1 -0
- data/config/currency_iso.json +4 -4
- data/lib/money/bank/base.rb +3 -7
- data/lib/money/bank/single_currency.rb +2 -3
- data/lib/money/bank/variable_exchange.rb +34 -37
- data/lib/money/currency/heuristics.rb +1 -1
- data/lib/money/currency/loader.rb +1 -1
- data/lib/money/currency.rb +53 -32
- data/lib/money/locale_backend/base.rb +1 -1
- data/lib/money/locale_backend/currency.rb +1 -1
- data/lib/money/locale_backend/i18n.rb +6 -4
- data/lib/money/money/allocation.rb +10 -9
- data/lib/money/money/arithmetic.rb +34 -25
- data/lib/money/money/constructors.rb +5 -6
- data/lib/money/money/formatter.rb +25 -20
- data/lib/money/money/formatting_rules.rb +4 -2
- data/lib/money/money/locale_backend.rb +4 -4
- data/lib/money/money.rb +25 -30
- data/lib/money/rates_store/memory.rb +5 -8
- data/lib/money/version.rb +1 -1
- data/money.gemspec +7 -7
- data/sig/lib/money/bank/base.rbs +117 -0
- data/sig/lib/money/bank/single_currency.rbs +15 -0
- data/sig/lib/money/bank/variable_exchange.rbs +198 -0
- data/sig/lib/money/currency/heuristics.rbs +8 -0
- data/sig/lib/money/currency.rbs +322 -0
- data/sig/lib/money/locale_backend/base.rbs +6 -0
- data/sig/lib/money/locale_backend/errors.rbs +9 -0
- data/sig/lib/money/locale_backend/i18n.rbs +11 -0
- data/sig/lib/money/money/allocation.rbs +24 -0
- data/sig/lib/money/money/arithmetic.rbs +225 -0
- data/sig/lib/money/money/constructors.rbs +73 -0
- data/sig/lib/money/money/formatter.rbs +214 -0
- data/sig/lib/money/money/formatting_rules.rbs +32 -0
- data/sig/lib/money/money/locale_backend.rbs +7 -0
- data/sig/lib/money/money.rbs +522 -0
- data/sig/lib/money/rates_store/memory.rbs +90 -0
- data/sig/manifest.yaml +10 -0
- metadata +20 -6
|
@@ -37,17 +37,17 @@ class Money
|
|
|
37
37
|
# Money.new(1_00).eql?("1.00") #=> false
|
|
38
38
|
#
|
|
39
39
|
# @see Money.strict_eql_compare
|
|
40
|
-
def eql?(
|
|
41
|
-
if
|
|
42
|
-
if !Money.strict_eql_compare && fractional == 0 &&
|
|
40
|
+
def eql?(other)
|
|
41
|
+
if other.is_a?(Money)
|
|
42
|
+
if !Money.strict_eql_compare && fractional == 0 && other.fractional == 0
|
|
43
43
|
warn "[DEPRECATION] Comparing 0 #{currency} with 0 " \
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
"#{other.currency} using `#eql?` will return false in " \
|
|
45
|
+
"future versions of Money. Opt-in to the new behavior by " \
|
|
46
|
+
"setting `Money.strict_eql_compare = true`."
|
|
47
47
|
return true
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
fractional ==
|
|
50
|
+
fractional == other.fractional && currency == other.currency
|
|
51
51
|
else
|
|
52
52
|
false
|
|
53
53
|
end
|
|
@@ -65,6 +65,7 @@ class Money
|
|
|
65
65
|
def <=>(other)
|
|
66
66
|
unless other.is_a?(Money)
|
|
67
67
|
return unless other.respond_to?(:zero?) && other.zero?
|
|
68
|
+
|
|
68
69
|
return other.is_a?(CoercedNumeric) ? 0 <=> fractional : fractional <=> 0
|
|
69
70
|
end
|
|
70
71
|
|
|
@@ -76,14 +77,16 @@ class Money
|
|
|
76
77
|
other = other.exchange_to(currency)
|
|
77
78
|
fractional <=> other.fractional
|
|
78
79
|
rescue Money::Bank::UnknownRate
|
|
80
|
+
nil
|
|
79
81
|
end
|
|
80
82
|
|
|
81
83
|
# Uses Comparable's implementation but raises ArgumentError if non-zero
|
|
82
84
|
# numeric value is given.
|
|
83
85
|
def ==(other)
|
|
84
86
|
if other.is_a?(Numeric) && !other.zero?
|
|
85
|
-
raise ArgumentError,
|
|
87
|
+
raise ArgumentError, "Money#== supports only zero numerics"
|
|
86
88
|
end
|
|
89
|
+
|
|
87
90
|
super
|
|
88
91
|
end
|
|
89
92
|
|
|
@@ -148,9 +151,11 @@ class Money
|
|
|
148
151
|
dup_with(fractional: new_fractional)
|
|
149
152
|
when CoercedNumeric
|
|
150
153
|
raise TypeError, non_zero_message.call(other.value) unless other.zero?
|
|
154
|
+
|
|
151
155
|
dup_with(fractional: other.value.public_send(op, fractional))
|
|
152
156
|
when Numeric
|
|
153
157
|
raise TypeError, non_zero_message.call(other) unless other.zero?
|
|
158
|
+
|
|
154
159
|
self
|
|
155
160
|
else
|
|
156
161
|
raise TypeError, "Unsupported argument type: #{other.class.name}"
|
|
@@ -172,12 +177,12 @@ class Money
|
|
|
172
177
|
# @example
|
|
173
178
|
# Money.new(100) * 2 #=> #<Money @fractional=200>
|
|
174
179
|
#
|
|
175
|
-
def *(
|
|
176
|
-
|
|
177
|
-
if
|
|
178
|
-
dup_with(fractional: fractional *
|
|
180
|
+
def *(other)
|
|
181
|
+
other = other.value if other.is_a?(CoercedNumeric)
|
|
182
|
+
if other.is_a? Numeric
|
|
183
|
+
dup_with(fractional: fractional * other)
|
|
179
184
|
else
|
|
180
|
-
raise TypeError, "Can't multiply a #{self.class.name} by a #{
|
|
185
|
+
raise TypeError, "Can't multiply a #{self.class.name} by a #{other.class.name}'s value"
|
|
181
186
|
end
|
|
182
187
|
end
|
|
183
188
|
|
|
@@ -196,17 +201,19 @@ class Money
|
|
|
196
201
|
# Money.new(100) / 10 #=> #<Money @fractional=10>
|
|
197
202
|
# Money.new(100) / Money.new(10) #=> 10.0
|
|
198
203
|
#
|
|
199
|
-
def /(
|
|
200
|
-
if
|
|
201
|
-
exchanged =
|
|
204
|
+
def /(other)
|
|
205
|
+
if other.is_a?(self.class)
|
|
206
|
+
exchanged = other.exchange_to(currency)
|
|
202
207
|
raise ZeroDivisionError, "divided by Money(0)" if exchanged.zero?
|
|
208
|
+
|
|
203
209
|
fractional / as_d(exchanged.fractional).to_f
|
|
204
210
|
else
|
|
205
|
-
raise TypeError,
|
|
211
|
+
raise TypeError, "Can not divide by Money" if other.is_a?(CoercedNumeric)
|
|
212
|
+
|
|
213
|
+
other = as_d(other)
|
|
214
|
+
raise ZeroDivisionError, "divided by zero" if other.zero?
|
|
206
215
|
|
|
207
|
-
|
|
208
|
-
raise ZeroDivisionError, "divided by zero" if value.zero?
|
|
209
|
-
dup_with(fractional: fractional / value)
|
|
216
|
+
dup_with(fractional: fractional / other)
|
|
210
217
|
end
|
|
211
218
|
end
|
|
212
219
|
|
|
@@ -244,6 +251,7 @@ class Money
|
|
|
244
251
|
def divmod_money(val)
|
|
245
252
|
cents = val.exchange_to(currency).cents
|
|
246
253
|
raise ZeroDivisionError, "divided by Money(0)" if cents == 0
|
|
254
|
+
|
|
247
255
|
quotient, remainder = fractional.divmod(cents)
|
|
248
256
|
[quotient, dup_with(fractional: remainder)]
|
|
249
257
|
end
|
|
@@ -252,6 +260,7 @@ class Money
|
|
|
252
260
|
def divmod_other(val)
|
|
253
261
|
val = as_d(val)
|
|
254
262
|
raise ZeroDivisionError, "divided by zero" if val.zero?
|
|
263
|
+
|
|
255
264
|
quotient, remainder = fractional.divmod(val)
|
|
256
265
|
[dup_with(fractional: quotient), dup_with(fractional: remainder)]
|
|
257
266
|
end
|
|
@@ -277,8 +286,8 @@ class Money
|
|
|
277
286
|
# @return [Money]
|
|
278
287
|
#
|
|
279
288
|
# @see #modulo
|
|
280
|
-
def %(
|
|
281
|
-
modulo(
|
|
289
|
+
def %(other)
|
|
290
|
+
modulo(other)
|
|
282
291
|
end
|
|
283
292
|
|
|
284
293
|
# If different signs +self.modulo(val) - val+ otherwise +self.modulo(val)+
|
|
@@ -295,9 +304,9 @@ class Money
|
|
|
295
304
|
end
|
|
296
305
|
|
|
297
306
|
if (fractional < 0 && val < 0) || (fractional > 0 && val > 0)
|
|
298
|
-
|
|
307
|
+
modulo(val)
|
|
299
308
|
else
|
|
300
|
-
|
|
309
|
+
modulo(val) - (val.is_a?(Money) ? val : dup_with(fractional: val))
|
|
301
310
|
end
|
|
302
311
|
end
|
|
303
312
|
|
|
@@ -331,7 +340,7 @@ class Money
|
|
|
331
340
|
# Money.new(100).nonzero? #=> #<Money @fractional=100>
|
|
332
341
|
# Money.new(0).nonzero? #=> nil
|
|
333
342
|
def nonzero?
|
|
334
|
-
fractional
|
|
343
|
+
fractional == 0 ? nil : self
|
|
335
344
|
end
|
|
336
345
|
|
|
337
346
|
# Used to make Money instance handle the operations when arguments order is reversed
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
class Money
|
|
4
4
|
module Constructors
|
|
5
|
-
|
|
6
5
|
# Create a new money object with value 0.
|
|
7
6
|
#
|
|
8
7
|
# @param [Currency, String, Symbol] currency The currency to use.
|
|
@@ -14,8 +13,8 @@ class Money
|
|
|
14
13
|
def empty(currency = default_currency)
|
|
15
14
|
new(0, currency)
|
|
16
15
|
end
|
|
17
|
-
alias_method :zero, :empty
|
|
18
16
|
|
|
17
|
+
alias zero empty
|
|
19
18
|
|
|
20
19
|
# Creates a new Money object of the given value, using the Canadian
|
|
21
20
|
# dollar currency.
|
|
@@ -31,8 +30,8 @@ class Money
|
|
|
31
30
|
def ca_dollar(cents)
|
|
32
31
|
new(cents, "CAD")
|
|
33
32
|
end
|
|
34
|
-
alias_method :cad, :ca_dollar
|
|
35
33
|
|
|
34
|
+
alias cad ca_dollar
|
|
36
35
|
|
|
37
36
|
# Creates a new Money object of the given value, using the American dollar
|
|
38
37
|
# currency.
|
|
@@ -48,8 +47,8 @@ class Money
|
|
|
48
47
|
def us_dollar(cents)
|
|
49
48
|
new(cents, "USD")
|
|
50
49
|
end
|
|
51
|
-
alias_method :usd, :us_dollar
|
|
52
50
|
|
|
51
|
+
alias usd us_dollar
|
|
53
52
|
|
|
54
53
|
# Creates a new Money object of the given value, using the Euro currency.
|
|
55
54
|
#
|
|
@@ -64,8 +63,8 @@ class Money
|
|
|
64
63
|
def euro(cents)
|
|
65
64
|
new(cents, "EUR")
|
|
66
65
|
end
|
|
67
|
-
alias_method :eur, :euro
|
|
68
66
|
|
|
67
|
+
alias eur euro
|
|
69
68
|
|
|
70
69
|
# Creates a new Money object of the given value, in British pounds.
|
|
71
70
|
#
|
|
@@ -80,7 +79,7 @@ class Money
|
|
|
80
79
|
def pound_sterling(pence)
|
|
81
80
|
new(pence, "GBP")
|
|
82
81
|
end
|
|
83
|
-
alias_method :gbp, :pound_sterling
|
|
84
82
|
|
|
83
|
+
alias gbp pound_sterling
|
|
85
84
|
end
|
|
86
85
|
end
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "money/money/formatting_rules"
|
|
4
4
|
|
|
5
5
|
class Money
|
|
6
6
|
class Formatter
|
|
7
7
|
DEFAULTS = {
|
|
8
|
-
thousands_separator:
|
|
9
|
-
decimal_mark:
|
|
8
|
+
thousands_separator: "",
|
|
9
|
+
decimal_mark: ".",
|
|
10
10
|
}.freeze
|
|
11
11
|
|
|
12
12
|
# Creates a formatted price string according to several rules.
|
|
@@ -117,7 +117,11 @@ class Money
|
|
|
117
117
|
#
|
|
118
118
|
# @example
|
|
119
119
|
# Money.ca_dollar(570).format(html_wrap: true, with_currency: true)
|
|
120
|
-
# #=> "<span class=\"money-currency-symbol\">$</span
|
|
120
|
+
# #=> "<span class=\"money-currency-symbol\">$</span>" \
|
|
121
|
+
# "<span class=\"money-whole\">5</span>" \
|
|
122
|
+
# "<span class=\"money-decimal-mark\">.</span>" \
|
|
123
|
+
# "<span class=\"money-decimal\">70</span> " \
|
|
124
|
+
# "<span class=\"money-currency\">CAD</span>"
|
|
121
125
|
#
|
|
122
126
|
# @option rules [Boolean] :sign_before_symbol (false) Whether the sign should be
|
|
123
127
|
# before the currency symbol.
|
|
@@ -145,7 +149,7 @@ class Money
|
|
|
145
149
|
# @example
|
|
146
150
|
# Money.new(10000, "USD").format(disambiguate: false) #=> "$100.00"
|
|
147
151
|
# Money.new(10000, "CAD").format(disambiguate: false) #=> "$100.00"
|
|
148
|
-
# Money.new(10000, "USD").format(disambiguate: true) #=> "$100.00"
|
|
152
|
+
# Money.new(10000, "USD").format(disambiguate: true) #=> "US$100.00"
|
|
149
153
|
# Money.new(10000, "CAD").format(disambiguate: true) #=> "C$100.00"
|
|
150
154
|
#
|
|
151
155
|
# @option rules [Boolean] :translate (true) `true` Checks for custom
|
|
@@ -191,6 +195,7 @@ class Money
|
|
|
191
195
|
|
|
192
196
|
def to_s
|
|
193
197
|
return free_text if show_free_text?
|
|
198
|
+
|
|
194
199
|
result = format_number
|
|
195
200
|
formatted = append_sign(result)
|
|
196
201
|
append_currency_symbol(formatted)
|
|
@@ -208,8 +213,8 @@ class Money
|
|
|
208
213
|
lookup :decimal_mark
|
|
209
214
|
end
|
|
210
215
|
|
|
211
|
-
|
|
212
|
-
|
|
216
|
+
alias delimiter thousands_separator
|
|
217
|
+
alias separator decimal_mark
|
|
213
218
|
|
|
214
219
|
private
|
|
215
220
|
|
|
@@ -230,7 +235,7 @@ class Money
|
|
|
230
235
|
[
|
|
231
236
|
html_wrap(whole_part, "whole"),
|
|
232
237
|
html_wrap(decimal_mark, "decimal-mark"),
|
|
233
|
-
html_wrap(decimal_part, "decimal")
|
|
238
|
+
html_wrap(decimal_part, "decimal"),
|
|
234
239
|
].join
|
|
235
240
|
end
|
|
236
241
|
else
|
|
@@ -239,15 +244,15 @@ class Money
|
|
|
239
244
|
end
|
|
240
245
|
|
|
241
246
|
def append_sign(formatted_number)
|
|
242
|
-
sign = money.negative? ?
|
|
247
|
+
sign = money.negative? ? "-" : ""
|
|
243
248
|
|
|
244
249
|
if rules[:sign_positive] == true && money.positive?
|
|
245
|
-
sign =
|
|
250
|
+
sign = "+"
|
|
246
251
|
end
|
|
247
252
|
|
|
248
253
|
if rules[:sign_before_symbol] == true
|
|
249
254
|
sign_before = sign
|
|
250
|
-
sign =
|
|
255
|
+
sign = ""
|
|
251
256
|
end
|
|
252
257
|
|
|
253
258
|
symbol_value = symbol_value_from(rules)
|
|
@@ -258,10 +263,10 @@ class Money
|
|
|
258
263
|
end
|
|
259
264
|
|
|
260
265
|
rules[:format]
|
|
261
|
-
.gsub(
|
|
262
|
-
.gsub(
|
|
266
|
+
.gsub("%u", [sign_before, symbol_value].join)
|
|
267
|
+
.gsub("%n", [sign, formatted_number].join)
|
|
263
268
|
else
|
|
264
|
-
|
|
269
|
+
"#{sign_before}#{sign}#{formatted_number}"
|
|
265
270
|
end
|
|
266
271
|
end
|
|
267
272
|
|
|
@@ -289,7 +294,7 @@ class Money
|
|
|
289
294
|
end
|
|
290
295
|
|
|
291
296
|
def free_text
|
|
292
|
-
rules[:display_free].respond_to?(:to_str) ? rules[:display_free] :
|
|
297
|
+
rules[:display_free].respond_to?(:to_str) ? rules[:display_free] : "free"
|
|
293
298
|
end
|
|
294
299
|
|
|
295
300
|
def format_whole_part(value)
|
|
@@ -309,7 +314,7 @@ class Money
|
|
|
309
314
|
fractional_units = BigDecimal(fractional) / currency.subunit_to_unit
|
|
310
315
|
|
|
311
316
|
# Split the result and return whole and decimal parts separately
|
|
312
|
-
fractional_units.to_s(
|
|
317
|
+
fractional_units.to_s("F").split(".")
|
|
313
318
|
end
|
|
314
319
|
|
|
315
320
|
def format_decimal_part(value)
|
|
@@ -318,10 +323,10 @@ class Money
|
|
|
318
323
|
return nil if rules[:no_cents_if_whole] && value.to_i == 0
|
|
319
324
|
|
|
320
325
|
# Pad value, making up for missing zeroes at the end
|
|
321
|
-
value = value.ljust(currency.decimal_places,
|
|
326
|
+
value = value.ljust(currency.decimal_places, "0")
|
|
322
327
|
|
|
323
328
|
# Drop trailing zeros if needed
|
|
324
|
-
value.gsub!(/0*$/,
|
|
329
|
+
value.gsub!(/0*$/, "") if rules[:drop_trailing_zeros]
|
|
325
330
|
|
|
326
331
|
value.empty? ? nil : value
|
|
327
332
|
end
|
|
@@ -338,7 +343,7 @@ class Money
|
|
|
338
343
|
|
|
339
344
|
def symbol_value_from(rules)
|
|
340
345
|
if rules.has_key?(:symbol)
|
|
341
|
-
if rules[:symbol]
|
|
346
|
+
if rules[:symbol] == true
|
|
342
347
|
if rules[:disambiguate] && currency.disambiguate_symbol
|
|
343
348
|
currency.disambiguate_symbol
|
|
344
349
|
else
|
|
@@ -350,7 +355,7 @@ class Money
|
|
|
350
355
|
""
|
|
351
356
|
end
|
|
352
357
|
elsif rules[:html_wrap]
|
|
353
|
-
currency.html_entity ==
|
|
358
|
+
currency.html_entity == "" ? currency.symbol : currency.html_entity
|
|
354
359
|
elsif rules[:disambiguate] && currency.disambiguate_symbol
|
|
355
360
|
currency.disambiguate_symbol
|
|
356
361
|
else
|
|
@@ -18,9 +18,11 @@ class Money
|
|
|
18
18
|
@rules[key]
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
+
# rubocop:disable Naming/PredicatePrefix
|
|
21
22
|
def has_key?(key)
|
|
22
23
|
@rules.has_key? key
|
|
23
24
|
end
|
|
25
|
+
# rubocop:enable Naming/PredicatePrefix
|
|
24
26
|
|
|
25
27
|
private
|
|
26
28
|
|
|
@@ -32,14 +34,14 @@ class Money
|
|
|
32
34
|
#
|
|
33
35
|
# @return [Hash]
|
|
34
36
|
def normalize_formatting_rules(rules)
|
|
35
|
-
if rules.
|
|
37
|
+
if rules.empty?
|
|
36
38
|
rules = {}
|
|
37
39
|
elsif rules.size == 1
|
|
38
40
|
rules = rules.pop
|
|
39
41
|
rules = rules.dup if rules.is_a?(Hash)
|
|
40
42
|
|
|
41
43
|
if rules.is_a?(Symbol)
|
|
42
|
-
warn
|
|
44
|
+
warn "[DEPRECATION] Use Hash when passing rules to Money#format."
|
|
43
45
|
rules = { rules => true }
|
|
44
46
|
end
|
|
45
47
|
end
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
3
|
+
require "money/locale_backend/errors"
|
|
4
|
+
require "money/locale_backend/i18n"
|
|
5
|
+
require "money/locale_backend/currency"
|
|
6
6
|
|
|
7
7
|
class Money
|
|
8
8
|
module LocaleBackend
|
|
9
9
|
BACKENDS = {
|
|
10
10
|
i18n: Money::LocaleBackend::I18n,
|
|
11
|
-
currency: Money::LocaleBackend::Currency
|
|
11
|
+
currency: Money::LocaleBackend::Currency,
|
|
12
12
|
}.freeze
|
|
13
13
|
|
|
14
14
|
def self.find(name)
|
data/lib/money/money.rb
CHANGED
|
@@ -82,16 +82,16 @@ class Money
|
|
|
82
82
|
#
|
|
83
83
|
# @return [Money]
|
|
84
84
|
def to_nearest_cash_value
|
|
85
|
-
unless
|
|
85
|
+
unless currency.smallest_denomination
|
|
86
86
|
raise UndefinedSmallestDenomination,
|
|
87
87
|
"Smallest denomination of this currency is not defined"
|
|
88
88
|
end
|
|
89
89
|
|
|
90
90
|
fractional = as_d(@fractional)
|
|
91
|
-
smallest_denomination = as_d(
|
|
91
|
+
smallest_denomination = as_d(currency.smallest_denomination)
|
|
92
92
|
rounded_value =
|
|
93
93
|
(fractional / smallest_denomination)
|
|
94
|
-
|
|
94
|
+
.round(0, self.class.rounding_mode) * smallest_denomination
|
|
95
95
|
|
|
96
96
|
dup_with(fractional: return_value(rounded_value))
|
|
97
97
|
end
|
|
@@ -106,7 +106,6 @@ class Money
|
|
|
106
106
|
|
|
107
107
|
# Class Methods
|
|
108
108
|
class << self
|
|
109
|
-
|
|
110
109
|
# @!attribute [rw] default_bank
|
|
111
110
|
# Used to set a default bank for currency exchange.
|
|
112
111
|
#
|
|
@@ -163,7 +162,13 @@ class Money
|
|
|
163
162
|
:conversion_precision,
|
|
164
163
|
:strict_eql_compare
|
|
165
164
|
attr_reader :locale_backend
|
|
166
|
-
attr_writer :default_bank
|
|
165
|
+
attr_writer :default_bank,
|
|
166
|
+
:default_currency
|
|
167
|
+
|
|
168
|
+
# @attr_writer rounding_mode Use this to specify the rounding mode
|
|
169
|
+
attr_writer :rounding_mode
|
|
170
|
+
|
|
171
|
+
alias from_cents new
|
|
167
172
|
end
|
|
168
173
|
|
|
169
174
|
# @!attribute default_currency
|
|
@@ -179,10 +184,6 @@ class Money
|
|
|
179
184
|
end
|
|
180
185
|
end
|
|
181
186
|
|
|
182
|
-
def self.default_currency=(currency)
|
|
183
|
-
@default_currency = currency
|
|
184
|
-
end
|
|
185
|
-
|
|
186
187
|
# Modified to support thread-local bank override
|
|
187
188
|
def self.default_bank
|
|
188
189
|
# Check for thread-local bank first, then fall back to global default
|
|
@@ -218,11 +219,6 @@ class Money
|
|
|
218
219
|
@locale_backend = value ? LocaleBackend.find(value) : nil
|
|
219
220
|
end
|
|
220
221
|
|
|
221
|
-
# @attr_writer rounding_mode Use this to specify the rounding mode
|
|
222
|
-
def self.rounding_mode=(new_rounding_mode)
|
|
223
|
-
@rounding_mode = new_rounding_mode
|
|
224
|
-
end
|
|
225
|
-
|
|
226
222
|
def self.setup_defaults
|
|
227
223
|
# Set the default bank for creating new +Money+ objects.
|
|
228
224
|
self.default_bank = Bank::VariableExchange.instance
|
|
@@ -246,6 +242,8 @@ class Money
|
|
|
246
242
|
|
|
247
243
|
def self.inherited(base)
|
|
248
244
|
base.setup_defaults
|
|
245
|
+
|
|
246
|
+
super
|
|
249
247
|
end
|
|
250
248
|
|
|
251
249
|
setup_defaults
|
|
@@ -316,10 +314,10 @@ class Money
|
|
|
316
314
|
#
|
|
317
315
|
# @see #initialize
|
|
318
316
|
def self.from_amount(amount, currency = default_currency, options = {})
|
|
319
|
-
raise ArgumentError, "'amount' must be numeric" unless Numeric
|
|
317
|
+
raise ArgumentError, "'amount' must be numeric" unless amount.is_a?(Numeric)
|
|
320
318
|
|
|
321
319
|
currency = Currency.wrap(currency) || Money.default_currency
|
|
322
|
-
raise Currency::NoCurrency,
|
|
320
|
+
raise Currency::NoCurrency, "must provide a currency" if currency.nil?
|
|
323
321
|
|
|
324
322
|
value = amount.to_d * currency.subunit_to_unit
|
|
325
323
|
new(value, currency, options)
|
|
@@ -335,10 +333,6 @@ class Money
|
|
|
335
333
|
from_amount(amount, currency, options)
|
|
336
334
|
end
|
|
337
335
|
|
|
338
|
-
class << self
|
|
339
|
-
alias_method :from_cents, :new
|
|
340
|
-
end
|
|
341
|
-
|
|
342
336
|
# Creates a new Money object of value given in the
|
|
343
337
|
# +fractional unit+ of the given +currency+.
|
|
344
338
|
#
|
|
@@ -373,8 +367,8 @@ class Money
|
|
|
373
367
|
@bank ||= Money.default_bank
|
|
374
368
|
|
|
375
369
|
# BigDecimal can be Infinity and NaN, money of that amount does not make sense
|
|
376
|
-
raise ArgumentError,
|
|
377
|
-
raise Currency::NoCurrency,
|
|
370
|
+
raise ArgumentError, "must be initialized with a finite value" unless @fractional.finite?
|
|
371
|
+
raise Currency::NoCurrency, "must provide a currency" if @currency.nil?
|
|
378
372
|
end
|
|
379
373
|
|
|
380
374
|
# DEPRECATED.
|
|
@@ -408,7 +402,7 @@ class Money
|
|
|
408
402
|
# @example
|
|
409
403
|
# Money.new(100).hash #=> 908351
|
|
410
404
|
def hash
|
|
411
|
-
[fractional
|
|
405
|
+
[fractional, currency].hash
|
|
412
406
|
end
|
|
413
407
|
|
|
414
408
|
# Uses +Currency#symbol+. If +nil+ is returned, defaults to "¤".
|
|
@@ -435,7 +429,7 @@ class Money
|
|
|
435
429
|
# @example
|
|
436
430
|
# Money.ca_dollar(100).to_s #=> "1.00"
|
|
437
431
|
def to_s
|
|
438
|
-
format thousands_separator:
|
|
432
|
+
format thousands_separator: "",
|
|
439
433
|
no_cents_if_whole: currency.decimal_places == 0,
|
|
440
434
|
symbol: false,
|
|
441
435
|
ignore_defaults: true
|
|
@@ -494,7 +488,7 @@ class Money
|
|
|
494
488
|
# @return [self]
|
|
495
489
|
def to_money(given_currency = nil)
|
|
496
490
|
given_currency = Currency.wrap(given_currency)
|
|
497
|
-
if given_currency.nil? ||
|
|
491
|
+
if given_currency.nil? || currency == given_currency
|
|
498
492
|
self
|
|
499
493
|
else
|
|
500
494
|
exchange_to(given_currency)
|
|
@@ -517,12 +511,12 @@ class Money
|
|
|
517
511
|
# Money.new(2000, "USD").exchange_to("EUR")
|
|
518
512
|
# Money.new(2000, "USD").exchange_to("EUR") {|x| x.round}
|
|
519
513
|
# Money.new(2000, "USD").exchange_to(Currency.new("EUR"))
|
|
520
|
-
def exchange_to(other_currency, &
|
|
514
|
+
def exchange_to(other_currency, &)
|
|
521
515
|
other_currency = Currency.wrap(other_currency)
|
|
522
|
-
if
|
|
516
|
+
if currency == other_currency
|
|
523
517
|
self
|
|
524
518
|
else
|
|
525
|
-
@bank.exchange_with(self, other_currency, &
|
|
519
|
+
@bank.exchange_with(self, other_currency, &)
|
|
526
520
|
end
|
|
527
521
|
end
|
|
528
522
|
|
|
@@ -584,7 +578,8 @@ class Money
|
|
|
584
578
|
amounts = Money::Allocation.generate(fractional, parts, !Money.default_infinite_precision)
|
|
585
579
|
amounts.map { |amount| dup_with(fractional: amount) }
|
|
586
580
|
end
|
|
587
|
-
|
|
581
|
+
|
|
582
|
+
alias split allocate
|
|
588
583
|
|
|
589
584
|
# Round the monetary amount to smallest unit of coinage.
|
|
590
585
|
#
|
|
@@ -636,7 +631,7 @@ class Money
|
|
|
636
631
|
self.class.new(
|
|
637
632
|
options[:fractional] || fractional,
|
|
638
633
|
options[:currency] || currency,
|
|
639
|
-
bank: options[:bank] || bank
|
|
634
|
+
bank: options[:bank] || bank,
|
|
640
635
|
)
|
|
641
636
|
end
|
|
642
637
|
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "monitor"
|
|
4
4
|
|
|
5
5
|
class Money
|
|
6
6
|
module RatesStore
|
|
7
|
-
|
|
8
7
|
# Class for thread-safe storage of exchange rate pairs.
|
|
9
8
|
# Used by instances of +Money::Bank::VariableExchange+.
|
|
10
9
|
#
|
|
@@ -15,7 +14,7 @@ class Money
|
|
|
15
14
|
# # iterates rates
|
|
16
15
|
# store.each_rate {|iso_from, iso_to, rate| puts "#{from} -> #{to}: #{rate}" }
|
|
17
16
|
class Memory
|
|
18
|
-
INDEX_KEY_SEPARATOR =
|
|
17
|
+
INDEX_KEY_SEPARATOR = "_TO_"
|
|
19
18
|
|
|
20
19
|
# Initializes a new +Money::RatesStore::Memory+ object.
|
|
21
20
|
#
|
|
@@ -72,10 +71,8 @@ class Money
|
|
|
72
71
|
end
|
|
73
72
|
|
|
74
73
|
# Wraps block execution in a thread-safe transaction
|
|
75
|
-
def transaction(&
|
|
76
|
-
guard.synchronize
|
|
77
|
-
yield
|
|
78
|
-
end
|
|
74
|
+
def transaction(&)
|
|
75
|
+
guard.synchronize(&)
|
|
79
76
|
end
|
|
80
77
|
|
|
81
78
|
# Iterate over rate tuples (iso_from, iso_to, rate)
|
|
@@ -90,7 +87,7 @@ class Money
|
|
|
90
87
|
# store.each_rate do |iso_from, iso_to, rate|
|
|
91
88
|
# puts [iso_from, iso_to, rate].join
|
|
92
89
|
# end
|
|
93
|
-
def each_rate(&
|
|
90
|
+
def each_rate(&)
|
|
94
91
|
return to_enum(:each_rate) unless block_given?
|
|
95
92
|
|
|
96
93
|
guard.synchronize do
|
data/lib/money/version.rb
CHANGED
data/money.gemspec
CHANGED
|
@@ -8,8 +8,8 @@ Gem::Specification.new do |s|
|
|
|
8
8
|
s.name = "money"
|
|
9
9
|
s.version = Money::VERSION
|
|
10
10
|
s.platform = Gem::Platform::RUBY
|
|
11
|
-
s.authors = [
|
|
12
|
-
s.email = [
|
|
11
|
+
s.authors = ["Shane Emmons", "Anthony Dmitriyev"]
|
|
12
|
+
s.email = ["shane@emmons.io", "anthony.dmitriyev@gmail.com"]
|
|
13
13
|
s.homepage = "https://rubymoney.github.io/money"
|
|
14
14
|
s.summary = "A Ruby Library for dealing with money and currency conversion."
|
|
15
15
|
s.description = "A Ruby Library for dealing with money and currency conversion."
|
|
@@ -20,13 +20,13 @@ Gem::Specification.new do |s|
|
|
|
20
20
|
|
|
21
21
|
s.required_ruby_version = ">= 3.1"
|
|
22
22
|
|
|
23
|
-
s.files = `git ls-files -z -- config/* lib/* CHANGELOG.md LICENSE money.gemspec README.md`.split("\x0")
|
|
23
|
+
s.files = `git ls-files -z -- config/* lib/* sig/* CHANGELOG.md LICENSE money.gemspec README.md`.split("\x0")
|
|
24
24
|
s.require_paths = ["lib"]
|
|
25
25
|
|
|
26
26
|
if s.respond_to?(:metadata)
|
|
27
|
-
s.metadata[
|
|
28
|
-
s.metadata[
|
|
29
|
-
s.metadata[
|
|
30
|
-
s.metadata[
|
|
27
|
+
s.metadata["changelog_uri"] = "https://github.com/RubyMoney/money/blob/main/CHANGELOG.md"
|
|
28
|
+
s.metadata["source_code_uri"] = "https://github.com/RubyMoney/money/"
|
|
29
|
+
s.metadata["bug_tracker_uri"] = "https://github.com/RubyMoney/money/issues"
|
|
30
|
+
s.metadata["rubygems_mfa_required"] = "true"
|
|
31
31
|
end
|
|
32
32
|
end
|