shopify-money 3.0.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/tests.yml +3 -3
  3. data/.gitignore +2 -1
  4. data/.rubocop.yml +36 -0
  5. data/.ruby-version +1 -1
  6. data/Gemfile +4 -1
  7. data/Gemfile.lock +160 -121
  8. data/Rakefile +2 -2
  9. data/config/currency_historic.yml +44 -2
  10. data/config/currency_iso.yml +38 -64
  11. data/lib/money/allocator.rb +13 -9
  12. data/lib/money/config.rb +8 -0
  13. data/lib/money/core_extensions.rb +2 -1
  14. data/lib/money/currency/loader.rb +4 -3
  15. data/lib/money/currency.rb +12 -3
  16. data/lib/money/deprecations.rb +22 -4
  17. data/lib/money/errors.rb +1 -0
  18. data/lib/money/helpers.rb +2 -1
  19. data/lib/money/money.rb +53 -29
  20. data/lib/money/null_currency.rb +11 -3
  21. data/lib/money/parser/accounting.rb +1 -0
  22. data/lib/money/parser/fuzzy.rb +14 -13
  23. data/lib/money/parser/locale_aware.rb +3 -6
  24. data/lib/money/parser/simple.rb +2 -1
  25. data/lib/money/rails/job_argument_serializer.rb +0 -1
  26. data/lib/money/railtie.rb +5 -3
  27. data/lib/money/splitter.rb +20 -24
  28. data/lib/money/version.rb +2 -1
  29. data/lib/money.rb +1 -0
  30. data/lib/money_column/active_record_hooks.rb +9 -6
  31. data/lib/money_column/active_record_type.rb +7 -4
  32. data/lib/money_column/railtie.rb +2 -1
  33. data/lib/money_column.rb +1 -0
  34. data/lib/rubocop/cop/money/missing_currency.rb +16 -23
  35. data/lib/rubocop/cop/money/zero_money.rb +7 -13
  36. data/lib/shopify-money.rb +1 -0
  37. data/money.gemspec +6 -6
  38. data/spec/config_spec.rb +14 -0
  39. data/spec/money_spec.rb +38 -0
  40. data/spec/rubocop/cop/money/missing_currency_spec.rb +7 -7
  41. data/spec/rubocop/cop/money/zero_money_spec.rb +2 -2
  42. metadata +18 -42
@@ -105,7 +105,7 @@ ars:
105
105
  subunit: Centavo
106
106
  subunit_to_unit: 100
107
107
  symbol_first: true
108
- html_entity: "₱"
108
+ html_entity: "$"
109
109
  decimal_mark: ","
110
110
  thousands_separator: "."
111
111
  iso_numeric: '032'
@@ -225,7 +225,7 @@ bhd:
225
225
  priority: 100
226
226
  iso_code: BHD
227
227
  name: Bahraini Dinar
228
- symbol: ب.د
228
+ symbol: د.ب
229
229
  alternate_symbols:
230
230
  - BD
231
231
  subunit: Fils
@@ -458,7 +458,7 @@ chf:
458
458
  symbol_first: true
459
459
  html_entity: ''
460
460
  decimal_mark: "."
461
- thousands_separator: ","
461
+ thousands_separator: "'"
462
462
  iso_numeric: '756'
463
463
  smallest_denomination: 5
464
464
  clf:
@@ -715,7 +715,7 @@ eur:
715
715
  subunit: Cent
716
716
  subunit_to_unit: 100
717
717
  symbol_first: true
718
- html_entity: "€"
718
+ html_entity: ""
719
719
  decimal_mark: ","
720
720
  thousands_separator: "."
721
721
  iso_numeric: '978'
@@ -771,7 +771,7 @@ gel:
771
771
  priority: 100
772
772
  iso_code: GEL
773
773
  name: Georgian Lari
774
- symbol:
774
+ symbol: "₾"
775
775
  alternate_symbols:
776
776
  - lari
777
777
  subunit: Tetri
@@ -905,20 +905,6 @@ hnl:
905
905
  thousands_separator: ","
906
906
  iso_numeric: '340'
907
907
  smallest_denomination: 5
