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.
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
+