class Money::Bank::OpenExchangeRatesBank

OpenExchangeRatesBank base class

Constants

BASE_URL
OER_HISTORICAL_URL
OER_URL

OpenExchangeRates urls

OE_SOURCE

Default base currency “base”: “USD”

RATES_KEY
TIMESTAMP_KEY
VERSION

Attributes

app_id[RW]

As of the end of August 2012 all requests to the Open Exchange Rates API must have a valid app_id see docs.openexchangerates.org/docs/authentication

@example

oxr.app_id = 'YOUR_APP_APP_ID'

@param [String] token to access OXR API @return [String] token to access OXR API

cache[RW]

Cache accessor

@example

oxr.cache = 'path/to/file/cache.json'

@param [String,Proc] for a String a filepath @return [String,Proc] for a String a filepath

date[RW]

Date for historical api see docs.openexchangerates.org/docs/historical-json

@example

oxr.date = '2015-01-01'

@param [String] The requested date in YYYY-MM-DD format @return [String] The requested date in YYYY-MM-DD format

force_refresh_rate_on_expire[RW]

Force refresh rates cache and store on the fly when ttl is expired This will slow down request on get_rate, so use at your on risk, if you don’t want to setup crontab/worker/scheduler for your application

@param [Boolean]

json_response[R]

Unparsed OpenExchangeRates response as String

@return [String] OpenExchangeRates json response

oer_rates[R]

Parsed OpenExchangeRates result as Hash

@return [Hash] All rates as Hash

prettyprint[W]

Minified Response (‘prettyprint’) see docs.openexchangerates.org/docs/prettyprint @example

oxr.prettyprint = false

@param [Boolean] Set to false to receive minified (default: true) @return [Boolean]

rates_expiration[R]

Rates expiration Time

@return [Time] expiration time

show_alternative[W]

Set support for the black market and alternative digital currencies see docs.openexchangerates.org/docs/alternative-currencies @example

oxr.show_alternative = true

@param [Boolean] if true show alternative @return [Boolean] Setted show alternative

symbols[W]

Filter response to a list of symbols see docs.openexchangerates.org/docs/get-specific-currencies @example

oxr.symbols = [:usd, :cad]

@param [Array] list of symbols @return [Array] Setted list of symbols

ttl_in_seconds[R]

Seconds after than the current rates are automatically expired

@return [Integer] Setted time to live in seconds

Public Instance Methods

expire_rates() click to toggle source

Expire rates when expired

@return [NilClass, Time] nil if not expired or new expiration time

# File lib/money/bank/open_exchange_rates_bank.rb, line 231
def expire_rates
  return unless ttl_in_seconds
  return if rates_expiration > Time.now

  refresh_rates if force_refresh_rate_on_expire
  update_rates
  refresh_rates_expiration
end
get_rate(from_currency, to_currency, opts = {}) click to toggle source