908
- hrk:
909
- priority: 100
910
- iso_code: HRK
911
- name: Croatian Kuna
912
- symbol: kn
913
- alternate_symbols: []
914
- subunit: Lipa
915
- subunit_to_unit: 100
916
- symbol_first: false
917
- html_entity: ''
918
- decimal_mark: ","
919
- thousands_separator: "."
920
- iso_numeric: '191'
921
- smallest_denomination: 1
922
908
  htg:
923
909
  priority: 100
924
910
  iso_code: HTG
@@ -964,7 +950,7 @@ idr:
964
950
  ils:
965
951
  priority: 100
966
952
  iso_code: ILS
967
- name: Israeli New Sheqel
953
+ name: Israeli New Shekel
968
954
  symbol: "₪"
969
955
  alternate_symbols:
970
956
  - ש״ח
@@ -1034,7 +1020,7 @@ isk:
1034
1020
  - Íkr
1035
1021
  subunit:
1036
1022
  subunit_to_unit: 1
1037
- symbol_first: true
1023
+ symbol_first: false
1038
1024
  html_entity: ''
1039
1025
  decimal_mark: ","
1040
1026
  thousands_separator: "."
@@ -1210,7 +1196,7 @@ kzt:
1210
1196
  priority: 100
1211
1197
  iso_code: KZT
1212
1198
  name: Kazakhstani Tenge
1213
- symbol: ""
1199
+ symbol: ""
1214
1200
  alternate_symbols: []
1215
1201
  subunit: Tiyn
1216
1202
  subunit_to_unit: 100
@@ -1302,34 +1288,6 @@ lsl:
1302
1288
  thousands_separator: ","
1303
1289
  iso_numeric: '426'
1304
1290
  smallest_denomination: 1
1305
- ltl:
1306
- priority: 100
1307
- iso_code: LTL
1308
- name: Lithuanian Litas
1309
- symbol: Lt
1310
- alternate_symbols: []
1311
- subunit: Centas
1312
- subunit_to_unit: 100
1313
- symbol_first: false
1314
- html_entity: ''
1315
- decimal_mark: "."
1316
- thousands_separator: ","
1317
- iso_numeric: '440'
1318
- smallest_denomination: 1
1319
- lvl:
1320
- priority: 100
1321
- iso_code: LVL
1322
- name: Latvian Lats
1323
- symbol: Ls
1324
- alternate_symbols: []
1325
- subunit: Santīms
1326
- subunit_to_unit: 100
1327
- symbol_first: true
1328
- html_entity: ''
1329
- decimal_mark: "."
1330
- thousands_separator: ","
1331
- iso_numeric: '428'
1332
- smallest_denomination: 1
1333
1291
  lyd:
1334
1292
  priority: 100
1335
1293
  iso_code: LYD
@@ -1620,11 +1578,12 @@ npr:
1620
1578
  priority: 100
1621
1579
  iso_code: NPR
1622
1580
  name: Nepalese Rupee
1623
- symbol: "₨"
1581
+ symbol: Rs.
1624
1582
  disambiguate_symbol: NPR
1625
1583
  alternate_symbols:
1626
1584
  - Rs
1627
1585
  - रू
1586
+ - "₨"
1628
1587
  subunit: Paisa
1629
1588
  subunit_to_unit: 100
1630
1589
  symbol_first: true
@@ -1681,14 +1640,14 @@ pen:
1681
1640
  priority: 100
1682
1641
  iso_code: PEN
1683
1642
  name: Peruvian Sol
1684
- symbol: S/.
1643
+ symbol: S/
1685
1644
  alternate_symbols: []
1686
1645
  subunit: Céntimo
1687
1646
  subunit_to_unit: 100
1688
1647
  symbol_first: true
1689
- html_entity: S/.
1690
1648
  decimal_mark: "."
1691
1649
  thousands_separator: ","
1650
+ html_entity: S/
1692
1651
  iso_numeric: '604'
1693
1652
  smallest_denomination: 1
1694
1653
  pgk:
@@ -1970,6 +1929,20 @@ skk:
1970
1929
  thousands_separator: ","
1971
1930
  iso_numeric: '703'
1972
1931
  smallest_denomination: 50
