money 6.5.1 → 6.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +209 -5
- data/LICENSE +18 -16
- data/README.md +321 -70
- data/config/currency_backwards_compatible.json +65 -0
- data/config/currency_iso.json +280 -94
- data/config/currency_non_iso.json +101 -3
- data/lib/money/bank/base.rb +1 -3
- data/lib/money/bank/variable_exchange.rb +88 -96
- data/lib/money/currency/heuristics.rb +1 -143
- data/lib/money/currency/loader.rb +15 -13
- data/lib/money/currency.rb +98 -81
- data/lib/money/locale_backend/base.rb +7 -0
- data/lib/money/locale_backend/currency.rb +11 -0
- data/lib/money/locale_backend/errors.rb +6 -0
- data/lib/money/locale_backend/i18n.rb +25 -0
- data/lib/money/locale_backend/legacy.rb +28 -0
- data/lib/money/money/allocation.rb +46 -0
- data/lib/money/money/arithmetic.rb +97 -52
- data/lib/money/money/constructors.rb +5 -6
- data/lib/money/money/formatter.rb +399 -0
- data/lib/money/money/formatting_rules.rb +142 -0
- data/lib/money/money/locale_backend.rb +22 -0
- data/lib/money/money.rb +268 -194
- data/lib/money/rates_store/memory.rb +120 -0
- data/lib/money/version.rb +1 -1
- data/money.gemspec +15 -20
- metadata +36 -59
- data/.coveralls.yml +0 -1
- data/.gitignore +0 -22
- data/.travis.yml +0 -13
- data/AUTHORS +0 -116
- data/CONTRIBUTING.md +0 -17
- data/Gemfile +0 -7
- data/Rakefile +0 -17
- data/lib/money/money/formatting.rb +0 -386
- data/spec/bank/base_spec.rb +0 -77
- data/spec/bank/single_currency_spec.rb +0 -11
- data/spec/bank/variable_exchange_spec.rb +0 -275
- data/spec/currency/heuristics_spec.rb +0 -84
- data/spec/currency_spec.rb +0 -321
- data/spec/money/arithmetic_spec.rb +0 -568
- data/spec/money/constructors_spec.rb +0 -75
- data/spec/money/formatting_spec.rb +0 -667
- data/spec/money_spec.rb +0 -745
- 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.
|
4
|
-
[![Build Status](https://travis-ci.org/RubyMoney/money.
|
5
|
-
[![Code Climate](https://codeclimate.com/github/RubyMoney/money.
|
6
|
-
[![
|
7
|
-
[![
|
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
|
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
|
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](
|
38
|
-
- [API Documentation](http://rubydoc.info/gems/money/frames)
|
39
|
-
- [Git Repository](
|
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.
|
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.
|
72
|
-
Money.
|
73
|
-
Money.
|
74
|
-
Money.
|
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.
|
78
|
-
Money.
|
79
|
-
Money.
|
80
|
-
Money.
|
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.
|
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.
|
95
|
-
Money.
|
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.
|
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
|
-
:
|
113
|
-
:
|
114
|
-
:
|
115
|
-
:
|
116
|
-
:
|
117
|
-
:
|
118
|
-
:
|
119
|
-
:
|
120
|
-
:
|
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
|
-
- `:
|
136
|
-
- `:
|
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](
|
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
|
-
# => [
|
185
|
+
# => [:usd, :eur, :gbp, :aud, :cad, :jpy]
|
175
186
|
|
176
187
|
all_currencies(Money::Currency.table)
|
177
|
-
# => [
|
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 `
|
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
|
-
[
|
196
|
-
information.
|
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
|
200
|
-
Money::Currency.new("JPY").exponent # => 0
|
201
|
-
Money::Currency.new("MGA").exponent # =>
|
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.
|
223
|
-
Money.ca_dollar(100).exchange_to("USD") # => Money.
|
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.
|
230
|
-
Money.
|
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.
|
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
|
-
|
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 =
|
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](
|
256
|
-
- [google_currency](
|
257
|
-
- [
|
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](
|
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
|
-
##
|
444
|
+
## Localization
|
270
445
|
|
271
|
-
|
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
|
-
|
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
|
-
|
292
|
-
|
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
|
-
|
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
|
-
|
545
|
+
I18n.enforce_available_locales = false
|
297
546
|
```
|
298
547
|
|
299
|
-
|
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
|
}
|