money 6.5.1 → 6.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +209 -5
  3. data/LICENSE +18 -16
  4. data/README.md +321 -70
  5. data/config/currency_backwards_compatible.json +65 -0
  6. data/config/currency_iso.json +280 -94
  7. data/config/currency_non_iso.json +101 -3
  8. data/lib/money/bank/base.rb +1 -3
  9. data/lib/money/bank/variable_exchange.rb +88 -96
  10. data/lib/money/currency/heuristics.rb +1 -143
  11. data/lib/money/currency/loader.rb +15 -13
  12. data/lib/money/currency.rb +98 -81
  13. data/lib/money/locale_backend/base.rb +7 -0
  14. data/lib/money/locale_backend/currency.rb +11 -0
  15. data/lib/money/locale_backend/errors.rb +6 -0
  16. data/lib/money/locale_backend/i18n.rb +25 -0
  17. data/lib/money/locale_backend/legacy.rb +28 -0
  18. data/lib/money/money/allocation.rb +46 -0
  19. data/lib/money/money/arithmetic.rb +97 -52
  20. data/lib/money/money/constructors.rb +5 -6
  21. data/lib/money/money/formatter.rb +399 -0
  22. data/lib/money/money/formatting_rules.rb +142 -0
  23. data/lib/money/money/locale_backend.rb +22 -0
  24. data/lib/money/money.rb +268 -194
  25. data/lib/money/rates_store/memory.rb +120 -0
  26. data/lib/money/version.rb +1 -1
  27. data/money.gemspec +15 -20
  28. metadata +36 -59
  29. data/.coveralls.yml +0 -1
  30. data/.gitignore +0 -22
  31. data/.travis.yml +0 -13
  32. data/AUTHORS +0 -116
  33. data/CONTRIBUTING.md +0 -17
  34. data/Gemfile +0 -7
  35. data/Rakefile +0 -17
  36. data/lib/money/money/formatting.rb +0 -386
  37. data/spec/bank/base_spec.rb +0 -77
  38. data/spec/bank/single_currency_spec.rb +0 -11
  39. data/spec/bank/variable_exchange_spec.rb +0 -275
  40. data/spec/currency/heuristics_spec.rb +0 -84
  41. data/spec/currency_spec.rb +0 -321
  42. data/spec/money/arithmetic_spec.rb +0 -568
  43. data/spec/money/constructors_spec.rb +0 -75
  44. data/spec/money/formatting_spec.rb +0 -667
  45. data/spec/money_spec.rb +0 -745
  46. data/spec/spec_helper.rb +0 -23
