money 6.9.0 → 6.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +131 -3
  3. data/LICENSE +17 -17
  4. data/README.md +181 -71
  5. data/config/currency_backwards_compatible.json +65 -0
  6. data/config/currency_iso.json +119 -56
  7. data/config/currency_non_iso.json +35 -2
  8. data/lib/money/bank/variable_exchange.rb +22 -12
  9. data/lib/money/currency/loader.rb +15 -13
  10. data/lib/money/currency.rb +38 -39
  11. data/lib/money/locale_backend/base.rb +7 -0
  12. data/lib/money/locale_backend/currency.rb +11 -0
  13. data/lib/money/locale_backend/errors.rb +6 -0
  14. data/lib/money/locale_backend/i18n.rb +25 -0
  15. data/lib/money/locale_backend/legacy.rb +28 -0
  16. data/lib/money/money/allocation.rb +46 -0
  17. data/lib/money/money/arithmetic.rb +33 -15
  18. data/lib/money/money/constructors.rb +1 -2
  19. data/lib/money/money/formatter.rb +399 -0
  20. data/lib/money/money/formatting_rules.rb +142 -0
  21. data/lib/money/money/locale_backend.rb +22 -0
  22. data/lib/money/money.rb +235 -187
  23. data/lib/money/rates_store/memory.rb +24 -24
  24. data/lib/money/version.rb +1 -1
  25. data/money.gemspec +14 -8
  26. metadata +36 -56
  27. data/.coveralls.yml +0 -1
  28. data/.gitignore +0 -23
  29. data/.rspec +0 -1
  30. data/.travis.yml +0 -26
  31. data/AUTHORS +0 -126
  32. data/CONTRIBUTING.md +0 -17
  33. data/Gemfile +0 -16
  34. data/Rakefile +0 -17
  35. data/lib/money/money/formatting.rb +0 -426
  36. data/spec/bank/base_spec.rb +0 -79
  37. data/spec/bank/single_currency_spec.rb +0 -13
  38. data/spec/bank/variable_exchange_spec.rb +0 -265
  39. data/spec/currency/heuristics_spec.rb +0 -11
  40. data/spec/currency/loader_spec.rb +0 -19
  41. data/spec/currency_spec.rb +0 -359
  42. data/spec/money/arithmetic_spec.rb +0 -693
  43. data/spec/money/constructors_spec.rb +0 -103
  44. data/spec/money/formatting_spec.rb +0 -757
  45. data/spec/money_spec.rb +0 -778
  46. data/spec/rates_store/memory_spec.rb +0 -69
  47. data/spec/spec_helper.rb +0 -28
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: f268faeee9a1901f8a4e482e8497370697eb436a
4
- data.tar.gz: 54f37ca793f33929f7c1dd10de33d58c813495fe
2
+ SHA256:
3
+ metadata.gz: 3de47437ec002ed24a400508cac96b2ff6812f484c666fe3db3a82e921a805c0
4
+ data.tar.gz: f96755602e56ea81d734b7505e7cfc88caaa948d7a8d285eeb470801028c15b9
5
5
  SHA512:
6
- metadata.gz: b9d33bfe048a6ba6fe92391ac9223a92268f31bd6c1f0ef932f2d202fd3a45e7df013c5c96d5ac99b98aacde1ece7a905fda77949aa9e4ad7625698b16b5914f
7
- data.tar.gz: b3b255302aec3569a1b7e1b4dc5a7e1a77b1b4129c09eb65f295461eadc48cc342f09de81236a229a6d4139a5038069108fdc53660d09255c9d3fa1130d22a02
6
+ metadata.gz: 2f8cd71611e96a80cb733651675cb6fac59d358cb7c9576c8c264abbfec6eb1da11b8cbe2af12cdfb070e5dd01cd74f6fdc70772da16aa4c2abc5248b13fca3c
7
+ data.tar.gz: '092ba5a188eb29d462431e94420e1c6d7a7f9a4a59c0895f66a4a1cf92cfaa37cbc1bc344a241f5f8cc9fc4e998189164bc2d0ab11480a589fe7bb0e341754ba'
data/CHANGELOG.md CHANGED
@@ -1,5 +1,133 @@
1
1
  # Changelog
