class ExchangeRate

Constants

CURRY_LENGTH_CONST

A constant value which defines the length of the standard currency abbreviation.

FAR_BACK_DATE
FUTURE_DATE
INVALID_DATE
NO_CURRY_FOR_DATE
NO_ERR

Error message constants for the error_msg_map

NULL_CURRY
NULL_DATE

Public Class Methods

new() click to toggle source
# File lib/ExchangeRate.rb, line 29
def initialize
  @date_hash = Hash.new
  @curry_list = Array.new
  @error_msg_map = Hash.new

  read_from_file
  fill_error_msg_map
end

Public Instance Methods

at(date, from_curry, to_curry) click to toggle source

Calculate exchange rate

# File lib/ExchangeRate.rb, line 134
def at(date, from_curry, to_curry)
  # Validate input
  date = date.to_s

  if chk_valid_input(date, from_curry) != NO_ERR
    error_msg_id = chk_valid_input(date, from_curry)

    return @error_msg_map[error_msg_id]

  elsif chk_valid_input(date, to_curry) != NO_ERR
    error_msg_id = chk_valid_input(date, to_curry)

    return @error_msg_map[error_msg_id]

  else
    rate_from_curry = curry_rate(date, from_curry)
    rate_to_curry = curry_rate(date, to_curry)

    return rate_to_curry/rate_from_curry
  end
end
chk_valid_date(date) click to toggle source

Check if the date read from the XML has a valid date format.

# File lib/ExchangeRate.rb, line 101
def chk_valid_date(date)
  Date.parse(date)
rescue ArgumentError
  return false
end
chk_valid_input(date, currency) click to toggle source

Check if the input parameters are valid.

# File lib/ExchangeRate.rb, line 108
def chk_valid_input(date, currency)

  if date == nil || date == ''
    return NULL_DATE
  elsif Date.today - Date.parse(date) < 0
    return FUTURE_DATE
  elsif Date.today - Date.parse(date) > 90
    return FAR_BACK_DATE
  elsif  currency == nil || currency == ''
    return NULL_CURRY
  elsif @date_hash[date] == nil
    return INVALID_DATE
  elsif @date_hash[date][currency] == nil
    return NO_CURRY_FOR_DATE
  else
    return NO_ERR
  end

end
chk_valid_read(currency, rate) click to toggle source

Check if the currency read from the XML has a valid format.

# File lib/ExchangeRate.rb, line 94
def chk_valid_read(currency, rate)
  begin
    return currency.upcase.length == CURRY_LENGTH_CONST && rate.is_a?(Float)
  end
end
curry_item(index) click to toggle source

Return a currency item from the list

# File lib/ExchangeRate.rb, line 157
def curry_item(index)
  # Keep unique currency entries only.
  @curry_list = @curry_list.uniq
  return @curry_list[index]
end
curry_rate(date, currency) click to toggle source

Find currency rate for given date

# File lib/ExchangeRate.rb, line 129
def curry_rate(date, currency)
  return @date_hash[date][currency]
end
fill_error_msg_map() click to toggle source
# File lib/ExchangeRate.rb, line 83
def fill_error_msg_map
  @error_msg_map[0] = "Date is null."
  @error_msg_map[1] = "Date cannot be in the future."
  @error_msg_map[2] = "Date must be within the last 90 days."
  @error_msg_map[3] = "Currency is null."
  @error_msg_map[4] = "No data for this date."
  @error_msg_map[5] = "Currency details do not exist for the given date."
end
read_from_file() click to toggle source

Assuming that the XML file is downloaded using cron once a day, we access the file and then all currency data are stored into hash tables. We could read directly from the URL, or ideally we could create a configuration file with the path or the URL in order to make it easier for parameterisation, but we can keep it simple for that case. The path where the XML file can be found is defined in the gemspeck.

# File lib/ExchangeRate.rb, line 44
def read_from_file
  
  xml_path = File.expand_path("../ExchangeRate/eurofxref-hist-90d.xml", __FILE__)
  xml_source = File.new(xml_path)
  xml_doc = Document.new(xml_source)

  # This will split based upon different dates.
  xml_doc.elements.each('gesmes:Envelope/Cube/Cube'){
    |date|

    curry_hash = Hash.new

    # This will split based upon each currency for the specific date.
    date.elements.each('Cube'){
        |currency|
      # If XML data are correct then write in the tables.
      if chk_valid_read(currency.attributes["currency"].to_s, currency.attributes["rate"].to_f)
        @curry_list.push(currency.attributes["currency"].to_s)
        curry_hash[currency.attributes["currency"].to_s] = currency.attributes["rate"].to_f
      else
        # Else, omit this row.
        puts "Incorrect currency format. Line was omited."
      end
    }
    # Euro is also added in the map and the list
    curry_hash["EUR"] = 1.00
    @curry_list.push("EUR")

    # If date format is correct then write in the table.
    if chk_valid_date(date.attributes["time"].to_s)
      @date_hash[date.attributes["time"].to_s] = curry_hash
    else
      # Else, omit this row.
      puts "Incorrect date format. Row was omited."
    end

  }
end