currency-rate 0.4.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +3 -4
- data/README.md +41 -53
- data/VERSION +1 -1
- data/currency-rate.gemspec +92 -78
- data/lib/adapter.rb +37 -83
- data/lib/adapters/crypto/bitfinex_adapter.rb +17 -0
- data/lib/adapters/crypto/bitpay_adapter.rb +14 -0
- data/lib/adapters/crypto/bitstamp_adapter.rb +19 -0
- data/lib/adapters/crypto/btc_china_adapter.rb +11 -0
- data/lib/adapters/crypto/btc_e_adapter.rb +18 -0
- data/lib/adapters/crypto/coinbase_adapter.rb +14 -0
- data/lib/adapters/crypto/huobi_adapter.rb +17 -0
- data/lib/adapters/crypto/kraken_adapter.rb +29 -0
- data/lib/adapters/crypto/localbitcoins_adapter.rb +14 -0
- data/lib/adapters/crypto/okcoin_adapter.rb +19 -0
- data/lib/adapters/fiat/fixer_adapter.rb +16 -0
- data/lib/adapters/fiat/forge_adapter.rb +23 -0
- data/lib/adapters/fiat/yahoo_adapter.rb +35 -0
- data/lib/configuration.rb +21 -0
- data/lib/currency_rate.rb +52 -48
- data/lib/fetcher.rb +71 -0
- data/lib/storage/file_storage.rb +29 -0
- data/lib/storage/serializers/yaml_serializer.rb +15 -0
- data/lib/synchronizer.rb +31 -0
- data/spec/fixtures/adapters/bitfinex_adapter.yml +18 -0
- data/spec/fixtures/adapters/bitpay_adapter.yml +486 -0
- data/spec/fixtures/adapters/bitstamp_adapter.yml +30 -0
- data/spec/fixtures/adapters/btc_china_adapter.yml +11 -0
- data/spec/fixtures/adapters/btce_adapter.yml +60 -0
- data/spec/fixtures/adapters/coinbase_adapter.yml +680 -0
- data/spec/fixtures/adapters/fixer_adapter.yml +34 -0
- data/spec/fixtures/adapters/forge_adapter.yml +75 -0
- data/spec/fixtures/adapters/huobi_adapter.yml +22 -0
- data/spec/fixtures/adapters/kraken_adapter.yml +124 -0
- data/spec/fixtures/adapters/localbitcoins_adapter.yml +381 -0
- data/spec/fixtures/adapters/normalized/bitfinex_adapter.yml +2 -0
- data/spec/fixtures/adapters/normalized/bitpay_adapter.yml +161 -0
- data/spec/fixtures/adapters/normalized/bitstamp_adapter.yml +3 -0
- data/spec/fixtures/adapters/normalized/btc_china_adapter.yml +1 -0
- data/spec/fixtures/adapters/normalized/btce_adapter.yml +5 -0
- data/spec/fixtures/adapters/normalized/coinbase_adapter.yml +680 -0
- data/spec/fixtures/adapters/normalized/fixer_adapter.yml +32 -0
- data/spec/fixtures/adapters/normalized/forge_adapter.yml +16 -0
- data/spec/fixtures/adapters/normalized/huobi_adapter.yml +2 -0
- data/spec/fixtures/adapters/normalized/kraken_adapter.yml +4 -0
- data/spec/fixtures/adapters/normalized/localbitcoins_adapter.yml +57 -0
- data/spec/fixtures/adapters/normalized/okcoin_adapter.yml +4 -0
- data/spec/fixtures/adapters/normalized/yahoo_adapter.yml +160 -0
- data/spec/fixtures/adapters/okcoin_adapter.yml +40 -0
- data/spec/fixtures/adapters/yahoo_adapter.yml +1119 -0
- data/spec/lib/adapter_spec.rb +54 -0
- data/spec/lib/adapters/crypto/bitfinex_adapter_spec.rb +13 -0
- data/spec/lib/adapters/crypto/bitpay_adapter_spec.rb +13 -0
- data/spec/lib/adapters/crypto/bitstamp_adapter_spec.rb +13 -0
- data/spec/lib/adapters/crypto/btc_china_adapter_spec.rb +13 -0
- data/spec/lib/adapters/crypto/btc_e_adapter_spec.rb +13 -0
- data/spec/lib/adapters/crypto/coinbase_adapter_spec.rb +13 -0
- data/spec/lib/adapters/crypto/huobi_adapter_spec.rb +13 -0
- data/spec/lib/adapters/crypto/kraken_adapter_spec.rb +13 -0
- data/spec/lib/adapters/crypto/localbitcoins_adapter_spec.rb +13 -0
- data/spec/lib/adapters/crypto/okcoin_adapter_spec.rb +13 -0
- data/spec/lib/adapters/fiat/fixer_adapter_spec.rb +13 -0
- data/spec/lib/adapters/fiat/forge_adapter_spec.rb +23 -0
- data/spec/lib/adapters/fiat/yahoo_adapter_spec.rb +13 -0
- data/spec/lib/currency_rate_spec.rb +9 -0
- data/spec/lib/fetcher_spec.rb +156 -0
- data/spec/lib/storage/file_storage_spec.rb +38 -0
- data/spec/lib/synchronizer_spec.rb +65 -0
- data/spec/spec_helper.rb +23 -8
- data/spec/support/matchers/eq_any_of.rb +3 -0
- metadata +67 -64
- data/Gemfile.lock +0 -93
- data/lib/core_ext/deep_get.rb +0 -11
- data/lib/crypto_adapter.rb +0 -19
- data/lib/crypto_adapters/average_rate_adapter.rb +0 -54
- data/lib/crypto_adapters/bitfinex_adapter.rb +0 -40
- data/lib/crypto_adapters/bitpay_adapter.rb +0 -33
- data/lib/crypto_adapters/bitstamp_adapter.rb +0 -44
- data/lib/crypto_adapters/btcchina_adapter.rb +0 -19
- data/lib/crypto_adapters/btce_adapter.rb +0 -44
- data/lib/crypto_adapters/coinbase_adapter.rb +0 -23
- data/lib/crypto_adapters/huobi_adapter.rb +0 -40
- data/lib/crypto_adapters/kraken_adapter.rb +0 -42
- data/lib/crypto_adapters/localbitcoins_adapter.rb +0 -30
- data/lib/crypto_adapters/okcoin_adapter.rb +0 -43
- data/lib/fiat_adapter.rb +0 -17
- data/lib/fiat_adapters/fixer_adapter.rb +0 -38
- data/lib/fiat_adapters/yahoo_adapter.rb +0 -51
- data/lib/storage.rb +0 -20
- data/spec/currency_rate_spec.rb +0 -52
- data/spec/fixtures/vcr/exchange_rate_adapters/btc_adapters/average_rate_adapter.yml +0 -567
- data/spec/fixtures/vcr/exchange_rate_adapters/btc_adapters/bitfinex_adapter.yml +0 -121
- data/spec/fixtures/vcr/exchange_rate_adapters/btc_adapters/bitpay_adapter.yml +0 -272
- data/spec/fixtures/vcr/exchange_rate_adapters/btc_adapters/btcchina_adapter.yml +0 -55
- data/spec/fixtures/vcr/exchange_rate_adapters/btc_adapters/btce_adapter.yml +0 -223
- data/spec/fixtures/vcr/exchange_rate_adapters/btc_adapters/coinbase_adapter.yml +0 -96
- data/spec/fixtures/vcr/exchange_rate_adapters/btc_adapters/huobi_adapter.yml +0 -83
- data/spec/fixtures/vcr/exchange_rate_adapters/btc_adapters/kraken_adapter.yml +0 -179
- data/spec/fixtures/vcr/exchange_rate_adapters/btc_adapters/localbitcoins_adapter.yml +0 -133
- data/spec/fixtures/vcr/exchange_rate_adapters/btc_adapters/okcoin_adapter.yml +0 -223
- data/spec/fixtures/vcr/exchange_rate_adapters/fiat_adapters/fixer_adapter.yml +0 -85
- data/spec/fixtures/vcr/exchange_rate_adapters/fiat_adapters/yahoo_adapter.yml +0 -48
- data/spec/lib/crypto_adapter_spec.rb +0 -56
- data/spec/lib/crypto_adapters/average_rate_adapter_spec.rb +0 -46
- data/spec/lib/crypto_adapters/bitfinex_adapter_spec.rb +0 -38
- data/spec/lib/crypto_adapters/bitpay_adapter_spec.rb +0 -40
- data/spec/lib/crypto_adapters/bitstamp_adapter_spec.rb +0 -44
- data/spec/lib/crypto_adapters/btcchina_adapter_spec.rb +0 -36
- data/spec/lib/crypto_adapters/btce_adapter_spec.rb +0 -42
- data/spec/lib/crypto_adapters/coinbase_adapter_spec.rb +0 -39
- data/spec/lib/crypto_adapters/huobi_adapter_spec.rb +0 -38
- data/spec/lib/crypto_adapters/kraken_adapter_spec.rb +0 -38
- data/spec/lib/crypto_adapters/localbitcoins_adapter_spec.rb +0 -36
- data/spec/lib/crypto_adapters/okcoin_adapter_spec.rb +0 -43
- data/spec/lib/fiat_adapters/fixer_adapter_spec.rb +0 -25
- data/spec/lib/fiat_adapters/yahoo_adapter_spec.rb +0 -25
- data/spec/lib/storage_spec.rb +0 -32
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
EXCHANGE_STUB_DOMAIN = "http://exchange.stub.com"
|
4
|
+
|
5
|
+
RESPONSE = {
|
6
|
+
"btc_usd" => 5000,
|
7
|
+
"ltc_usd" => 50,
|
8
|
+
}
|
9
|
+
|
10
|
+
class HashUrlAdapter < CurrencyRate::Adapter
|
11
|
+
FETCH_URL = {
|
12
|
+
"btc_usd" => "#{EXCHANGE_STUB_DOMAIN}/btc_usd",
|
13
|
+
"ltc_usd" => "#{EXCHANGE_STUB_DOMAIN}/ltc_usd",
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
class StringUrlAdapter < CurrencyRate::Adapter
|
18
|
+
FETCH_URL = EXCHANGE_STUB_DOMAIN
|
19
|
+
end
|
20
|
+
|
21
|
+
RSpec.describe CurrencyRate::Adapter do
|
22
|
+
describe "#exchange_data" do
|
23
|
+
context "when FETCH_URL is not defined" do
|
24
|
+
before { @adapter = CurrencyRate::Adapter.instance }
|
25
|
+
|
26
|
+
it "raises an error" do
|
27
|
+
expect { @adapter.exchange_data }.to raise_error("FETCH_URL is not defined!")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "when FETCH_URL is Hash" do
|
32
|
+
before do
|
33
|
+
@adapter = HashUrlAdapter.instance
|
34
|
+
@response_map = Hash[RESPONSE.map { |k, v| [k, { "price" => v } ] }]
|
35
|
+
RESPONSE.each { |k, v| stub_request(:get, "#{EXCHANGE_STUB_DOMAIN}/#{k}").to_return(body: { "price" => v }.to_json) }
|
36
|
+
end
|
37
|
+
|
38
|
+
it "fetches data for each defined pair" do
|
39
|
+
expect(@adapter.exchange_data).to eq(@response_map)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "when FETCH_URL is String" do
|
44
|
+
before do
|
45
|
+
@adapter = StringUrlAdapter.instance
|
46
|
+
stub_request(:get, EXCHANGE_STUB_DOMAIN).to_return(body: RESPONSE.to_json)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "fetches all data from exchange and retruns parsed Hash" do
|
50
|
+
expect(@adapter.exchange_data).to eq(RESPONSE)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe CurrencyRate::BitfinexAdapter do
|
4
|
+
before(:all) { @data, @normalized = data_for :bitfinex }
|
5
|
+
|
6
|
+
before { @adapter = CurrencyRate::BitfinexAdapter.instance }
|
7
|
+
|
8
|
+
describe "#normalize" do
|
9
|
+
it "brings data to canonical form" do
|
10
|
+
expect(@adapter.normalize(@data)).to eq(@normalized)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe CurrencyRate::BitpayAdapter do
|
4
|
+
before(:all) { @data, @normalized = data_for :bitpay }
|
5
|
+
|
6
|
+
before { @adapter = CurrencyRate::BitpayAdapter.instance }
|
7
|
+
|
8
|
+
describe "#normalize" do
|
9
|
+
it "brings data to cannonical form" do
|
10
|
+
expect(@adapter.normalize(@data)).to eq(@normalized)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe CurrencyRate::BitstampAdapter do
|
4
|
+
before(:all) { @data, @normalized = data_for :bitstamp }
|
5
|
+
|
6
|
+
before { @adapter = CurrencyRate::BitstampAdapter.instance }
|
7
|
+
|
8
|
+
describe "#normalize" do
|
9
|
+
it "brings data to cannonical form" do
|
10
|
+
expect(@adapter.normalize(@data)).to eq(@normalized)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe CurrencyRate::BtcChinaAdapter do
|
4
|
+
before(:all) { @data, @normalized = data_for :btc_china }
|
5
|
+
|
6
|
+
before { @adapter = CurrencyRate::BtcChinaAdapter.instance }
|
7
|
+
|
8
|
+
describe "#normalize" do
|
9
|
+
it "brings data to canonical form" do
|
10
|
+
expect(@adapter.normalize(@data)).to eq(@normalized)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe CurrencyRate::BtcEAdapter do
|
4
|
+
before(:all) { @data, @normalized = data_for :btce }
|
5
|
+
|
6
|
+
before { @adapter = CurrencyRate::BtcEAdapter.instance }
|
7
|
+
|
8
|
+
describe "#normalize" do
|
9
|
+
it "brings data to canonical form" do
|
10
|
+
expect(@adapter.normalize(@data)).to eq(@normalized)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe CurrencyRate::CoinbaseAdapter do
|
4
|
+
before(:all) { @data, @normalized = data_for :coinbase }
|
5
|
+
|
6
|
+
before { @adapter = CurrencyRate::CoinbaseAdapter.instance }
|
7
|
+
|
8
|
+
describe "#normalize" do
|
9
|
+
it "brings data to canonical form" do
|
10
|
+
expect(@adapter.normalize(@data)).to eq(@normalized)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe CurrencyRate::HuobiAdapter do
|
4
|
+
before(:all) { @data, @normalized = data_for :huobi }
|
5
|
+
|
6
|
+
before { @adapter = CurrencyRate::HuobiAdapter.instance }
|
7
|
+
|
8
|
+
describe "#normalize" do
|
9
|
+
it "brings data to canonical form" do
|
10
|
+
expect(@adapter.normalize(@data)).to eq(@normalized)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe CurrencyRate::KrakenAdapter do
|
4
|
+
before(:all) { @data, @normalized = data_for :kraken }
|
5
|
+
|
6
|
+
before { @adapter = CurrencyRate::KrakenAdapter.instance }
|
7
|
+
|
8
|
+
describe "#normalize" do
|
9
|
+
it "brings data to canonical form" do
|
10
|
+
expect(@adapter.normalize(@data)).to eq(@normalized)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe CurrencyRate::LocalbitcoinsAdapter do
|
4
|
+
before(:all) { @data, @normalized = data_for :localbitcoins }
|
5
|
+
|
6
|
+
before { @adapter = CurrencyRate::LocalbitcoinsAdapter.instance }
|
7
|
+
|
8
|
+
describe "#normalize" do
|
9
|
+
it "brings data to canonical form" do
|
10
|
+
expect(@adapter.normalize(@data)).to eq(@normalized)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe CurrencyRate::OkcoinAdapter do
|
4
|
+
before(:all) { @data, @normalized = data_for :okcoin }
|
5
|
+
|
6
|
+
before { @adapter = CurrencyRate::OkcoinAdapter.instance }
|
7
|
+
|
8
|
+
describe "#normalize" do
|
9
|
+
it "brings data to canonical form" do
|
10
|
+
expect(@adapter.normalize(@data)).to eq(@normalized)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe CurrencyRate::FixerAdapter do
|
4
|
+
before(:all) { @data, @normalized = data_for :fixer }
|
5
|
+
|
6
|
+
before { @adapter = CurrencyRate::FixerAdapter.instance }
|
7
|
+
|
8
|
+
describe "#normalize" do
|
9
|
+
it "brings data to canonical form" do
|
10
|
+
expect(@adapter.normalize(@data)).to eq(@normalized)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe CurrencyRate::ForgeAdapter do
|
4
|
+
before(:all) { @data, @normalized = data_for :forge }
|
5
|
+
|
6
|
+
before { stub_request(:get, /1forge/).to_return(body: @data) }
|
7
|
+
|
8
|
+
before { @adapter = CurrencyRate::ForgeAdapter.instance }
|
9
|
+
|
10
|
+
describe "#normalize" do
|
11
|
+
it "brings data to canonical form" do
|
12
|
+
expect(@adapter.normalize(@data)).to eq(@normalized)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#exchange_data" do
|
17
|
+
context "when api_key not defined" do
|
18
|
+
it "returns nil" do
|
19
|
+
expect(@adapter.exchange_data).to be_nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe CurrencyRate::YahooAdapter do
|
4
|
+
before(:all) { @data, @normalized = data_for :yahoo }
|
5
|
+
|
6
|
+
before { @adapter = CurrencyRate::YahooAdapter.instance }
|
7
|
+
|
8
|
+
describe "#normalize" do
|
9
|
+
it "brings data to canonical form" do
|
10
|
+
expect(@adapter.normalize(@data)).to eq(@normalized)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe CurrencyRate do
|
4
|
+
it { is_expected.to respond_to(:configure) }
|
5
|
+
it { is_expected.to respond_to(:sync!) }
|
6
|
+
it { is_expected.to respond_to(:fetch_crypto) }
|
7
|
+
it { is_expected.to respond_to(:fetch_fiat) }
|
8
|
+
it { is_expected.to respond_to(:logger) }
|
9
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe CurrencyRate::Fetcher do
|
4
|
+
before do
|
5
|
+
@usd_try = BigDecimal.new("22")
|
6
|
+
@usd_eur = BigDecimal.new("0.8457")
|
7
|
+
@eur_try = @usd_eur / @usd_try
|
8
|
+
@storage_double = double("storage")
|
9
|
+
@fetcher = CurrencyRate::Fetcher.new(storage: @storage_double)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "uses FileStorage by default" do
|
13
|
+
fetcher = CurrencyRate::Fetcher.new
|
14
|
+
expect(fetcher.storage).to be_a(CurrencyRate::FileStorage)
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#fetch_crypto" do
|
18
|
+
before do
|
19
|
+
@from = "BTC"
|
20
|
+
@to = "TRY"
|
21
|
+
@btc_try = BigDecimal.new("3832.5432")
|
22
|
+
@exchange = "Bitstamp"
|
23
|
+
end
|
24
|
+
|
25
|
+
subject { @fetcher.fetch_crypto(@exchange, @from, @to) }
|
26
|
+
|
27
|
+
context "when rates for selected exchange are not available" do
|
28
|
+
before { allow(@storage_double).to receive(:read).with(@exchange).and_return(nil) }
|
29
|
+
|
30
|
+
it { is_expected.to be_nil }
|
31
|
+
end
|
32
|
+
|
33
|
+
context "when pair supported by selected exchange" do
|
34
|
+
before do
|
35
|
+
allow(@storage_double).to receive(:read).with(@exchange).and_return({ "BTC_TRY" => @btc_try })
|
36
|
+
end
|
37
|
+
|
38
|
+
it { is_expected.to eq(@btc_try) }
|
39
|
+
|
40
|
+
it { is_expected.to be_a(BigDecimal) }
|
41
|
+
end
|
42
|
+
|
43
|
+
context "when requested cryptocurrency not supported by selected exchange" do
|
44
|
+
before do
|
45
|
+
allow(@storage_double).to receive(:read).with(@exchange).and_return({ "LTC_TRY" => @btc_try })
|
46
|
+
end
|
47
|
+
|
48
|
+
it { is_expected.to be_nil }
|
49
|
+
end
|
50
|
+
|
51
|
+
context "when requested fiat currency not supported by selected exchange" do
|
52
|
+
context "when selected exchange supports USD" do
|
53
|
+
before do
|
54
|
+
@btc_usd = @btc_try
|
55
|
+
allow(@storage_double).to receive(:read).with(@exchange).and_return({ "BTC_USD" => @btc_usd })
|
56
|
+
end
|
57
|
+
|
58
|
+
context "when any of fiat exchanges supports rate from USD to requested fiat currency" do
|
59
|
+
before do
|
60
|
+
allow(@fetcher).to receive(:fetch_fiat).with("USD", "TRY").and_return(@usd_try)
|
61
|
+
end
|
62
|
+
|
63
|
+
it { is_expected.to eq(@btc_usd * @usd_try) }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "when when selected exchange doesn't support USD" do
|
68
|
+
before do
|
69
|
+
@btc_eur = @btc_try
|
70
|
+
allow(@storage_double).to receive(:read).with(@exchange).and_return({ "BTC_EUR" => @btc_eur })
|
71
|
+
end
|
72
|
+
|
73
|
+
context "when any of fiat exchanges supports rate for one of supported by selected exchange currency" do
|
74
|
+
before do
|
75
|
+
allow(@fetcher).to receive(:fetch_fiat).with("EUR", "TRY").and_return(@eur_try)
|
76
|
+
end
|
77
|
+
|
78
|
+
it { is_expected.to eq(@btc_eur * @eur_try) }
|
79
|
+
end
|
80
|
+
|
81
|
+
context "when none of fiat exchanges support rate for one of supported by selected exchange currency" do
|
82
|
+
before do
|
83
|
+
allow(@fetcher).to receive(:fetch_fiat).with("EUR", "TRY").and_return(nil)
|
84
|
+
end
|
85
|
+
|
86
|
+
it { is_expected.to be_nil }
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "#fetch_fiat" do
|
93
|
+
before do
|
94
|
+
@from = "EUR"
|
95
|
+
@to = "TRY"
|
96
|
+
@fiat_exchanges = ["Yahoo", "Fixer", "Forge"]
|
97
|
+
end
|
98
|
+
|
99
|
+
subject { @fetcher.fetch_fiat(@from, @to) }
|
100
|
+
|
101
|
+
it "uses Yahoo -> Fixer -> Forge priority order" do
|
102
|
+
expect(@storage_double).to receive(:read).with("Yahoo").and_return(nil).ordered
|
103
|
+
expect(@storage_double).to receive(:read).with("Fixer").and_return(nil).ordered
|
104
|
+
expect(@storage_double).to receive(:read).with("Forge").and_return(nil).ordered
|
105
|
+
@fetcher.fetch_fiat("EUR", "TRY")
|
106
|
+
end
|
107
|
+
|
108
|
+
it "uses next exchange if rates for current do not exist" do
|
109
|
+
allow(@storage_double).to receive(:read).with(@fiat_exchanges.first).and_return(nil)
|
110
|
+
expect(@storage_double).to receive(:read).with(@fiat_exchanges[1]).and_return(nil)
|
111
|
+
expect(@storage_double).to receive(:read).with(@fiat_exchanges[2]).and_return(nil)
|
112
|
+
@fetcher.fetch_fiat("EUR", "TRY")
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'when first exchange has "from" currency as an anchor' do
|
116
|
+
before do
|
117
|
+
allow(@storage_double).to receive(:read).with(@fiat_exchanges.first).and_return({ "anchor" => "EUR", "TRY" => @eur_try })
|
118
|
+
end
|
119
|
+
|
120
|
+
it { is_expected.to eq(@eur_try) }
|
121
|
+
end
|
122
|
+
|
123
|
+
context 'when first exchange has "to" currency as an anchor' do
|
124
|
+
before do
|
125
|
+
allow(@storage_double).to receive(:read).with(@fiat_exchanges.first).and_return({ "anchor" => "TRY", "EUR" => (BigDecimal.new(1) / @eur_try).round(16) })
|
126
|
+
end
|
127
|
+
|
128
|
+
it "returns reversed to anchor rate" do
|
129
|
+
expect(subject.round(16)).to eq(@eur_try.round(16))
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
context "when first exchange has different from requested anchor currency" do
|
134
|
+
context "when first exchange has rates for both requested currencies" do
|
135
|
+
before do
|
136
|
+
allow(@storage_double).to receive(:read).with(@fiat_exchanges.first).and_return({
|
137
|
+
"anchor" => "USD",
|
138
|
+
"EUR" => @usd_eur,
|
139
|
+
"TRY" => @usd_try,
|
140
|
+
})
|
141
|
+
end
|
142
|
+
|
143
|
+
it { is_expected.to eq(@eur_try) }
|
144
|
+
end
|
145
|
+
|
146
|
+
context "when first exchange doen't have rates for requested currencies" do
|
147
|
+
before do
|
148
|
+
allow(@storage_double).to receive(:read).with(@fiat_exchanges.first).and_return(nil)
|
149
|
+
expect(@storage_double).to receive(:read).with(@fiat_exchanges[1]).and_return({ "anchor" => "EUR", "TRY" => @eur_try })
|
150
|
+
end
|
151
|
+
|
152
|
+
it { is_expected.to eq(@eur_try) }
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe CurrencyRate::FileStorage do
|
4
|
+
before do
|
5
|
+
@data = { "key" => "value" }
|
6
|
+
@serializer = CurrencyRate::Storage::YAMLSerializer.new
|
7
|
+
@serialized_data = @serializer.serialize(@data)
|
8
|
+
@storage = CurrencyRate::FileStorage.new(serializer: @serializer)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#read" do
|
12
|
+
before do
|
13
|
+
allow(File).to receive(:read).and_return(@serialized_data)
|
14
|
+
allow(File).to receive(:exist?).and_return(true)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "returns deserialized data from file" do
|
18
|
+
expect(@storage.read("exchange")).to eq(@data)
|
19
|
+
end
|
20
|
+
|
21
|
+
context "when exchange file doesn't exist" do
|
22
|
+
before do
|
23
|
+
allow(File).to receive(:read).and_raise(StandardError)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "returns nil" do
|
27
|
+
expect(@storage.read("exchange")).to be_nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#write" do
|
33
|
+
it "writes serialized data to file" do
|
34
|
+
expect(File).to receive(:write).with(kind_of(String), @serialized_data)
|
35
|
+
@storage.write("exchange", @data)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|