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.
@@ -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
@@ -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: ! '&#x20AC;'
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