simple_money 0.2.1 → 0.3.0
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/.gemtest +0 -0
- data/Rakefile +49 -0
- data/simple_money.gemspec +23 -0
- data/spec/simple_money/currency_spec.rb +43 -0
- data/spec/simple_money/money_spec.rb +840 -0
- metadata +17 -7
data/.gemtest
ADDED
File without changes
|
data/Rakefile
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/clean'
|
3
|
+
|
4
|
+
CLOBBER.include('doc', '.yardoc')
|
5
|
+
|
6
|
+
def gemspec
|
7
|
+
@gemspec ||= begin
|
8
|
+
file = File.expand_path("../simple_money.gemspec", __FILE__)
|
9
|
+
eval(File.read(file), binding, file)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
begin
|
14
|
+
require 'rspec/core/rake_task'
|
15
|
+
RSpec::Core::RakeTask.new
|
16
|
+
rescue LoadError
|
17
|
+
task(:spec){abort "`gem install rspec` to run specs"}
|
18
|
+
end
|
19
|
+
task :default => :spec
|
20
|
+
task :test => :spec
|
21
|
+
|
22
|
+
begin
|
23
|
+
require 'yard'
|
24
|
+
YARD::Rake::YardocTask.new do |t|
|
25
|
+
t.options << "--files" << "CHANGELOG.md,LICENSE"
|
26
|
+
end
|
27
|
+
rescue LoadError
|
28
|
+
task(:yardoc){abort "`gem install yard` to generate documentation"}
|
29
|
+
end
|
30
|
+
|
31
|
+
begin
|
32
|
+
require 'rake/gempackagetask'
|
33
|
+
Rake::GemPackageTask.new(gemspec) do |pkg|
|
34
|
+
pkg.gem_spec = gemspec
|
35
|
+
end
|
36
|
+
task :gem => :gemspec
|
37
|
+
rescue LoadError
|
38
|
+
task(:gem){abort "`gem install rake` to package gems"}
|
39
|
+
end
|
40
|
+
|
41
|
+
desc "Install the gem locally"
|
42
|
+
task :install => :gem do
|
43
|
+
sh "gem install pkg/#{gemspec.full_name}.gem"
|
44
|
+
end
|
45
|
+
|
46
|
+
desc "Validate the gemspec"
|
47
|
+
task :gemspec do
|
48
|
+
gemspec.validate
|
49
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "simple_money"
|
3
|
+
s.version = "0.3.0"
|
4
|
+
s.platform = Gem::Platform::RUBY
|
5
|
+
s.authors = ["Shane Emmons"]
|
6
|
+
s.email = "semmons99@gmail.com"
|
7
|
+
s.homepage = "http://github.com/semmons99/simple_money"
|
8
|
+
s.summary = "Library to work with money/currency."
|
9
|
+
s.description = "This gem is intended for working with financial calculations (money/currency) where you need highly accurate results."
|
10
|
+
|
11
|
+
s.required_ruby_version = ">= 1.8.7"
|
12
|
+
s.required_rubygems_version = ">= 1.3.7"
|
13
|
+
|
14
|
+
s.add_development_dependency "rspec", ">= 2.0.0"
|
15
|
+
s.add_development_dependency "yard"
|
16
|
+
|
17
|
+
s.files = Dir.glob("{lib,spec}/**/*")
|
18
|
+
s.files += %w(CHANGELOG.md LICENSE README.md)
|
19
|
+
s.files += %w(Rakefile .gemtest simple_money.gemspec)
|
20
|
+
|
21
|
+
s.require_path = "lib"
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'simple_money/currency'
|
2
|
+
|
3
|
+
describe "Currency" do
|
4
|
+
|
5
|
+
USD = Currency::CurrencyStruct.new(
|
6
|
+
1, "USD", "United States Dollar", "$", "Cent", 100, 2, true, "$", ".", ","
|
7
|
+
)
|
8
|
+
|
9
|
+
describe "#[]" do
|
10
|
+
|
11
|
+
it "should return a Hash pertaining to the requested currency id" do
|
12
|
+
Currency[:usd].should == USD
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should work with and uppercase string" do
|
16
|
+
Currency["USD"].should == USD
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should work with a lowercase string" do
|
20
|
+
Currency["usd"].should == USD
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should work with a uppercase symbol" do
|
24
|
+
Currency[:USD].should == USD
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should work with a lowercase symbol" do
|
28
|
+
Currency[:usd].should == USD
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should raise an ArgumentError if an invalid currency is requested" do
|
32
|
+
lambda{
|
33
|
+
Currency[:not_a_real_currency]
|
34
|
+
}.should raise_error ArgumentError
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should return the argument if it is already a CurrencyStruct" do
|
38
|
+
Currency[USD].should == USD
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,840 @@
|
|
1
|
+
require 'simple_money/money'
|
2
|
+
|
3
|
+
describe "Money" do
|
4
|
+
|
5
|
+
# Make sure defaults are reset
|
6
|
+
after :each do
|
7
|
+
Money.default_as = :cents
|
8
|
+
Money.default_rounding_method = :bankers
|
9
|
+
Money.default_currency = :usd
|
10
|
+
Money.reset_overflow
|
11
|
+
end
|
12
|
+
|
13
|
+
describe ".default_as" do
|
14
|
+
|
15
|
+
it "should return the default as used to create a new Money" do
|
16
|
+
Money.default_as.should == :cents
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
describe ".default_as=" do
|
22
|
+
|
23
|
+
it "should set the default as used to create a new Money" do
|
24
|
+
Money.default_as = :decimal
|
25
|
+
Money.default_as.should == :decimal
|
26
|
+
|
27
|
+
Money.default_as = :cents
|
28
|
+
Money.default_as.should == :cents
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should raise an ArgumentError unless as is valid" do
|
32
|
+
lambda{Money.default_as = :foo}.should raise_error ArgumentError
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
describe ".valid_as?" do
|
38
|
+
|
39
|
+
it "should return true if as is valid" do
|
40
|
+
Money.valid_as?(:cents).should == true
|
41
|
+
Money.valid_as?(:decimal).should == true
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should return false if as is invalid" do
|
45
|
+
Money.valid_as?(:foo).should == false
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
describe ".default_rounding_method" do
|
51
|
+
|
52
|
+
it "should return the default rounding method used" do
|
53
|
+
Money.default_rounding_method.should == :bankers
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
describe ".default_rounding_method=" do
|
59
|
+
|
60
|
+
it "should set the default rounding method" do
|
61
|
+
Money.default_rounding_method = :away_from_zero
|
62
|
+
Money.default_rounding_method.should == :away_from_zero
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should raise an ArgumentError unless rounding method is valid" do
|
66
|
+
lambda{
|
67
|
+
Money.default_rounding_method = :foo
|
68
|
+
}.should raise_error ArgumentError
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
describe ".valid_rounding_method?" do
|
74
|
+
|
75
|
+
it "should return true if rounding method is valid" do
|
76
|
+
Money.valid_rounding_method?(:away_from_zero).should == true
|
77
|
+
Money.valid_rounding_method?(:toward_zero).should == true
|
78
|
+
Money.valid_rounding_method?(:nearest_up).should == true
|
79
|
+
Money.valid_rounding_method?(:nearest_down).should == true
|
80
|
+
Money.valid_rounding_method?(:bankers).should == true
|
81
|
+
Money.valid_rounding_method?(:up).should == true
|
82
|
+
Money.valid_rounding_method?(:down).should == true
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should return false if rounding method is invalid" do
|
86
|
+
Money.valid_rounding_method?(:foo).should == false
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
describe ".default_currency" do
|
92
|
+
|
93
|
+
it "should return the default currency used" do
|
94
|
+
Money.default_currency.should == Currency[:usd]
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
describe ".default_currency=" do
|
100
|
+
|
101
|
+
it "should set the default currency used" do
|
102
|
+
Money.default_currency.should == Currency[:usd]
|
103
|
+
Money.default_currency = :eur
|
104
|
+
Money.default_currency.should == Currency[:eur]
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should raise and ArgumentError unless the currency is valid" do
|
108
|
+
lambda{
|
109
|
+
Money.default_currency = :not_a_real_currency
|
110
|
+
}.should raise_error ArgumentError
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
describe ".overflow" do
|
116
|
+
|
117
|
+
it "should return the sum of all rounded calculations" do
|
118
|
+
Money.overflow.should == BigDecimal("0")
|
119
|
+
Money.new(1.29)
|
120
|
+
Money.overflow.should == BigDecimal("0.29")
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
describe ".overflow=" do
|
126
|
+
|
127
|
+
it "should set the overflow to the provided value" do
|
128
|
+
Money.overflow.should == BigDecimal("0")
|
129
|
+
Money.overflow = 5
|
130
|
+
Money.overflow.should == BigDecimal("5")
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
describe ".reset_overflow" do
|
136
|
+
|
137
|
+
it "should reset the overflow bucket to 0" do
|
138
|
+
Money.overflow.should == BigDecimal("0")
|
139
|
+
Money.new(1.29)
|
140
|
+
Money.overflow.should == BigDecimal("0.29")
|
141
|
+
Money.reset_overflow
|
142
|
+
Money.overflow.should == BigDecimal("0")
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
describe ".round" do
|
148
|
+
|
149
|
+
context "without rounding method given" do
|
150
|
+
|
151
|
+
it "should round n using the default rounding method" do
|
152
|
+
Money.round(1.5).should == 2
|
153
|
+
Money.round(2.5).should == 2
|
154
|
+
Money.round(-1.5).should == -2
|
155
|
+
Money.round(-2.5).should == -2
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should added rounded fractional cents to the overflow bucket" do
|
159
|
+
Money.round(1.5)
|
160
|
+
Money.overflow.should == BigDecimal("-0.5")
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
context "with rounding method given" do
|
166
|
+
|
167
|
+
it "should round n using the given rounding method" do
|
168
|
+
Money.round(1.5, :away_from_zero).should == 2
|
169
|
+
Money.round(1.5, :toward_zero).should == 1
|
170
|
+
Money.round(1.5, :nearest_up).should == 2
|
171
|
+
Money.round(1.5, :nearest_down).should == 1
|
172
|
+
Money.round(1.5, :bankers).should == 2
|
173
|
+
Money.round(1.5, :up).should == 2
|
174
|
+
Money.round(1.5, :down).should == 1
|
175
|
+
|
176
|
+
Money.round(2.5, :away_from_zero).should == 3
|
177
|
+
Money.round(2.5, :toward_zero).should == 2
|
178
|
+
Money.round(2.5, :nearest_up).should == 3
|
179
|
+
Money.round(2.5, :nearest_down).should == 2
|
180
|
+
Money.round(2.5, :bankers).should == 2
|
181
|
+
Money.round(2.5, :up).should == 3
|
182
|
+
Money.round(2.5, :down).should == 2
|
183
|
+
|
184
|
+
Money.round(-1.5, :away_from_zero).should == -2
|
185
|
+
Money.round(-1.5, :toward_zero).should == -1
|
186
|
+
Money.round(-1.5, :nearest_up).should == -2
|
187
|
+
Money.round(-1.5, :nearest_down).should == -1
|
188
|
+
Money.round(-1.5, :bankers).should == -2
|
189
|
+
Money.round(-1.5, :up).should == -1
|
190
|
+
Money.round(-1.5, :down).should == -2
|
191
|
+
|
192
|
+
Money.round(-2.5, :away_from_zero).should == -3
|
193
|
+
Money.round(-2.5, :toward_zero).should == -2
|
194
|
+
Money.round(-2.5, :nearest_up).should == -3
|
195
|
+
Money.round(-2.5, :nearest_down).should == -2
|
196
|
+
Money.round(-2.5, :bankers).should == -2
|
197
|
+
Money.round(-2.5, :up).should == -2
|
198
|
+
Money.round(-2.5, :down).should == -3
|
199
|
+
end
|
200
|
+
|
201
|
+
it "should added rounded fractional cents to the overflow bucket" do
|
202
|
+
Money.round(1.5, :away_from_zero)
|
203
|
+
Money.overflow.should == BigDecimal("-0.5")
|
204
|
+
end
|
205
|
+
|
206
|
+
it "should raise an ArgumentError unless rounding method is valid" do
|
207
|
+
lambda{
|
208
|
+
Money.round(1.29, :foo)
|
209
|
+
}.should raise_error ArgumentError
|
210
|
+
end
|
211
|
+
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|
215
|
+
|
216
|
+
describe "#new" do
|
217
|
+
|
218
|
+
context "without value given" do
|
219
|
+
|
220
|
+
it "should default cents to 0" do
|
221
|
+
Money.new.cents.should == 0
|
222
|
+
end
|
223
|
+
|
224
|
+
end
|
225
|
+
|
226
|
+
context "with value given" do
|
227
|
+
|
228
|
+
it "should set cents appropriately" do
|
229
|
+
(0..100).each do |n|
|
230
|
+
Money.new(n).cents.should == n
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
it "should added rounded fractional cents to the overflow bucket" do
|
235
|
+
Money.new(1.5)
|
236
|
+
Money.overflow.should == BigDecimal("-0.5")
|
237
|
+
end
|
238
|
+
|
239
|
+
end
|
240
|
+
|
241
|
+
context "with :as => :cents" do
|
242
|
+
|
243
|
+
it "should treat passed value as cents" do
|
244
|
+
(0..100).each do |n|
|
245
|
+
Money.new(n, :as => :cents).cents.should == n
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
it "should added rounded fractional cents to the overflow bucket" do
|
250
|
+
Money.new(1.5, :as => :cents)
|
251
|
+
Money.overflow.should == BigDecimal("-0.5")
|
252
|
+
end
|
253
|
+
|
254
|
+
end
|
255
|
+
|
256
|
+
context "with :as => :decimal" do
|
257
|
+
|
258
|
+
it "should treat passed value as a decimal" do
|
259
|
+
("0.01".."1.00").map(&:to_f).each do |n|
|
260
|
+
Money.new(n, :as => :decimal).cents.should == (
|
261
|
+
Money.round BigDecimal(n.to_s) * 100
|
262
|
+
)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
it "should added rounded fractional cents to the overflow bucket" do
|
267
|
+
Money.new(1.555, :as => :decimal)
|
268
|
+
Money.overflow.should == BigDecimal("-0.5")
|
269
|
+
end
|
270
|
+
|
271
|
+
end
|
272
|
+
|
273
|
+
context "with invalid :as" do
|
274
|
+
|
275
|
+
it "should raise an ArgumentError" do
|
276
|
+
lambda{
|
277
|
+
Money.new(1_00, :as => :foo)
|
278
|
+
}.should raise_error ArgumentError
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
it "should use the default :as" do
|
283
|
+
Money.default_as = :decimal
|
284
|
+
("0.01".."1.00").map(&:to_f).each do |n|
|
285
|
+
Money.new(n).cents.should == (
|
286
|
+
Money.round BigDecimal(n.to_s) * 100
|
287
|
+
)
|
288
|
+
end
|
289
|
+
|
290
|
+
Money.default_as = :cents
|
291
|
+
(0..100).each do |n|
|
292
|
+
Money.new(n).cents.should == n
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
context "with valid :rounding_method" do
|
297
|
+
|
298
|
+
it "should use the provided rounding method" do
|
299
|
+
n = Money.new(1_00, :rounding_method => :up)
|
300
|
+
n.rounding_method.should == :up
|
301
|
+
end
|
302
|
+
|
303
|
+
end
|
304
|
+
|
305
|
+
context "with invalid :rounding_method" do
|
306
|
+
|
307
|
+
it "should raise and ArgumentError" do
|
308
|
+
lambda{
|
309
|
+
Money.new(1_00, :rounding_method => :fake_rounding_method)
|
310
|
+
}.should raise_error ArgumentError
|
311
|
+
end
|
312
|
+
|
313
|
+
end
|
314
|
+
|
315
|
+
context "with valid :currency" do
|
316
|
+
|
317
|
+
context "with String" do
|
318
|
+
|
319
|
+
it "should use the provided currency to create the object" do
|
320
|
+
Money.new(1_00, :currency => "EUR").currency.should == Currency[:eur]
|
321
|
+
end
|
322
|
+
|
323
|
+
end
|
324
|
+
|
325
|
+
context "with Symbol" do
|
326
|
+
|
327
|
+
it "should use the provided currency to create the object" do
|
328
|
+
Money.new(1_00, :currency => :eur).currency.should == Currency[:eur]
|
329
|
+
end
|
330
|
+
|
331
|
+
end
|
332
|
+
|
333
|
+
context "with CurrencyStruct" do
|
334
|
+
|
335
|
+
it "should use the provided currency to create the object" do
|
336
|
+
c = Currency[:eur]
|
337
|
+
Money.new(1_00, :currency => c).currency.should == Currency[:eur]
|
338
|
+
end
|
339
|
+
|
340
|
+
end
|
341
|
+
|
342
|
+
it "should respect a currency.subunit_to_unit of 10" do
|
343
|
+
Money.new(
|
344
|
+
1.9,
|
345
|
+
:as => :decimal,
|
346
|
+
:currency => :cny
|
347
|
+
).cents.should == 19
|
348
|
+
end
|
349
|
+
|
350
|
+
it "should respect a currency.subunit_to_unit of 100" do
|
351
|
+
Money.new(
|
352
|
+
1.99,
|
353
|
+
:as => :decimal,
|
354
|
+
:currency => :usd
|
355
|
+
).cents.should == 199
|
356
|
+
end
|
357
|
+
|
358
|
+
|
359
|
+
it "should respect a currency.subunit_to_unit of 1000" do
|
360
|
+
Money.new(
|
361
|
+
1.999,
|
362
|
+
:as => :decimal,
|
363
|
+
:currency => :bhd
|
364
|
+
).cents.should == 1999
|
365
|
+
end
|
366
|
+
|
367
|
+
|
368
|
+
it "should respect a currency.subunit_to_unit of 1" do
|
369
|
+
Money.new(
|
370
|
+
1,
|
371
|
+
:as => :decimal,
|
372
|
+
:currency => :clp
|
373
|
+
).cents.should == 1
|
374
|
+
end
|
375
|
+
|
376
|
+
|
377
|
+
it "should respect a currency.subunit_to_unit of 5" do
|
378
|
+
Money.new(
|
379
|
+
1.4,
|
380
|
+
:as => :decimal,
|
381
|
+
:currency => :mga
|
382
|
+
).cents.should == 9
|
383
|
+
end
|
384
|
+
|
385
|
+
end
|
386
|
+
|
387
|
+
context "with invalid :currency" do
|
388
|
+
|
389
|
+
it "should raise an ArgumentError" do
|
390
|
+
lambda{
|
391
|
+
Money.new(1_00, :currency => :not_a_real_currency)
|
392
|
+
}.should raise_error ArgumentError
|
393
|
+
end
|
394
|
+
|
395
|
+
end
|
396
|
+
|
397
|
+
it "should use the default :currency" do
|
398
|
+
Money.default_currency = :eur
|
399
|
+
Money.new(1_00).currency.should == Currency[:eur]
|
400
|
+
end
|
401
|
+
|
402
|
+
end
|
403
|
+
|
404
|
+
describe "#+" do
|
405
|
+
|
406
|
+
it "should add two Money objects together" do
|
407
|
+
(0..100).to_a.combination(2).each do |(a,b)|
|
408
|
+
(Money.new(a) + Money.new(b)).cents.should == a + b
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
it "should raise an error if argument is not a Money" do
|
413
|
+
lambda{
|
414
|
+
Money.new + 0
|
415
|
+
}.should raise_error ArgumentError
|
416
|
+
end
|
417
|
+
|
418
|
+
it "should raise an error if the currency isn't the same" do
|
419
|
+
lambda{
|
420
|
+
Money.new(1_00, :currency => :usd) + Money.new(1_00, :currency => :eur)
|
421
|
+
}.should raise_error ArgumentError
|
422
|
+
end
|
423
|
+
|
424
|
+
it "should use the base objects rounding method" do
|
425
|
+
a = Money.new(1_00, :rounding_method => :up)
|
426
|
+
b = Money.new(1_00, :rounding_method => :up)
|
427
|
+
(a + b).rounding_method.should == :up
|
428
|
+
end
|
429
|
+
|
430
|
+
it "should use the base objects currency" do
|
431
|
+
a = Money.new(1_00, :currency => :eur)
|
432
|
+
b = Money.new(1_00, :currency => :eur)
|
433
|
+
(a + b).currency.should == Currency[:eur]
|
434
|
+
end
|
435
|
+
|
436
|
+
end
|
437
|
+
|
438
|
+
describe "#-" do
|
439
|
+
|
440
|
+
it "should subtract two Money objects from each other" do
|
441
|
+
(0..100).to_a.combination(2).each do |(a,b)|
|
442
|
+
(Money.new(a) - Money.new(b)).cents.should == a - b
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
it "should raise an error if argument is not a Money" do
|
447
|
+
lambda{Money.new - 0}.should raise_error ArgumentError
|
448
|
+
end
|
449
|
+
|
450
|
+
it "should raise an error if the currency isn't the same" do
|
451
|
+
lambda{
|
452
|
+
Money.new(1_00, :currency => :usd) - Money.new(1_00, :currency => :eur)
|
453
|
+
}.should raise_error ArgumentError
|
454
|
+
end
|
455
|
+
|
456
|
+
it "should use the base objects rounding method" do
|
457
|
+
a = Money.new(1_00, :rounding_method => :up)
|
458
|
+
b = Money.new(1_00, :rounding_method => :up)
|
459
|
+
(a - b).rounding_method.should == :up
|
460
|
+
end
|
461
|
+
|
462
|
+
it "should use the base objects currency" do
|
463
|
+
a = Money.new(1_00, :currency => :eur)
|
464
|
+
b = Money.new(1_00, :currency => :eur)
|
465
|
+
(a - b).currency.should == Currency[:eur]
|
466
|
+
end
|
467
|
+
|
468
|
+
end
|
469
|
+
|
470
|
+
describe "#*" do
|
471
|
+
|
472
|
+
it "should multiply a Money object by a Numeric" do
|
473
|
+
(0..100).to_a.combination(2).each do |(a,b)|
|
474
|
+
(Money.new(a) * b).cents.should == a * b
|
475
|
+
end
|
476
|
+
|
477
|
+
("0.01".."1.00").map(&:to_f).combination(2).each do |(a,b)|
|
478
|
+
(Money.new(a, :as => :decimal) * b).cents.should == (
|
479
|
+
Money.round BigDecimal(a.to_s) * 100 * BigDecimal(b.to_s)
|
480
|
+
)
|
481
|
+
end
|
482
|
+
end
|
483
|
+
|
484
|
+
it "should added rounded fractional cents to the overflow bucket" do
|
485
|
+
Money.new(2) * 2.1
|
486
|
+
Money.overflow.should == BigDecimal("0.2")
|
487
|
+
end
|
488
|
+
|
489
|
+
it "should raise an error unless argument is a Numeric" do
|
490
|
+
lambda{Money.new * Money.new}.should raise_error ArgumentError
|
491
|
+
end
|
492
|
+
|
493
|
+
it "should use the base objects rounding method" do
|
494
|
+
a = Money.new(1_00, :rounding_method => :up)
|
495
|
+
(a * 2).rounding_method.should == :up
|
496
|
+
end
|
497
|
+
|
498
|
+
it "should use the base objects currency" do
|
499
|
+
a = Money.new(1_00, :currency => :eur)
|
500
|
+
(a * 2).currency.should == Currency[:eur]
|
501
|
+
end
|
502
|
+
|
503
|
+
end
|
504
|
+
|
505
|
+
describe "#/" do
|
506
|
+
|
507
|
+
it "should divide two Money objects" do
|
508
|
+
(1..100).to_a.combination(2).each do |(a,b)|
|
509
|
+
(Money.new(a) / Money.new(b)).should == (
|
510
|
+
BigDecimal(a.to_s) / BigDecimal(b.to_s)
|
511
|
+
)
|
512
|
+
end
|
513
|
+
end
|
514
|
+
|
515
|
+
it "should divide a Money object by a numeric" do
|
516
|
+
(1..100).to_a.combination(2).each do |(a,b)|
|
517
|
+
(Money.new(a) / b).cents.should == (
|
518
|
+
a.divmod(BigDecimal(b.to_s))[0]
|
519
|
+
)
|
520
|
+
(Money.new(a) / b.to_f).cents.should == (
|
521
|
+
a.divmod(BigDecimal(b.to_f.to_s))[0]
|
522
|
+
)
|
523
|
+
end
|
524
|
+
end
|
525
|
+
|
526
|
+
it "should added rounded fractional cents to the overflow bucket" do
|
527
|
+
Money.new(5) / 2
|
528
|
+
Money.overflow.should == BigDecimal("1")
|
529
|
+
end
|
530
|
+
|
531
|
+
it "should raise an error unless argument is a Money or Numeric" do
|
532
|
+
lambda{Money.new / :foo}.should raise_error ArgumentError
|
533
|
+
end
|
534
|
+
|
535
|
+
it "should raise an error if the currency isn't the same" do
|
536
|
+
lambda{
|
537
|
+
Money.new(1_00, :currency => :usd) / Money.new(1_00, :currency => :eur)
|
538
|
+
}.should raise_error ArgumentError
|
539
|
+
end
|
540
|
+
|
541
|
+
it "should use the base objects rounding method" do
|
542
|
+
a = Money.new(1_00, :rounding_method => :up)
|
543
|
+
(a / 2).rounding_method.should == :up
|
544
|
+
end
|
545
|
+
|
546
|
+
it "should use the base objects currency" do
|
547
|
+
a = Money.new(1_00, :currency => :eur)
|
548
|
+
(a / 2).currency.should == Currency[:eur]
|
549
|
+
end
|
550
|
+
|
551
|
+
end
|
552
|
+
|
553
|
+
describe "#%" do
|
554
|
+
|
555
|
+
it "should modulo two Money objects" do
|
556
|
+
(1..100).to_a.combination(2).each do |(a,b)|
|
557
|
+
(Money.new(a) % Money.new(b)).should == (
|
558
|
+
BigDecimal(a.to_s) % BigDecimal(b.to_s)
|
559
|
+
)
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
it "should modulo a Money object by a numeric" do
|
564
|
+
(1..100).to_a.combination(2).each do |(a,b)|
|
565
|
+
(Money.new(a) % b).cents.should == (
|
566
|
+
a % BigDecimal(b.to_s)
|
567
|
+
)
|
568
|
+
(Money.new(a) % b.to_f).cents.should == (
|
569
|
+
a % BigDecimal(b.to_f.to_s)
|
570
|
+
)
|
571
|
+
end
|
572
|
+
end
|
573
|
+
|
574
|
+
it "should raise an error unless argument is a Money or Numeric" do
|
575
|
+
lambda{Money.new % :foo}.should raise_error ArgumentError
|
576
|
+
end
|
577
|
+
|
578
|
+
it "should raise an error if the currency isn't the same" do
|
579
|
+
lambda{
|
580
|
+
Money.new(1_00, :currency => :usd) % Money.new(1_00, :currency => :eur)
|
581
|
+
}.should raise_error ArgumentError
|
582
|
+
end
|
583
|
+
|
584
|
+
it "should use the base objects rounding method" do
|
585
|
+
a = Money.new(1_00, :rounding_method => :up)
|
586
|
+
(a % 2).rounding_method.should == :up
|
587
|
+
end
|
588
|
+
|
589
|
+
it "should use the base objects currency" do
|
590
|
+
a = Money.new(1_00, :currency => :eur)
|
591
|
+
(a % 2).currency.should == Currency[:eur]
|
592
|
+
end
|
593
|
+
|
594
|
+
end
|
595
|
+
|
596
|
+
describe "#divmod" do
|
597
|
+
|
598
|
+
context "when n is a Money object" do
|
599
|
+
|
600
|
+
it "should return an appropriate array of values" do
|
601
|
+
Money.new(5).divmod(Money.new(2)).should == [
|
602
|
+
BigDecimal("2"), Money.new(1)
|
603
|
+
]
|
604
|
+
end
|
605
|
+
|
606
|
+
it "should raise an ArgumentError if n is an incompatible currency" do
|
607
|
+
lambda{
|
608
|
+
Money.new(5_00, :currency => :usd).divmod(
|
609
|
+
Money.new(2_00, :currency => :eur)
|
610
|
+
)
|
611
|
+
}.should raise_error ArgumentError
|
612
|
+
end
|
613
|
+
|
614
|
+
it "should use the base objects rounding method" do
|
615
|
+
Money.new(
|
616
|
+
5,
|
617
|
+
:rounding_method => :up
|
618
|
+
).divmod(Money.new(2))[1].rounding_method.should == :up
|
619
|
+
end
|
620
|
+
|
621
|
+
it "should use the base objects currency" do
|
622
|
+
Money.new(
|
623
|
+
5,
|
624
|
+
:currency => :eur
|
625
|
+
).divmod(
|
626
|
+
Money.new(
|
627
|
+
2,
|
628
|
+
:currency => :eur
|
629
|
+
)
|
630
|
+
)[1].currency.should == Currency[:eur]
|
631
|
+
end
|
632
|
+
|
633
|
+
end
|
634
|
+
|
635
|
+
context "when n is a Numeric" do
|
636
|
+
|
637
|
+
it "should return an appropriate array of values" do
|
638
|
+
Money.new(5).divmod(2).should == [
|
639
|
+
Money.new(2), Money.new(1)
|
640
|
+
]
|
641
|
+
end
|
642
|
+
|
643
|
+
it "should add to overflow when necessary" do
|
644
|
+
Money.overflow.should == BigDecimal("0")
|
645
|
+
Money.new(5).divmod(2.1)
|
646
|
+
Money.overflow.should == BigDecimal("-0.2")
|
647
|
+
end
|
648
|
+
|
649
|
+
it "shoud use the base objects rounding method" do
|
650
|
+
n = Money.new(
|
651
|
+
5,
|
652
|
+
:rounding_method => :up
|
653
|
+
).divmod(2)
|
654
|
+
n[0].rounding_method.should == :up
|
655
|
+
n[1].rounding_method.should == :up
|
656
|
+
end
|
657
|
+
|
658
|
+
it "should use the base objects currency" do
|
659
|
+
n = Money.new(
|
660
|
+
5,
|
661
|
+
:currency => :eur
|
662
|
+
).divmod(2)
|
663
|
+
n[0].currency.should == Currency[:eur]
|
664
|
+
n[1].currency.should == Currency[:eur]
|
665
|
+
end
|
666
|
+
|
667
|
+
end
|
668
|
+
|
669
|
+
it "should raise an ArgumentError unless n is a Money/Numeric" do
|
670
|
+
lambda{
|
671
|
+
Money.new(5).divmod(:foo)
|
672
|
+
}.should raise_error ArgumentError
|
673
|
+
end
|
674
|
+
|
675
|
+
end
|
676
|
+
|
677
|
+
describe "#<=>" do
|
678
|
+
|
679
|
+
it "should return -1 if self < n" do
|
680
|
+
a = Money.new(1_00)
|
681
|
+
b = Money.new(2_00)
|
682
|
+
(a <=> b).should == -1
|
683
|
+
end
|
684
|
+
|
685
|
+
it "should return 1 if self > n" do
|
686
|
+
a = Money.new(1_00)
|
687
|
+
b = Money.new(2_00)
|
688
|
+
(b <=> a).should == 1
|
689
|
+
end
|
690
|
+
|
691
|
+
it "should return 0 if self == n" do
|
692
|
+
a = Money.new(1_00)
|
693
|
+
(a <=> a).should == 0
|
694
|
+
end
|
695
|
+
|
696
|
+
it "should raise an ArgumentError unless n is a Money object" do
|
697
|
+
lambda{
|
698
|
+
a = Money.new(1_00)
|
699
|
+
a <=> :foo
|
700
|
+
}.should raise_error ArgumentError
|
701
|
+
end
|
702
|
+
|
703
|
+
it "should raise an ArgumentError if currency of n isn't the same" do
|
704
|
+
lambda{
|
705
|
+
a = Money.new(1_00, :currency => :usd)
|
706
|
+
b = Money.new(2_00, :currency => :eur)
|
707
|
+
a <=> b
|
708
|
+
}.should raise_error ArgumentError
|
709
|
+
end
|
710
|
+
|
711
|
+
end
|
712
|
+
|
713
|
+
describe "#==" do
|
714
|
+
|
715
|
+
it "should return true when self == n" do
|
716
|
+
a = Money.new(1_00)
|
717
|
+
b = Money.new(1_00)
|
718
|
+
(a == b).should == true
|
719
|
+
end
|
720
|
+
|
721
|
+
it "should return false when self != n" do
|
722
|
+
a = Money.new(1_00)
|
723
|
+
b = Money.new(2_00)
|
724
|
+
(a == b).should == false
|
725
|
+
end
|
726
|
+
|
727
|
+
it "should raise an ArgumentError unless n is a Money object" do
|
728
|
+
lambda{
|
729
|
+
a = Money.new(1_00)
|
730
|
+
a == :foo
|
731
|
+
}.should raise_error ArgumentError
|
732
|
+
end
|
733
|
+
|
734
|
+
it "should raise an ArgumentError if currency of n isn't the same" do
|
735
|
+
lambda{
|
736
|
+
a = Money.new(1_00, :currency => :usd)
|
737
|
+
b = Money.new(2_00, :currency => :eur)
|
738
|
+
a == b
|
739
|
+
}.should raise_error ArgumentError
|
740
|
+
end
|
741
|
+
|
742
|
+
end
|
743
|
+
|
744
|
+
describe "abs" do
|
745
|
+
|
746
|
+
it "should return the a new Money object using cents.abs" do
|
747
|
+
Money.new(-1_00).abs.should == Money.new(1_00)
|
748
|
+
end
|
749
|
+
|
750
|
+
it "should use the base objects rounding method" do
|
751
|
+
Money.new(
|
752
|
+
-1_00,
|
753
|
+
:rounding_method => :up
|
754
|
+
).abs.rounding_method.should == :up
|
755
|
+
end
|
756
|
+
|
757
|
+
it "should use the base objects currency" do
|
758
|
+
Money.new(
|
759
|
+
-1_00,
|
760
|
+
:currency => :eur
|
761
|
+
).abs.currency.should == Currency[:eur]
|
762
|
+
end
|
763
|
+
|
764
|
+
end
|
765
|
+
|
766
|
+
describe "#to_s" do
|
767
|
+
|
768
|
+
it "should return cents formatted as a string" do
|
769
|
+
Money.new(1_00).to_s.should == "100"
|
770
|
+
end
|
771
|
+
|
772
|
+
context "with :as => :cents" do
|
773
|
+
|
774
|
+
it "should return cents formatted as a string" do
|
775
|
+
Money.new(1_00).to_s.should == "100"
|
776
|
+
end
|
777
|
+
|
778
|
+
end
|
779
|
+
|
780
|
+
context "with :as => :decimal" do
|
781
|
+
|
782
|
+
it "should return cents formatted as a decimal" do
|
783
|
+
Money.new(1_00).to_s(:as => :decimal).should == "1.00"
|
784
|
+
end
|
785
|
+
|
786
|
+
it "should work with a subunit_to_unit of 1" do
|
787
|
+
Money.new(
|
788
|
+
1,
|
789
|
+
:as => :decimal,
|
790
|
+
:currency => :clp
|
791
|
+
).to_s(:as => :decimal).should == "1"
|
792
|
+
end
|
793
|
+
|
794
|
+
it "should work with a subunit_to_unit of 5" do
|
795
|
+
Money.new(
|
796
|
+
1.4,
|
797
|
+
:as => :decimal,
|
798
|
+
:currency => :mga
|
799
|
+
).to_s(:as => :decimal).should == "1.4"
|
800
|
+
end
|
801
|
+
|
802
|
+
it "should work with a subunit_to_unit of 10" do
|
803
|
+
Money.new(
|
804
|
+
1.9,
|
805
|
+
:as => :decimal,
|
806
|
+
:currency => :cny
|
807
|
+
).to_s(:as => :decimal).should == "1.9"
|
808
|
+
end
|
809
|
+
|
810
|
+
it "should work with a subunit_to_unit of 100" do
|
811
|
+
Money.new(
|
812
|
+
1.99,
|
813
|
+
:as => :decimal,
|
814
|
+
:currency => :usd
|
815
|
+
).to_s(:as => :decimal).should == "1.99"
|
816
|
+
end
|
817
|
+
|
818
|
+
it "should work with a subunit_to_unit of 100" do
|
819
|
+
Money.new(
|
820
|
+
1.999,
|
821
|
+
:as => :decimal,
|
822
|
+
:currency => :bhd
|
823
|
+
).to_s(:as => :decimal).should == "1.999"
|
824
|
+
end
|
825
|
+
|
826
|
+
end
|
827
|
+
|
828
|
+
context "with invalid :as" do
|
829
|
+
|
830
|
+
it "should raise an ArgumentError" do
|
831
|
+
lambda{
|
832
|
+
Money.new(1_00).to_s(:as => :foo)
|
833
|
+
}.should raise_error ArgumentError
|
834
|
+
end
|
835
|
+
|
836
|
+
end
|
837
|
+
|
838
|
+
end
|
839
|
+
|
840
|
+
end
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple_money
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 19
|
5
|
+
prerelease:
|
5
6
|
segments:
|
6
7
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
8
|
+
- 3
|
9
|
+
- 0
|
10
|
+
version: 0.3.0
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Shane Emmons
|
@@ -14,7 +15,7 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2011-
|
18
|
+
date: 2011-02-18 00:00:00 -05:00
|
18
19
|
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
@@ -25,6 +26,7 @@ dependencies:
|
|
25
26
|
requirements:
|
26
27
|
- - ">="
|
27
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 15
|
28
30
|
segments:
|
29
31
|
- 2
|
30
32
|
- 0
|
@@ -40,12 +42,13 @@ dependencies:
|
|
40
42
|
requirements:
|
41
43
|
- - ">="
|
42
44
|
- !ruby/object:Gem::Version
|
45
|
+
hash: 3
|
43
46
|
segments:
|
44
47
|
- 0
|
45
48
|
version: "0"
|
46
49
|
type: :development
|
47
50
|
version_requirements: *id002
|
48
|
-
description: This gem is intended for working with financial calculations where you need highly accurate results.
|
51
|
+
description: This gem is intended for working with financial calculations (money/currency) where you need highly accurate results.
|
49
52
|
email: semmons99@gmail.com
|
50
53
|
executables: []
|
51
54
|
|
@@ -57,9 +60,14 @@ files:
|
|
57
60
|
- lib/simple_money/currency.rb
|
58
61
|
- lib/simple_money/money.rb
|
59
62
|
- lib/simple_money.rb
|
63
|
+
- spec/simple_money/currency_spec.rb
|
64
|
+
- spec/simple_money/money_spec.rb
|
60
65
|
- CHANGELOG.md
|
61
66
|
- LICENSE
|
62
67
|
- README.md
|
68
|
+
- Rakefile
|
69
|
+
- .gemtest
|
70
|
+
- simple_money.gemspec
|
63
71
|
has_rdoc: true
|
64
72
|
homepage: http://github.com/semmons99/simple_money
|
65
73
|
licenses: []
|
@@ -74,6 +82,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
74
82
|
requirements:
|
75
83
|
- - ">="
|
76
84
|
- !ruby/object:Gem::Version
|
85
|
+
hash: 57
|
77
86
|
segments:
|
78
87
|
- 1
|
79
88
|
- 8
|
@@ -84,6 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
84
93
|
requirements:
|
85
94
|
- - ">="
|
86
95
|
- !ruby/object:Gem::Version
|
96
|
+
hash: 21
|
87
97
|
segments:
|
88
98
|
- 1
|
89
99
|
- 3
|
@@ -92,7 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
92
102
|
requirements: []
|
93
103
|
|
94
104
|
rubyforge_project:
|
95
|
-
rubygems_version: 1.
|
105
|
+
rubygems_version: 1.5.2
|
96
106
|
signing_key:
|
97
107
|
specification_version: 3
|
98
108
|
summary: Library to work with money/currency.
|