frankfurter/lib/provider/adapters/bob.rb

62 lines
1.7 KiB
Ruby
Raw Permalink Normal View History

2026-05-21 01:38:14 -06:00
# frozen_string_literal: true
require "net/http"
require "provider/adapters/adapter"
class Provider
module Adapters
# Bank of Botswana. Publishes daily rates for ~7 currencies against BWP.
# The CSV export only contains these columns.
class BOB < Adapter
CSV_URL = URI("https://www.bankofbotswana.bw/export/exchange-rates.csv?page&_format=csv")
# Columns in the CSV mapped to ISO currency codes
COLUMNS = {
"CHN" => "CNY",
"EUR" => "EUR",
"GBP" => "GBP",
"USD" => "USD",
"YEN" => "JPY",
"ZAR" => "ZAR",
}.freeze
class << self
end
def fetch(after: nil, upto: nil)
records = parse(Net::HTTP.get(CSV_URL))
after ? records.select { |r| r[:date] >= Date.parse(after.to_s) } : records
end
def parse(csv)
csv = csv.dup.force_encoding(Encoding::UTF_8)
rows = csv.delete_prefix("\uFEFF").lines(chomp: true)
headers = rows.shift&.split(",")
date_index = headers&.index("Date")
return [] unless date_index
column_indices = COLUMNS.each_with_object({}) do |(col, iso), map|
idx = headers.index(col)
map[iso] = idx if idx
end
rows.filter_map do |line|
values = line.delete('"').split(",")
date = Date.strptime(values[date_index].strip, "%d %b %Y")
rates = column_indices.filter_map do |iso, idx|
val = values[idx]
next if val.nil? || val.empty?
rate = Float(val)
next if rate.zero?
{ date:, base: "BWP", quote: iso, rate: }
end
rates.empty? ? nil : rates
end.flatten.sort_by { |r| r[:date] }
end
end
end
end