1932
+ sle:
1933
+ priority: 100
1934
+ iso_code: SLE
1935
+ name: New Leone
1936
+ symbol: Le
1937
+ alternate_symbols: []
1938
+ subunit: Cent
1939
+ subunit_to_unit: 100
1940
+ symbol_first: false
1941
+ html_entity: ''
1942
+ decimal_mark: "."
1943
+ thousands_separator: ","
1944
+ iso_numeric: '925'
1945
+ smallest_denomination: 1000
1973
1946
  sll:
1974
1947
  priority: 100
1975
1948
  iso_code: SLL
@@ -2274,13 +2247,13 @@ uyu:
2274
2247
  priority: 100
2275
2248
  iso_code: UYU
2276
2249
  name: Uruguayan Peso
2277
- symbol: "$"
2250
+ symbol: "$U"
2278
2251
  alternate_symbols:
2279
2252
  - "$U"
2280
2253
  subunit: Centésimo
2281
2254
  subunit_to_unit: 100
2282
2255
  symbol_first: true
2283
- html_entity: "₱"
2256
+ html_entity: "$U"
2284
2257
  decimal_mark: ","
2285
2258
  thousands_separator: "."
2286
2259
  iso_numeric: '858'
@@ -2289,7 +2262,7 @@ uzs:
2289
2262
  priority: 100
2290
2263
  iso_code: UZS
2291
2264
  name: Uzbekistan Som
2292
- symbol: ''
2265
+ symbol: so'm
2293
2266
  alternate_symbols:
2294
2267
  - so‘m
2295
2268
  - сўм
@@ -2325,9 +2298,10 @@ ved:
2325
2298
  ves:
2326
2299
  priority: 100
2327
2300
  iso_code: VES
2328
- name: Venezuelan Bolívar soberano
2329
- symbol: Bs.S.
2330
- alternate_symbols: []
2301
+ name: Venezuelan Bolívar Soberano
2302
+ symbol: Bs
2303
+ alternate_symbols:
2304
+ - Bs.S
2331
2305
  subunit: Céntimo
2332
2306
  subunit_to_unit: 100
2333
2307
  symbol_first: true
@@ -2389,7 +2363,7 @@ xaf:
2389
2363
  priority: 100
2390
2364
  iso_code: XAF
2391
2365
  name: Central African Cfa Franc
2392
- symbol: Fr
2366
+ symbol: CFA
2393
2367
  disambiguate_symbol: FCFA
2394
2368
  alternate_symbols:
2395
2369
  - FCFA
@@ -2576,7 +2550,7 @@ xpt:
2576
2550
  smallest_denomination: ''
2577
2551
  xts:
2578
2552
  priority: 100
2579
- iso_code: xts
2553
+ iso_code: XTS
2580
2554
  name: Codes specifically reserved for testing purposes
2581
2555
  symbol: ''
2582
2556
  alternate_symbols: []
@@ -2612,8 +2586,8 @@ zar:
2612
2586
  subunit_to_unit: 100
2613
2587
  symbol_first: true
2614
2588
  html_entity: "R"
2615
- decimal_mark: "."
2616
- thousands_separator: ","
2589
+ decimal_mark: ","
2590
+ thousands_separator: " "
2617
2591
  iso_numeric: '710'
2618
2592
  smallest_denomination: 10
2619
2593
  zmk:
@@ -2635,7 +2609,7 @@ zmw:
2635
2609
  priority: 100
2636
2610
  iso_code: ZMW
2637
2611
  name: Zambian Kwacha
2638
- symbol: ZK
2612
+ symbol: K
2639
2613
  disambiguate_symbol: ZMW
2640
2614
  alternate_symbols: []
2641
2615
  subunit: Ngwee
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'delegate'
3
4
 
4
5
  class Money
@@ -107,7 +108,7 @@ class Money
107
108
  # Money.new(100).allocate_max_amounts([Money.new(5), Money.new(2)])
108
109
  # #=> [Money.new(5), Money.new(2)]
109
110
  def allocate_max_amounts(maximums)
110
- allocation_currency = extract_currency(maximums + [self.__getobj__])
111
+ allocation_currency = extract_currency(maximums + [__getobj__])
111
112
  maximums = maximums.map { |max| max.to_money(allocation_currency) }
