# frozen_string_literal: true require 'csv' require 'json' require 'net/http' require 'net/https' require 'uri' class CPIFetcher def cpi resp = fetch_raw_response return nil unless resp['Results']['series'] resp['Results']['series'].first['data'] end def cpi_csv CSV.generate do |csv| csv << %w[year period period_name value] cpi.each do |rec| csv << %w[ year period periodName value ].map { |k| rec.fetch(k) } end end end private def url @url ||= URI(ENV['CPI_SERIES_URL'] || File.join( 'https://api.bls.gov', 'publicAPI/v2/timeseries/data/' )) end private def series_id @series_id ||= ENV.fetch( 'CPI_SERIES_ID', 'CUUR0200SA0' ).split(/[, ]/).map(&:strip).reject(&:empty?) end private def start_year @start_year ||= ENV.fetch('CPI_SERIES_START_YEAR', '2014') end private def end_year @end_year ||= ENV.fetch('CPI_SERIES_END_YEAR', Time.now.year.to_s) end private def bls_token @bls_token ||= ENV.fetch('BLS_TOKEN') end private def start_cpi_value(data) data = data.sort do |a, b| record_key(a) <=> record_key(b) end data.first.fetch('value') end private def record_key(record) "#{record['year']}.#{record['period']}" end private def latest_cpi_value(data) data.find { |d| d['latest'] == 'true' }.fetch('value') end private def fetch_raw_response Net::HTTP.new(url.hostname, url.port) .tap { |h| h.use_ssl = true } .tap { |h| h.verify_mode = OpenSSL::SSL::VERIFY_PEER } .then { |h| JSON.parse(h.request(build_request).body) } end private def build_request Net::HTTP::Post.new(url) .tap { |r| r['Authorization'] = "token #{bls_token}" } .tap { |r| r['Content-Type'] = 'application/json' } .tap { |r| r.body = JSON.generate(build_request_body) } end private def build_request_body { 'seriesid' => series_id, 'startyear' => start_year, 'endyear' => end_year } end end if $PROGRAM_NAME == __FILE__ puts CPIFetcher.new.cpi_csv exit 0 end