currency 0.3.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/COPYING.txt +339 -0
  2. data/LICENSE.txt +62 -0
  3. data/Manifest.txt +37 -14
  4. data/README.txt +8 -0
  5. data/Rakefile +42 -8
  6. data/Releases.txt +26 -0
  7. data/TODO.txt +1 -0
  8. data/examples/ex1.rb +3 -3
  9. data/examples/xe1.rb +3 -2
  10. data/lib/currency.rb +71 -9
  11. data/lib/currency/active_record.rb +138 -21
  12. data/lib/currency/core_extensions.rb +7 -5
  13. data/lib/currency/currency.rb +94 -177
  14. data/lib/currency/{currency_factory.rb → currency/factory.rb} +46 -25
  15. data/lib/currency/currency_version.rb +3 -3
  16. data/lib/currency/exception.rb +14 -14
  17. data/lib/currency/exchange.rb +14 -12
  18. data/lib/currency/exchange/rate.rb +159 -28
  19. data/lib/currency/exchange/rate/deriver.rb +146 -0
  20. data/lib/currency/exchange/rate/source.rb +84 -0
  21. data/lib/currency/exchange/rate/source/base.rb +156 -0
  22. data/lib/currency/exchange/rate/source/failover.rb +57 -0
  23. data/lib/currency/exchange/rate/source/historical.rb +79 -0
  24. data/lib/currency/exchange/rate/source/historical/rate.rb +181 -0
  25. data/lib/currency/exchange/rate/source/historical/writer.rb +203 -0
  26. data/lib/currency/exchange/rate/source/new_york_fed.rb +91 -0
  27. data/lib/currency/exchange/rate/source/provider.rb +105 -0
  28. data/lib/currency/exchange/rate/source/test.rb +50 -0
  29. data/lib/currency/exchange/rate/source/the_financials.rb +190 -0
  30. data/lib/currency/exchange/rate/source/timed_cache.rb +144 -0
  31. data/lib/currency/exchange/rate/source/xe.rb +166 -0
  32. data/lib/currency/exchange/time_quantitizer.rb +111 -0
  33. data/lib/currency/formatter.rb +159 -0
  34. data/lib/currency/macro.rb +321 -0
  35. data/lib/currency/money.rb +90 -64
  36. data/lib/currency/money_helper.rb +6 -5
  37. data/lib/currency/parser.rb +153 -0
  38. data/test/ar_column_test.rb +6 -3
  39. data/test/ar_simple_test.rb +5 -2
  40. data/test/ar_test_base.rb +39 -33
  41. data/test/ar_test_core.rb +64 -0
  42. data/test/formatter_test.rb +81 -0
  43. data/test/historical_writer_test.rb +184 -0
  44. data/test/macro_test.rb +109 -0
  45. data/test/money_test.rb +72 -4
  46. data/test/new_york_fed_test.rb +57 -0
  47. data/test/parser_test.rb +60 -0
  48. data/test/test_base.rb +13 -3
  49. data/test/time_quantitizer_test.rb +136 -0
  50. data/test/xe_test.rb +29 -5
  51. metadata +41 -18
  52. data/lib/currency/exchange/base.rb +0 -84
  53. data/lib/currency/exchange/test.rb +0 -39
  54. data/lib/currency/exchange/xe.rb +0 -250
@@ -1,4 +1,7 @@
1
- require 'test/ar_test_base'
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 < ArTestBase
14
+ class ArSimpleTest < ArTestCore
12
15
 
13
16
  def test_simple
14
17
  insert_records
@@ -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 ||= CurrencyTestMigration
48
- @currency_test ||= CurrencyTest
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 => "mysql",
64
- :host => "localhost",
65
- :username => "test",
66
- :password => "test",
67
- :database => "test"
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
- insert_records
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 "&#8364;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 "&#8364;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
+