class Money::Bank::OpenexchangeratesBank

CurrencylayerBank base class

Constants

CL_SECURE_URL

CurrencylayerBank secure url

CL_SOURCE

Default base currency

CL_URL

CurrencylayerBank url

Attributes

access_key[RW]

API must have a valid access_key

@param value [String] API access key @return [String] chosen API access key

cache[RW]

Cache accessor, can be a String or a Proc

@param value [String,Pathname,Proc] cache system @return [String,Pathname,Proc] chosen cache system

rates[R]

Parsed CurrencylayerBank result as Hash

rates_mem_timestamp[R]

Get the timestamp of rates in memory @return [Time] time object or nil

secure_connection[RW]

Use https to fetch rates from CurrencylayerBank CurrencylayerBank only allows http as connection for the free plan users.

@param value [Boolean] true for secure connection @return [Boolean] chosen secure connection

ttl_in_seconds[W]

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] chosen time to live in seconds

Public Instance Methods

add_rate(from_currency, to_currency, rate) click to toggle source

Override Money `add_rate` method for caching @param [String] from_currency Currency ISO code. ex. 'USD' @param [String] to_currency Currency ISO code. ex. 'CAD' @param [Numeric] rate Rate to use when exchanging currencies. @return [Numeric] rate.

Calls superclass method
# File lib/money/bank/openexchangerates_bank.rb, line 147
def add_rate(from_currency, to_currency, rate)
  super
end
alternatives() click to toggle source

Get alternative system. Default is nil @return [String,nil] chosen alternative system

# File lib/money/bank/openexchangerates_bank.rb, line 116
def alternatives
  @alternatives || nil
end
alternatives=(system) click to toggle source

Set alternative system, to request alternative rates

@example

alternatives = :all
alternatives = :only
alternatives = nil

@param value [String,Symbol] alternatives @return [String,nil] chosen alternative system

# File lib/money/bank/openexchangerates_bank.rb, line 105
def alternatives=(system)
  @alternatives = case system.to_sym
                  when :all
                    'show_alternative'
                  when :only
                    'only_alternative'
                  end
end
expire_rates!() click to toggle source

Fetch new rates if cached rates are expired or stale @return [Boolean] true if rates are expired and updated from remote

# File lib/money/bank/openexchangerates_bank.rb, line 167
def expire_rates!
  if expired?
    update_rates(true)
    true
  elsif stale?
    update_rates
    true
  else
    false
  end
end
expired?() click to toggle source

Check if rates are expired @return [Boolean] true if rates are expired

# File lib/money/bank/openexchangerates_bank.rb, line 181
def expired?
  Time.now > 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' @param [Hash] opts Options hash to set special parameters. @return [Numeric] rate.

# File lib/money/bank/openexchangerates_bank.rb, line 159
def get_rate(from_currency, to_currency, opts = {})
  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
rates_expiration() click to toggle source

Get rates expiration time based on ttl @return [Time] rates expiration time

# File lib/money/bank/openexchangerates_bank.rb, line 207
def rates_expiration
  rates_timestamp + ttl_in_seconds
end
rates_timestamp() click to toggle source

Get the timestamp of rates @return [Time] time object or nil

# File lib/money/bank/openexchangerates_bank.rb, line 213
def rates_timestamp
  raw = raw_rates_careful
  raw.key?('timestamp') ? Time.at(raw['timestamp']) : Time.at(0)
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/openexchangerates_bank.rb, line 92
def source
  @source ||= CL_SOURCE
end
source=(value) click to toggle source

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

@example

source = 'USD'

@param value [String] Currency code, ISO 3166-1 alpha-3 @return [String] chosen base currency

# File lib/money/bank/openexchangerates_bank.rb, line 86
def source=(value)
  @source = Money::Currency.find(value.to_s).try(:iso_code) || CL_SOURCE
end
source_url() click to toggle source

Source url of CurrencylayerBank defined with access_key and secure_connection @return [String] the remote API url

# File lib/money/bank/openexchangerates_bank.rb, line 196
def source_url
  raise NoAccessKey if access_key.nil? || access_key.empty?
  cl_url = CL_URL
  cl_url = CL_SECURE_URL if secure_connection
  params = "#{cl_url}?base=#{source}&app_id=#{access_key}&prettyprint=0"
  params += "&#{alternatives}=1" unless alternatives.nil?
  params
end
stale?() click to toggle source

Check if rates are stale Stale is true if rates are updated straight by another thread. The actual thread has always old rates in memory store. @return [Boolean] true if rates are stale

