diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 8772de41df..ea6d12eabb 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -105,19 +105,6 @@ RSpec/MessageSpies: RSpec/MultipleExpectations: Max: 18 -# Configuration parameters: EnforcedStyle, IgnoreSharedExamples. -# SupportedStyles: always, named_only -RSpec/NamedSubject: - Exclude: - - 'spec/bank/base_spec.rb' - - 'spec/bank/single_currency_spec.rb' - - 'spec/bank/variable_exchange_spec.rb' - - 'spec/currency/loader_spec.rb' - - 'spec/locale_backend/currency_spec.rb' - - 'spec/locale_backend/i18n_spec.rb' - - 'spec/money_spec.rb' - - 'spec/rates_store/memory_spec.rb' - # Configuration parameters: AllowedGroups. RSpec/NestedGroups: Max: 5 @@ -149,15 +136,6 @@ RSpec/StubbedMock: - 'spec/money/formatting_spec.rb' - 'spec/money_spec.rb' -RSpec/SubjectDeclaration: - Exclude: - - 'spec/rates_store/memory_spec.rb' - -RSpec/SubjectStub: - Exclude: - - 'spec/bank/variable_exchange_spec.rb' - - 'spec/currency/loader_spec.rb' - # Configuration parameters: IgnoreNameless, IgnoreSymbolicNames. RSpec/VerifiedDoubles: Exclude: diff --git a/spec/bank/base_spec.rb b/spec/bank/base_spec.rb index a977b228df..f6de49b2a8 100644 --- a/spec/bank/base_spec.rb +++ b/spec/bank/base_spec.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true RSpec.describe Money::Bank::Base do + subject(:bank) { described_class.new } + describe ".instance" do it "is local to one class" do subclass = Class.new(described_class) @@ -35,43 +37,44 @@ def setup describe "#exchange_with" do it "is not implemented" do - expect { subject.exchange_with(Money.new(100, 'USD'), 'EUR') }.to raise_error(NotImplementedError) + expect { bank.exchange_with(Money.new(100, 'USD'), 'EUR') }.to raise_error(NotImplementedError) end end describe "#same_currency?" do it "accepts str/str" do - expect { subject.send(:same_currency?, 'USD', 'EUR') }.not_to raise_error + expect { bank.send(:same_currency?, 'USD', 'EUR') }.not_to raise_error end it "accepts currency/str" do - expect { subject.send(:same_currency?, Money::Currency.wrap('USD'), 'EUR') }.not_to raise_error + expect { bank.send(:same_currency?, Money::Currency.wrap('USD'), 'EUR') }.not_to raise_error end it "accepts str/currency" do - expect { subject.send(:same_currency?, 'USD', Money::Currency.wrap('EUR')) }.not_to raise_error + expect { bank.send(:same_currency?, 'USD', Money::Currency.wrap('EUR')) }.not_to raise_error end it "accepts currency/currency" do - expect { subject.send(:same_currency?, Money::Currency.wrap('USD'), Money::Currency.wrap('EUR')) }.not_to raise_error + expect { bank.send(:same_currency?, Money::Currency.wrap('USD'), Money::Currency.wrap('EUR')) }.not_to raise_error end it "returns true when currencies match" do - expect(subject.send(:same_currency?, 'USD', 'USD')).to be true - expect(subject.send(:same_currency?, Money::Currency.wrap('USD'), 'USD')).to be true - expect(subject.send(:same_currency?, 'USD', Money::Currency.wrap('USD'))).to be true - expect(subject.send(:same_currency?, Money::Currency.wrap('USD'), Money::Currency.wrap('USD'))).to be true + expect(bank.send(:same_currency?, 'USD', 'USD')).to be true + expect(bank.send(:same_currency?, Money::Currency.wrap('USD'), 'USD')).to be true + expect(bank.send(:same_currency?, 'USD', Money::Currency.wrap('USD'))).to be true + expect(bank.send(:same_currency?, Money::Currency.wrap('USD'), Money::Currency.wrap('USD'))).to be true end it "returns false when currencies do not match" do - expect(subject.send(:same_currency?, 'USD', 'EUR')).to be false - expect(subject.send(:same_currency?, Money::Currency.wrap('USD'), 'EUR')).to be false - expect(subject.send(:same_currency?, 'USD', Money::Currency.wrap('EUR'))).to be false - expect(subject.send(:same_currency?, Money::Currency.wrap('USD'), Money::Currency.wrap('EUR'))).to be false + expect(bank.send(:same_currency?, 'USD', 'EUR')).to be false + expect(bank.send(:same_currency?, Money::Currency.wrap('USD'), 'EUR')).to be false + expect(bank.send(:same_currency?, 'USD', Money::Currency.wrap('EUR'))).to be false + expect(bank.send(:same_currency?, Money::Currency.wrap('USD'), Money::Currency.wrap('EUR'))).to be false end it "raises an UnknownCurrency error when an unknown currency is passed" do - expect { subject.send(:same_currency?, 'AAA', 'BBB') }.to raise_error(Money::Currency::UnknownCurrency) + expect { bank.send(:same_currency?, 'AAA', 'BBB') } + .to raise_error(Money::Currency::UnknownCurrency) end end end diff --git a/spec/bank/single_currency_spec.rb b/spec/bank/single_currency_spec.rb index 96d14f80ff..369736395a 100644 --- a/spec/bank/single_currency_spec.rb +++ b/spec/bank/single_currency_spec.rb @@ -1,10 +1,12 @@ # frozen_string_literal: true RSpec.describe Money::Bank::SingleCurrency do + subject(:bank) { described_class.new } + describe "#exchange_with" do it "raises when called" do expect do - subject.exchange_with(Money.new(100, 'USD'), 'EUR') + bank.exchange_with(Money.new(100, "USD"), "EUR") end.to raise_error(Money::Bank::DifferentCurrencyError, "No exchanging of currencies allowed: 1.00 USD to EUR") end end diff --git a/spec/bank/variable_exchange_spec.rb b/spec/bank/variable_exchange_spec.rb index 8f693637c2..34fa6206eb 100644 --- a/spec/bank/variable_exchange_spec.rb +++ b/spec/bank/variable_exchange_spec.rb @@ -4,6 +4,8 @@ require 'yaml' RSpec.describe Money::Bank::VariableExchange do + subject(:bank) { described_class.new } + describe "#initialize" do context "without &block" do let(:bank) do @@ -108,87 +110,87 @@ describe "#add_rate" do it 'delegates to store#add_rate' do - expect(subject.store).to receive(:add_rate).with('USD', 'EUR', 1.25).and_return 1.25 - expect(subject.add_rate('USD', 'EUR', 1.25)).to be 1.25 + expect(bank.store).to receive(:add_rate).with('USD', 'EUR', 1.25).and_return 1.25 + expect(bank.add_rate('USD', 'EUR', 1.25)).to be 1.25 end it "adds rates with correct ISO codes" do - expect(subject.store).to receive(:add_rate).with('USD', 'EUR', 0.788332676) - subject.add_rate("USD", "EUR", 0.788332676) + expect(bank.store).to receive(:add_rate).with('USD', 'EUR', 0.788332676) + bank.add_rate("USD", "EUR", 0.788332676) - expect(subject.store).to receive(:add_rate).with('EUR', 'JPY', 122.631477) - subject.add_rate("EUR", "YEN", 122.631477) + expect(bank.store).to receive(:add_rate).with('EUR', 'JPY', 122.631477) + bank.add_rate("EUR", "YEN", 122.631477) end it "treats currency names case-insensitively" do - subject.add_rate("usd", "eur", 1) - expect(subject.get_rate('USD', 'EUR')).to eq 1 + bank.add_rate("usd", "eur", 1) + expect(bank.get_rate('USD', 'EUR')).to eq 1 end end describe "#set_rate" do it 'delegates to store#add_rate' do - expect(subject.store).to receive(:add_rate).with('USD', 'EUR', 1.25).and_return 1.25 - expect(subject.set_rate('USD', 'EUR', 1.25)).to be 1.25 + expect(bank.store).to receive(:add_rate).with('USD', 'EUR', 1.25).and_return 1.25 + expect(bank.set_rate('USD', 'EUR', 1.25)).to be 1.25 end it "sets a rate" do - subject.set_rate('USD', 'EUR', 1.25) - expect(subject.store.get_rate('USD', 'EUR')).to eq 1.25 + bank.set_rate('USD', 'EUR', 1.25) + expect(bank.store.get_rate('USD', 'EUR')).to eq 1.25 end it "raises an UnknownCurrency error when an unknown currency is passed" do - expect { subject.set_rate('AAA', 'BBB', 1.25) }.to raise_error(Money::Currency::UnknownCurrency) + expect { bank.set_rate('AAA', 'BBB', 1.25) }.to raise_error(Money::Currency::UnknownCurrency) end end describe "#get_rate" do it "returns a rate" do - subject.set_rate('USD', 'EUR', 1.25) - expect(subject.get_rate('USD', 'EUR')).to eq 1.25 + bank.set_rate('USD', 'EUR', 1.25) + expect(bank.get_rate('USD', 'EUR')).to eq 1.25 end it "raises an UnknownCurrency error when an unknown currency is passed" do - expect { subject.get_rate('AAA', 'BBB') }.to raise_error(Money::Currency::UnknownCurrency) + expect { bank.get_rate('AAA', 'BBB') }.to raise_error(Money::Currency::UnknownCurrency) end it "delegates options to store, options are a no-op" do - expect(subject.store).to receive(:get_rate).with('USD', 'EUR') - subject.get_rate('USD', 'EUR') + expect(bank.store).to receive(:get_rate).with('USD', 'EUR') + bank.get_rate('USD', 'EUR') end end describe "#export_rates" do before do - subject.set_rate('USD', 'EUR', 1.25) - subject.set_rate('USD', 'JPY', 2.55) + bank.set_rate('USD', 'EUR', 1.25) + bank.set_rate('USD', 'JPY', 2.55) @rates = { "USD_TO_EUR" => 1.25, "USD_TO_JPY" => 2.55 } end context "with format == :json" do it "returns rates formatted as json" do - json = subject.export_rates(:json) + json = bank.export_rates(:json) expect(JSON.load(json)).to eq @rates end end context "with format == :ruby" do it "returns rates formatted as ruby objects" do - expect(Marshal.load(subject.export_rates(:ruby))).to eq @rates + expect(Marshal.load(bank.export_rates(:ruby))).to eq @rates end end context "with format == :yaml" do it "returns rates formatted as yaml" do - yaml = subject.export_rates(:yaml) + yaml = bank.export_rates(:yaml) expect(YAML.load(yaml)).to eq @rates end end context "with unknown format" do it "raises Money::Bank::UnknownRateFormat" do - expect { subject.export_rates(:foo) }.to raise_error Money::Bank::UnknownRateFormat + expect { bank.export_rates(:foo) }.to raise_error Money::Bank::UnknownRateFormat end end @@ -198,13 +200,13 @@ expect(File).to receive(:open).with('null', 'w').and_yield(f) expect(f).to receive(:write).with(JSON.dump(@rates)) - subject.export_rates(:json, 'null') + bank.export_rates(:json, 'null') end end it "delegates execution to store, options are a no-op" do - expect(subject.store).to receive(:transaction) - subject.export_rates(:yaml, nil, foo: 1) + expect(bank.store).to receive(:transaction) + bank.export_rates(:yaml, nil, foo: 1) end end @@ -212,9 +214,9 @@ context "with format == :json" do it "loads the rates provided" do s = '{"USD_TO_EUR":1.25,"USD_TO_JPY":2.55}' - subject.import_rates(:json, s) - expect(subject.get_rate('USD', 'EUR')).to eq 1.25 - expect(subject.get_rate('USD', 'JPY')).to eq 2.55 + bank.import_rates(:json, s) + expect(bank.get_rate('USD', 'EUR')).to eq 1.25 + expect(bank.get_rate('USD', 'JPY')).to eq 2.55 end end @@ -222,55 +224,58 @@ let(:dump) { Marshal.dump({ "USD_TO_EUR" => 1.25, "USD_TO_JPY" => 2.55 }) } it "loads the rates provided" do - subject.import_rates(:ruby, dump) + bank.import_rates(:ruby, dump) - expect(subject.get_rate('USD', 'EUR')).to eq 1.25 - expect(subject.get_rate('USD', 'JPY')).to eq 2.55 + expect(bank.get_rate('USD', 'EUR')).to eq 1.25 + expect(bank.get_rate('USD', 'JPY')).to eq 2.55 end + # rubocop:disable RSpec/SubjectStub it "prints a warning" do - allow(subject).to receive(:warn) + allow(bank).to receive(:warn) - subject.import_rates(:ruby, dump) + bank.import_rates(:ruby, dump) - expect(subject) + expect(bank) .to have_received(:warn) .with(include('[WARNING] Using :ruby format when importing rates is potentially unsafe')) end + # rubocop:enable RSpec/SubjectStub end context "with format == :yaml" do it "loads the rates provided" do s = "--- \nUSD_TO_EUR: 1.25\nUSD_TO_JPY: 2.55\n" - subject.import_rates(:yaml, s) - expect(subject.get_rate('USD', 'EUR')).to eq 1.25 - expect(subject.get_rate('USD', 'JPY')).to eq 2.55 + bank.import_rates(:yaml, s) + expect(bank.get_rate('USD', 'EUR')).to eq 1.25 + expect(bank.get_rate('USD', 'JPY')).to eq 2.55 end end context "with unknown format" do it "raises Money::Bank::UnknownRateFormat" do - expect { subject.import_rates(:foo, "") }.to raise_error Money::Bank::UnknownRateFormat + expect { bank.import_rates(:foo, "") } + .to raise_error Money::Bank::UnknownRateFormat end end it "delegates execution to store#transaction" do - expect(subject.store).to receive(:transaction) + expect(bank.store).to receive(:transaction) s = "--- \nUSD_TO_EUR: 1.25\nUSD_TO_JPY: 2.55\n" - subject.import_rates(:yaml, s, foo: 1) + bank.import_rates(:yaml, s, foo: 1) end end describe "#marshal_dump" do it "does not raise an error" do - expect { Marshal.dump(subject) }.not_to raise_error + expect { Marshal.dump(bank) }.not_to raise_error end it "works with Marshal.load" do - bank = Marshal.load(Marshal.dump(subject)) + new_bank = Marshal.load(Marshal.dump(bank)) - expect(bank.rates).to eq subject.rates - expect(bank.rounding_method).to eq subject.rounding_method + expect(new_bank.rates).to eq bank.rates + expect(new_bank.rounding_method).to eq bank.rounding_method end end end diff --git a/spec/currency/loader_spec.rb b/spec/currency/loader_spec.rb index e2bd669f3e..6107da5150 100644 --- a/spec/currency/loader_spec.rb +++ b/spec/currency/loader_spec.rb @@ -2,12 +2,12 @@ RSpec.describe Money::Currency::Loader do it "returns a currency table hash" do - expect(subject.load_currencies).to be_a Hash + expect(described_class.load_currencies).to be_a Hash end it "parse currency_iso.json & currency_non_iso.json & currency_backwards_compatible.json" do - expect(subject).to receive(:parse_currency_file).exactly(3).times.and_return({}) + expect(described_class).to receive(:parse_currency_file).exactly(3).times.and_return({}) - subject.load_currencies + described_class.load_currencies end end diff --git a/spec/locale_backend/currency_spec.rb b/spec/locale_backend/currency_spec.rb index 5c86573df7..5b93a5893d 100644 --- a/spec/locale_backend/currency_spec.rb +++ b/spec/locale_backend/currency_spec.rb @@ -1,19 +1,21 @@ # frozen_string_literal: true RSpec.describe Money::LocaleBackend::Currency do + subject(:backend) { described_class.new } + describe '#lookup' do let(:currency) { Money::Currency.new('EUR') } it 'returns thousands_separator as defined in currency' do - expect(subject.lookup(:thousands_separator, currency)).to eq('.') + expect(backend.lookup(:thousands_separator, currency)).to eq('.') end it 'returns decimal_mark based as defined in currency' do - expect(subject.lookup(:decimal_mark, currency)).to eq(',') + expect(backend.lookup(:decimal_mark, currency)).to eq(',') end it 'returns format based as defined in currency' do - expect(subject.lookup(:format, currency)).to be_nil + expect(backend.lookup(:format, currency)).to be_nil end end end diff --git a/spec/locale_backend/i18n_spec.rb b/spec/locale_backend/i18n_spec.rb index 66a1f2099e..10abae6b53 100644 --- a/spec/locale_backend/i18n_spec.rb +++ b/spec/locale_backend/i18n_spec.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true RSpec.describe Money::LocaleBackend::I18n do + subject(:backend) { described_class.new } + describe '#initialize' do it 'raises an error when I18n is not defined' do hide_const('I18n') @@ -10,8 +12,6 @@ end describe '#lookup' do - subject { described_class.new } - after do I18n.locale = :en end @@ -25,19 +25,19 @@ end it 'returns thousands_separator based on the current locale' do - expect(subject.lookup(:thousands_separator, nil)).to eq('.') + expect(backend.lookup(:thousands_separator, nil)).to eq('.') end it 'returns decimal_mark based on the current locale' do - expect(subject.lookup(:decimal_mark, nil)).to eq(',') + expect(backend.lookup(:decimal_mark, nil)).to eq(',') end it 'returns symbol based on the current locale' do - expect(subject.lookup(:symbol, nil)).to eq('$') + expect(backend.lookup(:symbol, nil)).to eq('$') end it 'returns format based on the current locale' do - expect(subject.lookup(:format, nil)).to eq('%u%n') + expect(backend.lookup(:format, nil)).to eq('%u%n') end end @@ -48,29 +48,29 @@ end it 'returns thousands_separator based on the current locale' do - expect(subject.lookup(:thousands_separator, nil)).to eq('.') + expect(backend.lookup(:thousands_separator, nil)).to eq('.') end it 'returns decimal_mark based on the current locale' do - expect(subject.lookup(:decimal_mark, nil)).to eq(',') + expect(backend.lookup(:decimal_mark, nil)).to eq(',') end end context 'with no translation defined' do it 'returns thousands_separator based on the current locale' do - expect(subject.lookup(:thousands_separator, nil)).to be_nil + expect(backend.lookup(:thousands_separator, nil)).to be_nil end it 'returns decimal_mark based on the current locale' do - expect(subject.lookup(:decimal_mark, nil)).to be_nil + expect(backend.lookup(:decimal_mark, nil)).to be_nil end it 'returns symbol based on the current locale' do - expect(subject.lookup(:symbol, nil)).to be_nil + expect(backend.lookup(:symbol, nil)).to be_nil end it 'returns format based on the current locale' do - expect(subject.lookup(:format, nil)).to be_nil + expect(backend.lookup(:format, nil)).to be_nil end end end diff --git a/spec/money_spec.rb b/spec/money_spec.rb index ad398d6b5e..98c15eea98 100644 --- a/spec/money_spec.rb +++ b/spec/money_spec.rb @@ -901,12 +901,10 @@ end context "with all zeros" do - subject { Money.us_dollar(100).allocate(arry).map(&:fractional) } - - let(:arry) { [0, 0] } + let(:moneys) { Money.us_dollar(100).allocate([0, 0]) } it "allocates evenly" do - expect(subject).to eq [50, 50] + expect(moneys.map(&:fractional)).to eq [50, 50] end end diff --git a/spec/rates_store/memory_spec.rb b/spec/rates_store/memory_spec.rb index 95413630fa..2ea36a113b 100644 --- a/spec/rates_store/memory_spec.rb +++ b/spec/rates_store/memory_spec.rb @@ -1,62 +1,62 @@ # frozen_string_literal: true RSpec.describe Money::RatesStore::Memory do - let(:subject) { described_class.new } + subject(:store) { described_class.new } describe '#add_rate and #get_rate' do it 'stores rate in memory' do - expect(subject.add_rate('USD', 'CAD', 0.9)).to be 0.9 - expect(subject.get_rate('USD', 'CAD')).to be 0.9 + expect(store.add_rate('USD', 'CAD', 0.9)).to be 0.9 + expect(store.get_rate('USD', 'CAD')).to be 0.9 end end describe 'add_rate' do it "uses a mutex by default" do - expect(subject.instance_variable_get(:@guard)).to receive(:synchronize) - subject.add_rate('USD', 'EUR', 1.25) + expect(store.instance_variable_get(:@guard)).to receive(:synchronize) + store.add_rate('USD', 'EUR', 1.25) end end describe '#each_rate' do before do - subject.add_rate('USD', 'CAD', 0.9) - subject.add_rate('CAD', 'USD', 1.1) + store.add_rate('USD', 'CAD', 0.9) + store.add_rate('CAD', 'USD', 1.1) end it 'iterates over rates' do - expect { |b| subject.each_rate(&b) }.to yield_successive_args(['USD', 'CAD', 0.9], ['CAD', 'USD', 1.1]) + expect { |b| store.each_rate(&b) }.to yield_successive_args(['USD', 'CAD', 0.9], ['CAD', 'USD', 1.1]) end it 'is an Enumeator' do - expect(subject.each_rate).to be_a(Enumerator) - result = subject.each_rate.with_object({}) { |(from, to, rate), m| m[[from, to].join] = rate } + expect(store.each_rate).to be_a(Enumerator) + result = store.each_rate.with_object({}) { |(from, to, rate), m| m[[from, to].join] = rate } expect(result).to match({ 'USDCAD' => 0.9, 'CADUSD' => 1.1 }) end end describe '#transaction' do it 'uses mutex' do - expect(subject.instance_variable_get('@guard')).to receive(:synchronize) - subject.transaction { 1 + 1 } + expect(store.instance_variable_get('@guard')).to receive(:synchronize) + store.transaction { 1 + 1 } end it 'wraps block in mutex transaction only once' do expect do - subject.transaction do - subject.add_rate('USD', 'CAD', 1) + store.transaction do + store.add_rate('USD', 'CAD', 1) end end.not_to raise_error end end describe '#marshal_dump' do - let(:subject) { described_class.new(optional: true) } + subject(:store) { described_class.new(optional: true) } it 'can reload' do - bank = Money::Bank::VariableExchange.new(subject) + bank = Money::Bank::VariableExchange.new(store) bank = Marshal.load(Marshal.dump(bank)) - expect(bank.store.instance_variable_get(:@options)).to eq subject.instance_variable_get(:@options) - expect(bank.store.instance_variable_get(:@index)).to eq subject.instance_variable_get(:@index) + expect(bank.store.instance_variable_get(:@options)).to eq store.instance_variable_get(:@options) + expect(bank.store.instance_variable_get(:@index)).to eq store.instance_variable_get(:@index) end end end