money 3.6.1 → 3.6.2

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.
data/spec/money_spec.rb CHANGED
@@ -1,1268 +1,271 @@
1
- # encoding: utf-8
2
-
3
- require "spec_helper"
4
-
5
- describe Money do
6
-
7
- describe "#new" do
8
- it "rounds the given cents to an integer" do
9
- Money.new(1.00, "USD").cents.should == 1
10
- Money.new(1.01, "USD").cents.should == 1
11
- Money.new(1.50, "USD").cents.should == 2
12
- end
13
-
14
- it "is associated to the singleton instance of Bank::VariableExchange by default" do
15
- Money.new(0).bank.should be_equal(Money::Bank::VariableExchange.instance)
16
- end
17
-
18
- end
19
-
20
- describe "#cents" do
21
- it "returns the amount of cents passed to the constructor" do
22
- Money.new(200_00, "USD").cents.should == 200_00
23
- end
24
-
25
- it "stores cents as an integer regardless of what is passed into the constructor" do
26
- [ Money.new(100), 1.to_money, 1.00.to_money, BigDecimal('1.00').to_money ].each do |m|
27
- m.cents.should == 100
28
- m.cents.should be_an_instance_of(Fixnum)
29
- end
30
- end
31
- end
32
-
33
- describe "#dollars" do
34
- it "gets cents as dollars" do
35
- Money.new_with_dollars(1).should == Money.new(100)
36
- Money.new_with_dollars(1, "USD").should == Money.new(100, "USD")
37
- Money.new_with_dollars(1, "EUR").should == Money.new(100, "EUR")
38
- end
39
-
40
- it "should respect :subunit_to_unit currency property" do
41
- Money.new(1_00, "USD").dollars.should == 1
42
- Money.new(1_000, "TND").dollars.should == 1
43
- Money.new(1, "CLP").dollars.should == 1
44
- end
45
-
46
- it "should not loose precision" do
47
- Money.new(100_37).dollars.should == 100.37
48
- Money.new_with_dollars(100.37).dollars.should == 100.37
49
- end
50
- end
51
-
52
- specify "#currency returns the currency passed to the constructor" do
53
- Money.new(200_00, "USD").currency.should == Money::Currency.new("USD")
54
- end
55
-
56
- specify "#currency_string returns the iso_code of the currency object" do
57
- Money.new(200_00, "USD").currency_as_string.should == Money::Currency.new("USD").to_s
58
- Money.new(200_00, "USD").currency_as_string.should == "USD"
59
- Money.new(200_00, "EUR").currency_as_string.should == "EUR"
60
- Money.new(200_00, "YEN").currency_as_string.should == "YEN"
61
- end
62
-
63
- specify "#currency_string= set the currency object using the provided string" do
64
- obj = Money.new(200_00, "USD")
65
- obj.currency_as_string = "EUR"
66
- obj.currency.should == Money::Currency.new("EUR")
67
- obj.currency_as_string = "YEN"
68
- obj.currency.should == Money::Currency.new("YEN")
69
- obj.currency_as_string = "USD"
70
- obj.currency.should == Money::Currency.new("USD")
71
- end
72
-
73
- specify "#zero? returns whether the amount is 0" do
74
- Money.new(0, "USD").should be_zero
75
- Money.new(0, "EUR").should be_zero
76
- Money.new(1, "USD").should_not be_zero
77
- Money.new(10, "YEN").should_not be_zero
78
- Money.new(-1, "EUR").should_not be_zero
79
- end
80
-
81
- specify "#nonzero? returns whether the amount is not 0" do
82
- Money.new(0, "USD").should_not be_nonzero
83
- Money.new(0, "EUR").should_not be_nonzero
84
- Money.new(1, "USD").should be_nonzero
85
- Money.new(10, "YEN").should be_nonzero
86
- Money.new(-1, "EUR").should be_nonzero
87
- end
88
-
89
- specify "#nonzero? has the same return-value semantics as Numeric#nonzero?" do
90
- Money.new(0, "USD").nonzero?.should be_nil
91
-
92
- money = Money.new(1, "USD")
93
- money.nonzero?.should be_equal(money)
94
- end
95
-
96
- specify "#exchange_to exchanges the amount via its exchange bank" do
97
- money = Money.new(100_00, "USD")
98
- money.bank.should_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')))
99
- money.exchange_to("EUR")
100
- end
101
-
102
- specify "#exchange_to exchanges the amount properly" do
103
- money = Money.new(100_00, "USD")
104
- money.bank.should_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')))
105
- money.exchange_to("EUR").should == Money.new(200_00, "EUR")
106
- end
107
-
108
- specify "#== returns true if and only if their amount and currency are equal" do
109
- Money.new(1_00, "USD").should == Money.new(1_00, "USD")
110
- Money.new(1_00, "USD").should_not == Money.new(1_00, "EUR")
111
- Money.new(1_00, "USD").should_not == Money.new(2_00, "USD")
112
- Money.new(1_00, "USD").should_not == Money.new(99_00, "EUR")
113
- end
114
-
115
- specify "#== can be used to compare with a String money value" do
116
- Money.new(1_00, "USD").should == "1.00"
117
- Money.new(1_00, "USD").should_not == "2.00"
118
- Money.new(1_00, "GBP").should_not == "1.00"
119
- end
120
-
121
- specify "#== can be used to compare with a Numeric money value" do
122
- Money.new(1_00, "USD").should == 1
123
- Money.new(1_57, "USD").should == 1.57
124
- Money.new(1_00, "USD").should_not == 2
125
- Money.new(1_00, "GBP").should_not == 1
126
- end
127
-
128
- specify "#== can be used to compare with an object that responds to #to_money" do
129
- klass = Class.new do
130
- def initialize(money)
131
- @money = money
132
- end
133
-
134
- def to_money
135
- @money
136
- end
137
- end
138
-
139
- Money.new(1_00, "USD").should == klass.new(Money.new(1_00, "USD"))
140
- Money.new(2_50, "USD").should == klass.new(Money.new(2_50, "USD"))
141
- Money.new(2_50, "USD").should_not == klass.new(Money.new(3_00, "USD"))
142
- Money.new(1_00, "GBP").should_not == klass.new(Money.new(1_00, "USD"))
143
- end
144
-
145
- specify "#== returns false if used to compare with an object that doesn't respond to #to_money" do
146
- Money.new(1_00, "USD").should_not == Object.new
147
- Money.new(1_00, "USD").should_not == Class
148
- Money.new(1_00, "USD").should_not == Kernel
149
- Money.new(1_00, "USD").should_not == /foo/
150
- Money.new(1_00, "USD").should_not == nil
151
- end
152
-
153
- specify "#eql? returns true if and only if their amount and currency are equal" do
154
- Money.new(1_00, "USD").eql?(Money.new(1_00, "USD")).should be true
155
- Money.new(1_00, "USD").eql?(Money.new(1_00, "EUR")).should be false
156
- Money.new(1_00, "USD").eql?(Money.new(2_00, "USD")).should be false
157
- Money.new(1_00, "USD").eql?(Money.new(99_00, "EUR")).should be false
158
- end
159
-
160
- specify "#eql? can be used to compare with a String money value" do
161
- Money.new(1_00, "USD").eql?("1.00").should be true
162
- Money.new(1_00, "USD").eql?("2.00").should be false
163
- Money.new(1_00, "GBP").eql?("1.00").should be false
164
- end
165
-
166
- specify "#eql? can be used to compare with a Numeric money value" do
167
- Money.new(1_00, "USD").eql?(1).should be true
168
- Money.new(1_57, "USD").eql?(1.57).should be true
169
- Money.new(1_00, "USD").eql?(2).should be false
170
- Money.new(1_00, "GBP").eql?(1).should be false
171
- end
172
-
173
- specify "#eql? can be used to compare with an object that responds to #to_money" do
174
- klass = Class.new do
175
- def initialize(money)
176
- @money = money
177
- end
178
-
179
- def to_money
180
- @money
181
- end
182
- end
183
-
184
- Money.new(1_00, "USD").eql?(klass.new(Money.new(1_00, "USD"))).should be true
185
- Money.new(2_50, "USD").eql?(klass.new(Money.new(2_50, "USD"))).should be true
186
- Money.new(2_50, "USD").eql?(klass.new(Money.new(3_00, "USD"))).should be false
187
- Money.new(1_00, "GBP").eql?(klass.new(Money.new(1_00, "USD"))).should be false
188
- end
189
-
190
- specify "#eql? returns false if used to compare with an object that doesn't respond to #to_money" do
191
- Money.new(1_00, "USD").eql?(Object.new).should be false
192
- Money.new(1_00, "USD").eql?(Class).should be false
193
- Money.new(1_00, "USD").eql?(Kernel).should be false
194
- Money.new(1_00, "USD").eql?(/foo/).should be false
195
- Money.new(1_00, "USD").eql?(nil).should be false
196
- end
197
-
198
- specify "#hash should return the same value for equal objects" do
199
- Money.new(1_00, :eur).hash.should == Money.new(1_00, :eur).hash
200
- Money.new(2_00, :usd).hash.should == Money.new(2_00, :usd).hash
201
- Money.new(1_00, :eur).hash.should_not == Money.new(2_00, :eur).hash
202
- Money.new(1_00, :eur).hash.should_not == Money.new(1_00, :usd).hash
203
- Money.new(1_00, :eur).hash.should_not == Money.new(2_00, :usd).hash
204
- end
205
-
206
- specify "#hash can be used to return the intersection of Money object arrays" do
207
- intersection = [Money.new(1_00, :eur), Money.new(1_00, :usd)] & [Money.new(1_00, :eur)]
208
- intersection.should == [Money.new(1_00, :eur)]
209
- end
210
-
211
- specify "#<=> can be used to compare with a String money value" do
212
- (Money.new(1_00) <=> "1.00").should == 0
213
- (Money.new(1_00) <=> ".99").should > 0
214
- (Money.new(1_00) <=> "2.00").should < 0
215
- end
216
-
217
- specify "#<=> can be used to compare with a Numeric money value" do
218
- (Money.new(1_00) <=> 1).should == 0
219
- (Money.new(1_00) <=> 0.99).should > 0
220
- (Money.new(1_00) <=> 2.00).should < 0
221
- end
222
-
223
- specify "#<=> can be used to compare with an object that responds to #to_money" do
224
- klass = Class.new do
225
- def initialize(money)
226
- @money = money
227
- end
228
-
229
- def to_money
230
- @money
231
- end
232
- end
233
-
234
- (Money.new(1_00) <=> klass.new(Money.new(1_00))).should == 0
235
- (Money.new(1_00) <=> klass.new(Money.new(99))).should > 0
236
- (Money.new(1_00) <=> klass.new(Money.new(2_00))).should < 0
237
- end
238
-
239
- specify "#<=> raises ArgumentError when used to compare with an object that doesn't respond to #to_money" do
240
- expected_message = /Comparison .+ failed/
241
- lambda{ Money.new(1_00) <=> Object.new }.should raise_error(ArgumentError, expected_message)
242
- lambda{ Money.new(1_00) <=> Class }.should raise_error(ArgumentError, expected_message)
243
- lambda{ Money.new(1_00) <=> Kernel }.should raise_error(ArgumentError, expected_message)
244
- lambda{ Money.new(1_00) <=> /foo/ }.should raise_error(ArgumentError, expected_message)
245
- end
246
-
247
- describe "#*" do
248
- it "should multiply current money amount by the multiplier while retaining the currency" do
249
- (Money.new(1_00, "USD") * 10).should == Money.new(10_00, "USD")
250
- end
251
-
252
- it "should multiply Money by Fixnum and returns Money" do
253
- ts = [
254
- {:a => Money.new( 10, :USD), :b => 4, :c => Money.new( 40, :USD)},
255
- {:a => Money.new( 10, :USD), :b => -4, :c => Money.new(-40, :USD)},
256
- {:a => Money.new(-10, :USD), :b => 4, :c => Money.new(-40, :USD)},
257
- {:a => Money.new(-10, :USD), :b => -4, :c => Money.new( 40, :USD)},
258
- ]
259
- ts.each do |t|
260
- (t[:a] * t[:b]).should == t[:c]
261
- end
262
- end
263
-
264
- it "should not multiply Money by Money (same currency)" do
265
- lambda { Money.new( 10, :USD) * Money.new( 4, :USD) }.should raise_error(ArgumentError)
266
- end
267
-
268
- it "should not multiply Money by Money (different currency)" do
269
- lambda { Money.new( 10, :USD) * Money.new( 4, :EUR) }.should raise_error(ArgumentError)
270
- end
271
- end
272
-
273
- describe "#/" do
274
- it "divides current money amount by the divisor while retaining the currency" do
275
- (Money.new(10_00, "USD") / 10).should == Money.new(1_00, "USD")
276
- end
277
-
278
- it "divides Money by Fixnum and returns Money" do
279
- ts = [
280
- {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 3, :USD)},
281
- {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-4, :USD)},
282
- {:a => Money.new(-13, :USD), :b => 4, :c => Money.new(-4, :USD)},
283
- {:a => Money.new(-13, :USD), :b => -4, :c => Money.new( 3, :USD)},
284
- ]
285
- ts.each do |t|
286
- (t[:a] / t[:b]).should == t[:c]
287
- end
288
- end
289
-
290
- it "divides Money by Money (same currency) and returns Float" do
291
- ts = [
292
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => 3.25},
293
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => -3.25},
294
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => -3.25},
295
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => 3.25},
296
- ]
297
- ts.each do |t|
298
- (t[:a] / t[:b]).should == t[:c]
299
- end
300
- end
301
-
302
- it "divides Money by Money (different currency) and returns Float" do
303
- ts = [
304
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => 1.625},
305
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => -1.625},
306
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => -1.625},
307
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => 1.625},
308
- ]
309
- ts.each do |t|
310
- t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
311
- (t[:a] / t[:b]).should == t[:c]
312
- end
313
- end
314
- end
315
-
316
- specify "#div -> money / fixnum" do
317
- ts = [
318
- {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 3, :USD)},
319
- {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-4, :USD)},
320
- {:a => Money.new(-13, :USD), :b => 4, :c => Money.new(-4, :USD)},
321
- {:a => Money.new(-13, :USD), :b => -4, :c => Money.new( 3, :USD)},
322
- ]
323
- ts.each do |t|
324
- t[:a].div(t[:b]).should == t[:c]
325
- end
326
- end
327
-
328
- specify "#div -> money / money (same currency)" do
329
- ts = [
330
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => 3.25},
331
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => -3.25},
332
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => -3.25},
333
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => 3.25},
334
- ]
335
- ts.each do |t|
336
- t[:a].div(t[:b]).should == t[:c]
337
- end
338
- end
339
-
340
- specify "#div -> money / money (different currency)" do
341
- ts = [
342
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => 1.625},
343
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => -1.625},
344
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => -1.625},
345
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => 1.625},
346
- ]
347
- ts.each do |t|
348
- t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
349
- t[:a].div(t[:b]).should == t[:c]
350
- end
351
- end
352
-
353
- specify "#divmod -> money `divmod` fixnum" do
354
- ts = [
355
- {:a => Money.new( 13, :USD), :b => 4, :c => [Money.new( 3, :USD), Money.new( 1, :USD)]},
356
- {:a => Money.new( 13, :USD), :b => -4, :c => [Money.new(-4, :USD), Money.new(-3, :USD)]},
357
- {:a => Money.new(-13, :USD), :b => 4, :c => [Money.new(-4, :USD), Money.new( 3, :USD)]},
358
- {:a => Money.new(-13, :USD), :b => -4, :c => [Money.new( 3, :USD), Money.new(-1, :USD)]},
359
- ]
360
- ts.each do |t|
361
- t[:a].divmod(t[:b]).should == t[:c]
362
- end
363
- end
364
-
365
- specify "#divmod -> money `divmod` money (same currency)" do
366
- ts = [
367
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => [ 3, Money.new( 1, :USD)]},
368
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => [-4, Money.new(-3, :USD)]},
369
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => [-4, Money.new( 3, :USD)]},
370
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => [ 3, Money.new(-1, :USD)]},
371
- ]
372
- ts.each do |t|
373
- t[:a].divmod(t[:b]).should == t[:c]
374
- end
375
- end
376
-
377
- specify "#divmod -> money `divmod` money (different currency)" do
378
- ts = [
379
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => [ 1, Money.new( 5, :USD)]},
380
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => [-2, Money.new(-3, :USD)]},
381
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => [-2, Money.new( 3, :USD)]},
382
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => [ 1, Money.new(-5, :USD)]},
383
- ]
384
- ts.each do |t|
385
- t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
386
- t[:a].divmod(t[:b]).should == t[:c]
387
- end
388
- end
389
-
390
- specify "#modulo -> money `modulo` fixnum" do
391
- ts = [
392
- {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 1, :USD)},
393
- {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-3, :USD)},
394
- {:a => Money.new(-13, :USD), :b => 4, :c => Money.new( 3, :USD)},
395
- {:a => Money.new(-13, :USD), :b => -4, :c => Money.new(-1, :USD)},
396
- ]
397
- ts.each do |t|
398
- t[:a].modulo(t[:b]).should == t[:c]
399
- end
400
- end
401
-
402
- specify "#modulo -> money `modulo` money (same currency)" do
403
- ts = [
404
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => Money.new( 1, :USD)},
405
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => Money.new(-3, :USD)},
406
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => Money.new( 3, :USD)},
407
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => Money.new(-1, :USD)},
408
- ]
409
- ts.each do |t|
410
- t[:a].modulo(t[:b]).should == t[:c]
411
- end
412
- end
413
-
414
- specify "#modulo -> money `modulo` money (different currency)" do
415
- ts = [
416
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => Money.new( 5, :USD)},
417
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => Money.new(-3, :USD)},
418
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => Money.new( 3, :USD)},
419
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => Money.new(-5, :USD)},
420
- ]
421
- ts.each do |t|
422
- t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
423
- t[:a].modulo(t[:b]).should == t[:c]
424
- end
425
- end
426
-
427
- specify "#% -> money % fixnum" do
428
- ts = [
429
- {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 1, :USD)},
430
- {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-3, :USD)},
431
- {:a => Money.new(-13, :USD), :b => 4, :c => Money.new( 3, :USD)},
432
- {:a => Money.new(-13, :USD), :b => -4, :c => Money.new(-1, :USD)},
433
- ]
434
- ts.each do |t|
435
- (t[:a] % t[:b]).should == t[:c]
436
- end
437
- end
438
-
439
- specify "#% -> money % money (same currency)" do
440
- ts = [
441
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => Money.new( 1, :USD)},
442
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => Money.new(-3, :USD)},
443
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => Money.new( 3, :USD)},
444
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => Money.new(-1, :USD)},
445
- ]
446
- ts.each do |t|
447
- (t[:a] % t[:b]).should == t[:c]
448
- end
449
- end
450
-
451
- specify "#% -> money % money (different currency)" do
452
- ts = [
453
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => Money.new( 5, :USD)},
454
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => Money.new(-3, :USD)},
455
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => Money.new( 3, :USD)},
456
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => Money.new(-5, :USD)},
457
- ]
458
- ts.each do |t|
459
- t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
460
- (t[:a] % t[:b]).should == t[:c]
461
- end
462
- end
463
-
464
- specify "#remainder -> money `remainder` fixnum" do
465
- ts = [
466
- {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 1, :USD)},
467
- {:a => Money.new( 13, :USD), :b => -4, :c => Money.new( 1, :USD)},
468
- {:a => Money.new(-13, :USD), :b => 4, :c => Money.new(-1, :USD)},
469
- {:a => Money.new(-13, :USD), :b => -4, :c => Money.new(-1, :USD)},
470
- ]
471
- ts.each do |t|
472
- t[:a].remainder(t[:b]).should == t[:c]
473
- end
474
- end
475
-
476
- specify "#remainder -> money `remainder` money (same currency)" do
477
- ts = [
478
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => Money.new( 1, :USD)},
479
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => Money.new( 1, :USD)},
480
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => Money.new(-1, :USD)},
481
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => Money.new(-1, :USD)},
482
- ]
483
- ts.each do |t|
484
- t[:a].remainder(t[:b]).should == t[:c]
485
- end
486
- end
487
-
488
- specify "#remainder -> money `remainder` money (different currency)" do
489
- ts = [
490
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => Money.new( 5, :USD)},
491
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => Money.new( 5, :USD)},
492
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => Money.new(-5, :USD)},
493
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => Money.new(-5, :USD)},
494
- ]
495
- ts.each do |t|
496
- t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
497
- t[:a].remainder(t[:b]).should == t[:c]
498
- end
499
- end
500
-
501
- specify "#abs correctly returns the absolute value as a new Money object" do
502
- n = Money.new(-1, :USD)
503
- n.abs.should == Money.new( 1, :USD)
504
- n.should == Money.new(-1, :USD)
505
- end
506
-
507
- specify "Money.format brute force :subunit_to_unit = 1" do
508
- ("0".."9").each do |amt|
509
- amt.to_money("VUV").format(:symbol => false).should == amt
510
- end
511
- ("-1".."-9").each do |amt|
512
- amt.to_money("VUV").format(:symbol => false).should == amt
513
- end
514
- "1000".to_money("VUV").format(:symbol => false).should == "1,000"
515
- "-1000".to_money("VUV").format(:symbol => false).should == "-1,000"
516
- end
517
-
518
- specify "Money.format brute force :subunit_to_unit = 5" do
519
- ("0.0".."9.4").each do |amt|
520
- next if amt[-1].to_i > 4
521
- amt.to_money("MGA").format(:symbol => false).should == amt
522
- end
523
- ("-0.1".."-9.4").each do |amt|
524
- next if amt[-1].to_i > 4
525
- amt.to_money("MGA").format(:symbol => false).should == amt
526
- end
527
- "1000.0".to_money("MGA").format(:symbol => false).should == "1,000.0"
528
- "-1000.0".to_money("MGA").format(:symbol => false).should == "-1,000.0"
529
- end
530
-
531
- specify "Money.format brute force :subunit_to_unit = 10" do
532
- ("0.0".."9.9").each do |amt|
533
- amt.to_money("VND").format(:symbol => false).should == amt.to_s.gsub(/\./, ",")
534
- end
535
- ("-0.1".."-9.9").each do |amt|
536
- amt.to_money("VND").format(:symbol => false).should == amt.to_s.gsub(/\./, ",")
537
- end
538
- "1000.0".to_money("VND").format(:symbol => false).should == "1.000,0"
539
- "-1000.0".to_money("VND").format(:symbol => false).should == "-1.000,0"
540
- end
541
-
542
- specify "Money.format brute force :subunit_to_unit = 100" do
543
- ("0.00".."9.99").each do |amt|
544
- amt.to_money("USD").format(:symbol => false).should == amt
545
- end
546
- ("-0.01".."-9.99").each do |amt|
547
- amt.to_money("USD").format(:symbol => false).should == amt
548
- end
549
- "1000.00".to_money("USD").format(:symbol => false).should == "1,000.00"
550
- "-1000.00".to_money("USD").format(:symbol => false).should == "-1,000.00"
551
- end
552
-
553
- specify "Money.format brute force :subunit_to_unit = 1000" do
554
- ("0.000".."9.999").each do |amt|
555
- amt.to_money("IQD").format(:symbol => false).should == amt
556
- end
557
- ("-0.001".."-9.999").each do |amt|
558
- amt.to_money("IQD").format(:symbol => false).should == amt
559
- end
560
- "1000.000".to_money("IQD").format(:symbol => false).should == "1,000.000"
561
- "-1000.000".to_money("IQD").format(:symbol => false).should == "-1,000.000"
562
- end
563
-
564
- specify "Money.to_s works" do
565
- Money.new(10_00).to_s.should == "10.00"
566
- Money.new(400_08).to_s.should == "400.08"
567
- Money.new(-237_43).to_s.should == "-237.43"
568
- end
569
-
570
- specify "Money.to_s should respect :subunit_to_unit currency property" do
571
- Money.new(10_00, "BHD").to_s.should == "1.000"
572
- Money.new(10_00, "CNY").to_s.should == "10.00"
573
- end
574
-
575
- specify "Money.to_s shouldn't have decimal when :subunit_to_unit is 1" do
576
- Money.new(10_00, "CLP").to_s.should == "1000"
577
- end
578
-
579
- specify "Money.to_s should work with :subunit_to_unit == 5" do
580
- Money.new(10_00, "MGA").to_s.should == "200.0"
581
- end
582
-
583
- specify "Money.to_s should respect :decimal_mark" do
584
- Money.new(10_00, "BRL").to_s.should == "10,00"
585
- end
586
-
587
- specify "Money.to_f works" do
588
- Money.new(10_00).to_f.should == 10.0
589
- end
590
-
591
- specify "Money.to_f should respect :subunit_to_unit currency property" do
592
- Money.new(10_00, "BHD").to_f.should == 1.0
593
- end
594
-
595
- specify "#symbol works as documented" do
596
- currency = Money::Currency.new("EUR")
597
- currency.should_receive(:symbol).and_return("€")
598
- Money.empty(currency).symbol.should == "€"
599
-
600
- currency = Money::Currency.new("EUR")
601
- currency.should_receive(:symbol).and_return(nil)
602
- Money.empty(currency).symbol.should == "¤"
603
- end
604
-
605
- {
606
- :thousands_separator => { :default => ",", :other => "." },
607
- :decimal_mark => { :default => ".", :other => "," }
608
- }.each do |method, options|
609
- describe "##{method}" do
610
- context "without I18n" do
611
- it "works as documented" do
612
- Money.empty("USD").send(method).should == options[:default]
613
- Money.empty("EUR").send(method).should == options[:other]
614
- Money.empty("BRL").send(method).should == options[:other]
615
- end
616
- end
617
-
618
- if Object.const_defined?("I18n")
619
- context "with I18n" do
620
- before :all do
621
- reset_i18n
622
- store_number_formats(:en, method => options[:default])
623
- store_number_formats(:de, method => options[:other])
624
- end
625
-
626
- it "looks up #{method} for current locale" do
627
- I18n.locale = :en
628
- Money.empty("USD").send(method).should == options[:default]
629
- I18n.locale = :de
630
- Money.empty("USD").send(method).should == options[:other]
631
- end
632
-
633
- it "fallbacks to default behaviour for missing translations" do
634
- I18n.locale = :de
635
- Money.empty("USD").send(method).should == options[:other]
636
- I18n.locale = :fr
637
- Money.empty("USD").send(method).should == options[:default]
638
- end
639
-
640
- after :all do
641
- reset_i18n
642
- end
643
- end
644
- else
645
- puts "can't test ##{method} with I18n because it isn't loaded"
646
- end
647
- end
648
- end
649
-
650
- describe "#format" do
651
- it "returns the monetary value as a string" do
652
- Money.ca_dollar(100).format.should == "$1.00"
653
- Money.new(40008).format.should == "$400.08"
654
- end
655
-
656
- it "should respect :subunit_to_unit currency property" do
657
- Money.new(10_00, "BHD").format.should == "ب.د1.000"
658
- end
659
-
660
- it "doesn't display a decimal when :subunit_to_unit is 1" do
661
- Money.new(10_00, "CLP").format.should == "$1.000"
662
- end
663
-
664
- it "respects the thousands_separator and decimal_mark defaults" do
665
- one_thousand = Proc.new do |currency|
666
- Money.new(1000_00, currency).format
667
- end
668
-
669
- # Pounds
670
- one_thousand["GBP"].should == "£1,000.00"
671
-
672
- # Dollars
673
- one_thousand["USD"].should == "$1,000.00"
674
- one_thousand["CAD"].should == "$1,000.00"
675
- one_thousand["AUD"].should == "$1,000.00"
676
- one_thousand["NZD"].should == "$1,000.00"
677
- one_thousand["ZWD"].should == "$1,000.00"
678
-
679
- # Yen
680
- one_thousand["JPY"].should == "¥1,000.00"
681
- one_thousand["CNY"].should == "¥1,000.00"
682
-
683
- # Euro
684
- one_thousand["EUR"].should == "1.000,00 €"
685
-
686
- # Rupees
687
- one_thousand["INR"].should == "₨1,000.00"
688
- one_thousand["NPR"].should == "₨1,000.00"
689
- one_thousand["SCR"].should == "1,000.00 ₨"
690
- one_thousand["LKR"].should == "1,000.00 ₨"
691
-
692
- # Brazilian Real
693
- one_thousand["BRL"].should == "R$ 1.000,00"
694
-
695
- # Other
696
- one_thousand["SEK"].should == "kr1,000.00"
697
- one_thousand["GHC"].should == "₵1,000.00"
698
- end
699
-
700
- describe "if the monetary value is 0" do
701
- before :each do
702
- @money = Money.us_dollar(0)
703
- end
704
-
705
- it "returns 'free' when :display_free is true" do
706
- @money.format(:display_free => true).should == 'free'
707
- end
708
-
709
- it "returns '$0.00' when :display_free is false or not given" do
710
- @money.format.should == '$0.00'
711
- @money.format(:display_free => false).should == '$0.00'
712
- @money.format(:display_free => nil).should == '$0.00'
713
- end
714
-
715
- it "returns the value specified by :display_free if it's a string-like object" do
716
- @money.format(:display_free => 'gratis').should == 'gratis'
717
- end
718
- end
719
-
720
- specify "#format(:with_currency => true) works as documented" do
721
- Money.ca_dollar(100).format(:with_currency => true).should == "$1.00 CAD"
722
- Money.us_dollar(85).format(:with_currency => true).should == "$0.85 USD"
723
- end
724
-
725
- specify "#format(:no_cents => true) works as documented" do
726
- Money.ca_dollar(100).format(:no_cents => true).should == "$1"
727
- Money.ca_dollar(599).format(:no_cents => true).should == "$5"
728
- Money.ca_dollar(570).format(:no_cents => true, :with_currency => true).should == "$5 CAD"
729
- Money.ca_dollar(39000).format(:no_cents => true).should == "$390"
730
- end
731
-
732
- specify "#format(:no_cents => true) should respect :subunit_to_unit currency property" do
733
- Money.new(10_00, "BHD").format(:no_cents => true).should == "ب.د1"
734
- end
735
-
736
- specify "#format(:symbol => a symbol string) uses the given value as the money symbol" do
737
- Money.new(100, "GBP").format(:symbol => "£").should == "£1.00"
738
- end
739
-
740
- specify "#format(:symbol => true) returns symbol based on the given currency code" do
741
- one = Proc.new do |currency|
742
- Money.new(100, currency).format(:symbol => true)
743
- end
744
-
745
- # Pounds
746
- one["GBP"].should == "£1.00"
747
-
748
- # Dollars
749
- one["USD"].should == "$1.00"
750
- one["CAD"].should == "$1.00"
751
- one["AUD"].should == "$1.00"
752
- one["NZD"].should == "$1.00"
753
- one["ZWD"].should == "$1.00"
754
-
755
- # Yen
756
- one["JPY"].should == "¥1.00"
757
- one["CNY"].should == "¥1.00"
758
-
759
- # Euro
760
- one["EUR"].should == "1,00 €"
761
-
762
- # Rupees
763
- one["INR"].should == "₨1.00"
764
- one["NPR"].should == "₨1.00"
765
- one["SCR"].should == "1.00 ₨"
766
- one["LKR"].should == "1.00 ₨"
767
-
768
- # Brazilian Real
769
- one["BRL"].should == "R$ 1,00"
770
-
771
- # Other
772
- one["SEK"].should == "kr1.00"
773
- one["GHC"].should == "₵1.00"
774
- end
775
-
776
- specify "#format(:symbol => true) returns $ when currency code is not recognized" do
777
- currency = Money::Currency.new("EUR")
778
- currency.should_receive(:symbol).and_return(nil)
779
- Money.new(100, currency).format(:symbol => true).should == "1,00 ¤"
780
- end
781
-
782
- specify "#format(:symbol => some non-Boolean value that evaluates to true) returns symbol based on the given currency code" do
783
- Money.new(100, "GBP").format(:symbol => true).should == "£1.00"
784
- Money.new(100, "EUR").format(:symbol => true).should == "1,00 €"
785
- Money.new(100, "SEK").format(:symbol => true).should == "kr1.00"
786
- end
787
-
788
- specify "#format with :symbol == "", nil or false returns the amount without a symbol" do
789
- money = Money.new(100, "GBP")
790
- money.format(:symbol => "").should == "1.00"
791
- money.format(:symbol => nil).should == "1.00"
792
- money.format(:symbol => false).should == "1.00"
793
- end
794
-
795
- specify "#format without :symbol assumes that :symbol is set to true" do
796
- money = Money.new(100)
797
- money.format.should == "$1.00"
798
-
799
- money = Money.new(100, "GBP")
800
- money.format.should == "£1.00"
801
-
802
- money = Money.new(100, "EUR")
803
- money.format.should == "1,00 €"
804
- end
805
-
806
- specify "#format(:decimal_mark => a decimal_mark string) works as documented" do
807
- Money.us_dollar(100).format(:decimal_mark => ",").should == "$1,00"
808
- end
809
-
810
- specify "#format will default decimal_mark to '.' if currency isn't recognized" do
811
- Money.new(100, "ZWD").format.should == "$1.00"
812
- end
813
-
814
- specify "#format(:separator => a separator string) works as documented" do
815
- Money.us_dollar(100).format(:separator => ",").should == "$1,00"
816
- end
817
-
818
- specify "#format(:thousands_separator => a thousands_separator string) works as documented" do
819
- Money.us_dollar(100000).format(:thousands_separator => ".").should == "$1.000.00"
820
- Money.us_dollar(200000).format(:thousands_separator => "").should == "$2000.00"
821
- end
822
-
823
- specify "#format(:thousands_separator => false or nil) works as documented" do
824
- Money.us_dollar(100000).format(:thousands_separator => false).should == "$1000.00"
825
- Money.us_dollar(200000).format(:thousands_separator => nil).should == "$2000.00"
826
- end
827
-
828
- specify "#format(:delimiter => a delimiter string) works as documented" do
829
- Money.us_dollar(100000).format(:delimiter => ".").should == "$1.000.00"
830
- Money.us_dollar(200000).format(:delimiter => "").should == "$2000.00"
831
- end
832
-
833
- specify "#format(:delimiter => false or nil) works as documented" do
834
- Money.us_dollar(100000).format(:delimiter => false).should == "$1000.00"
835
- Money.us_dollar(200000).format(:delimiter => nil).should == "$2000.00"
836
- end
837
-
838
- specify "#format will default thousands_separator to ',' if currency isn't recognized" do
839
- Money.new(100000, "ZWD").format.should == "$1,000.00"
840
- end
841
-
842
- specify "#format(:html => true) works as documented" do
843
- string = Money.ca_dollar(570).format(:html => true, :with_currency => true)
844
- string.should == "$5.70 <span class=\"currency\">CAD</span>"
845
- end
846
-
847
- it "should insert commas into the result if the amount is sufficiently large" do
848
- Money.us_dollar(1_000_000_000_12).format.should == "$1,000,000,000.12"
849
- Money.us_dollar(1_000_000_000_12).format(:no_cents => true).should == "$1,000,000,000"
850
- end
851
-
852
- it "inserts thousands separator into the result if the amount is sufficiently large and the currency symbol is at the end" do
853
- Money.euro(1_234_567_12).format.should == "1.234.567,12 €"
854
- Money.euro(1_234_567_12).format(:no_cents => true).should == "1.234.567 €"
855
- end
856
-
857
- it "inserts currency symbol before the amount when :symbol_position is set to :before" do
858
- Money.euro(1_234_567_12).format(:symbol_position => :before).should == "€1.234.567,12"
859
- end
860
-
861
- it "inserts currency symbol after the amount when :symbol_position is set to :after" do
862
- Money.us_dollar(1_000_000_000_12).format(:symbol_position => :after).should == "1,000,000,000.12 $"
863
- end
864
- end
865
-
866
-
867
- describe "Money.empty" do
868
- it "Money.empty creates a new Money object of 0 cents" do
869
- Money.empty.should == Money.new(0)
870
- end
871
- end
872
-
873
- describe "Money.ca_dollar" do
874
- it "creates a new Money object of the given value in CAD" do
875
- Money.ca_dollar(50).should == Money.new(50, "CAD")
876
- end
877
- end
878
-
879
- describe "Money.us_dollar" do
880
- it "creates a new Money object of the given value in USD" do
881
- Money.us_dollar(50).should == Money.new(50, "USD")
882
- end
883
- end
884
-
885
- describe "Money.euro" do
886
- it "creates a new Money object of the given value in EUR" do
887
- Money.euro(50).should == Money.new(50, "EUR")
888
- end
889
- end
890
-
891
-
892
- describe "Money.new_with_dollars" do
893
- it "converts given amount to cents" do
894
- Money.new_with_dollars(1).should == Money.new(100)
895
- Money.new_with_dollars(1, "USD").should == Money.new(100, "USD")
896
- Money.new_with_dollars(1, "EUR").should == Money.new(100, "EUR")
897
- end
898
-
899
- it "should respect :subunit_to_unit currency property" do
900
- Money.new_with_dollars(1, "USD").should == Money.new(1_00, "USD")
901
- Money.new_with_dollars(1, "TND").should == Money.new(1_000, "TND")
902
- Money.new_with_dollars(1, "CLP").should == Money.new(1, "CLP")
903
- end
904
-
905
- it "should not loose precision" do
906
- Money.new_with_dollars(1234).cents.should == 1234_00
907
- Money.new_with_dollars(100.37).cents.should == 100_37
908
- Money.new_with_dollars(BigDecimal.new('1234')).cents.should == 1234_00
909
- end
910
-
911
- it "accepts a currency options" do
912
- m = Money.new_with_dollars(1)
913
- m.currency.should == Money.default_currency
914
-
915
- m = Money.new_with_dollars(1, Money::Currency.wrap("EUR"))
916
- m.currency.should == Money::Currency.wrap("EUR")
917
-
918
- m = Money.new_with_dollars(1, "EUR")
919
- m.currency.should == Money::Currency.wrap("EUR")
920
- end
921
-
922
- it "accepts a bank options" do
923
- m = Money.new_with_dollars(1)
924
- m.bank.should == Money.default_bank
925
-
926
- m = Money.new_with_dollars(1, "EUR", bank = Object.new)
927
- m.bank.should == bank
928
- end
929
-
930
- it "is associated to the singleton instance of Bank::VariableExchange by default" do
931
- Money.new_with_dollars(0).bank.should be_equal(Money::Bank::VariableExchange.instance)
932
- end
933
- end
934
-
935
- describe "Money.from_string" do
936
- it "converts given amount to cents" do
937
- Money.from_string("1").should == Money.new(1_00)
938
- Money.from_string("1").should == Money.new(1_00, "USD")
939
- Money.from_string("1", "EUR").should == Money.new(1_00, "EUR")
940
- end
941
-
942
- it "should respect :subunit_to_unit currency property" do
943
- Money.from_string("1", "USD").should == Money.new(1_00, "USD")
944
- Money.from_string("1", "TND").should == Money.new(1_000, "TND")
945
- Money.from_string("1", "CLP").should == Money.new(1, "CLP")
946
- end
947
-
948
- it "accepts a currency options" do
949
- m = Money.from_string("1")
950
- m.currency.should == Money.default_currency
951
-
952
- m = Money.from_string("1", Money::Currency.wrap("EUR"))
953
- m.currency.should == Money::Currency.wrap("EUR")
954
-
955
- m = Money.from_string("1", "EUR")
956
- m.currency.should == Money::Currency.wrap("EUR")
957
- end
958
- end
959
-
960
- describe "Money.from_fixnum" do
961
- it "converts given amount to cents" do
962
- Money.from_fixnum(1).should == Money.new(1_00)
963
- Money.from_fixnum(1).should == Money.new(1_00, "USD")
964
- Money.from_fixnum(1, "EUR").should == Money.new(1_00, "EUR")
965
- end
966
-
967
- it "should respect :subunit_to_unit currency property" do
968
- Money.from_fixnum(1, "USD").should == Money.new(1_00, "USD")
969
- Money.from_fixnum(1, "TND").should == Money.new(1_000, "TND")
970
- Money.from_fixnum(1, "CLP").should == Money.new(1, "CLP")
971
- end
972
-
973
- it "accepts a currency options" do
974
- m = Money.from_fixnum(1)
975
- m.currency.should == Money.default_currency
976
-
977
- m = Money.from_fixnum(1, Money::Currency.wrap("EUR"))
978
- m.currency.should == Money::Currency.wrap("EUR")
979
-
980
- m = Money.from_fixnum(1, "EUR")
981
- m.currency.should == Money::Currency.wrap("EUR")
982
- end
983
- end
984
-
985
- describe "Money.from_float" do
986
- it "converts given amount to cents" do
987
- Money.from_float(1.2).should == Money.new(1_20)
988
- Money.from_float(1.2).should == Money.new(1_20, "USD")
989
- Money.from_float(1.2, "EUR").should == Money.new(1_20, "EUR")
990
- end
991
-
992
- it "should respect :subunit_to_unit currency property" do
993
- Money.from_float(1.2, "USD").should == Money.new(1_20, "USD")
994
- Money.from_float(1.2, "TND").should == Money.new(1_200, "TND")
995
- Money.from_float(1.2, "CLP").should == Money.new(1, "CLP")
996
- end
997
-
998
- it "accepts a currency options" do
999
- m = Money.from_float(1.2)
1000
- m.currency.should == Money.default_currency
1001
-
1002
- m = Money.from_float(1.2, Money::Currency.wrap("EUR"))
1003
- m.currency.should == Money::Currency.wrap("EUR")
1004
-
1005
- m = Money.from_float(1.2, "EUR")
1006
- m.currency.should == Money::Currency.wrap("EUR")
1007
- end
1008
- end
1009
-
1010
- describe "Money.from_bigdecimal" do
1011
- it "converts given amount to cents" do
1012
- Money.from_bigdecimal(BigDecimal.new("1")).should == Money.new(1_00)
1013
- Money.from_bigdecimal(BigDecimal.new("1")).should == Money.new(1_00, "USD")
1014
- Money.from_bigdecimal(BigDecimal.new("1"), "EUR").should == Money.new(1_00, "EUR")
1015
- end
1016
-
1017
- it "should respect :subunit_to_unit currency property" do
1018
- Money.from_bigdecimal(BigDecimal.new("1"), "USD").should == Money.new(1_00, "USD")
1019
- Money.from_bigdecimal(BigDecimal.new("1"), "TND").should == Money.new(1_000, "TND")
1020
- Money.from_bigdecimal(BigDecimal.new("1"), "CLP").should == Money.new(1, "CLP")
1021
- end
1022
-
1023
- it "accepts a currency options" do
1024
- m = Money.from_bigdecimal(BigDecimal.new("1"))
1025
- m.currency.should == Money.default_currency
1026
-
1027
- m = Money.from_bigdecimal(BigDecimal.new("1"), Money::Currency.wrap("EUR"))
1028
- m.currency.should == Money::Currency.wrap("EUR")
1029
-
1030
- m = Money.from_bigdecimal(BigDecimal.new("1"), "EUR")
1031
- m.currency.should == Money::Currency.wrap("EUR")
1032
- end
1033
- end
1034
-
1035
- describe "Money.from_numeric" do
1036
- it "converts given amount to cents" do
1037
- Money.from_numeric(1).should == Money.new(1_00)
1038
- Money.from_numeric(1.0).should == Money.new(1_00)
1039
- Money.from_numeric(BigDecimal.new("1")).should == Money.new(1_00)
1040
- end
1041
-
1042
- it "should raise ArgumentError with unsupported argument" do
1043
- lambda { Money.from_numeric("100") }.should raise_error(ArgumentError)
1044
- end
1045
-
1046
- it "should optimize workload" do
1047
- Money.should_receive(:from_fixnum).with(1, "USD").and_return(Money.new(1_00, "USD"))
1048
- Money.from_numeric(1, "USD").should == Money.new(1_00, "USD")
1049
- Money.should_receive(:from_bigdecimal).with(BigDecimal.new("1.0"), "USD").and_return(Money.new(1_00, "USD"))
1050
- Money.from_numeric(1.0, "USD").should == Money.new(1_00, "USD")
1051
- end
1052
-
1053
- it "should respect :subunit_to_unit currency property" do
1054
- Money.from_numeric(1, "USD").should == Money.new(1_00, "USD")
1055
- Money.from_numeric(1, "TND").should == Money.new(1_000, "TND")
1056
- Money.from_numeric(1, "CLP").should == Money.new(1, "CLP")
1057
- end
1058
-
1059
- it "accepts a bank option" do
1060
- Money.from_numeric(1).should == Money.new(1_00)
1061
- Money.from_numeric(1).should == Money.new(1_00, "USD")
1062
- Money.from_numeric(1, "EUR").should == Money.new(1_00, "EUR")
1063
- end
1064
-
1065
- it "accepts a currency options" do
1066
- m = Money.from_numeric(1)
1067
- m.currency.should == Money.default_currency
1068
-
1069
- m = Money.from_numeric(1, Money::Currency.wrap("EUR"))
1070
- m.currency.should == Money::Currency.wrap("EUR")
1071
-
1072
- m = Money.from_numeric(1, "EUR")
1073
- m.currency.should == Money::Currency.wrap("EUR")
1074
- end
1075
- end
1076
-
1077
- describe "split" do
1078
- specify "#split needs at least one party" do
1079
- lambda {Money.us_dollar(1).split(0)}.should raise_error(ArgumentError)
1080
- lambda {Money.us_dollar(1).split(-1)}.should raise_error(ArgumentError)
1081
- end
1082
-
1083
-
1084
- specify "#gives 1 cent to both people if we start with 2" do
1085
- Money.us_dollar(2).split(2).should == [Money.us_dollar(1), Money.us_dollar(1)]
1086
- end
1087
-
1088
- specify "#split may distribute no money to some parties if there isnt enough to go around" do
1089
- Money.us_dollar(2).split(3).should == [Money.us_dollar(1), Money.us_dollar(1), Money.us_dollar(0)]
1090
- end
1091
-
1092
- specify "#split does not lose pennies" do
1093
- Money.us_dollar(5).split(2).should == [Money.us_dollar(3), Money.us_dollar(2)]
1094
- end
1095
-
1096
- specify "#split a dollar" do
1097
- moneys = Money.us_dollar(100).split(3)
1098
- moneys[0].cents.should == 34
1099
- moneys[1].cents.should == 33
1100
- moneys[2].cents.should == 33
1101
- end
1102
- end
1103
-
1104
- describe "allocation" do
1105
- specify "#allocate takes no action when one gets all" do
1106
- Money.us_dollar(005).allocate([1.0]).should == [Money.us_dollar(5)]
1107
- end
1108
-
1109
- specify "#allocate keeps currencies intact" do
1110
- Money.ca_dollar(005).allocate([1]).should == [Money.ca_dollar(5)]
1111
- end
1112
-
1113
- specify "#allocate does not loose pennies" do
1114
- moneys = Money.us_dollar(5).allocate([0.3,0.7])
1115
- moneys[0].should == Money.us_dollar(2)
1116
- moneys[1].should == Money.us_dollar(3)
1117
- end
1118
-
1119
- specify "#allocate does not loose pennies" do
1120
- moneys = Money.us_dollar(100).allocate([0.333,0.333, 0.333])
1121
- moneys[0].cents.should == 34
1122
- moneys[1].cents.should == 33
1123
- moneys[2].cents.should == 33
1124
- end
1125
-
1126
- specify "#allocate requires total to be less then 1" do
1127
- lambda { Money.us_dollar(0.05).allocate([0.5,0.6]) }.should raise_error(ArgumentError)
1128
- end
1129
- end
1130
-
1131
- describe "Money.add_rate" do
1132
- it "saves rate into current bank" do
1133
- Money.add_rate("EUR", "USD", 10)
1134
- Money.new(10_00, "EUR").exchange_to("USD").should == Money.new(100_00, "USD")
1135
- end
1136
- end
1137
-
1138
-
1139
- # Sets $VERBOSE to nil for the duration of the block and back to its original value afterwards.
1140
- #
1141
- # silence_warnings do
1142
- # value = noisy_call # no warning voiced
1143
- # end
1144
- #
1145
- # noisy_call # warning voiced
1146
- def silence_warnings
1147
- old_verbose, $VERBOSE = $VERBOSE, nil
1148
- yield
1149
- ensure
1150
- $VERBOSE = old_verbose
1151
- end
1152
-
1153
- end
1154
-
1155
- describe "Actions involving two Money objects" do
1156
- describe "if the other Money object has the same currency" do
1157
- specify "#<=> compares the two object amounts" do
1158
- (Money.new(1_00, "USD") <=> Money.new(1_00, "USD")).should == 0
1159
- (Money.new(1_00, "USD") <=> Money.new(99, "USD")).should > 0
1160
- (Money.new(1_00, "USD") <=> Money.new(2_00, "USD")).should < 0
1161
- end
1162
-
1163
- specify "#+ adds other amount to current amount and returns a Money while retaining the currency" do
1164
- (Money.new(10_00, "USD") + Money.new(90, "USD")).should == Money.new(10_90, "USD")
1165
- end
1166
-
1167
- specify "#- subtracts other amount from current amount and returns a Money while retaining the currency" do
1168
- (Money.new(10_00, "USD") - Money.new(90, "USD")).should == Money.new(9_10, "USD")
1169
- end
1170
-
1171
- specify "#* should raise ArgumentError" do
1172
- lambda { Money.new(10_00, "USD") * Money.new(2, "USD") }.should raise_error(ArgumentError)
1173
- end
1174
-
1175
- specify "#/ divides current amount by other amount and returns a Float" do
1176
- (Money.new(10_00, "USD") / Money.new(100_00, "USD")).should == 0.1
1177
- end
1178
- end
1179
-
1180
- describe "if the other Money object has a different currency" do
1181
- specify "#<=> converts other object amount to current currency, then compares the two object amounts" do
1182
- target = Money.new(200_00, "EUR")
1183
- target.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(300_00, "USD"))
1184
- (Money.new(100_00, "USD") <=> target).should < 0
1185
-
1186
- target = Money.new(200_00, "EUR")
1187
- target.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(100_00, "USD"))
1188
- (Money.new(100_00, "USD") <=> target).should == 0
1189
-
1190
- target = Money.new(200_00, "EUR")
1191
- target.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(99_00, "USD"))
1192
- (Money.new(100_00, "USD") <=> target).should > 0
1193
- end
1194
-
1195
- specify "#+ converts other object amount to current currency, then adds other amount to current amount and returns a Money" do
1196
- other = Money.new(90, "EUR")
1197
- other.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(9_00, "USD"))
1198
- (Money.new(10_00, "USD") + other).should == Money.new(19_00, "USD")
1199
- end
1200
-
1201
- specify "#- converts other object amount to current currency, then subtracts other amount from current amount and returns a Money" do
1202
- other = Money.new(90, "EUR")
1203
- other.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(9_00, "USD"))
1204
- (Money.new(10_00, "USD") - other).should == Money.new(1_00, "USD")
1205
- end
1206
-
1207
- specify "#* should raise ArgumentError" do
1208
- lambda { Money.new(10_00, "USD") * Money.new(10, "EUR") }.should raise_error(ArgumentError)
1209
- end
1210
-
1211
- specify "#/ converts other object amount to current currency, then divides current amount by other amount and returns a Float" do
1212
- other = Money.new(1000, "EUR")
1213
- other.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(100_00, "USD"))
1214
- (Money.new(10_00, "USD") / other).should == 0.1
1215
- end
1216
- end
1217
- end
1218
-
1219
-
1220
- describe "Money.parse" do
1221
-
1222
- it "should be able to parse european-formatted inputs under 10EUR" do
1223
- five_ninety_five = Money.new(595, 'EUR')
1224
-
1225
- Money.parse('EUR 5,95').should == five_ninety_five
1226
- #TODO: try and handle these
1227
- #Money.parse('€5,95').should == five_ninety_five
1228
- #Money.parse('&#036;5.95').should == five_ninety_five
1229
- end
1230
-
1231
- it "should be able to parse european-formatted inputs with multiple thousands-seperators" do
1232
- Money.parse('EUR 1.234.567,89').should == Money.new(123456789, 'EUR')
1233
- Money.parse('EUR 1.111.234.567,89').should == Money.new(111123456789, 'EUR')
1234
- end
1235
-
1236
- it "should be able to parse USD-formatted inputs under $10" do
1237
- five_ninety_five = Money.new(595, 'USD')
1238
-
1239
- Money.parse(5.95).should == five_ninety_five
1240
- Money.parse('5.95').should == five_ninety_five
1241
- Money.parse('$5.95').should == five_ninety_five
1242
- Money.parse("\n $5.95 \n").should == five_ninety_five
1243
- Money.parse('$ 5.95').should == five_ninety_five
1244
- Money.parse('$5.95 ea.').should == five_ninety_five
1245
- Money.parse('$5.95, each').should == five_ninety_five
1246
- end
1247
-
1248
- it "should be able to parse USD-formatted inputs with multiple thousands-seperators" do
1249
- Money.parse('1,234,567.89').should == Money.new(123456789, 'USD')
1250
- Money.parse('1,111,234,567.89').should == Money.new(111123456789, 'USD')
1251
- end
1252
-
1253
- it "should not return a price if there is a price range" do
1254
- lambda {Money.parse('$5.95-10.95')}.should raise_error ArgumentError
1255
- lambda {Money.parse('$5.95 - 10.95')}.should raise_error ArgumentError
1256
- lambda {Money.parse('$5.95 - $10.95')}.should raise_error ArgumentError
1257
- end
1258
-
1259
- it "should not return a price for completely invalid input" do
1260
- # TODO: shouldn't these throw an error instead of being considered
1261
- # equal to $0.0?
1262
- empty_price = Money.new(0, 'USD')
1263
-
1264
- Money.parse(nil).should == empty_price
1265
- Money.parse('hellothere').should == empty_price
1266
- Money.parse('').should == empty_price
1267
- end
1268
- end
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe Money do
6
+
7
+ describe "#new" do
8
+ it "rounds the given cents to an integer" do
9
+ Money.new(1.00, "USD").cents.should == 1
10
+ Money.new(1.01, "USD").cents.should == 1
11
+ Money.new(1.50, "USD").cents.should == 2
12
+ end
13
+
14
+ it "is associated to the singleton instance of Bank::VariableExchange by default" do
15
+ Money.new(0).bank.should be_equal(Money::Bank::VariableExchange.instance)
16
+ end
17
+
18
+ end
19
+
20
+ describe "#cents" do
21
+ it "returns the amount of cents passed to the constructor" do
22
+ Money.new(200_00, "USD").cents.should == 200_00
23
+ end
24
+
25
+ it "stores cents as an integer regardless of what is passed into the constructor" do
26
+ [ Money.new(100), 1.to_money, 1.00.to_money, BigDecimal('1.00').to_money ].each do |m|
27
+ m.cents.should == 100
28
+ m.cents.should be_an_instance_of(Fixnum)
29
+ end
30
+ end
31
+ end
32
+
33
+ describe "#dollars" do
34
+ it "gets cents as dollars" do
35
+ Money.new_with_dollars(1).should == Money.new(100)
36
+ Money.new_with_dollars(1, "USD").should == Money.new(100, "USD")
37
+ Money.new_with_dollars(1, "EUR").should == Money.new(100, "EUR")
38
+ end
39
+
40
+ it "should respect :subunit_to_unit currency property" do
41
+ Money.new(1_00, "USD").dollars.should == 1
42
+ Money.new(1_000, "TND").dollars.should == 1
43
+ Money.new(1, "CLP").dollars.should == 1
44
+ end
45
+
46
+ it "should not loose precision" do
47
+ Money.new(100_37).dollars.should == 100.37
48
+ Money.new_with_dollars(100.37).dollars.should == 100.37
49
+ end
50
+ end
51
+
52
+ specify "#currency returns the currency passed to the constructor" do
53
+ Money.new(200_00, "USD").currency.should == Money::Currency.new("USD")
54
+ end
55
+
56
+ specify "#currency_string returns the iso_code of the currency object" do
57
+ Money.new(200_00, "USD").currency_as_string.should == Money::Currency.new("USD").to_s
58
+ Money.new(200_00, "USD").currency_as_string.should == "USD"
59
+ Money.new(200_00, "EUR").currency_as_string.should == "EUR"
60
+ Money.new(200_00, "YEN").currency_as_string.should == "YEN"
61
+ end
62
+
63
+ specify "#currency_string= set the currency object using the provided string" do
64
+ obj = Money.new(200_00, "USD")
65
+ obj.currency_as_string = "EUR"
66
+ obj.currency.should == Money::Currency.new("EUR")
67
+ obj.currency_as_string = "YEN"
68
+ obj.currency.should == Money::Currency.new("YEN")
69
+ obj.currency_as_string = "USD"
70
+ obj.currency.should == Money::Currency.new("USD")
71
+ end
72
+
73
+
74
+ specify "#exchange_to exchanges the amount via its exchange bank" do
75
+ money = Money.new(100_00, "USD")
76
+ money.bank.should_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')))
77
+ money.exchange_to("EUR")
78
+ end
79
+
80
+ specify "#exchange_to exchanges the amount properly" do
81
+ money = Money.new(100_00, "USD")
82
+ money.bank.should_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')))
83
+ money.exchange_to("EUR").should == Money.new(200_00, "EUR")
84
+ end
85
+
86
+ specify "#hash should return the same value for equal objects" do
87
+ Money.new(1_00, :eur).hash.should == Money.new(1_00, :eur).hash
88
+ Money.new(2_00, :usd).hash.should == Money.new(2_00, :usd).hash
89
+ Money.new(1_00, :eur).hash.should_not == Money.new(2_00, :eur).hash
90
+ Money.new(1_00, :eur).hash.should_not == Money.new(1_00, :usd).hash
91
+ Money.new(1_00, :eur).hash.should_not == Money.new(2_00, :usd).hash
92
+ end
93
+
94
+ specify "#hash can be used to return the intersection of Money object arrays" do
95
+ intersection = [Money.new(1_00, :eur), Money.new(1_00, :usd)] & [Money.new(1_00, :eur)]
96
+ intersection.should == [Money.new(1_00, :eur)]
97
+ end
98
+
99
+
100
+ specify "Money.to_s works" do
101
+ Money.new(10_00).to_s.should == "10.00"
102
+ Money.new(400_08).to_s.should == "400.08"
103
+ Money.new(-237_43).to_s.should == "-237.43"
104
+ end
105
+
106
+ specify "Money.to_s should respect :subunit_to_unit currency property" do
107
+ Money.new(10_00, "BHD").to_s.should == "1.000"
108
+ Money.new(10_00, "CNY").to_s.should == "10.00"
109
+ end
110
+
111
+ specify "Money.to_s shouldn't have decimal when :subunit_to_unit is 1" do
112
+ Money.new(10_00, "CLP").to_s.should == "1000"
113
+ end
114
+
115
+ specify "Money.to_s should work with :subunit_to_unit == 5" do
116
+ Money.new(10_00, "MGA").to_s.should == "200.0"
117
+ end
118
+
119
+ specify "Money.to_s should respect :decimal_mark" do
120
+ Money.new(10_00, "BRL").to_s.should == "10,00"
121
+ end
122
+
123
+ specify "Money.to_f works" do
124
+ Money.new(10_00).to_f.should == 10.0
125
+ end
126
+
127
+ specify "Money.to_f should respect :subunit_to_unit currency property" do
128
+ Money.new(10_00, "BHD").to_f.should == 1.0
129
+ end
130
+
131
+ specify "#symbol works as documented" do
132
+ currency = Money::Currency.new("EUR")
133
+ currency.should_receive(:symbol).and_return("€")
134
+ Money.empty(currency).symbol.should == "€"
135
+
136
+ currency = Money::Currency.new("EUR")
137
+ currency.should_receive(:symbol).and_return(nil)
138
+ Money.empty(currency).symbol.should == "¤"
139
+ end
140
+
141
+ describe "Money.empty" do
142
+ it "Money.empty creates a new Money object of 0 cents" do
143
+ Money.empty.should == Money.new(0)
144
+ end
145
+ end
146
+
147
+ describe "Money.ca_dollar" do
148
+ it "creates a new Money object of the given value in CAD" do
149
+ Money.ca_dollar(50).should == Money.new(50, "CAD")
150
+ end
151
+ end
152
+
153
+ describe "Money.us_dollar" do
154
+ it "creates a new Money object of the given value in USD" do
155
+ Money.us_dollar(50).should == Money.new(50, "USD")
156
+ end
157
+ end
158
+
159
+ describe "Money.euro" do
160
+ it "creates a new Money object of the given value in EUR" do
161
+ Money.euro(50).should == Money.new(50, "EUR")
162
+ end
163
+ end
164
+
165
+
166
+ describe "Money.new_with_dollars" do
167
+ it "converts given amount to cents" do
168
+ Money.new_with_dollars(1).should == Money.new(100)
169
+ Money.new_with_dollars(1, "USD").should == Money.new(100, "USD")
170
+ Money.new_with_dollars(1, "EUR").should == Money.new(100, "EUR")
171
+ end
172
+
173
+ it "should respect :subunit_to_unit currency property" do
174
+ Money.new_with_dollars(1, "USD").should == Money.new(1_00, "USD")
175
+ Money.new_with_dollars(1, "TND").should == Money.new(1_000, "TND")
176
+ Money.new_with_dollars(1, "CLP").should == Money.new(1, "CLP")
177
+ end
178
+
179
+ it "should not loose precision" do
180
+ Money.new_with_dollars(1234).cents.should == 1234_00
181
+ Money.new_with_dollars(100.37).cents.should == 100_37
182
+ Money.new_with_dollars(BigDecimal.new('1234')).cents.should == 1234_00
183
+ end
184
+
185
+ it "accepts a currency options" do
186
+ m = Money.new_with_dollars(1)
187
+ m.currency.should == Money.default_currency
188
+
189
+ m = Money.new_with_dollars(1, Money::Currency.wrap("EUR"))
190
+ m.currency.should == Money::Currency.wrap("EUR")
191
+
192
+ m = Money.new_with_dollars(1, "EUR")
193
+ m.currency.should == Money::Currency.wrap("EUR")
194
+ end
195
+
196
+ it "accepts a bank options" do
197
+ m = Money.new_with_dollars(1)
198
+ m.bank.should == Money.default_bank
199
+
200
+ m = Money.new_with_dollars(1, "EUR", bank = Object.new)
201
+ m.bank.should == bank
202
+ end
203
+
204
+ it "is associated to the singleton instance of Bank::VariableExchange by default" do
205
+ Money.new_with_dollars(0).bank.should be_equal(Money::Bank::VariableExchange.instance)
206
+ end
207
+ end
208
+
209
+ describe "split" do
210
+ specify "#split needs at least one party" do
211
+ lambda {Money.us_dollar(1).split(0)}.should raise_error(ArgumentError)
212
+ lambda {Money.us_dollar(1).split(-1)}.should raise_error(ArgumentError)
213
+ end
214
+
215
+
216
+ specify "#gives 1 cent to both people if we start with 2" do
217
+ Money.us_dollar(2).split(2).should == [Money.us_dollar(1), Money.us_dollar(1)]
218
+ end
219
+
220
+ specify "#split may distribute no money to some parties if there isnt enough to go around" do
221
+ Money.us_dollar(2).split(3).should == [Money.us_dollar(1), Money.us_dollar(1), Money.us_dollar(0)]
222
+ end
223
+
224
+ specify "#split does not lose pennies" do
225
+ Money.us_dollar(5).split(2).should == [Money.us_dollar(3), Money.us_dollar(2)]
226
+ end
227
+
228
+ specify "#split a dollar" do
229
+ moneys = Money.us_dollar(100).split(3)
230
+ moneys[0].cents.should == 34
231
+ moneys[1].cents.should == 33
232
+ moneys[2].cents.should == 33
233
+ end
234
+ end
235
+
236
+ describe "allocation" do
237
+ specify "#allocate takes no action when one gets all" do
238
+ Money.us_dollar(005).allocate([1.0]).should == [Money.us_dollar(5)]
239
+ end
240
+
241
+ specify "#allocate keeps currencies intact" do
242
+ Money.ca_dollar(005).allocate([1]).should == [Money.ca_dollar(5)]
243
+ end
244
+
245
+ specify "#allocate does not loose pennies" do
246
+ moneys = Money.us_dollar(5).allocate([0.3,0.7])
247
+ moneys[0].should == Money.us_dollar(2)
248
+ moneys[1].should == Money.us_dollar(3)
249
+ end
250
+
251
+ specify "#allocate does not loose pennies" do
252
+ moneys = Money.us_dollar(100).allocate([0.333,0.333, 0.333])
253
+ moneys[0].cents.should == 34
254
+ moneys[1].cents.should == 33
255
+ moneys[2].cents.should == 33
256
+ end
257
+
258
+ specify "#allocate requires total to be less then 1" do
259
+ lambda { Money.us_dollar(0.05).allocate([0.5,0.6]) }.should raise_error(ArgumentError)
260
+ end
261
+ end
262
+
263
+ describe "Money.add_rate" do
264
+ it "saves rate into current bank" do
265
+ Money.add_rate("EUR", "USD", 10)
266
+ Money.new(10_00, "EUR").exchange_to("USD").should == Money.new(100_00, "USD")
267
+ end
268
+ end
269
+
270
+ end
271
+