Override Money ‘get_rate` method for caching

@param [String] from_currency Currency ISO code. ex. ‘USD’ @param [String] to_currency Currency ISO code. ex. ‘CAD’

@return [Numeric] rate.

Calls superclass method
# File lib/money/bank/open_exchange_rates_bank.rb, line 211
def get_rate(from_currency, to_currency, opts = {})
  super if opts[:call_super]
  expire_rates
  rate = get_rate_or_calc_inverse(from_currency, to_currency, opts)
  rate || calc_pair_rate_using_base(from_currency, to_currency, opts)
end
Also aliased as: super_get_rate
prettyprint() click to toggle source

Get prettyprint option

@return [Boolean]

# File lib/money/bank/open_exchange_rates_bank.rb, line 250
def prettyprint
  return true unless defined? @prettyprint
  return true if @prettyprint.nil?

  @prettyprint
end
rates_timestamp() click to toggle source

Current rates timestamp

@return [Time]

# File lib/money/bank/open_exchange_rates_bank.rb, line 140
def rates_timestamp
  @rates_timestamp || Time.now
end
rates_timestamp=(at) click to toggle source

Set current rates timestamp

@return [Time]

# File lib/money/bank/open_exchange_rates_bank.rb, line 133
def rates_timestamp=(at)
  @rates_timestamp = Time.at(at)
end
refresh_rates() click to toggle source

Fetch from url and save cache

@return [Array] Array of exchange rates

# File lib/money/bank/open_exchange_rates_bank.rb, line 221
def refresh_rates
  read_from_url
end
Also aliased as: save_rates
save_rates()

Alias refresh_rates method

Alias for: refresh_rates
show_alternative() click to toggle source

Get show alternative

@return [Boolean] if true show alternative

# File lib/money/bank/open_exchange_rates_bank.rb, line 243
def show_alternative
  @show_alternative ||= false
end
source() click to toggle source

Get the base currency for all rates. By default, USD is used.

@return [String] base currency

# File lib/money/bank/open_exchange_rates_bank.rb, line 181
def source
  @source ||= OE_SOURCE
end
source=(value) click to toggle source

Set the base currency for all rates. By default, USD is used. OpenExchangeRates only allows USD as base currency for the free plan users.

@example

oxr.source = 'USD'

@param value [String] Currency code, ISO 3166-1 alpha-3

@return [String] chosen base currency

# File lib/money/bank/open_exchange_rates_bank.rb, line 169
def source=(value)
  scurrency = Money::Currency.find(value.to_s)
  @source = if scurrency
              scurrency.iso_code
            else
              OE_SOURCE
            end
end
source_url() click to toggle source

Source url of openexchangerates defined with app_id

@return [String] URL

# File lib/money/bank/open_exchange_rates_bank.rb, line 268
def source_url
  str = "#{oer_url}?app_id=#{app_id}"
  str = "#{str}&base=#{source}" unless source == OE_SOURCE
  str = "#{str}&show_alternative=#{show_alternative}"
  str = "#{str}&prettyprint=#{prettyprint}"
  str = "#{str}&symbols=#{symbols.join(',')}" if symbols&.is_a?(Array)
  str
end
super_get_rate(from_currency, to_currency, opts = {})

Alias super method

Alias for: get_rate
symbols() click to toggle source

Get symbols

@return [Array] list of symbols to filter by

# File lib/money/bank/open_exchange_rates_bank.rb, line 260
def symbols
  @symbols ||= nil
end
ttl_in_seconds=(value) click to toggle source

Set the seconds after than the current rates are automatically expired by default, they never expire.

@example

ttl_in_seconds = 86400 # will expire the rates in one day

@param value [Integer] Time to live in seconds

@return [Integer] Setted time to live in seconds

# File lib/money/bank/open_exchange_rates_bank.rb, line 153
def ttl_in_seconds=(value)
  @ttl_in_seconds = value
  refresh_rates_expiration if ttl_in_seconds
  ttl_in_seconds
end
update_rates() click to toggle source

Update all rates from openexchangerates JSON

@return [Array] Array of exchange rates

# File lib/money/bank/open_exchange_rates_bank.rb, line 188
def update_rates
  store.transaction do
    clear_rates!
    exchange_rates.each do |exchange_rate|
      rate = exchange_rate.last
      currency = exchange_rate.first
      next unless Money::Currency.find(currency)

      set_rate(source, currency, rate)
      set_rate(currency, source, 1.0 / rate)
    end
  end
end

Protected Instance Methods

api_response() click to toggle source

Read API

@return [String]

# File lib/money/bank/open_exchange_rates_bank.rb, line 350
def api_response
  Net::HTTP.get(URI(source_url))
end
calc_pair_rate_using_base(from_currency, to_currency, opts) click to toggle source

Tries to calculate a pair rate using base currency rate

@param [String] from_currency Currency ISO code. ex. ‘USD’ @param [String] to_currency Currency ISO code. ex. ‘CAD’

@return [Numeric] rate or nil if cannot calculate rate.

# File lib/money/bank/open_exchange_rates_bank.rb, line 426
def calc_pair_rate_using_base(from_currency, to_currency, opts)
  from_base_rate = get_rate_or_calc_inverse(source, from_currency, opts)
  to_base_rate   = get_rate_or_calc_inverse(source, to_currency, opts)
  return unless to_base_rate
  return unless from_base_rate

  rate = BigDecimal(to_base_rate.to_s) / from_base_rate
  add_rate(from_currency, to_currency, rate)
  rate
end
clear_rates!() click to toggle source

Clears cached rates in store

@return [Hash] All rates from store as Hash

# File lib/money/bank/open_exchange_rates_bank.rb, line 440
def clear_rates!
  store.each_rate do |iso_from, iso_to|
    add_rate(iso_from, iso_to, nil)
  end
end
exchange_rates() click to toggle source

Get expire rates, first from cache and then from url

@return [Hash] key is country code (ISO 3166-1 alpha-3) value Float

# File lib/money/bank/open_exchange_rates_bank.rb, line 384
def exchange_rates
  doc = JSON.parse(read_from_cache || read_from_url)
  if doc['error'] && ERROR_MAP.key?(doc['message'].to_sym)
    raise ERROR_MAP[doc['message'].to_sym]
  end

  self.rates_timestamp = doc[TIMESTAMP_KEY]
  @oer_rates = doc[RATES_KEY]
end
get_rate_or_calc_inverse(from_currency, to_currency, opts = {}) click to toggle source

Get rate or calculate it as inverse rate

@param [String] from_currency Currency ISO code. ex. ‘USD’ @param [String] to_currency Currency ISO code. ex. ‘CAD’

@return [Numeric] rate or rate calculated as inverse rate.

# File lib/money/bank/open_exchange_rates_bank.rb, line 407
def get_rate_or_calc_inverse(from_currency, to_currency, opts = {})
  rate = super_get_rate(from_currency, to_currency, opts)
  unless rate
    # Tries to calculate an inverse rate
    inverse_rate = super_get_rate(to_currency, from_currency, opts)
    if inverse_rate
      rate = 1.0 / inverse_rate
      add_rate(from_currency, to_currency, rate)
    end
  end
  rate
end
historical_url() click to toggle source

Historical url generated from ‘date` attr_accessor

