class Money::Bank::Currencylayer

Money::Bank implementation that gives access to the current exchange rates using jsonrates.com api.

Constants

SERVICE_HOST

Host of service jsonrates

SERVICE_PATH

Relative path of jsonrates api

Attributes

rates_careful[R]

@return [Boolean] Returns is Rates Careful mode set.

rates_expiration[R]

@return [Time] Returns the time when the rates expire.

ttl_in_seconds[R]

@return [Integer] Returns the Time To Live (TTL) in seconds.

access_key[RW]

accessor of access_key of jsonrates.com service

rates[R]

@return [Hash] Stores the currently known rates.

Public Class Methods

rates_careful=(value) click to toggle source

Set Rates Careful mode

@param [Boolean] value - mode Careful, if set - don’t reload cache if get some exception

# File lib/money/bank/currencylayer.rb, line 51
def rates_careful= value
  @rates_careful = !!value
end
refresh_rates_expiration!() click to toggle source

Set the rates expiration TTL seconds from the current time.

@return [Time] The next expiration.

# File lib/money/bank/currencylayer.rb, line 68
def refresh_rates_expiration!
  @rates_expiration = Time.now + ttl_in_seconds
end
ttl_in_seconds=(value) click to toggle source

Set the Time To Live (TTL) in seconds.

@param [Integer] value - the seconds between an expiration and another.

# File lib/money/bank/currencylayer.rb, line 59
def ttl_in_seconds= value
  @ttl_in_seconds = value
  refresh_rates_expiration! if ttl_in_seconds
end

Public Instance Methods

add_rate(from, to, rate) click to toggle source

