mumboe-currency 0.5
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/bin/currency_historical_rate_load +105 -0
- data/examples/ex1.rb +13 -0
- data/examples/xe1.rb +20 -0
- data/lib/currency/active_record.rb +265 -0
- data/lib/currency/config.rb +91 -0
- data/lib/currency/core_extensions.rb +41 -0
- data/lib/currency/currency/factory.rb +228 -0
- data/lib/currency/currency.rb +175 -0
- data/lib/currency/currency_version.rb +6 -0
- data/lib/currency/exception.rb +119 -0
- data/lib/currency/exchange/rate/deriver.rb +157 -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/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/historical.rb +79 -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/rate/source.rb +89 -0
- data/lib/currency/exchange/rate.rb +214 -0
- data/lib/currency/exchange/time_quantitizer.rb +111 -0
- data/lib/currency/exchange.rb +50 -0
- data/lib/currency/formatter.rb +290 -0
- data/lib/currency/macro.rb +321 -0
- data/lib/currency/money.rb +295 -0
- data/lib/currency/money_helper.rb +13 -0
- data/lib/currency/parser.rb +151 -0
- data/lib/currency.rb +143 -0
- data/test/string_test.rb +54 -0
- data/test/test_base.rb +44 -0
- metadata +90 -0
@@ -0,0 +1,166 @@
|
|
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'
|
5
|
+
|
6
|
+
# = Currency::Exchange::Rate::Source::Base
|
7
|
+
#
|
8
|
+
# The Currency::Exchange::Rate::Source::Base class is the base class for
|
9
|
+
# currency exchange rate providers.
|
10
|
+
#
|
11
|
+
# Currency::Exchange::Rate::Source::Base subclasses are Currency::Exchange::Rate
|
12
|
+
# factories.
|
13
|
+
#
|
14
|
+
# Represents a method of converting between two currencies.
|
15
|
+
#
|
16
|
+
# See Currency;:Exchange::Rate::source for more details.
|
17
|
+
#
|
18
|
+
class Currency::Exchange::Rate::Source::Base
|
19
|
+
|
20
|
+
# The name of this Exchange.
|
21
|
+
attr_accessor :name
|
22
|
+
|
23
|
+
# Currency to use as pivot for deriving rate pairs.
|
24
|
+
# Defaults to :USD.
|
25
|
+
attr_accessor :pivot_currency
|
26
|
+
|
27
|
+
# If true, this Exchange will log information.
|
28
|
+
attr_accessor :verbose
|
29
|
+
|
30
|
+
attr_accessor :time_quantitizer
|
31
|
+
|
32
|
+
|
33
|
+
def initialize(opt = { })
|
34
|
+
@name = nil
|
35
|
+
@verbose = nil unless defined? @verbose
|
36
|
+
@pivot_currency ||= :USD
|
37
|
+
|
38
|
+
@rate = { }
|
39
|
+
@currencies = nil
|
40
|
+
opt.each_pair{|k,v| self.send("#{k}=", v)}
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
def __subclass_responsibility(meth)
|
45
|
+
raise ::Currency::Exception::SubclassResponsibility,
|
46
|
+
[
|
47
|
+
"#{self.class}#\#{meth}",
|
48
|
+
:class, self.class,
|
49
|
+
:method, method,
|
50
|
+
]
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
# Converts Money m in Currency c1 to a new
|
55
|
+
# Money value in Currency c2.
|
56
|
+
def convert(m, c2, time = nil, c1 = nil)
|
57
|
+
c1 = m.currency if c1 == nil
|
58
|
+
time = m.time if time == nil
|
59
|
+
time = normalize_time(time)
|
60
|
+
if c1 == c2 && normalize_time(m.time) == time
|
61
|
+
m
|
62
|
+
else
|
63
|
+
rate = rate(c1, c2, time)
|
64
|
+
# raise ::Currency::Exception::UnknownRate, "#{c1} #{c2} #{time}" unless rate
|
65
|
+
|
66
|
+
rate && ::Currency::Money(rate.convert(m, c1), c2, time)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
# Flush all cached Rate.
|
72
|
+
def clear_rates
|
73
|
+
@rate.clear
|
74
|
+
@currencies = nil
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
# Flush any cached Rate between Currency c1 and c2.
|
79
|
+
def clear_rate(c1, c2, time, recip = true)
|
80
|
+
time = time && normalize_time(time)
|
81
|
+
@rate["#{c1}:#{c2}:#{time}"] = nil
|
82
|
+
@rate["#{c2}:#{c1}:#{time}"] = nil if recip
|
83
|
+
time
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
# Returns the cached Rate between Currency c1 and c2 at a given time.
|
88
|
+
#
|
89
|
+
# Time is normalized using #normalize_time(time)
|
90
|
+
#
|
91
|
+
# Subclasses can override this method to implement
|
92
|
+
# rate expiration rules.
|
93
|
+
#
|
94
|
+
def rate(c1, c2, time)
|
95
|
+
time = time && normalize_time(time)
|
96
|
+
@rate["#{c1}:#{c2}:#{time}"] ||= get_rate(c1, c2, time)
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
# Gets all rates available by this source.
|
101
|
+
#
|
102
|
+
def rates(time = nil)
|
103
|
+
__subclass_responsibility(:rates)
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
# Returns a list of Currencies that the rate source provides.
|
108
|
+
#
|
109
|
+
# Subclasses can override this method.
|
110
|
+
def currencies
|
111
|
+
@currencies ||= rates.collect{| r | [ r.c1, r.c2 ]}.flatten.uniq
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
# Determines and creates the Rate between Currency c1 and c2.
|
116
|
+
#
|
117
|
+
# May attempt to use a pivot currency to bridge between
|
118
|
+
# rates.
|
119
|
+
#
|
120
|
+
def get_rate(c1, c2, time)
|
121
|
+
__subclass_responsibility(:get_rate)
|
122
|
+
end
|
123
|
+
|
124
|
+
# Returns a base Rate.
|
125
|
+
#
|
126
|
+
# Subclasses are required to implement this method.
|
127
|
+
def get_rate_base(c1, c2, time)
|
128
|
+
__subclass_responsibility(:get_rate_base)
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
# Returns a list of all available rates.
|
133
|
+
#
|
134
|
+
# Subclasses must override this method.
|
135
|
+
def get_rates(time = nil)
|
136
|
+
__subclass_responsibility(:get_rates)
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
# Called by implementors to construct new Rate objects.
|
141
|
+
def new_rate(c1, c2, c1_to_c2_rate, time = nil, derived = nil)
|
142
|
+
c1 = ::Currency::Currency.get(c1)
|
143
|
+
c2 = ::Currency::Currency.get(c2)
|
144
|
+
rate = ::Currency::Exchange::Rate.new(c1, c2, c1_to_c2_rate, name, time, derived)
|
145
|
+
# $stderr.puts "new_rate = #{rate}"
|
146
|
+
rate
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
# Normalizes rate time to a quantitized value.
|
151
|
+
#
|
152
|
+
# Subclasses can override this method.
|
153
|
+
def normalize_time(time)
|
154
|
+
time && (time_quantitizer || ::Currency::Exchange::TimeQuantitizer.current).quantitize_time(time)
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
# Returns a simple string rep.
|
159
|
+
def to_s
|
160
|
+
"#<#{self.class.name} #{self.name && self.name.inspect}>"
|
161
|
+
end
|
162
|
+
alias :inspect :to_s
|
163
|
+
|
164
|
+
end # class
|
165
|
+
|
166
|
+
|
@@ -0,0 +1,63 @@
|
|
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'
|
5
|
+
|
6
|
+
|
7
|
+
# Gets Rates from primary source, if primary fails, attempts secondary source.
|
8
|
+
#
|
9
|
+
class Currency::Exchange::Rate::Source::Failover < ::Currency::Exchange::Base
|
10
|
+
# Primary rate source.
|
11
|
+
attr_accessor :primary
|
12
|
+
|
13
|
+
# Secondary rate source if primary fails.
|
14
|
+
attr_accessor :secondary
|
15
|
+
|
16
|
+
def name
|
17
|
+
"failover(#{primary.name}, #{secondary.name})"
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
def clear_rates
|
22
|
+
@primary.clear_rates
|
23
|
+
@secondary.clear_rates
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def get_rate(c1, c2, time)
|
29
|
+
rate = nil
|
30
|
+
|
31
|
+
# Try primary.
|
32
|
+
err = nil
|
33
|
+
begin
|
34
|
+
rate = @primary.get_rate(c1, c2, time)
|
35
|
+
rescue Object => e
|
36
|
+
err = e
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
if rate == nil || err
|
41
|
+
$stderr.puts "Failover: primary failed for get_rate(#{c1}, #{c2}, #{time}) : #{err.inspect}"
|
42
|
+
rate = @secondary.get_rate(c1, c2, time)
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
unless rate
|
47
|
+
raise Currency::Exception::UnknownRate,
|
48
|
+
[
|
49
|
+
"Failover: secondary failed for get_rate(#{c1}, #{c2}, #{time})",
|
50
|
+
:c1, c1,
|
51
|
+
:c2, c2,
|
52
|
+
:time, time,
|
53
|
+
]
|
54
|
+
end
|
55
|
+
|
56
|
+
rate
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
end # class
|
61
|
+
|
62
|
+
|
63
|
+
|
@@ -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}\t#{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
|
+
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'active_record/base'
|
3
|
+
|
4
|
+
require 'currency/exchange/rate/source/historical'
|
5
|
+
|
6
|
+
# This class represents a historical Rate in a database.
|
7
|
+
# It requires ActiveRecord.
|
8
|
+
#
|
9
|
+
class Currency::Exchange::Rate::Source::Historical::Rate < ::ActiveRecord::Base
|
10
|
+
@@_table_name ||= Currency::Config.current.historical_table_name
|
11
|
+
set_table_name @@_table_name
|
12
|
+
|
13
|
+
# Can create a table and indices for this class
|
14
|
+
# when passed a Migration.
|
15
|
+
def self.__create_table(m, table_name = @@_table_name)
|
16
|
+
table_name = table_name.intern
|
17
|
+
m.instance_eval do
|
18
|
+
create_table table_name do |t|
|
19
|
+
t.column :created_on, :datetime, :null => false
|
20
|
+
t.column :updated_on, :datetime
|
21
|
+
|
22
|
+
t.column :c1, :string, :limit => 3, :null => false
|
23
|
+
t.column :c2, :string, :limit => 3, :null => false
|
24
|
+
|
25
|
+
t.column :source, :string, :limit => 32, :null => false
|
26
|
+
|
27
|
+
t.column :rate, :float, :null => false
|
28
|
+
|
29
|
+
t.column :rate_avg, :float
|
30
|
+
t.column :rate_samples, :integer
|
31
|
+
t.column :rate_lo, :float
|
32
|
+
t.column :rate_hi, :float
|
33
|
+
t.column :rate_date_0, :float
|
34
|
+
t.column :rate_date_1, :float
|
35
|
+
|
36
|
+
t.column :date, :datetime, :null => false
|
37
|
+
t.column :date_0, :datetime
|
38
|
+
t.column :date_1, :datetime
|
39
|
+
|
40
|
+
t.column :derived, :string, :limit => 64
|
41
|
+
end
|
42
|
+
|
43
|
+
add_index table_name, :c1
|
44
|
+
add_index table_name, :c2
|
45
|
+
add_index table_name, :source
|
46
|
+
add_index table_name, :date
|
47
|
+
add_index table_name, :date_0
|
48
|
+
add_index table_name, :date_1
|
49
|
+
add_index table_name, [:c1, :c2, :source, :date_0, :date_1], :name => 'c1_c2_src_date_range', :unique => true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
# Initializes this object from a Currency::Exchange::Rate object.
|
55
|
+
def from_rate(rate)
|
56
|
+
self.c1 = rate.c1.code.to_s
|
57
|
+
self.c2 = rate.c2.code.to_s
|
58
|
+
self.rate = rate.rate
|
59
|
+
self.rate_avg = rate.rate_avg
|
60
|
+
self.rate_samples = rate.rate_samples
|
61
|
+
self.rate_lo = rate.rate_lo
|
62
|
+
self.rate_hi = rate.rate_hi
|
63
|
+
self.rate_date_0 = rate.rate_date_0
|
64
|
+
self.rate_date_1 = rate.rate_date_1
|
65
|
+
self.source = rate.source
|
66
|
+
self.derived = rate.derived
|
67
|
+
self.date = rate.date
|
68
|
+
self.date_0 = rate.date_0
|
69
|
+
self.date_1 = rate.date_1
|
70
|
+
self
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
# Convert all dates to localtime.
|
75
|
+
def dates_to_localtime!
|
76
|
+
self.date = self.date && self.date.clone.localtime
|
77
|
+
self.date_0 = self.date_0 && self.date_0.clone.localtime
|
78
|
+
self.date_1 = self.date_1 && self.date_1.clone.localtime
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
# Creates a new Currency::Exchange::Rate object.
|
83
|
+
def to_rate(cls = ::Currency::Exchange::Rate)
|
84
|
+
cls.
|
85
|
+
new(
|
86
|
+
::Currency::Currency.get(self.c1),
|
87
|
+
::Currency::Currency.get(self.c2),
|
88
|
+
self.rate,
|
89
|
+
"historical #{self.source}",
|
90
|
+
self.date,
|
91
|
+
self.derived,
|
92
|
+
{
|
93
|
+
:rate_avg => self.rate_avg,
|
94
|
+
:rate_samples => self.rate_samples,
|
95
|
+
:rate_lo => self.rate_lo,
|
96
|
+
:rate_hi => self.rate_hi,
|
97
|
+
:rate_date_0 => self.rate_date_0,
|
98
|
+
:rate_date_1 => self.rate_date_1,
|
99
|
+
:date_0 => self.date_0,
|
100
|
+
:date_1 => self.date_1
|
101
|
+
})
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
# Various defaults.
|
106
|
+
def before_validation
|
107
|
+
self.rate_avg = self.rate unless self.rate_avg
|
108
|
+
self.rate_samples = 1 unless self.rate_samples
|
109
|
+
self.rate_lo = self.rate unless self.rate_lo
|
110
|
+
self.rate_hi = self.rate unless self.rate_hi
|
111
|
+
self.rate_date_0 = self.rate unless self.rate_date_0
|
112
|
+
self.rate_date_1 = self.rate unless self.rate_date_1
|
113
|
+
|
114
|
+
#self.date_0 = self.date unless self.date_0
|
115
|
+
#self.date_1 = self.date unless self.date_1
|
116
|
+
self.date = self.date_0 + (self.date_1 - self.date_0) * 0.5 if ! self.date && self.date_0 && self.date_1
|
117
|
+
self.date = self.date_0 unless self.date
|
118
|
+
self.date = self.date_1 unless self.date
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
# Returns a ActiveRecord::Base#find :conditions value
|
123
|
+
# to locate any rates that will match this one.
|
124
|
+
#
|
125
|
+
# source may be a list of sources.
|
126
|
+
# date will match inside date_0 ... date_1 or exactly.
|
127
|
+
#
|
128
|
+
def find_matching_this_conditions
|
129
|
+
sql = [ ]
|
130
|
+
values = [ ]
|
131
|
+
|
132
|
+
if self.c1
|
133
|
+
sql << 'c1 = ?'
|
134
|
+
values.push(self.c1.to_s)
|
135
|
+
end
|
136
|
+
|
137
|
+
if self.c2
|
138
|
+
sql << 'c2 = ?'
|
139
|
+
values.push(self.c2.to_s)
|
140
|
+
end
|
141
|
+
|
142
|
+
if self.source
|
143
|
+
if self.source.kind_of?(Array)
|
144
|
+
sql << 'source IN ?'
|
145
|
+
else
|
146
|
+
sql << 'source = ?'
|
147
|
+
end
|
148
|
+
values.push(self.source)
|
149
|
+
end
|
150
|
+
|
151
|
+
if self.date
|
152
|
+
sql << '(((date_0 IS NULL) OR (date_0 <= ?)) AND ((date_1 IS NULL) OR (date_1 > ?))) OR date = ?'
|
153
|
+
values.push(self.date, self.date, self.date)
|
154
|
+
end
|
155
|
+
|
156
|
+
if self.date_0
|
157
|
+
sql << 'date_0 = ?'
|
158
|
+
values.push(self.date_0)
|
159
|
+
end
|
160
|
+
|
161
|
+
if self.date_1
|
162
|
+
sql << 'date_1 = ?'
|
163
|
+
values.push(self.date_1)
|
164
|
+
end
|
165
|
+
|
166
|
+
sql << '1 = 1' if sql.empty?
|
167
|
+
|
168
|
+
values.unshift(sql.collect{|x| "(#{x})"}.join(' AND '))
|
169
|
+
|
170
|
+
# $stderr.puts "values = #{values.inspect}"
|
171
|
+
|
172
|
+
values
|
173
|
+
end
|
174
|
+
|
175
|
+
|
176
|
+
# Shorthand.
|
177
|
+
def find_matching_this(opt1 = :all, *opts)
|
178
|
+
self.class.find(opt1, :conditions => find_matching_this_conditions, *opts)
|
179
|
+
end
|
180
|
+
|
181
|
+
end # class
|
182
|
+
|
183
|
+
|
184
|
+
|