acvwilson-currency 0.5.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/COPYING.txt +339 -0
- data/ChangeLog +8 -0
- data/LICENSE.txt +65 -0
- data/Manifest.txt +58 -0
- data/README.txt +51 -0
- data/Releases.txt +155 -0
- data/TODO.txt +9 -0
- data/currency.gemspec +18 -0
- data/examples/ex1.rb +13 -0
- data/examples/xe1.rb +20 -0
- data/lib/currency.rb +143 -0
- data/lib/currency/active_record.rb +265 -0
- data/lib/currency/config.rb +91 -0
- data/lib/currency/core_extensions.rb +83 -0
- data/lib/currency/currency.rb +175 -0
- data/lib/currency/currency/factory.rb +121 -0
- data/lib/currency/currency_version.rb +6 -0
- data/lib/currency/exception.rb +119 -0
- data/lib/currency/exchange.rb +48 -0
- data/lib/currency/exchange/rate.rb +214 -0
- data/lib/currency/exchange/rate/deriver.rb +157 -0
- data/lib/currency/exchange/rate/source.rb +89 -0
- data/lib/currency/exchange/rate/source/base.rb +166 -0
- data/lib/currency/exchange/rate/source/failover.rb +63 -0
- data/lib/currency/exchange/rate/source/federal_reserve.rb +160 -0
- data/lib/currency/exchange/rate/source/historical.rb +79 -0
- data/lib/currency/exchange/rate/source/historical/rate.rb +184 -0
- data/lib/currency/exchange/rate/source/historical/rate_loader.rb +186 -0
- data/lib/currency/exchange/rate/source/historical/writer.rb +220 -0
- data/lib/currency/exchange/rate/source/new_york_fed.rb +127 -0
- data/lib/currency/exchange/rate/source/provider.rb +120 -0
- data/lib/currency/exchange/rate/source/test.rb +50 -0
- data/lib/currency/exchange/rate/source/the_financials.rb +191 -0
- data/lib/currency/exchange/rate/source/timed_cache.rb +198 -0
- data/lib/currency/exchange/rate/source/xe.rb +165 -0
- data/lib/currency/exchange/time_quantitizer.rb +111 -0
- data/lib/currency/formatter.rb +310 -0
- data/lib/currency/macro.rb +321 -0
- data/lib/currency/money.rb +298 -0
- data/lib/currency/money_helper.rb +13 -0
- data/lib/currency/parser.rb +193 -0
- data/spec/ar_column_spec.rb +76 -0
- data/spec/ar_core_spec.rb +68 -0
- data/spec/ar_simple_spec.rb +23 -0
- data/spec/config_spec.rb +29 -0
- data/spec/federal_reserve_spec.rb +75 -0
- data/spec/formatter_spec.rb +72 -0
- data/spec/historical_writer_spec.rb +187 -0
- data/spec/macro_spec.rb +109 -0
- data/spec/money_spec.rb +355 -0
- data/spec/new_york_fed_spec.rb +73 -0
- data/spec/parser_spec.rb +105 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/time_quantitizer_spec.rb +115 -0
- data/spec/timed_cache_spec.rb +95 -0
- data/spec/xe_spec.rb +50 -0
- metadata +117 -0
data/spec/macro_spec.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
# Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
|
2
|
+
# See LICENSE.txt for details.
|
3
|
+
|
4
|
+
require 'test/test_base'
|
5
|
+
require 'currency'
|
6
|
+
require 'currency/macro'
|
7
|
+
|
8
|
+
module Currency
|
9
|
+
|
10
|
+
class MacroTest < TestBase
|
11
|
+
class Record
|
12
|
+
include ::Currency::Macro
|
13
|
+
|
14
|
+
attr_accessor :date
|
15
|
+
attr_accessor :gross
|
16
|
+
attr_accessor :tax
|
17
|
+
attr_accessor :net
|
18
|
+
attr_accessor :currency
|
19
|
+
|
20
|
+
attr_money :gross_money, :value => :gross, :time => :date, :currency => :currency
|
21
|
+
attr_money :tax_money, :value => :tax, :time => :date, :currency => :currency
|
22
|
+
attr_money :net_money, :value => :net, :time => :date, :currency => :currency
|
23
|
+
|
24
|
+
def initialize
|
25
|
+
self.date = Time.now
|
26
|
+
self.currency = :USD
|
27
|
+
end
|
28
|
+
|
29
|
+
def compute_net
|
30
|
+
self.net = self.gross - self.tax
|
31
|
+
end
|
32
|
+
|
33
|
+
def compute_net_money
|
34
|
+
self.net_money = self.gross_money - self.tax_money
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
before do
|
40
|
+
super
|
41
|
+
end
|
42
|
+
|
43
|
+
############################################
|
44
|
+
# Tests
|
45
|
+
#
|
46
|
+
|
47
|
+
it "read money" do
|
48
|
+
assert_kind_of Record, r = Record.new
|
49
|
+
r.gross = 10.00.should.not == nil
|
50
|
+
r.gross.should == r.gross_money.to_f
|
51
|
+
r.currency.should == r.gross_money.currency.code
|
52
|
+
r.date.should == r.gross_money.time
|
53
|
+
|
54
|
+
r
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
it "write money rep" do
|
59
|
+
assert_kind_of Record, r = Record.new
|
60
|
+
r.gross_money = 10.00.should.not == nil
|
61
|
+
r.gross.should == r.gross_money.to_f
|
62
|
+
r.currency.should == r.gross_money.currency.code
|
63
|
+
r.date.should == r.gross_money.time
|
64
|
+
|
65
|
+
r
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
it "money cache" do
|
70
|
+
r = test_read_money
|
71
|
+
|
72
|
+
r_gross = r.gross.should.not == nil
|
73
|
+
r_gross.object_id.should == r.gross.object_id
|
74
|
+
|
75
|
+
# Cache flush
|
76
|
+
r.gross = 12.00.should.not == nil
|
77
|
+
r.gross.should == r.gross_money.to_f
|
78
|
+
r_gross.object_id != r.gross.object_id.should.not == nil
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
it "currency" do
|
83
|
+
r = test_read_money
|
84
|
+
|
85
|
+
r.gross_money.currency.should.not == nil
|
86
|
+
r.currency.should == r.gross_money.currency.code
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
it "compute" do
|
92
|
+
assert_kind_of Record, r = Record.new
|
93
|
+
r.gross = 10.00.should.not == nil
|
94
|
+
r.tax = 1.50.should.not == nil
|
95
|
+
r.compute_net
|
96
|
+
|
97
|
+
r.net.should == 8.50
|
98
|
+
r.net_money.to_f.should == r.net
|
99
|
+
|
100
|
+
r.compute_net_money
|
101
|
+
|
102
|
+
r.net.should == 8.50
|
103
|
+
r.net_money.to_f.should == r.net
|
104
|
+
end
|
105
|
+
|
106
|
+
end # class
|
107
|
+
|
108
|
+
end # module
|
109
|
+
|
data/spec/money_spec.rb
ADDED
@@ -0,0 +1,355 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe Currency::Money do
|
5
|
+
|
6
|
+
it "create" do
|
7
|
+
m = Currency::Money.new(1.99)
|
8
|
+
m.should be_kind_of(Currency::Money)
|
9
|
+
Currency::Currency.default.should == m.currency
|
10
|
+
:USD.should == m.currency.code
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "object money method" do
|
14
|
+
it "works with a float" do
|
15
|
+
m = 1.99.money(:USD)
|
16
|
+
m.should be_kind_of(Currency::Money)
|
17
|
+
:USD.should == m.currency.code
|
18
|
+
m.rep.should == 1990000
|
19
|
+
end
|
20
|
+
|
21
|
+
it "works with a FixNum" do
|
22
|
+
m = 199.money(:CAD)
|
23
|
+
m.should be_kind_of(Currency::Money)
|
24
|
+
:CAD.should == m.currency.code
|
25
|
+
m.rep.should == 199000000
|
26
|
+
end
|
27
|
+
|
28
|
+
it "works with a string" do
|
29
|
+
m = "13.98".money(:CAD)
|
30
|
+
m.should be_kind_of(Currency::Money)
|
31
|
+
:CAD.should == m.currency.code
|
32
|
+
m.rep.should == 13980000
|
33
|
+
end
|
34
|
+
|
35
|
+
it "works with a string again" do
|
36
|
+
m = "45.99".money(:EUR)
|
37
|
+
m.should be_kind_of(Currency::Money)
|
38
|
+
:EUR.should == m.currency.code
|
39
|
+
m.rep.should == 45990000
|
40
|
+
end
|
41
|
+
|
42
|
+
it "creates money objects from strings" do
|
43
|
+
"12.0001".money(:USD).to_s.should == "$12.0001"
|
44
|
+
# "12.000108".money(:USD).to_s(:thousands => false, :decimals => 5).should == "$12.00011"
|
45
|
+
@money = Currency::Money.new_rep(1234567890000, :USD, nil)
|
46
|
+
|
47
|
+
Currency::Money.new("12.000108").to_s(:thousands => false, :decimals => 5).should == "$12.00011"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def zero_money
|
52
|
+
@zero_money ||= Currency::Money.new(0)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "zero" do
|
56
|
+
zero_money.negative?.should_not == true
|
57
|
+
zero_money.zero?.should_not == nil
|
58
|
+
zero_money.positive?.should_not == true
|
59
|
+
end
|
60
|
+
|
61
|
+
def negative_money
|
62
|
+
@negative_money ||= Currency::Money.new(-1.00, :USD)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "negative" do
|
66
|
+
negative_money.negative?.should_not == nil
|
67
|
+
negative_money.zero?.should_not == true
|
68
|
+
negative_money.positive?.should_not == true
|
69
|
+
end
|
70
|
+
|
71
|
+
def positive_money
|
72
|
+
@positive_money ||= Currency::Money.new(2.99, :USD)
|
73
|
+
end
|
74
|
+
it "positive" do
|
75
|
+
positive_money.negative?.should_not == true
|
76
|
+
positive_money.zero?.should_not == true
|
77
|
+
positive_money.positive?.should_not == nil
|
78
|
+
end
|
79
|
+
|
80
|
+
it "relational" do
|
81
|
+
n = negative_money
|
82
|
+
z = zero_money
|
83
|
+
p = positive_money
|
84
|
+
|
85
|
+
(n.should < p)
|
86
|
+
(n > p).should_not == true
|
87
|
+
(p < n).should_not == true
|
88
|
+
(p.should > n)
|
89
|
+
(p != n).should_not == nil
|
90
|
+
|
91
|
+
(z.should <= z)
|
92
|
+
(z.should >= z)
|
93
|
+
|
94
|
+
(z.should <= p)
|
95
|
+
(n.should <= z)
|
96
|
+
(z.should >= n)
|
97
|
+
|
98
|
+
n.should == n
|
99
|
+
p.should == p
|
100
|
+
|
101
|
+
z.should == zero_money
|
102
|
+
end
|
103
|
+
|
104
|
+
it "compare" do
|
105
|
+
n = negative_money
|
106
|
+
z = zero_money
|
107
|
+
p = positive_money
|
108
|
+
|
109
|
+
(n <=> p).should == -1
|
110
|
+
(p <=> n).should == 1
|
111
|
+
(p <=> z).should == 1
|
112
|
+
|
113
|
+
(n <=> n).should == 0
|
114
|
+
(z <=> z).should == 0
|
115
|
+
(p <=> p).should == 0
|
116
|
+
end
|
117
|
+
|
118
|
+
it "rep" do
|
119
|
+
m = Currency::Money.new(123, :USD)
|
120
|
+
m.should_not == nil
|
121
|
+
m.rep.should == 123000000
|
122
|
+
|
123
|
+
m = Currency::Money.new(123.45, :USD)
|
124
|
+
m.should_not == nil
|
125
|
+
m.rep.should == 123450000
|
126
|
+
|
127
|
+
m = Currency::Money.new("123.456", :USD)
|
128
|
+
m.should_not == nil
|
129
|
+
m.rep.should == 123456000
|
130
|
+
end
|
131
|
+
|
132
|
+
it "convert" do
|
133
|
+
m = Currency::Money.new("123.456", :USD)
|
134
|
+
m.should_not == nil
|
135
|
+
m.rep.should == 123456000
|
136
|
+
|
137
|
+
m.to_i.should == 123
|
138
|
+
m.to_f.should == 123.456
|
139
|
+
m.to_s.should == "$123.456000"
|
140
|
+
end
|
141
|
+
|
142
|
+
it "eql" do
|
143
|
+
usd1 = Currency::Money.new(123, :USD)
|
144
|
+
usd1.should_not == nil
|
145
|
+
usd2 = Currency::Money.new("123", :USD)
|
146
|
+
usd2.should_not == nil
|
147
|
+
|
148
|
+
usd1.currency.code.should == :USD
|
149
|
+
usd2.currency.code.should == :USD
|
150
|
+
|
151
|
+
usd2.rep.should == usd1.rep
|
152
|
+
|
153
|
+
usd1.should == usd2
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
it "not eql" do
|
158
|
+
|
159
|
+
usd1 = Currency::Money.new(123, :USD)
|
160
|
+
usd1.should_not == nil
|
161
|
+
usd2 = Currency::Money.new("123.01", :USD)
|
162
|
+
usd2.should_not == nil
|
163
|
+
|
164
|
+
usd1.currency.code.should == :USD
|
165
|
+
usd2.currency.code.should == :USD
|
166
|
+
|
167
|
+
usd2.rep.should_not == usd1.rep
|
168
|
+
|
169
|
+
(usd1 != usd2).should_not == nil
|
170
|
+
|
171
|
+
################
|
172
|
+
# currency !=
|
173
|
+
# rep ==
|
174
|
+
|
175
|
+
usd = Currency::Money.new(123, :USD)
|
176
|
+
usd.should_not == nil
|
177
|
+
cad = Currency::Money.new(123, :CAD)
|
178
|
+
cad.should_not == nil
|
179
|
+
|
180
|
+
usd.currency.code.should == :USD
|
181
|
+
cad.currency.code.should == :CAD
|
182
|
+
|
183
|
+
cad.rep.should == usd.rep
|
184
|
+
(usd.currency != cad.currency).should_not == nil
|
185
|
+
|
186
|
+
(usd != cad).should_not == nil
|
187
|
+
|
188
|
+
end
|
189
|
+
|
190
|
+
describe "operations" do
|
191
|
+
before(:each) do
|
192
|
+
@usd = Currency::Money.new(123.45, :USD)
|
193
|
+
@cad = Currency::Money.new(123.45, :CAD)
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should work" do
|
197
|
+
@usd.should_not == nil
|
198
|
+
@cad.should_not == nil
|
199
|
+
end
|
200
|
+
|
201
|
+
it "handle negative money" do
|
202
|
+
# - Currency::Money => Currency::Money
|
203
|
+
(- @usd).rep.should == -123450000
|
204
|
+
(- @usd).currency.code.should == :USD
|
205
|
+
|
206
|
+
(- @cad).rep.should == -123450000
|
207
|
+
(- @cad).currency.code.should == :CAD
|
208
|
+
end
|
209
|
+
|
210
|
+
it "should add monies of the same currency" do
|
211
|
+
m = (@usd + @usd)
|
212
|
+
m.should be_kind_of(Currency::Money)
|
213
|
+
m.rep.should == 246900000
|
214
|
+
m.currency.code.should == :USD
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should add monies of different currencies and return USD" do
|
218
|
+
m = (@usd + @cad)
|
219
|
+
m.should be_kind_of(Currency::Money)
|
220
|
+
m.rep.should == 228890724
|
221
|
+
m.currency.code.should == :USD
|
222
|
+
end
|
223
|
+
|
224
|
+
it "should add monies of different currencies and return CAD" do
|
225
|
+
m = (@cad + @usd)
|
226
|
+
m.should be_kind_of(Currency::Money)
|
227
|
+
m.rep.should == 267985260
|
228
|
+
m.currency.code.should == :CAD
|
229
|
+
end
|
230
|
+
|
231
|
+
it "should subtract monies of the same currency" do
|
232
|
+
m = (@usd - @usd)
|
233
|
+
m.should be_kind_of(Currency::Money)
|
234
|
+
m.rep.should == 0
|
235
|
+
m.currency.code.should == :USD
|
236
|
+
end
|
237
|
+
|
238
|
+
it "should subtract monies of different currencies and return USD" do
|
239
|
+
m = (@usd - @cad)
|
240
|
+
m.should be_kind_of(Currency::Money)
|
241
|
+
m.rep.should == 18009276
|
242
|
+
m.currency.code.should == :USD
|
243
|
+
end
|
244
|
+
|
245
|
+
it "should subtract monies of different currencies and return CAD" do
|
246
|
+
m = (@cad - @usd)
|
247
|
+
m.should be_kind_of(Currency::Money)
|
248
|
+
m.rep.should == -21085260
|
249
|
+
m.currency.code.should == :CAD
|
250
|
+
end
|
251
|
+
|
252
|
+
it "should multiply by numerics and return money" do
|
253
|
+
m = (@usd * 0.5)
|
254
|
+
m.should be_kind_of(Currency::Money)
|
255
|
+
m.rep.should == 61725000
|
256
|
+
m.currency.code.should == :USD
|
257
|
+
end
|
258
|
+
|
259
|
+
it "should divide by numerics and return money" do
|
260
|
+
m = @usd / 3
|
261
|
+
m.should be_kind_of(Currency::Money)
|
262
|
+
m.rep.should == 41150000
|
263
|
+
m.currency.code.should == :USD
|
264
|
+
end
|
265
|
+
|
266
|
+
it "should divide by monies of the same currency and return numeric" do
|
267
|
+
m = @usd / Currency::Money.new("41.15", :USD)
|
268
|
+
m.should be_kind_of(Numeric)
|
269
|
+
m.should be_close(3.0, 1.0e-8)
|
270
|
+
end
|
271
|
+
|
272
|
+
it "should divide by monies of different currencies and return numeric" do
|
273
|
+
m = (@usd / @cad)
|
274
|
+
m.should be_kind_of(Numeric)
|
275
|
+
m.should be_close(Currency::Exchange::Rate::Source::Test.USD_CAD, 0.0001)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
it "pivot conversions" do
|
280
|
+
# Using default get_rate
|
281
|
+
cad = Currency::Money.new(123.45, :CAD)
|
282
|
+
cad.should_not == nil
|
283
|
+
eur = cad.convert(:EUR)
|
284
|
+
eur.should_not == nil
|
285
|
+
m = (eur.to_f / cad.to_f)
|
286
|
+
m.should be_kind_of(Numeric)
|
287
|
+
m_expected = (1.0 / Currency::Exchange::Rate::Source::Test.USD_CAD) * Currency::Exchange::Rate::Source::Test.USD_EUR
|
288
|
+
m.should be_close(m_expected, 0.001)
|
289
|
+
|
290
|
+
|
291
|
+
gbp = Currency::Money.new(123.45, :GBP)
|
292
|
+
gbp.should_not == nil
|
293
|
+
eur = gbp.convert(:EUR)
|
294
|
+
eur.should_not == nil
|
295
|
+
m = (eur.to_f / gbp.to_f)
|
296
|
+
m.should be_kind_of(Numeric)
|
297
|
+
m_expected = (1.0 / Currency::Exchange::Rate::Source::Test.USD_GBP) * Currency::Exchange::Rate::Source::Test.USD_EUR
|
298
|
+
m.should be_close(m_expected, 0.001)
|
299
|
+
end
|
300
|
+
|
301
|
+
|
302
|
+
it "invalid currency code" do
|
303
|
+
lambda {Currency::Money.new(123, :asdf)}.should raise_error(Currency::Exception::InvalidCurrencyCode)
|
304
|
+
lambda {Currency::Money.new(123, 5)}.should raise_error(Currency::Exception::InvalidCurrencyCode)
|
305
|
+
end
|
306
|
+
|
307
|
+
|
308
|
+
it "time default" do
|
309
|
+
Currency::Money.default_time = nil
|
310
|
+
|
311
|
+
usd = Currency::Money.new(123.45, :USD)
|
312
|
+
usd.should_not == nil
|
313
|
+
usd.time.should == nil
|
314
|
+
|
315
|
+
Currency::Money.default_time = Time.now
|
316
|
+
usd = Currency::Money.new(123.45, :USD)
|
317
|
+
usd.should_not == nil
|
318
|
+
Currency::Money.default_time.should == usd.time
|
319
|
+
end
|
320
|
+
|
321
|
+
|
322
|
+
it "time now" do
|
323
|
+
Currency::Money.default_time = :now
|
324
|
+
|
325
|
+
usd = Currency::Money.new(123.45, :USD)
|
326
|
+
usd.should_not == nil
|
327
|
+
usd.time.should_not == nil
|
328
|
+
|
329
|
+
sleep 1
|
330
|
+
|
331
|
+
usd2 = Currency::Money.new(123.45, :USD)
|
332
|
+
usd2.should_not == nil
|
333
|
+
usd2.time.should_not == nil
|
334
|
+
(usd.time != usd2.time).should_not == nil
|
335
|
+
|
336
|
+
Currency::Money.default_time = nil
|
337
|
+
end
|
338
|
+
|
339
|
+
|
340
|
+
it "time fixed" do
|
341
|
+
Currency::Money.default_time = Time.new
|
342
|
+
|
343
|
+
usd = Currency::Money.new(123.45, :USD)
|
344
|
+
usd.should_not == nil
|
345
|
+
usd.time.should_not == nil
|
346
|
+
|
347
|
+
sleep 1
|
348
|
+
|
349
|
+
usd2 = Currency::Money.new(123.45, :USD)
|
350
|
+
usd2.should_not == nil
|
351
|
+
usd2.time.should_not == nil
|
352
|
+
usd.time.should == usd2.time
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|