currency-rate 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +91 -0
- data/LICENSE.txt +20 -0
- data/README.md +52 -0
- data/Rakefile +24 -0
- data/VERSION +1 -0
- data/currency-rate.gemspec +95 -0
- data/lib/adapter.rb +42 -0
- data/lib/btc_adapter.rb +17 -0
- data/lib/btc_adapters/average_rate_adapter.rb +50 -0
- data/lib/btc_adapters/bitpay_adapter.rb +18 -0
- data/lib/btc_adapters/bitstamp_adapter.rb +14 -0
- data/lib/btc_adapters/btce_adapter.rb +14 -0
- data/lib/btc_adapters/coinbase_adapter.rb +13 -0
- data/lib/btc_adapters/kraken_adapter.rb +14 -0
- data/lib/btc_adapters/localbitcoins_adapter.rb +13 -0
- data/lib/btc_adapters/okcoin_adapter.rb +14 -0
- data/lib/core_ext/classify.rb +7 -0
- data/lib/core_ext/deep_get.rb +11 -0
- data/lib/currency_rate.rb +49 -0
- data/lib/fiat_adapter.rb +30 -0
- data/lib/fiat_adapters/fixer_adapter.rb +11 -0
- data/lib/fiat_adapters/yahoo_adapter.rb +22 -0
- data/lib/storage.rb +17 -0
- data/spec/currency_rate_spec.rb +28 -0
- data/spec/lib/btc_adapter_spec.rb +55 -0
- data/spec/lib/btc_adapters/average_rate_adapter_spec.rb +51 -0
- data/spec/lib/btc_adapters/bitpay_adapter_spec.rb +35 -0
- data/spec/lib/btc_adapters/bitstamp_adapter_spec.rb +35 -0
- data/spec/lib/btc_adapters/btce_adapter_spec.rb +35 -0
- data/spec/lib/btc_adapters/coinbase_adapter_spec.rb +35 -0
- data/spec/lib/btc_adapters/kraken_adapter_spec.rb +35 -0
- data/spec/lib/btc_adapters/localbitcoins_adapter_spec.rb +35 -0
- data/spec/lib/btc_adapters/okcoin_adapter_spec.rb +35 -0
- data/spec/lib/fiat_adapters/fixer_adapter_spec.rb +22 -0
- data/spec/lib/fiat_adapters/yahoo_adapter_spec.rb +22 -0
- data/spec/lib/storage_spec.rb +25 -0
- data/spec/spec_helper.rb +13 -0
- metadata +169 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
module CurrencyRate
|
2
|
+
class BitstampAdapter < BtcAdapter
|
3
|
+
|
4
|
+
FETCH_URL = 'https://www.bitstamp.net/api/ticker/'
|
5
|
+
|
6
|
+
def rate_for(currency_code)
|
7
|
+
super
|
8
|
+
raise CurrencyNotSupported if currency_code != 'USD'
|
9
|
+
rate = get_rate_value_from_hash(@rates, "last")
|
10
|
+
rate_to_f(rate)
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module CurrencyRate
|
2
|
+
class BtceAdapter < BtcAdapter
|
3
|
+
|
4
|
+
FETCH_URL = 'https://btc-e.com/api/2/btc_usd/ticker'
|
5
|
+
|
6
|
+
def rate_for(currency_code)
|
7
|
+
super
|
8
|
+
raise CurrencyNotSupported if !FETCH_URL.include?("btc_#{currency_code.downcase}")
|
9
|
+
rate = get_rate_value_from_hash(@rates, 'ticker', 'last')
|
10
|
+
rate_to_f(rate)
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module CurrencyRate
|
2
|
+
class CoinbaseAdapter < BtcAdapter
|
3
|
+
|
4
|
+
FETCH_URL = 'https://coinbase.com/api/v1/currencies/exchange_rates'
|
5
|
+
|
6
|
+
def rate_for(currency_code)
|
7
|
+
super
|
8
|
+
rate = get_rate_value_from_hash(@rates, "btc_to_#{currency_code.downcase}")
|
9
|
+
rate_to_f(rate)
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module CurrencyRate
|
2
|
+
class KrakenAdapter < BtcAdapter
|
3
|
+
|
4
|
+
FETCH_URL = 'https://api.kraken.com/0/public/Ticker?pair=xbtusd'
|
5
|
+
|
6
|
+
def rate_for(currency_code)
|
7
|
+
super
|
8
|
+
rate = get_rate_value_from_hash(@rates, 'result', 'XXBTZ' + currency_code.upcase, 'c')
|
9
|
+
rate = rate.kind_of?(Array) ? rate.first : raise(CurrencyNotSupported)
|
10
|
+
rate_to_f(rate)
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module CurrencyRate
|
2
|
+
class LocalbitcoinsAdapter < BtcAdapter
|
3
|
+
|
4
|
+
FETCH_URL = 'https://localbitcoins.com/bitcoinaverage/ticker-all-currencies/'
|
5
|
+
|
6
|
+
def rate_for(currency_code)
|
7
|
+
super
|
8
|
+
rate = get_rate_value_from_hash(@rates, currency_code.upcase, 'rates', 'last')
|
9
|
+
rate_to_f(rate)
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module CurrencyRate
|
2
|
+
class OkcoinAdapter < BtcAdapter
|
3
|
+
|
4
|
+
FETCH_URL = 'https://www.okcoin.com/api/ticker.do?ok=1'
|
5
|
+
|
6
|
+
def rate_for(currency_code)
|
7
|
+
super
|
8
|
+
raise CurrencyNotSupported if currency_code != 'USD'
|
9
|
+
rate = get_rate_value_from_hash(@rates, 'ticker', 'last')
|
10
|
+
rate_to_f(rate)
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'bigdecimal'
|
3
|
+
require 'satoshi-unit'
|
4
|
+
require 'open-uri'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
require "adapter"
|
8
|
+
require "btc_adapter"
|
9
|
+
require "fiat_adapter"
|
10
|
+
|
11
|
+
Dir["#{File.expand_path File.dirname(__FILE__)}/**/*.rb"].each { |f| require f }
|
12
|
+
|
13
|
+
module CurrencyRate
|
14
|
+
|
15
|
+
def self.get(adapter_name, currency)
|
16
|
+
adapter_class(adapter_name).rate_for(currency)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.convert(adapter_name, amount:, from:, to:, anchor_currency: nil)
|
20
|
+
a = adapter_class(adapter_name)
|
21
|
+
|
22
|
+
# Setting default values for anchor currency depending on
|
23
|
+
# which adapter type is un use.
|
24
|
+
anchor_currency = if a.kind_of?(BtcAdapter)
|
25
|
+
'BTC' if anchor_currency.nil?
|
26
|
+
else
|
27
|
+
'USD' if anchor_currency.nil?
|
28
|
+
end
|
29
|
+
|
30
|
+
# None of the currencies is anchor currency?
|
31
|
+
# No problem, convert the amount given into the anchor currency first.
|
32
|
+
unless [to, from].include?(anchor_currency)
|
33
|
+
amount = convert(adapter_name, amount: amount, from: from, to: anchor_currency)
|
34
|
+
from = anchor_currency
|
35
|
+
end
|
36
|
+
|
37
|
+
rate = get(a, (from == anchor_currency) ? to : from)
|
38
|
+
result = from == anchor_currency ? amount.to_f*rate : amount.to_f/rate
|
39
|
+
to == 'BTC' ? result : result.round(2)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def self.adapter_class(s)
|
45
|
+
return s unless s.kind_of?(String) # if we pass class, no need to convert
|
46
|
+
adapter = "#{s}_adapter".classify(CurrencyRate).instance
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
data/lib/fiat_adapter.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
module CurrencyRate
|
2
|
+
|
3
|
+
class FiatAdapter < Adapter
|
4
|
+
|
5
|
+
CROSS_RATE_CURRENCY = 'USD'
|
6
|
+
SUPPORTED_CURRENCIES = %w(
|
7
|
+
AUD BGN BRL CAD CHF CNY CZK DKK GBP HKD HRK HUF IDR ILS INR JPY
|
8
|
+
KRW MXN MYR NOK NZD PHP PLN RON RUB SEK SGD THB TRY USD ZAR EUR
|
9
|
+
)
|
10
|
+
DECIMAL_PRECISION = 2
|
11
|
+
|
12
|
+
# Set half-even rounding mode
|
13
|
+
# http://apidock.com/ruby/BigDecimal/mode/class
|
14
|
+
BigDecimal.mode BigDecimal::ROUND_MODE, :banker
|
15
|
+
|
16
|
+
def rate_for(currency_code)
|
17
|
+
return 1 if currency_code == CROSS_RATE_CURRENCY
|
18
|
+
raise CurrencyNotSupported unless SUPPORTED_CURRENCIES.include?(currency_code)
|
19
|
+
super
|
20
|
+
# call 'super' in descendant classes and return real rate
|
21
|
+
end
|
22
|
+
|
23
|
+
def convert_from_currency(amount_in_currency, currency: CROSS_RATE_CURRENCY)
|
24
|
+
return amount_in_currency if currency == CROSS_RATE_CURRENCY
|
25
|
+
amount_in_currency.to_f / rate_for(currency)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module CurrencyRate
|
2
|
+
class FixerAdapter < FiatAdapter
|
3
|
+
FETCH_URL = "http://api.fixer.io/latest?base=#{CROSS_RATE_CURRENCY}"
|
4
|
+
|
5
|
+
def rate_for(currency_code)
|
6
|
+
super
|
7
|
+
rate = get_rate_value_from_hash(@rates, 'rates', currency_code)
|
8
|
+
rate_to_f(rate)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module CurrencyRate
|
4
|
+
class YahooAdapter < FiatAdapter
|
5
|
+
# Example URL (follow to un-shorten): http://goo.gl/62Aedt
|
6
|
+
FETCH_URL = "http://query.yahooapis.com/v1/public/yql?" + URI.encode_www_form(
|
7
|
+
format: 'json',
|
8
|
+
env: "store://datatables.org/alltableswithkeys",
|
9
|
+
q: "SELECT * FROM yahoo.finance.xchange WHERE pair IN" +
|
10
|
+
# The following line is building array string in SQL: '("USDJPY", "USDRUB", ...)'
|
11
|
+
"(#{SUPPORTED_CURRENCIES.map{|x| '"' + CROSS_RATE_CURRENCY.upcase + x.upcase + '"'}.join(',')})"
|
12
|
+
)
|
13
|
+
|
14
|
+
def rate_for(currency_code)
|
15
|
+
super
|
16
|
+
rates = @rates.deep_get('query', 'results', 'rate')
|
17
|
+
rate = rates && rates.find{|x| x['id'] == CROSS_RATE_CURRENCY + currency_code.upcase}
|
18
|
+
rate = rate && rate['Rate']
|
19
|
+
rate_to_f(rate)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/storage.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
module CurrencyRate
|
2
|
+
class Storage
|
3
|
+
|
4
|
+
def initialize(timeout: 1800)
|
5
|
+
@timeout = timeout
|
6
|
+
@mem_storage = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def fetch(key)
|
10
|
+
if @mem_storage[key].nil? || (@mem_storage[key][:timestamp] < (Time.now.to_i - @timeout))
|
11
|
+
@mem_storage[key] = { content: yield, timestamp: Time.now.to_i }
|
12
|
+
end
|
13
|
+
@mem_storage[key][:content]
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CurrencyRate do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
allow(CurrencyRate::BitstampAdapter.instance).to receive('rate_for').with('USD').and_return(550)
|
7
|
+
allow(CurrencyRate::BitstampAdapter.instance).to receive('rate_for').with('RUB').and_return(33100)
|
8
|
+
allow(CurrencyRate::YahooAdapter.instance).to receive('rate_for').with('RUB').and_return(65)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "fetches currency rate from a specified exchange" do
|
12
|
+
expect(CurrencyRate.get('Bitstamp', 'USD')).to eq(550)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "converts one currency into another" do
|
16
|
+
expect(CurrencyRate.convert('Bitstamp', amount: 5, from: 'BTC', to: 'USD')).to eq(2750)
|
17
|
+
expect(CurrencyRate.convert('Bitstamp', amount: 2750, from: 'USD', to: 'BTC')).to eq(5)
|
18
|
+
expect(CurrencyRate.convert('Yahoo', amount: 300, from: 'USD', to: 'RUB')).to eq(19500)
|
19
|
+
expect(CurrencyRate.convert('Yahoo', amount: 19500, from: 'RUB', to: 'USD')).to eq(300)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "converts non-anchor currencies" do
|
23
|
+
expect(CurrencyRate.convert('Bitstamp', amount: 1000, from: 'USD', to: 'RUB')).to eq(60181.82)
|
24
|
+
expect(CurrencyRate.convert('Bitstamp', amount: 60181.81, from: 'RUB', to: 'USD')).to eq(1000)
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe CurrencyRate::BtcAdapter do
|
4
|
+
|
5
|
+
class CurrencyRate::Adapter
|
6
|
+
FETCH_URL = ''
|
7
|
+
end
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
@exchange_adapter = CurrencyRate::BtcAdapter.instance
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "converting currencies" do
|
14
|
+
|
15
|
+
before(:each) do
|
16
|
+
allow(@exchange_adapter).to receive(:fetch_rates!)
|
17
|
+
allow(@exchange_adapter).to receive(:rate_for).with('USD').and_return(450.5412)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "converts amount from currency into BTC" do
|
21
|
+
expect(@exchange_adapter.convert_from_currency(2252.706, currency: 'USD')).to eq(500000000)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "converts from btc into currency" do
|
25
|
+
expect(@exchange_adapter.convert_to_currency(500000000, currency: 'USD')).to eq(2252.706)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "shows btc amounts in various denominations" do
|
29
|
+
expect(@exchange_adapter.convert_from_currency(2252.706, currency: 'USD', btc_denomination: :btc)).to eq(5)
|
30
|
+
expect(@exchange_adapter.convert_to_currency(5, currency: 'USD', btc_denomination: :btc)).to eq(2252.706)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "accepts string as amount and converts it properly" do
|
34
|
+
expect(@exchange_adapter.convert_from_currency('2252.706', currency: 'USD', btc_denomination: :btc)).to eq(5)
|
35
|
+
expect(@exchange_adapter.convert_to_currency('5', currency: 'USD', btc_denomination: :btc)).to eq(2252.706)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
it "when checking for rates, only calls fetch_rates! if they were checked long time ago or never" do
|
41
|
+
uri_mock = double('uri mock')
|
42
|
+
expect(URI).to receive(:parse).and_return(uri_mock).once
|
43
|
+
expect(uri_mock).to receive(:read).and_return('{ "USD": 534.4343 }').once
|
44
|
+
@exchange_adapter.rate_for('USD')
|
45
|
+
@exchange_adapter.rate_for('USD') # not calling fetch_rates! because we've just checked
|
46
|
+
@exchange_adapter.instance_variable_set(:@rates_updated_at, Time.now-1900)
|
47
|
+
@exchange_adapter.rate_for('USD')
|
48
|
+
end
|
49
|
+
|
50
|
+
it "raises exception if rate is nil" do
|
51
|
+
rate = nil
|
52
|
+
expect( -> { @exchange_adapter.rate_to_f(rate) }).to raise_error(CurrencyRate::Adapter::CurrencyNotSupported)
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe CurrencyRate::AverageRateAdapter do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
VCR.insert_cassette 'exchange_rate_adapters/btc_adapters/average_rate_adapter'
|
7
|
+
end
|
8
|
+
|
9
|
+
after :all do
|
10
|
+
VCR.eject_cassette
|
11
|
+
end
|
12
|
+
|
13
|
+
before(:each) do
|
14
|
+
@average_rates_adapter = CurrencyRate::AverageRateAdapter.instance(
|
15
|
+
CurrencyRate::BitstampAdapter,
|
16
|
+
CurrencyRate::BitpayAdapter.instance,
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "calculates average rate" do
|
21
|
+
json_response_bistamp = '{"high": "232.89", "last": "100", "timestamp": "1423457015", "bid": "224.00", "vwap": "224.57", "volume": "14810.41127494", "low": "217.28", "ask": "224.13"}'
|
22
|
+
json_response_bitpay = '[{"code":"USD","name":"US Dollar","rate":200},{"code":"EUR","name":"Eurozone Euro","rate":197.179544}]'
|
23
|
+
uri_mock = double('uri mock')
|
24
|
+
allow(uri_mock).to receive(:read).with(read_timeout: 4).and_return(json_response_bistamp, json_response_bitpay)
|
25
|
+
allow(URI).to receive(:parse).and_return(uri_mock)
|
26
|
+
expect(@average_rates_adapter.rate_for('USD')).to eq 150
|
27
|
+
end
|
28
|
+
|
29
|
+
it "fetches rates for all adapters" do
|
30
|
+
expect(@average_rates_adapter.fetch_rates!).not_to be_empty
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'raises error if all adapters failed to fetch rates' do
|
34
|
+
adapter_mocks = [double('adapter_1'), double('adapter_2')]
|
35
|
+
adapter_mocks.each do |adapter|
|
36
|
+
expect(adapter).to receive(:fetch_rates!).and_raise(CurrencyRate::Adapter::FetchingFailed)
|
37
|
+
end
|
38
|
+
average_rates_adapter = CurrencyRate::AverageRateAdapter.instance(*adapter_mocks)
|
39
|
+
expect( -> { average_rates_adapter.fetch_rates! }).to raise_error(CurrencyRate::Adapter::FetchingFailed)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "raises exception if all adapters fail to get rates" do
|
43
|
+
expect( -> { @average_rates_adapter.rate_for('FEDcoin') }).to raise_error(CurrencyRate::Adapter::CurrencyNotSupported)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "raises exception if unallowed method is called" do # fetch_rates! is not to be used in AverageRateAdapter itself
|
47
|
+
expect( -> { @average_rates_adapter.get_rate_value_from_hash(nil, 'nothing') }).to raise_error("This method is not supposed to be used in #{@average_rates_adapter.class}.")
|
48
|
+
expect( -> { @average_rates_adapter.rate_to_f(nil) }).to raise_error("This method is not supposed to be used in #{@average_rates_adapter.class}.")
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe CurrencyRate::BitpayAdapter do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
VCR.insert_cassette 'exchange_rate_adapters/btc_adapters/bitpay_adapter.yml'
|
7
|
+
end
|
8
|
+
|
9
|
+
after :all do
|
10
|
+
VCR.eject_cassette
|
11
|
+
end
|
12
|
+
|
13
|
+
before(:each) do
|
14
|
+
@exchange_adapter = CurrencyRate::BitpayAdapter.instance
|
15
|
+
end
|
16
|
+
|
17
|
+
it "finds the rate for currency code" do
|
18
|
+
expect(@exchange_adapter.rate_for('USD')).to be_kind_of(Float)
|
19
|
+
expect( -> { @exchange_adapter.rate_for('FEDcoin') }).to raise_error(CurrencyRate::Adapter::CurrencyNotSupported)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "raises exception if rate is nil" do
|
23
|
+
json_response_1 = '[{},{}]'
|
24
|
+
json_response_2 = '[{"code":"USD","name":"US Dollar","rat":223.59},{"code":"EUR","name":"Eurozone Euro","rate":197.179544}]'
|
25
|
+
json_response_3 = '[{"code":"USD","name":"US Dollar","rate":null},{"code":"EUR","name":"Eurozone Euro","rate":197.179544}]'
|
26
|
+
uri_mock = double('uri mock')
|
27
|
+
allow(uri_mock).to receive(:read).with(read_timeout: 4).and_return(json_response_1, json_response_2, json_response_3)
|
28
|
+
allow(URI).to receive(:parse).and_return(uri_mock)
|
29
|
+
3.times do
|
30
|
+
@exchange_adapter.fetch_rates!
|
31
|
+
expect( -> { @exchange_adapter.rate_for('USD') }).to raise_error(CurrencyRate::Adapter::CurrencyNotSupported)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe CurrencyRate::BitstampAdapter do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
VCR.insert_cassette 'exchange_rate_adapters/btc_adapters/bitstamp_adapter'
|
7
|
+
end
|
8
|
+
|
9
|
+
after :all do
|
10
|
+
VCR.eject_cassette
|
11
|
+
end
|
12
|
+
|
13
|
+
before(:each) do
|
14
|
+
@exchange_adapter = CurrencyRate::BitstampAdapter.instance
|
15
|
+
end
|
16
|
+
|
17
|
+
it "finds the rate for currency code" do
|
18
|
+
expect(@exchange_adapter.rate_for('USD')).to be_kind_of(Float)
|
19
|
+
expect( -> { @exchange_adapter.rate_for('FEDcoin') }).to raise_error(CurrencyRate::Adapter::CurrencyNotSupported)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "raises exception if rate is nil" do
|
23
|
+
json_response_1 = '{}'
|
24
|
+
json_response_2 = '{"high": "232.89", "list": "224.13", "timestamp": "1423457015", "bid": "224.00", "vwap": "224.57", "volume": "14810.41127494", "low": "217.28", "ask": "224.13"}'
|
25
|
+
json_response_3 = '{"high": "232.89", "last": null, "timestamp": "1423457015", "bid": "224.00", "vwap": "224.57", "volume": "14810.41127494", "low": "217.28", "ask": "224.13"}'
|
26
|
+
uri_mock = double('uri mock')
|
27
|
+
allow(uri_mock).to receive(:read).with(read_timeout: 4).and_return(json_response_1, json_response_2, json_response_3)
|
28
|
+
allow(URI).to receive(:parse).and_return(uri_mock)
|
29
|
+
3.times do
|
30
|
+
@exchange_adapter.fetch_rates!
|
31
|
+
expect( -> { @exchange_adapter.rate_for('USD') }).to raise_error(CurrencyRate::Adapter::CurrencyNotSupported)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|