112
113
  maximums_total = maximums.reduce(Money.new(0, allocation_currency), :+)
113
114
 
@@ -116,16 +117,16 @@ class Money
116
117
  Money.rational(max_amount, maximums_total)
117
118
  end
118
119
 
119
- total_allocatable = [maximums_total.subunits, self.subunits].min
120
+ total_allocatable = [maximums_total.subunits, subunits].min
120
121
 
121
122
  subunits_amounts, left_over = amounts_from_splits(1, splits, total_allocatable)
122
123
  subunits_amounts.map! { |amount| amount[:whole_subunits] }
123
124
 
124
125
  subunits_amounts.each_with_index do |amount, index|
125
- break unless left_over > 0
126
+ break if left_over <= 0
126
127
 
127
128
  max_amount = maximums[index].value * allocation_currency.subunit_to_unit
128
- next unless amount < max_amount
129
+ next if amount >= max_amount
129
130
 
130
131
  left_over -= 1
131
132
  subunits_amounts[index] += 1
@@ -137,9 +138,12 @@ class Money
137
138
  private
138
139
 
139
140
  def extract_currency(money_array)
140
- currencies = money_array.lazy.select { |money| money.is_a?(Money) }.reject(&:no_currency?).map(&:currency).to_a.uniq
141
+ currencies = money_array.lazy.select do |money|
142
+ money.is_a?(Money)
143
+ end.reject(&:no_currency?).map(&:currency).to_a.uniq
141
144
  if currencies.size > 1
142
- raise ArgumentError, "operation not permitted for Money objects with different currencies #{currencies.join(', ')}"
145
+ raise ArgumentError,
146
+ "operation not permitted for Money objects with different currencies #{currencies.join(", ")}"
143
147
  end
144
148
  currencies.first || NULL_CURRENCY
145
149
  end
@@ -154,8 +158,8 @@ class Money
154
158
  fractional_subunits = (subunits_to_split * ratio / allocations.to_r).to_f - whole_subunits
155
159
  left_over -= whole_subunits
156
160
  {
157
- :whole_subunits => whole_subunits,
158
- :fractional_subunits => fractional_subunits
161
+ whole_subunits: whole_subunits,
162
+ fractional_subunits: fractional_subunits,
159
163
  }
160
164
  end
161
165
 
@@ -172,7 +176,7 @@ class Money
172
176
  # the next whole number. Similarly, given the input [9.1, 5.5, 3.9] the correct ranking is *still* 2, 1, 0. This
173
177
  # is because 3.9 is nearer to 4 than 9.1 is to 10.
174
178
  def rank_by_nearest(amounts)
175
- amounts.each_with_index.sort_by{ |amount, i| 1 - amount[:fractional_subunits] }.map(&:last)
179
+ amounts.each_with_index.sort_by { |amount, _i| 1 - amount[:fractional_subunits] }.map(&:last)
176
180
  end
177
181
  end
178
182
  end
data/lib/money/config.rb CHANGED
@@ -21,5 +21,13 @@ class Money
21
21
  @legacy_json_format = false
22
22
  @legacy_deprecations = false
23
23
  end
24
+
25
+ def without_legacy_deprecations(&block)
26
+ old_legacy_deprecations = @legacy_deprecations
27
+ @legacy_deprecations = false
28
+ yield
29
+ ensure
30
+ @legacy_deprecations = old_legacy_deprecations
31
+ end
24
32
  end
25
33
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # Allows Writing of 100.to_money for +Numeric+ types
3
4
  # 100.to_money => #<Money @cents=10000>
4
5
  # 100.37.to_money => #<Money @cents=10037>
@@ -25,7 +26,7 @@ class String
25
26
  return Money.new(self, currency)
26
27
  end
27
28
 
28
- return Money.new(0, currency) if self.empty?
29
+ return Money.new(0, currency) if empty?
29
30
 
30
31
  Money::Parser::Fuzzy.parse(self, currency).tap do |money|
31
32
  old_value = money.value
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'yaml'
3
4
 
4
5
  class Money
@@ -9,9 +10,9 @@ class Money
9
10
  currency_data_path = File.expand_path("../../../../config", __FILE__)
10
11
 
11
12
  currencies = {}
