currency 0.4.6 → 0.4.7

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.
@@ -22,6 +22,7 @@ lib/currency/exchange/rate/deriver.rb
22
22
  lib/currency/exchange/rate/source.rb
23
23
  lib/currency/exchange/rate/source/base.rb
24
24
  lib/currency/exchange/rate/source/failover.rb
25
+ lib/currency/exchange/rate/source/federal_reserve.rb
25
26
  lib/currency/exchange/rate/source/historical.rb
26
27
  lib/currency/exchange/rate/source/historical/rate.rb
27
28
  lib/currency/exchange/rate/source/historical/writer.rb
@@ -42,6 +43,7 @@ test/ar_simple_test.rb
42
43
  test/ar_test_base.rb
43
44
  test/ar_test_core.rb
44
45
  test/config_test.rb
46
+ test/federal_reserve_test.rb
45
47
  test/formatter_test.rb
46
48
  test/historical_writer_test.rb
47
49
  test/macro_test.rb
@@ -1,5 +1,21 @@
1
1
  = Currency Release History
2
2
 
3
+ == Release 0.4.7: 2007/06/25
4
+
5
+ CRITICAL FIXES
6
+
7
+ * NewYorkFed: CRITICAL FIX:
8
+
9
+ Rates for USDAUD, USDEUR, USDNZD and USDGBP were reciprocals.
10
+ See http://www.newyorkfed.org/markets/fxrates/noon.cfm
11
+
12
+ * FederalReserve: Added support for historical rates from http://www.federalreserve.gov/releases/H10/hist
13
+ * Provider#get_rate(): Return first rate immediately.
14
+ * Rate::Writable for rate summary computation support.
15
+ * Rate: collect_rate(): fixed rate_date_1.
16
+ * Historical::Rate: to_rate(): takes optional class.
17
+ * Historical::Rate: from_rate(): fixed rate_samples.
18
+
3
19
  == Release 0.4.6: 2007/05/29
4
20
 
5
21
  * NewYorkFed: changed FEXtime to FEXTIME.
data/TODO.txt CHANGED
@@ -3,3 +3,5 @@
3
3
 
4
4
  * Refactor all configuration class variables into Currency::Config
5
5
  * Refactor all cached values into objects that can be reinstantiated on a per-thread basis
6
+ * Support http://www.xe.com/ucc/full.php rate queries.
7
+
@@ -1,5 +1,5 @@
1
1
  module Currency
2
- CurrencyVersion = '0.4.6'
2
+ CurrencyVersion = '0.4.7'
3
3
  end
4
4
  # DO NOT EDIT
5
5
  # This file is auto-generated by build scripts.
@@ -1,6 +1,8 @@
1
1
  # Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
2
2
  # See LICENSE.txt for details.
3
3
 
4
+ require 'currency'
5
+
4
6
  # The Currency::Exchange package is responsible for
5
7
  # the buying and selling of currencies.
6
8
  #
@@ -1,6 +1,8 @@
1
1
  # Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
2
2
  # See LICENSE.txt for details.
3
3
 
4
+ require 'currency/exchange'
5
+
4
6
  # Represents a convertion rate between two currencies at a given period of time.
5
7
  class Currency::Exchange::Rate
6
8
  # The first Currency.
@@ -132,7 +134,6 @@ class Currency::Exchange::Rate
132
134
  @source ||= rate.source
133
135
  @c1 ||= rate.c1
134
136
  @c2 ||= rate.c2
135
- @date ||= rate.date
136
137
 
137
138
  # Reciprocal?
138
139
  if @c1 == rate.c2 && @c2 == rate.c1
@@ -170,7 +171,7 @@ class Currency::Exchange::Rate
170
171
  d = rate.date_1 || rate.date
171
172
  unless @date_1 && @date_1 > d
172
173
  @date_1 = d
173
- @rate_date_0 = r
174
+ @rate_date_1 = r
174
175
  end
