money 3.7.1 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/CHANGELOG.md +384 -351
  2. data/LICENSE +21 -21
  3. data/README.md +243 -214
  4. data/Rakefile +49 -49
  5. data/lib/money.rb +28 -27
  6. data/lib/money/bank/base.rb +131 -131
  7. data/lib/money/bank/variable_exchange.rb +252 -252
  8. data/lib/money/core_extensions.rb +82 -82
  9. data/lib/money/currency.rb +263 -422
  10. data/lib/money/currency_loader.rb +19 -0
  11. data/lib/money/money.rb +405 -405
  12. data/lib/money/money/arithmetic.rb +246 -246
  13. data/lib/money/money/formatting.rb +260 -244
  14. data/lib/money/money/parsing.rb +350 -350
  15. data/money.gemspec +29 -35
  16. data/spec/bank/base_spec.rb +72 -72
  17. data/spec/bank/variable_exchange_spec.rb +238 -238
  18. data/spec/core_extensions_spec.rb +158 -158
  19. data/spec/currency_spec.rb +120 -133
  20. data/spec/money/arithmetic_spec.rb +479 -479
  21. data/spec/money/formatting_spec.rb +383 -375
  22. data/spec/money/parsing_spec.rb +197 -197
  23. data/spec/money_spec.rb +292 -292
  24. data/spec/spec_helper.rb +28 -28
  25. metadata +54 -126
  26. data/lib/money.rbc +0 -184
  27. data/lib/money/bank/base.rbc +0 -818
  28. data/lib/money/bank/variable_exchange.rbc +0 -2550
  29. data/lib/money/core_extensions.rbc +0 -664
  30. data/lib/money/currency.rbc +0 -22708
  31. data/lib/money/money.rbc +0 -3861
  32. data/lib/money/money/arithmetic.rbc +0 -2778
  33. data/lib/money/money/formatting.rbc +0 -2265
  34. data/lib/money/money/parsing.rbc +0 -2737
  35. data/spec/bank/base_spec.rbc +0 -2461
  36. data/spec/bank/variable_exchange_spec.rbc +0 -7541
  37. data/spec/core_extensions_spec.rbc +0 -5921
  38. data/spec/currency_spec.rbc +0 -4535
  39. data/spec/money/arithmetic_spec.rbc +0 -25140
  40. data/spec/money/formatting_spec.rbc +0 -12545
  41. data/spec/money/parsing_spec.rbc +0 -6511
  42. data/spec/money_spec.rbc +0 -9824
  43. data/spec/spec_helper.rbc +0 -575
