It is a google sheets function now

This commit is contained in:
Dan Buch 2023-01-21 20:29:36 -05:00
parent 5aadce63fd
commit 4f05c1cbae
Signed by: meatballhat
GPG Key ID: A12F782281063434
12 changed files with 45 additions and 244 deletions

View File

@ -1,15 +0,0 @@
inherit_from: .rubocop_todo.yml
AllCops:
NewCops: enable
SuggestExtensions: false
TargetRubyVersion: 3.2
Style/Documentation:
Enabled: false
Style/AccessModifierDeclarations:
EnforcedStyle: inline
Layout/MultilineMethodCallIndentation:
EnforcedStyle: indented

View File

@ -1,7 +0,0 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2023-01-01 17:49:35 UTC using RuboCop version 1.42.0.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.

41
Code.gs Normal file
View File

@ -0,0 +1,41 @@
const defaultSeriesURL = "https://api.bls.gov/publicAPI/v2/timeseries/data/";
const defaultSeriesID = "CUUR0200SA0";
const defaultStartYear = "2014";
function CURRENTCPI(blsToken, options) {
var seriesURL = options?.seriesURL || defaultSeriesURL;
var seriesID = options?.seriesID || defaultSeriesID;
var startYear = options?.startYear || defaultStartYear;
var endYear = options?.endYear || new Date().getFullYear().toString();
var reqOptions = {
"method": "post",
"payload": JSON.stringify({
"seriesid": [seriesID],
"startyear": startYear,
"endyear": endYear
}),
"contentType": "application/json",
"headers": {
"Authorization": "token "+blsToken,
"Content-Type": "application/json"
}
};
var resp = UrlFetchApp.fetch(seriesURL, reqOptions);
var rawData = resp.getContentText().toString().trim();
var parsedData = JSON.parse(rawData);
var respData = parsedData.Results.series[0].data;
var rows = [["year", "period", "period_name", "value"]];
for (var i = 0; i < respData.length; i++) {
rows.push([
respData[i].year,
respData[i].period,
respData[i].periodName,
respData[i].value
]);
}
return rows;
}

11
Gemfile
View File

@ -1,11 +0,0 @@
# frozen_string_literal: true
source 'https://rubygems.org'
ruby '3.2.0' if ENV.key?('DYNO')
gem 'aws-sdk-s3', '~> 1'
gem 'pry', group: %i[development test]
gem 'rack'
gem 'rake'
gem 'rubocop', group: %i[development test]

View File

@ -1,62 +0,0 @@
GEM
remote: https://rubygems.org/
specs:
ast (2.4.2)
aws-eventstream (1.2.0)
aws-partitions (1.686.0)
aws-sdk-core (3.168.4)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.5)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.61.0)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.117.2)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
aws-sigv4 (1.5.2)
aws-eventstream (~> 1, >= 1.0.2)
coderay (1.1.3)
jmespath (1.6.2)
json (2.6.3)
method_source (1.0.0)
parallel (1.22.1)
parser (3.1.3.0)
ast (~> 2.4.1)
pry (0.14.1)
coderay (~> 1.1)
method_source (~> 1.0)
rack (3.0.3)
rainbow (3.1.1)
rake (13.0.6)
regexp_parser (2.6.1)
rexml (3.2.5)
rubocop (1.42.0)
json (~> 2.3)
parallel (~> 1.10)
parser (>= 3.1.2.1)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.24.1, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 3.0)
rubocop-ast (1.24.1)
parser (>= 3.1.1.0)
ruby-progressbar (1.11.0)
unicode-display_width (2.3.0)
PLATFORMS
ruby
DEPENDENCIES
aws-sdk-s3 (~> 1)
pry
rack
rake
rubocop
BUNDLED WITH
2.1.2

View File

@ -1 +0,0 @@
web: bundle exec rackup -p $PORT

View File

@ -1,21 +1,17 @@
# cpi-feed
Transforms [this](https://api.bls.gov/publicAPI/v2/timeseries/data/CUUSA210SA0)
into [this](https://s3.amazonaws.com/meatballhat/cpi/current.csv) :tada:.
into CSV rows.
## usage
This is intended for use with Google Sheets via:
```
=IMPORTDATA("https://s3.amazonaws.com/meatballhat/cpi/current.csv")
=CURRENTCPI("{bls-token}")
```
## deployment
A copy of this thing is deployed to Heroku with a Heroku Scheduler addon
configured to run the following once daily:
``` bash
bundle exec ./sync
```
Just like [this
example](https://apipheny.io/import-json-google-sheets/).

View File

@ -1,11 +0,0 @@
# frozen_string_literal: true
begin
require 'rubocop/rake_task'
rescue LoadError => e
warn e
end
RuboCop::RakeTask.new if defined?(RuboCop)
task default: %i[rubocop]

View File

@ -1,3 +0,0 @@
# frozen_string_literal: true
run ->(*) { [301, { 'Location' => ENV.fetch('CPI_FEED_URL', nil) }, []] }

View File

@ -1,94 +0,0 @@
# 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

View File

@ -1,30 +0,0 @@
# frozen_string_literal: true
require 'aws-sdk-s3'
class MiniS3put
def initialize(key: nil, instream: $stdin)
@bucket = ENV.fetch('CPI_FEED_AWS_BUCKET')
@key = key || ENV.fetch('CPI_FEED_AWS_KEY')
@instream = instream
end
attr_reader :bucket, :key, :instream
private :bucket, :key, :instream
def put
body = instream.read
puts Aws::S3::Resource.new.bucket(bucket).object(key).put(body:)
puts body
puts Aws::S3::Client.new.put_object_acl(
bucket:, key:, acl: 'public-read'
)
end
end
if $PROGRAM_NAME == __FILE__
MiniS3put.new(key: ARGV.first).put
exit 0
end

2
sync
View File

@ -1,2 +0,0 @@
#!/usr/bin/env bash
ruby cpi_fetcher.rb | ruby mini_s3put.rb