money 6.18.0 → 7.0.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 +110 -49
- data/LICENSE +1 -1
- data/README.md +55 -54
- data/config/currency_backwards_compatible.json +17 -0
- data/config/currency_iso.json +47 -33
- data/config/currency_non_iso.json +1 -1
- data/lib/money/bank/base.rb +2 -0
- data/lib/money/bank/single_currency.rb +2 -0
- data/lib/money/bank/variable_exchange.rb +2 -0
- data/lib/money/currency/heuristics.rb +1 -1
- data/lib/money/currency/loader.rb +2 -0
- data/lib/money/currency.rb +35 -9
- data/lib/money/locale_backend/base.rb +2 -0
- data/lib/money/locale_backend/currency.rb +2 -0
- data/lib/money/locale_backend/errors.rb +2 -0
- data/lib/money/locale_backend/i18n.rb +4 -1
- data/lib/money/money/allocation.rb +51 -10
- data/lib/money/money/arithmetic.rb +31 -13
- data/lib/money/money/constructors.rb +2 -0
- data/lib/money/money/formatter.rb +13 -62
- data/lib/money/money/formatting_rules.rb +9 -59
- data/lib/money/money/locale_backend.rb +1 -3
- data/lib/money/money.rb +105 -119
- data/lib/money/rates_store/memory.rb +2 -0
- data/lib/money/version.rb +3 -1
- data/lib/money.rb +3 -0
- data/money.gemspec +8 -3
- metadata +22 -17
- data/lib/money/locale_backend/legacy.rb +0 -28
data/config/currency_iso.json
CHANGED
|
@@ -52,13 +52,13 @@
|
|
|
52
52
|
"priority": 100,
|
|
53
53
|
"iso_code": "AMD",
|
|
54
54
|
"name": "Armenian Dram",
|
|
55
|
-
"symbol": "
|
|
55
|
+
"symbol": "֏",
|
|
56
56
|
"alternate_symbols": ["dram"],
|
|
57
57
|
"subunit": "Luma",
|
|
58
58
|
"subunit_to_unit": 100,
|
|
59
59
|
"symbol_first": false,
|
|
60
60
|
"format": "%n %u",
|
|
61
|
-
"html_entity": "",
|
|
61
|
+
"html_entity": "֏",
|
|
62
62
|
"decimal_mark": ".",
|
|
63
63
|
"thousands_separator": ",",
|
|
64
64
|
"iso_numeric": "051",
|
|
@@ -452,10 +452,10 @@
|
|
|
452
452
|
"subunit": "Rappen",
|
|
453
453
|
"subunit_to_unit": 100,
|
|
454
454
|
"symbol_first": true,
|
|
455
|
-
"format": "%u%n",
|
|
455
|
+
"format": "%u %n",
|
|
456
456
|
"html_entity": "",
|
|
457
457
|
"decimal_mark": ".",
|
|
458
|
-
"thousands_separator": "
|
|
458
|
+
"thousands_separator": "'",
|
|
459
459
|
"iso_numeric": "756",
|
|
460
460
|
"smallest_denomination": 5
|
|
461
461
|
},
|
|
@@ -922,22 +922,6 @@
|
|
|
922
922
|
"iso_numeric": "340",
|
|
923
923
|
"smallest_denomination": 5
|
|
924
924
|
},
|
|
925
|
-
"hrk": {
|
|
926
|
-
"priority": 100,
|
|
927
|
-
"iso_code": "HRK",
|
|
928
|
-
"name": "Croatian Kuna",
|
|
929
|
-
"symbol": "kn",
|
|
930
|
-
"alternate_symbols": [],
|
|
931
|
-
"subunit": "Lipa",
|
|
932
|
-
"subunit_to_unit": 100,
|
|
933
|
-
"symbol_first": false,
|
|
934
|
-
"format": "%n %u",
|
|
935
|
-
"html_entity": "",
|
|
936
|
-
"decimal_mark": ",",
|
|
937
|
-
"thousands_separator": ".",
|
|
938
|
-
"iso_numeric": "191",
|
|
939
|
-
"smallest_denomination": 1
|
|
940
|
-
},
|
|
941
925
|
"htg": {
|
|
942
926
|
"priority": 100,
|
|
943
927
|
"iso_code": "HTG",
|
|
@@ -988,7 +972,7 @@
|
|
|
988
972
|
"ils": {
|
|
989
973
|
"priority": 100,
|
|
990
974
|
"iso_code": "ILS",
|
|
991
|
-
"name": "Israeli New
|
|
975
|
+
"name": "Israeli New Shekel",
|
|
992
976
|
"symbol": "₪",
|
|
993
977
|
"alternate_symbols": ["ש״ח", "NIS"],
|
|
994
978
|
"subunit": "Agora",
|
|
@@ -1387,7 +1371,7 @@
|
|
|
1387
1371
|
"symbol": "Ar",
|
|
1388
1372
|
"alternate_symbols": [],
|
|
1389
1373
|
"subunit": "Iraimbilanja",
|
|
1390
|
-
"subunit_to_unit":
|
|
1374
|
+
"subunit_to_unit": 1,
|
|
1391
1375
|
"symbol_first": true,
|
|
1392
1376
|
"html_entity": "",
|
|
1393
1377
|
"decimal_mark": ".",
|
|
@@ -1706,8 +1690,8 @@
|
|
|
1706
1690
|
"subunit_to_unit": 100,
|
|
1707
1691
|
"symbol_first": true,
|
|
1708
1692
|
"html_entity": "S/",
|
|
1709
|
-
"decimal_mark": "
|
|
1710
|
-
"thousands_separator": "
|
|
1693
|
+
"decimal_mark": ",",
|
|
1694
|
+
"thousands_separator": ".",
|
|
1711
1695
|
"iso_numeric": "604",
|
|
1712
1696
|
"smallest_denomination": 1
|
|
1713
1697
|
},
|
|
@@ -1826,14 +1810,14 @@
|
|
|
1826
1810
|
"priority": 100,
|
|
1827
1811
|
"iso_code": "RSD",
|
|
1828
1812
|
"name": "Serbian Dinar",
|
|
1829
|
-
"symbol": "
|
|
1830
|
-
"alternate_symbols": ["
|
|
1813
|
+
"symbol": "RSD",
|
|
1814
|
+
"alternate_symbols": ["РСД", "din", "дин", "din.", "DIN", "Din", "дин."],
|
|
1831
1815
|
"subunit": "Para",
|
|
1832
1816
|
"subunit_to_unit": 100,
|
|
1833
|
-
"symbol_first":
|
|
1817
|
+
"symbol_first": false,
|
|
1834
1818
|
"html_entity": "",
|
|
1835
|
-
"decimal_mark": "
|
|
1836
|
-
"thousands_separator": "
|
|
1819
|
+
"decimal_mark": ",",
|
|
1820
|
+
"thousands_separator": ".",
|
|
1837
1821
|
"iso_numeric": "941",
|
|
1838
1822
|
"smallest_denomination": 100
|
|
1839
1823
|
},
|
|
@@ -2196,13 +2180,13 @@
|
|
|
2196
2180
|
"priority": 100,
|
|
2197
2181
|
"iso_code": "TMT",
|
|
2198
2182
|
"name": "Turkmenistani Manat",
|
|
2199
|
-
"symbol": "
|
|
2183
|
+
"symbol": "m",
|
|
2200
2184
|
"alternate_symbols": [],
|
|
2201
2185
|
"subunit": "Tenge",
|
|
2202
2186
|
"subunit_to_unit": 100,
|
|
2203
2187
|
"symbol_first": false,
|
|
2204
2188
|
"format": "%n %u",
|
|
2205
|
-
"html_entity": "",
|
|
2189
|
+
"html_entity": "m",
|
|
2206
2190
|
"decimal_mark": ".",
|
|
2207
2191
|
"thousands_separator": ",",
|
|
2208
2192
|
"iso_numeric": "934",
|
|
@@ -2573,6 +2557,21 @@
|
|
|
2573
2557
|
"iso_numeric": "951",
|
|
2574
2558
|
"smallest_denomination": 1
|
|
2575
2559
|
},
|
|
2560
|
+
"xcg": {
|
|
2561
|
+
"priority": 100,
|
|
2562
|
+
"iso_code": "XCG",
|
|
2563
|
+
"name": "Caribbean Guilder",
|
|
2564
|
+
"symbol": "Cg",
|
|
2565
|
+
"alternate_symbols": [],
|
|
2566
|
+
"subunit": "Cent",
|
|
2567
|
+
"subunit_to_unit": 100,
|
|
2568
|
+
"symbol_first": true,
|
|
2569
|
+
"html_entity": "",
|
|
2570
|
+
"decimal_mark": ",",
|
|
2571
|
+
"thousands_separator": ".",
|
|
2572
|
+
"iso_numeric": "532",
|
|
2573
|
+
"smallest_denomination": 1
|
|
2574
|
+
},
|
|
2576
2575
|
"xdr": {
|
|
2577
2576
|
"priority": 100,
|
|
2578
2577
|
"iso_code": "XDR",
|
|
@@ -2695,8 +2694,8 @@
|
|
|
2695
2694
|
"subunit_to_unit": 100,
|
|
2696
2695
|
"symbol_first": true,
|
|
2697
2696
|
"html_entity": "R",
|
|
2698
|
-
"decimal_mark": "
|
|
2699
|
-
"thousands_separator": "
|
|
2697
|
+
"decimal_mark": ",",
|
|
2698
|
+
"thousands_separator": " ",
|
|
2700
2699
|
"iso_numeric": "710",
|
|
2701
2700
|
"smallest_denomination": 10
|
|
2702
2701
|
},
|
|
@@ -2732,5 +2731,20 @@
|
|
|
2732
2731
|
"thousands_separator": ",",
|
|
2733
2732
|
"iso_numeric": "967",
|
|
2734
2733
|
"smallest_denomination": 5
|
|
2734
|
+
},
|
|
2735
|
+
"zwg": {
|
|
2736
|
+
"priority": 100,
|
|
2737
|
+
"iso_code": "ZWG",
|
|
2738
|
+
"name": "Zimbabwe Gold",
|
|
2739
|
+
"symbol": "ZiG",
|
|
2740
|
+
"alternate_symbols": [],
|
|
2741
|
+
"subunit": "cent",
|
|
2742
|
+
"subunit_to_unit": 100,
|
|
2743
|
+
"symbol_first": false,
|
|
2744
|
+
"html_entity": "",
|
|
2745
|
+
"decimal_mark": ".",
|
|
2746
|
+
"thousands_separator": ",",
|
|
2747
|
+
"iso_numeric": "924",
|
|
2748
|
+
"smallest_denomination": 1
|
|
2735
2749
|
}
|
|
2736
2750
|
}
|
data/lib/money/bank/base.rb
CHANGED
data/lib/money/currency.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
4
|
require "money/currency/loader"
|
|
@@ -9,7 +9,7 @@ class Money
|
|
|
9
9
|
# Represents a specific currency unit.
|
|
10
10
|
#
|
|
11
11
|
# @see https://en.wikipedia.org/wiki/Currency
|
|
12
|
-
# @see
|
|
12
|
+
# @see https://www.iso.org/iso-4217-currency-codes.html
|
|
13
13
|
class Currency
|
|
14
14
|
include Comparable
|
|
15
15
|
extend Enumerable
|
|
@@ -33,6 +33,9 @@ class Money
|
|
|
33
33
|
# Thrown when an unknown currency is requested.
|
|
34
34
|
class UnknownCurrency < ArgumentError; end
|
|
35
35
|
|
|
36
|
+
# Thrown when currency is not provided.
|
|
37
|
+
class NoCurrency < ArgumentError; end
|
|
38
|
+
|
|
36
39
|
class << self
|
|
37
40
|
def new(id)
|
|
38
41
|
id = id.to_s.downcase
|
|
@@ -80,8 +83,8 @@ class Money
|
|
|
80
83
|
def find_by_iso_numeric(num)
|
|
81
84
|
num = num.to_s.rjust(3, '0')
|
|
82
85
|
return if num.empty?
|
|
83
|
-
id
|
|
84
|
-
new(id)
|
|
86
|
+
id = iso_numeric_index[num]
|
|
87
|
+
new(id) if id
|
|
85
88
|
rescue UnknownCurrency
|
|
86
89
|
nil
|
|
87
90
|
end
|
|
@@ -113,13 +116,13 @@ class Money
|
|
|
113
116
|
#
|
|
114
117
|
# == monetary unit
|
|
115
118
|
# The standard unit of value of a currency, as the dollar in the United States or the peso in Mexico.
|
|
116
|
-
# https://www.answers.com/
|
|
119
|
+
# https://www.answers.com/redirectSearch?query=monetary-unit
|
|
117
120
|
# == fractional monetary unit, subunit
|
|
118
121
|
# A monetary unit that is valued at a fraction (usually one hundredth) of the basic monetary unit
|
|
119
|
-
# https://www.answers.com/
|
|
122
|
+
# https://www.answers.com/redirectSearch?query=fractional-monetary-unit-subunit
|
|
120
123
|
#
|
|
121
124
|
# See https://en.wikipedia.org/wiki/List_of_circulating_currencies and
|
|
122
|
-
#
|
|
125
|
+
# https://metacpan.org/release/TNGUYEN/Locale-Currency-Format-1.28/view/Format.pm
|
|
123
126
|
def table
|
|
124
127
|
@table ||= Loader.load_currencies
|
|
125
128
|
end
|
|
@@ -142,7 +145,7 @@ class Money
|
|
|
142
145
|
|
|
143
146
|
# We need a string-based validator before creating an unbounded number of
|
|
144
147
|
# symbols.
|
|
145
|
-
# http://www.randomhacks.net/
|
|
148
|
+
# http://www.randomhacks.net.s3-website-us-east-1.amazonaws.com/2007/01/20/13-ways-of-looking-at-a-ruby-symbol/#11
|
|
146
149
|
# https://github.com/RubyMoney/money/issues/132
|
|
147
150
|
#
|
|
148
151
|
# @return [Set]
|
|
@@ -172,6 +175,7 @@ class Money
|
|
|
172
175
|
@@mutex.synchronize { _instances.delete(key.to_s) }
|
|
173
176
|
@table[key] = curr
|
|
174
177
|
@stringified_keys = nil
|
|
178
|
+
clear_iso_numeric_cache
|
|
175
179
|
end
|
|
176
180
|
|
|
177
181
|
# Inherit a new currency from existing one
|
|
@@ -209,10 +213,21 @@ class Money
|
|
|
209
213
|
def reset!
|
|
210
214
|
@@instances = {}
|
|
211
215
|
@table = Loader.load_currencies
|
|
216
|
+
clear_iso_numeric_cache
|
|
212
217
|
end
|
|
213
218
|
|
|
214
219
|
private
|
|
215
220
|
|
|
221
|
+
def iso_numeric_index
|
|
222
|
+
@iso_numeric_index ||= table.each_with_object({}) do |(id, attrs), index|
|
|
223
|
+
index[attrs[:iso_numeric]] = id
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def clear_iso_numeric_cache
|
|
228
|
+
@iso_numeric_index = nil
|
|
229
|
+
end
|
|
230
|
+
|
|
216
231
|
def stringify_keys
|
|
217
232
|
table.keys.each_with_object(Set.new) { |k, set| set.add(k.to_s.downcase) }
|
|
218
233
|
end
|
|
@@ -405,7 +420,7 @@ class Money
|
|
|
405
420
|
!!@symbol_first
|
|
406
421
|
end
|
|
407
422
|
|
|
408
|
-
# Returns if a code currency is ISO.
|
|
423
|
+
# Returns true if a code currency is ISO.
|
|
409
424
|
#
|
|
410
425
|
# @return [Boolean]
|
|
411
426
|
#
|
|
@@ -416,6 +431,17 @@ class Money
|
|
|
416
431
|
iso_numeric && iso_numeric != ''
|
|
417
432
|
end
|
|
418
433
|
|
|
434
|
+
# Returns true if a subunit is cents-based.
|
|
435
|
+
#
|
|
436
|
+
# @return [Boolean]
|
|
437
|
+
#
|
|
438
|
+
# @example
|
|
439
|
+
# Money::Currency.new(:usd).cents_based?
|
|
440
|
+
#
|
|
441
|
+
def cents_based?
|
|
442
|
+
subunit_to_unit == 100
|
|
443
|
+
end
|
|
444
|
+
|
|
419
445
|
# Returns the relation between subunit and unit as a base 10 exponent.
|
|
420
446
|
#
|
|
421
447
|
# Note that MGA and MRU are exceptions and are rounded to 1
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'money/locale_backend/base'
|
|
2
4
|
|
|
3
5
|
class Money
|
|
@@ -6,7 +8,8 @@ class Money
|
|
|
6
8
|
KEY_MAP = {
|
|
7
9
|
thousands_separator: :delimiter,
|
|
8
10
|
decimal_mark: :separator,
|
|
9
|
-
symbol: :unit
|
|
11
|
+
symbol: :unit,
|
|
12
|
+
format: :format,
|
|
10
13
|
}.freeze
|
|
11
14
|
|
|
12
15
|
def initialize
|
|
@@ -1,18 +1,27 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class Money
|
|
4
4
|
class Allocation
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
# parts listed first will likely receive more pennies than the ones listed later.
|
|
5
|
+
# Allocates a specified amount into parts based on their proportions or distributes
|
|
6
|
+
# it evenly when the number of parts is specified numerically.
|
|
8
7
|
#
|
|
9
|
-
# The
|
|
8
|
+
# The total of the allocated amounts will always equal the original amount.
|
|
10
9
|
#
|
|
11
10
|
# The parts can be specified as:
|
|
12
|
-
# Numeric — performs the split between a given number of parties
|
|
11
|
+
# Numeric — performs the split between a given number of parties evenly
|
|
13
12
|
# Array<Numeric> — allocates the amounts proportionally to the given array
|
|
14
13
|
#
|
|
15
|
-
|
|
14
|
+
# @param amount [Numeric] The total amount to be allocated.
|
|
15
|
+
# @param parts [Numeric, Array<Numeric>] Number of parts to split into or an array (proportions for allocation)
|
|
16
|
+
# @param decimal_cutoff [Boolean, Integer] Controls per-split precision:
|
|
17
|
+
# - When true, splits are truncated to whole amounts.
|
|
18
|
+
# - When an Integer N, splits are rounded to N decimal places.
|
|
19
|
+
# - When false or nil, no rounding/truncation is applied.
|
|
20
|
+
# Defaults to true (whole amounts).
|
|
21
|
+
#
|
|
22
|
+
# @return [Array<Numeric>] An array containing the allocated amounts.
|
|
23
|
+
# @raise [ArgumentError] If parts is empty or not provided.
|
|
24
|
+
def self.generate(amount, parts, decimal_cutoff = true)
|
|
16
25
|
parts = if parts.is_a?(Numeric)
|
|
17
26
|
Array.new(parts, 1)
|
|
18
27
|
elsif parts.all?(&:zero?)
|
|
@@ -21,26 +30,58 @@ class Money
|
|
|
21
30
|
parts.dup
|
|
22
31
|
end
|
|
23
32
|
|
|
24
|
-
raise ArgumentError, 'need at least one
|
|
33
|
+
raise ArgumentError, 'need at least one part' if parts.empty?
|
|
34
|
+
|
|
35
|
+
if [amount, *parts].any? { |i| i.is_a?(BigDecimal) || i.is_a?(Float) || i.is_a?(Rational) }
|
|
36
|
+
amount = convert_to_big_decimal(amount)
|
|
37
|
+
parts.map! { |p| convert_to_big_decimal(p) }
|
|
38
|
+
end
|
|
25
39
|
|
|
26
40
|
result = []
|
|
27
41
|
remaining_amount = amount
|
|
42
|
+
round_to_whole = decimal_cutoff.is_a?(TrueClass)
|
|
43
|
+
round_to_precision = decimal_cutoff.is_a?(Integer)
|
|
44
|
+
|
|
45
|
+
parts_sum = parts.sum
|
|
28
46
|
|
|
29
47
|
until parts.empty? do
|
|
30
|
-
parts_sum = parts.inject(0, :+)
|
|
31
48
|
part = parts.pop
|
|
32
49
|
|
|
33
50
|
current_split = 0
|
|
34
51
|
if parts_sum > 0
|
|
35
52
|
current_split = remaining_amount * part / parts_sum
|
|
36
|
-
current_split =
|
|
53
|
+
current_split =
|
|
54
|
+
if round_to_whole
|
|
55
|
+
current_split.truncate
|
|
56
|
+
elsif round_to_precision
|
|
57
|
+
current_split.round(decimal_cutoff)
|
|
58
|
+
else
|
|
59
|
+
current_split
|
|
60
|
+
end
|
|
37
61
|
end
|
|
38
62
|
|
|
39
63
|
result.unshift current_split
|
|
40
64
|
remaining_amount -= current_split
|
|
65
|
+
parts_sum -= part
|
|
41
66
|
end
|
|
42
67
|
|
|
43
68
|
result
|
|
44
69
|
end
|
|
70
|
+
|
|
71
|
+
# Converts a given number to BigDecimal.
|
|
72
|
+
# This method supports inputs of BigDecimal, Rational, and other numeric types by ensuring they are all returned
|
|
73
|
+
# as BigDecimal instances for consistent handling.
|
|
74
|
+
#
|
|
75
|
+
# @param number [Numeric, BigDecimal, Rational] The number to convert.
|
|
76
|
+
# @return [BigDecimal] The converted number as a BigDecimal.
|
|
77
|
+
def self.convert_to_big_decimal(number)
|
|
78
|
+
if number.is_a? BigDecimal
|
|
79
|
+
number
|
|
80
|
+
elsif number.is_a? Rational
|
|
81
|
+
BigDecimal(number.to_f.to_s)
|
|
82
|
+
else
|
|
83
|
+
BigDecimal(number.to_s)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
45
86
|
end
|
|
46
87
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
class Money
|
|
2
4
|
module Arithmetic
|
|
3
5
|
# Wrapper for coerced numeric values to distinguish
|
|
@@ -20,24 +22,32 @@ class Money
|
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
# Checks whether two Money objects have the same currency and the same
|
|
23
|
-
# amount.
|
|
24
|
-
#
|
|
25
|
-
# a subclass will always return false.
|
|
25
|
+
# amount. Checks against objects that are not Money or a subclass will
|
|
26
|
+
# always return false.
|
|
26
27
|
#
|
|
27
28
|
# @param [Money] other_money Value to compare with.
|
|
28
29
|
#
|
|
29
30
|
# @return [Boolean]
|
|
30
31
|
#
|
|
31
32
|
# @example
|
|
32
|
-
# Money.new(
|
|
33
|
-
# Money.new(
|
|
34
|
-
# Money.new(
|
|
35
|
-
# Money.new(0, "USD").eql?(Money.new(0, "EUR"))
|
|
36
|
-
# Money.new(
|
|
33
|
+
# Money.new(1_00).eql?(Money.new(1_00)) #=> true
|
|
34
|
+
# Money.new(1_00).eql?(Money.new(1_01)) #=> false
|
|
35
|
+
# Money.new(1_00, "USD").eql?(Money.new(1_00, "GBP")) #=> false
|
|
36
|
+
# Money.new(0, "USD").eql?(Money.new(0, "EUR")) #=> false
|
|
37
|
+
# Money.new(1_00).eql?("1.00") #=> false
|
|
38
|
+
#
|
|
39
|
+
# @see Money.strict_eql_compare
|
|
37
40
|
def eql?(other_money)
|
|
38
41
|
if other_money.is_a?(Money)
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
if !Money.strict_eql_compare && fractional == 0 && other_money.fractional == 0
|
|
43
|
+
warn "[DEPRECATION] Comparing 0 #{currency} with 0 " \
|
|
44
|
+
"#{other_money.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
|
+
return true
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
fractional == other_money.fractional && currency == other_money.currency
|
|
41
51
|
else
|
|
42
52
|
false
|
|
43
53
|
end
|
|
@@ -190,10 +200,15 @@ class Money
|
|
|
190
200
|
#
|
|
191
201
|
def /(value)
|
|
192
202
|
if value.is_a?(self.class)
|
|
193
|
-
|
|
203
|
+
exchanged = value.exchange_to(currency)
|
|
204
|
+
raise ZeroDivisionError, "divided by Money(0)" if exchanged.zero?
|
|
205
|
+
fractional / as_d(exchanged.fractional).to_f
|
|
194
206
|
else
|
|
195
207
|
raise TypeError, 'Can not divide by Money' if value.is_a?(CoercedNumeric)
|
|
196
|
-
|
|
208
|
+
|
|
209
|
+
value = as_d(value)
|
|
210
|
+
raise ZeroDivisionError, "divided by zero" if value.zero?
|
|
211
|
+
dup_with(fractional: fractional / value)
|
|
197
212
|
end
|
|
198
213
|
end
|
|
199
214
|
|
|
@@ -230,13 +245,16 @@ class Money
|
|
|
230
245
|
|
|
231
246
|
def divmod_money(val)
|
|
232
247
|
cents = val.exchange_to(currency).cents
|
|
248
|
+
raise ZeroDivisionError, "divided by Money(0)" if cents == 0
|
|
233
249
|
quotient, remainder = fractional.divmod(cents)
|
|
234
250
|
[quotient, dup_with(fractional: remainder)]
|
|
235
251
|
end
|
|
236
252
|
private :divmod_money
|
|
237
253
|
|
|
238
254
|
def divmod_other(val)
|
|
239
|
-
|
|
255
|
+
val = as_d(val)
|
|
256
|
+
raise ZeroDivisionError, "divided by zero" if val.zero?
|
|
257
|
+
quotient, remainder = fractional.divmod(val)
|
|
240
258
|
[dup_with(fractional: quotient), dup_with(fractional: remainder)]
|
|
241
259
|
end
|
|
242
260
|
private :divmod_other
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
require 'money/money/formatting_rules'
|
|
3
4
|
|
|
4
5
|
class Money
|
|
@@ -82,33 +83,6 @@ class Money
|
|
|
82
83
|
# Money.new(10000000, "INR").format(south_asian_number_formatting: true) #=> "1,00,000.00"
|
|
83
84
|
# Money.new(10000000).format(south_asian_number_formatting: true) #=> "$1,00,000.00"
|
|
84
85
|
#
|
|
85
|
-
# @option rules [Boolean, nil] :symbol_before_without_space (true) Whether
|
|
86
|
-
# a space between the money symbol and the amount should be inserted when
|
|
87
|
-
# +:symbol_position+ is +:before+. The default is true (meaning no space). Ignored
|
|
88
|
-
# if +:symbol+ is false or +:symbol_position+ is not +:before+.
|
|
89
|
-
#
|
|
90
|
-
# @example
|
|
91
|
-
# # Default is to not insert a space.
|
|
92
|
-
# Money.new(100, "USD").format #=> "$1.00"
|
|
93
|
-
#
|
|
94
|
-
# # Same thing.
|
|
95
|
-
# Money.new(100, "USD").format(symbol_before_without_space: true) #=> "$1.00"
|
|
96
|
-
#
|
|
97
|
-
# # If set to false, will insert a space.
|
|
98
|
-
# Money.new(100, "USD").format(symbol_before_without_space: false) #=> "$ 1.00"
|
|
99
|
-
#
|
|
100
|
-
# @option rules [Boolean, nil] :symbol_after_without_space (false) Whether
|
|
101
|
-
# a space between the amount and the money symbol should be inserted when
|
|
102
|
-
# +:symbol_position+ is +:after+. The default is false (meaning space). Ignored
|
|
103
|
-
# if +:symbol+ is false or +:symbol_position+ is not +:after+.
|
|
104
|
-
#
|
|
105
|
-
# @example
|
|
106
|
-
# # Default is to insert a space.
|
|
107
|
-
# Money.new(100, "USD").format(symbol_position: :after) #=> "1.00 $"
|
|
108
|
-
#
|
|
109
|
-
# # If set to true, will not insert a space.
|
|
110
|
-
# Money.new(100, "USD").format(symbol_position: :after, symbol_after_without_space: true) #=> "1.00$"
|
|
111
|
-
#
|
|
112
86
|
# @option rules [Boolean, String, nil] :decimal_mark (true) Whether the
|
|
113
87
|
# currency should be separated by the specified character or '.'
|
|
114
88
|
#
|
|
@@ -139,13 +113,6 @@ class Money
|
|
|
139
113
|
# # default to "," as thousands_separator.
|
|
140
114
|
# Money.new(100000, "FOO").format #=> "$1,000.00"
|
|
141
115
|
#
|
|
142
|
-
# @option rules [Boolean] :html (false) Whether the currency should be
|
|
143
|
-
# HTML-formatted. Only useful in combination with +:with_currency+.
|
|
144
|
-
#
|
|
145
|
-
# @example
|
|
146
|
-
# Money.ca_dollar(570).format(html: true, with_currency: true)
|
|
147
|
-
# #=> "$5.70 <span class=\"currency\">CAD</span>"
|
|
148
|
-
#
|
|
149
116
|
# @option rules [Boolean] :html_wrap (false) Whether all currency parts should be HTML-formatted.
|
|
150
117
|
#
|
|
151
118
|
# @example
|
|
@@ -181,20 +148,6 @@ class Money
|
|
|
181
148
|
# Money.new(10000, "USD").format(disambiguate: true) #=> "$100.00"
|
|
182
149
|
# Money.new(10000, "CAD").format(disambiguate: true) #=> "C$100.00"
|
|
183
150
|
#
|
|
184
|
-
# @option rules [Boolean] :html_wrap_symbol (false) Wraps the currency symbol
|
|
185
|
-
# in a html <span> tag.
|
|
186
|
-
#
|
|
187
|
-
# @example
|
|
188
|
-
# Money.new(10000, "USD").format(disambiguate: false)
|
|
189
|
-
# #=> "<span class=\"currency_symbol\">$100.00</span>
|
|
190
|
-
#
|
|
191
|
-
# @option rules [Symbol] :symbol_position (:before) `:before` if the currency
|
|
192
|
-
# symbol goes before the amount, `:after` if it goes after.
|
|
193
|
-
#
|
|
194
|
-
# @example
|
|
195
|
-
# Money.new(10000, "USD").format(symbol_position: :before) #=> "$100.00"
|
|
196
|
-
# Money.new(10000, "USD").format(symbol_position: :after) #=> "100.00 $"
|
|
197
|
-
#
|
|
198
151
|
# @option rules [Boolean] :translate (true) `true` Checks for custom
|
|
199
152
|
# symbol definitions using I18n.
|
|
200
153
|
#
|
|
@@ -300,9 +253,7 @@ class Money
|
|
|
300
253
|
symbol_value = symbol_value_from(rules)
|
|
301
254
|
|
|
302
255
|
if symbol_value && !symbol_value.empty?
|
|
303
|
-
if rules[:
|
|
304
|
-
symbol_value = "<span class=\"currency_symbol\">#{symbol_value}</span>"
|
|
305
|
-
elsif rules[:html_wrap]
|
|
256
|
+
if rules[:html_wrap]
|
|
306
257
|
symbol_value = html_wrap(symbol_value, "currency-symbol")
|
|
307
258
|
end
|
|
308
259
|
|
|
@@ -316,17 +267,17 @@ class Money
|
|
|
316
267
|
|
|
317
268
|
def append_currency_symbol(formatted_number)
|
|
318
269
|
if rules[:with_currency]
|
|
319
|
-
|
|
270
|
+
currency_part =
|
|
271
|
+
if rules[:html_wrap]
|
|
272
|
+
html_wrap(currency.to_s, "currency")
|
|
273
|
+
else
|
|
274
|
+
currency.to_s
|
|
275
|
+
end
|
|
320
276
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
formatted_number << html_wrap(currency.to_s, "currency")
|
|
325
|
-
else
|
|
326
|
-
formatted_number << currency.to_s
|
|
327
|
-
end
|
|
277
|
+
"#{formatted_number} #{currency_part}"
|
|
278
|
+
else
|
|
279
|
+
formatted_number
|
|
328
280
|
end
|
|
329
|
-
formatted_number
|
|
330
281
|
end
|
|
331
282
|
|
|
332
283
|
def show_free_text?
|
|
@@ -398,7 +349,7 @@ class Money
|
|
|
398
349
|
else
|
|
399
350
|
""
|
|
400
351
|
end
|
|
401
|
-
elsif rules[:
|
|
352
|
+
elsif rules[:html_wrap]
|
|
402
353
|
currency.html_entity == '' ? currency.symbol : currency.html_entity
|
|
403
354
|
elsif rules[:disambiguate] && currency.disambiguate_symbol
|
|
404
355
|
currency.disambiguate_symbol
|