2
2
 
3
+ ## 6.16.0
4
+
5
+ - Add `Money.from_cents` alias as a more explicit initializer, it's the same as `Money.new`
6
+
7
+ ## 6.15.0
8
+
9
+ - Add :delimiter_pattern option to the Formatter
10
+
11
+ ## 6.14.1
12
+
13
+ - Fix CHF format regression introduced in v6.14.0
14
+ - Fix deprecation warning in #format_decimal_part
15
+
16
+ ## 6.14.0
17
+
18
+ - Fix Bahraini dinar symbol
19
+ - Raise exception when default currency is not set or passed as parameter
20
+ - Allow specifying default_bank as a lambda
21
+ - Allow passing a default format in currencies definition only valid without symbol_position
22
+ - Always allow comparison with zero Money
23
+ - Rename Money.infinite_precision to default_infinite_precision
24
+ - Add Currency.reset! method to reload all the default currency definitions
25
+ - Fix edgecase for Money#allocate when applying to array of all zero values
26
+
27
+ ## 6.13.8
28
+ - Update symbol for XOF
29
+ - Update UYU currency symbol
30
+ - Allow double conversion using same bank
31
+ - Warn when using unsafe serializer for rate import
32
+ - Move Icelandic symbol after the amount
33
+
34
+ ## 6.13.7
35
+ - Improve deprecation warnings for the upcoming major release
36
+
37
+ ## 6.13.6
38
+ - Fix a regression introduced in 6.13.5 that broken RatesStore::Memory subclasses
39
+
40
+ ## 6.13.5
41
+ - Raise warning on using Money.default_currency
42
+ - Raise warning on using default Money.rounding_mode
43
+ - Add Second Ouguiya MRU 929 to currency iso file
44
+ - Add symbol for UZS
45
+ - Use monitor for recursive mutual exclusion in RatesStore::Memory
46
+ - Allow passing store as a string to Money::Bank::VariableExchange (to support Rails 6)
47
+
48
+ ## 6.13.4
49
+ - Update currency config for Zambian Kwacha (ZMW)
50
+ - Do not modify options passed to FormattingRules
51
+
52
+ ## 6.13.3
53
+ - Remove specs from the packaged gem
54
+ - Use Currency::Loader directly without extending
55
+ - Add Money.with_rounding_mode as a replacement for calling Money.rounding_mode with a block
56
+ - Fix currency search for two digit ISO numbers
57
+ - Add description to TypeError raised by +/- operations
58
+
59
+ ## 6.13.2
60
+ - Prevent Money initialization with non-finite amounts
61
+ - Convert the fractional value of a Money object to BigDecimal when initializing
62
+ - Offer replacements for currency position deprecations
63
+ - Fix Peruvian Sol symbol
64
+ - Lock i18n to <= 1.2.0 for older (< 2.3) rubies
65
+ - Prevent Divide By Zero in `Money#allocate`
66
+
67
+ ## 6.13.1
68
+ - Add bolívar soberano (VES)
69
+ - Deprecate bolívar fuerte (VEF)
70
+ - Deprecate old `#format` rules passed as a symbol
71
+ - Clarify `use_i18n` deprecation
72
+ - Add `:currency` locale_backend for explicit per-currency localization
73
+
74
+ ## 6.13.0
75
+ - Add :format option to the Formatter
76
+ - Add ruby 2.6.0 support
77
+ - Performance improvement (lazy stringify currency keys)
78
+ - Add `Money.locale_backend` for translation lookups
79
+ - Deprecate `use_i18n` flag in favour of `locale_backend = :i18n`
80
+ - Deprecate old formatting rules in favour of `:format`
81
+ - LVL and LTL are no longer used
82
+ - Add `Currency#iso?` for checking if currency is iso or not
83
+ - Relax versions-lock of `i18n` and `rspec` dependencies
84
+ - Add Bitcoin Cash
85
+ - Fix incorrect behaviour of `Currency#find_by_currency_iso` when given empty input
86
+
87
+ ## 6.12.0
88
+ - Remove caching of `.empty`/`.zero`
89
+ - Preserve assigned bank when rounding
90
+ - Always round the fractional part when calling `#round`
91
+ - Wrap all amount parts when `:html_wrap` option is used
92
+ - Deprecate `#currency_as_string` and `#currency_as_string=` (in favour of `#with_currency`)
93
+ - Add `#with_currency` for swapping the currency
94
+ - Rewrite allocate/split (fixing some penny losing issues)
95
+
96
+ ## 6.11.3
97
+ - Fix regression: if enabled use i18n locales in Money#to_s
98
+
99
+ ## 6.11.2
100
+ - Fix regression: ignore formatting defaults for Money#to_s
101
+
102
+ ## 6.11.1
103
+ - Fix issue with adding non-USD money to zero (used when calling `.sum` on an array)
104
+
105
+ ## 6.11.0
106
+ - Support i18n 1.0
107
+ - Update yard dependency to 0.9.11
108
+ - Support for ruby 2.5.0
109
+ - Add inheritance for currency definitions
110
+ - Added new symbol for bitcoin denomination
111
+ - Specify custom rounding precision when using `infinite_precision`
112
+ - Allow splits with sums greater than 1
113
+ - Prevent arithmetic methods from losing reference to the bank
114
+ - Fix coerced zero numeric subtraction
115
+ - Fix south asian formatting to support whole numbers
116
+ - Refactor formatting logic
117
+
118
+ ## 6.10.1
119
+ - Fix an issue with Money.empty memoization
120
+
121
+ ## 6.10.0
122
+ - Added support for i18n version 0.9
123
+ - Disabled rounding when verifying allocation splits
124
+ - Added Chinese Yuan Offshore (CNH)
125
+ - Fixed html_entity for ARS
126
+ - Fixed KZT symbol
127
+ - Allowed comparing cross currency when both are zero
128
+ - Fixed memory rate store
129
+ - Corrected HUF subunit and thousands separator config
130
+
3
131
  ## 6.9.0
