money 6.5.1 → 6.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -12,13 +12,20 @@ describe Money do
12
12
  end
13
13
 
14
14
  describe "#==" do
15
- it "returns true if and only if their amount and currency are equal" do
15
+ it "returns true if both the amounts and currencies are equal" do
16
16
  expect(Money.new(1_00, "USD")).to eq Money.new(1_00, "USD")
17
17
  expect(Money.new(1_00, "USD")).not_to eq Money.new(1_00, "EUR")
18
18
  expect(Money.new(1_00, "USD")).not_to eq Money.new(2_00, "USD")
19
19
  expect(Money.new(1_00, "USD")).not_to eq Money.new(99_00, "EUR")
20
20
  end
21
21
 
22
+ it "returns true if both amounts are zero, even if currency differs" do
23
+ expect(Money.new(0, "USD")).to eq Money.new(0, "USD")
24
+ expect(Money.new(0, "USD")).to eq Money.new(0, "EUR")
25
+ expect(Money.new(0, "USD")).to eq Money.new(0, "AUD")
26
+ expect(Money.new(0, "USD")).to eq Money.new(0, "JPY")
27
+ end
28
+
22
29
  it "returns false if used to compare with an object that doesn't respond to #to_money" do
23
30
  expect(Money.new(1_00, "USD")).not_to eq Object.new
24
31
  expect(Money.new(1_00, "USD")).not_to eq Class
@@ -116,12 +123,11 @@ describe Money do
116
123
  expect(Money.new(1_00) <=> klass.new(Money.new(2_00))).to be < 0
117
124
  end
118
125
 
119
- it "raises ArgumentError when used to compare with an object that doesn't respond to #to_money" do
120
- expected_message = /Comparison .+ failed/
121
- expect{ Money.new(1_00) <=> Object.new }.to raise_error(ArgumentError, expected_message)
122
- expect{ Money.new(1_00) <=> Class }.to raise_error(ArgumentError, expected_message)
123
- expect{ Money.new(1_00) <=> Kernel }.to raise_error(ArgumentError, expected_message)
124
- expect{ Money.new(1_00) <=> /foo/ }.to raise_error(ArgumentError, expected_message)
126
+ it "returns nil when used to compare with an object that doesn't respond to #to_money" do
127
+ expect(Money.new(1_00) <=> Object.new).to be_nil
128
+ expect(Money.new(1_00) <=> Class).to be_nil
129
+ expect(Money.new(1_00) <=> Kernel).to be_nil
130
+ expect(Money.new(1_00) <=> /foo/).to be_nil
125
131
  end
126
132
  end
127
133
 
@@ -287,15 +293,7 @@ describe Money do
287
293
  end
288
294
  end
289
295
 
290
- context "infinite_precision = true" do
291
- before do
292
- Money.infinite_precision = true
293
- end
294
-
295
- after do
296
- Money.infinite_precision = false
297
- end
298
-
296
+ context "with infinite_precision", :infinite_precision do
299
297
  it "uses BigDecimal division" do
300
298
  ts = [
301
299
  {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 3.25, :USD)},
@@ -348,15 +346,7 @@ describe Money do
348
346
  end
349
347
  end
350
348
 
351
- context "infinite_precision = true" do
352
- before do
353
- Money.infinite_precision = true
354
- end
355
-
356
- after do
357
- Money.infinite_precision = false
358
- end
359
-
349
+ context "with infinite_precision", :infinite_precision do
360
350
  it "uses BigDecimal division" do
361
351
  ts = [
362
352
  {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 3.25, :USD)},
@@ -409,15 +399,7 @@ describe Money do
409
399
  end
410
400
  end
411
401
 
412
- context "infinite_precision = true" do
413
- before do
414
- Money.infinite_precision = true
415
- end
416
-
417
- after do
418
- Money.infinite_precision = false
419
- end
420
-
402
+ context "with infinite_precision", :infinite_precision do
421
403
  it "uses BigDecimal division" do
