require 'money' require 'open-uri' require 'multi_json' class Money module Bank class GoogleCurrencyRailsCache < Money::Bank::VariableExchange SERVICE_HOST = "www.google.com" SERVICE_PATH = "/finance/converter" ## # Clears all rates stored in @rates # # @example # @bank = GoogleCurrencyRailsCache.new #=> # @bank.get_rate(:USD, :EUR) #=> 0.776337241 # @bank.flush_rates #=> nil def flush_rates rates = Rails.cache.read("exchange_rate/all_rates") unless rates.nil? rates.each do |rate_key| Rails.cache.delete "exchange_rate/#{rate_key}" end end Rails.cache.delete("exchange_rate/all_rates") end ## # 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 [Boolean] Indicating successful removal. # # @example # @bank = GoogleCurrencyRailsCache.new #=> # @bank.get_rate(:USD, :EUR) #=> 0.776337241 # @bank.flush_rate(:USD, :EUR) #=> 0.776337241 def flush_rate(from, to) rate_key = rate_key_for(from, to) Rails.cache.delete("exchange_rate/#{rate_key}") remove_from_stored_rates(rate_key) end ## # Returns the requested rate. # # @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 = GoogleCurrencyRailsCache.new #=> # @bank.get_rate(:USD, :EUR) #=> 0.776337241 def get_rate(from, to) Rails.cache.fetch("exchange_rate/#{rate_key_for(from, to)}", :expires_in => 12.hours ) { fetch_rate(from, to) } end ## # Lists all rates currency cached. # # @return [Array] An array of rates. # def cached_rates Rails.cache.read("exchange_rate/all_rates") end private ## # 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. def fetch_rate(from, to) from, to = Currency.wrap(from), Currency.wrap(to) data = build_uri(from, to).read extract_rate(data) end ## # 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] def build_uri(from, to) uri = URI::HTTP.build( :host => SERVICE_HOST, :path => SERVICE_PATH, :query => "a=1&from=#{from.iso_code}&to=#{to.iso_code}" ) end def extract_rate(data) case data when /(\d+\.?\d*) [A-Z]{3}<\/span>/ BigDecimal($1) when /Could not convert\./ raise UnknownRate else raise GoogleCurrencyFetchError end end ## # Removes the specified rate from the global list of stored rates # # @param [String] rate The rate to remove # # @return [Boolean] def remove_from_stored_rates(rate) rates = Rails.cache.read("exchange_rate/all_rates") unless rates.nil? rates.delete(rate) Rails.cache.write("exchange_rate/all_rates", rates) end end ## # Add the specified rate to the global list of stored rates # # @param [String] rate The rate to add # # @return [Boolean] def add_to_stored_rates(rate) rates = Rails.cache.read("exchange_rate/all_rates") if rates.nil? rates = [] end rates << rate Rails.cache.write("exchange_rate/all_rates", rates) end end end end