# File lib/money/bank/openexchangerates_bank.rb, line 189
def stale?
  rates_timestamp != rates_mem_timestamp
end
super_get_rate(from_currency, to_currency, opts = {})

Alias super method

Alias for: get_rate
ttl_in_seconds() click to toggle source

Get the seconds after than the current rates are automatically expired by default, they never expire. @return [Integer] chosen time to live in seconds

# File lib/money/bank/openexchangerates_bank.rb, line 123
def ttl_in_seconds
  @ttl_in_seconds ||= 0
end
update_rates(straight = false) click to toggle source

Update all rates from CurrencylayerBank JSON @return [Array] array of exchange rates

# File lib/money/bank/openexchangerates_bank.rb, line 129
def update_rates(straight = false)
  store.reset!
  rates = exchange_rates(straight).each do |exchange_rate|
    currency = exchange_rate.first
    rate = exchange_rate.last
    next unless Money::Currency.find(currency)
    add_rate(source, currency, rate)
    add_rate(currency, source, 1.0 / rate)
  end
  @rates_mem_timestamp = rates_timestamp
  rates
end

Protected Instance Methods

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/openexchangerates_bank.rb, line 342
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)
  if to_base_rate && from_base_rate
    rate = to_base_rate / from_base_rate
    add_rate(from_currency, to_currency, rate)
    return rate
  end
  nil
end
exchange_rates(straight = false) click to toggle source

Get exchange rates with different strategies

@example

exchange_rates(true)
exchange_rates

@param straight [Boolean] true for straight, default is careful @return [Hash] key is country code (ISO 3166-1 alpha-3) value Float

# File lib/money/bank/openexchangerates_bank.rb, line 296
def exchange_rates(straight = false)
  @rates = if straight
             raw_rates_straight['rates']
           else
             raw_rates_careful['rates']
           end
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/openexchangerates_bank.rb, line 325
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
open_url() click to toggle source

Opens an url and reads the content @return [String] unparsed JSON content

# File lib/money/bank/openexchangerates_bank.rb, line 268
def open_url
  URI.open(source_url).read
rescue OpenURI::HTTPError
  ''
end
raw_rates_careful(rescue_straight = true) click to toggle source

Get raw exchange rates from cache and then from url @param rescue_straight [Boolean] true for rescue straight, default true @return [String] JSON content

# File lib/money/bank/openexchangerates_bank.rb, line 307
def raw_rates_careful(rescue_straight = true)
  JSON.parse(read_from_cache.to_s)
rescue JSON::ParserError
  rescue_straight ? raw_rates_straight : { 'rates' => {} }
end
raw_rates_straight() click to toggle source

Get raw exchange rates from url @return [String] JSON content

# File lib/money/bank/openexchangerates_bank.rb, line 315
def raw_rates_straight
  JSON.parse(read_from_url)
rescue JSON::ParserError
  raw_rates_careful(false)
end
read_from_cache() click to toggle source

Read from cache when exist @return [Proc,String] parsed JSON content

# File lib/money/bank/openexchangerates_bank.rb, line 249
def read_from_cache
  if cache.is_a?(Proc)
    cache.call(nil)
  elsif (cache.is_a?(String) || cache.is_a?(Pathname)) &&
        File.exist?(cache)
    open(cache).read
  end
end
read_from_url() click to toggle source

Get remote content and store in cache @return [String] unparsed JSON content

# File lib/money/bank/openexchangerates_bank.rb, line 260
def read_from_url
  text = open_url
  store_in_cache(text) if valid_rates?(text) && cache
  text
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.

@example

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

@param text [String] parsed JSON content @return [String,Integer]

# File lib/money/bank/openexchangerates_bank.rb, line 228
def store_in_cache(text)
  if cache.is_a?(Proc)
    cache.call(text)
  elsif cache.is_a?(String) || cache.is_a?(Pathname)
    write_to_file(text)
  end
end
valid_rates?(text) click to toggle source

Check validity of rates response only for store in cache

@example

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

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

# File lib/money/bank/openexchangerates_bank.rb, line 281
def valid_rates?(text)
  parsed = JSON.parse(text)
  parsed && parsed.key?('rates')
rescue JSON::ParserError
  false
end
write_to_file(text) click to toggle source

Writes content to file cache @param text [String] parsed JSON content @return [String,Integer]

# File lib/money/bank/openexchangerates_bank.rb, line 239
def write_to_file(text)
  open(cache, 'w') do |f|
    f.write(text)
  end
rescue Errno::ENOENT
  raise InvalidCache
end