money 6.13.2 → 6.13.3
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 +4 -4
- data/CHANGELOG.md +7 -0
- data/lib/money/currency.rb +3 -3
- data/lib/money/currency/loader.rb +15 -13
- data/lib/money/money.rb +21 -17
- data/lib/money/money/arithmetic.rb +17 -7
- data/lib/money/version.rb +1 -1
- data/money.gemspec +3 -3
- metadata +5 -47
- data/.coveralls.yml +0 -1
- data/.gitignore +0 -23
- data/.rspec +0 -2
- data/.travis.yml +0 -32
- data/AUTHORS +0 -131
- data/CONTRIBUTING.md +0 -17
- data/Gemfile +0 -17
- data/Rakefile +0 -17
- data/spec/bank/base_spec.rb +0 -79
- data/spec/bank/single_currency_spec.rb +0 -13
- data/spec/bank/variable_exchange_spec.rb +0 -265
- data/spec/currency/heuristics_spec.rb +0 -11
- data/spec/currency/loader_spec.rb +0 -19
- data/spec/currency_spec.rb +0 -400
- data/spec/locale_backend/currency_spec.rb +0 -15
- data/spec/locale_backend/i18n_spec.rb +0 -70
- data/spec/locale_backend/legacy_spec.rb +0 -74
- data/spec/money/allocation_spec.rb +0 -135
- data/spec/money/arithmetic_spec.rb +0 -756
- data/spec/money/constructors_spec.rb +0 -91
- data/spec/money/formatting_spec.rb +0 -859
- data/spec/money/locale_backend_spec.rb +0 -14
- data/spec/money_spec.rb +0 -894
- data/spec/rates_store/memory_spec.rb +0 -80
- data/spec/spec_helper.rb +0 -30
- data/spec/support/shared_examples/money_examples.rb +0 -14
@@ -1,14 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
describe Money::LocaleBackend do
|
4
|
-
describe '.find' do
|
5
|
-
it 'returns an initialized backend' do
|
6
|
-
expect(described_class.find(:legacy)).to be_a(Money::LocaleBackend::Legacy)
|
7
|
-
expect(described_class.find(:i18n)).to be_a(Money::LocaleBackend::I18n)
|
8
|
-
end
|
9
|
-
|
10
|
-
it 'raises an error if a backend is unknown' do
|
11
|
-
expect { described_class.find(:foo) }.to raise_error(Money::LocaleBackend::Unknown)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
data/spec/money_spec.rb
DELETED
@@ -1,894 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
describe Money do
|
4
|
-
describe '.locale_backend' do
|
5
|
-
after { Money.locale_backend = :legacy }
|
6
|
-
|
7
|
-
it 'sets the locale_backend' do
|
8
|
-
Money.locale_backend = :i18n
|
9
|
-
|
10
|
-
expect(Money.locale_backend).to be_a(Money::LocaleBackend::I18n)
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'sets the locale_backend to nil' do
|
14
|
-
Money.locale_backend = nil
|
15
|
-
|
16
|
-
expect(Money.locale_backend).to eq(nil)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
describe ".new" do
|
21
|
-
let(:initializing_value) { 1 }
|
22
|
-
subject(:money) { Money.new(initializing_value) }
|
23
|
-
|
24
|
-
it "should be an instance of `Money::Bank::VariableExchange`" do
|
25
|
-
expect(money.bank).to be Money::Bank::VariableExchange.instance
|
26
|
-
end
|
27
|
-
|
28
|
-
context 'given the initializing value is an integer' do
|
29
|
-
let(:initializing_value) { Integer(1) }
|
30
|
-
it 'stores the integer as the number of cents' do
|
31
|
-
expect(money.cents).to eq initializing_value
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
context 'given the initializing value is a float' do
|
36
|
-
context 'and the value is 1.00' do
|
37
|
-
let(:initializing_value) { 1.00 }
|
38
|
-
it { is_expected.to eq Money.new(1) }
|
39
|
-
end
|
40
|
-
|
41
|
-
context 'and the value is 1.01' do
|
42
|
-
let(:initializing_value) { 1.01 }
|
43
|
-
it { is_expected.to eq Money.new(1) }
|
44
|
-
end
|
45
|
-
|
46
|
-
context 'and the value is 1.50' do
|
47
|
-
let(:initializing_value) { 1.50 }
|
48
|
-
it { is_expected.to eq Money.new(2) }
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
context 'given the initializing value is a rational' do
|
53
|
-
let(:initializing_value) { Rational(1) }
|
54
|
-
it { is_expected.to eq Money.new(1) }
|
55
|
-
end
|
56
|
-
|
57
|
-
context 'given the initializing value is money' do
|
58
|
-
let(:initializing_value) { Money.new(1_00, Money::Currency.new('NZD')) }
|
59
|
-
it { is_expected.to eq initializing_value }
|
60
|
-
end
|
61
|
-
|
62
|
-
context "given the initializing value doesn't respond to .to_d" do
|
63
|
-
let(:initializing_value) { :"1" }
|
64
|
-
it { is_expected.to eq Money.new(1) }
|
65
|
-
end
|
66
|
-
|
67
|
-
context 'given a currency is not provided' do
|
68
|
-
subject(:money) { Money.new(initializing_value) }
|
69
|
-
|
70
|
-
it "should have the default currency" do
|
71
|
-
expect(money.currency).to eq Money.default_currency
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
context 'given a currency is provided' do
|
76
|
-
subject(:money) { Money.new(initializing_value, currency) }
|
77
|
-
|
78
|
-
context 'and the currency is NZD' do
|
79
|
-
let(:currency) { Money::Currency.new('NZD') }
|
80
|
-
|
81
|
-
it "should have NZD currency" do
|
82
|
-
expect(money.currency).to eq Money::Currency.new('NZD')
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
context 'and the currency is nil' do
|
87
|
-
let(:currency) { nil }
|
88
|
-
|
89
|
-
it "should have the default currency" do
|
90
|
-
expect(money.currency).to eq Money.default_currency
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
context 'non-finite value is given' do
|
96
|
-
let(:error) { 'must be initialized with a finite value' }
|
97
|
-
|
98
|
-
it 'raises an error when trying to initialize with Infinity' do
|
99
|
-
expect { Money.new('Infinity') }.to raise_error(ArgumentError, error)
|
100
|
-
expect { Money.new(BigDecimal('Infinity')) }.to raise_error(ArgumentError, error)
|
101
|
-
end
|
102
|
-
|
103
|
-
it 'raises an error when trying to initialize with NaN' do
|
104
|
-
expect { Money.new('NaN') }.to raise_error(ArgumentError, error)
|
105
|
-
expect { Money.new(BigDecimal('NaN')) }.to raise_error(ArgumentError, error)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
context "with infinite_precision", :infinite_precision do
|
110
|
-
context 'given the initializing value is 1.50' do
|
111
|
-
let(:initializing_value) { 1.50 }
|
112
|
-
|
113
|
-
it "should have the correct cents" do
|
114
|
-
expect(money.cents).to eq BigDecimal('1.50')
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
describe ".add_rate" do
|
121
|
-
before do
|
122
|
-
@default_bank = Money.default_bank
|
123
|
-
Money.default_bank = Money::Bank::VariableExchange.new
|
124
|
-
end
|
125
|
-
|
126
|
-
after do
|
127
|
-
Money.default_bank = @default_bank
|
128
|
-
end
|
129
|
-
|
130
|
-
it "saves rate into current bank" do
|
131
|
-
Money.add_rate("EUR", "USD", 10)
|
132
|
-
expect(Money.new(10_00, "EUR").exchange_to("USD")).to eq Money.new(100_00, "USD")
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
describe ".disallow_currency_conversions!" do
|
137
|
-
before do
|
138
|
-
@default_bank = Money.default_bank
|
139
|
-
end
|
140
|
-
|
141
|
-
after do
|
142
|
-
Money.default_bank = @default_bank
|
143
|
-
end
|
144
|
-
|
145
|
-
it "disallows conversions when doing money arithmetic" do
|
146
|
-
Money.disallow_currency_conversion!
|
147
|
-
expect { Money.new(100, "USD") + Money.new(100, "EUR") }.to raise_exception(Money::Bank::DifferentCurrencyError)
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
describe ".from_amount" do
|
152
|
-
it "accepts numeric values" do
|
153
|
-
expect(Money.from_amount(1, "USD")).to eq Money.new(1_00, "USD")
|
154
|
-
expect(Money.from_amount(1.0, "USD")).to eq Money.new(1_00, "USD")
|
155
|
-
expect(Money.from_amount("1".to_d, "USD")).to eq Money.new(1_00, "USD")
|
156
|
-
end
|
157
|
-
|
158
|
-
it "raises ArgumentError with unsupported argument" do
|
159
|
-
expect { Money.from_amount("1") }.to raise_error(ArgumentError)
|
160
|
-
expect { Money.from_amount(Object.new) }.to raise_error(ArgumentError)
|
161
|
-
end
|
162
|
-
|
163
|
-
it "converts given amount to subunits according to currency" do
|
164
|
-
expect(Money.from_amount(1, "USD")).to eq Money.new(1_00, "USD")
|
165
|
-
expect(Money.from_amount(1, "TND")).to eq Money.new(1_000, "TND")
|
166
|
-
expect(Money.from_amount(1, "JPY")).to eq Money.new(1, "JPY")
|
167
|
-
end
|
168
|
-
|
169
|
-
it "rounds the given amount to subunits" do
|
170
|
-
expect(Money.from_amount(4.444, "USD").amount).to eq "4.44".to_d
|
171
|
-
expect(Money.from_amount(5.555, "USD").amount).to eq "5.56".to_d
|
172
|
-
expect(Money.from_amount(444.4, "JPY").amount).to eq "444".to_d
|
173
|
-
expect(Money.from_amount(555.5, "JPY").amount).to eq "556".to_d
|
174
|
-
end
|
175
|
-
|
176
|
-
it "does not round the given amount when infinite_precision is set", :infinite_precision do
|
177
|
-
expect(Money.from_amount(4.444, "USD").amount).to eq "4.444".to_d
|
178
|
-
expect(Money.from_amount(5.555, "USD").amount).to eq "5.555".to_d
|
179
|
-
expect(Money.from_amount(444.4, "JPY").amount).to eq "444.4".to_d
|
180
|
-
expect(Money.from_amount(555.5, "JPY").amount).to eq "555.5".to_d
|
181
|
-
end
|
182
|
-
|
183
|
-
it "accepts an optional currency" do
|
184
|
-
expect(Money.from_amount(1).currency).to eq Money.default_currency
|
185
|
-
jpy = Money::Currency.wrap("JPY")
|
186
|
-
expect(Money.from_amount(1, jpy).currency).to eq jpy
|
187
|
-
expect(Money.from_amount(1, "JPY").currency).to eq jpy
|
188
|
-
end
|
189
|
-
|
190
|
-
it "accepts an optional bank" do
|
191
|
-
expect(Money.from_amount(1).bank).to eq Money.default_bank
|
192
|
-
bank = double "bank"
|
193
|
-
expect(Money.from_amount(1, "USD", bank).bank).to eq bank
|
194
|
-
end
|
195
|
-
|
196
|
-
it 'rounds using rounding_mode' do
|
197
|
-
expect(Money.from_amount(1.999).to_d).to eq 2
|
198
|
-
expect(Money.rounding_mode(BigDecimal::ROUND_DOWN) do
|
199
|
-
Money.from_amount(1.999).to_d
|
200
|
-
end).to eq 1.99
|
201
|
-
end
|
202
|
-
|
203
|
-
context 'given a currency is provided' do
|
204
|
-
context 'and the currency is nil' do
|
205
|
-
let(:currency) { nil }
|
206
|
-
|
207
|
-
it "should have the default currency" do
|
208
|
-
expect(Money.from_amount(1, currency).currency).to eq Money.default_currency
|
209
|
-
end
|
210
|
-
end
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
|
-
%w[cents pence].each do |units|
|
215
|
-
describe "##{units}" do
|
216
|
-
it "is a synonym of #fractional" do
|
217
|
-
expectation = Money.new(0)
|
218
|
-
def expectation.fractional
|
219
|
-
"expectation"
|
220
|
-
end
|
221
|
-
expect(expectation.cents).to eq "expectation"
|
222
|
-
end
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
describe "#fractional" do
|
227
|
-
it "returns the amount in fractional unit" do
|
228
|
-
expect(Money.new(1_00).fractional).to eq 1_00
|
229
|
-
end
|
230
|
-
|
231
|
-
it "stores fractional as an integer regardless of what is passed into the constructor" do
|
232
|
-
m = Money.new(100)
|
233
|
-
expect(m.fractional).to eq 100
|
234
|
-
expect(m.fractional).to be_a(Integer)
|
235
|
-
end
|
236
|
-
|
237
|
-
context "loading a serialized Money via YAML" do
|
238
|
-
|
239
|
-
let(:serialized) { <<YAML
|
240
|
-
!ruby/object:Money
|
241
|
-
fractional: 249.5
|
242
|
-
currency: !ruby/object:Money::Currency
|
243
|
-
id: :eur
|
244
|
-
priority: 2
|
245
|
-
iso_code: EUR
|
246
|
-
name: Euro
|
247
|
-
symbol: €
|
248
|
-
alternate_symbols: []
|
249
|
-
subunit: Cent
|
250
|
-
subunit_to_unit: 100
|
251
|
-
symbol_first: true
|
252
|
-
html_entity: ! '€'
|
253
|
-
decimal_mark: ! ','
|
254
|
-
thousands_separator: .
|
255
|
-
iso_numeric: '978'
|
256
|
-
mutex: !ruby/object:Mutex {}
|
257
|
-
last_updated: 2012-11-23 20:41:47.454438399 +02:00
|
258
|
-
YAML
|
259
|
-
}
|
260
|
-
|
261
|
-
it "uses BigDecimal when rounding" do
|
262
|
-
m = YAML::load serialized
|
263
|
-
expect(m).to be_a(Money)
|
264
|
-
expect(m.class.infinite_precision).to be false
|
265
|
-
expect(m.fractional).to eq 250 # 249.5 rounded up
|
266
|
-
expect(m.fractional).to be_a(Integer)
|
267
|
-
end
|
268
|
-
|
269
|
-
it "is a BigDecimal when using infinite_precision", :infinite_precision do
|
270
|
-
money = YAML::load serialized
|
271
|
-
expect(money.fractional).to be_a BigDecimal
|
272
|
-
end
|
273
|
-
end
|
274
|
-
|
275
|
-
context "user changes rounding_mode" do
|
276
|
-
after do
|
277
|
-
Money.rounding_mode = BigDecimal::ROUND_HALF_EVEN
|
278
|
-
end
|
279
|
-
|
280
|
-
context "with the setter" do
|
281
|
-
it "respects the rounding_mode" do
|
282
|
-
Money.rounding_mode = BigDecimal::ROUND_DOWN
|
283
|
-
expect(Money.new(1.9).fractional).to eq 1
|
284
|
-
|
285
|
-
Money.rounding_mode = BigDecimal::ROUND_UP
|
286
|
-
expect(Money.new(1.1).fractional).to eq 2
|
287
|
-
end
|
288
|
-
end
|
289
|
-
|
290
|
-
context "with a block" do
|
291
|
-
it "respects the rounding_mode" do
|
292
|
-
expect(Money.rounding_mode(BigDecimal::ROUND_DOWN) do
|
293
|
-
Money.new(1.9).fractional
|
294
|
-
end).to eq 1
|
295
|
-
|
296
|
-
expect(Money.rounding_mode(BigDecimal::ROUND_UP) do
|
297
|
-
Money.new(1.1).fractional
|
298
|
-
end).to eq 2
|
299
|
-
|
300
|
-
expect(Money.rounding_mode).to eq BigDecimal::ROUND_HALF_EVEN
|
301
|
-
end
|
302
|
-
|
303
|
-
it "works for multiplication within a block" do
|
304
|
-
Money.rounding_mode(BigDecimal::ROUND_DOWN) do
|
305
|
-
expect((Money.new(1_00) * "0.019".to_d).fractional).to eq 1
|
306
|
-
end
|
307
|
-
|
308
|
-
Money.rounding_mode(BigDecimal::ROUND_UP) do
|
309
|
-
expect((Money.new(1_00) * "0.011".to_d).fractional).to eq 2
|
310
|
-
end
|
311
|
-
|
312
|
-
expect(Money.rounding_mode).to eq BigDecimal::ROUND_HALF_EVEN
|
313
|
-
end
|
314
|
-
end
|
315
|
-
end
|
316
|
-
|
317
|
-
context "with infinite_precision", :infinite_precision do
|
318
|
-
it "returns the amount in fractional unit" do
|
319
|
-
expect(Money.new(1_00).fractional).to eq BigDecimal("100")
|
320
|
-
end
|
321
|
-
|
322
|
-
it "stores in fractional unit as an integer regardless of what is passed into the constructor" do
|
323
|
-
m = Money.new(100)
|
324
|
-
expect(m.fractional).to eq BigDecimal("100")
|
325
|
-
expect(m.fractional).to be_a(BigDecimal)
|
326
|
-
end
|
327
|
-
end
|
328
|
-
end
|
329
|
-
|
330
|
-
describe "#round_to_nearest_cash_value" do
|
331
|
-
it "rounds to the nearest possible cash value" do
|
332
|
-
money = Money.new(2350, "AED")
|
333
|
-
expect(money.round_to_nearest_cash_value).to eq 2350
|
334
|
-
|
335
|
-
money = Money.new(-2350, "AED")
|
336
|
-
expect(money.round_to_nearest_cash_value).to eq(-2350)
|
337
|
-
|
338
|
-
money = Money.new(2213, "AED")
|
339
|
-
expect(money.round_to_nearest_cash_value).to eq 2225
|
340
|
-
|
341
|
-
money = Money.new(-2213, "AED")
|
342
|
-
expect(money.round_to_nearest_cash_value).to eq(-2225)
|
343
|
-
|
344
|
-
money = Money.new(2212, "AED")
|
345
|
-
expect(money.round_to_nearest_cash_value).to eq 2200
|
346
|
-
|
347
|
-
money = Money.new(-2212, "AED")
|
348
|
-
expect(money.round_to_nearest_cash_value).to eq(-2200)
|
349
|
-
|
350
|
-
money = Money.new(178, "CHF")
|
351
|
-
expect(money.round_to_nearest_cash_value).to eq 180
|
352
|
-
|
353
|
-
money = Money.new(-178, "CHF")
|
354
|
-
expect(money.round_to_nearest_cash_value).to eq(-180)
|
355
|
-
|
356
|
-
money = Money.new(177, "CHF")
|
357
|
-
expect(money.round_to_nearest_cash_value).to eq 175
|
358
|
-
|
359
|
-
money = Money.new(-177, "CHF")
|
360
|
-
expect(money.round_to_nearest_cash_value).to eq(-175)
|
361
|
-
|
362
|
-
money = Money.new(175, "CHF")
|
363
|
-
expect(money.round_to_nearest_cash_value).to eq 175
|
364
|
-
|
365
|
-
money = Money.new(-175, "CHF")
|
366
|
-
expect(money.round_to_nearest_cash_value).to eq(-175)
|
367
|
-
|
368
|
-
money = Money.new(299, "USD")
|
369
|
-
expect(money.round_to_nearest_cash_value).to eq 299
|
370
|
-
|
371
|
-
money = Money.new(-299, "USD")
|
372
|
-
expect(money.round_to_nearest_cash_value).to eq(-299)
|
373
|
-
|
374
|
-
money = Money.new(300, "USD")
|
375
|
-
expect(money.round_to_nearest_cash_value).to eq 300
|
376
|
-
|
377
|
-
money = Money.new(-300, "USD")
|
378
|
-
expect(money.round_to_nearest_cash_value).to eq(-300)
|
379
|
-
|
380
|
-
money = Money.new(301, "USD")
|
381
|
-
expect(money.round_to_nearest_cash_value).to eq 301
|
382
|
-
|
383
|
-
money = Money.new(-301, "USD")
|
384
|
-
expect(money.round_to_nearest_cash_value).to eq(-301)
|
385
|
-
end
|
386
|
-
|
387
|
-
it "raises an exception if smallest denomination is not defined" do
|
388
|
-
money = Money.new(100, "XAG")
|
389
|
-
expect {money.round_to_nearest_cash_value}.to raise_error(Money::UndefinedSmallestDenomination)
|
390
|
-
end
|
391
|
-
|
392
|
-
it "returns a Integer when infinite_precision is not set" do
|
393
|
-
money = Money.new(100, "USD")
|
394
|
-
expect(money.round_to_nearest_cash_value).to be_a Integer
|
395
|
-
end
|
396
|
-
|
397
|
-
it "returns a BigDecimal when infinite_precision is set", :infinite_precision do
|
398
|
-
money = Money.new(100, "EUR")
|
399
|
-
expect(money.round_to_nearest_cash_value).to be_a BigDecimal
|
400
|
-
end
|
401
|
-
end
|
402
|
-
|
403
|
-
describe "#amount" do
|
404
|
-
it "returns the amount of cents as dollars" do
|
405
|
-
expect(Money.new(1_00).amount).to eq 1
|
406
|
-
end
|
407
|
-
|
408
|
-
it "respects :subunit_to_unit currency property" do
|
409
|
-
expect(Money.new(1_00, "USD").amount).to eq 1
|
410
|
-
expect(Money.new(1_000, "TND").amount).to eq 1
|
411
|
-
expect(Money.new(1, "VUV").amount).to eq 1
|
412
|
-
expect(Money.new(1, "CLP").amount).to eq 1
|
413
|
-
end
|
414
|
-
|
415
|
-
it "does not lose precision" do
|
416
|
-
expect(Money.new(100_37).amount).to eq 100.37
|
417
|
-
end
|
418
|
-
|
419
|
-
it 'produces a BigDecimal' do
|
420
|
-
expect(Money.new(1_00).amount).to be_a BigDecimal
|
421
|
-
end
|
422
|
-
end
|
423
|
-
|
424
|
-
describe "#dollars" do
|
425
|
-
it "is synonym of #amount" do
|
426
|
-
m = Money.new(0)
|
427
|
-
|
428
|
-
# Make a small expectation
|
429
|
-
def m.amount
|
430
|
-
5
|
431
|
-
end
|
432
|
-
|
433
|
-
expect(m.dollars).to eq 5
|
434
|
-
end
|
435
|
-
end
|
436
|
-
|
437
|
-
describe "#currency" do
|
438
|
-
it "returns the currency object" do
|
439
|
-
expect(Money.new(1_00, "USD").currency).to eq Money::Currency.new("USD")
|
440
|
-
end
|
441
|
-
end
|
442
|
-
|
443
|
-
describe "#currency_as_string" do
|
444
|
-
it "returns the iso_code of the currency object" do
|
445
|
-
expect(Money.new(1_00, "USD").currency_as_string).to eq "USD"
|
446
|
-
expect(Money.new(1_00, "EUR").currency_as_string).to eq "EUR"
|
447
|
-
end
|
448
|
-
end
|
449
|
-
|
450
|
-
describe "#currency_as_string=" do
|
451
|
-
it "sets the currency object using the provided string leaving cents intact" do
|
452
|
-
money = Money.new(100_00, "USD")
|
453
|
-
|
454
|
-
money.currency_as_string = "EUR"
|
455
|
-
expect(money.currency).to eq Money::Currency.new("EUR")
|
456
|
-
expect(money.cents).to eq 100_00
|
457
|
-
|
458
|
-
money.currency_as_string = "YEN"
|
459
|
-
expect(money.currency).to eq Money::Currency.new("YEN")
|
460
|
-
expect(money.cents).to eq 100_00
|
461
|
-
end
|
462
|
-
end
|
463
|
-
|
464
|
-
describe "#hash=" do
|
465
|
-
it "returns the same value for equal objects" do
|
466
|
-
expect(Money.new(1_00, "EUR").hash).to eq Money.new(1_00, "EUR").hash
|
467
|
-
expect(Money.new(2_00, "USD").hash).to eq Money.new(2_00, "USD").hash
|
468
|
-
expect(Money.new(1_00, "EUR").hash).not_to eq Money.new(2_00, "EUR").hash
|
469
|
-
expect(Money.new(1_00, "EUR").hash).not_to eq Money.new(1_00, "USD").hash
|
470
|
-
expect(Money.new(1_00, "EUR").hash).not_to eq Money.new(2_00, "USD").hash
|
471
|
-
end
|
472
|
-
|
473
|
-
it "can be used to return the intersection of Money object arrays" do
|
474
|
-
intersection = [Money.new(1_00, "EUR"), Money.new(1_00, "USD")] & [Money.new(1_00, "EUR")]
|
475
|
-
expect(intersection).to eq [Money.new(1_00, "EUR")]
|
476
|
-
end
|
477
|
-
end
|
478
|
-
|
479
|
-
describe "#symbol" do
|
480
|
-
it "works as documented" do
|
481
|
-
currency = Money::Currency.new("EUR")
|
482
|
-
expect(currency).to receive(:symbol).and_return("€")
|
483
|
-
expect(Money.new(0, currency).symbol).to eq "€"
|
484
|
-
|
485
|
-
currency = Money::Currency.new("EUR")
|
486
|
-
expect(currency).to receive(:symbol).and_return(nil)
|
487
|
-
expect(Money.new(0, currency).symbol).to eq "¤"
|
488
|
-
end
|
489
|
-
end
|
490
|
-
|
491
|
-
describe "#to_s" do
|
492
|
-
it "works as documented" do
|
493
|
-
expect(Money.new(10_00).to_s).to eq "10.00"
|
494
|
-
expect(Money.new(400_08).to_s).to eq "400.08"
|
495
|
-
expect(Money.new(-237_43).to_s).to eq "-237.43"
|
496
|
-
end
|
497
|
-
|
498
|
-
it "respects :subunit_to_unit currency property" do
|
499
|
-
expect(Money.new(10_00, "BHD").to_s).to eq "1.000"
|
500
|
-
expect(Money.new(10_00, "CNY").to_s).to eq "10.00"
|
501
|
-
end
|
502
|
-
|
503
|
-
it "does not have decimal when :subunit_to_unit == 1" do
|
504
|
-
expect(Money.new(10_00, "VUV").to_s).to eq "1000"
|
505
|
-
end
|
506
|
-
|
507
|
-
it "does not work when :subunit_to_unit == 5" do
|
508
|
-
expect(Money.new(10_00, "MGA").to_s).to eq "200.0"
|
509
|
-
end
|
510
|
-
|
511
|
-
it "respects :decimal_mark" do
|
512
|
-
expect(Money.new(10_00, "BRL").to_s).to eq "10,00"
|
513
|
-
end
|
514
|
-
|
515
|
-
context "using i18n" do
|
516
|
-
before { I18n.backend.store_translations(:en, number: { format: { separator: "." } }) }
|
517
|
-
after { reset_i18n }
|
518
|
-
|
519
|
-
it "respects decimal mark" do
|
520
|
-
expect(Money.new(10_00, "BRL").to_s).to eq "10.00"
|
521
|
-
end
|
522
|
-
end
|
523
|
-
|
524
|
-
context "with defaults set" do
|
525
|
-
before { Money.default_formatting_rules = { with_currency: true } }
|
526
|
-
after { Money.default_formatting_rules = nil }
|
527
|
-
|
528
|
-
it "ignores defaults" do
|
529
|
-
expect(Money.new(10_00, 'USD').to_s).to eq '10.00'
|
530
|
-
end
|
531
|
-
end
|
532
|
-
|
533
|
-
context "with infinite_precision", :infinite_precision do
|
534
|
-
it "shows fractional cents" do
|
535
|
-
expect(Money.new(1.05, "USD").to_s).to eq "0.0105"
|
536
|
-
end
|
537
|
-
|
538
|
-
it "suppresses fractional cents when there is none" do
|
539
|
-
expect(Money.new(1.0, "USD").to_s).to eq "0.01"
|
540
|
-
end
|
541
|
-
|
542
|
-
it "shows fractional if needed when :subunut_to_unit == 1" do
|
543
|
-
expect(Money.new(10_00.1, "VUV").to_s).to eq "1000.1"
|
544
|
-
end
|
545
|
-
end
|
546
|
-
end
|
547
|
-
|
548
|
-
describe "#to_d" do
|
549
|
-
it "works as documented" do
|
550
|
-
decimal = Money.new(10_00).to_d
|
551
|
-
expect(decimal).to be_a(BigDecimal)
|
552
|
-
expect(decimal).to eq 10.0
|
553
|
-
end
|
554
|
-
|
555
|
-
it "respects :subunit_to_unit currency property" do
|
556
|
-
decimal = Money.new(10_00, "BHD").to_d
|
557
|
-
expect(decimal).to be_a(BigDecimal)
|
558
|
-
expect(decimal).to eq 1.0
|
559
|
-
end
|
560
|
-
|
561
|
-
it "works with float :subunit_to_unit currency property" do
|
562
|
-
money = Money.new(10_00, "BHD")
|
563
|
-
allow(money.currency).to receive(:subunit_to_unit).and_return(1000.0)
|
564
|
-
|
565
|
-
decimal = money.to_d
|
566
|
-
expect(decimal).to be_a(BigDecimal)
|
567
|
-
expect(decimal).to eq 1.0
|
568
|
-
end
|
569
|
-
end
|
570
|
-
|
571
|
-
describe "#to_f" do
|
572
|
-
it "works as documented" do
|
573
|
-
expect(Money.new(10_00).to_f).to eq 10.0
|
574
|
-
end
|
575
|
-
|
576
|
-
it "respects :subunit_to_unit currency property" do
|
577
|
-
expect(Money.new(10_00, "BHD").to_f).to eq 1.0
|
578
|
-
end
|
579
|
-
end
|
580
|
-
|
581
|
-
describe "#to_i" do
|
582
|
-
it "works as documented" do
|
583
|
-
expect(Money.new(10_00).to_i).to eq 10
|
584
|
-
end
|
585
|
-
|
586
|
-
it "respects :subunit_to_unit currency property" do
|
587
|
-
expect(Money.new(10_00, "BHD").to_i).to eq 1
|
588
|
-
end
|
589
|
-
end
|
590
|
-
|
591
|
-
describe "#to_money" do
|
592
|
-
it "works as documented" do
|
593
|
-
money = Money.new(10_00, "DKK")
|
594
|
-
expect(money).to eq money.to_money
|
595
|
-
expect(money).to eq money.to_money("DKK")
|
596
|
-
expect(money.bank).to receive(:exchange_with).with(Money.new(10_00, Money::Currency.new("DKK")), Money::Currency.new("EUR")).and_return(Money.new(200_00, Money::Currency.new('EUR')))
|
597
|
-
expect(money.to_money("EUR")).to eq Money.new(200_00, "EUR")
|
598
|
-
end
|
599
|
-
end
|
600
|
-
|
601
|
-
describe "#with_currency" do
|
602
|
-
it 'returns self if currency is the same' do
|
603
|
-
money = Money.new(10_00, 'USD')
|
604
|
-
|
605
|
-
expect(money.with_currency('USD')).to eq(money)
|
606
|
-
expect(money.with_currency('USD').object_id).to eq(money.object_id)
|
607
|
-
end
|
608
|
-
|
609
|
-
it 'returns a new instance in a given currency' do
|
610
|
-
money = Money.new(10_00, 'USD')
|
611
|
-
new_money = money.with_currency('EUR')
|
612
|
-
|
613
|
-
expect(new_money).to eq(Money.new(10_00, 'EUR'))
|
614
|
-
expect(money.fractional).to eq(new_money.fractional)
|
615
|
-
expect(money.bank).to eq(new_money.bank)
|
616
|
-
expect(money.object_id).not_to eq(new_money.object_id)
|
617
|
-
end
|
618
|
-
end
|
619
|
-
|
620
|
-
describe "#exchange_to" do
|
621
|
-
it "exchanges the amount via its exchange bank" do
|
622
|
-
money = Money.new(100_00, "USD")
|
623
|
-
expect(money.bank).to receive(:exchange_with).with(Money.new(100_00, Money::Currency.new("USD")), Money::Currency.new("EUR")).and_return(Money.new(200_00, Money::Currency.new('EUR')))
|
624
|
-
money.exchange_to("EUR")
|
625
|
-
end
|
626
|
-
|
627
|
-
it "exchanges the amount properly" do
|
628
|
-
money = Money.new(100_00, "USD")
|
629
|
-
expect(money.bank).to receive(:exchange_with).with(Money.new(100_00, Money::Currency.new("USD")), Money::Currency.new("EUR")).and_return(Money.new(200_00, Money::Currency.new('EUR')))
|
630
|
-
expect(money.exchange_to("EUR")).to eq Money.new(200_00, "EUR")
|
631
|
-
end
|
632
|
-
|
633
|
-
it 'uses the block given as rounding method' do
|
634
|
-
money = Money.new(100_00, 'USD')
|
635
|
-
expect(money.bank).to receive(:exchange_with).and_yield(300_00)
|
636
|
-
expect { |block| money.exchange_to(Money::Currency.new('EUR'), &block) }.to yield_successive_args(300_00)
|
637
|
-
end
|
638
|
-
|
639
|
-
it "does no exchange when the currencies are the same" do
|
640
|
-
money = Money.new(100_00, "USD")
|
641
|
-
expect(money.bank).to_not receive(:exchange_with)
|
642
|
-
expect(money.exchange_to("USD")).to eq money
|
643
|
-
end
|
644
|
-
end
|
645
|
-
|
646
|
-
describe "#allocate" do
|
647
|
-
it "takes no action when one gets all" do
|
648
|
-
expect(Money.us_dollar(005).allocate([1.0])).to eq [Money.us_dollar(5)]
|
649
|
-
end
|
650
|
-
|
651
|
-
it "keeps currencies intact" do
|
652
|
-
expect(Money.ca_dollar(005).allocate([1])).to eq [Money.ca_dollar(5)]
|
653
|
-
end
|
654
|
-
|
655
|
-
it "does not lose pennies" do
|
656
|
-
moneys = Money.us_dollar(5).allocate([0.3, 0.7])
|
657
|
-
expect(moneys[0]).to eq Money.us_dollar(2)
|
658
|
-
expect(moneys[1]).to eq Money.us_dollar(3)
|
659
|
-
end
|
660
|
-
|
661
|
-
it "handles small splits" do
|
662
|
-
moneys = Money.us_dollar(5).allocate([0.03, 0.07])
|
663
|
-
expect(moneys[0]).to eq Money.us_dollar(2)
|
664
|
-
expect(moneys[1]).to eq Money.us_dollar(3)
|
665
|
-
end
|
666
|
-
|
667
|
-
it "handles large splits" do
|
668
|
-
moneys = Money.us_dollar(5).allocate([3, 7])
|
669
|
-
expect(moneys[0]).to eq Money.us_dollar(2)
|
670
|
-
expect(moneys[1]).to eq Money.us_dollar(3)
|
671
|
-
end
|
672
|
-
|
673
|
-
it "does not lose pennies" do
|
674
|
-
moneys = Money.us_dollar(100).allocate([0.333, 0.333, 0.333])
|
675
|
-
expect(moneys[0].cents).to eq 34
|
676
|
-
expect(moneys[1].cents).to eq 33
|
677
|
-
expect(moneys[2].cents).to eq 33
|
678
|
-
end
|
679
|
-
|
680
|
-
it "does not round rationals" do
|
681
|
-
splits = 7.times.map { Rational(950, 6650) }
|
682
|
-
moneys = Money.us_dollar(6650).allocate(splits)
|
683
|
-
moneys.each do |money|
|
684
|
-
expect(money.cents).to eq 950
|
685
|
-
end
|
686
|
-
end
|
687
|
-
|
688
|
-
it "handles mixed split types" do
|
689
|
-
splits = [Rational(1, 4), 0.25, 0.25, BigDecimal('0.25')]
|
690
|
-
moneys = Money.us_dollar(100).allocate(splits)
|
691
|
-
moneys.each do |money|
|
692
|
-
expect(money.cents).to eq 25
|
693
|
-
end
|
694
|
-
end
|
695
|
-
|
696
|
-
context "negative amount" do
|
697
|
-
it "does not lose pennies" do
|
698
|
-
moneys = Money.us_dollar(-100).allocate([0.333, 0.333, 0.333])
|
699
|
-
|
700
|
-
expect(moneys[0].cents).to eq(-34)
|
701
|
-
expect(moneys[1].cents).to eq(-33)
|
702
|
-
expect(moneys[2].cents).to eq(-33)
|
703
|
-
end
|
704
|
-
|
705
|
-
it "allocates the same way as positive amounts" do
|
706
|
-
ratios = [0.6667, 0.3333]
|
707
|
-
|
708
|
-
expect(Money.us_dollar(10_00).allocate(ratios).map(&:fractional)).to eq([6_67, 3_33])
|
709
|
-
expect(Money.us_dollar(-10_00).allocate(ratios).map(&:fractional)).to eq([-6_67, -3_33])
|
710
|
-
end
|
711
|
-
end
|
712
|
-
|
713
|
-
it "keeps subclasses intact" do
|
714
|
-
special_money_class = Class.new(Money)
|
715
|
-
expect(special_money_class.new(005).allocate([1]).first).to be_a special_money_class
|
716
|
-
end
|
717
|
-
|
718
|
-
context "with infinite_precision", :infinite_precision do
|
719
|
-
it "allows for fractional cents allocation" do
|
720
|
-
moneys = Money.new(100).allocate([1, 1, 1])
|
721
|
-
expect(moneys.inject(0, :+)).to eq(Money.new(100))
|
722
|
-
end
|
723
|
-
end
|
724
|
-
end
|
725
|
-
|
726
|
-
describe "#split" do
|
727
|
-
it "needs at least one party" do
|
728
|
-
expect { Money.us_dollar(1).split(0) }.to raise_error(ArgumentError)
|
729
|
-
expect { Money.us_dollar(1).split(-1) }.to raise_error(ArgumentError)
|
730
|
-
end
|
731
|
-
|
732
|
-
it "gives 1 cent to both people if we start with 2" do
|
733
|
-
expect(Money.us_dollar(2).split(2)).to eq [Money.us_dollar(1), Money.us_dollar(1)]
|
734
|
-
end
|
735
|
-
|
736
|
-
it "may distribute no money to some parties if there isnt enough to go around" do
|
737
|
-
expect(Money.us_dollar(2).split(3)).to eq [Money.us_dollar(1), Money.us_dollar(1), Money.us_dollar(0)]
|
738
|
-
end
|
739
|
-
|
740
|
-
it "does not lose pennies" do
|
741
|
-
expect(Money.us_dollar(5).split(2)).to eq [Money.us_dollar(3), Money.us_dollar(2)]
|
742
|
-
end
|
743
|
-
|
744
|
-
it "splits a dollar" do
|
745
|
-
moneys = Money.us_dollar(100).split(3)
|
746
|
-
expect(moneys[0].cents).to eq 34
|
747
|
-
expect(moneys[1].cents).to eq 33
|
748
|
-
expect(moneys[2].cents).to eq 33
|
749
|
-
end
|
750
|
-
|
751
|
-
it "preserves the class in the result when using a subclass of Money" do
|
752
|
-
special_money_class = Class.new(Money)
|
753
|
-
expect(special_money_class.new(10_00).split(1).first).to be_a special_money_class
|
754
|
-
end
|
755
|
-
|
756
|
-
context "with infinite_precision", :infinite_precision do
|
757
|
-
it "allows for splitting by fractional cents" do
|
758
|
-
moneys = Money.new(100).split(3)
|
759
|
-
expect(moneys.inject(0, :+)).to eq(Money.new(100))
|
760
|
-
end
|
761
|
-
end
|
762
|
-
end
|
763
|
-
|
764
|
-
describe "#round" do
|
765
|
-
let(:money) { Money.new(15.75, 'NZD') }
|
766
|
-
subject(:rounded) { money.round }
|
767
|
-
|
768
|
-
context "without infinite_precision" do
|
769
|
-
it "returns a different money" do
|
770
|
-
expect(rounded).not_to be money
|
771
|
-
end
|
772
|
-
|
773
|
-
it "rounds the cents" do
|
774
|
-
expect(rounded.cents).to eq 16
|
775
|
-
end
|
776
|
-
|
777
|
-
it "maintains the currency" do
|
778
|
-
expect(rounded.currency).to eq Money::Currency.new('NZD')
|
779
|
-
end
|
780
|
-
|
781
|
-
it "uses a provided rounding strategy" do
|
782
|
-
rounded = money.round(BigDecimal::ROUND_DOWN)
|
783
|
-
expect(rounded.cents).to eq 15
|
784
|
-
end
|
785
|
-
|
786
|
-
it "does not accumulate rounding error" do
|
787
|
-
money_1 = Money.new(10.9).round(BigDecimal::ROUND_DOWN)
|
788
|
-
money_2 = Money.new(10.9).round(BigDecimal::ROUND_DOWN)
|
789
|
-
|
790
|
-
expect(money_1 + money_2).to eq(Money.new(20))
|
791
|
-
end
|
792
|
-
end
|
793
|
-
|
794
|
-
context "with infinite_precision", :infinite_precision do
|
795
|
-
it "returns a different money" do
|
796
|
-
expect(rounded).not_to be money
|
797
|
-
end
|
798
|
-
|
799
|
-
it "rounds the cents" do
|
800
|
-
expect(rounded.cents).to eq 16
|
801
|
-
end
|
802
|
-
|
803
|
-
it "maintains the currency" do
|
804
|
-
expect(rounded.currency).to eq Money::Currency.new('NZD')
|
805
|
-
end
|
806
|
-
|
807
|
-
it "uses a provided rounding strategy" do
|
808
|
-
rounded = money.round(BigDecimal::ROUND_DOWN)
|
809
|
-
expect(rounded.cents).to eq 15
|
810
|
-
end
|
811
|
-
|
812
|
-
context "when using a specific rounding precision" do
|
813
|
-
let(:money) { Money.new(15.7526, 'NZD') }
|
814
|
-
|
815
|
-
it "uses the provided rounding precision" do
|
816
|
-
rounded = money.round(BigDecimal::ROUND_DOWN, 3)
|
817
|
-
expect(rounded.fractional).to eq 15.752
|
818
|
-
end
|
819
|
-
end
|
820
|
-
end
|
821
|
-
|
822
|
-
it 'preserves assigned bank' do
|
823
|
-
bank = Money::Bank::VariableExchange.new
|
824
|
-
rounded = Money.new(1_00, 'USD', bank).round
|
825
|
-
|
826
|
-
expect(rounded.bank).to eq(bank)
|
827
|
-
end
|
828
|
-
|
829
|
-
context "when using a subclass of Money" do
|
830
|
-
let(:special_money_class) { Class.new(Money) }
|
831
|
-
let(:money) { special_money_class.new(15.75, 'NZD') }
|
832
|
-
|
833
|
-
it "preserves the class in the result" do
|
834
|
-
expect(rounded).to be_a special_money_class
|
835
|
-
end
|
836
|
-
end
|
837
|
-
end
|
838
|
-
|
839
|
-
describe "#inspect" do
|
840
|
-
it "reports the class name properly when using inheritance" do
|
841
|
-
expect(Money.new(1).inspect).to start_with '#<Money'
|
842
|
-
Subclass = Class.new(Money)
|
843
|
-
expect(Subclass.new(1).inspect).to start_with '#<Subclass'
|
844
|
-
end
|
845
|
-
end
|
846
|
-
|
847
|
-
describe "#as_*" do
|
848
|
-
before do
|
849
|
-
Money.default_bank = Money::Bank::VariableExchange.new
|
850
|
-
Money.add_rate("EUR", "USD", 1)
|
851
|
-
Money.add_rate("EUR", "CAD", 1)
|
852
|
-
Money.add_rate("USD", "EUR", 1)
|
853
|
-
end
|
854
|
-
|
855
|
-
after do
|
856
|
-
Money.default_bank = Money::Bank::VariableExchange.instance
|
857
|
-
end
|
858
|
-
|
859
|
-
specify "as_us_dollar converts Money object to USD" do
|
860
|
-
obj = Money.new(1, "EUR")
|
861
|
-
expect(obj.as_us_dollar).to eq Money.new(1, "USD")
|
862
|
-
end
|
863
|
-
|
864
|
-
specify "as_ca_dollar converts Money object to CAD" do
|
865
|
-
obj = Money.new(1, "EUR")
|
866
|
-
expect(obj.as_ca_dollar).to eq Money.new(1, "CAD")
|
867
|
-
end
|
868
|
-
|
869
|
-
specify "as_euro converts Money object to EUR" do
|
870
|
-
obj = Money.new(1, "USD")
|
871
|
-
expect(obj.as_euro).to eq Money.new(1, "EUR")
|
872
|
-
end
|
873
|
-
end
|
874
|
-
|
875
|
-
describe ".default_currency" do
|
876
|
-
before do
|
877
|
-
@default_currency = Money.default_currency
|
878
|
-
end
|
879
|
-
|
880
|
-
after do
|
881
|
-
Money.default_currency = @default_currency
|
882
|
-
end
|
883
|
-
|
884
|
-
it "accepts a lambda" do
|
885
|
-
Money.default_currency = lambda { :eur }
|
886
|
-
expect(Money.default_currency).to eq Money::Currency.new(:eur)
|
887
|
-
end
|
888
|
-
|
889
|
-
it "accepts a symbol" do
|
890
|
-
Money.default_currency = :eur
|
891
|
-
expect(Money.default_currency).to eq Money::Currency.new(:eur)
|
892
|
-
end
|
893
|
-
end
|
894
|
-
end
|