class EuCentralBank

Constants

CURRENCIES
DECIMAL_PRECISION
ECB_90_DAY_URL
ECB_RATES_URL
SERIALIZER_DATE_SEPARATOR

Attributes

historical_last_updated[RW]
historical_rates_updated_at[RW]
last_updated[RW]
rates_updated_at[RW]

Public Class Methods

new(st = Money::RatesStore::StoreWithHistoricalDataSupport.new, &block) click to toggle source
Calls superclass method
# File lib/eu_central_bank.rb, line 23
def initialize(st = Money::RatesStore::StoreWithHistoricalDataSupport.new, &block)
  super
  @currency_string = nil
end

Public Instance Methods

check_currency_available(currency) click to toggle source
# File lib/eu_central_bank.rb, line 156
def check_currency_available(currency)
  currency_string = currency.to_s
  return true if currency_string == "EUR"
  return true if CURRENCIES.include?(currency_string)
  raise CurrencyUnavailable, "No rates available for #{currency_string}"
end
exchange(cents, from_currency, to_currency, date=nil) click to toggle source
# File lib/eu_central_bank.rb, line 52
def exchange(cents, from_currency, to_currency, date=nil)
  exchange_with(Money.new(cents, from_currency), to_currency, date)
end
exchange_with(from, to_currency, date=nil) click to toggle source
# File lib/eu_central_bank.rb, line 56
def exchange_with(from, to_currency, date=nil)
  from_base_rate, to_base_rate = nil, nil
  rate = get_rate(from.currency, to_currency, date)

  unless rate
    store.transaction true do
      from_base_rate = get_rate("EUR", from.currency.to_s, date)
      to_base_rate = get_rate("EUR", to_currency, date)
    end

    unless from_base_rate && to_base_rate
      message = "No conversion rate known for '#{from.currency.iso_code}' -> '#{to_currency}'"
      message << " on #{date.to_s}" if date

      raise Money::Bank::UnknownRate, message
    end

    rate = to_base_rate / from_base_rate
  end

  calculate_exchange(from, to_currency, rate)
end
export_rates(format, file = nil, opts = {}) click to toggle source
# File lib/eu_central_bank.rb, line 109
def export_rates(format, file = nil, opts = {})
  raise Money::Bank::UnknownRateFormat unless
    RATE_FORMATS.include? format

  store.transaction true do
    s = case format
    when :json
      JSON.dump(rates)
    when :ruby
      Marshal.dump(rates)
    when :yaml
      YAML.dump(rates)
    end

    unless file.nil?
      File.open(file, "w") {|f| f.write(s) }
    end

    s
  end
end
get_rate(from, to, date = nil) click to toggle source
# File lib/eu_central_bank.rb, line 79
def get_rate(from, to, date = nil)
  return 1 if from == to

  check_currency_available(from)
  check_currency_available(to)

  if date.is_a?(Hash)
    # Backwards compatibility for the opts hash
    date = date[:date]
  end

  store.get_rate(::Money::Currency.wrap(from).iso_code, ::Money::Currency.wrap(to).iso_code, date)
end
import_rates(format, s, opts = {}) click to toggle source
# File lib/eu_central_bank.rb, line 131
def import_rates(format, s, opts = {})
  raise Money::Bank::UnknownRateFormat unless
    RATE_FORMATS.include? format

  store.transaction true do
    data = case format
     when :json
       JSON.load(s)
     when :ruby
       Marshal.load(s)
     when :yaml
       YAML.load(s)
     end

    data.each do |key, rate|
      from, to = key.split(SERIALIZER_SEPARATOR)
      to, date = to.split(SERIALIZER_DATE_SEPARATOR)

      store.add_rate from, to, BigDecimal(rate, DECIMAL_PRECISION), date
    end
  end

  self
end
rates() click to toggle source
# File lib/eu_central_bank.rb, line 101
def rates
  store.each_rate.each_with_object({}) do |(from,to,rate,date),hash|
    key = [from, to].join(SERIALIZER_SEPARATOR)
    key = [key, date.to_s].join(SERIALIZER_DATE_SEPARATOR) if date
    hash[key] = rate
  end
end
save_rates(cache, url=ECB_RATES_URL) click to toggle source
# File lib/eu_central_bank.rb, line 36
def save_rates(cache, url=ECB_RATES_URL)
  raise InvalidCache unless cache
  File.open(cache, "w") do |file|
    io = open_url(url);
    io.each_line { |line| file.puts line }
  end
