currency 0.3.3 → 0.4.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/LICENSE.txt +62 -0
- data/Manifest.txt +37 -14
- data/README.txt +8 -0
- data/Rakefile +42 -8
- data/Releases.txt +26 -0
- data/TODO.txt +1 -0
- data/examples/ex1.rb +3 -3
- data/examples/xe1.rb +3 -2
- data/lib/currency.rb +71 -9
- data/lib/currency/active_record.rb +138 -21
- data/lib/currency/core_extensions.rb +7 -5
- data/lib/currency/currency.rb +94 -177
- data/lib/currency/{currency_factory.rb → currency/factory.rb} +46 -25
- data/lib/currency/currency_version.rb +3 -3
- data/lib/currency/exception.rb +14 -14
- data/lib/currency/exchange.rb +14 -12
- data/lib/currency/exchange/rate.rb +159 -28
- data/lib/currency/exchange/rate/deriver.rb +146 -0
- data/lib/currency/exchange/rate/source.rb +84 -0
- data/lib/currency/exchange/rate/source/base.rb +156 -0
- data/lib/currency/exchange/rate/source/failover.rb +57 -0
- data/lib/currency/exchange/rate/source/historical.rb +79 -0
- data/lib/currency/exchange/rate/source/historical/rate.rb +181 -0
- data/lib/currency/exchange/rate/source/historical/writer.rb +203 -0
- data/lib/currency/exchange/rate/source/new_york_fed.rb +91 -0
- data/lib/currency/exchange/rate/source/provider.rb +105 -0
- data/lib/currency/exchange/rate/source/test.rb +50 -0
- data/lib/currency/exchange/rate/source/the_financials.rb +190 -0
- data/lib/currency/exchange/rate/source/timed_cache.rb +144 -0
- data/lib/currency/exchange/rate/source/xe.rb +166 -0
- data/lib/currency/exchange/time_quantitizer.rb +111 -0
- data/lib/currency/formatter.rb +159 -0
- data/lib/currency/macro.rb +321 -0
- data/lib/currency/money.rb +90 -64
- data/lib/currency/money_helper.rb +6 -5
- data/lib/currency/parser.rb +153 -0
- data/test/ar_column_test.rb +6 -3
- data/test/ar_simple_test.rb +5 -2
- data/test/ar_test_base.rb +39 -33
- data/test/ar_test_core.rb +64 -0
- data/test/formatter_test.rb +81 -0
- data/test/historical_writer_test.rb +184 -0
- data/test/macro_test.rb +109 -0
- data/test/money_test.rb +72 -4
- data/test/new_york_fed_test.rb +57 -0
- data/test/parser_test.rb +60 -0
- data/test/test_base.rb +13 -3
- data/test/time_quantitizer_test.rb +136 -0
- data/test/xe_test.rb +29 -5
- metadata +41 -18
- data/lib/currency/exchange/base.rb +0 -84
- data/lib/currency/exchange/test.rb +0 -39
- data/lib/currency/exchange/xe.rb +0 -250
data/test/ar_simple_test.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
-
|
1
|
+
# Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
|
2
|
+
# See LICENSE.txt for details.
|
3
|
+
|
4
|
+
require 'test/ar_test_core'
|
2
5
|
require 'currency'
|
3
6
|
|
4
7
|
require 'rubygems'
|
@@ -8,7 +11,7 @@ require 'currency/active_record'
|
|
8
11
|
|
9
12
|
module Currency
|
10
13
|
|
11
|
-
class ArSimpleTest <
|
14
|
+
class ArSimpleTest < ArTestCore
|
12
15
|
|
13
16
|
def test_simple
|
14
17
|
insert_records
|
data/test/ar_test_base.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
# Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
|
2
|
+
# See LICENSE.txt for details.
|
3
|
+
|
1
4
|
require 'test/test_base'
|
2
5
|
require 'currency'
|
3
6
|
|
@@ -13,30 +16,6 @@ module Currency
|
|
13
16
|
|
14
17
|
class ArTestBase < TestBase
|
15
18
|
|
16
|
-
##################################################
|
17
|
-
# Basic CurrenyTest AR::B class
|
18
|
-
#
|
19
|
-
|
20
|
-
TABLE_NAME = 'currency_test'
|
21
|
-
|
22
|
-
class CurrencyTestMigration < AR_M
|
23
|
-
def self.up
|
24
|
-
create_table TABLE_NAME.intern do |t|
|
25
|
-
t.column :name, :string
|
26
|
-
t.column :amount, :integer # Money
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.down
|
31
|
-
drop_table TABLE_NAME.intern
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
class CurrencyTest < AR_B
|
36
|
-
set_table_name TABLE_NAME
|
37
|
-
money :amount
|
38
|
-
end
|
39
|
-
|
40
19
|
##################################################
|
41
20
|
|
42
21
|
def setup
|
@@ -44,31 +23,50 @@ class ArTestBase < TestBase
|
|
44
23
|
AR_B.establish_connection(database_spec)
|
45
24
|
|
46
25
|
# Subclasses can override this.
|
47
|
-
@currency_test_migration ||=
|
48
|
-
@currency_test ||=
|
26
|
+
@currency_test_migration ||= nil
|
27
|
+
@currency_test ||= nil
|
49
28
|
|
50
29
|
# schema_down
|
51
30
|
|
52
31
|
schema_up
|
53
32
|
end
|
54
33
|
|
34
|
+
|
55
35
|
def teardown
|
56
36
|
super
|
57
37
|
# schema_down
|
58
38
|
end
|
59
39
|
|
40
|
+
|
60
41
|
def database_spec
|
61
42
|
# TODO: Get from ../config/database.yml:test
|
43
|
+
# Create test database on:
|
44
|
+
|
45
|
+
# MYSQL:
|
46
|
+
#
|
47
|
+
# sudo mysqladmin create test;
|
48
|
+
# sudo mysql
|
49
|
+
# grant all on test.* to test@localhost identified by 'test';
|
50
|
+
# flush privileges;
|
51
|
+
|
52
|
+
# POSTGRES:
|
53
|
+
#
|
54
|
+
# CREATE USER test PASSWORD 'test';
|
55
|
+
# CREATE DATABASE test WITH OWNER = test;
|
56
|
+
#
|
57
|
+
|
62
58
|
@database_spec = {
|
63
|
-
:adapter =>
|
64
|
-
:host =>
|
65
|
-
:username =>
|
66
|
-
:password =>
|
67
|
-
:database =>
|
59
|
+
:adapter => ENV['TEST_DB_ADAPTER'] || 'mysql',
|
60
|
+
:host => ENV['TEST_DB_HOST'] || 'localhost',
|
61
|
+
:username => ENV['TEST_DB_USER'] || 'test',
|
62
|
+
:password => ENV['TEST_DB_PASS'] || 'test',
|
63
|
+
:database => ENV['TEST_DB_TEST'] || 'test'
|
68
64
|
}
|
69
65
|
end
|
70
66
|
|
67
|
+
|
71
68
|
def schema_up
|
69
|
+
return unless @currency_test_migration
|
72
70
|
begin
|
73
71
|
@currency_test_migration.migrate(:up)
|
74
72
|
rescue Object =>e
|
@@ -76,7 +74,9 @@ class ArTestBase < TestBase
|
|
76
74
|
end
|
77
75
|
end
|
78
76
|
|
77
|
+
|
79
78
|
def schema_down
|
79
|
+
return unless @currency_test_migration
|
80
80
|
begin
|
81
81
|
@currency_test_migration.migrate(:down)
|
82
82
|
rescue Object => e
|
@@ -84,6 +84,7 @@ class ArTestBase < TestBase
|
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
87
|
+
|
87
88
|
##################################################
|
88
89
|
# Scaffold
|
89
90
|
#
|
@@ -100,12 +101,15 @@ class ArTestBase < TestBase
|
|
100
101
|
@cad.save
|
101
102
|
end
|
102
103
|
|
104
|
+
|
103
105
|
def delete_records
|
104
106
|
@currency_test.destroy_all
|
105
107
|
end
|
106
108
|
|
109
|
+
|
107
110
|
##################################################
|
108
111
|
|
112
|
+
|
109
113
|
def assert_equal_money(a,b)
|
110
114
|
assert_not_nil a
|
111
115
|
assert_not_nil b
|
@@ -121,8 +125,8 @@ class ArTestBase < TestBase
|
|
121
125
|
assert_equal a.amount.convert(b.amount.currency).rep, b.amount.rep
|
122
126
|
end
|
123
127
|
|
124
|
-
def assert_equal_currency(a,b)
|
125
128
|
|
129
|
+
def assert_equal_currency(a,b)
|
126
130
|
assert_equal_money a, b
|
127
131
|
|
128
132
|
assert_equal a.amount.rep, b.amount.rep
|
@@ -131,12 +135,14 @@ class ArTestBase < TestBase
|
|
131
135
|
|
132
136
|
end
|
133
137
|
|
138
|
+
|
134
139
|
##################################################
|
135
140
|
#
|
136
141
|
#
|
142
|
+
|
137
143
|
|
138
144
|
def test_dummy
|
139
|
-
|
145
|
+
|
140
146
|
end
|
141
147
|
|
142
148
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
|
2
|
+
# See LICENSE.txt for details.
|
3
|
+
|
4
|
+
require 'test/ar_test_base'
|
5
|
+
|
6
|
+
module Currency
|
7
|
+
|
8
|
+
class ArTestCore < ArTestBase
|
9
|
+
|
10
|
+
##################################################
|
11
|
+
# Basic CurrenyTest AR::B class
|
12
|
+
#
|
13
|
+
|
14
|
+
TABLE_NAME = 'currency_test'
|
15
|
+
|
16
|
+
class CurrencyTestMigration < AR_M
|
17
|
+
def self.up
|
18
|
+
create_table TABLE_NAME.intern do |t|
|
19
|
+
t.column :name, :string
|
20
|
+
t.column :amount, :integer # Money
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.down
|
25
|
+
drop_table TABLE_NAME.intern
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
class CurrencyTest < AR_B
|
31
|
+
set_table_name TABLE_NAME
|
32
|
+
attr_money :amount
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
##################################################
|
37
|
+
|
38
|
+
|
39
|
+
def setup
|
40
|
+
@currency_test_migration ||= CurrencyTestMigration
|
41
|
+
@currency_test ||= CurrencyTest
|
42
|
+
super
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
def teardown
|
47
|
+
super
|
48
|
+
# schema_down
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
##################################################
|
53
|
+
#
|
54
|
+
#
|
55
|
+
|
56
|
+
|
57
|
+
def test_insert
|
58
|
+
insert_records
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end # module
|
64
|
+
|
@@ -0,0 +1,81 @@
|
|
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
|
+
|
7
|
+
module Currency
|
8
|
+
|
9
|
+
class FormatterTest < TestBase
|
10
|
+
def setup
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
############################################
|
15
|
+
# Simple stuff.
|
16
|
+
#
|
17
|
+
|
18
|
+
def test_default
|
19
|
+
assert_kind_of Money, m = ::Currency::Money.new_rep(123456789)
|
20
|
+
assert_equal m.currency, Currency.default
|
21
|
+
assert_equal m.currency.code, :USD
|
22
|
+
assert_equal "$1,234,567.89", m.to_s
|
23
|
+
|
24
|
+
m
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def test_thousands
|
29
|
+
m = test_default
|
30
|
+
assert_equal "$1234567.89", m.to_s(:thousands => false)
|
31
|
+
assert_equal "$1,234,567.89", m.to_s(:thousands => true)
|
32
|
+
|
33
|
+
m
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def test_cents
|
38
|
+
m = test_default
|
39
|
+
assert_equal "$1,234,567", m.to_s(:cents => false)
|
40
|
+
assert_equal "$1,234,567.89", m.to_s(:cents => true)
|
41
|
+
|
42
|
+
m
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
def test_symbol
|
47
|
+
m = test_default
|
48
|
+
assert_equal "1,234,567.89", m.to_s(:symbol => false)
|
49
|
+
assert_equal "$1,234,567.89", m.to_s(:symbol => true)
|
50
|
+
|
51
|
+
m
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def test_code
|
56
|
+
m = test_default
|
57
|
+
assert_equal "$1,234,567.89", m.to_s(:code => false)
|
58
|
+
assert_equal "$1,234,567.89 USD", m.to_s(:code => true)
|
59
|
+
|
60
|
+
m
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_misc
|
64
|
+
m = ::Currency::Money(12.45, :USD)
|
65
|
+
assert_equal "$12.45 <span class=\"currency_code\">USD</span>",
|
66
|
+
m.to_s(:html => true, :code => true)
|
67
|
+
|
68
|
+
m = ::Currency::Money(12.45, :EUR)
|
69
|
+
assert_equal "€12.45 <span class=\"currency_code\">EUR</span>",
|
70
|
+
m.to_s(:html => true, :code => true)
|
71
|
+
|
72
|
+
m = ::Currency::Money(12.45, :EUR)
|
73
|
+
assert_equal "€12.45 <span class=\"currency_code\">EUR</span>",
|
74
|
+
m.to_s(:html => true, :code => true, :thousands_separator => '_')
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end # module
|
81
|
+
|
@@ -0,0 +1,184 @@
|
|
1
|
+
# Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
|
2
|
+
# See LICENSE.txt for details.
|
3
|
+
|
4
|
+
require 'test/ar_test_base'
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
require 'active_record'
|
8
|
+
require 'active_record/migration'
|
9
|
+
|
10
|
+
require 'currency' # For :type => :money
|
11
|
+
|
12
|
+
require 'currency/exchange/rate/source/historical'
|
13
|
+
require 'currency/exchange/rate/source/historical/writer'
|
14
|
+
require 'currency/exchange/rate/source/xe'
|
15
|
+
require 'currency/exchange/rate/source/new_york_fed'
|
16
|
+
|
17
|
+
|
18
|
+
module Currency
|
19
|
+
|
20
|
+
class HistoricalWriterTest < ArTestBase
|
21
|
+
|
22
|
+
RATE_CLASS = Exchange::Rate::Source::Historical::Rate
|
23
|
+
TABLE_NAME = RATE_CLASS.table_name
|
24
|
+
|
25
|
+
class HistoricalRateMigration < AR_M
|
26
|
+
def self.up
|
27
|
+
RATE_CLASS.__create_table(self)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.down
|
31
|
+
drop_table TABLE_NAME.intern
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def initialize(*args)
|
37
|
+
@currency_test_migration = HistoricalRateMigration
|
38
|
+
super
|
39
|
+
|
40
|
+
@src = Exchange::Rate::Source::Xe.new
|
41
|
+
@src2 = Exchange::Rate::Source::NewYorkFed.new
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
def setup
|
46
|
+
super
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
def test_writer
|
52
|
+
assert_not_nil src = @src
|
53
|
+
assert_not_nil writer = Exchange::Rate::Source::Historical::Writer.new()
|
54
|
+
writer.time_quantitizer = :current
|
55
|
+
writer.required_currencies = [ :USD, :GBP, :EUR, :CAD ]
|
56
|
+
writer.base_currencies = [ :USD ]
|
57
|
+
writer.preferred_currencies = writer.required_currencies
|
58
|
+
writer.reciprocal_rates = true
|
59
|
+
writer.all_rates = true
|
60
|
+
writer.identity_rates = false
|
61
|
+
|
62
|
+
writer
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
def writer_src
|
67
|
+
writer = test_writer
|
68
|
+
writer.source = @src
|
69
|
+
rates = writer.write_rates
|
70
|
+
assert_not_nil rates
|
71
|
+
assert rates.size > 0
|
72
|
+
assert 12, rates.size
|
73
|
+
assert_h_rates(rates, writer)
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
def writer_src2
|
78
|
+
writer = test_writer
|
79
|
+
writer.source = @src2
|
80
|
+
rates = writer.write_rates
|
81
|
+
assert_not_nil rates
|
82
|
+
assert rates.size > 0
|
83
|
+
assert_equal 12, rates.size
|
84
|
+
assert_h_rates(rates, writer)
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
def xxx_test_required_failure
|
89
|
+
assert_not_nil writer = Exchange::Rate::Source::Historical::Writer.new()
|
90
|
+
assert_not_nil src = @src
|
91
|
+
writer.source = src
|
92
|
+
writer.required_currencies = [ :USD, :GBP, :EUR, :CAD, :ZZZ ]
|
93
|
+
writer.preferred_currencies = writer.required_currencies
|
94
|
+
assert_raises(::RuntimeError) { writer.selected_rates }
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
def test_historical_rates
|
99
|
+
# Make sure there are historical Rates avail for today.
|
100
|
+
writer_src
|
101
|
+
writer_src2
|
102
|
+
|
103
|
+
# Force Historical Rate Source.
|
104
|
+
source = Exchange::Rate::Source::Historical.new
|
105
|
+
deriver = Exchange::Rate::Deriver.new(:source => source)
|
106
|
+
Exchange::Rate::Source.default = deriver
|
107
|
+
|
108
|
+
rates = source.get_raw_rates
|
109
|
+
#$stderr.puts "historical rates = #{rates.inspect}"
|
110
|
+
|
111
|
+
rates = source.get_rates
|
112
|
+
#$stderr.puts "historical rates = #{rates.inspect}"
|
113
|
+
|
114
|
+
assert_not_nil m_usd = ::Currency::Money('1234.56', :USD, :now)
|
115
|
+
#$stderr.puts "m_usd = #{m_usd.to_s(:code => true)}"
|
116
|
+
assert_not_nil m_eur = m_usd.convert(:EUR)
|
117
|
+
#$stderr.puts "m_eur = #{m_eur.to_s(:code => true)}"
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
def assert_h_rates(rates, writer = nil)
|
123
|
+
assert_not_nil hr0 = rates[0]
|
124
|
+
rates.each do | hr |
|
125
|
+
found_hr = nil
|
126
|
+
begin
|
127
|
+
assert_not_nil found_hr = hr.find_matching_this(:first)
|
128
|
+
rescue Object => err
|
129
|
+
raise "#{hr.inspect}: #{err}:\n#{err.backtrace.inspect}"
|
130
|
+
end
|
131
|
+
|
132
|
+
assert_not_nil hr0
|
133
|
+
|
134
|
+
assert_equal hr0.date, hr.date
|
135
|
+
assert_equal hr0.date_0, hr.date_0
|
136
|
+
assert_equal hr0.date_1, hr.date_1
|
137
|
+
assert_equal hr0.source, hr.source
|
138
|
+
|
139
|
+
assert_equal_rate(hr, found_hr)
|
140
|
+
assert_rate_defaults(hr, writer)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
|
145
|
+
def assert_equal_rate(hr0, hr)
|
146
|
+
assert_equal hr0.c1.to_s, hr.c1.to_s
|
147
|
+
assert_equal hr0.c2.to_s, hr.c2.to_s
|
148
|
+
assert_equal hr0.source, hr.source
|
149
|
+
assert_equal_float hr0.rate, hr.rate
|
150
|
+
assert_equal_float hr0.rate_avg, hr.rate_avg
|
151
|
+
assert_equal hr0.rate_samples, hr.rate_samples
|
152
|
+
assert_equal_float hr0.rate_lo, hr.rate_lo
|
153
|
+
assert_equal_float hr0.rate_hi, hr.rate_hi
|
154
|
+
assert_equal_float hr0.rate_date_0, hr.rate_date_0
|
155
|
+
assert_equal_float hr0.rate_date_1, hr.rate_date_1
|
156
|
+
assert_equal hr0.date, hr.date
|
157
|
+
assert_equal hr0.date_0, hr.date_0
|
158
|
+
assert_equal hr0.date_1, hr.date_1
|
159
|
+
assert_equal hr0.derived, hr.derived
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
def assert_rate_defaults(hr, writer)
|
164
|
+
assert_equal writer.source.name, hr.source if writer
|
165
|
+
assert_equal hr.rate, hr.rate_avg
|
166
|
+
assert_equal hr.rate_samples, 1
|
167
|
+
assert_equal hr.rate, hr.rate_lo
|
168
|
+
assert_equal hr.rate, hr.rate_hi
|
169
|
+
assert_equal hr.rate, hr.rate_date_0
|
170
|
+
assert_equal hr.rate, hr.rate_date_1
|
171
|
+
end
|
172
|
+
|
173
|
+
|
174
|
+
def assert_equal_float(x1, x2, eps = 0.00001)
|
175
|
+
eps = (x1 * eps).abs
|
176
|
+
assert((x1 - eps) <= x2)
|
177
|
+
assert((x1 + eps) >= x2)
|
178
|
+
end
|
179
|
+
|
180
|
+
|
181
|
+
end
|
182
|
+
|
183
|
+
end # module
|
184
|
+
|