12
- currencies.merge! YAML.load_file("#{currency_data_path}/currency_historic.yml")
13
- currencies.merge! YAML.load_file("#{currency_data_path}/currency_non_iso.yml")
14
- currencies.merge! YAML.load_file("#{currency_data_path}/currency_iso.yml")
13
+ currencies.merge!(YAML.load_file("#{currency_data_path}/currency_historic.yml"))
14
+ currencies.merge!(YAML.load_file("#{currency_data_path}/currency_non_iso.yml"))
15
+ currencies.merge!(YAML.load_file("#{currency_data_path}/currency_iso.yml"))
15
16
  deep_deduplicate!(currencies)
16
17
  end
17
18
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require "money/currency/loader"
3
4
 
4
5
  class Money
@@ -27,8 +28,16 @@ class Money
27
28
  end
28
29
  end
29
30
 
30
- attr_reader :iso_code, :iso_numeric, :name, :smallest_denomination, :subunit_symbol,
31
- :subunit_to_unit, :minor_units, :symbol, :disambiguate_symbol, :decimal_mark
31
+ attr_reader :iso_code,
32
+ :iso_numeric,
33
+ :name,
34
+ :smallest_denomination,
35
+ :subunit_symbol,
36
+ :subunit_to_unit,
37
+ :minor_units,
38
+ :symbol,
39
+ :disambiguate_symbol,
40
+ :decimal_mark
32
41
 
33
42
  def initialize(currency_iso)
34
43
  data = self.class.currencies[currency_iso]
@@ -51,7 +60,7 @@ class Money
51
60
  end
52
61
 
53
62
  def hash
54
- [ self.class, iso_code ].hash
63
+ [self.class, iso_code].hash
55
64
  end
56
65
 
57
66
  def compatible?(other)
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  Money.class_eval do
3
4
  ACTIVE_SUPPORT_DEFINED = defined?(ActiveSupport)
5
+ DEPRECATION_STACKTRACE_LENGTH = 5
4
6
 
5
7
  def self.active_support_deprecator
6
8
  @active_support_deprecator ||= begin
@@ -11,12 +13,28 @@ Money.class_eval do
11
13
 
12
14
  def self.deprecate(message)
13
15
  if ACTIVE_SUPPORT_DEFINED
14
- external_callstack = caller_locations.reject do |location|
15
- location.to_s.include?('gems/shopify-money')
16
- end
17
- active_support_deprecator.warn("[Shopify/Money] #{message}\n", external_callstack)
16
+ active_support_deprecator.warn("[Shopify/Money] #{message}\n", caller_stack)
18
17
  else
19
18
  Kernel.warn("DEPRECATION WARNING: [Shopify/Money] #{message}\n")
20
19
  end
21
20
  end
21
+
22
+ # :nocov:
23
+ if Thread.respond_to?(:each_caller_location)
24
+ def self.caller_stack
25
+ stack = []
26
+ Thread.each_caller_location do |location|
27
+ stack << location unless location.path.include?('gems/shopify-money')
28
+ break if stack.length == DEPRECATION_STACKTRACE_LENGTH
29
+ end
30
+ stack
31
+ end
32
+ else
33
+ def self.caller_stack
34
+ caller_locations(2, DEPRECATION_STACKTRACE_LENGTH * 2).reject do |location|
35
+ location.path.include?('gems/shopify-money')
36
+ end
37
+ end
38
+ end
39
+ # :nocov:
22
40
  end
data/lib/money/errors.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  class Money
3
4
  class Error < StandardError
4
5
  end
data/lib/money/helpers.rb CHANGED
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'bigdecimal'
3
4
 
4
5
  class Money
5
6
  module Helpers
6
- module_function
7
+ extend self
7
8
 
8
9
  DECIMAL_ZERO = BigDecimal(0).freeze
9
10
  MAX_DECIMAL = 21
data/lib/money/money.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'forwardable'
4
+ require 'json'
3
5
 
4
6
  class Money
5
7
  include Comparable
@@ -8,6 +10,7 @@ class Money
8
10
  NULL_CURRENCY = NullCurrency.new.freeze
9
11
 
10
12
  attr_reader :value, :currency
