Class: Currency::Exchange::Rate::Source::Historical::Writer

Inherits:
Object
  • Object
show all
Defined in:
lib/currency/exchange/rate/source/historical/writer.rb

Overview

Responsible for writing historical rates from a rate source.

Defined Under Namespace

Classes: Error

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opt = { }) ⇒ Writer

Returns a new instance of Writer.



41
42
43
44
45
46
47
48
49
50
# File 'lib/currency/exchange/rate/source/historical/writer.rb', line 41

def initialize(opt = { })
  @all_rates = true
  @identity_rates = false
  @reciprocal_rates = true
  @preferred_currencies = nil
  @required_currencies = nil
  @base_currencies = nil
  @time_quantitizer = nil
  opt.each_pair{| k, v | self.send("#{k}=", v) }
end

Instance Attribute Details

#all_ratesObject

If true, compute all Rates between rates. This can be used to aid complex join reports that may assume c1 as the from currency and c2 as the to currency.



16
17
18
# File 'lib/currency/exchange/rate/source/historical/writer.rb', line 16

def all_rates
  @all_rates
end

#base_currenciesObject

If set, a list of required base currencies. base currencies must have rates as c1.



33
34
35
# File 'lib/currency/exchange/rate/source/historical/writer.rb', line 33

def base_currencies
  @base_currencies
end

#identity_ratesObject

If true, store identity rates. This can be used to aid complex join reports.



20
21
22
# File 'lib/currency/exchange/rate/source/historical/writer.rb', line 20

def identity_rates
  @identity_rates
end

#preferred_currenciesObject

If set, a set of preferred currencies.



26
27
28
# File 'lib/currency/exchange/rate/source/historical/writer.rb', line 26

def preferred_currencies
  @preferred_currencies
end

#reciprocal_ratesObject

If true, compute and store all reciprocal rates.



23
24
25
# File 'lib/currency/exchange/rate/source/historical/writer.rb', line 23

def reciprocal_rates
  @reciprocal_rates
end

#required_currenciesObject

If set, a list of required currencies.



29
30
31
# File 'lib/currency/exchange/rate/source/historical/writer.rb', line 29

def required_currencies
  @required_currencies
end

#sourceObject

The source of rates.



11
12
13
# File 'lib/currency/exchange/rate/source/historical/writer.rb', line 11

def source
  @source
end

#time_quantitizerObject

If set, use this time quantitizer to manipulate the Rate date_0 date_1 time ranges. If :default, use the TimeQuantitizer.default.



38
39
40
# File 'lib/currency/exchange/rate/source/historical/writer.rb', line 38

def time_quantitizer
  @time_quantitizer
end

Instance Method Details

#selected_ratesObject

Returns a list of selected rates from source.



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/currency/exchange/rate/source/historical/writer.rb', line 54

def selected_rates
  # Produce a list of all currencies.
  currencies = source.currencies

  # $stderr.puts "currencies = #{currencies.join(', ')}"

  selected_rates = [ ]

  # Get list of preferred_currencies.
  if self.preferred_currencies
    self.preferred_currencies = self.preferred_currencies.collect do | c | 
      ::Currency::Currency.get(c) 
    end
    currencies = currencies.select do | c | 
      self.preferred_currencies.include?(c)
    end.uniq
  end


  # Check for required currencies.
  if self.required_currencies
    self.required_currencies = self.required_currencies.collect do | c |
      ::Currency::Currency.get(c) 
    end

    self.required_currencies.each do | c |
      unless currencies.include?(c)
        raise ::Currency::Exception::MissingCurrency, 
        [ 
         "Required currency #{c.inspect} not in #{currencies.inspect}", 
         :currency, c, 
         :required_currency, currencies,
        ]
      end
    end
  end


  # $stderr.puts "currencies = #{currencies.inspect}"

  deriver = ::Currency::Exchange::Rate::Deriver.new(:source => source)

  # Produce Rates for all pairs of currencies.
  if all_rates
    currencies.each do | c1 |
      currencies.each do | c2 |
        next if c1 == c2 && ! identity_rates
         rate = deriver.rate(c1, c2, nil)
        selected_rates << rate unless selected_rates.include?(rate)
      end
    end
  elsif base_currencies
    base_currencies.each do | c1 |
      c1 = ::Currency::Currency.get(c1)
      currencies.each do | c2 |
        next if c1 == c2 && ! identity_rates
        rate = deriver.rate(c1, c2, nil)
        selected_rates << rate unless selected_rates.include?(rate)
      end
    end
  else
    selected_rates = source.rates.select do | r |
      next if r.c1 == r.c2 && ! identity_rates
      currencies.include?(r.c1) && currencies.include?(r.c2)
    end
  end

  if identity_rates
    currencies.each do | c1 |
      c1 = ::Currency::Currency.get(c1)
      c2 = c1
      rate = deriver.rate(c1, c2, nil)
      selected_rates << rate unless selected_rates.include?(rate)
    end
  else
    selected_rates = selected_rates.select do | r |
      r.c1 != r.c2
    end
  end

  if reciprocal_rates
    selected_rates.clone.each do | r |
      c1 = r.c2
      c2 = r.c1
      rate = deriver.rate(c1, c2, nil)
      selected_rates << rate unless selected_rates.include?(rate)
    end
  end

  # $stderr.puts "selected_rates = #{selected_rates.inspect}\n [#{selected_rates.size}]"

  selected_rates
end

#write_rates(rates = selected_rates) ⇒ Object

Returns an Array of Historical::Rate objects that were written. Avoids writing Rates that already have been written.



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/currency/exchange/rate/source/historical/writer.rb', line 151

def write_rates(rates = selected_rates)
 
  # Create Historical::Rate objects.
  h_rate_class = ::Currency::Exchange::Rate::Source::Historical::Rate

  # Most Rates from the same Source will probably have the same time,
  # so cache the computed date_range.
  date_range_cache = { } 
  rate_0 = nil
  if time_quantitizer = self.time_quantitizer
    time_quantitizer = ::Currency::Exchange::TimeQuantitizer.current if time_quantitizer == :current
  end

  h_rates = rates.collect do | r |
    rr = h_rate_class.new.from_rate(r)
    rr.dates_to_localtime!

    if rr.date && time_quantitizer
      date_range = date_range_cache[rr.date] ||= time_quantitizer.quantitize_time_range(rr.date)
      rr.date_0 = date_range.begin
      rr.date_1 = date_range.end
    end

    rate_0 ||= rr if rr.date_0 && rr.date_1

    rr
  end

  # Fix any dateless Rates.
  if rate_0
    h_rates.each do | rr |
      rr.date_0 = rate_0.date_0 unless rr.date_0
      rr.date_1 = rate_0.date_1 unless rr.date_1
    end
  end

  # Save them all or none.
  stored_h_rates = [ ] 
  h_rate_class.transaction do 
    h_rates.each do | rr |
      # Skip identity rates.
      next if rr.c1 == rr.c2 && ! identity_rates

      # Skip if already exists.
      existing_rate = rr.find_matching_this(:first)
      if existing_rate
        stored_h_rates << existing_rate # Already existed.
      else
        begin
          rr.save!
        rescue Object => err
          raise ::Currency::Exception::Generic, 
          [ 
           "During save of #{rr.inspect}", 
           :error, err,
          ]
        end
        stored_h_rates << rr # Written.
      end
    end
  end

  # Return written Historical::Rates.
  stored_h_rates
end