4
132
  - Extracted heuristics into money-heuristics gem
5
133
 
@@ -148,7 +276,7 @@
148
276
  - Works on Ruby 1.8.7
149
277
  - Update deps
150
278
  - Depreciate Money.parse
151
- - Passing :symbol => false when formatting 'JPY' currency in :ja locale
279
+ - Passing symbol: false when formatting 'JPY' currency in :ja locale
152
280
  will work as expected
153
281
  - Divide now obeys the specified rounding mode
154
282
  - Add Money#round method. This is helpful when working in infinite_precision mode and would like to perform rounding at specific points in your work flow.
@@ -331,7 +459,7 @@ Features
331
459
 
332
460
  Bugfixes
333
461
  --------
334
- - Fixed issue with #format(:no_cents => true) (thanks Romain & Julien)
462
+ - Fixed issue with #format(no_cents: true) (thanks Romain & Julien)
335
463
 
336
464
  Money 3.5.5
337
465
  ===========
@@ -418,7 +546,7 @@ Features
418
546
  - Deprecated `Money#format` with separate params instead of Hash. Deprecation
419
547
  target set to Money 3.5.0.
420
548
  ([#issue/31](http://github.com/RubyMoney/money/issues/31))
421
- - Deprecated `Money#new(0, :currency => "EUR")` in favor of
549
+ - Deprecated `Money#new(0, currency: "EUR")` in favor of
422
550
  `Money#new(0, "EUR")`. Deprecation target set to Money 3.5.0.
423
551
  ([#issue/31](http://github.com/RubyMoney/money/issues/31))
424
552
  - Throw ArgumentError when trying to multiply two Money objects together.
data/LICENSE CHANGED
@@ -1,23 +1,23 @@
1
- The MIT License (MIT)
1
+ MIT License
2
2
 
3
3
  Copyright (c) 2005 Tobias Lutke
4
4
  Copyright (c) 2008 Phusion
5
+ Copyright (c) 2021 Shane Emmons
5
6
 
6
- Permission is hereby granted, free of charge, to any person obtaining
7
- a copy of this software and associated documentation files (the
8
- "Software"), to deal in the Software without restriction, including
9
- without limitation the rights to use, copy, modify, merge, publish,
10
- distribute, sublicense, and/or sell copies of the Software, and to
11
- permit persons to whom the Software is furnished to do so, subject to
12
- the following conditions:
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
13
 
14
- The above copyright notice and this permission notice shall be
15
- included in all copies or substantial portions of the Software.
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
16
 
17
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
data/README.md CHANGED
@@ -3,9 +3,7 @@
3
3
  [![Gem Version](https://badge.fury.io/rb/money.svg)](https://rubygems.org/gems/money)
4
4
  [![Build Status](https://travis-ci.org/RubyMoney/money.svg?branch=master)](https://travis-ci.org/RubyMoney/money)
5
5
  [![Code Climate](https://codeclimate.com/github/RubyMoney/money.svg)](https://codeclimate.com/github/RubyMoney/money)
6
- [![Coverage Status](https://coveralls.io/repos/RubyMoney/money/badge.svg?branch=master)](https://coveralls.io/r/RubyMoney/money?branch=master)
7
6
  [![Inline docs](https://inch-ci.org/github/RubyMoney/money.svg)](https://inch-ci.org/github/RubyMoney/money)
8
- [![Dependency Status](https://gemnasium.com/RubyMoney/money.svg)](https://gemnasium.com/RubyMoney/money)
9
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.
@@ -22,7 +20,7 @@ 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.
@@ -63,35 +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")
81
79
 
82
80
  # Unit to subunit conversions
83
- Money.from_amount(5, "USD") == Money.new(500, "USD") # 5 USD
84
- Money.from_amount(5, "JPY") == Money.new(5, "JPY") # 5 JPY
85
- Money.from_amount(5, "TND") == Money.new(5000, "TND") # 5 TND
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
86
84
 
87
85
  # Currency conversions
88
86
  some_code_to_setup_exchange_rates
89
- 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")
90
91
 
91
92
  # Formatting (see Formatting section for more options)
92
- Money.new(100, "USD").format #=> "$1.00"
93
- Money.new(100, "GBP").format #=> "£1.00"
94
- Money.new(100, "EUR").format #=> "€1.00"
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"
95
96
  ```
96
97
 
97
98
  ## Currency
@@ -101,15 +102,15 @@ The most part of `Money` APIs allows you to supply either a `String` or a
101
102
  `Money::Currency`.
102
103
 
103
104
  ``` ruby
104
- Money.new(1000, "USD") == Money.new(1000, Money::Currency.new("USD"))
105
- Money.new(1000, "EUR").currency == Money::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")
106
107
  ```
107
108
 
108
109
  A `Money::Currency` instance holds all the information about the currency,
109
110
  including the currency symbol, name and much more.
110
111
 
111
112
  ``` ruby
112
- currency = Money.new(1000, "USD").currency
113
+ currency = Money.from_cents(1000, "USD").currency
113
114
  currency.iso_code #=> "USD"
114
115
  currency.name #=> "United States Dollar"
115
116
  ```
@@ -119,15 +120,15 @@ below.
119
120
 
120
121
  ``` ruby
121
122
  curr = {
122
- :priority => 1,
123
- :iso_code => "USD",
124
- :iso_numeric => "840",
125
- :name => "United States Dollar",
126
- :symbol => "$",
127
- :subunit => "Cent",
128
- :subunit_to_unit => 100,
129
- :separator => ".",
130
- :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: ","
131
132
  }
132
133
 
133
134
  Money::Currency.register(curr)
@@ -142,8 +143,8 @@ The pre-defined set of attributes includes:
142
143
  - `:symbol` the currency symbol (UTF-8 encoded)
143
144
  - `:subunit` the name of the fractional monetary unit
144
145
  - `:subunit_to_unit` the proportion between the unit and the subunit
145
- - `:separator` character between the whole and fraction amounts
146
- - `:delimiter` character between each thousands place
146
+ - `:decimal_mark` character between the whole and fraction amounts
147
+ - `:thousands_separator` character between each thousands place
147
148
 
148
149
  All attributes except `:iso_code` are optional. Some attributes, such as
149
150
  `:symbol`, are used by the Money class to print out a representation of the
@@ -196,7 +197,7 @@ using:
196
197
  Money.default_currency = Money::Currency.new("CAD")
197
198
  ```
198
199
 
199
- 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.
200
201
 
201
202
  ### Currency Exponent
202
203
 
@@ -229,18 +230,18 @@ an example of how it works:
229
230
  Money.add_rate("USD", "CAD", 1.24515)
230
231
  Money.add_rate("CAD", "USD", 0.803115)
231
232
 
232
- Money.us_dollar(100).exchange_to("CAD") # => Money.new(124, "CAD")
233
- 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")
234
235
  ```
235
236
 
236
237
  Comparison and arithmetic operations work as expected:
237
238
 
238
239
  ``` ruby
239
- Money.new(1000, "USD") <=> Money.new(900, "USD") # => 1; 9.00 USD is smaller
240
- 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")
241
242
 
242
243
  Money.add_rate("USD", "EUR", 0.5)
243
- 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")
244
245
  ```
245
246
 
246
247
  ### Exchange rate stores
@@ -251,7 +252,7 @@ The default bank is initialized with an in-memory store for exchange rates.
251
252
  Money.default_bank = Money::Bank::VariableExchange.new(Money::RatesStore::Memory.new)
252
253
  ```
253
254
 
254
- You can pass you own store implementation, ie. for storing and retrieving rates off a database, file, cache, etc.
255
+ You can pass your own store implementation, i.e. for storing and retrieving rates off a database, file, cache, etc.
255
256
 
256
257
  ```ruby
257
258
  Money.default_bank = Money::Bank::VariableExchange.new(MyCustomStore.new)
@@ -268,7 +269,7 @@ Stores must implement the following interface:
268
269
  # @return [Numeric] rate.
269
270
  def add_rate(iso_from, iso_to, rate); end
270
271
 
271
- # Get rate. Must be idempotent. ie. adding the same rate must not produce duplicates.
272
+ # Get rate. Must be idempotent. i.e. adding the same rate must not produce duplicates.
272
273
  # @param [String] iso_from Currency ISO code. ex. 'USD'
273
274
  # @param [String] iso_to Currency ISO code. ex. 'CAD'
274
275
  #
@@ -312,25 +313,35 @@ def marshal_dump; end
312
313
  The following example implements an `ActiveRecord` store to save exchange rates to a database.
313
314
 
314
315
  ```ruby
315
- # DB columns :from[String], :to[String], :rate[Float]
316
+ # rails g model exchange_rate from:string to:string rate:float
316
317
 
317
- class ExchangeRate < ActiveRecord::Base
318
+ class ExchangeRate < ApplicationRecord
318
319
  def self.get_rate(from_iso_code, to_iso_code)
319
- rate = find_by(:from => from_iso_code, :to => to_iso_code)
320
- rate.present? ? rate.rate : nil
320
+ rate = find_by(from: from_iso_code, to: to_iso_code)
321
+ rate&.rate
321
322
  end
322
323
 
323
324
  def self.add_rate(from_iso_code, to_iso_code, rate)
324
- exrate = find_or_initialize_by(:from => from_iso_code, :to => to_iso_code)
325
+ exrate = find_or_initialize_by(from: from_iso_code, to: to_iso_code)
325
326
  exrate.rate = rate
326
327
  exrate.save!
327
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
328
337
  end
329
338
  ```
330
339
 
331
340
  Now you can use it with the default bank.
332
341
 
333
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")
334
345
  Money.default_bank = Money::Bank::VariableExchange.new(ExchangeRate)
335
346
 
336
347
  # Add to the underlying store
@@ -338,7 +349,7 @@ Money.default_bank.add_rate('USD', 'CAD', 0.9)
338
349
  # Retrieve from the underlying store
339
350
  Money.default_bank.get_rate('USD', 'CAD') # => 0.9
340
351
  # Exchanging amounts just works.
341
- Money.new(1000, 'USD').exchange_to('CAD') #=> #<Money fractional:900 currency:CAD>
352
+ Money.from_cents(1000, 'USD').exchange_to('CAD') #=> #<Money fractional:900 currency:CAD>
342
353
  ```
343
354
 
344
355
  There is nothing stopping you from creating store objects which scrapes
@@ -378,61 +389,160 @@ implementations.
378
389
  - [russian_central_bank](https://github.com/rmustafin/russian_central_bank)
379
390
  - [money-uphold-bank](https://github.com/subvisual/money-uphold-bank)
380
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
437
+
381
438
  ## Ruby on Rails
382
439
 
383
440
  To integrate money in a Rails application use [money-rails](https://github.com/RubyMoney/money-rails).
384
441
 
385
442
  For deprecated methods of integrating with Rails, check [the wiki](https://github.com/RubyMoney/money/wiki).
386
443
 
387
- ## I18n
444
+ ## Localization
388
445
 
389
- If you want thousands seperator and decimal mark to be same across all
390
- currencies this can be defined in your `I18n` translation files.
446
+ In order to localize formatting you can use `I18n` gem:
391
447
 
392
- 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:
393
453
 
394
454
  ```yml
395
455
  # config/locale/en.yml
396
456
  en:
397
- number:
398
- format:
399
- delimiter: ","
400
- separator: "."
401
- # or
402
457
  number:
403
458
  currency:
404
459
  format:
405
460
  delimiter: ","
406
461
  separator: "."
462
+ # falling back to
463
+ number:
464
+ format:
465
+ delimiter: ","
466
+ separator: "."
407
467
  ```
408
468
 
409
- For this example `Money.new(123456789, "SEK").format` will return `1,234,567.89
410
- kr` which otherwise will return `1 234 567,89 kr`.
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:
411
475
 
412
- If you wish to disable this feature:
413
476
  ``` ruby
414
- Money.use_i18n = false
477
+ Money.locale_backend = nil
415
478
  ```
416
479
 
417
- ### Troubleshooting
480
+ ### Deprecation
418
481
 
419
- If you get a runtime error such as:
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.
420
485
 
421
- I18n::InvalidLocale: :en is not a valid locale
486
+ If you would like to use I18n localization (formatting depends on the locale):
422
487
 
423
- Set the following:
424
- ``` ruby
425
- I18n.enforce_available_locales = false
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
426
499
  ```
427
500
 
428
- ## Formatting
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.*
429
504
 
430
- 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/formatting.rb), or read the latest release's [rdoc version](http://www.rubydoc.info/gems/money/Money/Formatting).
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):
431
512
 
432
- 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:
433
513
  ```ruby
434
- m = Money.new('123', :gbp) # => #<Money fractional:123 currency:GBP>
435
- m.format( symbol: m.currency.to_s + ' ') # => "GBP 1.23"
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
+ ```
520
+
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:
544
+ ``` ruby
545
+ I18n.enforce_available_locales = false
436
546
  ```
437
547
 
438
548
  ## Heuristics