175
176
 
176
177
  @date ||= rate.date || rate.date0 || rate.date1
@@ -190,3 +191,13 @@ class Currency::Exchange::Rate
190
191
  end # class
191
192
 
192
193
 
194
+ class Currency::Exchange::Rate::Writable < Currency::Exchange::Rate
195
+ attr_writer :source
196
+ attr_writer :derived
197
+ attr_writer :rate
198
+ def initialize(c1 = nil, c2 = nil, rate = nil, *opts)
199
+ super(c1, c2, 0.0, *opts)
200
+ @rate = rate
201
+ end
202
+ end # class
203
+
@@ -0,0 +1,160 @@
1
+ # Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
2
+ # See LICENSE.txt for details.
3
+
4
+ require 'currency/exchange/rate/source/provider'
5
+
6
+ require 'net/http'
7
+ require 'open-uri'
8
+
9
+
10
+ # Connects to http://www.federalreserve.gov/releases/H10/hist/dat00_<country>.txtb
11
+ # Parses all known currency files.
12
+ #
13
+ class Currency::Exchange::Rate::Source::FederalReserve < ::Currency::Exchange::Rate::Source::Provider
14
+ # Defines the pivot currency for http://www.federalreserve.gov/releases/H10/hist/dat00_#{country_code}.txt data files.
15
+ PIVOT_CURRENCY = :USD
16
+
17
+ # Arbitrary currency code used by www.federalreserve.gov for
18
+ # naming historical data files.
19
+ # Used internally.
20
+ attr_accessor :country_code
21
+
22
+ def initialize(*opt)
23
+ self.uri = 'http://www.federalreserve.gov/releases/H10/hist/dat00_#{country_code}.txt'
24
+ self.country_code = ''
25
+ @raw_rates = nil
26
+ super(*opt)
27
+ end
28
+
29
+
30
+ # Returns 'federalreserve.gov'.
31
+ def name
32
+ 'federalreserve.gov'
33
+ end
34
+
35
+
36
+ # FIXME?
37
+ #def available?(time = nil)
38
+ # time ||= Time.now
39
+ # ! [0, 6].include?(time.wday) ? true : false
40
+ #end
41
+
42
+
43
+ def clear_rates
44
+ @raw_rates = nil
45
+ super
46
+ end
47
+
48
+
49
+ def raw_rates
50
+ rates
51
+ @raw_rates
52
+ end
53
+
54
+ # Maps bizzare federalreserve.gov country codes to ISO currency codes.
55
+ # May only work for the dat00_XX.txt data files.
56
+ # See http://www.jhall.demon.co.uk/currency/by_country.html
57
+ #
58
+ # Some data files list reciprocal rates!
59
+ @@country_to_currency =
60
+ {
61
+ 'al' => [ :AUD, :USD ],
62
+ # 'au' => :ASH, # AUSTRIAN SHILLING: pre-EUR?
63
+ 'bz' => [ :USD, :BRL ],
64
+ 'ca' => [ :USD, :CAD ],
65
+ 'ch' => [ :USD, :CNY ],
66
+ 'dn' => [ :USD, :DKK ],
67
+ 'eu' => [ :EUR, :USD ],
68
+ # 'gr' => :XXX, # Greece Drachma: pre-EUR?
69
+ 'hk' => [ :USD, :HKD ],
70
+ 'in' => [ :USD, :INR ],
71
+ 'ja' => [ :USD, :JPY ],
72
+ 'ma' => [ :USD, :MYR ],
73
+ 'mx' => [ :USD, :MXN ], # OR MXP?
74
+ 'nz' => [ :NZD, :USD ],
75
+ 'no' => [ :USD, :NOK ],
76
+ 'ko' => [ :USD, :KRW ],
77
+ 'sf' => [ :USD, :ZAR ],
78
+ 'sl' => [ :USD, :LKR ],
79
+ 'sd' => [ :USD, :SEK ],
80
+ 'sz' => [ :USD, :CHF ],
81
+ 'ta' => [ :USD, :TWD ], # New Taiwan Dollar.
82
+ 'th' => [ :USD, :THB ],
83
+ 'uk' => [ :GBP, :USD ],
84
+ 've' => [ :USD, :VEB ],
85
+ }
86
+
87
+
88
+ # Parses text file for rates.
89
+ def parse_rates(data = nil)
90
+ data = get_page_content unless data
91
+
92
+ rates = [ ]
93
+
94
+ @raw_rates ||= { }
95
+
96
+ $stderr.puts "#{self}: parse_rates: data =\n#{data}" if @verbose
97
+
98
+ # Rates are USD/currency so
99
+ # c1 = currency
100
+ # c2 = :USD
101
+ c1, c2 = @@country_to_currency[country_code]
102
+
103
+ unless c1 && c2
104
+ raise(::Currency::Exception::UnavailableRates, "Cannot determine currency code for federalreserve.gov country code #{country_code.inspect}")
105
+ end
106
+
107
+ data.split(/\r?\n\r?/).each do | line |
108
+ # day month yy rate
109
+ m = /^\s*(\d\d?)-([A-Z][a-z][a-z])-(\d\d)\s+([\d\.]+)/.match(line)
110
+ next unless m
111
+
112
+ day = m[1].to_i
113
+ month = m[2]
114
+ year = m[3].to_i
115
+ if year >= 50 and year < 100
116
+ year += 1900
117
+ elsif year < 50
118
+ year += 2000
119
+ end
120
+
121
+ date = Time.parse("#{day}-#{month}-#{year} 12:00:00 -05:00") # USA NY => EST
122
+
123
+ rate = m[4].to_f
124
+
125
+ STDERR.puts "#{c1} #{c2} #{rate} #{date}" if @verbose
126
+
127
+ rates << new_rate(c1, c2, rate, date)
128
+
129
+ ((@raw_rates[date] ||= { })[c1] ||= { })[c2] ||= rate
130
+ ((@raw_rates[date] ||= { })[c2] ||= { })[c1] ||= 1.0 / rate
131
+ end
132
+
133
+ # Put most recent rate first.
134
+ # See Provider#get_rate.
135
+ rates.reverse!
136
+
137
+ # $stderr.puts "rates = #{rates.inspect}"
138
+ raise ::Currency::Exception::UnavailableRates, "No rates found in #{get_uri.inspect}" if rates.empty?
139
+
140
+ rates
141
+ end
142
+
143
+
144
+ # Return a list of known base rates.
145
+ def load_rates(time = nil)
146
+ # $stderr.puts "#{self}: load_rates(#{time})" if @verbose
147
+ self.date = time
148
+ rates = [ ]
149
+ @@country_to_currency.keys.each do | cc |
150
+ self.country_code = cc
151
+ rates.push(*parse_rates)
152
+ end
153
+ rates
154
+ end
155
+
156
+
157
+ end # class
158
+
159
+
160
+
@@ -56,6 +56,7 @@ class Currency::Exchange::Rate::Source::Historical::Rate < ::ActiveRecord::Base
56
56
  self.c2 = rate.c2.code.to_s
