money 6.13.0 → 6.13.8

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