@@ -1,479 +1,479 @@
1
- # encoding: utf-8
2
-
3
- require "spec_helper"
4
-
5
- describe Money do
6
- specify "#zero? returns whether the amount is 0" do
7
- Money.new(0, "USD").should be_zero
8
- Money.new(0, "EUR").should be_zero
9
- Money.new(1, "USD").should_not be_zero
10
- Money.new(10, "YEN").should_not be_zero
11
- Money.new(-1, "EUR").should_not be_zero
12
- end
13
-
14
- specify "#nonzero? returns whether the amount is not 0" do
15
- Money.new(0, "USD").should_not be_nonzero
16
- Money.new(0, "EUR").should_not be_nonzero
17
- Money.new(1, "USD").should be_nonzero
18
- Money.new(10, "YEN").should be_nonzero
19
- Money.new(-1, "EUR").should be_nonzero
20
- end
21
-
22
- specify "#nonzero? has the same return-value semantics as Numeric#nonzero?" do
23
- Money.new(0, "USD").nonzero?.should be_nil
24
-
25
- money = Money.new(1, "USD")
26
- money.nonzero?.should be_equal(money)
27
- end
28
-
29
- specify "#== returns true if and only if their amount and currency are equal" do
30
- Money.new(1_00, "USD").should == Money.new(1_00, "USD")
31
- Money.new(1_00, "USD").should_not == Money.new(1_00, "EUR")
32
- Money.new(1_00, "USD").should_not == Money.new(2_00, "USD")
33
- Money.new(1_00, "USD").should_not == Money.new(99_00, "EUR")
34
- end
35
-
36
- specify "#== can be used to compare with a String money value" do
37
- Money.new(1_00, "USD").should == "1.00"
38
- Money.new(1_00, "USD").should_not == "2.00"
39
- Money.new(1_00, "GBP").should_not == "1.00"
40
- end
41
-
42
- specify "#== can be used to compare with a Numeric money value" do
43
- Money.new(1_00, "USD").should == 1
44
- Money.new(1_57, "USD").should == 1.57
45
- Money.new(1_00, "USD").should_not == 2
46
- Money.new(1_00, "GBP").should_not == 1
47
- end
48
-
49
- specify "#== can be used to compare with an object that responds to #to_money" do
50
- klass = Class.new do
51
- def initialize(money)
52
- @money = money
53
- end
54
-
55
- def to_money
56
- @money
57
- end
58
- end
59
-
60
- Money.new(1_00, "USD").should == klass.new(Money.new(1_00, "USD"))
61
- Money.new(2_50, "USD").should == klass.new(Money.new(2_50, "USD"))
62
- Money.new(2_50, "USD").should_not == klass.new(Money.new(3_00, "USD"))
63
- Money.new(1_00, "GBP").should_not == klass.new(Money.new(1_00, "USD"))
64
- end
65
-
66
- specify "#== returns false if used to compare with an object that doesn't respond to #to_money" do
67
- Money.new(1_00, "USD").should_not == Object.new
68
- Money.new(1_00, "USD").should_not == Class
69
- Money.new(1_00, "USD").should_not == Kernel
70
- Money.new(1_00, "USD").should_not == /foo/
71
- Money.new(1_00, "USD").should_not == nil
72
- end
73
-
74
- specify "#eql? returns true if and only if their amount and currency are equal" do
75
- Money.new(1_00, "USD").eql?(Money.new(1_00, "USD")).should be true
76
- Money.new(1_00, "USD").eql?(Money.new(1_00, "EUR")).should be false
77
- Money.new(1_00, "USD").eql?(Money.new(2_00, "USD")).should be false
78
- Money.new(1_00, "USD").eql?(Money.new(99_00, "EUR")).should be false
79
- end
80
-
81
- specify "#eql? can be used to compare with a String money value" do
82
- Money.new(1_00, "USD").eql?("1.00").should be true
83
- Money.new(1_00, "USD").eql?("2.00").should be false
84
- Money.new(1_00, "GBP").eql?("1.00").should be false
85
- end
86
-
87
- specify "#eql? can be used to compare with a Numeric money value" do
88
- Money.new(1_00, "USD").eql?(1).should be true
89
- Money.new(1_57, "USD").eql?(1.57).should be true
90
- Money.new(1_00, "USD").eql?(2).should be false
91
- Money.new(1_00, "GBP").eql?(1).should be false
92
- end
93
-
94
- specify "#eql? can be used to compare with an object that responds to #to_money" do
95
- klass = Class.new do
96
- def initialize(money)
97
- @money = money
98
- end
99
-
100
- def to_money
101
- @money
102
- end
103
- end
104
-
105
- Money.new(1_00, "USD").eql?(klass.new(Money.new(1_00, "USD"))).should be true
106
- Money.new(2_50, "USD").eql?(klass.new(Money.new(2_50, "USD"))).should be true
107
- Money.new(2_50, "USD").eql?(klass.new(Money.new(3_00, "USD"))).should be false
108
- Money.new(1_00, "GBP").eql?(klass.new(Money.new(1_00, "USD"))).should be false
109
- end
110
-
111
- specify "#eql? returns false if used to compare with an object that doesn't respond to #to_money" do
112
- Money.new(1_00, "USD").eql?(Object.new).should be false
113
- Money.new(1_00, "USD").eql?(Class).should be false
114
- Money.new(1_00, "USD").eql?(Kernel).should be false
115
- Money.new(1_00, "USD").eql?(/foo/).should be false
116
- Money.new(1_00, "USD").eql?(nil).should be false
117
- end
118
-
119
- specify "#<=> can be used to compare with a String money value" do
120
- (Money.new(1_00) <=> "1.00").should == 0
121
- (Money.new(1_00) <=> ".99").should > 0
122
- (Money.new(1_00) <=> "2.00").should < 0
123
- end
124
-
125
- specify "#<=> can be used to compare with a Numeric money value" do
126
- (Money.new(1_00) <=> 1).should == 0
127
- (Money.new(1_00) <=> 0.99).should > 0
128
- (Money.new(1_00) <=> 2.00).should < 0
129
- end
130
-
131
- specify "#<=> can be used to compare with an object that responds to #to_money" do
132
- klass = Class.new do
133
- def initialize(money)
134
- @money = money
135
- end
136
-
137
- def to_money
138
- @money
139
- end
140
- end
141
-
142
- (Money.new(1_00) <=> klass.new(Money.new(1_00))).should == 0
143
- (Money.new(1_00) <=> klass.new(Money.new(99))).should > 0
144
- (Money.new(1_00) <=> klass.new(Money.new(2_00))).should < 0
145
- end
146
-
147
- specify "#<=> raises ArgumentError when used to compare with an object that doesn't respond to #to_money" do
148
- expected_message = /Comparison .+ failed/
149
- lambda{ Money.new(1_00) <=> Object.new }.should raise_error(ArgumentError, expected_message)
150
- lambda{ Money.new(1_00) <=> Class }.should raise_error(ArgumentError, expected_message)
151
- lambda{ Money.new(1_00) <=> Kernel }.should raise_error(ArgumentError, expected_message)
152
- lambda{ Money.new(1_00) <=> /foo/ }.should raise_error(ArgumentError, expected_message)
153
- end
154
-
155
- describe "#*" do
156
- it "should multiply current money amount by the multiplier while retaining the currency" do
157
- (Money.new(1_00, "USD") * 10).should == Money.new(10_00, "USD")
158
- end
159
-
160
- it "should multiply Money by Fixnum and returns Money" do
161
- ts = [
162
- {:a => Money.new( 10, :USD), :b => 4, :c => Money.new( 40, :USD)},
163
- {:a => Money.new( 10, :USD), :b => -4, :c => Money.new(-40, :USD)},
164
- {:a => Money.new(-10, :USD), :b => 4, :c => Money.new(-40, :USD)},
165
- {:a => Money.new(-10, :USD), :b => -4, :c => Money.new( 40, :USD)},
166
- ]
167
- ts.each do |t|
168
- (t[:a] * t[:b]).should == t[:c]
169
- end
170
- end
171
-
172
- it "should not multiply Money by Money (same currency)" do
173
- lambda { Money.new( 10, :USD) * Money.new( 4, :USD) }.should raise_error(ArgumentError)
174
- end
175
-
176
- it "should not multiply Money by Money (different currency)" do
177
- lambda { Money.new( 10, :USD) * Money.new( 4, :EUR) }.should raise_error(ArgumentError)
178
- end
179
- end
180
-
181
- describe "#/" do
182
- it "divides current money amount by the divisor while retaining the currency" do
183
- (Money.new(10_00, "USD") / 10).should == Money.new(1_00, "USD")
184
- end
185
-
186
- it "divides Money by Fixnum and returns Money" do
187
- ts = [
188
- {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 3, :USD)},
189
- {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-4, :USD)},
190
- {:a => Money.new(-13, :USD), :b => 4, :c => Money.new(-4, :USD)},
191
- {:a => Money.new(-13, :USD), :b => -4, :c => Money.new( 3, :USD)},
192
- ]
193
- ts.each do |t|
194
- (t[:a] / t[:b]).should == t[:c]
195
- end
196
- end
197
-
198
- it "divides Money by Money (same currency) and returns Float" do
199
- ts = [
200
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => 3.25},
201
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => -3.25},
202
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => -3.25},
203
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => 3.25},
204
- ]
205
- ts.each do |t|
206
- (t[:a] / t[:b]).should == t[:c]
207
- end
208
- end
209
-
210
- it "divides Money by Money (different currency) and returns Float" do
211
- ts = [
212
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => 1.625},
213
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => -1.625},
214
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => -1.625},
215
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => 1.625},
216
- ]
217
- ts.each do |t|
218
- t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
219
- (t[:a] / t[:b]).should == t[:c]
220
- end
221
- end
222
- end
223
-
224
- specify "#div -> money / fixnum" do
225
- ts = [
226
- {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 3, :USD)},
227
- {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-4, :USD)},
228
- {:a => Money.new(-13, :USD), :b => 4, :c => Money.new(-4, :USD)},
229
- {:a => Money.new(-13, :USD), :b => -4, :c => Money.new( 3, :USD)},
230
- ]
231
- ts.each do |t|
232
- t[:a].div(t[:b]).should == t[:c]
233
- end
234
- end
235
-
236
- specify "#div -> money / money (same currency)" do
237
- ts = [
238
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => 3.25},
239
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => -3.25},
240
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => -3.25},
241
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => 3.25},
242
- ]
243
- ts.each do |t|
244
- t[:a].div(t[:b]).should == t[:c]
245
- end
246
- end
247
-
248
- specify "#div -> money / money (different currency)" do
249
- ts = [
250
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => 1.625},
251
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => -1.625},
252
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => -1.625},
253
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => 1.625},
254
- ]
255
- ts.each do |t|
256
- t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
257
- t[:a].div(t[:b]).should == t[:c]
258
- end
259
- end
260
-
261
- specify "#divmod -> money `divmod` fixnum" do
262
- ts = [
263
- {:a => Money.new( 13, :USD), :b => 4, :c => [Money.new( 3, :USD), Money.new( 1, :USD)]},
264
- {:a => Money.new( 13, :USD), :b => -4, :c => [Money.new(-4, :USD), Money.new(-3, :USD)]},
265
- {:a => Money.new(-13, :USD), :b => 4, :c => [Money.new(-4, :USD), Money.new( 3, :USD)]},
266
- {:a => Money.new(-13, :USD), :b => -4, :c => [Money.new( 3, :USD), Money.new(-1, :USD)]},
267
- ]
268
- ts.each do |t|
269
- t[:a].divmod(t[:b]).should == t[:c]
270
- end
271
- end
272
-
273
- specify "#divmod -> money `divmod` money (same currency)" do
274
- ts = [
275
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => [ 3, Money.new( 1, :USD)]},
276
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => [-4, Money.new(-3, :USD)]},
277
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => [-4, Money.new( 3, :USD)]},
278
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => [ 3, Money.new(-1, :USD)]},
279
- ]
280
- ts.each do |t|
281
- t[:a].divmod(t[:b]).should == t[:c]
282
- end
283
- end
284
-
285
- specify "#divmod -> money `divmod` money (different currency)" do
286
- ts = [
287
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => [ 1, Money.new( 5, :USD)]},
288
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => [-2, Money.new(-3, :USD)]},
289
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => [-2, Money.new( 3, :USD)]},
290
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => [ 1, Money.new(-5, :USD)]},
291
- ]
292
- ts.each do |t|
293
- t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
294
- t[:a].divmod(t[:b]).should == t[:c]
295
- end
296
- end
297
-
298
- specify "#modulo -> money `modulo` fixnum" do
299
- ts = [
300
- {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 1, :USD)},
301
- {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-3, :USD)},
302
- {:a => Money.new(-13, :USD), :b => 4, :c => Money.new( 3, :USD)},
303
- {:a => Money.new(-13, :USD), :b => -4, :c => Money.new(-1, :USD)},
304
- ]
305
- ts.each do |t|
306
- t[:a].modulo(t[:b]).should == t[:c]
307
- end
308
- end
309
-
310
- specify "#modulo -> money `modulo` money (same currency)" do
311
- ts = [
312
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => Money.new( 1, :USD)},
313
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => Money.new(-3, :USD)},
314
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => Money.new( 3, :USD)},
315
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => Money.new(-1, :USD)},
316
- ]
317
- ts.each do |t|
318
- t[:a].modulo(t[:b]).should == t[:c]
319
- end
320
- end
321
-
322
- specify "#modulo -> money `modulo` money (different currency)" do
323
- ts = [
324
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => Money.new( 5, :USD)},
325
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => Money.new(-3, :USD)},
326
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => Money.new( 3, :USD)},
327
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => Money.new(-5, :USD)},
328
- ]
329
- ts.each do |t|
330
- t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
331
- t[:a].modulo(t[:b]).should == t[:c]
332
- end
333
- end
334
-
335
- specify "#% -> money % fixnum" do
336
- ts = [
337
- {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 1, :USD)},
338
- {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-3, :USD)},
339
- {:a => Money.new(-13, :USD), :b => 4, :c => Money.new( 3, :USD)},
340
- {:a => Money.new(-13, :USD), :b => -4, :c => Money.new(-1, :USD)},
341
- ]
342
- ts.each do |t|
343
- (t[:a] % t[:b]).should == t[:c]
344
- end
345
- end
346
-
347
- specify "#% -> money % money (same currency)" do
348
- ts = [
349
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => Money.new( 1, :USD)},
350
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => Money.new(-3, :USD)},
351
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => Money.new( 3, :USD)},
352
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => Money.new(-1, :USD)},
353
- ]
354
- ts.each do |t|
355
- (t[:a] % t[:b]).should == t[:c]
356
- end
357
- end
358
-
359
- specify "#% -> money % money (different currency)" do
360
- ts = [
361
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => Money.new( 5, :USD)},
362
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => Money.new(-3, :USD)},
363
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => Money.new( 3, :USD)},
364
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => Money.new(-5, :USD)},
365
- ]
366
- ts.each do |t|
367
- t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
368
- (t[:a] % t[:b]).should == t[:c]
369
- end
370
- end
371
-
372
- specify "#remainder -> money `remainder` fixnum" do
373
- ts = [
374
- {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 1, :USD)},
375
- {:a => Money.new( 13, :USD), :b => -4, :c => Money.new( 1, :USD)},
376
- {:a => Money.new(-13, :USD), :b => 4, :c => Money.new(-1, :USD)},
377
- {:a => Money.new(-13, :USD), :b => -4, :c => Money.new(-1, :USD)},
378
- ]
379
- ts.each do |t|
380
- t[:a].remainder(t[:b]).should == t[:c]
381
- end
382
- end
383
-
384
- specify "#remainder -> money `remainder` money (same currency)" do
385
- ts = [
386
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => Money.new( 1, :USD)},
387
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => Money.new( 1, :USD)},
388
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => Money.new(-1, :USD)},
389
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => Money.new(-1, :USD)},
390
- ]
391
- ts.each do |t|
392
- t[:a].remainder(t[:b]).should == t[:c]
393
- end
394
- end
395
-
396
- specify "#remainder -> money `remainder` money (different currency)" do
397
- ts = [
398
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => Money.new( 5, :USD)},
399
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => Money.new( 5, :USD)},
400
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => Money.new(-5, :USD)},
401
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => Money.new(-5, :USD)},
402
- ]
403
- ts.each do |t|
404
- t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
405
- t[:a].remainder(t[:b]).should == t[:c]
406
- end
407
- end
408
-
409
- specify "#abs correctly returns the absolute value as a new Money object" do
410
- n = Money.new(-1, :USD)
411
- n.abs.should == Money.new( 1, :USD)
412
- n.should == Money.new(-1, :USD)
413
- end
414
-
415
- describe "Actions involving two Money objects" do
416
- describe "if the other Money object has the same currency" do
417
- specify "#<=> compares the two object amounts" do
418
- (Money.new(1_00, "USD") <=> Money.new(1_00, "USD")).should == 0
419
- (Money.new(1_00, "USD") <=> Money.new(99, "USD")).should > 0
420
- (Money.new(1_00, "USD") <=> Money.new(2_00, "USD")).should < 0
421
- end
422
-
423
- specify "#+ adds other amount to current amount and returns a Money while retaining the currency" do
424
- (Money.new(10_00, "USD") + Money.new(90, "USD")).should == Money.new(10_90, "USD")
425
- end
426
-
427
- specify "#- subtracts other amount from current amount and returns a Money while retaining the currency" do
428
- (Money.new(10_00, "USD") - Money.new(90, "USD")).should == Money.new(9_10, "USD")
429
- end
430
-
431
- specify "#* should raise ArgumentError" do
432
- lambda { Money.new(10_00, "USD") * Money.new(2, "USD") }.should raise_error(ArgumentError)
433
- end
434
-
435
- specify "#/ divides current amount by other amount and returns a Float" do
436
- (Money.new(10_00, "USD") / Money.new(100_00, "USD")).should == 0.1
437
- end
438
- end
439
-
440
- describe "if the other Money object has a different currency" do
441
- specify "#<=> converts other object amount to current currency, then compares the two object amounts" do
442
- target = Money.new(200_00, "EUR")
443
- target.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(300_00, "USD"))
444
- (Money.new(100_00, "USD") <=> target).should < 0
445
-
446
- target = Money.new(200_00, "EUR")
447
- target.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(100_00, "USD"))
448
- (Money.new(100_00, "USD") <=> target).should == 0
449
-
450
- target = Money.new(200_00, "EUR")
451
- target.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(99_00, "USD"))
452
- (Money.new(100_00, "USD") <=> target).should > 0
453
- end
454
-
455
- specify "#+ converts other object amount to current currency, then adds other amount to current amount and returns a Money" do
456
- other = Money.new(90, "EUR")
457
- other.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(9_00, "USD"))
458
- (Money.new(10_00, "USD") + other).should == Money.new(19_00, "USD")
459
- end
460
-
461
- specify "#- converts other object amount to current currency, then subtracts other amount from current amount and returns a Money" do
462
- other = Money.new(90, "EUR")
463
- other.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(9_00, "USD"))
464
- (Money.new(10_00, "USD") - other).should == Money.new(1_00, "USD")
465
- end
466
-
467
- specify "#* should raise ArgumentError" do
468
- lambda { Money.new(10_00, "USD") * Money.new(10, "EUR") }.should raise_error(ArgumentError)
469
- end
470
-
471
- specify "#/ converts other object amount to current currency, then divides current amount by other amount and returns a Float" do
472
- other = Money.new(1000, "EUR")
473
- other.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(100_00, "USD"))
474
- (Money.new(10_00, "USD") / other).should == 0.1
475
- end
476
- end
477
- end
478
-
479
- end
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe Money do
6
+ specify "#zero? returns whether the amount is 0" do
7
+ Money.new(0, "USD").should be_zero
8
+ Money.new(0, "EUR").should be_zero
9
+ Money.new(1, "USD").should_not be_zero
10
+ Money.new(10, "YEN").should_not be_zero
11
+ Money.new(-1, "EUR").should_not be_zero
12
+ end
13
+
14
+ specify "#nonzero? returns whether the amount is not 0" do
15
+ Money.new(0, "USD").should_not be_nonzero
16
+ Money.new(0, "EUR").should_not be_nonzero
17
+ Money.new(1, "USD").should be_nonzero
18
+ Money.new(10, "YEN").should be_nonzero
19
+ Money.new(-1, "EUR").should be_nonzero
20
+ end
21
+
22
+ specify "#nonzero? has the same return-value semantics as Numeric#nonzero?" do
23
+ Money.new(0, "USD").nonzero?.should be_nil
24
+
25
+ money = Money.new(1, "USD")
26
+ money.nonzero?.should be_equal(money)
27
+ end
28
+
29
+ specify "#== returns true if and only if their amount and currency are equal" do
30
+ Money.new(1_00, "USD").should == Money.new(1_00, "USD")
31
+ Money.new(1_00, "USD").should_not == Money.new(1_00, "EUR")
32
+ Money.new(1_00, "USD").should_not == Money.new(2_00, "USD")
33
+ Money.new(1_00, "USD").should_not == Money.new(99_00, "EUR")
34
+ end
35
+
36
+ specify "#== can be used to compare with a String money value" do
37
+ Money.new(1_00, "USD").should == "1.00"
38
+ Money.new(1_00, "USD").should_not == "2.00"
39
+ Money.new(1_00, "GBP").should_not == "1.00"
40
+ end
41
+
42
+ specify "#== can be used to compare with a Numeric money value" do
43
+ Money.new(1_00, "USD").should == 1
44
+ Money.new(1_57, "USD").should == 1.57
45
+ Money.new(1_00, "USD").should_not == 2
46
+ Money.new(1_00, "GBP").should_not == 1
47
+ end
48
+
49
+ specify "#== can be used to compare with an object that responds to #to_money" do
50
+ klass = Class.new do
51
+ def initialize(money)
52
+ @money = money
53
+ end
54
+
55
+ def to_money
56
+ @money
57
+ end
58
+ end
59
+
60
+ Money.new(1_00, "USD").should == klass.new(Money.new(1_00, "USD"))
61
+ Money.new(2_50, "USD").should == klass.new(Money.new(2_50, "USD"))
62
+ Money.new(2_50, "USD").should_not == klass.new(Money.new(3_00, "USD"))
63
+ Money.new(1_00, "GBP").should_not == klass.new(Money.new(1_00, "USD"))
64
+ end
65
+
66
+ specify "#== returns false if used to compare with an object that doesn't respond to #to_money" do
67
+ Money.new(1_00, "USD").should_not == Object.new
68
+ Money.new(1_00, "USD").should_not == Class
69
+ Money.new(1_00, "USD").should_not == Kernel
70
+ Money.new(1_00, "USD").should_not == /foo/
71
+ Money.new(1_00, "USD").should_not == nil
72
+ end
73
+
74
+ specify "#eql? returns true if and only if their amount and currency are equal" do
75
+ Money.new(1_00, "USD").eql?(Money.new(1_00, "USD")).should be true
76
+ Money.new(1_00, "USD").eql?(Money.new(1_00, "EUR")).should be false
77
+ Money.new(1_00, "USD").eql?(Money.new(2_00, "USD")).should be false
78
+ Money.new(1_00, "USD").eql?(Money.new(99_00, "EUR")).should be false
79
+ end
80
+
81
+ specify "#eql? can be used to compare with a String money value" do
82
+ Money.new(1_00, "USD").eql?("1.00").should be true
83
+ Money.new(1_00, "USD").eql?("2.00").should be false
84
+ Money.new(1_00, "GBP").eql?("1.00").should be false
85
+ end
86
+
87
+ specify "#eql? can be used to compare with a Numeric money value" do
88
+ Money.new(1_00, "USD").eql?(1).should be true
89
+ Money.new(1_57, "USD").eql?(1.57).should be true
90
+ Money.new(1_00, "USD").eql?(2).should be false
91
+ Money.new(1_00, "GBP").eql?(1).should be false
92
+ end
93
+
94
+ specify "#eql? can be used to compare with an object that responds to #to_money" do
95
+ klass = Class.new do
96
+ def initialize(money)
97
+ @money = money
98
+ end
99
+
100
+ def to_money
101
+ @money
102
+ end
103
+ end
104
+
105
+ Money.new(1_00, "USD").eql?(klass.new(Money.new(1_00, "USD"))).should be true
106
+ Money.new(2_50, "USD").eql?(klass.new(Money.new(2_50, "USD"))).should be true
107
+ Money.new(2_50, "USD").eql?(klass.new(Money.new(3_00, "USD"))).should be false
108
+ Money.new(1_00, "GBP").eql?(klass.new(Money.new(1_00, "USD"))).should be false
109
+ end
110
+
111
+ specify "#eql? returns false if used to compare with an object that doesn't respond to #to_money" do
112
+ Money.new(1_00, "USD").eql?(Object.new).should be false
113
+ Money.new(1_00, "USD").eql?(Class).should be false
114
+ Money.new(1_00, "USD").eql?(Kernel).should be false
115
+ Money.new(1_00, "USD").eql?(/foo/).should be false
116
+ Money.new(1_00, "USD").eql?(nil).should be false
117
+ end
118
+
119
+ specify "#<=> can be used to compare with a String money value" do
120
+ (Money.new(1_00) <=> "1.00").should == 0
121
+ (Money.new(1_00) <=> ".99").should > 0
122
+ (Money.new(1_00) <=> "2.00").should < 0
123
+ end
124
+
125
+ specify "#<=> can be used to compare with a Numeric money value" do
126
+ (Money.new(1_00) <=> 1).should == 0
127
+ (Money.new(1_00) <=> 0.99).should > 0
128
+ (Money.new(1_00) <=> 2.00).should < 0
129
+ end
130
+
131
+ specify "#<=> can be used to compare with an object that responds to #to_money" do
132
+ klass = Class.new do
133
+ def initialize(money)
134
+ @money = money
135
+ end
136
+
137
+ def to_money
138
+ @money
139
+ end
140
+ end
141
+
142
+ (Money.new(1_00) <=> klass.new(Money.new(1_00))).should == 0
143
+ (Money.new(1_00) <=> klass.new(Money.new(99))).should > 0
144
+ (Money.new(1_00) <=> klass.new(Money.new(2_00))).should < 0
145
+ end
146
+
147
+ specify "#<=> raises ArgumentError when used to compare with an object that doesn't respond to #to_money" do
148
+ expected_message = /Comparison .+ failed/
149
+ lambda{ Money.new(1_00) <=> Object.new }.should raise_error(ArgumentError, expected_message)
150
+ lambda{ Money.new(1_00) <=> Class }.should raise_error(ArgumentError, expected_message)
151
+ lambda{ Money.new(1_00) <=> Kernel }.should raise_error(ArgumentError, expected_message)
152
+ lambda{ Money.new(1_00) <=> /foo/ }.should raise_error(ArgumentError, expected_message)
153
+ end
154
+
155
+ describe "#*" do
156
+ it "should multiply current money amount by the multiplier while retaining the currency" do
157
+ (Money.new(1_00, "USD") * 10).should == Money.new(10_00, "USD")
158
+ end
159
+
160
+ it "should multiply Money by Fixnum and returns Money" do
161
+ ts = [
162
+ {:a => Money.new( 10, :USD), :b => 4, :c => Money.new( 40, :USD)},
163
+ {:a => Money.new( 10, :USD), :b => -4, :c => Money.new(-40, :USD)},
164
+ {:a => Money.new(-10, :USD), :b => 4, :c => Money.new(-40, :USD)},
165
+ {:a => Money.new(-10, :USD), :b => -4, :c => Money.new( 40, :USD)},
166
+ ]
167
+ ts.each do |t|
168
+ (t[:a] * t[:b]).should == t[:c]
169
+ end
170
+ end
171
+
172
+ it "should not multiply Money by Money (same currency)" do
173
+ lambda { Money.new( 10, :USD) * Money.new( 4, :USD) }.should raise_error(ArgumentError)
174
+ end
175
+
176
+ it "should not multiply Money by Money (different currency)" do
177
+ lambda { Money.new( 10, :USD) * Money.new( 4, :EUR) }.should raise_error(ArgumentError)
178
+ end
179
+ end
180
+
181
+ describe "#/" do
182
+ it "divides current money amount by the divisor while retaining the currency" do
183
+ (Money.new(10_00, "USD") / 10).should == Money.new(1_00, "USD")
184
+ end
185
+
186
+ it "divides Money by Fixnum and returns Money" do
187
+ ts = [
188
+ {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 3, :USD)},
189
+ {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-4, :USD)},
190
+ {:a => Money.new(-13, :USD), :b => 4, :c => Money.new(-4, :USD)},
191
+ {:a => Money.new(-13, :USD), :b => -4, :c => Money.new( 3, :USD)},
192
+ ]
193
+ ts.each do |t|
194
+ (t[:a] / t[:b]).should == t[:c]
195
+ end
196
+ end
197
+
198
+ it "divides Money by Money (same currency) and returns Float" do
199
+ ts = [
200
+ {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => 3.25},
201
+ {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => -3.25},
202
+ {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => -3.25},
203
+ {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => 3.25},
204
+ ]
205
+ ts.each do |t|
206
+ (t[:a] / t[:b]).should == t[:c]
207
+ end
208
+ end
209
+
210
+ it "divides Money by Money (different currency) and returns Float" do
211
+ ts = [
212
+ {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => 1.625},
213
+ {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => -1.625},
214
+ {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => -1.625},
215
+ {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => 1.625},
216
+ ]
217
+ ts.each do |t|
218
+ t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
219
+ (t[:a] / t[:b]).should == t[:c]
220
+ end
221
+ end
222
+ end
223
+
224
+ specify "#div -> money / fixnum" do
225
+ ts = [
226
+ {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 3, :USD)},
227
+ {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-4, :USD)},
228
+ {:a => Money.new(-13, :USD), :b => 4, :c => Money.new(-4, :USD)},
229
+ {:a => Money.new(-13, :USD), :b => -4, :c => Money.new( 3, :USD)},
230
+ ]
231
+ ts.each do |t|
232
+ t[:a].div(t[:b]).should == t[:c]
233
+ end
234
+ end
235
+
236
+ specify "#div -> money / money (same currency)" do
237
+ ts = [
238
+ {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => 3.25},
239
+ {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => -3.25},
240
+ {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => -3.25},
241
+ {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => 3.25},
242
+ ]
243
+ ts.each do |t|
244
+ t[:a].div(t[:b]).should == t[:c]
245
+ end
246
+ end
247
+
248
+ specify "#div -> money / money (different currency)" do
249
+ ts = [
250
+ {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => 1.625},
251
+ {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => -1.625},
252
+ {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => -1.625},
253
+ {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => 1.625},
254
+ ]
255
+ ts.each do |t|
256
+ t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
257
+ t[:a].div(t[:b]).should == t[:c]
258
+ end
259
+ end
260
+
261
+ specify "#divmod -> money `divmod` fixnum" do
262
+ ts = [
263
+ {:a => Money.new( 13, :USD), :b => 4, :c => [Money.new( 3, :USD), Money.new( 1, :USD)]},
264
+ {:a => Money.new( 13, :USD), :b => -4, :c => [Money.new(-4, :USD), Money.new(-3, :USD)]},
265
+ {:a => Money.new(-13, :USD), :b => 4, :c => [Money.new(-4, :USD), Money.new( 3, :USD)]},
266
+ {:a => Money.new(-13, :USD), :b => -4, :c => [Money.new( 3, :USD), Money.new(-1, :USD)]},
267
+ ]
268
+ ts.each do |t|
269
+ t[:a].divmod(t[:b]).should == t[:c]
270
+ end
271
+ end
272
+
273
+ specify "#divmod -> money `divmod` money (same currency)" do
274
+ ts = [
275
+ {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => [ 3, Money.new( 1, :USD)]},
276
+ {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => [-4, Money.new(-3, :USD)]},
277
+ {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => [-4, Money.new( 3, :USD)]},
278
+ {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => [ 3, Money.new(-1, :USD)]},
279
+ ]
280
+ ts.each do |t|
281
+ t[:a].divmod(t[:b]).should == t[:c]
282
+ end
283
+ end
284
+
285
+ specify "#divmod -> money `divmod` money (different currency)" do
286
+ ts = [
287
+ {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => [ 1, Money.new( 5, :USD)]},
288
+ {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => [-2, Money.new(-3, :USD)]},
289
+ {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => [-2, Money.new( 3, :USD)]},
290
+ {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => [ 1, Money.new(-5, :USD)]},
291
+ ]
292
+ ts.each do |t|
293
+ t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
294
+ t[:a].divmod(t[:b]).should == t[:c]
295
+ end
296
+ end
297
+
298
+ specify "#modulo -> money `modulo` fixnum" do
299
+ ts = [
300
+ {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 1, :USD)},
301
+ {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-3, :USD)},
302
+ {:a => Money.new(-13, :USD), :b => 4, :c => Money.new( 3, :USD)},
303
+ {:a => Money.new(-13, :USD), :b => -4, :c => Money.new(-1, :USD)},
304
+ ]
305
+ ts.each do |t|
306
+ t[:a].modulo(t[:b]).should == t[:c]
307
+ end
308
+ end
309
+
310
+ specify "#modulo -> money `modulo` money (same currency)" do
311
+ ts = [
312
+ {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => Money.new( 1, :USD)},
313
+ {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => Money.new(-3, :USD)},
314
+ {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => Money.new( 3, :USD)},
315
+ {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => Money.new(-1, :USD)},
316
+ ]
317
+ ts.each do |t|
318
+ t[:a].modulo(t[:b]).should == t[:c]
319
+ end
320
+ end
321
+
322
+ specify "#modulo -> money `modulo` money (different currency)" do
323
+ ts = [
324
+ {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => Money.new( 5, :USD)},
325
+ {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => Money.new(-3, :USD)},
326
+ {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => Money.new( 3, :USD)},
327
+ {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => Money.new(-5, :USD)},
328
+ ]
329
+ ts.each do |t|
330
+ t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
331
+ t[:a].modulo(t[:b]).should == t[:c]
332
+ end
333
+ end
334
+
335
+ specify "#% -> money % fixnum" do
336
+ ts = [
337
+ {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 1, :USD)},
338
+ {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-3, :USD)},
339
+ {:a => Money.new(-13, :USD), :b => 4, :c => Money.new( 3, :USD)},
340
+ {:a => Money.new(-13, :USD), :b => -4, :c => Money.new(-1, :USD)},
341
+ ]
342
+ ts.each do |t|
343
+ (t[:a] % t[:b]).should == t[:c]
344
+ end
345
+ end
346
+
347
+ specify "#% -> money % money (same currency)" do
348
+ ts = [
349
+ {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => Money.new( 1, :USD)},
350
+ {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => Money.new(-3, :USD)},
351
+ {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => Money.new( 3, :USD)},
352
+ {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => Money.new(-1, :USD)},
353
+ ]
354
+ ts.each do |t|
355
+ (t[:a] % t[:b]).should == t[:c]
356
+ end
357
+ end
358
+
359
+ specify "#% -> money % money (different currency)" do
360
+ ts = [
361
+ {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => Money.new( 5, :USD)},
362
+ {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => Money.new(-3, :USD)},
363
+ {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => Money.new( 3, :USD)},
364
+ {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => Money.new(-5, :USD)},
365
+ ]
366
+ ts.each do |t|
367
+ t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
368
+ (t[:a] % t[:b]).should == t[:c]
369
+ end
370
+ end
371
+
372
+ specify "#remainder -> money `remainder` fixnum" do
373
+ ts = [
374
+ {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 1, :USD)},
375
+ {:a => Money.new( 13, :USD), :b => -4, :c => Money.new( 1, :USD)},
376
+ {:a => Money.new(-13, :USD), :b => 4, :c => Money.new(-1, :USD)},
377
+ {:a => Money.new(-13, :USD), :b => -4, :c => Money.new(-1, :USD)},
378
+ ]
379
+ ts.each do |t|
380
+ t[:a].remainder(t[:b]).should == t[:c]
381
+ end
382
+ end
383
+
384
+ specify "#remainder -> money `remainder` money (same currency)" do
385
+ ts = [
386
+ {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => Money.new( 1, :USD)},
387
+ {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => Money.new( 1, :USD)},
388
+ {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => Money.new(-1, :USD)},
389
+ {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => Money.new(-1, :USD)},
390
+ ]
391
+ ts.each do |t|
392
+ t[:a].remainder(t[:b]).should == t[:c]
393
+ end
394
+ end
395
+
396
+ specify "#remainder -> money `remainder` money (different currency)" do
397
+ ts = [
398
+ {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => Money.new( 5, :USD)},
399
+ {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => Money.new( 5, :USD)},
400
+ {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => Money.new(-5, :USD)},
401
+ {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => Money.new(-5, :USD)},
402
+ ]
403
+ ts.each do |t|
404
+ t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
405
+ t[:a].remainder(t[:b]).should == t[:c]
406
+ end
407
+ end
408
+
409
+ specify "#abs correctly returns the absolute value as a new Money object" do
410
+ n = Money.new(-1, :USD)
411
+ n.abs.should == Money.new( 1, :USD)
412
+ n.should == Money.new(-1, :USD)
413
+ end
414
+
415
+ describe "Actions involving two Money objects" do
416
+ describe "if the other Money object has the same currency" do
417
+ specify "#<=> compares the two object amounts" do
418
+ (Money.new(1_00, "USD") <=> Money.new(1_00, "USD")).should == 0
419
+ (Money.new(1_00, "USD") <=> Money.new(99, "USD")).should > 0
420
+ (Money.new(1_00, "USD") <=> Money.new(2_00, "USD")).should < 0
421
+ end
422
+
423
+ specify "#+ adds other amount to current amount and returns a Money while retaining the currency" do
424
+ (Money.new(10_00, "USD") + Money.new(90, "USD")).should == Money.new(10_90, "USD")
425
+ end
426
+
427
+ specify "#- subtracts other amount from current amount and returns a Money while retaining the currency" do
428
+ (Money.new(10_00, "USD") - Money.new(90, "USD")).should == Money.new(9_10, "USD")
429
+ end
430
+
431
+ specify "#* should raise ArgumentError" do
432
+ lambda { Money.new(10_00, "USD") * Money.new(2, "USD") }.should raise_error(ArgumentError)
433
+ end
434
+
435
+ specify "#/ divides current amount by other amount and returns a Float" do
436
+ (Money.new(10_00, "USD") / Money.new(100_00, "USD")).should == 0.1
437
+ end
438
+ end
439
+
440
+ describe "if the other Money object has a different currency" do
441
+ specify "#<=> converts other object amount to current currency, then compares the two object amounts" do
442
+ target = Money.new(200_00, "EUR")
443
+ target.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(300_00, "USD"))
444
+ (Money.new(100_00, "USD") <=> target).should < 0
445
+
446
+ target = Money.new(200_00, "EUR")
447
+ target.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(100_00, "USD"))
448
+ (Money.new(100_00, "USD") <=> target).should == 0
449
+
450
+ target = Money.new(200_00, "EUR")
451
+ target.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(99_00, "USD"))
452
+ (Money.new(100_00, "USD") <=> target).should > 0
453
+ end
454
+
455
+ specify "#+ converts other object amount to current currency, then adds other amount to current amount and returns a Money" do
456
+ other = Money.new(90, "EUR")
457
+ other.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(9_00, "USD"))
458
+ (Money.new(10_00, "USD") + other).should == Money.new(19_00, "USD")
459
+ end
460
+
461
+ specify "#- converts other object amount to current currency, then subtracts other amount from current amount and returns a Money" do
462
+ other = Money.new(90, "EUR")
463
+ other.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(9_00, "USD"))
464
+ (Money.new(10_00, "USD") - other).should == Money.new(1_00, "USD")
465
+ end
466
+
467
+ specify "#* should raise ArgumentError" do
468
+ lambda { Money.new(10_00, "USD") * Money.new(10, "EUR") }.should raise_error(ArgumentError)
469
+ end
470
+
471
+ specify "#/ converts other object amount to current currency, then divides current amount by other amount and returns a Float" do
472
+ other = Money.new(1000, "EUR")
473
+ other.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(100_00, "USD"))
474
+ (Money.new(10_00, "USD") / other).should == 0.1
475
+ end
476
+ end
477
+ end
478
+
479
+ end