@return [String] URL

# File lib/money/bank/open_exchange_rates_bank.rb, line 303
def historical_url
  URI.join(OER_HISTORICAL_URL, "#{date}.json")
end
latest_url() click to toggle source

Latest url

@return [String] URL

# File lib/money/bank/open_exchange_rates_bank.rb, line 310
def latest_url
  OER_URL
end
oer_url() click to toggle source

Latest url if no date given

@return [String] URL

# File lib/money/bank/open_exchange_rates_bank.rb, line 292
def oer_url
  if date
    historical_url
  else
    latest_url
  end
end
read_from_cache() click to toggle source

Read from cache when exist

@return [String] Raw string from file or cache proc

# File lib/money/bank/open_exchange_rates_bank.rb, line 338
def read_from_cache
  result = if cache.is_a?(Proc)
             cache.call(nil)
           elsif File.exist?(cache.to_s)
             File.read(cache)
           end
  result if valid_rates?(result)
end
read_from_url() click to toggle source

Read from url

@return [String] JSON content

# File lib/money/bank/open_exchange_rates_bank.rb, line 357
def read_from_url
  raise NoAppId if app_id.nil? || app_id.empty?

  @json_response = api_response
  save_cache if cache
  @json_response
end
refresh_rates_expiration() click to toggle source

Refresh expiration from now

@return [Time] new expiration time

# File lib/money/bank/open_exchange_rates_bank.rb, line 397
def refresh_rates_expiration
  @rates_expiration = rates_timestamp + ttl_in_seconds
end
save_cache() click to toggle source

Save rates on cache Can raise InvalidCache

@return [Proc,File]

# File lib/money/bank/open_exchange_rates_bank.rb, line 283
def save_cache
  store_in_cache(@json_response) if valid_rates?(@json_response)
rescue Errno::ENOENT
  raise InvalidCache
end
store_in_cache(text) click to toggle source

Store the provided text data by calling the proc method provided for the cache, or write to the cache file. Can raise InvalidCache

@example

oxr.store_in_cache("{\"rates\": {\"AED\": 3.67304}}")

@param text [String] String to cache @return [String,Integer]

# File lib/money/bank/open_exchange_rates_bank.rb, line 323
def store_in_cache(text)
  if cache.is_a?(Proc)
    cache.call(text)
  elsif cache.is_a?(String) || cache.is_a?(Pathname)
    File.open(cache.to_s, 'w') do |f|
      f.write(text)
    end
  else
    raise InvalidCache
  end
end
valid_rates?(text) click to toggle source

Check validity of rates response only for store in cache

@example

oxr.valid_rates?("{\"rates\": {\"AED\": 3.67304}}")

@param [String] text is JSON content @return [Boolean] valid or not

# File lib/money/bank/open_exchange_rates_bank.rb, line 372
def valid_rates?(text)
  return false unless text

  parsed = JSON.parse(text)
  parsed&.key?(RATES_KEY) && parsed&.key?(TIMESTAMP_KEY)
rescue JSON::ParserError
  false
end