money 6.13.3 → 6.13.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: f37a415a5295b884c2d1c5c55a94d1bb68856a01
4
- data.tar.gz: efea099f7b00a66f8ccda8099426ba16edd8b1f0
2
+ SHA256:
3
+ metadata.gz: 1773172616f278d2f107e19153498c029c5f1b63f4ae68a7468ef66fbbef8991
4
+ data.tar.gz: 035cd8170e536decc4748cd8a6c2ef1b7a7d5e985e6a2ecba0c989f8cf89096c
5
5
  SHA512:
6
- metadata.gz: 60c02cb6a321987bacea58784b5707337ff09dcf793189a9ffee28f6eee73fd57b5bedd49948a08215c7d6a7e9e124d713a33cf04fc55cc77b57b749545250c8
7
- data.tar.gz: 17120c61dd889fd9de0f5c498497cedb4aa4b7b4f27c477e6069b6cdc1017b3fb77453d761c34a7fd07baef08295d5ce979a094344a888c3219f0d698733869c
6
+ metadata.gz: 5636c6323a8538ccc669a2ecfd07a3108adde4f6315e43d0d2b0bb818fc31d1c230ff0ca9715a2c1ca67edcdfa7cb71c9c4d8405410f0764cc82aaad5d3af4e1
7
+ data.tar.gz: 4b2532f674ca8b665b43c745f5b8cc2beb3d7d5fda0584273bc53d8a42e8a551037758374b6864cfe4b227d61d043282394ed51b62e27f82b8f374ddb27dbe5b
@@ -1,9 +1,34 @@
1
1
  # Changelog
2
2
 
3
+ ## 6.13.8
4
+ - Update symbol for XOF
5
+ - Update UYU currency symbol
6
+ - Allow double conversion using same bank
7
+ - Warn when using unsafe serializer for rate import
8
+ - Move Icelandic symbol after the amount
9
+
10
+ ## 6.13.7
11
+ - Improve deprecation warnings for the upcoming major release
12
+
13
+ ## 6.13.6
14
+ - Fix a regression introduced in 6.13.5 that broken RatesStore::Memory subclasses
15
+
16
+ ## 6.13.5
17
+ - Raise warning on using Money.default_currency
18
+ - Raise warning on using default Money.rounding_mode
19
+ - Add Second Ouguiya MRU 929 to currency iso file
20
+ - Add symbol for UZS
21
+ - Use monitor for recursive mutual exclusion in RatesStore::Memory
22
+ - Allow passing store as a string to Money::Bank::VariableExchange (to support Rails 6)
23
+
24
+ ## 6.13.4
25
+ - Update currency config for Zambian Kwacha (ZMW)
26
+ - Do not modify options passed to FormattingRules
27
+
3
28
  ## 6.13.3
4
29
  - Remove specs from the packaged gem
5
30
  - Use Currency::Loader directly without extending
6
- - Add Money.with_rounding_mode as a replacement for calling Money.roudning_mode with a block
31
+ - Add Money.with_rounding_mode as a replacement for calling Money.rounding_mode with a block
7
32
  - Fix currency search for two digit ISO numbers
8
33
  - Add description to TypeError raised by +/- operations
9
34
 
@@ -42,7 +67,7 @@
42
67
  - Wrap all amount parts when `:html_wrap` option is used
43
68
  - Deprecate `#currency_as_string` and `#currency_as_string=` (in favour of `#with_currency`)
44
69
  - Add `#with_currency` for swapping the currency
45
- - Rewrite allocate/split (fixing some penny loosing issues)
70
+ - Rewrite allocate/split (fixing some penny losing issues)
46
71
 
47
72
  ## 6.11.3
48
73
  - Fix regression: if enabled use i18n locales in Money#to_s
@@ -61,7 +86,7 @@
61
86
  - Added new symbol for bitcoin denomination
62
87
  - Specify custom rounding precision when using `infinite_precision`
63
88
  - Allow splits with sums greater than 1