57
57
  self.rate = rate.rate
58
58
  self.rate_avg = rate.rate_avg
59
+ self.rate_samples = rate.rate_samples
59
60
  self.rate_lo = rate.rate_lo
60
61
  self.rate_hi = rate.rate_hi
61
62
  self.rate_date_0 = rate.rate_date_0
@@ -78,24 +79,25 @@ class Currency::Exchange::Rate::Source::Historical::Rate < ::ActiveRecord::Base
78
79
 
79
80
 
80
81
  # Creates a new Currency::Exchange::Rate object.
81
- def to_rate
82
- Currency::Exchange::Rate.new(
83
- ::Currency::Currency.get(self.c1),
84
- ::Currency::Currency.get(self.c2),
85
- self.rate,
86
- "historical #{self.source}",
87
- self.date,
88
- self.derived,
89
- {
90
- :rate_avg => self.rate_avg,
91
- :rate_samples => self.rate_samples,
92
- :rate_lo => self.rate_lo,
93
- :rate_hi => self.rate_hi,
94
- :rate_date_0 => self.rate_date_0,
95
- :rate_date_1 => self.rate_date_1,
96
- :date_0 => self.date_0,
97
- :date_1 => self.date_1
98
- })
82
+ def to_rate(cls = ::Currency::Exchange::Rate)
83
+ cls.
84
+ new(
85
+ ::Currency::Currency.get(self.c1),
86
+ ::Currency::Currency.get(self.c2),
87
+ self.rate,
88
+ "historical #{self.source}",
89
+ self.date,
90
+ self.derived,
91
+ {
92
+ :rate_avg => self.rate_avg,
93
+ :rate_samples => self.rate_samples,
94
+ :rate_lo => self.rate_lo,
95
+ :rate_hi => self.rate_hi,
96
+ :rate_date_0 => self.rate_date_0,
97
+ :rate_date_1 => self.rate_date_1,
98
+ :date_0 => self.date_0,
99
+ :date_1 => self.date_1
100
+ })
99
101
  end