13
+
11
14
  def_delegators :@value, :zero?, :nonzero?, :positive?, :negative?, :to_i, :to_f, :hash
12
15
 
13
16
  class ReverseOperationProxy
@@ -36,11 +39,17 @@ class Money
36
39
 
37
40
  class << self
38
41
  extend Forwardable
39
- attr_accessor :config
40
- def_delegators :@config, :default_currency, :default_currency=
42
+ def_delegators :config, :default_currency, :default_currency=, :without_legacy_deprecations
43
+
44
+ def config
45
+ Thread.current[:shopify_money__config] ||= Config.new
46
+ end
47
+
48
+ def config=(config)
49
+ Thread.current[:shopify_money__config] = config
50
+ end
41
51
 
42
52
  def configure
43
- self.config ||= Config.new
44
53
  yield(config) if block_given?
45
54
  end
46
55
 
@@ -74,6 +83,16 @@ class Money
74
83
  new(value, currency)
75
84
  end
76
85
 
86
+ def from_json(string)
87
+ hash = JSON.parse(string, symbolize_names: true)
88
+ Money.new(hash.fetch(:value), hash.fetch(:currency))
89
+ end
90
+
91
+ def from_hash(hash)
92
+ hash = hash.transform_keys(&:to_sym)
93
+ Money.new(hash.fetch(:value), hash.fetch(:currency))
94
+ end
95
+
77
96
  def rational(money1, money2)
78
97
  money1.send(:arithmetic, money2) do
79
98
  factor = money1.currency.subunit_to_unit * money2.currency.subunit_to_unit
@@ -94,13 +113,11 @@ class Money
94
113
  # I18n.with_locale and ActiveSupport's Time.use_zone. This won't affect
95
114
  # instances being created with explicitly set currency.
96
115
  def with_currency(new_currency)
97
- begin
98
- old_currency = Money.current_currency
99
- Money.current_currency = new_currency
100
- yield
101
- ensure
102
- Money.current_currency = old_currency
103
- end
116
+ old_currency = Money.current_currency
117
+ Money.current_currency = new_currency
118
+ yield
119
+ ensure
120
+ Money.current_currency = old_currency
104
121
  end
105
122
 
106
123
  private
@@ -116,10 +133,12 @@ class Money
116
133
  return amount
117
134
  end
118
135
 
119
- msg = "Money.new(Money.new(amount, #{amount.currency}), #{currency}) is changing the currency of an existing money object"
136
+ msg = "Money.new(Money.new(amount, #{amount.currency}), #{currency}) " \
137
+ "is changing the currency of an existing money object"
138
+
120
139
  if Money.config.legacy_deprecations
121
140
  Money.deprecate("#{msg}. A Money::IncompatibleCurrencyError will raise in the next major release")
122
- return Money.new(amount.value, currency)
141
+ Money.new(amount.value, currency)
123
142
  else
124
143
  raise Money::IncompatibleCurrencyError, msg
125
144
  end
@@ -184,19 +203,19 @@ class Money
184
203
  end
185
204
  end
186
205
 
187
- def *(numeric)
188
- raise ArgumentError, "Money objects can only be multiplied by a Numeric" unless numeric.is_a?(Numeric)
206
+ def *(other)
207
+ raise ArgumentError, "Money objects can only be multiplied by a Numeric" unless other.is_a?(Numeric)
189
208
 
190
- return self if numeric == 1
191
- Money.new(value.to_r * numeric, currency)
209
+ return self if other == 1
210
+ Money.new(value.to_r * other, currency)
192
211
  end
193
212
 
194
- def /(numeric)
213
+ def /(other)
195
214
  raise "[Money] Dividing money objects can lose pennies. Use #split instead"
196
215
  end
197
216
 
198
217
  def inspect
199
- "#<#{self.class} value:#{self} currency:#{self.currency}>"
218
+ "#<#{self.class} value:#{self} currency:#{currency}>"
200
219
  end
201
220
 
202
221
  def ==(other)
@@ -228,8 +247,10 @@ class Money
228
247
  return Money.new(value, new_currency)
229
248
  end
230
249
 