64
- - Prevent arithmetic methods from loosing reference to the bank
89
+ - Prevent arithmetic methods from losing reference to the bank
65
90
  - Fix coerced zero numeric subtraction
66
91
  - Fix south asian formatting to support whole numbers
67
92
  - Refactor formatting logic
data/README.md CHANGED
@@ -21,7 +21,7 @@ A Ruby Library for dealing with money and currency conversion.
21
21
 
22
22
  ### Features
23
23
 
24
- - Provides a `Money` class which encapsulates all information about an certain
24
+ - Provides a `Money` class which encapsulates all information about a certain
25
25
  amount of money, such as its value and its currency.
26
26
  - Provides a `Money::Currency` class which encapsulates all information about
27
27
  a monetary unit.
@@ -253,7 +253,7 @@ The default bank is initialized with an in-memory store for exchange rates.
253
253
  Money.default_bank = Money::Bank::VariableExchange.new(Money::RatesStore::Memory.new)
254
254
  ```
255
255
 
256
- You can pass you own store implementation, ie. for storing and retrieving rates off a database, file, cache, etc.
256
+ You can pass your own store implementation, i.e. for storing and retrieving rates off a database, file, cache, etc.
257
257
 
258
258
  ```ruby
259
259
  Money.default_bank = Money::Bank::VariableExchange.new(MyCustomStore.new)
@@ -270,7 +270,7 @@ Stores must implement the following interface:
270
270
  # @return [Numeric] rate.
271
271
  def add_rate(iso_from, iso_to, rate); end
272
272
 
273
- # Get rate. Must be idempotent. ie. adding the same rate must not produce duplicates.
273
+ # Get rate. Must be idempotent. i.e. adding the same rate must not produce duplicates.
274
274
  # @param [String] iso_from Currency ISO code. ex. 'USD'
275
275
  # @param [String] iso_to Currency ISO code. ex. 'CAD'
276
276
  #
@@ -334,6 +334,8 @@ end
334
334
  Now you can use it with the default bank.
335
335
 
336
336
  ```ruby
337
+ # For Rails 6 pass model name as a string to make it compatible with zeitwerk
338
+ # Money.default_bank = Money::Bank::VariableExchange.new("ExchangeRate")
337
339
  Money.default_bank = Money::Bank::VariableExchange.new(ExchangeRate)
338
340
 
339
341
  # Add to the underlying store
@@ -421,6 +423,13 @@ Money.new(2.34567).round.format #=> "$0.02"
421
423
  Money.new(2.34567).round(BigDecimal::ROUND_HALF_UP, 2).format #=> "$0.0235"
422
424
  ```
423
425
 