100
102
 
101
103
 
@@ -47,6 +47,17 @@ class Currency::Exchange::Rate::Source::NewYorkFed < ::Currency::Exchange::Rate:
47
47
  rates
48
48
  @raw_rates
49
49
  end
50
+
51
+
52
+ # The fed swaps rates on some currency pairs!
53
+ # See http://www.newyorkfed.org/markets/fxrates/noon.cfm (LISTS AUD!)
54
+ # http://www.newyorkfed.org/xml/fx.html (DOES NOT LIST AUD!)
55
+ @@swap_units = {
56
+ :AUD => true,
57
+ :EUR => true,
58
+ :NZD => true,
59
+ :GBP => true,
60
+ }
50
61
 
51
62
 
52
63
  # Parses XML for rates.
@@ -80,6 +91,11 @@ class Currency::Exchange::Rate::Source::NewYorkFed < ::Currency::Exchange::Rate:
80
91
  date = date.text
81
92
  date = Time.parse("#{date} 12:00:00 -05:00") # USA NY => EST
82
93
 
94
+ # Handle arbitrary rate reciprocals!
95
+ if @@swap_units[c1] || @@swap_units[c2]
96
+ c1, c2 = c2, c1
97
+ end
98
+
83
99
  rates << new_rate(c1, c2, rate, date)
84
100
 
85
101
  (@raw_rates[c1] ||= { })[c2] ||= rate
@@ -94,14 +94,16 @@ class Currency::Exchange::Rate::Source::Provider < Currency::Exchange::Rate::Sou
94
94
  end
95
95
 
96
96
 
97
- # Return a matching base rate?
97
+ # Return a matching base rate.
98
98
  def get_rate(c1, c2, time)
99
- matching_rates = rates.select do | rate |
100
- rate.c1 == c1 &&
101
- rate.c2 == c2 &&
102
- (! time || normalize_time(rate.date) == time)
99
+ rates.each do | rate |
100
+ return rate if
101
+ rate.c1 == c1 &&
102
+ rate.c2 == c2 &&
103
+ (! time || normalize_time(rate.date) == time)
103
104
  end
104
- matching_rates[0]
105
+
106
+ nil
105
107
  end
106
108
 
107
109
  alias :get_rate_base :get_rate