end
save_rates_to_s(url=ECB_RATES_URL) click to toggle source
# File lib/eu_central_bank.rb, line 48
def save_rates_to_s(url=ECB_RATES_URL)
  open_url(url).read
end
set_rate(from, to, rate, date = nil) click to toggle source
# File lib/eu_central_bank.rb, line 93
def set_rate(from, to, rate, date = nil)
  if date.is_a?(Hash)
    # Backwards compatibility for the opts hash
    date = date[:date]
  end
  store.add_rate(::Money::Currency.wrap(from).iso_code, ::Money::Currency.wrap(to).iso_code, rate, date)
end
update_historical_rates(cache=nil) click to toggle source
# File lib/eu_central_bank.rb, line 32
def update_historical_rates(cache=nil)
  update_parsed_historical_rates(doc(cache, ECB_90_DAY_URL))
end
update_rates(cache=nil, url=ECB_RATES_URL) click to toggle source
# File lib/eu_central_bank.rb, line 28
def update_rates(cache=nil, url=ECB_RATES_URL)
  update_parsed_rates(doc(cache, url))
end
update_rates_from_s(content) click to toggle source
# File lib/eu_central_bank.rb, line 44
def update_rates_from_s(content)
  update_parsed_rates(doc_from_s(content))
end

Protected Instance Methods

doc(cache, url=ECB_RATES_URL) click to toggle source
# File lib/eu_central_bank.rb, line 165
def doc(cache, url=ECB_RATES_URL)
  rates_source = !!cache ? cache : url
  Nokogiri::XML(open_url(rates_source)).tap { |doc| doc.xpath('gesmes:Envelope/xmlns:Cube/xmlns:Cube//xmlns:Cube') }
rescue Nokogiri::XML::XPath::SyntaxError
  Nokogiri::XML(open_url(url))
end
doc_from_s(content) click to toggle source
# File lib/eu_central_bank.rb, line 172
def doc_from_s(content)
  Nokogiri::XML(content)
end
update_parsed_historical_rates(doc) click to toggle source
# File lib/eu_central_bank.rb, line 194
def update_parsed_historical_rates(doc)
  rates = doc.xpath('gesmes:Envelope/xmlns:Cube/xmlns:Cube//xmlns:Cube')

  store.transaction true do
    rates.each do |exchange_rate|
      rate = BigDecimal(exchange_rate.attribute("rate").value, DECIMAL_PRECISION)
      currency = exchange_rate.attribute("currency").value
      date = exchange_rate.parent.attribute("time").value
      set_rate("EUR", currency, rate, date)
    end
  end

  rates_updated_at = doc.xpath('gesmes:Envelope/xmlns:Cube/xmlns:Cube/@time').first.value
  @historical_rates_updated_at = Time.parse(rates_updated_at)

  @historical_last_updated = Time.now
end
update_parsed_rates(doc) click to toggle source
# File lib/eu_central_bank.rb, line 176
def update_parsed_rates(doc)
  rates = doc.xpath('gesmes:Envelope/xmlns:Cube/xmlns:Cube//xmlns:Cube')

  store.transaction true do
    rates.each do |exchange_rate|
      rate = BigDecimal(exchange_rate.attribute("rate").value, DECIMAL_PRECISION)
      currency = exchange_rate.attribute("currency").value
      set_rate("EUR", currency, rate)
    end
    set_rate("EUR", "EUR", 1)
  end

  rates_updated_at = doc.xpath('gesmes:Envelope/xmlns:Cube/xmlns:Cube/@time').first.value
  @rates_updated_at = Time.parse(rates_updated_at)

  @last_updated = Time.now
end

Private Instance Methods

calculate_exchange(from, to_currency, rate) click to toggle source
# File lib/eu_central_bank.rb, line 214
def calculate_exchange(from, to_currency, rate)
  to_currency_money = Money::Currency.wrap(to_currency).subunit_to_unit
  from_currency_money = from.currency.subunit_to_unit
  decimal_money = BigDecimal(to_currency_money, DECIMAL_PRECISION) / BigDecimal(from_currency_money, DECIMAL_PRECISION)
  money = (decimal_money * from.cents * rate).round
  Money.new(money, to_currency)
end
open_url(url) click to toggle source
# File lib/eu_central_bank.rb, line 222
def open_url(url)
  if RUBY_VERSION >= '2.5.0'
    URI.open(url)
  else
    open(url)
  end
end