class Money::Bank::CurrencylayerHistoricalBank

CurrencylayerBank base class rubocop:disable Metrics/ClassLength

Constants

CL_HISTORICAL_URL

CurrencylayerBank historical url

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

cache[RW]

Cache accessor, can be a String or a Proc

historical_date[RW]

Fetch historical rates on selected date

rates[R]

Parsed CurrencylayerBank result as Hash

rates_expiration[R]

Rates expiration Time

secure_connection[RW]

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

ttl_in_seconds[R]

Seconds after than the current rates are automatically expired

Public Instance Methods

expire_rates!() click to toggle source

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

# File lib/money/bank/currencylayer_historical_bank.rb, line 137
def expire_rates!
  if expired?
    update_rates(true)
    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/currencylayer_historical_bank.rb, line 148
def expired?
  return true if historical_date
  rates_expiration ? rates_expiration <= Time.now : true
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/currencylayer_historical_bank.rb, line 103
def get_rate(from_currency, to_currency, opts = {}) # rubocop:disable all
  @historical_date = Date.parse(opts[:date].to_s).strftime("%Y-%m-%d") if opts[:date]
  expire_rates!
  rate = super
  unless rate
    # Tries to calculate an inverse rate
    inverse_rate = super(to_currency, from_currency, opts)
    if inverse_rate
      rate = 1.0 / inverse_rate
      add_rate(from_currency, to_currency, rate)
    end
  end
  unless rate
    # Tries to calculate a pair rate using base currency rate
    from_base_rate = super(source, from_currency, opts)
    unless from_base_rate
      from_inverse_rate = super(from_currency, source, opts)
      from_base_rate = 1.0 / from_inverse_rate if from_inverse_rate
    end
    to_base_rate = super(source, to_currency, opts)
    unless to_base_rate
      to_inverse_rate = super(to_currency, source, opts)
      to_base_rate = 1.0 / to_inverse_rate if to_inverse_rate
    end
    if to_base_rate && from_base_rate
      rate = to_base_rate / from_base_rate
      add_rate(from_currency, to_currency, rate)
    end
  end
  rate
end
rates_timestamp() click to toggle source

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

# File lib/money/bank/currencylayer_historical_bank.rb, line 172
def rates_timestamp
  @rates_timestamp ||= init_rates_timestamp
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/currencylayer_historical_bank.rb, line 67
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/currencylayer_historical_bank.rb, line 61
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/currencylayer_historical_bank.rb, line 156
def source_url
  raise NoAccessKey if access_key.nil? || access_key.empty?
  cl_url = historical_date ? CL_HISTORICAL_URL : CL_URL
  cl_url = CL_SECURE_URL if secure_connection

  base_url = "#{cl_url}?source=#{source}&access_key=#{access_key}"
  if historical_date
    date_url = "&date=#{historical_date}"
    base_url = base_url + date_url
  end

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

# File lib/money/bank/currencylayer_historical_bank.rb, line 80
def ttl_in_seconds=(value)
  @ttl_in_seconds = value
  refresh_rates_expiration!
  @ttl_in_seconds
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/currencylayer_historical_bank.rb, line 88
def update_rates(straight = false)
  exchange_rates(straight).each do |exchange_rate|
    currency = exchange_rate.first[3..-1]
    rate = exchange_rate.last
    next unless Money::Currency.find(currency)
    add_rate(source, currency, rate)
    add_rate(currency, source, 1.0 / rate)
  end
end

Protected Instance Methods

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/currencylayer_historical_bank.rb, line 268
def exchange_rates(straight = false)
  @rates = if straight
             raw_rates_straight['quotes']
           else
             raw_rates_careful['quotes']
           end
end
init_rates_timestamp(raw_rates = nil) click to toggle source

Sets the rates timestamp from parsed JSON content

@example

set_rates_timestamp("{\"timestamp\": 1441049528,
                      \"quotes\": {\"USDAED\": 3.67304}}")

@param raw_rates [String] parsed JSON content, default is nil @return [Time] time object with rates timestamp

# File lib/money/bank/currencylayer_historical_bank.rb, line 186
def init_rates_timestamp(raw_rates = nil)
  raw = raw_rates || raw_rates_careful
  @rates_timestamp = Time.at(raw['timestamp']) if raw.key?('timestamp')
end
open_url() click to toggle source

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

# File lib/money/bank/currencylayer_historical_bank.rb, line 242
def open_url
  open(source_url).read
end
raw_rates_careful() click to toggle source

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

# File lib/money/bank/currencylayer_historical_bank.rb, line 278
def raw_rates_careful
  JSON.parse(read_from_cache.to_s)
rescue JSON::ParserError
  raw_rates_straight
end
raw_rates_straight() click to toggle source

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

# File lib/money/bank/currencylayer_historical_bank.rb, line 286
def raw_rates_straight
  raw_rates = JSON.parse(read_from_url)
  init_rates_timestamp(raw_rates)
  raw_rates
rescue JSON::ParserError
  { 'quotes' => {} }
end
read_from_cache() click to toggle source

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

# File lib/money/bank/currencylayer_historical_bank.rb, line 220
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/currencylayer_historical_bank.rb, line 231
def read_from_url
  text = open_url
  if valid_rates?(text)
    refresh_rates_expiration!
    store_in_cache(text) if cache
  end
  text
end
refresh_rates_expiration!() click to toggle source

Refresh expiration from now return [Time] new expiration time

# File lib/money/bank/currencylayer_historical_bank.rb, line 296
def refresh_rates_expiration!
  @rates_expiration = Time.now + ttl_in_seconds unless ttl_in_seconds.nil?
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("{\"quotes\": {\"USDAED\": 3.67304}}")

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

# File lib/money/bank/currencylayer_historical_bank.rb, line 199
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?("{\"quotes\": {\"USDAED\": 3.67304}}")

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

# File lib/money/bank/currencylayer_historical_bank.rb, line 253
def valid_rates?(text)
  parsed = JSON.parse(text)
  parsed && parsed.key?('quotes')
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/currencylayer_historical_bank.rb, line 210
def write_to_file(text)
  open(cache, 'w') do |f|
    f.write(text)
  end
rescue Errno::ENOENT
  raise InvalidCache
end