231
- ensure_compatible_currency(Helpers.value_to_currency(new_currency),
232
- "to_money is attempting to change currency of an existing money object from #{currency} to #{new_currency}")
250
+ ensure_compatible_currency(
251
+ Helpers.value_to_currency(new_currency),
252
+ "to_money is attempting to change currency of an existing money object from #{currency} to #{new_currency}",
253
+ )
233
254
 
234
255
  self
235
256
  end
@@ -250,7 +271,7 @@ class Money
250
271
 
251
272
  rounded_value = value.round(units)
252
273
  if units == 0
253
- sprintf("%d", rounded_value)
274
+ format("%d", rounded_value)
254
275
  else
255
276
  formatted = rounded_value.to_s("F")
256
277
  decimal_digits = formatted.size - formatted.index(".") - 1
@@ -264,7 +285,7 @@ class Money
264
285
  alias_method :to_formatted_s, :to_fs
265
286
 
266
287
  def to_json(options = nil)
267
- if (options.is_a?(Hash) && options.delete(:legacy_format)) || Money.config.legacy_json_format
288
+ if (options.is_a?(Hash) && options[:legacy_format]) || Money.config.legacy_json_format
268
289
  to_s
269
290
  else
270
291
  as_json(options).to_json
@@ -272,12 +293,13 @@ class Money
272
293
  end
273
294
 
274
295
  def as_json(options = nil)
275
- if (options.is_a?(Hash) && options.delete(:legacy_format)) || Money.config.legacy_json_format
296
+ if (options.is_a?(Hash) && options[:legacy_format]) || Money.config.legacy_json_format
276
297
  to_s
277
298
  else
278
299
  { value: to_s(:amount), currency: currency.to_s }
279
300
  end
280
301
  end
302
+ alias_method :to_h, :as_json
281
303
 
282
304
  def abs
283
305
  abs = value.abs
@@ -291,7 +313,7 @@ class Money
291
313
  Money.new(floor, currency)
292
314
  end
293
315
 
294
- def round(ndigits=0)
316
+ def round(ndigits = 0)
295
317
  round = value.round(ndigits)
296
318
  return self if round == value
297
319
  Money.new(round, currency)
@@ -352,13 +374,13 @@ class Money
352
374
  def clamp(min, max)
353
375
  raise ArgumentError, 'min cannot be greater than max' if min > max
354
376
 
355
- clamped_value = min if self.value < min
356
- clamped_value = max if self.value > max
377
+ clamped_value = min if value < min
378
+ clamped_value = max if value > max
357
379
 
358
380
  if clamped_value.nil?
359
381
  self
360
382
  else
361
- Money.new(clamped_value, self.currency)
383
+ Money.new(clamped_value, currency)
362
384
  end
363
385
  end
364
386
 
@@ -367,8 +389,10 @@ class Money
367
389
  def arithmetic(other)
368
390
  case other
369
391
  when Money
370
- ensure_compatible_currency(other.currency,
371
- "mathematical operation not permitted for Money objects with different currencies #{other.currency} and #{currency}.")
392
+ desc = "mathematical operation not permitted for Money objects with different currencies " \
393
+ "#{other.currency} and #{currency}."
394
+
395
+ ensure_compatible_currency(other.currency, desc)
372
396
  yield(other)
373
397
 
374
398
  when Numeric, String
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  class Money
3
4
  # A placeholder currency for instances where no actual currency is available,
4
5
  # as defined by ISO4217. You should rarely, if ever, need to use this
@@ -32,9 +33,16 @@ class Money
32
33
  # #=> #<Money value:5.00 currency:CAD>
33
34
  #
34
35
  class NullCurrency
35
-
36
- attr_reader :iso_code, :iso_numeric, :name, :smallest_denomination, :subunit_symbol,
37
- :subunit_to_unit, :minor_units, :symbol, :disambiguate_symbol, :decimal_mark
36
+ attr_reader :iso_code,
37
+ :iso_numeric,
38
+ :name,
39
+ :smallest_denomination,
40
+ :subunit_symbol,
41
+ :subunit_to_unit,
42
+ :minor_units,
43
+ :symbol,
44
+ :disambiguate_symbol,
45
+ :decimal_mark
38
46
 
39
47
  def initialize
40
48
  @symbol = '$'
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  class Money
3
4
  module Parser
4
5
  class Accounting < Fuzzy