422
404
  ts = [
423
405
  {:a => Money.new( 13, :USD), :b => 4, :c => [Money.new( 3, :USD), Money.new( 1, :USD)]},
@@ -95,6 +95,23 @@ describe Money, "formatting" do
95
95
  expect(money.decimal_mark).to eq ','
96
96
  end
97
97
  end
98
+
99
+ context "with number.currency.symbol.*" do
100
+ before :each do
101
+ reset_i18n
102
+ I18n.locale = :de
103
+ I18n.backend.store_translations(
104
+ :de,
105
+ :number => { :currency => { :symbol => { :CAD => "CAD$" } } }
106
+ )
107
+ end
108
+
109
+ subject(:money) { Money.empty("CAD") }
110
+
111
+ it "should use 'CAD$' as the currency symbol" do
112
+ expect(money.format(:translate => true)).to eq("CAD$0.00")
113
+ end
114
+ end
98
115
  end
99
116
 
100
117
  describe "#format" do
@@ -512,15 +529,7 @@ describe Money, "formatting" do
512
529
  end
513
530
  end
514
531
 
515
- describe ":rounded_infinite_precision option" do
516
- before do
517
- Money.infinite_precision = true
518
- end
519
-
520
- after do
521
- Money.infinite_precision = false
522
- end
523
-
532
+ describe ":rounded_infinite_precision option", :infinite_precision do
524
533
  it "does round fractional when set to true" do
525
534
  expect(Money.new(BigDecimal.new('12.1'), "USD").format(:rounded_infinite_precision => true)).to eq "$0.12"
526
535
  expect(Money.new(BigDecimal.new('12.5'), "USD").format(:rounded_infinite_precision => true)).to eq "$0.13"
@@ -541,15 +550,13 @@ describe Money, "formatting" do
541
550
  expect(Money.new(BigDecimal.new('1'), "MGA").format(:rounded_infinite_precision => false)).to eq "Ar0.1"
542
551
  end
543
552
 
544
- describe ":rounded_infinite_precision option with i18n = false" do
553
+ describe "with i18n = false" do
545
554
  before do
546
555
  Money.use_i18n = false
547
- Money.infinite_precision = true
548
556
  end
549
557
 
550
558
  after do
551
559
  Money.use_i18n = true
552
- Money.infinite_precision = false
553
560
  end
554
561
 
555
562
  it 'does round fractional when set to true' do
data/spec/money_spec.rb CHANGED
@@ -78,8 +78,7 @@ describe Money do
78
78
  end
79
79
  end
80
80
 
81
- context "infinite_precision = true" do
82
- before { expect(Money).to receive(:infinite_precision).and_return(true) }
81
+ context "with infinite_precision", :infinite_precision do
83
82
  context 'given the initializing value is 1.50' do
84
83
  let(:initializing_value) { 1.50 }
85
84
 
@@ -121,6 +120,59 @@ describe Money do
121
120
  end
122
121
  end
123
122
 
123
+ describe ".from_amount" do
124
+ it "accepts numeric values" do
125
+ expect(Money.from_amount(1, "USD")).to eq Money.new(1_00, "USD")
126
+ expect(Money.from_amount(1.0, "USD")).to eq Money.new(1_00, "USD")
127
+ expect(Money.from_amount("1".to_d, "USD")).to eq Money.new(1_00, "USD")
128
+ end
129
+
130
+ it "raises ArgumentError with unsupported argument" do
131
+ expect { Money.from_amount("1") }.to raise_error(ArgumentError)
132
+ expect { Money.from_amount(Object.new) }.to raise_error(ArgumentError)
133
+ end
134
+
135
+ it "converts given amount to subunits according to currency" do
136
+ expect(Money.from_amount(1, "USD")).to eq Money.new(1_00, "USD")
137
+ expect(Money.from_amount(1, "TND")).to eq Money.new(1_000, "TND")
138
+ expect(Money.from_amount(1, "JPY")).to eq Money.new(1, "JPY")
139
+ end
140
+
141
+ it "rounds the given amount to subunits" do
142
+ expect(Money.from_amount(4.444, "USD").amount).to eq "4.44".to_d
143
+ expect(Money.from_amount(5.555, "USD").amount).to eq "5.56".to_d
144
+ expect(Money.from_amount(444.4, "JPY").amount).to eq "444".to_d
145
+ expect(Money.from_amount(555.5, "JPY").amount).to eq "556".to_d
146
+ end
147
+
148
+ it "does not round the given amount when infinite_precision is set", :infinite_precision do
149
+ expect(Money.from_amount(4.444, "USD").amount).to eq "4.444".to_d
150
+ expect(Money.from_amount(5.555, "USD").amount).to eq "5.555".to_d
151
+ expect(Money.from_amount(444.4, "JPY").amount).to eq "444.4".to_d
152
+ expect(Money.from_amount(555.5, "JPY").amount).to eq "555.5".to_d
153
+ end
154
+
155
+ it "accepts an optional currency" do
156
+ expect(Money.from_amount(1).currency).to eq Money.default_currency
157
+ jpy = Money::Currency.wrap("JPY")
158
+ expect(Money.from_amount(1, jpy).currency).to eq jpy
159
+ expect(Money.from_amount(1, "JPY").currency).to eq jpy
160
+ end
161
+
162
+ it "accepts an optional bank" do
163
+ expect(Money.from_amount(1).bank).to eq Money.default_bank
164
+ bank = double "bank"
165
+ expect(Money.from_amount(1, "USD", bank).bank).to eq bank
166
+ end
167
+
168
+ it 'rounds using rounding_mode' do
169
+ expect(Money.from_amount(1.999).to_d).to eq 2
170
+ expect(Money.rounding_mode(BigDecimal::ROUND_DOWN) do
171
+ Money.from_amount(1.999).to_d
172
+ end).to eq 1.99
173
+ end
174
+ end
175
+
124
176
  %w[cents pence].each do |units|
125
177
  describe "##{units}" do
126
178
  it "is a synonym of #fractional" do
@@ -176,19 +228,9 @@ YAML
176
228
  expect(m.fractional).to be_a(Integer)
177
229
  end
178
230
 
179
- context "with infinite_precision" do
180
- before do
181
- Money.infinite_precision = true
182
- end
183
-
184
- after do
185
- Money.infinite_precision = false
186
- end
187
-
188
- it "is a BigDecimal" do
189
- money = YAML::load serialized
190
- expect(money.fractional).to be_a BigDecimal
191
- end
231
+ it "is a BigDecimal when using infinite_precision", :infinite_precision do
232
+ money = YAML::load serialized
233
+ expect(money.fractional).to be_a BigDecimal
192
234
  end
193
235
  end
194
236
 
@@ -234,15 +276,7 @@ YAML
234
276
  end
235
277
  end
236
278
 
237
- context "infinite_precision = true" do
238
- before do
239
- Money.infinite_precision = true
240
- end
241
-
242
- after do
243
- Money.infinite_precision = false
244
- end
245
-
279
+ context "with infinite_precision", :infinite_precision do
246
280
  it "returns the amount in fractional unit" do
247
281
  expect(Money.new(1_00).fractional).to eq BigDecimal("100")
248
282
  end
@@ -254,87 +288,77 @@ YAML
254
288
  end
255
289
  end
256
290
  end
257
-
291
+
258
292
  describe "#round_to_nearest_cash_value" do
259
293
  it "rounds to the nearest possible cash value" do
260
294
  money = Money.new(2350, "AED")
261
295
  expect(money.round_to_nearest_cash_value).to eq 2350
262
-
296
+
263
297
  money = Money.new(-2350, "AED")
264
298
  expect(money.round_to_nearest_cash_value).to eq(-2350)
265
-
299
+
266
300
  money = Money.new(2213, "AED")
267
301
  expect(money.round_to_nearest_cash_value).to eq 2225
268
-
302
+
269
303
  money = Money.new(-2213, "AED")
270
304
  expect(money.round_to_nearest_cash_value).to eq(-2225)
271
-
305
+
272
306
  money = Money.new(2212, "AED")
273
307
  expect(money.round_to_nearest_cash_value).to eq 2200
274
-
308
+
275
309
  money = Money.new(-2212, "AED")
276
310
  expect(money.round_to_nearest_cash_value).to eq(-2200)
277
-
311
+
278
312
  money = Money.new(178, "CHF")
279
313
  expect(money.round_to_nearest_cash_value).to eq 180
280
-
314
+
281
315
  money = Money.new(-178, "CHF")
282
316
  expect(money.round_to_nearest_cash_value).to eq(-180)
283
-
317
+
284
318
  money = Money.new(177, "CHF")
285
319
  expect(money.round_to_nearest_cash_value).to eq 175
286
-
320
+
287
321
  money = Money.new(-177, "CHF")
288
322
  expect(money.round_to_nearest_cash_value).to eq(-175)
289
-
323
+
290
324
  money = Money.new(175, "CHF")
291
325
  expect(money.round_to_nearest_cash_value).to eq 175
292
-
326
+
293
327
  money = Money.new(-175, "CHF")
294
328
  expect(money.round_to_nearest_cash_value).to eq(-175)
295
-
329
+
296
330
  money = Money.new(299, "USD")
297
331
  expect(money.round_to_nearest_cash_value).to eq 299
298
-
332
+
299
333
  money = Money.new(-299, "USD")
300
334
  expect(money.round_to_nearest_cash_value).to eq(-299)
301
-
335
+
302
336
  money = Money.new(300, "USD")
303
337
  expect(money.round_to_nearest_cash_value).to eq 300
304
-
338
+
305
339
  money = Money.new(-300, "USD")
306
340
  expect(money.round_to_nearest_cash_value).to eq(-300)
307
-
341
+
308
342
  money = Money.new(301, "USD")
309
343
  expect(money.round_to_nearest_cash_value).to eq 301
310
-
344
+
311
345
  money = Money.new(-301, "USD")
312
346
  expect(money.round_to_nearest_cash_value).to eq(-301)
313
347
  end
314
-
348
+
315
349
  it "raises an exception if smallest denomination is not defined" do
316
350
  money = Money.new(100, "XAG")
317
351
  expect {money.round_to_nearest_cash_value}.to raise_error(Money::UndefinedSmallestDenomination)
318
352
  end
319
-
353
+
320
354
  it "returns a Fixnum when infinite_precision is not set" do
321
355
  money = Money.new(100, "USD")
322
356
  expect(money.round_to_nearest_cash_value).to be_a Fixnum
323
357
  end
324
-
325
- context "with infinite_precision" do
326
- before do
327
- Money.infinite_precision = true
328
- end
329
358
 
330
- after do
331
- Money.infinite_precision = false
332
- end
333
-
334
- it "returns a BigDecimal" do
335
- money = Money.new(100, "EUR")
336
- expect(money.round_to_nearest_cash_value).to be_a BigDecimal
337
- end
359
+ it "returns a BigDecimal when infinite_precision is set", :infinite_precision do
360
+ money = Money.new(100, "EUR")
361
+ expect(money.round_to_nearest_cash_value).to be_a BigDecimal
338
362
  end
339
363
  end
340
364
 
@@ -347,6 +371,7 @@ YAML
347
371
  expect(Money.new(1_00, "USD").amount).to eq 1
348
372
  expect(Money.new(1_000, "TND").amount).to eq 1
349
373
  expect(Money.new(1, "VUV").amount).to eq 1
374
+ expect(Money.new(1, "CLP").amount).to eq 1
350
375
  end
351
376
 
352
377
  it "does not loose precision" do
@@ -445,15 +470,7 @@ YAML
445
470
  expect(Money.new(10_00, "BRL").to_s).to eq "10,00"
446
471
  end
447
472
 
448
- context "infinite_precision = true" do
449
- before do
450
- Money.infinite_precision = true
451
- end
452
-
453
- after do
454
- Money.infinite_precision = false
455
- end
456
-
473
+ context "with infinite_precision", :infinite_precision do
457
474
  it "shows fractional cents" do
458
475
  expect(Money.new(1.05, "USD").to_s).to eq "0.0105"
459
476
  end
@@ -573,15 +590,7 @@ YAML
573
590
  expect { Money.us_dollar(0.05).allocate([0.5, 0.6]) }.to raise_error(ArgumentError)
574
591
  end
575
592
 
576
- context "infinite_precision = true" do
577
- before do
578
- Money.infinite_precision = true
579
- end
580
-
581
- after do
582
- Money.infinite_precision = false
583
- end
584
-
593
+ context "with infinite_precision", :infinite_precision do
585
594
  it "allows for fractional cents allocation" do
586
595
  one_third = BigDecimal("1") / BigDecimal("3")
587
596
 
@@ -618,15 +627,7 @@ YAML
618
627
  expect(moneys[2].cents).to eq 33
619
628
  end
620
629
 
621
- context "infinite_precision = true" do
622
- before do
623
- Money.infinite_precision = true
624
- end
625
-
626
- after do
627
- Money.infinite_precision = false
628
- end
629
-
630
+ context "with infinite_precision", :infinite_precision do
630
631
  it "allows for splitting by fractional cents" do
631
632
  thirty_three_and_one_third = BigDecimal("100") / BigDecimal("3")
632
633
 
@@ -644,10 +645,6 @@ YAML
644
645
  subject(:rounded) { money.round }
645
646
 
646
647
  context "without infinite_precision" do
647
- before do
648
- Money.infinite_precision = false
649
- end
650
-
651
648
  it "returns self (as it is already rounded)" do
652
649
  rounded = money.round
653
650
  expect(rounded).to be money
@@ -655,15 +652,7 @@ YAML
655
652
  end
656
653
  end
657
654
 
658
- context "with infinite_precision" do
659
- before do
660
- Money.infinite_precision = true
661
- end
662
-
663
- after do
664
- Money.infinite_precision = false
665
- end
666
-
655
+ context "with infinite_precision", :infinite_precision do
667
656
  it "returns a different money" do
668
657
  expect(rounded).not_to be money
669
658
  end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+
3
+ describe Money::RatesStore::Memory do
4
+ let(:subject) { described_class.new }
5
+
6
+ describe '#add_rate and #get_rate' do
7
+ it 'stores rate in memory' do
8
+ expect(subject.add_rate('USD', 'CAD', 0.9)).to eql 0.9
9
+ expect(subject.get_rate('USD', 'CAD')).to eql 0.9
10
+ end
11
+ end
12
+
13
+ describe 'add_rate' do
14
+ it "uses a mutex by default" do
15
+ expect(subject.instance_variable_get(:@mutex)).to receive(:synchronize)
16
+ subject.add_rate('USD', 'EUR', 1.25)
17
+ end
18
+
19
+ context ':without_mutex' do
20
+ let(:subject) { Money::RatesStore::Memory.new(:without_mutex => true) }
21
+
22
+ it "doesn't use mutex if requested not to" do
23
+ expect(subject.instance_variable_get(:@mutex)).not_to receive(:synchronize)
24
+ subject.add_rate('USD', 'EUR', 1.25)
25
+ end
26
+ end
27
+ end
28
+
29
+ describe '#each_rate' do
30
+ before do
31
+ subject.add_rate('USD', 'CAD', 0.9)
32
+ subject.add_rate('CAD', 'USD', 1.1)
33
+ end
34
+
35
+ it 'iterates over rates' do
36
+ expect{|b| subject.each_rate(&b)}.to yield_successive_args(['USD', 'CAD', 0.9], ['CAD', 'USD', 1.1])
37
+ end
38
+
39
+ it 'is an Enumeator' do
40
+ expect(subject.each_rate).to be_kind_of(Enumerator)
41
+ result = subject.each_rate.each_with_object({}){|(from, to, rate),m| m[[from,to].join] = rate}
42
+ expect(result).to match({'USDCAD' => 0.9, 'CADUSD' => 1.1})
43
+ end
44
+ end
45
+
46
+ describe '#transaction' do
47
+ context 'mutex' do
48
+ it 'uses mutex' do
49
+ expect(subject.instance_variable_get('@mutex')).to receive(:synchronize)
50
+ subject.transaction{ a = 1}
51
+ end
52
+
53
+ it 'wraps block in mutex transaction only once' do
54
+ expect{
55
+ subject.transaction do
56
+ subject.add_rate('USD', 'CAD', 1)
57
+ end
58
+ }.not_to raise_error
59
+ end
60
+ end
61
+
62
+ context 'no mutex' do
63
+ let(:subject) { Money::RatesStore::Memory.new(:without_mutex => true) }
64
+
65
+ it 'does not use mutex' do
66
+ expect(subject.instance_variable_get('@mutex')).not_to receive(:synchronize)
67
+ subject.transaction{ a = 1}
68
+ end
69
+ end
70
+ end
71
+ end
data/spec/spec_helper.rb CHANGED
@@ -21,3 +21,13 @@ end
21
21
  def reset_i18n
22
22
  I18n.backend = I18n::Backend::Simple.new
23
23
  end
24
+
25
+ RSpec.shared_context "with infinite precision", :infinite_precision do
26
+ before do
27
+ Money.infinite_precision = true
28
+ end
29
+
30
+ after do
31
+ Money.infinite_precision = false
32
+ end
33
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: money
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.5.1
4
+ version: 6.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shane Emmons
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-03 00:00:00.000000000 Z
11
+ date: 2015-07-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: i18n
@@ -64,14 +64,14 @@ dependencies:
64
64
  requirements:
65
65
  - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: 3.0.0
67
+ version: 3.2.0
68
68
  type: :development
69
69
  prerelease: false
70
70
  version_requirements: !ruby/object:Gem::Requirement
71
71
  requirements:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
- version: 3.0.0
74
+ version: 3.2.0
75
75
  - !ruby/object:Gem::Dependency
76
76
  name: yard
77
77
  requirement: !ruby/object:Gem::Requirement
@@ -131,17 +131,20 @@ files:
131
131
  - lib/money/money/arithmetic.rb
132
132
  - lib/money/money/constructors.rb
133
133
  - lib/money/money/formatting.rb
134
+ - lib/money/rates_store/memory.rb
134
135
  - lib/money/version.rb
135
136
  - money.gemspec
136
137
  - spec/bank/base_spec.rb
137
138
  - spec/bank/single_currency_spec.rb
138
139
  - spec/bank/variable_exchange_spec.rb
139
140
  - spec/currency/heuristics_spec.rb
141
+ - spec/currency/loader_spec.rb
140
142
  - spec/currency_spec.rb
141
143
  - spec/money/arithmetic_spec.rb
142
144
  - spec/money/constructors_spec.rb
143
145
  - spec/money/formatting_spec.rb
144
146
  - spec/money_spec.rb
147
+ - spec/rates_store/memory_spec.rb
145
148
  - spec/spec_helper.rb
146
149
  homepage: http://rubymoney.github.io/money
147
150
  licenses:
@@ -171,7 +174,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
171
174
  version: '0'
172
175
  requirements: []
173
176
  rubyforge_project:
174
- rubygems_version: 2.2.2
177
+ rubygems_version: 2.4.5
175
178
  signing_key:
176
179
  specification_version: 4
177
180
  summary: A Ruby Library for dealing with money and currency conversion.
@@ -180,10 +183,12 @@ test_files:
180
183
  - spec/bank/single_currency_spec.rb
181
184
  - spec/bank/variable_exchange_spec.rb
182
185
  - spec/currency/heuristics_spec.rb
186
+ - spec/currency/loader_spec.rb
183
187
  - spec/currency_spec.rb
184
188
  - spec/money/arithmetic_spec.rb
185
189
  - spec/money/constructors_spec.rb
186
190
  - spec/money/formatting_spec.rb
187
191
  - spec/money_spec.rb
192
+ - spec/rates_store/memory_spec.rb
188
193
  - spec/spec_helper.rb
189
194
  has_rdoc: