class MoneyOXR::RatesStore

Attributes

app_id[R]
cache_path[R]
last_updated_at[R]
max_age[R]
on_api_failure[R]
source[R]

Public Class Methods

new(*) click to toggle source
Calls superclass method
# File lib/money_oxr/rates_store.rb, line 11
def initialize(*)
  super
  @app_id = options[:app_id]
  @source = options[:source] || 'USD'
  @cache_path = options[:cache_path]
  @max_age = options[:max_age]
  @on_api_failure = options[:on_api_failure] || :warn
end

Public Instance Methods

api_uri() click to toggle source
# File lib/money_oxr/rates_store.rb, line 84
def api_uri
  "https://openexchangerates.org/api/latest.json?base=#{source}&app_id=#{app_id}"
end
get_json_from_api() click to toggle source
# File lib/money_oxr/rates_store.rb, line 76
def get_json_from_api
  URI.open(api_uri).read
rescue OpenURI::HTTPError, SocketError
  raise unless on_api_failure == :warn
  warn "#{$!.class}: #{$!.message}"
  nil
end
get_rate(iso_from, iso_to) click to toggle source
Calls superclass method
# File lib/money_oxr/rates_store.rb, line 20
def get_rate(iso_from, iso_to)
  load
  super || begin
    if iso_from == source
      nil
    elsif inverse_rate = super(iso_to, iso_from)
      add_rate(iso_from, iso_to, 1 / inverse_rate)
    elsif iso_to == source
      nil
    else
      rate1 = get_rate(iso_from, source)
      rate2 = get_rate(source, iso_to)
      rate1 && rate2 && add_rate(iso_from, iso_to, rate1 * rate2)
    end
  end
end
load() click to toggle source
# File lib/money_oxr/rates_store.rb, line 43
def load
  # Loads data and ensures it is not stale.
  if !loaded? && cache_path && File.exist?(cache_path)
    load_from_cache_path
  end
  if app_id && (!loaded? || stale?)
    load_from_api
  end
end
load_from_api() click to toggle source
# File lib/money_oxr/rates_store.rb, line 59
def load_from_api
  # When loading from the API, set the last_updated_at to now.
  # "timestamp" value in response may be days old (it may not update over
  # the weekend)
  now = Time.now
  json = get_json_from_api
  # Protect against saving or loading nil/bad data from API.
  return unless json && json =~ /rates/
  if cache_path
    write_cache_file(json)
    load_from_cache_path
  else
    load_json(json)
  end
  @last_updated_at = now
end
load_from_cache_path() click to toggle source
# File lib/money_oxr/rates_store.rb, line 88
def load_from_cache_path
  load_json(File.read(cache_path))
end
load_json(text) click to toggle source
# File lib/money_oxr/rates_store.rb, line 96
def load_json(text)
  data = parse_json(text)
  transaction do
    @last_updated_at = Time.at(data['timestamp'])
    rates.clear
    data['rates'].each do |iso_to, rate|
      add_rate(source, iso_to, rate)
    end
  end
end
loaded?() click to toggle source
# File lib/money_oxr/rates_store.rb, line 37
def loaded?
  transaction do
    rates.any?
  end
end
parse_json(text) click to toggle source
# File lib/money_oxr/rates_store.rb, line 107
def parse_json(text)
  # Convert text to strings so that we can use BigDecimal instead of Float
  text = text.gsub(/("[A-Z]{3}": ?)(\d+\.\d+)/, '\\1"\\2"')
  data = JSON.parse(text)
  data['rates'] = data['rates'].each_with_object({}) do |(key, value), rates|
    rates[key] = BigDecimal(value)
  end
  data
end
stale?() click to toggle source
# File lib/money_oxr/rates_store.rb, line 53
def stale?
  return false if !max_age
  return true if last_updated_at.nil?
  last_updated_at + max_age < Time.now
end
write_cache_file(text) click to toggle source
# File lib/money_oxr/rates_store.rb, line 92
def write_cache_file(text)
  File.open(cache_path, 'w') { |file| file.write text }
end