Registers a conversion rate and returns it (uses #set_rate).

@param [Currency, String, Symbol] from Currency to exchange from. @param [Currency, String, Symbol] to Currency to exchange to. @param [Numeric] rate Rate to use when exchanging currencies.

@return [Numeric]

@example

bank = Money::Bank::Currencylayer.new  #=> <Money::Bank::Currencylayer...>
bank.add_rate("USD", "CAD", 1.24515)  #=> 1.24515
bank.add_rate("CAD", "USD", 0.803115)  #=> 0.803115
# File lib/money/bank/currencylayer.rb, line 142
def add_rate from, to, rate
  set_rate from, to, rate
end
expire_rates() click to toggle source

Flushes all the rates if they are expired.

@return [Boolean]

# File lib/money/bank/currencylayer.rb, line 193
def expire_rates
  if expired?
    flush_rates
    self.class.refresh_rates_expiration!
    true
  else
    false
  end
end
flush_rate(from, to) click to toggle source

Clears the specified rate stored in @rates.

@param [String, Symbol, Currency] from Currency to convert from (used

for key into @rates).

@param [String, Symbol, Currency] to Currency to convert to (used for

key into @rates).

@return [Float] The flushed rate.

@example

bank = Money::Bank::Currencylayer.new    #=> <Money::Bank::Currencylayer...>
bank.get_rate(:USD, :EUR)    #=> 0.776337241
bank.flush_rate(:USD, :EUR)  #=> 0.776337241
# File lib/money/bank/currencylayer.rb, line 102
def flush_rate(from, to)
  key = rate_key_for(from, to)
  @mutex.synchronize{
    @rates.delete(key)
  }
end
flush_rates() click to toggle source

Clears all rates stored in @rates

@return [Hash] The empty @rates Hash.

@example

bank = Money::Bank::Currencylayer.new  #=> <Money::Bank::Currencylayer...>
bank.get_rate(:USD, :EUR)  #=> 0.776337241
bank.flush_rates           #=> {}
# File lib/money/bank/currencylayer.rb, line 82
def flush_rates
  @mutex.synchronize{
    @rates = {}
  }
end
get_rate(from, to) click to toggle source

Returns the requested rate.

It uses #get_rate_careful or #get_rate_straight respect of @rates_careful value

@param [String, Symbol, Currency] from Currency to convert from @param [String, Symbol, Currency] to Currency to convert to

@return [Float] The requested rate.

@example

bank = Money::Bank::Currencylayer.new  #=> <Money::Bank::Currencylayer...>
bank.get_rate(:USD, :EUR)  #=> 0.776337241
# File lib/money/bank/currencylayer.rb, line 122
def get_rate(from, to)
  if self.class.rates_careful
    get_rate_careful(from, to)
  else
    get_rate_straight(from, to)
  end
end
rate_key_for(from, to) click to toggle source

Return the rate hashkey for the given currencies.

@param [Currency, String, Symbol] from The currency to exchange from. @param [Currency, String, Symbol] to The currency to exchange to.

@return [String]

@example

rate_key_for("USD", "CAD") #=> "USD_TO_CAD"
Money::Bank::Currencylayer.rates_careful = true
rate_key_for("USD", "CAD") #=> "USD_TO_CAD_C"
Calls superclass method
# File lib/money/bank/currencylayer.rb, line 181
def rate_key_for(from, to)
  if self.class.rates_careful
    "#{Currency.wrap(from).iso_code}_TO_#{Currency.wrap(to).iso_code}_C".upcase
  else
    super
  end
end
set_rate(from, to, rate) click to toggle source

Set the rate for the given currencies. Uses Mutex to synchronize data access.

@param [Currency, String, Symbol] from Currency to exchange from. @param [Currency, String, Symbol] to Currency to exchange to. @param [Numeric] rate Rate to use when exchanging currencies. @param [Hash] opts Options hash to set special parameters @option opts [Boolean] :without_mutex disables the usage of a mutex

@return [Numeric]

@example

@bank = Money::Bank::Currencylayer.new  #=> <Money::Bank::Currencylayer...>
bank.set_rate("USD", "CAD", 1.24515)  #=> 1.24515
bank.set_rate("CAD", "USD", 0.803115)  #=> 0.803115
Calls superclass method
# File lib/money/bank/currencylayer.rb, line 161
def set_rate from, to, rate
  if self.class.rates_careful
    set_rate_with_time(from, to, rate)
  else
    super
  end
end

Private Instance Methods

add_rate_with_time(from, to, rate) click to toggle source

Registers a conversion rate with created_at and returns it (uses #set_rate_with_time).

@param [Currency, String, Symbol] from Currency to exchange from. @param [Currency, String, Symbol] to Currency to exchange to. @param [Numeric] rate Rate to use when exchanging currencies.

@return [Numeric]

# File lib/money/bank/currencylayer.rb, line 268
def add_rate_with_time(from, to, rate)
  set_rate_with_time(from, to, rate)
end
build_uri(from, to) click to toggle source

Build a URI for the given arguments.

@param [Currency] from The currency to convert from. @param [Currency] to The currency to convert to.

@return [URI::HTTP]

# File lib/money/bank/currencylayer.rb, line 333
def build_uri(from, to)
  raise AccessError if access_key.nil? || access_key.empty?
  uri = URI::HTTP.build(
    :host  => SERVICE_HOST,
    :path  => SERVICE_PATH,
    :query => "access_key=#{access_key}&source=#{from}&currencies=#{to}"
  )
end
expired?() click to toggle source

Returns whether the time expired.

@return [Boolean]

# File lib/money/bank/currencylayer.rb, line 209
def expired?
  self.class.ttl_in_seconds && self.class.rates_expiration <= Time.now
end
expired_time?(time) click to toggle source

Check if time is expired

@param [Time] time Time to check

@return [Boolean] Is the time expired.

# File lib/money/bank/currencylayer.rb, line 296
def expired_time? time
  time + self.class.ttl_in_seconds.to_i < Time.now
end
extract_rate(data, from, to) click to toggle source

Takes the response from jsonrates.com and extract the rate.

@param [String] data HTTP-Response of api.

@return [BigDecimal]

# File lib/money/bank/currencylayer.rb, line 348
def extract_rate(data, from, to)
  request_hash = JSON.parse(data)
  success = request_hash['success']
  raise RequestError, request_hash['error']['info'] unless success
  BigDecimal.new(request_hash['quotes']["#{from}#{to}"].to_s)
end
fetch_rate(from, to) click to toggle source

Queries for the requested rate and returns it.

@param [String, Symbol, Currency] from Currency to convert from @param [String, Symbol, Currency] to Currency to convert to

@return [BigDecimal] The requested rate.

# File lib/money/bank/currencylayer.rb, line 307
def fetch_rate(from, to)
  from, to = Currency.wrap(from), Currency.wrap(to)
  uri = build_uri(from, to)
  data = perform_request(uri)
  extract_rate(data, from, to)
end
get_rate_careful(from, to) click to toggle source

Returns the requested rate.

It not flushes all the rates and create rates with created_at time. Check expired for each rate respectively. If it can’t get new rate by some reason it returns cached value.

@param [String, Symbol, Currency] from Currency to convert from @param [String, Symbol, Currency] to Currency to convert to

@return [Float] The requested rate.

# File lib/money/bank/currencylayer.rb, line 224
def get_rate_careful(from, to)

  rate_key    = rate_key_for(from, to)
  rate_cached = @rates[rate_key]

  if rate_cached.nil? || expired_time?(rate_cached[:created_at])
    set_rate_with_time(from, to, fetch_rate(from, to))
    @rates[rate_key][:rate]
  else
    rate_cached[:rate]
  end
rescue RequestError => e
  if rate_cached.nil?
    raise e
  else
    rate_cached[:rate]
  end
end
get_rate_straight(from, to) click to toggle source

Returns the requested rate.

It also flushes all the rates when and if they are expired.

@param [String, Symbol, Currency] from Currency to convert from @param [String, Symbol, Currency] to Currency to convert to

@return [Float] The requested rate.

# File lib/money/bank/currencylayer.rb, line 252
def get_rate_straight(from, to)
  expire_rates

  @mutex.synchronize{
    @rates[rate_key_for(from, to)] ||= fetch_rate(from, to)
  }
end
perform_request(uri) click to toggle source

Performs request on uri or raise exception message with RequestError

@param [String] uri Requested uri

@return [String]

# File lib/money/bank/currencylayer.rb, line 320
def perform_request(uri)
  uri.read
rescue Exception => e
  raise RequestError, e.message
end
set_rate_with_time(from, to, rate) click to toggle source

Set the rate and created_at time for the given currencies. Uses Mutex to synchronize data access.

@param [Currency, String, Symbol] from Currency to exchange from. @param [Currency, String, Symbol] to Currency to exchange to. @param [Numeric] rate Rate to use when exchanging currencies. @param [Hash] opts Options hash to set special parameters @option opts [Boolean] :without_mutex disables the usage of a mutex

@return [Numeric]

# File lib/money/bank/currencylayer.rb, line 282
def set_rate_with_time(from, to, rate)
  rate_d = BigDecimal.new(rate.to_s)
  @mutex.synchronize {
    @rates[rate_key_for(from, to)] = {rate: rate_d, created_at: Time.now}
  }
  rate_d
end