426
+ You can set the default rounding mode by passing one of the `BigDecimal` mode enumerables like so:
427
+ ```ruby
428
+ Money.rounding_mode = BigDecimal::ROUND_HALF_EVEN
429
+ ```
430
+ See [BigDecimal::ROUND_MODE](https://ruby-doc.org/stdlib-2.5.1/libdoc/bigdecimal/rdoc/BigDecimal.html#ROUND_MODE) for more information
431
+
432
+
424
433
  ## Ruby on Rails
425
434
 
426
435
  To integrate money in a Rails application use [money-rails](https://github.com/RubyMoney/money-rails).
@@ -484,6 +493,16 @@ Money.new(10_000_00, 'USD').format # => $10.000,00
484
493
  Money.new(10_000_00, 'EUR').format # => €10.000,00
485
494
  ```
486
495
 
496
+ If you need to localize the position of the currency symbol, you
497
+ have to pass it manually. *Note: this will become the default formatting
498
+ behavior in the next version.*
499
+
500
+ ```ruby
501
+ I18n.locale = :fr
502
+ format = I18n.t :format, scope: 'number.currency.format'
503
+ Money.new(10_00, 'EUR').format(format: format) # => 10,00 €
504
+ ```
505
+
487
506
  For the legacy behaviour of "per currency" localization (formatting depends only on currency):
488
507
 
489
508
  ```ruby
@@ -60,6 +60,22 @@
60
60
  "iso_numeric": "428",
61
61
  "smallest_denomination": 1
62
62
  },
63
+ "mro": {
64
+ "priority": 100,
65
+ "iso_code": "MRO",
66
+ "name": "Mauritanian Ouguiya",
67
+ "symbol": "UM",
68
+ "disambiguate_symbol": "A-UM",
69
+ "alternate_symbols": [],
70
+ "subunit": "Khoums",
71
+ "subunit_to_unit": 5,
72
+ "symbol_first": false,
73
+ "html_entity": "",
74
+ "decimal_mark": ".",
75
+ "thousands_separator": ",",
76
+ "iso_numeric": "478",
77
+ "smallest_denomination": 1
78
+ },
63
79
  "mtl": {
64
80
  "priority": 100,
65
81
  "iso_code": "MTL",
@@ -1019,11 +1019,11 @@
1019
1019
  "priority": 100,
1020
1020
  "iso_code": "ISK",
1021
1021
  "name": "Icelandic Króna",
1022
- "symbol": "kr",
1022
+ "symbol": "kr.",
1023
1023
  "alternate_symbols": ["Íkr"],
1024
1024
  "subunit": null,
1025
1025
  "subunit_to_unit": 1,
1026
- "symbol_first": true,
1026
+ "symbol_first": false,
1027
1027
  "html_entity": "",
1028
1028
  "decimal_mark": ",",
1029
1029
  "thousands_separator": ".",
@@ -1412,9 +1412,9 @@
1412
1412
  "iso_numeric": "446",
1413
1413
  "smallest_denomination": 10
1414
1414
  },
1415
- "mro": {
1415
+ "mru": {
1416
1416
  "priority": 100,
1417
- "iso_code": "MRO",
1417
+ "iso_code": "MRU",
1418
1418
  "name": "Mauritanian Ouguiya",
1419
1419
  "symbol": "UM",
1420
1420
  "alternate_symbols": [],
@@ -1424,7 +1424,7 @@
1424
1424
  "html_entity": "",
1425
1425
  "decimal_mark": ".",
1426
1426
  "thousands_separator": ",",
1427
- "iso_numeric": "478",
1427
+ "iso_numeric": "929",
1428
1428
  "smallest_denomination": 1
1429
1429
  },
1430
1430
  "mur": {
@@ -2245,12 +2245,12 @@
2245
2245
  "priority": 100,
2246
2246
  "iso_code": "UYU",
2247
2247
  "name": "Uruguayan Peso",
2248
- "symbol": "$",
2248
+ "symbol": "$U",
2249
2249
  "alternate_symbols": ["$U"],
2250
2250
  "subunit": "Centésimo",
2251
2251
  "subunit_to_unit": 100,
2252
2252
  "symbol_first": true,
2253
- "html_entity": "₱",
2253
+ "html_entity": "$U",
2254
2254
  "decimal_mark": ",",
2255
2255
  "thousands_separator": ".",
2256
2256
  "iso_numeric": "858",
@@ -2260,7 +2260,7 @@
2260
2260
  "priority": 100,
2261
2261
  "iso_code": "UZS",
2262
2262
  "name": "Uzbekistan Som",
2263
- "symbol": "",
2263
+ "symbol": "so'm",
2264
2264
  "alternate_symbols": ["so‘m", "сўм", "сум", "s", "с"],
2265
2265
  "subunit": "Tiyin",
2266
2266
  "subunit_to_unit": 100,
@@ -2336,7 +2336,7 @@
2336
2336
  "priority": 100,
2337
2337
  "iso_code": "XAF",
2338
2338
  "name": "Central African Cfa Franc",
2339
- "symbol": "Fr",
2339
+ "symbol": "CFA",
2340
2340
  "disambiguate_symbol": "FCFA",
2341
2341
  "alternate_symbols": ["FCFA"],
2342
2342
  "subunit": "Centime",
@@ -2594,12 +2594,12 @@
2594
2594
  "priority": 100,
2595
2595
  "iso_code": "ZMW",
2596
2596
  "name": "Zambian Kwacha",
2597
- "symbol": "ZK",
2597
+ "symbol": "K",
2598
2598
  "disambiguate_symbol": "ZMW",
2599
2599
  "alternate_symbols": [],
2600
2600
  "subunit": "Ngwee",
2601
2601
  "subunit_to_unit": 100,
2602
- "symbol_first": false,
2602
+ "symbol_first": true,
2603
2603
  "html_entity": "",
2604
2604
  "decimal_mark": ".",
2605
2605
  "thousands_separator": ",",
@@ -42,7 +42,7 @@ class Money
42
42
  # bank.get_rate 'USD', 'CAD'
43
43
  class VariableExchange < Base
44
44
 
45
- attr_reader :mutex, :store
45
+ attr_reader :mutex
46
46
 
47
47
  # Available formats for importing/exporting rates.
48
48
  RATE_FORMATS = [:json, :ruby, :yaml].freeze
@@ -61,6 +61,10 @@ class Money
61
61
  super(&block)
62
62
  end
63
63
 
64
+ def store
65
+ @store.is_a?(String) ? Object.const_get(@store) : @store
66
+ end
67
+
64
68
  def marshal_dump
65
69
  [store.marshal_dump, @rounding_method]
66
70
  end
@@ -110,7 +114,7 @@ class Money
110
114
  if rate = get_rate(from.currency, to_currency)
111
115
  fractional = calculate_fractional(from, to_currency)
112
116
  from.class.new(
113
- exchange(fractional, rate, &block), to_currency
117
+ exchange(fractional, rate, &block), to_currency, self
114
118
  )
115
119
  else
116
120
  raise UnknownRate, "No conversion rate known for '#{from.currency.iso_code}' -> '#{to_currency}'"
@@ -213,8 +217,7 @@ class Money
213
217
  # s = bank.export_rates(:json)
214
218
  # s #=> "{\"USD_TO_CAD\":1.24515,\"CAD_TO_USD\":0.803115}"
215
219
  def export_rates(format, file = nil, opts = {})
216
- raise Money::Bank::UnknownRateFormat unless
217
- RATE_FORMATS.include? format
220
+ raise Money::Bank::UnknownRateFormat unless RATE_FORMATS.include?(format)
218
221
 
219
222
  store.transaction do
220
223
  s = FORMAT_SERIALIZERS[format].dump(rates)
@@ -254,8 +257,13 @@ class Money
254
257
  # bank.get_rate("USD", "CAD") #=> 1.24515
255
258
  # bank.get_rate("CAD", "USD") #=> 0.803115
256
259
  def import_rates(format, s, opts = {})
257
- raise Money::Bank::UnknownRateFormat unless
258
- RATE_FORMATS.include? format
260
+ raise Money::Bank::UnknownRateFormat unless RATE_FORMATS.include?(format)
261
+
262
+ if format == :ruby
263
+ warn '[WARNING] Using :ruby format when importing rates is potentially unsafe and ' \
264
+ 'might lead to remote code execution via Marshal.load deserializer. Consider using ' \
265
+ 'safe alternatives such as :json and :yaml.'
266
+ end
259
267
 
260
268
  store.transaction do
261
269
  data = FORMAT_SERIALIZERS[format].load(s)
@@ -414,7 +414,7 @@ class Money
414
414
 
415
415
  # Returns the relation between subunit and unit as a base 10 exponent.
416
416
  #
417
- # Note that MGA and MRO are exceptions and are rounded to 1
417
+ # Note that MGA and MRU are exceptions and are rounded to 1
418
418
  # @see https://en.wikipedia.org/wiki/ISO_4217#Active_codes
419
419
  #
420
420
  # @return [Integer]
@@ -91,51 +91,63 @@ class Money
91
91
  class << self
92
92
 
93
93
  # @!attribute [rw] default_bank
94
- # @return [Money::Bank::Base] Each Money object is associated to a bank
95
- # object, which is responsible for currency exchange. This property
96
- # allows you to specify the default bank object. The default value for
97
- # this property is an instance of +Bank::VariableExchange.+ It allows
98
- # one to specify custom exchange rates.
94
+ # Used to set a default bank for currency exchange.
95
+ #
96
+ # Each Money object is associated with a bank
97
+ # object, which is responsible for currency exchange. This property
98
+ # allows you to specify the default bank object. The default value for
99
+ # this property is an instance of +Bank::VariableExchange.+ It allows
100
+ # one to specify custom exchange rates.
101
+ #
102
+ # @return [Money::Bank::Base]
99
103
  #
100
104
  # @!attribute default_formatting_rules
101
- # @return [Hash] Use this to define a default hash of rules for every time
102
- # +Money#format+ is called. Rules provided on method call will be
103
- # merged with the default ones. To overwrite a rule, just provide the
104
- # intended value while calling +format+.
105
+ # Used to define a default hash of rules for every time
106
+ # +Money#format+ is called. Rules provided on method call will be
107
+ # merged with the default ones. To overwrite a rule, just provide the
108
+ # intended value while calling +format+.
105
109
  #
106
- # @see +Money::Formatting#format+ for more details.
110
+ # @see Money::Formatter#initialize Money::Formatter for more details
107
111
  #
108
112
  # @example
109
113
  # Money.default_formatting_rules = { display_free: true }
110
114
  # Money.new(0, "USD").format # => "free"
111
115
  # Money.new(0, "USD").format(display_free: false) # => "$0.00"
112
116
  #
117
+ # @return [Hash]
118
+ #
113
119
  # @!attribute [rw] use_i18n
114
- # @return [Boolean] Use this to disable i18n even if it's used by other
115
- # objects in your app.
120
+ # Used to disable i18n even if it's used by other components of your app.
121
+ #
122
+ # @return [Boolean]
116
123
  #
117
124
  # @!attribute [rw] infinite_precision
118
- # @return [Boolean] Use this to enable infinite precision cents
125
+ # Used to enable infinite precision cents
126
+ #
127
+ # @return [Boolean]
119
128
  #
120
129
  # @!attribute [rw] conversion_precision
121
- # @return [Integer] Use this to specify precision for converting Rational
122
- # to BigDecimal
123
- attr_accessor :default_bank, :default_formatting_rules,
124
- :use_i18n, :infinite_precision, :conversion_precision,
125
- :locale_backend
126
-
127
- # @attr_writer rounding_mode Use this to specify the rounding mode
130
+ # Used to specify precision for converting Rational to BigDecimal
128
131
  #
129
- # @!attribute default_currency
130
- # @return [Money::Currency] The default currency, which is used when
131
- # +Money.new+ is called without an explicit currency argument. The
132
- # default value is Currency.new("USD"). The value must be a valid
133
- # +Money::Currency+ instance.
134
- attr_writer :rounding_mode, :default_currency
132
+ # @return [Integer]
133
+ attr_accessor :default_bank, :default_formatting_rules,
134
+ :infinite_precision, :conversion_precision
135
135
 
136
+ attr_reader :use_i18n, :locale_backend
136
137
  end
137
138
 
139
+ # @!attribute default_currency
140
+ # @return [Money::Currency] The default currency, which is used when
141
+ # +Money.new+ is called without an explicit currency argument. The
142
+ # default value is Currency.new("USD"). The value must be a valid
143
+ # +Money::Currency+ instance.
138
144
  def self.default_currency
145
+ if @using_deprecated_default_currency
146
+ warn '[WARNING] The default currency will change from `USD` to `nil` in the next major release. Make ' \
147
+ 'sure to set it explicitly using `Money.default_currency=` to avoid potential issues'
148
+ @using_deprecated_default_currency = false
149
+ end
150
+
139
151
  if @default_currency.respond_to?(:call)
140
152
  Money::Currency.new(@default_currency.call)
141
153
  else
@@ -143,10 +155,21 @@ class Money
143
155
  end
144
156
  end
145
157
 
158
+ def self.default_currency=(currency)
159
+ @using_deprecated_default_currency = false
160
+ @default_currency = currency
161
+ end
162
+
146
163
  def self.locale_backend=(value)
147
164
  @locale_backend = value ? LocaleBackend.find(value) : nil
148
165
  end
149
166
 
167
+ # @attr_writer rounding_mode Use this to specify the rounding mode
168
+ def self.rounding_mode=(new_rounding_mode)
169
+ @using_deprecated_default_rounding_mode = false
170
+ @rounding_mode = new_rounding_mode
171
+ end
172
+
150
173
  def self.use_i18n=(value)
151
174
  if value
152
175
  warn '[DEPRECATION] `use_i18n` is deprecated - use `Money.locale_backend = :i18n` instead for locale based formatting'
@@ -163,6 +186,7 @@ class Money
163
186
 
164
187
  # Set the default currency for creating new +Money+ object.
165
188
  self.default_currency = Currency.new("USD")
189
+ @using_deprecated_default_currency = true
166
190
 
167
191
  # Default to using i18n
168
192
  @use_i18n = true
@@ -175,6 +199,7 @@ class Money
175
199
 
176
200
  # Default to bankers rounding
177
201
  self.rounding_mode = BigDecimal::ROUND_HALF_EVEN
202
+ @using_deprecated_default_rounding_mode = true
178
203
 
179
204
  # Default the conversion of Rationals precision to 16
180
205
  self.conversion_precision = 16
@@ -192,18 +217,30 @@ class Money
192
217
  #
193
218
  # @return [BigDecimal::ROUND_MODE] rounding mode
194
219
  def self.rounding_mode(mode = nil)
195
- return Thread.current[:money_rounding_mode] || @rounding_mode unless mode
220
+ if mode
221
+ warn "[DEPRECATION] calling `rounding_mode` with a block is deprecated. Please use `.with_rounding_mode` instead."
222
+ return with_rounding_mode(mode) { yield }
223
+ end
196
224
 
197
- warn "[DEPRECATION] calling `rounding_mode` with a block is deprecated. Please use `.with_rounding_mode` instead."
198
- with_rounding_mode(mode) { yield }
225
+ return Thread.current[:money_rounding_mode] if Thread.current[:money_rounding_mode]
226
+
227
+ if @using_deprecated_default_rounding_mode
228
+ warn '[WARNING] The default rounding mode will change from `ROUND_HALF_EVEN` to `ROUND_HALF_UP` in the ' \
229
+ 'next major release. Set it explicitly using `Money.rounding_mode=` to avoid potential problems.'
230
+ @using_deprecated_default_rounding_mode = false
231
+ end
232
+
233
+ @rounding_mode
199
234
  end
200
235
 
201
- # This method temporarily changes the rounding mode. It will then return the
202
- # results of the block instead.
236
+ # Temporarily changes the rounding mode in a given block.
203
237
  #
204
238
  # @param [BigDecimal::ROUND_MODE] mode
205
239
  #
206
- # @return [BigDecimal::ROUND_MODE,Yield] block results
240
+ # @yield The block within which rounding mode will be changed. Its return
241
+ # value will also be the return value of the whole method.
242
+ #
243
+ # @return [Object] block results
207
244
  #
208
245
  # @example
209
246
  # fee = Money.with_rounding_mode(BigDecimal::ROUND_HALF_UP) do
@@ -509,13 +546,15 @@ class Money
509
546
  exchange_to("EUR")
510
547
  end
511
548
 
512
- # Splits a given amount in parts without loosing pennies. The left-over pennies will be
513
- # distributed round-robin amongst the parties. This means that parties listed first will likely
514
- # receive more pennies than ones that are listed later.
549
+ # Splits a given amount in parts without losing pennies. The left-over pennies will be
550
+ # distributed round-robin amongst the parties. This means that parts listed first will likely
551
+ # receive more pennies than ones listed later.
552
+ #
553
+ # Pass [2, 1, 1] as input to give twice as much to part1 as part2 or
554
+ # part3 which results in 50% of the cash to party1, 25% to part2, and 25% to part3. Passing a
555
+ # number instead of an array will split the amount evenly (without losing pennies when rounding).
515
556
  #
516
- # @param [Array<Numeric>, Numeric] pass [2, 1, 1] to give twice as much to party1 as party2 or
517
- # party3 which results in 50% of the cash to party1, 25% to party2, and 25% to party3. Passing a
518
- # number instead of an array will split the amount evenly (without loosing pennies when rounding).
557
+ # @param [Array<Numeric>, Numeric] parts how amount should be distributed to parts
519
558
  #
520
559
  # @return [Array<Money>]
521
560
  #
@@ -553,7 +592,7 @@ class Money
553
592
 
554
593
  # Creates a formatted price string according to several rules.
555
594
  #
556
- # @param [Hash] See Money::Formatter for the list of formatting options
595
+ # @param [Hash] rules See {Money::Formatter Money::Formatter} for the list of formatting options
557
596
  #
558
597
  # @return [String]
559
598
  #
@@ -2,9 +2,9 @@
2
2
 
3
3
  class Money
4
4
  class Allocation
5
- # Splits a given amount in parts without loosing pennies.
6
- # The left-over pennies will be distributed round-robin amongst the parties. This means that
7
- # parties listed first will likely receive more pennies than ones that are listed later.
5
+ # Splits a given amount in parts without losing pennies.
6
+ # The left-over pennies will be distributed round-robin amongst the parts. This means that
7
+ # parts listed first will likely receive more pennies than the ones listed later.
8
8
  #
9
9
  # The results should always add up to the original amount.
10
10
  #
@@ -46,7 +46,7 @@ class Money
46
46
  # Compares two Money objects. If money objects have a different currency it
47
47
  # will attempt to convert the currency.
48
48
  #
49
- # @param [Money] other_money Value to compare with.
49
+ # @param [Money] other Value to compare with.
50
50
  #
51
51
  # @return [Integer]
52
52
  #
@@ -103,7 +103,7 @@ class Money
103
103
  # values. If +other_money+ has a different currency then its monetary value
104
104
  # is automatically exchanged to this object's currency using +exchange_to+.
105
105
  #
106
- # @param [Money] other_money Other +Money+ object to add.
106
+ # @param [Money] other Other +Money+ object to add.
107
107
  #
108
108
  # @return [Money]
109
109
  #
@@ -116,7 +116,7 @@ class Money
116
116
  # its monetary value is automatically exchanged to this object's currency
117
117
  # using +exchange_to+.
118
118
  #
119
- # @param [Money] other_money Other +Money+ object to subtract.
119
+ # @param [Money] other Other +Money+ object to subtract.
120
120
  #
121
121
  # @return [Money]
122
122
  #
@@ -38,6 +38,7 @@ class Money
38
38
  rules = {}
39
39
  elsif rules.size == 1
40
40
  rules = rules.pop
41
+ rules = rules.dup if rules.is_a?(Hash)
41
42
 
42
43
  if rules.is_a?(Symbol)
43
44
  warn '[DEPRECATION] Use Hash when passing rules to Money#format.'
@@ -1,3 +1,5 @@
1
+ require 'monitor'
2
+
1
3
  class Money
2
4
  module RatesStore
3
5
 
@@ -17,11 +19,11 @@ class Money
17
19
  #
18
20
  # @param [Hash] opts Optional store options.
19
21
  # @option opts [Boolean] :without_mutex disables the usage of a mutex
20
- # @param [Hash] rt Optional initial exchange rate data.
21
- def initialize(opts = {}, rt = {})
22
- @options, @index = opts, rt
23
- @mutex = Mutex.new
24
- @in_transaction = false
22
+ # @param [Hash] rates Optional initial exchange rate data.
23
+ def initialize(opts = {}, rates = {})
24
+ @rates = rates
25
+ @options = opts
26
+ @guard = Monitor.new
25
27
  end
26
28
 
27
29
  # Registers a conversion rate and returns it. Uses +Mutex+ to synchronize data access.
@@ -37,7 +39,9 @@ class Money
37
39
  # store.add_rate("USD", "CAD", 1.24515)
38
40
  # store.add_rate("CAD", "USD", 0.803115)
39
41
  def add_rate(currency_iso_from, currency_iso_to, rate)
40
- transaction { index[rate_key_for(currency_iso_from, currency_iso_to)] = rate }
42
+ guard.synchronize do
43
+ rates[rate_key_for(currency_iso_from, currency_iso_to)] = rate
44
+ end
41
45
  end
42
46
 
43
47
  # Retrieve the rate for the given currencies. Uses +Mutex+ to synchronize data access.
@@ -54,24 +58,21 @@ class Money
54
58
  #
55
59
  # store.get_rate("USD", "CAD") #=> 1.24515
56
60
  def get_rate(currency_iso_from, currency_iso_to)
57
- transaction { index[rate_key_for(currency_iso_from, currency_iso_to)] }
61
+ guard.synchronize do
62
+ rates[rate_key_for(currency_iso_from, currency_iso_to)]
63
+ end
58
64
  end
59
65
 
60
66
  def marshal_dump
61
- [self.class, options, index]
67
+ guard.synchronize do
68
+ return [self.class, options, rates.dup]
69
+ end
62
70
  end
63
71
 
64
72
  # Wraps block execution in a thread-safe transaction
65
73
  def transaction(&block)
66
- if @in_transaction || options[:without_mutex]
67
- block.call self
68
- else
69
- @mutex.synchronize do
70
- @in_transaction = true
71
- result = block.call
72
- @in_transaction = false
73
- result
74
- end
74
+ guard.synchronize do
75
+ yield
75
76
  end
76
77
  end
77
78
 
@@ -88,19 +89,19 @@ class Money
88
89
  # puts [iso_from, iso_to, rate].join
89
90
  # end
90
91
  def each_rate(&block)
91
- enum = Enumerator.new do |yielder|
92
- index.each do |key, rate|
92
+ return to_enum(:each_rate) unless block_given?
93
+
94
+ guard.synchronize do
95
+ rates.each do |key, rate|
93
96
  iso_from, iso_to = key.split(INDEX_KEY_SEPARATOR)
94
- yielder.yield iso_from, iso_to, rate
97
+ yield iso_from, iso_to, rate
95
98
  end
96
99
  end
97
-
98
- block_given? ? enum.each(&block) : enum
99
100
  end
100
101
 
101
102
  private
102
103
 
103
- attr_reader :index, :options
104
+ attr_reader :rates, :options, :guard
104
105
 
105
106
  # Return the rate hashkey for the given currencies.
106
107
  #
@@ -1,3 +1,3 @@
1
1
  class Money
2
- VERSION = '6.13.3'
2
+ VERSION = '6.13.8'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: money
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.13.3
4
+ version: 6.13.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shane Emmons
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-04-14 00:00:00.000000000 Z
12
+ date: 2020-07-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: i18n
@@ -159,8 +159,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
159
159
  - !ruby/object:Gem::Version
160
160
  version: '0'
161
161
  requirements: []
162
- rubyforge_project:
163
- rubygems_version: 2.6.8
162
+ rubygems_version: 3.1.2
164
163
  signing_key:
165
164
  specification_version: 4
166
165
  summary: A Ruby Library for dealing with money and currency conversion.