diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index c496bc7..0000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,11 +0,0 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for all configuration options: -# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file - -version: 2 -updates: - - package-ecosystem: "bundler" # See documentation for possible values - directory: "/" # Location of package manifests - schedule: - interval: "weekly" diff --git a/.github/stale.yml b/.github/stale.yml deleted file mode 100644 index dc90e5a..0000000 --- a/.github/stale.yml +++ /dev/null @@ -1,17 +0,0 @@ -# Number of days of inactivity before an issue becomes stale -daysUntilStale: 60 -# Number of days of inactivity before a stale issue is closed -daysUntilClose: 7 -# Issues with these labels will never be considered stale -exemptLabels: - - pinned - - security -# Label to use when marking an issue as stale -staleLabel: wontfix -# Comment to post when marking an issue as stale. Set to `false` to disable -markComment: > - This issue has been automatically marked as stale because it has not had - recent activity. It will be closed if no further activity occurs. Thank you - for your contributions. -# Comment to post when closing a stale issue. Set to `false` to disable -closeComment: false diff --git a/.rubocop.yml b/.rubocop.yml index 0e0a2af..2299bcc 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,3 +1,6 @@ +inherit_gem: + rubocop-shopify: rubocop.yml + inherit_from: ".rubocop_todo.yml" require: diff --git a/Gemfile b/Gemfile index 2ed1724..6cab696 100644 --- a/Gemfile +++ b/Gemfile @@ -1,34 +1,34 @@ # frozen_string_literal: true -source 'https://rubygems.org' +source "https://rubygems.org" -ruby File.read('.ruby-version').chomp +ruby File.read(".ruby-version").chomp -gem 'money' -gem 'oj' -gem 'ox' -gem 'rack-contrib' -gem 'rack-cors' -gem 'rake' -gem 'roda' -gem 'rufus-scheduler' -gem 'sequel_pg' -gem 'unicorn' +gem "money" +gem "oj" +gem "ox" +gem "rack-contrib" +gem "rack-cors" +gem "rake" +gem "roda" +gem "rufus-scheduler" +gem "sequel_pg" +gem "unicorn" group :development, :test do - gem 'pry-byebug' - gem 'rubocop-minitest' - gem 'rubocop-performance' - gem 'rubocop-rake' - gem 'rubocop-sequel' + gem "rubocop-minitest" + gem "rubocop-performance" + gem "rubocop-rake" + gem "rubocop-sequel" + gem "rubocop-shopify" end group :test do - gem 'minitest' - gem 'minitest-around' - gem 'minitest-focus' - gem 'rack-test' - gem 'simplecov' - gem 'vcr' - gem 'webmock' + gem "minitest" + gem "minitest-around" + gem "minitest-focus" + gem "rack-test" + gem "simplecov" + gem "vcr" + gem "webmock" end diff --git a/Gemfile.lock b/Gemfile.lock index ea9714f..2e7f3d2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,8 +6,6 @@ GEM ast (2.4.2) base64 (0.2.0) bigdecimal (3.1.8) - byebug (11.1.3) - coderay (1.1.3) concurrent-ruby (1.3.4) crack (1.0.0) bigdecimal @@ -18,13 +16,12 @@ GEM fugit (1.11.1) et-orbi (~> 1, >= 1.2.11) raabro (~> 1.4) - hashdiff (1.1.1) + hashdiff (1.1.2) i18n (1.14.6) concurrent-ruby (~> 1.0) json (2.8.2) kgio (2.11.4) language_server-protocol (3.17.0.3) - method_source (1.1.0) minitest (5.25.1) minitest-around (0.5.0) minitest (~> 5.0) @@ -35,19 +32,13 @@ GEM oj (3.16.7) bigdecimal (>= 3.0) ostruct (>= 0.2) - ostruct (0.6.0) + ostruct (0.6.1) ox (2.14.18) parallel (1.26.3) parser (3.3.6.0) ast (~> 2.4.1) racc - pg (1.5.8) - pry (0.14.2) - coderay (~> 1.1) - method_source (~> 1.0) - pry-byebug (3.10.1) - byebug (~> 11.0) - pry (>= 0.13, < 0.15) + pg (1.5.9) public_suffix (6.0.1) raabro (1.4.0) racc (1.8.1) @@ -87,10 +78,12 @@ GEM rubocop (~> 1.0) rubocop-sequel (0.3.7) rubocop (~> 1.0) + rubocop-shopify (2.15.1) + rubocop (~> 1.51) ruby-progressbar (1.13.0) rufus-scheduler (3.9.2) fugit (~> 1.1, >= 1.11.1) - sequel (5.85.0) + sequel (5.86.0) bigdecimal sequel_pg (1.17.1) pg (>= 0.18.0, != 1.2.0) @@ -124,7 +117,6 @@ DEPENDENCIES money oj ox - pry-byebug rack-contrib rack-cors rack-test @@ -134,6 +126,7 @@ DEPENDENCIES rubocop-performance rubocop-rake rubocop-sequel + rubocop-shopify rufus-scheduler sequel_pg simplecov diff --git a/Rakefile b/Rakefile index 358da59..f47a29f 100644 --- a/Rakefile +++ b/Rakefile @@ -1,3 +1,3 @@ # frozen_string_literal: true -Dir.glob('lib/tasks/*.rake').each { |r| import r } +Dir.glob("lib/tasks/*.rake").each { |r| import r } diff --git a/bin/schedule b/bin/schedule index aea3f7e..7c5e64d 100755 --- a/bin/schedule +++ b/bin/schedule @@ -1,12 +1,12 @@ #!/usr/bin/env ruby # frozen_string_literal: true -require 'rufus-scheduler' +require "rufus-scheduler" scheduler = Rufus::Scheduler.new -scheduler.cron '*/30 15,16,17 * * 1-5' do - `rake rates:current` +scheduler.cron("*/30 15,16,17 * * 1-5") do + %x(rake rates:current) end scheduler.join diff --git a/config.ru b/config.ru index c7015e8..b9e3011 100644 --- a/config.ru +++ b/config.ru @@ -1,6 +1,6 @@ # frozen_string_literal: true -require './config/environment' -require 'web/server' +require "./config/environment" +require "web/server" run Web::Server.freeze.app diff --git a/config/app.rb b/config/app.rb index d3921c3..0902e4b 100644 --- a/config/app.rb +++ b/config/app.rb @@ -1,16 +1,16 @@ # frozen_string_literal: true -require 'pathname' +require "pathname" # Encapsulates app configuration module App class << self def env - ENV['APP_ENV'] || 'development' + ENV["APP_ENV"] || "development" end def root - Pathname.new(File.expand_path('..', __dir__)) + Pathname.new(File.expand_path("..", __dir__)) end end end diff --git a/config/environment.rb b/config/environment.rb index 578fb8c..b43fb20 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -require_relative 'app' -$LOAD_PATH << App.root.join('lib') -Dir[App.root.join('config/initializers/*.rb')].each { |f| require f } +require_relative "app" +$LOAD_PATH << App.root.join("lib") +Dir[App.root.join("config/initializers/*.rb")].each { |f| require f } diff --git a/config/initializers/sequel.rb b/config/initializers/sequel.rb index c158846..08672e6 100644 --- a/config/initializers/sequel.rb +++ b/config/initializers/sequel.rb @@ -1,10 +1,10 @@ # frozen_string_literal: true -require 'pg' -require 'sequel' +require "pg" +require "sequel" -Sequel.extension :pg_json_ops +Sequel.extension(:pg_json_ops) Sequel.single_threaded = true -Sequel.connect(ENV['DATABASE_URL'] || - "postgres://localhost:#{ENV.fetch('PGPORT', nil)}/frankfurter_#{App.env}") - .extension :pg_json +Sequel.connect(ENV["DATABASE_URL"] || + "postgres://localhost:#{ENV.fetch("PGPORT", nil)}/frankfurter_#{App.env}") + .extension(:pg_json) diff --git a/config/unicorn.rb b/config/unicorn.rb index 41a6ea8..ea30450 100644 --- a/config/unicorn.rb +++ b/config/unicorn.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -`rake db:prepare` +%x(rake db:prepare) -worker_process_count = (ENV['WORKER_PROCESSES'] || 4).to_i +worker_process_count = (ENV["WORKER_PROCESSES"] || 4).to_i preload_app true worker_processes worker_process_count @@ -12,7 +12,7 @@ initialized = false before_fork do |_server, _worker| Sequel::DATABASES.each(&:disconnect) unless initialized - require 'scheduler/daemon' + require "scheduler/daemon" Scheduler::Daemon.start initialized = true end diff --git a/db/migrate/001_create_currencies.rb b/db/migrate/001_create_currencies.rb index 80a5d55..bec0a4f 100644 --- a/db/migrate/001_create_currencies.rb +++ b/db/migrate/001_create_currencies.rb @@ -7,7 +7,7 @@ Sequel.migration do String :iso_code Float :rate - index %i[date iso_code], unique: true + index [:date, :iso_code], unique: true end end diff --git a/db/migrate/002_denormalise_currencies.rb b/db/migrate/002_denormalise_currencies.rb index 3aeb767..6722fc7 100644 --- a/db/migrate/002_denormalise_currencies.rb +++ b/db/migrate/002_denormalise_currencies.rb @@ -15,7 +15,7 @@ Sequel.migration do date :date string :iso_code float :rate - index %i[date iso_code], unique: true + index [:date, :iso_code], unique: true end drop_table :days end diff --git a/lib/bank.rb b/lib/bank.rb index bc56e95..bce79f3 100644 --- a/lib/bank.rb +++ b/lib/bank.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require 'day' -require 'bank/feed' +require "day" +require "bank/feed" module Bank class << self diff --git a/lib/bank/feed.rb b/lib/bank/feed.rb index ca79da6..6d5f315 100644 --- a/lib/bank/feed.rb +++ b/lib/bank/feed.rb @@ -1,36 +1,38 @@ # frozen_string_literal: true -require 'net/http' -require 'ox' +require "net/http" +require "ox" module Bank class Feed include Enumerable - def self.current - url = URI('https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml') - xml = Net::HTTP.get(url) + class << self + def current + url = URI("https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml") + xml = Net::HTTP.get(url) - new(xml) - end + new(xml) + end - def self.ninety_days - url = URI('https://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist-90d.xml') - xml = Net::HTTP.get(url) + def ninety_days + url = URI("https://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist-90d.xml") + xml = Net::HTTP.get(url) - new(xml) - end + new(xml) + end - def self.historical - url = URI('https://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist.xml') - xml = Net::HTTP.get(url) + def historical + url = URI("https://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist.xml") + xml = Net::HTTP.get(url) - new(xml) - end + new(xml) + end - def self.saved_data - xml = File.read(File.join(__dir__, 'eurofxref-hist.xml')) - new(xml) + def saved_data + xml = File.read(File.join(__dir__, "eurofxref-hist.xml")) + new(xml) + end end def initialize(xml) @@ -38,8 +40,8 @@ module Bank end def each - @document.locate('gesmes:Envelope/Cube/Cube').each do |day| - yield(date: Date.parse(day['time']), + @document.locate("gesmes:Envelope/Cube/Cube").each do |day| + yield(date: Date.parse(day["time"]), rates: day.nodes.each_with_object({}) do |currency, rates| rates[currency[:currency]] = Float(currency[:rate]) end) diff --git a/lib/currency.rb b/lib/currency.rb index a52fbdc..2037858 100644 --- a/lib/currency.rb +++ b/lib/currency.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require 'day' -require 'forwardable' +require "day" +require "forwardable" class Currency < Sequel::Model(Day.currencies) class << self @@ -17,7 +17,7 @@ class Currency < Sequel::Model(Day.currencies) def between(interval) case interval.last - interval.first - when 366.. then super.sample('week') + when 366.. then super.sample("week") else super end end diff --git a/lib/currency_names.rb b/lib/currency_names.rb index d5c7e9b..44e29bc 100644 --- a/lib/currency_names.rb +++ b/lib/currency_names.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require 'currency' -require 'money/currency' +require "currency" +require "money/currency" class CurrencyNames def cache_key @@ -17,7 +17,7 @@ class CurrencyNames private def iso_codes - currencies.map(&:iso_code).append('EUR').sort + currencies.map(&:iso_code).append("EUR").sort end def currencies diff --git a/lib/day.rb b/lib/day.rb index aa8de00..6e176a0 100644 --- a/lib/day.rb +++ b/lib/day.rb @@ -3,7 +3,7 @@ class Day < Sequel::Model dataset_module do def latest(date = Date.today) - where(date: select(:date).where(Sequel.lit('date <= ?', date)) + where(date: select(:date).where(Sequel.lit("date <= ?", date)) .order(Sequel.desc(:date)) .limit(1)) end @@ -13,9 +13,11 @@ class Day < Sequel::Model end def currencies - select(:date, - Sequel.lit('rates.key').as(:iso_code), - Sequel.lit('rates.value::text::float').as(:rate)) + select( + :date, + Sequel.lit("rates.key").as(:iso_code), + Sequel.lit("rates.value::text::float").as(:rate), + ) .join(Sequel.function(:jsonb_each, :rates).lateral.as(:rates), true) end end diff --git a/lib/query.rb b/lib/query.rb index da980df..a155612 100644 --- a/lib/query.rb +++ b/lib/query.rb @@ -1,8 +1,10 @@ # frozen_string_literal: true class Query - def self.build(params) - new(params).to_h + class << self + def build(params) + new(params).to_h + end end def initialize(params = {}) @@ -20,7 +22,7 @@ class Query end def symbols - @params.values_at(:to, :symbols).compact.first&.upcase&.split(',') + @params.values_at(:to, :symbols).compact.first&.upcase&.split(",") end def date diff --git a/lib/quote.rb b/lib/quote.rb index 359cf45..c92aadc 100644 --- a/lib/quote.rb +++ b/lib/quote.rb @@ -1,4 +1,4 @@ # frozen_string_literal: true -require 'quote/end_of_day' -require 'quote/interval' +require "quote/end_of_day" +require "quote/interval" diff --git a/lib/quote/base.rb b/lib/quote/base.rb index 83a0ca1..765e2fe 100644 --- a/lib/quote/base.rb +++ b/lib/quote/base.rb @@ -1,16 +1,16 @@ # frozen_string_literal: true -require 'roundable' +require "roundable" module Quote class Base include Roundable - DEFAULT_BASE = 'EUR' + DEFAULT_BASE = "EUR" attr_reader :amount, :base, :date, :symbols, :result - def initialize(date:, amount: 1.0, base: 'EUR', symbols: nil) + def initialize(date:, amount: 1.0, base: "EUR", symbols: nil) @date = date @amount = amount @base = base @@ -29,7 +29,7 @@ module Quote end def must_rebase? - base != 'EUR' + base != "EUR" end def formatted @@ -64,16 +64,16 @@ module Quote def rebase_rates result.each do |date, rates| - rates['EUR'] = amount if symbols.nil? || symbols.include?('EUR') + rates["EUR"] = amount if symbols.nil? || symbols.include?("EUR") divisor = rates.delete(base) if divisor.nil? || rates.empty? result.delete(date) else result[date] = rates.sort - .map! do |iso_code, rate| - [iso_code, round(amount * rate / divisor)] - end - .to_h + .map! do |iso_code, rate| + [iso_code, round(amount * rate / divisor)] + end + .to_h end end end diff --git a/lib/quote/end_of_day.rb b/lib/quote/end_of_day.rb index 20adf4e..f3d24dc 100644 --- a/lib/quote/end_of_day.rb +++ b/lib/quote/end_of_day.rb @@ -1,15 +1,17 @@ # frozen_string_literal: true -require 'quote/base' -require 'digest' +require "quote/base" +require "digest" module Quote class EndOfDay < Base def formatted - { amount:, + { + amount:, base:, date: result.keys.first, - rates: result.values.first } + rates: result.values.first, + } end def cache_key @@ -21,7 +23,7 @@ module Quote private def fetch_data - require 'currency' + require "currency" scope = Currency.latest(date) scope = scope.only(*(symbols + [base])) if symbols diff --git a/lib/quote/interval.rb b/lib/quote/interval.rb index 6061924..2559b49 100644 --- a/lib/quote/interval.rb +++ b/lib/quote/interval.rb @@ -1,15 +1,17 @@ # frozen_string_literal: true -require 'quote/base' +require "quote/base" module Quote class Interval < Base def formatted - { amount:, + { + amount:, base:, start_date: result.keys.first, end_date: result.keys.last, - rates: result } + rates: result, + } end def cache_key @@ -21,7 +23,7 @@ module Quote private def fetch_data - require 'currency' + require "currency" scope = Currency.between(date) scope = scope.only(*(symbols + [base])) if symbols diff --git a/lib/roundable.rb b/lib/roundable.rb index 11265f8..b4a1c96 100644 --- a/lib/roundable.rb +++ b/lib/roundable.rb @@ -13,18 +13,18 @@ module Roundable if value > 5000 value.round elsif value > 80 - Float(format('%.2f', value:)) + Float(format("%.2f", value:)) elsif value > 20 - Float(format('%.3f', value:)) + Float(format("%.3f", value:)) elsif value > 1 - Float(format('%.4f', value:)) + Float(format("%.4f", value:)) # I had originally opted to round smaller numbers simply to five decimal # places but introduced this refinement to handle an edge case where a # lower-rate base currency like IDR produces less precise quotes. elsif value > 0.0001 - Float(format('%.5f', value:)) + Float(format("%.5f", value:)) else - Float(format('%.6f', value:)) + Float(format("%.6f", value:)) end end end diff --git a/lib/scheduler/daemon.rb b/lib/scheduler/daemon.rb index fc1d8d4..bf6a323 100644 --- a/lib/scheduler/daemon.rb +++ b/lib/scheduler/daemon.rb @@ -4,8 +4,10 @@ module Scheduler class Daemon attr_reader :pid - def self.start - new.start + class << self + def start + new.start + end end def initialize @@ -25,7 +27,7 @@ module Scheduler private def run - load 'bin/schedule' + load("bin/schedule") end def monitor_child @@ -33,7 +35,7 @@ module Scheduler @child_monitor = Thread.new do loop do - sleep 5 + sleep(5) unless alive?(pid) @pid = nil start @@ -46,7 +48,7 @@ module Scheduler Thread.new do loop do exit unless alive?(@parent_pid) - sleep 1 + sleep(1) end end end diff --git a/lib/tasks/db.rake b/lib/tasks/db.rake index ff2028b..2f70861 100644 --- a/lib/tasks/db.rake +++ b/lib/tasks/db.rake @@ -1,26 +1,26 @@ # frozen_string_literal: true namespace :db do - desc 'Run database migrations' + desc "Run database migrations" task migrate: :environment do Sequel.extension(:migration) db = Sequel::DATABASES.first - dir = App.root.join('db/migrate') + dir = App.root.join("db/migrate") opts = {} - opts.update(target: ENV['VERSION'].to_i) if ENV['VERSION'] + opts.update(target: ENV["VERSION"].to_i) if ENV["VERSION"] Sequel::IntegerMigrator.new(db, dir, opts).run end - desc 'Run database migrations and seed data' - task prepare: %w[db:migrate rates:all] + desc "Run database migrations and seed data" + task prepare: ["db:migrate", "rates:all"] namespace :test do - desc 'Run database migrations and seed with saved data' + desc "Run database migrations and seed with saved data" task :prepare do - ENV['APP_ENV'] ||= 'test' - Rake::Task['db:migrate'].invoke - Rake::Task['rates:seed_with_saved_data'].invoke + ENV["APP_ENV"] ||= "test" + Rake::Task["db:migrate"].invoke + Rake::Task["rates:seed_with_saved_data"].invoke end end end diff --git a/lib/tasks/environment.rake b/lib/tasks/environment.rake index ac9e199..c54f079 100644 --- a/lib/tasks/environment.rake +++ b/lib/tasks/environment.rake @@ -1,6 +1,6 @@ # frozen_string_literal: true -desc 'Load environment' +desc "Load environment" task :environment do - require './config/environment' + require "./config/environment" end diff --git a/lib/tasks/rates.rake b/lib/tasks/rates.rake index 91f4541..94667cb 100644 --- a/lib/tasks/rates.rake +++ b/lib/tasks/rates.rake @@ -1,27 +1,27 @@ # frozen_string_literal: true namespace :rates do - desc 'Load all' + desc "Load all" task all: :environment do - require 'bank' + require "bank" Bank.fetch_all! end - desc 'Load last 90 days' + desc "Load last 90 days" task ninety_days: :environment do - require 'bank' + require "bank" Bank.fetch_ninety_days! end - desc 'Load current' + desc "Load current" task current: :environment do - require 'bank' + require "bank" Bank.fetch_current! end - desc 'Seed with saved data' + desc "Seed with saved data" task :seed_with_saved_data do - require 'bank' + require "bank" Bank.seed_with_saved_data! end end diff --git a/lib/tasks/sitemap.rake b/lib/tasks/sitemap.rake index 863cca0..b382b54 100644 --- a/lib/tasks/sitemap.rake +++ b/lib/tasks/sitemap.rake @@ -1,7 +1,7 @@ # frozen_string_literal: true begin - require 'sitemap_generator/tasks' + require "sitemap_generator/tasks" rescue LoadError return end diff --git a/lib/tasks/test.rake b/lib/tasks/test.rake index 71dbd60..fa9c9a3 100644 --- a/lib/tasks/test.rake +++ b/lib/tasks/test.rake @@ -1,18 +1,18 @@ # frozen_string_literal: true -require 'rake/testtask' +require "rake/testtask" begin - require 'rubocop/rake_task' + require "rubocop/rake_task" rescue LoadError return end Rake::TestTask.new(test: :environment) do |t| - t.libs.push('lib') - t.test_files = FileList['spec/**/*_spec.rb'] - t.ruby_opts += ['-W0'] + t.libs.push("lib") + t.test_files = FileList["spec/**/*_spec.rb"] + t.ruby_opts += ["-W0"] end RuboCop::RakeTask.new -task default: %w[rubocop db:test:prepare test] +task default: ["rubocop", "db:test:prepare", "test"] diff --git a/lib/web/server.rb b/lib/web/server.rb index f3a5857..ce41bc5 100644 --- a/lib/web/server.rb +++ b/lib/web/server.rb @@ -1,20 +1,20 @@ # frozen_string_literal: true -require 'oj' -require 'rack/contrib/jsonp' -require 'rack/cors' -require 'roda' +require "oj" +require "rack/contrib/jsonp" +require "rack/cors" +require "roda" -require 'currency_names' -require 'query' -require 'quote' +require "currency_names" +require "query" +require "quote" module Web class Server < Roda use Rack::Cors do allow do - origins '*' - resource '*', headers: :any, methods: %i[get options] + origins "*" + resource "*", headers: :any, methods: [:get, :options] end end use Rack::JSONP @@ -23,51 +23,52 @@ module Web plugin :halt plugin :error_handler do |error| - request.halt 422, { message: error.message } + request.halt(422, { message: error.message }) end plugin :indifferent_params - plugin :json, content_type: 'application/json; charset=utf-8', - serializer: ->(o) { Oj.dump(o, mode: :compat) } + plugin :json, + content_type: "application/json; charset=utf-8", + serializer: ->(o) { Oj.dump(o, mode: :compat) } plugin :params_capturing route do |r| - response.cache_control public: true, max_age: 900 + response.cache_control(public: true, max_age: 900) r.root do - { docs: 'https://www.frankfurter.app/docs' } + { docs: "https://www.frankfurter.app/docs" } end r.is(/latest|current/) do - r.params['date'] = Date.today.to_s + r.params["date"] = Date.today.to_s quote = quote_end_of_day(r) - r.etag quote.cache_key + r.etag(quote.cache_key) quote.formatted end r.is(/(\d{4}-\d{2}-\d{2})/) do - r.params['date'] = r.params['captures'].first + r.params["date"] = r.params["captures"].first quote = quote_end_of_day(r) - r.etag quote.cache_key + r.etag(quote.cache_key) quote.formatted end r.is(/(\d{4}-\d{2}-\d{2})\.\.(\d{4}-\d{2}-\d{2})?/) do - r.params['start_date'] = r.params['captures'].first - r.params['end_date'] = r.params['captures'][1] || Date.today.to_s + r.params["start_date"] = r.params["captures"].first + r.params["end_date"] = r.params["captures"][1] || Date.today.to_s quote = quote_interval(r) - r.etag quote.cache_key + r.etag(quote.cache_key) quote.formatted end - r.is 'currencies' do + r.is("currencies") do currency_names = CurrencyNames.new - r.etag currency_names.cache_key + r.etag(currency_names.cache_key) currency_names.formatted end @@ -79,7 +80,7 @@ module Web query = Query.build(request.params) quote = Quote::EndOfDay.new(**query) quote.perform - request.halt 404, { message: 'not found' } if quote.not_found? + request.halt(404, { message: "not found" }) if quote.not_found? quote end @@ -88,7 +89,7 @@ module Web query = Query.build(request.params) quote = Quote::Interval.new(**query) quote.perform - request.halt 404, { message: 'not found' } if quote.not_found? + request.halt(404, { message: "not found" }) if quote.not_found? quote end diff --git a/spec/bank/feed_spec.rb b/spec/bank/feed_spec.rb index e52a6fe..5c14e83 100644 --- a/spec/bank/feed_spec.rb +++ b/spec/bank/feed_spec.rb @@ -1,46 +1,46 @@ # frozen_string_literal: true -require_relative '../helper' -require 'bank/feed' +require_relative "../helper" +require "bank/feed" module Bank describe Feed do before do - VCR.insert_cassette 'feed' + VCR.insert_cassette("feed") end after do VCR.eject_cassette end - it 'fetches current rates' do + it "fetches current rates" do feed = Feed.current - _(feed.count).must_be :==, 1 + _(feed.count).must_be(:==, 1) end - it 'fetches rates for the past 90 days' do + it "fetches rates for the past 90 days" do feed = Feed.ninety_days - _(feed.count).must_be :>, 1 - _(feed.count).must_be :<=, 90 + _(feed.count).must_be(:>, 1) + _(feed.count).must_be(:<=, 90) end - it 'fetches historical rates' do + it "fetches historical rates" do feed = Feed.historical - _(feed.count).must_be :>, 90 + _(feed.count).must_be(:>, 90) end - it 'parses dates' do + it "parses dates" do feed = Feed.current day = feed.first - _(day[:date]).must_be_kind_of Date + _(day[:date]).must_be_kind_of(Date) end - it 'parses rates' do + it "parses rates" do feed = Feed.current day = feed.first day[:rates].each do |iso_code, value| - _(iso_code).must_be_kind_of String - _(value).must_be_kind_of Float + _(iso_code).must_be_kind_of(String) + _(value).must_be_kind_of(Float) end end end diff --git a/spec/bank_spec.rb b/spec/bank_spec.rb index 83aac54..0e1e8e5 100644 --- a/spec/bank_spec.rb +++ b/spec/bank_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require_relative 'helper' -require 'bank' +require_relative "helper" +require "bank" describe Bank do around do |test| @@ -13,55 +13,55 @@ describe Bank do end before do - VCR.insert_cassette 'feed' + VCR.insert_cassette("feed") end after do VCR.eject_cassette end - it 'fetches all rates' do + it "fetches all rates" do Bank.fetch_all! - _(Day.count).must_be :>, 90 + _(Day.count).must_be(:>, 90) end - it 'does not duplicate when fetching all rates' do + it "does not duplicate when fetching all rates" do Bank.fetch_all! count = Day.count Bank.fetch_all! - _(Day.count).must_equal count + _(Day.count).must_equal(count) end - it 'fetches rates for last 90 days' do + it "fetches rates for last 90 days" do Bank.fetch_ninety_days! - _(Day.count).must_be :>, 1 - _(Day.count).must_be :<, 90 + _(Day.count).must_be(:>, 1) + _(Day.count).must_be(:<, 90) end - it 'seeds rates with saved data' do + it "seeds rates with saved data" do Bank.seed_with_saved_data! - _(Day.count).must_be :>, 90 + _(Day.count).must_be(:>, 90) end - it 'does not duplicate when fetching rates for last 90 days' do + it "does not duplicate when fetching rates for last 90 days" do Bank.fetch_ninety_days! count = Day.count Bank.fetch_ninety_days! - _(Day.count).must_equal count + _(Day.count).must_equal(count) end - it 'fetches current rates' do + it "fetches current rates" do Bank.fetch_current! - _(Day.count).must_equal 1 + _(Day.count).must_equal(1) end - it 'does not duplicate when fetching current rates' do + it "does not duplicate when fetching current rates" do 2.times { Bank.fetch_current! } - _(Day.count).must_equal 1 + _(Day.count).must_equal(1) end - it 'replaces all rates' do + it "replaces all rates" do Bank.replace_all! - _(Day.count).must_be :>, 90 + _(Day.count).must_be(:>, 90) end end diff --git a/spec/currency_names_spec.rb b/spec/currency_names_spec.rb index 096d846..22ffd25 100644 --- a/spec/currency_names_spec.rb +++ b/spec/currency_names_spec.rb @@ -1,18 +1,18 @@ # frozen_string_literal: true -require_relative 'helper' -require 'currency_names' +require_relative "helper" +require "currency_names" describe CurrencyNames do let(:currency_names) do CurrencyNames.new end - it 'returns currency codes and names' do - _(currency_names.formatted['USD']).must_equal 'United States Dollar' + it "returns currency codes and names" do + _(currency_names.formatted["USD"]).must_equal("United States Dollar") end - it 'has a cache key' do - _(currency_names.cache_key).wont_be :empty? + it "has a cache key" do + _(currency_names.cache_key).wont_be(:empty?) end end diff --git a/spec/currency_spec.rb b/spec/currency_spec.rb index 9b91190..b627640 100644 --- a/spec/currency_spec.rb +++ b/spec/currency_spec.rb @@ -1,48 +1,48 @@ # frozen_string_literal: true -require_relative 'helper' -require 'currency' -require 'minitest/autorun' +require_relative "helper" +require "currency" +require "minitest/autorun" describe Currency do - describe '.latest' do - it 'returns latest rates' do + describe ".latest" do + it "returns latest rates" do data = Currency.latest.all - _(data.count).must_be :>, 1 + _(data.count).must_be(:>, 1) end end - describe '.between' do + describe ".between" do let(:day) do - Date.parse('2010-01-01') + Date.parse("2010-01-01") end - it 'returns everything up to a year' do + it "returns everything up to a year" do interval = day..day + 365 - _(Currency.between(interval).map(:date).uniq.count).must_be :>, 52 + _(Currency.between(interval).map(:date).uniq.count).must_be(:>, 52) end - it 'samples weekly over a year' do + it "samples weekly over a year" do interval = day..day + 366 - _(Currency.between(interval).map(:date).uniq.count).must_be :<, 54 + _(Currency.between(interval).map(:date).uniq.count).must_be(:<, 54) end - it 'sorts by date when sampling' do + it "sorts by date when sampling" do interval = day..day + 366 dates = Currency.between(interval).map(:date) - _(dates).must_equal dates.sort + _(dates).must_equal(dates.sort) end end - describe '.only' do - it 'filters symbols' do - iso_codes = %w[CAD USD] + describe ".only" do + it "filters symbols" do + iso_codes = ["CAD", "USD"] data = Currency.latest.only(*iso_codes).all - _(data.map(&:iso_code).sort).must_equal iso_codes + _(data.map(&:iso_code).sort).must_equal(iso_codes) end - it 'returns nothing if no matches' do - _(Currency.only('FOO').all).must_be_empty + it "returns nothing if no matches" do + _(Currency.only("FOO").all).must_be_empty end end end diff --git a/spec/day_spec.rb b/spec/day_spec.rb index eedac74..0d28a4c 100644 --- a/spec/day_spec.rb +++ b/spec/day_spec.rb @@ -1,32 +1,32 @@ # frozen_string_literal: true -require_relative 'helper' -require 'day' +require_relative "helper" +require "day" describe Day do - describe '.latest' do - it 'returns latest rates before given date' do - date = Date.parse('2010-01-01') + describe ".latest" do + it "returns latest rates before given date" do + date = Date.parse("2010-01-01") data = Day.latest(date) - _(data.first.date).must_be :<=, date + _(data.first.date).must_be(:<=, date) end - it 'returns nothing if there are no rates before given date' do - _(Day.latest(Date.parse('1998-01-01'))).must_be_empty + it "returns nothing if there are no rates before given date" do + _(Day.latest(Date.parse("1998-01-01"))).must_be_empty end end - describe '.between' do - it 'returns rates between given dates' do - start_date = Date.parse('2010-01-01') - end_date = Date.parse('2010-01-31') + describe ".between" do + it "returns rates between given dates" do + start_date = Date.parse("2010-01-01") + end_date = Date.parse("2010-01-31") dates = Day.between((start_date..end_date)).map(:date).sort - _(dates.first).must_be :>=, start_date - _(dates.last).must_be :<=, end_date + _(dates.first).must_be(:>=, start_date) + _(dates.last).must_be(:<=, end_date) end - it 'returns nothing if there are no rates between given dates' do - interval = (Date.parse('1998-01-01')..Date.parse('1998-01-31')) + it "returns nothing if there are no rates between given dates" do + interval = (Date.parse("1998-01-01")..Date.parse("1998-01-31")) _(Day.between(interval)).must_be_empty end end diff --git a/spec/edge_cases_spec.rb b/spec/edge_cases_spec.rb index 9381489..cf5bff7 100644 --- a/spec/edge_cases_spec.rb +++ b/spec/edge_cases_spec.rb @@ -1,10 +1,10 @@ # frozen_string_literal: true -require_relative 'helper' -require 'rack/test' -require 'web/server' +require_relative "helper" +require "rack/test" +require "web/server" -describe 'the server' do +describe "the server" do include Rack::Test::Methods let(:app) { Web::Server.freeze } @@ -13,38 +13,38 @@ describe 'the server' do Oj.load(last_response.body) end - it 'handles unfound pages' do - get '/foo' - _(last_response.status).must_equal 404 + it "handles unfound pages" do + get "/foo" + _(last_response.status).must_equal(404) end - it 'will not process an invalid date' do - get '/2010-31-01' - _(last_response).must_be :unprocessable? + it "will not process an invalid date" do + get "/2010-31-01" + _(last_response).must_be(:unprocessable?) end - it 'will not process a date before 2000' do - get '/1999-01-01' - _(last_response).must_be :not_found? + it "will not process a date before 2000" do + get "/1999-01-01" + _(last_response).must_be(:not_found?) end - it 'will not process an unavailable base' do - get '/latest?base=UAH' - _(last_response).must_be :not_found? + it "will not process an unavailable base" do + get "/latest?base=UAH" + _(last_response).must_be(:not_found?) end - it 'handles malformed queries' do - get '/latest?base=USD?callback=?' - _(last_response).must_be :not_found? + it "handles malformed queries" do + get "/latest?base=USD?callback=?" + _(last_response).must_be(:not_found?) end - it 'does not return stale dates' do + it "does not return stale dates" do Day.db.transaction do - get '/latest' - date = json['date'] + get "/latest" + date = json["date"] Day.latest.delete - get '/latest' - _(json['date']).wont_equal date + get "/latest" + _(json["date"]).wont_equal(date) raise Sequel::Rollback end end diff --git a/spec/helper.rb b/spec/helper.rb index 3264453..89210af 100644 --- a/spec/helper.rb +++ b/spec/helper.rb @@ -1,24 +1,23 @@ # frozen_string_literal: true -ENV['APP_ENV'] ||= 'test' +ENV["APP_ENV"] ||= "test" # Keep SimpleCov at top. -require 'simplecov' +require "simplecov" SimpleCov.start do - add_filter '/spec/' + add_filter "/spec/" end -require_relative '../config/environment' +require_relative "../config/environment" -require 'minitest/autorun' -require 'minitest/around/spec' -require 'minitest/focus' -require 'pry-byebug' -require 'vcr' -require 'webmock' +require "minitest/autorun" +require "minitest/around/spec" +require "minitest/focus" +require "vcr" +require "webmock" VCR.configure do |c| - c.cassette_library_dir = 'spec/vcr_cassettes' - c.hook_into :webmock + c.cassette_library_dir = "spec/vcr_cassettes" + c.hook_into(:webmock) end diff --git a/spec/query_spec.rb b/spec/query_spec.rb index 45756b8..be3fa63 100644 --- a/spec/query_spec.rb +++ b/spec/query_spec.rb @@ -1,72 +1,72 @@ # frozen_string_literal: true -require_relative 'helper' -require 'query' +require_relative "helper" +require "query" describe Query do - it 'builds a query hash' do - _(Query.build(date: '2014-01-01')).must_be_kind_of Hash + it "builds a query hash" do + _(Query.build(date: "2014-01-01")).must_be_kind_of(Hash) end - it 'returns given amount' do - query = Query.new(amount: '100') - _(query.amount).must_equal 100.0 + it "returns given amount" do + query = Query.new(amount: "100") + _(query.amount).must_equal(100.0) end - it 'defaults amount to nothing' do + it "defaults amount to nothing" do query = Query.new _(query.amount).must_be_nil end - it 'returns given base' do - query = Query.new(base: 'USD') - _(query.base).must_equal 'USD' + it "returns given base" do + query = Query.new(base: "USD") + _(query.base).must_equal("USD") end - it 'upcases given base' do - query = Query.new(base: 'usd') - _(query.base).must_equal 'USD' + it "upcases given base" do + query = Query.new(base: "usd") + _(query.base).must_equal("USD") end - it 'defaults base to nothing' do + it "defaults base to nothing" do query = Query.new _(query.base).must_be_nil end - it 'aliases base with from' do - query = Query.new(from: 'USD') - _(query.base).must_equal 'USD' + it "aliases base with from" do + query = Query.new(from: "USD") + _(query.base).must_equal("USD") end - it 'returns given symbols' do - query = Query.new(symbols: 'USD,GBP') - _(query.symbols).must_equal %w[USD GBP] + it "returns given symbols" do + query = Query.new(symbols: "USD,GBP") + _(query.symbols).must_equal(["USD", "GBP"]) end - it 'upcases given symbols' do - query = Query.new(symbols: 'usd,gbp') - _(query.symbols).must_equal %w[USD GBP] + it "upcases given symbols" do + query = Query.new(symbols: "usd,gbp") + _(query.symbols).must_equal(["USD", "GBP"]) end - it 'aliases symbols with to' do - query = Query.new(to: 'USD') - _(query.symbols).must_equal ['USD'] + it "aliases symbols with to" do + query = Query.new(to: "USD") + _(query.symbols).must_equal(["USD"]) end - it 'defaults symbols to nothing' do + it "defaults symbols to nothing" do query = Query.new _(query.symbols).must_be_nil end - it 'returns given date' do - date = '2014-01-01' + it "returns given date" do + date = "2014-01-01" query = Query.new(date:) - _(query.date).must_equal Date.parse(date) + _(query.date).must_equal(Date.parse(date)) end - it 'returns given date interval' do - start_date = '2014-01-01' - end_date = '2014-12-31' + it "returns given date interval" do + start_date = "2014-01-01" + end_date = "2014-12-31" query = Query.new(start_date:, end_date:) _(query.date).must_equal((Date.parse(start_date)..Date.parse(end_date))) end diff --git a/spec/quote/base_spec.rb b/spec/quote/base_spec.rb index b1bf2c0..eed7fbe 100644 --- a/spec/quote/base_spec.rb +++ b/spec/quote/base_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require_relative '../helper' -require 'quote/base' +require_relative "../helper" +require "quote/base" module Quote describe Base do @@ -13,83 +13,83 @@ module Quote klass.new(date: Date.today) end - it 'requires data' do - _ { quote.perform }.must_raise NotImplementedError + it "requires data" do + _ { quote.perform }.must_raise(NotImplementedError) end - it 'does not know how to format result' do - _ { quote.formatted }.must_raise NotImplementedError + it "does not know how to format result" do + _ { quote.formatted }.must_raise(NotImplementedError) end - it 'does not know how to generate a cache key' do - _ { quote.cache_key }.must_raise NotImplementedError + it "does not know how to generate a cache key" do + _ { quote.cache_key }.must_raise(NotImplementedError) end - it 'defaults base to Euro' do - _(quote.base).must_equal 'EUR' + it "defaults base to Euro" do + _(quote.base).must_equal("EUR") end - it 'defaults amount to 1' do - _(quote.amount).must_equal 1 + it "defaults amount to 1" do + _(quote.amount).must_equal(1) end - describe 'when given data' do + describe "when given data" do before do def quote.fetch_data [] end end - it 'performs' do + it "performs" do assert quote.perform end - it 'performs only once' do + it "performs only once" do quote.perform refute quote.perform end end - describe 'when rebasing from an unavailable currency' do + describe "when rebasing from an unavailable currency" do let(:date) do - Date.parse('2000-01-01') + Date.parse("2000-01-01") end let(:quote) do - klass.new(date:, base: 'ILS') + klass.new(date:, base: "ILS") end before do def quote.fetch_data - [{ date:, iso_code: 'USD', rate: 1 }] + [{ date:, iso_code: "USD", rate: 1 }] end end - it 'finds nothing' do + it "finds nothing" do quote.perform - _(quote.not_found?).must_equal true + _(quote.not_found?).must_equal(true) end end - describe 'when rebasing and converting to an unavailable currency' do + describe "when rebasing and converting to an unavailable currency" do let(:date) do Date.today end let(:quote) do - klass.new(date:, base: 'USD', symbols: ['FOO']) + klass.new(date:, base: "USD", symbols: ["FOO"]) end before do def quote.fetch_data - [{ date:, iso_code: 'USD', rate: 1 }] + [{ date:, iso_code: "USD", rate: 1 }] end end - it 'finds nothing' do + it "finds nothing" do quote.perform - _(quote.not_found?).must_equal true + _(quote.not_found?).must_equal(true) end end end diff --git a/spec/quote/end_of_day_spec.rb b/spec/quote/end_of_day_spec.rb index ae78675..469abbe 100644 --- a/spec/quote/end_of_day_spec.rb +++ b/spec/quote/end_of_day_spec.rb @@ -1,12 +1,12 @@ # frozen_string_literal: true -require_relative '../helper' -require 'quote/end_of_day' +require_relative "../helper" +require "quote/end_of_day" module Quote describe EndOfDay do let(:date) do - Date.parse('2010-10-10') + Date.parse("2010-10-10") end let(:quote) do @@ -17,66 +17,66 @@ module Quote quote.perform end - it 'returns rates' do - _(quote.formatted[:rates]).wont_be :empty? + it "returns rates" do + _(quote.formatted[:rates]).wont_be(:empty?) end - it 'quotes given date' do - _(Date.parse(quote.formatted[:date])).must_be :<=, date + it "quotes given date" do + _(Date.parse(quote.formatted[:date])).must_be(:<=, date) end - it 'quotes against the Euro' do - _(quote.formatted[:rates].keys).wont_include 'EUR' + it "quotes against the Euro" do + _(quote.formatted[:rates].keys).wont_include("EUR") end - it 'sorts rates' do + it "sorts rates" do rates = quote.formatted[:rates] - _(rates.keys).must_equal rates.keys.sort + _(rates.keys).must_equal(rates.keys.sort) end - it 'has a cache key' do - _(quote.cache_key).wont_be :empty? + it "has a cache key" do + _(quote.cache_key).wont_be(:empty?) end - describe 'given a new base' do + describe "given a new base" do let(:quote) do - EndOfDay.new(date:, base: 'USD') + EndOfDay.new(date:, base: "USD") end - it 'quotes against that base' do - _(quote.formatted[:rates].keys).wont_include 'USD' + it "quotes against that base" do + _(quote.formatted[:rates].keys).wont_include("USD") end - it 'sorts rates' do + it "sorts rates" do rates = quote.formatted[:rates] - _(rates.keys).must_equal rates.keys.sort + _(rates.keys).must_equal(rates.keys.sort) end end - describe 'given symbols' do + describe "given symbols" do let(:quote) do - EndOfDay.new(date:, symbols: %w[USD GBP JPY]) + EndOfDay.new(date:, symbols: ["USD", "GBP", "JPY"]) end - it 'quotes only for those symbols' do + it "quotes only for those symbols" do rates = quote.formatted[:rates] - _(rates.keys).must_include 'USD' - _(rates.keys).wont_include 'CAD' + _(rates.keys).must_include("USD") + _(rates.keys).wont_include("CAD") end - it 'sorts rates' do + it "sorts rates" do rates = quote.formatted[:rates] - _(rates.keys).must_equal rates.keys.sort + _(rates.keys).must_equal(rates.keys.sort) end end - describe 'when given an amount' do + describe "when given an amount" do let(:quote) do EndOfDay.new(date:, amount: 100) end - it 'calculates quotes for that amount' do - _(quote.formatted[:rates]['USD']).must_be :>, 10 + it "calculates quotes for that amount" do + _(quote.formatted[:rates]["USD"]).must_be(:>, 10) end end end diff --git a/spec/quote/interval_spec.rb b/spec/quote/interval_spec.rb index 02b7caf..a590ccb 100644 --- a/spec/quote/interval_spec.rb +++ b/spec/quote/interval_spec.rb @@ -1,12 +1,12 @@ # frozen_string_literal: true -require_relative '../helper' -require 'quote/interval' +require_relative "../helper" +require "quote/interval" module Quote describe Interval do let(:dates) do - (Date.parse('2010-01-01')..Date.parse('2010-12-31')) + (Date.parse("2010-01-01")..Date.parse("2010-12-31")) end let(:quote) do @@ -17,76 +17,76 @@ module Quote quote.perform end - it 'returns rates' do - _(quote.formatted[:rates]).wont_be :empty? + it "returns rates" do + _(quote.formatted[:rates]).wont_be(:empty?) end - it 'quotes given date interval' do - _(Date.parse(quote.formatted[:start_date])).must_be :>=, dates.first - _(Date.parse(quote.formatted[:end_date])).must_be :<=, dates.last + it "quotes given date interval" do + _(Date.parse(quote.formatted[:start_date])).must_be(:>=, dates.first) + _(Date.parse(quote.formatted[:end_date])).must_be(:<=, dates.last) end - it 'quotes against the Euro' do + it "quotes against the Euro" do quote.formatted[:rates].each_value do |rates| - _(rates.keys).wont_include 'EUR' + _(rates.keys).wont_include("EUR") end end - it 'sorts rates' do + it "sorts rates" do quote.formatted[:rates].each_value do |rates| - _(rates.keys).must_equal rates.keys.sort + _(rates.keys).must_equal(rates.keys.sort) end end - it 'has a cache key' do - _(quote.cache_key).wont_be :empty? + it "has a cache key" do + _(quote.cache_key).wont_be(:empty?) end - describe 'given a new base' do + describe "given a new base" do let(:quote) do - Interval.new(date: dates, base: 'USD') + Interval.new(date: dates, base: "USD") end - it 'quotes against that base' do + it "quotes against that base" do quote.formatted[:rates].each_value do |rates| - _(rates.keys).wont_include 'USD' + _(rates.keys).wont_include("USD") end end - it 'sorts rates' do + it "sorts rates" do quote.formatted[:rates].each_value do |rates| - _(rates.keys).must_equal rates.keys.sort + _(rates.keys).must_equal(rates.keys.sort) end end end - describe 'given symbols' do + describe "given symbols" do let(:quote) do - Interval.new(date: dates, symbols: %w[USD GBP JPY]) + Interval.new(date: dates, symbols: ["USD", "GBP", "JPY"]) end - it 'quotes only for those symbols' do + it "quotes only for those symbols" do quote.formatted[:rates].each_value do |rates| - _(rates.keys).must_include 'USD' - _(rates.keys).wont_include 'CAD' + _(rates.keys).must_include("USD") + _(rates.keys).wont_include("CAD") end end - it 'sorts rates' do + it "sorts rates" do quote.formatted[:rates].each_value do |rates| - _(rates.keys).must_equal rates.keys.sort + _(rates.keys).must_equal(rates.keys.sort) end end end - describe 'when given an amount' do + describe "when given an amount" do let(:quote) do Interval.new(date: dates, amount: 100) end - it 'calculates quotes for that amount' do + it "calculates quotes for that amount" do quote.formatted[:rates].each_value do |rates| - _(rates['USD']).must_be :>, 10 + _(rates["USD"]).must_be(:>, 10) end end end diff --git a/spec/roundable_spec.rb b/spec/roundable_spec.rb index 8e89fbd..71409d3 100644 --- a/spec/roundable_spec.rb +++ b/spec/roundable_spec.rb @@ -1,44 +1,44 @@ # frozen_string_literal: true -require_relative 'helper' -require 'roundable' +require_relative "helper" +require "roundable" describe Roundable do include Roundable - it 'rounds values over 5,000 to zero decimal places' do - _(round(5000.123456)).must_equal 5000 + it "rounds values over 5,000 to zero decimal places" do + _(round(5000.123456)).must_equal(5000) end - it 'rounds values over 80 and below 5,000 to two decimal places' do - _(round(80.123456)).must_equal 80.12 - _(round(4999.123456)).must_equal 4999.12 + it "rounds values over 80 and below 5,000 to two decimal places" do + _(round(80.123456)).must_equal(80.12) + _(round(4999.123456)).must_equal(4999.12) end - it 'rounds values over 20 and below 80 to three decimal places' do - _(round(79.123456)).must_equal 79.123 - _(round(20.123456)).must_equal 20.123 + it "rounds values over 20 and below 80 to three decimal places" do + _(round(79.123456)).must_equal(79.123) + _(round(20.123456)).must_equal(20.123) end - it 'rounds values over 1 and below 20 to four decimal places' do - _(round(19.123456)).must_equal 19.1235 - _(round(1.123456)).must_equal 1.1235 + it "rounds values over 1 and below 20 to four decimal places" do + _(round(19.123456)).must_equal(19.1235) + _(round(1.123456)).must_equal(1.1235) end - it 'rounds values below 1 to five decimal places' do - _(round(0.123456)).must_equal 0.12346 + it "rounds values below 1 to five decimal places" do + _(round(0.123456)).must_equal(0.12346) end - it 'rounds values below 0.0001 to six decimal places' do - _(round(0.0000655)).must_equal 0.000066 + it "rounds values below 0.0001 to six decimal places" do + _(round(0.0000655)).must_equal(0.000066) end - it 'conforms to ECB conventions' do + it "conforms to ECB conventions" do skip "We don't conform ¯_(ツ)_/¯" - require 'day' + require "day" rates = Day.all.sample.rates.to_a rates.shuffle.each_value do |rate| - _(round(rate)).must_equal rate + _(round(rate)).must_equal(rate) end end end diff --git a/spec/web/server_spec.rb b/spec/web/server_spec.rb index 228dbf4..bb81f0d 100644 --- a/spec/web/server_spec.rb +++ b/spec/web/server_spec.rb @@ -1,119 +1,119 @@ # frozen_string_literal: true -require_relative '../helper' -require 'rack/test' -require 'web/server' +require_relative "../helper" +require "rack/test" +require "web/server" -describe 'the server' do +describe "the server" do include Rack::Test::Methods let(:app) { Web::Server.freeze } let(:json) { Oj.load(last_response.body) } let(:headers) { last_response.headers } - it 'returns link to docs' do - get '/' - _(json['docs']).wont_be_nil + it "returns link to docs" do + get "/" + _(json["docs"]).wont_be_nil end - it 'returns latest quotes' do - get '/latest' - _(last_response).must_be :ok? + it "returns latest quotes" do + get "/latest" + _(last_response).must_be(:ok?) end - it 'sets base currency' do - get '/latest' + it "sets base currency" do + get "/latest" res = Oj.load(last_response.body) - get '/latest?from=USD' - _(json).wont_equal res + get "/latest?from=USD" + _(json).wont_equal(res) end - it 'sets base amount' do - get '/latest?amount=10' - _(json['rates']['USD']).must_be :>, 10 + it "sets base amount" do + get "/latest?amount=10" + _(json["rates"]["USD"]).must_be(:>, 10) end - it 'filters symbols' do - get '/latest?to=USD' - _(json['rates'].keys).must_equal %w[USD] + it "filters symbols" do + get "/latest?to=USD" + _(json["rates"].keys).must_equal(["USD"]) end - it 'returns historical quotes' do - get '/2012-11-20' - _(json['rates']).wont_be :empty? - _(json['date']).must_equal '2012-11-20' + it "returns historical quotes" do + get "/2012-11-20" + _(json["rates"]).wont_be(:empty?) + _(json["date"]).must_equal("2012-11-20") end - it 'works around holidays' do - get '/2010-01-01' - _(json['rates']).wont_be :empty? + it "works around holidays" do + get "/2010-01-01" + _(json["rates"]).wont_be(:empty?) end - it 'returns an ETag' do - %w[/latest /2012-11-20].each do |path| + it "returns an ETag" do + ["/latest", "/2012-11-20"].each do |path| get path - _(headers['ETag']).wont_be_nil + _(headers["ETag"]).wont_be_nil end end - it 'returns a cache control header' do - %w[/latest /2012-11-20].each do |path| + it "returns a cache control header" do + ["/latest", "/2012-11-20"].each do |path| get path - _(headers['Cache-Control']).wont_be_nil + _(headers["Cache-Control"]).wont_be_nil end end - it 'allows cross-origin requests' do - %w[/ /latest /2012-11-20].each do |path| - header 'Origin', '*' + it "allows cross-origin requests" do + ["/", "/latest", "/2012-11-20"].each do |path| + header "Origin", "*" get path - assert headers.key?('Access-Control-Allow-Methods') + assert headers.key?("Access-Control-Allow-Methods") end end - it 'responds to preflight requests' do - %w[/ /latest /2012-11-20].each do |path| - header 'Origin', '*' - header 'Access-Control-Request-Method', 'GET' - header 'Access-Control-Request-Headers', 'Content-Type' + it "responds to preflight requests" do + ["/", "/latest", "/2012-11-20"].each do |path| + header "Origin", "*" + header "Access-Control-Request-Method", "GET" + header "Access-Control-Request-Headers", "Content-Type" options path - assert headers.key?('Access-Control-Allow-Methods') + assert headers.key?("Access-Control-Allow-Methods") end end - it 'converts an amount' do - get '/latest?from=GBP&to=USD&amount=100' - _(json['rates']['USD']).must_be :>, 100 + it "converts an amount" do + get "/latest?from=GBP&to=USD&amount=100" + _(json["rates"]["USD"]).must_be(:>, 100) end - it 'returns rates for a given period' do - get '/2010-01-01..2010-12-31' - _(json['start_date']).wont_be :empty? - _(json['end_date']).wont_be :empty? - _(json['rates']).wont_be :empty? + it "returns rates for a given period" do + get "/2010-01-01..2010-12-31" + _(json["start_date"]).wont_be(:empty?) + _(json["end_date"]).wont_be(:empty?) + _(json["rates"]).wont_be(:empty?) end - it 'returns rates when given period does not include end date' do - get '/2010-01-01..' - _(json['start_date']).wont_be :empty? - _(json['end_date']).wont_be :empty? - _(json['rates']).wont_be :empty? + it "returns rates when given period does not include end date" do + get "/2010-01-01.." + _(json["start_date"]).wont_be(:empty?) + _(json["end_date"]).wont_be(:empty?) + _(json["rates"]).wont_be(:empty?) end - it 'returns currencies' do - get '/currencies' - _(json['USD']).must_equal 'United States Dollar' + it "returns currencies" do + get "/currencies" + _(json["USD"]).must_equal("United States Dollar") end - it 'handles JSONP' do - get '/latest?callback=foo' - _(last_response.body).must_be :start_with?, '/**/foo' + it "handles JSONP" do + get "/latest?callback=foo" + _(last_response.body).must_be(:start_with?, "/**/foo") end - it 'sets charset to utf-8' do - get '/currencies' - _(last_response.headers['content-type']).must_be :end_with?, 'charset=utf-8' + it "sets charset to utf-8" do + get "/currencies" + _(last_response.headers["content-type"]).must_be(:end_with?, "charset=utf-8") end end