# frozen_string_literal: true require "json" require "net/http" require "provider/adapters/adapter" class Provider module Adapters # Bank of Canada daily indicative rates. Current series starts 2017-01-03. # Legacy noon rates (2007-2017) are available under the LEGACY_NOON_RATES group with ~65 currencies. class BOC < Adapter BASE_URL = "https://www.bankofcanada.ca/valet/observations/group/FX_RATES_DAILY/json" def fetch(after: nil, upto: nil) params = { start_date: after } params[:end_date] = upto if upto fetch_rates(**params) end def parse(json) data = json.is_a?(String) ? JSON.parse(json) : json data["observations"].flat_map do |obs| date = Date.parse(obs["d"]) extract_rates(obs).map do |foreign, rate| { date:, base: foreign, quote: "CAD", rate: } end end end private def fetch_rates(**params) url = URI(BASE_URL) url.query = URI.encode_www_form(params) parse(Net::HTTP.get(url)) end def extract_rates(observation) observation.each_with_object({}) do |(series, data), rates| next unless series.start_with?("FX") iso = series.delete_prefix("FX").delete_suffix("CAD") rates[iso] = Float(data["v"]) end end end end end