currency-rate 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|