data/README.md CHANGED
@@ -1,12 +1,10 @@
1
1
  # RubyMoney - Money
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/money.png)](http://badge.fury.io/rb/money)
4
- [![Build Status](https://travis-ci.org/RubyMoney/money.png?branch=master)](https://travis-ci.org/RubyMoney/money)
5
- [![Code Climate](https://codeclimate.com/github/RubyMoney/money.png)](https://codeclimate.com/github/RubyMoney/money)
6
- [![Coverage Status](https://coveralls.io/repos/RubyMoney/money/badge.png?branch=master)](https://coveralls.io/r/RubyMoney/money?branch=master)
7
- [![Inline docs](http://inch-ci.org/github/RubyMoney/money.png)](http://inch-ci.org/github/RubyMoney/money)
8
- [![Dependency Status](https://gemnasium.com/RubyMoney/money.png)](https://gemnasium.com/RubyMoney/money)
9
- [![License](http://img.shields.io/license/MIT.png?color=green)](http://opensource.org/licenses/MIT)
3
+ [![Gem Version](https://badge.fury.io/rb/money.svg)](https://rubygems.org/gems/money)
4
+ [![Build Status](https://travis-ci.org/RubyMoney/money.svg?branch=master)](https://travis-ci.org/RubyMoney/money)
5
+ [![Code Climate](https://codeclimate.com/github/RubyMoney/money.svg)](https://codeclimate.com/github/RubyMoney/money)
6
+ [![Inline docs](https://inch-ci.org/github/RubyMoney/money.svg)](https://inch-ci.org/github/RubyMoney/money)
7
+ [![License](https://img.shields.io/github/license/RubyMoney/money.svg)](https://opensource.org/licenses/MIT)
10
8
 
11
9
  :warning: Please read the [migration notes](#migration-notes) before upgrading to a new major version.
12
10
 
@@ -22,21 +20,21 @@ A Ruby Library for dealing with money and currency conversion.
22
20
 
23
21
  ### Features
24
22
 
25
- - Provides a `Money` class which encapsulates all information about an certain
23
+ - Provides a `Money` class which encapsulates all information about a certain
26
24
  amount of money, such as its value and its currency.
27
25
  - Provides a `Money::Currency` class which encapsulates all information about
28
26
  a monetary unit.
29
27
  - Represents monetary values as integers, in cents. This avoids floating point
30
28
  rounding errors.
31
- - Represents currency as `Money::Currency` instances providing an high level of
29
+ - Represents currency as `Money::Currency` instances providing a high level of
32
30
  flexibility.
33
31
  - Provides APIs for exchanging money from one currency to another.
34
32
 
35
33
  ### Resources
36
34
 
37
- - [Website](http://rubymoney.github.com/money)
38
- - [API Documentation](http://rubydoc.info/gems/money/frames)
39
- - [Git Repository](http://github.com/RubyMoney/money)
35
+ - [Website](https://rubymoney.github.io/money/)
36
+ - [API Documentation](http://www.rubydoc.info/gems/money/frames)
37
+ - [Git Repository](https://github.com/RubyMoney/money)
40
38
 
41
39
  ### Notes
42
40
 
@@ -63,25 +61,38 @@ The development version (hosted on Github) can be installed with:
63
61
  require 'money'
64
62
 
65
63
  # 10.00 USD
66
- money = Money.new(1000, "USD")
64
+ money = Money.from_cents(1000, "USD")
67
65
  money.cents #=> 1000
68
66
  money.currency #=> Currency.new("USD")
69
67
 
70
68
  # Comparisons
71
- Money.new(1000, "USD") == Money.new(1000, "USD") #=> true
72
- Money.new(1000, "USD") == Money.new(100, "USD") #=> false
73
- Money.new(1000, "USD") == Money.new(1000, "EUR") #=> false
74
- Money.new(1000, "USD") != Money.new(1000, "EUR") #=> true
69
+ Money.from_cents(1000, "USD") == Money.from_cents(1000, "USD") #=> true
70
+ Money.from_cents(1000, "USD") == Money.from_cents(100, "USD") #=> false
71
+ Money.from_cents(1000, "USD") == Money.from_cents(1000, "EUR") #=> false
72
+ Money.from_cents(1000, "USD") != Money.from_cents(1000, "EUR") #=> true
75
73
 
76
74
  # Arithmetic
77
- Money.new(1000, "USD") + Money.new(500, "USD") == Money.new(1500, "USD")
78
- Money.new(1000, "USD") - Money.new(200, "USD") == Money.new(800, "USD")
79
- Money.new(1000, "USD") / 5 == Money.new(200, "USD")
80
- Money.new(1000, "USD") * 5 == Money.new(5000, "USD")
75
+ Money.from_cents(1000, "USD") + Money.from_cents(500, "USD") == Money.from_cents(1500, "USD")
76
+ Money.from_cents(1000, "USD") - Money.from_cents(200, "USD") == Money.from_cents(800, "USD")
77
+ Money.from_cents(1000, "USD") / 5 == Money.from_cents(200, "USD")
78
+ Money.from_cents(1000, "USD") * 5 == Money.from_cents(5000, "USD")
79
+
80
+ # Unit to subunit conversions
81
+ Money.from_amount(5, "USD") == Money.from_cents(500, "USD") # 5 USD
82
+ Money.from_amount(5, "JPY") == Money.from_cents(5, "JPY") # 5 JPY
83
+ Money.from_amount(5, "TND") == Money.from_cents(5000, "TND") # 5 TND
81
84
 
82
85
  # Currency conversions
83
86
  some_code_to_setup_exchange_rates
84
- Money.new(1000, "USD").exchange_to("EUR") == Money.new(some_value, "EUR")
87
+ Money.from_cents(1000, "USD").exchange_to("EUR") == Money.from_cents(some_value, "EUR")
88
+
89
+ # Swap currency
90
+ Money.from_cents(1000, "USD").with_currency("EUR") == Money.from_cents(1000, "EUR")
91
+
92
+ # Formatting (see Formatting section for more options)
93
+ Money.from_cents(100, "USD").format #=> "$1.00"
94
+ Money.from_cents(100, "GBP").format #=> "£1.00"
95
+ Money.from_cents(100, "EUR").format #=> "€1.00"
85
96
  ```
86
97
 
87
98
  ## Currency
@@ -91,15 +102,15 @@ The most part of `Money` APIs allows you to supply either a `String` or a
91
102
  `Money::Currency`.
92
103
 
93
104
  ``` ruby
94
- Money.new(1000, "USD") == Money.new(1000, Currency.new("USD"))
95
- Money.new(1000, "EUR").currency == Currency.new("EUR")
105
+ Money.from_cents(1000, "USD") == Money.from_cents(1000, Money::Currency.new("USD"))
106
+ Money.from_cents(1000, "EUR").currency == Money::Currency.new("EUR")
96
107
  ```
97
108
 
98
109
  A `Money::Currency` instance holds all the information about the currency,
99
110
  including the currency symbol, name and much more.
100
111
 
101
112
  ``` ruby
102
- currency = Money.new(1000, "USD").currency
113
+ currency = Money.from_cents(1000, "USD").currency
103
114
  currency.iso_code #=> "USD"
104
115
  currency.name #=> "United States Dollar"
105
116
  ```
@@ -109,15 +120,15 @@ below.
109
120
 
110
121
  ``` ruby
111
122
  curr = {
112
- :priority => 1,
113
- :iso_code => "USD",
114
- :iso_numeric => "840",
115
- :name => "United States Dollar",
116
- :symbol => "$",
117
- :subunit => "Cent",
118
- :subunit_to_unit => 100,
119
- :separator => ".",
120
- :delimiter => ","
123
+ priority: 1,
124
+ iso_code: "USD",
125
+ iso_numeric: "840",
126
+ name: "United States Dollar",
127
+ symbol: "$",
128
+ subunit: "Cent",
129
+ subunit_to_unit: 100,
130
+ decimal_mark: ".",
131
+ thousands_separator: ","
121
132
  }
122
133
 
123
134
  Money::Currency.register(curr)
@@ -132,8 +143,8 @@ The pre-defined set of attributes includes:
132
143
  - `:symbol` the currency symbol (UTF-8 encoded)
133
144
  - `:subunit` the name of the fractional monetary unit
134
145
  - `:subunit_to_unit` the proportion between the unit and the subunit
135
- - `:separator` character between the whole and fraction amounts
136
- - `:delimiter` character between each thousands place
146
+ - `:decimal_mark` character between the whole and fraction amounts
147
+ - `:thousands_separator` character between each thousands place
137
148
 
138
149
  All attributes except `:iso_code` are optional. Some attributes, such as
139
150
  `:symbol`, are used by the Money class to print out a representation of the
@@ -147,7 +158,7 @@ The priority attribute is an arbitrary numerical value you can assign to the
147
158
 
148
159
  For instance, let's assume your Rails application needs to render a currency
149
160
  selector like the one available
150
- [here](http://finance.yahoo.com/currency-converter/). You can create a couple of
161
+ [here](https://finance.yahoo.com/currency-converter/). You can create a couple of
151
162
  custom methods to return the list of major currencies and all currencies as
152
163
  follows:
153
164
 
@@ -171,10 +182,10 @@ def all_currencies(hash)
171
182
  end
172
183
 
173
184
  major_currencies(Money::Currency.table)
174
- # => [ :usd, :eur, :bgp, :cad ]
185
+ # => [:usd, :eur, :gbp, :aud, :cad, :jpy]
175
186
 
176
187
  all_currencies(Money::Currency.table)
177
- # => [ :aed, :afn, all, ... ]
188
+ # => [:aed, :afn, :all, ...]
178
189
  ```
179
190
 
180
191
  ### Default Currency
@@ -186,19 +197,19 @@ using:
186
197
  Money.default_currency = Money::Currency.new("CAD")
187
198
  ```
188
199
 
189
- If you use Rails, then `environment.rb` is a very good place to put this.
200
+ If you use [Rails](https://github.com/RubyMoney/money/tree/master#ruby-on-rails), then `config/initializers/money.rb` is a very good place to put this.
190
201
 
191
202
  ### Currency Exponent
192
203
 
193
204
  The exponent of a money value is the number of digits after the decimal
194
205
  separator (which separates the major unit from the minor unit). See e.g.
195
- [Wikipedia on ISO 4217](http://en.wikipedia.org/wiki/ISO_4217) for more
196
- information. You can find the exponent (as a `Float`) by
206
+ [ISO 4217](https://www.currency-iso.org/en/shared/amendments/iso-4217-amendment.html) for more
207
+ information. You can find the exponent (as an `Integer`) by
197
208
 
198
209
  ``` ruby
199
- Money::Currency.new("USD").exponent # => 2.0
200
- Money::Currency.new("JPY").exponent # => 0.0
201
- Money::Currency.new("MGA").exponent # => 0.6989700043360189
210
+ Money::Currency.new("USD").exponent # => 2
211
+ Money::Currency.new("JPY").exponent # => 0
212
+ Money::Currency.new("MGA").exponent # => 1
202
213
  ```
203
214
 
204
215
  ### Currency Lookup
@@ -219,25 +230,140 @@ an example of how it works:
219
230
  Money.add_rate("USD", "CAD", 1.24515)
220
231
  Money.add_rate("CAD", "USD", 0.803115)
221
232
 
222
- Money.us_dollar(100).exchange_to("CAD") # => Money.new(124, "CAD")
223
- Money.ca_dollar(100).exchange_to("USD") # => Money.new(80, "USD")
233
+ Money.us_dollar(100).exchange_to("CAD") # => Money.from_cents(124, "CAD")
234
+ Money.ca_dollar(100).exchange_to("USD") # => Money.from_cents(80, "USD")
224
235
  ```
225
236
 
226
237
  Comparison and arithmetic operations work as expected:
227
238
 
228
239
  ``` ruby
229
- Money.new(1000, "USD") <=> Money.new(900, "USD") # => 1; 9.00 USD is smaller
230
- Money.new(1000, "EUR") + Money.new(10, "EUR") == Money.new(1010, "EUR")
240
+ Money.from_cents(1000, "USD") <=> Money.from_cents(900, "USD") # => 1; 9.00 USD is smaller
241
+ Money.from_cents(1000, "EUR") + Money.from_cents(10, "EUR") == Money.from_cents(1010, "EUR")
231
242
 
232
243
  Money.add_rate("USD", "EUR", 0.5)
233
- Money.new(1000, "EUR") + Money.new(1000, "USD") == Money.new(1500, "EUR")
244
+ Money.from_cents(1000, "EUR") + Money.from_cents(1000, "USD") == Money.from_cents(1500, "EUR")
245
+ ```
246
+
247
+ ### Exchange rate stores
248
+
249
+ The default bank is initialized with an in-memory store for exchange rates.
250
+
251
+ ```ruby
252
+ Money.default_bank = Money::Bank::VariableExchange.new(Money::RatesStore::Memory.new)
253
+ ```
254
+
255
+ You can pass your own store implementation, i.e. for storing and retrieving rates off a database, file, cache, etc.
256
+
257
+ ```ruby
258
+ Money.default_bank = Money::Bank::VariableExchange.new(MyCustomStore.new)
259
+ ```
260
+
261
+ Stores must implement the following interface:
262
+
263
+ ```ruby
264
+ # Add new exchange rate.
265
+ # @param [String] iso_from Currency ISO code. ex. 'USD'
266
+ # @param [String] iso_to Currency ISO code. ex. 'CAD'
267
+ # @param [Numeric] rate Exchange rate. ex. 0.0016
268
+ #
269
+ # @return [Numeric] rate.
270
+ def add_rate(iso_from, iso_to, rate); end
271
+
272
+ # Get rate. Must be idempotent. i.e. adding the same rate must not produce duplicates.
273
+ # @param [String] iso_from Currency ISO code. ex. 'USD'
274
+ # @param [String] iso_to Currency ISO code. ex. 'CAD'
275
+ #
276
+ # @return [Numeric] rate.
277
+ def get_rate(iso_from, iso_to); end
278
+
279
+ # Iterate over rate tuples (iso_from, iso_to, rate)
280
+ #
281
+ # @yieldparam iso_from [String] Currency ISO string.
282
+ # @yieldparam iso_to [String] Currency ISO string.
283
+ # @yieldparam rate [Numeric] Exchange rate.
284
+ #
285
+ # @return [Enumerator]
286
+ #
287
+ # @example
288
+ # store.each_rate do |iso_from, iso_to, rate|
289
+ # puts [iso_from, iso_to, rate].join
290
+ # end
291
+ def each_rate(&block); end
292
+
293
+ # Wrap store operations in a thread-safe transaction
294
+ # (or IO or Database transaction, depending on your implementation)
295
+ #
296
+ # @yield [n] Block that will be wrapped in transaction.
297
+ #
298
+ # @example
299
+ # store.transaction do
300
+ # store.add_rate('USD', 'CAD', 0.9)
301
+ # store.add_rate('USD', 'CLP', 0.0016)
302
+ # end
303
+ def transaction(&block); end
304
+
305
+ # Serialize store and its content to make Marshal.dump work.
306
+ #
307
+ # Returns an array with store class and any arguments needed to initialize the store in the current state.
308
+
309
+ # @return [Array] [class, arg1, arg2]
310
+ def marshal_dump; end
234
311
  ```
235
312
 
236
- There is nothing stopping you from creating bank objects which scrapes
313
+ The following example implements an `ActiveRecord` store to save exchange rates to a database.
314
+
315
+ ```ruby
316
+ # rails g model exchange_rate from:string to:string rate:float
317
+
318
+ class ExchangeRate < ApplicationRecord
319
+ def self.get_rate(from_iso_code, to_iso_code)
320
+ rate = find_by(from: from_iso_code, to: to_iso_code)
321
+ rate&.rate
322
+ end
323
+
324
+ def self.add_rate(from_iso_code, to_iso_code, rate)
325
+ exrate = find_or_initialize_by(from: from_iso_code, to: to_iso_code)
326
+ exrate.rate = rate
327
+ exrate.save!
328
+ end
329
+
330
+ def self.each_rate
331
+ return find_each unless block_given?
332
+
333
+ find_each do |rate|
334
+ yield rate.from, rate.to, rate.rate
335
+ end
336
+ end
337
+ end
338
+ ```
339
+
340
+ Now you can use it with the default bank.
341
+
342
+ ```ruby
343
+ # For Rails 6 pass model name as a string to make it compatible with zeitwerk
344
+ # Money.default_bank = Money::Bank::VariableExchange.new("ExchangeRate")
345
+ Money.default_bank = Money::Bank::VariableExchange.new(ExchangeRate)
346
+
347
+ # Add to the underlying store
348
+ Money.default_bank.add_rate('USD', 'CAD', 0.9)
349
+ # Retrieve from the underlying store
350
+ Money.default_bank.get_rate('USD', 'CAD') # => 0.9
351
+ # Exchanging amounts just works.
352
+ Money.from_cents(1000, 'USD').exchange_to('CAD') #=> #<Money fractional:900 currency:CAD>
353
+ ```
354
+
355
+ There is nothing stopping you from creating store objects which scrapes
237
356
  [XE](http://www.xe.com) for the current rates or just returns `rand(2)`:
238
357
 
239
358
  ``` ruby
240
- Money.default_bank = ExchangeBankWhichScrapesXeDotCom.new
359
+ Money.default_bank = Money::Bank::VariableExchange.new(StoreWhichScrapesXeDotCom.new)
360
+ ```
361
+
362
+ You can also implement your own Bank to calculate exchanges differently.
363
+ Different banks can share Stores.
364
+
365
+ ```ruby
366
+ Money.default_bank = MyCustomBank.new(Money::RatesStore::Memory.new)
241
367
  ```
242
368
 
243
369
  If you wish to disable automatic currency conversion to prevent arithmetic when
@@ -252,51 +378,176 @@ Money.disallow_currency_conversion!
252
378
  The following is a list of Money.gem compatible currency exchange rate
253
379
  implementations.
254
380
 
255
- - [eu_central_bank](http://github.com/RubyMoney/eu_central_bank)
256
- - [google_currency](http://github.com/RubyMoney/google_currency)
257
- - [nordea](https://github.com/k33l0r/nordea)
381
+ - [eu_central_bank](https://github.com/RubyMoney/eu_central_bank)
382
+ - [google_currency](https://github.com/RubyMoney/google_currency)
383
+ - [currencylayer](https://github.com/askuratovsky/currencylayer)
384
+ - [nordea](https://github.com/matiaskorhonen/nordea)
258
385
  - [nbrb_currency](https://github.com/slbug/nbrb_currency)
386
+ - [money-currencylayer-bank](https://github.com/phlegx/money-currencylayer-bank)
259
387
  - [money-open-exchange-rates](https://github.com/spk/money-open-exchange-rates)
260
388
  - [money-historical-bank](https://github.com/atwam/money-historical-bank)
261
389
  - [russian_central_bank](https://github.com/rmustafin/russian_central_bank)
390
+ - [money-uphold-bank](https://github.com/subvisual/money-uphold-bank)
391
+
392
+ ## Formatting
393
+
394
+ There are several formatting rules for when `Money#format` is called. For more information, check out the [formatting module source](https://github.com/RubyMoney/money/blob/master/lib/money/money/formatter.rb), or read the latest release's [rdoc version](http://www.rubydoc.info/gems/money/Money/Formatter).
395
+
396
+ If you wish to format money according to the EU's [Rules for expressing monetary units](http://publications.europa.eu/code/en/en-370303.htm#position) in either English, Irish, Latvian or Maltese:
397
+
398
+ ```ruby
399
+ m = Money.from_cents('123', :gbp) # => #<Money fractional:123 currency:GBP>
400
+ m.format(symbol: m.currency.to_s + ' ') # => "GBP 1.23"
401
+ ```
402
+
403
+ ## Rounding
404
+
405
+ By default, `Money` objects are rounded to the nearest cent and the additional precision is not preserved:
406
+
407
+ ```ruby
408
+ Money.from_amount(2.34567).format #=> "$2.35"
409
+ ```
410
+
411
+ To retain the additional precision, you will also need to set `infinite_precision` to `true`.
412
+
413
+ ```ruby
414
+ Money.default_infinite_precision = true
415
+ Money.from_amount(2.34567).format #=> "$2.34567"
416
+ ```
417
+
418
+ To round to the nearest cent (or anything more precise), you can use the `round` method. However, note that the `round` method on a `Money` object does not work the same way as a normal Ruby `Float` object. Money's `round` method accepts different arguments. The first argument to the round method is the rounding mode, while the second argument is the level of precision relative to the cent.
419
+
420
+ ```
421
+ # Float
422
+ 2.34567.round #=> 2
423
+ 2.34567.round(2) #=> 2.35
424
+
425
+ # Money
426
+ Money.default_infinite_precision = true
427
+ Money.from_cents(2.34567).format #=> "$0.0234567"
428
+ Money.from_cents(2.34567).round.format #=> "$0.02"
429
+ Money.from_cents(2.34567).round(BigDecimal::ROUND_HALF_UP, 2).format #=> "$0.0235"
430
+ ```
431
+
432
+ You can set the default rounding mode by passing one of the `BigDecimal` mode enumerables like so:
433
+ ```ruby
434
+ Money.rounding_mode = BigDecimal::ROUND_HALF_EVEN
435
+ ```
436
+ See [BigDecimal::ROUND_MODE](https://ruby-doc.org/stdlib-2.5.1/libdoc/bigdecimal/rdoc/BigDecimal.html#ROUND_MODE) for more information
262
437
 
263
438
  ## Ruby on Rails
264
439
 
265
- To integrate money in a Rails application use [money-rails](http://github.com/RubyMoney/money-rails).
440
+ To integrate money in a Rails application use [money-rails](https://github.com/RubyMoney/money-rails).
266
441
 
267
442
  For deprecated methods of integrating with Rails, check [the wiki](https://github.com/RubyMoney/money/wiki).
268
443
 
269
- ## I18n
444
+ ## Localization
270
445
 
271
- If you want thousands seperator and decimal mark to be same across all
272
- currencies this can be defined in your `I18n` translation files.
446
+ In order to localize formatting you can use `I18n` gem:
273
447
 
274
- In an rails application this may look like:
448
+ ```ruby
449
+ Money.locale_backend = :i18n
450
+ ```
451
+
452
+ With this enabled a thousands seperator and a decimal mark will get looked up in your `I18n` translation files. In a Rails application this may look like:
275
453
 
276
454
  ```yml
277
455
  # config/locale/en.yml
278
456
  en:
279
- number:
280
- format:
281
- delimiter: ","
282
- separator: "."
283
- # or
284
457
  number:
285
458
  currency:
286
459
  format:
287
460
  delimiter: ","
288
461
  separator: "."
462
+ # falling back to
463
+ number:
464
+ format:
465
+ delimiter: ","
466
+ separator: "."
467
+ ```
468
+
469
+ For this example `Money.from_cents(123456789, "SEK").format` will return `1,234,567.89
470
+ kr` which otherwise would have returned `1 234 567,89 kr`.
471
+
472
+ This will work seamlessly with [rails-i18n](https://github.com/svenfuchs/rails-i18n) gem that already has a lot of locales defined.
473
+
474
+ If you wish to disable this feature and use defaults instead:
475
+
476
+ ``` ruby
477
+ Money.locale_backend = nil
478
+ ```
479
+
480
+ ### Deprecation
481
+
482
+ The current default behaviour always checks the I18n locale first, falling back to "per currency"
483
+ localization. This is now deprecated and will be removed in favour of explicitly defined behaviour
484
+ in the next major release.
485
+
486
+ If you would like to use I18n localization (formatting depends on the locale):
487
+
488
+ ```ruby
489
+ Money.locale_backend = :i18n
490
+
491
+ # example (using default localization from rails-i18n):
492
+ I18n.locale = :en
493
+ Money.from_cents(10_000_00, 'USD').format # => $10,000.00
494
+ Money.from_cents(10_000_00, 'EUR').format # => €10,000.00
495
+
496
+ I18n.locale = :es
497
+ Money.from_cents(10_000_00, 'USD').format # => $10.000,00
498
+ Money.from_cents(10_000_00, 'EUR').format # => €10.000,00
289
499
  ```
290
500
 
291
- For this example `Money.new(123456789, "SEK").format` will return `1,234,567.89
292
- kr` which otherwise will return `1 234 567,89 kr`.
501
+ If you need to localize the position of the currency symbol, you
502
+ have to pass it manually. *Note: this will become the default formatting
503
+ behavior in the next version.*
504
+
505
+ ```ruby
506
+ I18n.locale = :fr
507
+ format = I18n.t :format, scope: 'number.currency.format'
508
+ Money.from_cents(10_00, 'EUR').format(format: format) # => 10,00 €
509
+ ```
510
+
511
+ For the legacy behaviour of "per currency" localization (formatting depends only on currency):
512
+
513
+ ```ruby
514
+ Money.locale_backend = :currency
515
+
516
+ # example:
517
+ Money.from_cents(10_000_00, 'USD').format # => $10,000.00
518
+ Money.from_cents(10_000_00, 'EUR').format # => €10.000,00
519
+ ```
293
520
 
294
- If you wish to disable this feature:
521
+ In case you don't need localization and would like to use default values (can be redefined using
522
+ `Money.default_formatting_rules`):
523
+
524
+ ```ruby
525
+ Money.locale_backend = nil
526
+
527
+ # example:
528
+ Money.from_cents(10_000_00, 'USD').format # => $10000.00
529
+ Money.from_cents(10_000_00, 'EUR').format # => €10000.00
530
+ ```
531
+
532
+ ## Collection
533
+
534
+ In case you're working with collections of `Money` instances, have a look at [money-collection](https://github.com/RubyMoney/money-collection)
535
+ for improved performance and accuracy.
536
+
537
+ ### Troubleshooting
538
+
539
+ If you don't have some locale and don't want to get a runtime error such as:
540
+
541
+ I18n::InvalidLocale: :en is not a valid locale
542
+
543
+ Set the following:
295
544
  ``` ruby
296
- Money.use_i18n = false
545
+ I18n.enforce_available_locales = false
297
546
  ```
298
547
 
299
- *Note: There are several formatting rules for when `Money#format` is called. For more information, check out the [formatting module](https://github.com/RubyMoney/money/blob/master/lib/money/money/formatting.rb).*
548
+ ## Heuristics
549
+
550
+ Prior to v6.9.0 heuristic analysis of string input was part of this gem. Since then it was extracted in to [money-heuristics gem](https://github.com/RubyMoney/money-heuristics).
300
551
 
301
552
  ## Migration Notes
302
553
 
@@ -8,6 +8,7 @@
8
8
  "subunit": "Sent",
9
9
  "subunit_to_unit": 100,
10
10
  "symbol_first": false,
11
+ "format": "%n %u",
11
12
  "html_entity": "",
12
13
  "decimal_mark": ".",
13
14
  "thousands_separator": ",",
@@ -30,6 +31,54 @@
30
31
  "iso_numeric": "288",
31
32
  "smallest_denomination": 1
32
33
  },
34
+ "ltl": {
35
+ "priority": 100,
36
+ "iso_code": "LTL",
37
+ "name": "Lithuanian Litas",
38
+ "symbol": "Lt",
39
+ "alternate_symbols": [],
40
+ "subunit": "Centas",
41
+ "subunit_to_unit": 100,
42
+ "symbol_first": false,
43
+ "format": "%n %u",
44
+ "html_entity": "",
45
+ "decimal_mark": ".",
46
+ "thousands_separator": ",",
47
+ "iso_numeric": "440",
48
+ "smallest_denomination": 1
49
+ },
50
+ "lvl": {
51
+ "priority": 100,
52
+ "iso_code": "LVL",
53
+ "name": "Latvian Lats",
54
+ "symbol": "Ls",
55
+ "alternate_symbols": [],
56
+ "subunit": "Santīms",
57
+ "subunit_to_unit": 100,
58
+ "symbol_first": true,
59
+ "html_entity": "",
60
+ "decimal_mark": ".",
61
+ "thousands_separator": ",",
62
+ "iso_numeric": "428",
63
+ "smallest_denomination": 1
64
+ },
65
+ "mro": {
66
+ "priority": 100,
67
+ "iso_code": "MRO",
68
+ "name": "Mauritanian Ouguiya",
69
+ "symbol": "UM",
70
+ "disambiguate_symbol": "A-UM",
71
+ "alternate_symbols": [],
72
+ "subunit": "Khoums",
73
+ "subunit_to_unit": 5,
74
+ "symbol_first": false,
75
+ "format": "%n %u",
76
+ "html_entity": "",
77
+ "decimal_mark": ".",
78
+ "thousands_separator": ",",
79
+ "iso_numeric": "478",
80
+ "smallest_denomination": 1
81
+ },
33
82
  "mtl": {
34
83
  "priority": 100,
35
84
  "iso_code": "MTL",
@@ -54,6 +103,7 @@
54
103
  "subunit": "Tennesi",
55
104
  "subunit_to_unit": 100,
56
105
  "symbol_first": false,
106
+ "format": "%n %u",
57
107
  "html_entity": "",
58
108
  "decimal_mark": ".",
59
109
  "thousands_separator": ",",
@@ -139,5 +189,20 @@
139
189
  "thousands_separator": ",",
140
190
  "iso_numeric": "935",
141
191
  "smallest_denomination": 100
192
+ },
193
+ "vef": {
194
+ "priority": 100,
195
+ "iso_code": "VEF",
196
+ "name": "Venezuelan Bolívar",
197
+ "symbol": "Bs.F",
198
+ "alternate_symbols": ["Bs"],
199
+ "subunit": "Céntimo",
200
+ "subunit_to_unit": 100,
201
+ "symbol_first": true,
202
+ "html_entity": "",
203
+ "decimal_mark": ",",
204
+ "thousands_separator": ".",
205
+ "iso_numeric": "937",
206
+ "smallest_denomination": 1
142
207
  }
143
208
  }