@@ -0,0 +1,75 @@
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
+
6
+ require 'currency' # For :type => :money
7
+ require 'currency/exchange/rate/source/federal_reserve'
8
+
9
+ module Currency
10
+
11
+ class FederalReserveTest < TestBase
12
+ def setup
13
+ super
14
+ end
15
+
16
+
17
+ @@available = nil
18
+
19
+ # New York Fed rates are not available on Saturday and Sunday.
20
+ def available?
21
+ if @@available == nil
22
+ @@available = @source.available?
23
+ STDERR.puts "Warning: FederalReserve unavailable on Saturday and Sunday, skipping tests." unless @@available
24
+ end
25
+ @@available
26
+ end
27
+
28
+
29
+ def get_rate_source
30
+ # Force FederalReserve Exchange.
31
+ verbose = false
32
+ source = @source = Exchange::Rate::Source::FederalReserve.new(:verbose => verbose)
33
+ deriver = Exchange::Rate::Deriver.new(:source => source, :verbose => source.verbose)
34
+ end
35
+
36
+
37
+
38
+ def test_usd_cad
39
+ return unless available?
40
+
41
+ # yesterday = Time.now.to_date - 1
42
+
43
+ assert_not_nil rates = Exchange::Rate::Source.default.source.raw_rates
44
+ #assert_not_nil rates[:USD]
45
+ #assert_not_nil usd_cad = rates[:USD][:CAD]
46
+
47
+ assert_not_nil usd = Money.new(123.45, :USD)
48
+ assert_not_nil cad = usd.convert(:CAD)
49
+
50
+ # assert_kind_of Numeric, m = (cad.to_f / usd.to_f)
51
+ # $stderr.puts "m = #{m}"
52
+ # assert_equal_float usd_cad, m, 0.001
53
+ end
54
+
55
+
56
+ def test_cad_eur
57
+ return unless available?
58
+
59
+ assert_not_nil rates = Exchange::Rate::Source.default.source.raw_rates
60
+ #assert_not_nil rates[:USD]
61
+ #assert_not_nil usd_cad = rates[:USD][:CAD]
62
+ #assert_not_nil usd_eur = rates[:USD][:EUR]
63
+
64
+ assert_not_nil cad = Money.new(123.45, :CAD)
65
+ assert_not_nil eur = cad.convert(:EUR)
66
+
67
+ #assert_kind_of Numeric, m = (eur.to_f / cad.to_f)
68
+ # $stderr.puts "m = #{m}"
69
+ #assert_equal_float (1.0 / usd_cad) * usd_eur, m, 0.001
70
+ end
71
+
72
+ end
73
+
74
+ end # module
75
+
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: currency
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.4.6
7
- date: 2007-05-30 00:00:00 -04:00
6
+ version: 0.4.7
7
+ date: 2007-06-25 00:00:00 -04:00
8
8
  summary: "Currency models currencies, monetary values, foreign exchanges rates. Pulls live and historical rates from http://xe.com/, http://newyorkfed.org/, http://thefinancials.com/. Can store/retrieve historical rate data from database using ActiveRecord. Can store/retrieve Money values using ActiveRecord. For more details, see: http://rubyforge.org/projects/currency/ http://currency.rubyforge.org/ http://currency.rubyforge.org/files/README_txt.html"
9
9
  require_paths:
10
10
  - lib
@@ -54,6 +54,7 @@ files:
54
54
  - lib/currency/exchange/rate/source.rb
55
55
  - lib/currency/exchange/rate/source/base.rb
56
56
  - lib/currency/exchange/rate/source/failover.rb
57
+ - lib/currency/exchange/rate/source/federal_reserve.rb
57
58
  - lib/currency/exchange/rate/source/historical.rb
58
59
  - lib/currency/exchange/rate/source/historical/rate.rb
59
60
  - lib/currency/exchange/rate/source/historical/writer.rb
@@ -74,6 +75,7 @@ files:
74
75
  - test/ar_test_base.rb
75
76
  - test/ar_test_core.rb
76
77
  - test/config_test.rb
78
+ - test/federal_reserve_test.rb
77
79
  - test/formatter_test.rb
78
80
  - test/historical_writer_test.rb
79
81
  - test/macro_test.rb