] containing the URL to image of the currency
38 | def currencies(table_rows)
39 | table_rows.lazy.map do |e|
40 | e.css('img').map { |img| img.attribute('src').value }
41 | end.force.flatten
42 | end
43 |
44 | # Extract the text descriping the exchange rates from content nodes
45 | # @return [Array] text description for buy/sell rates
46 | def rates(table_rows)
47 | table_rows.map do |e|
48 | e.css('.content').map(&:text).map(&:strip).map do |txt|
49 | txt.split("\n").map(&:strip)
50 | end
51 | end
52 | end
53 |
54 | # Parse the #raw_exchange_rates returned in response
55 | # @param [Array] of the raw_data scraped
56 | # @return [Hash] of exchange rates for selling and buying
57 | # {
58 | # { sell: { SYM: rate }, { SYM: rate }, ... },
59 | # { buy: { SYM: rate }, { SYM: rate }, ... }
60 | # }
61 | def parse(raw_data)
62 | raw_data.each_with_object(sell: {}, buy: {}) do |row, result|
63 | currency = currency_symbol(row[0])
64 | sell_rate = row[1][0][1][5..-1].to_f
65 | buy_rate = row[1][0][0][4..-1].to_f
66 |
67 | result[:sell][currency] = sell_rate
68 | result[:buy][currency] = buy_rate
69 | end
70 | end
71 | end
72 | end
73 |
--------------------------------------------------------------------------------
/lib/egp_rates/cib.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | module EGPRates
3 | # Commercial International Bank (CIB)
4 | class CIB < EGPRates::Bank
5 | def initialize
6 | @sym = :CIB
7 | @uri = URI.parse('http://www.cibeg.com/_layouts/15/LINKDev.CIB.CurrenciesFunds/FundsCurrencies.aspx/GetCurrencies')
8 | end
9 |
10 | # @return [Hash] of exchange rates for selling and buying
11 | # {
12 | # { sell: { SYM: rate }, { SYM: rate }, ... },
13 | # { buy: { SYM: rate }, { SYM: rate }, ... }
14 | # }
15 | def exchange_rates
16 | @exchange_rates ||= parse(raw_exchange_rates)
17 | end
18 |
19 | private
20 |
21 | # Send the request to URL and return the JSON response
22 | # @return [Hash] JSON response of the exchange rates
23 | # {
24 | # "d"=> [
25 | # {
26 | # "__type"=>"LINKDev.CIB.CurrenciesFunds.CIBFund.CurrencyObject",
27 | # "CurrencyID"=>"USD",
28 | # "BuyRate"=>15.9,
29 | # "SellRate"=>16.05
30 | # }, {
31 | # "__type"=>"LINKDev.CIB.CurrenciesFunds.CIBFund.CurrencyObject",
32 | # "CurrencyID"=>"EUR",
33 | # "BuyRate"=>17.1904,
34 | # "SellRate"=>17.5234
35 | # }, {
36 | # ...
37 | # }
38 | # ]
39 | # }
40 | def raw_exchange_rates
41 | req = Net::HTTP::Post.new(@uri, 'Content-Type' => 'application/json')
42 | req.body = { lang: :en }.to_json
43 | response = Net::HTTP.start(@uri.hostname, @uri.port) do |http|
44 | http.request(req)
45 | end
46 | fail ResponseError, response.code unless response.is_a? Net::HTTPSuccess
47 | response = JSON.parse(response.body)
48 |
49 | # CIB provide 6 currencies only
50 | unless response['d'] && response['d'].size >= 6
51 | fail ResponseError, "Unknown JSON #{response}"
52 | end
53 |
54 | response
55 | rescue JSON::ParserError
56 | raise ResponseError, "Unknown JSON: #{response.body}"
57 | end
58 |
59 | # Parse the #raw_exchange_rates returned in response
60 | # @param [Array] of the raw_data scraped
61 | # @return [Hash] of exchange rates for selling and buying
62 | # {
63 | # { sell: { SYM: rate }, { SYM: rate }, ... },
64 | # { buy: { SYM: rate }, { SYM: rate }, ... }
65 | # }
66 | def parse(raw_data)
67 | raw_data['d'].each_with_object(sell: {}, buy: {}) do |obj, result|
68 | sell_rate = obj['SellRate']
69 | buy_rate = obj['BuyRate']
70 | currency = obj['CurrencyID'].to_sym
71 |
72 | result[:sell][currency] = sell_rate
73 | result[:buy][currency] = buy_rate
74 | end
75 | end
76 | end
77 | end
78 |
--------------------------------------------------------------------------------
/spec/egp_rates/blom_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | describe EGPRates::Blom do
3 | subject(:bank) { described_class.new }
4 |
5 | it 'Live Testing', :live do
6 | expect(bank.exchange_rates).to include(:buy, :sell)
7 | expect(bank.exchange_rates[:buy].size).to eq 14
8 | expect(bank.exchange_rates[:sell].size).to eq 14
9 | end
10 |
11 | describe '.new' do
12 | it 'initialize instance variables' do
13 | expect(bank.sym).to eq :Blom
14 | expect(bank.instance_variable_get(:@uri)).to be_a URI
15 | end
16 | end
17 |
18 | describe '#exchange_rates' do
19 | it 'calls #parse with #raw_exchange_rates' do
20 | expect(bank).to receive(:raw_exchange_rates)
21 | expect(bank).to receive(:parse)
22 | bank.exchange_rates
23 | end
24 | end
25 |
26 | describe '#raw_exchange_rates' do
27 | it 'raises ResponseError unless Net::HTTPSuccess', :no_vcr do
28 | stub_request(:get, /.*blom.*/).to_return(body: '', status: 500)
29 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
30 | EGPRates::ResponseError, '500'
31 | end
32 |
33 | it 'raises ResponseError if HTML structure changed', :no_vcr do
34 | stub_request(:get, /.*blom.*/).to_return(body: '', status: 200)
35 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
36 | EGPRates::ResponseError, 'Unknown HTML'
37 | end
38 |
39 | it 'returns <#Enumerator::Lazy> of 14 rows',
40 | vcr: { cassette_name: :Blom } do
41 | lazy_enumerator = bank.send(:raw_exchange_rates)
42 | expect(lazy_enumerator).to be_a Enumerator::Lazy
43 | expect(lazy_enumerator.size).to eq 14
44 | end
45 | end
46 |
47 | describe '#parse', vcr: { cassette_name: :Blom } do
48 | let(:raw_data) { bank.send(:raw_exchange_rates) }
49 |
50 | it 'returns sell: hash of selling prices' do
51 | expect(bank.send(:parse, raw_data)[:sell]).to match(
52 | AED: 4.9006,
53 | BHD: 0.0,
54 | CAD: 13.5788,
55 | CHF: 17.8625,
56 | DKK: 2.5862,
57 | EUR: 19.2402,
58 | GBP: 22.9266,
59 | JPY: 15.88,
60 | KWD: 59.0164,
61 | NOK: 2.143,
62 | QAR: 0.0,
63 | SAR: 4.7992,
64 | SEK: 1.9644,
65 | USD: 18.0
66 | )
67 | end
68 |
69 | it 'returns buy: hash of buying prices' do
70 | expect(bank.send(:parse, raw_data)[:buy]).to match(
71 | AED: 4.7781,
72 | BHD: 0.0,
73 | CAD: 13.1757,
74 | CHF: 17.3385,
75 | DKK: 2.5066,
76 | EUR: 18.6486,
77 | GBP: 22.0621,
78 | JPY: 15.3664,
79 | KWD: 57.541,
80 | NOK: 2.0741,
81 | QAR: 0.0,
82 | SAR: 4.6788,
83 | SEK: 1.9022,
84 | USD: 17.55
85 | )
86 | end
87 | end
88 | end
89 |
--------------------------------------------------------------------------------
/lib/egp_rates.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'oga'
4 | require 'json'
5 | require 'uri'
6 | require 'net/http'
7 | require 'thread'
8 | require 'egp_rates/bank'
9 | require 'egp_rates/cbe'
10 | require 'egp_rates/nbe'
11 | require 'egp_rates/cib'
12 | require 'egp_rates/aaib'
13 | require 'egp_rates/banque_misr'
14 | require 'egp_rates/banque_du_caire'
15 | require 'egp_rates/suez_canal_bank'
16 | require 'egp_rates/al_baraka_bank'
17 | require 'egp_rates/al_ahli_bank_of_kuwait'
18 | require 'egp_rates/midb'
19 | require 'egp_rates/ube'
20 | require 'egp_rates/cae'
21 | require 'egp_rates/edbe'
22 | require 'egp_rates/alex_bank'
23 | require 'egp_rates/blom'
24 | require 'egp_rates/adib'
25 | require 'egp_rates/egb'
26 | require 'egp_rates/nbg'
27 |
28 | # Base Module
29 | module EGPRates
30 | # Class Idicating HTTPResponseErrors when unexpected behaviour encountered
31 | # while scraping the [Bank] data
32 | class ResponseError < StandardError
33 | end
34 |
35 | # Threaded execution to get the exchange rates from different banks
36 | # @return [Hash] of the exchange rates of different banks
37 | # {
38 | # BANK: {
39 | # sell: { SYM: rate, SYM: rate },
40 | # buy: { SYM: rate, SYM: rate }
41 | # },
42 | # BANK: {
43 | # sell: { SYM: rate, SYM: rate },
44 | # buy: { SYM: rate, SYM: rate }
45 | # },
46 | # }
47 | def self.exchange_rates
48 | semaphore = Mutex.new
49 | # Fetch all the constants (Banks) implemented
50 | (constants - [:Bank, :ResponseError]).each_with_object({}) do |klass, rates|
51 | Thread.new do
52 | bank = EGPRates.const_get(klass).new
53 |
54 | semaphore.synchronize do
55 | begin
56 | rates[klass] = bank.exchange_rates
57 | rescue ResponseError
58 | rates[klass] = 'Failed to get exchange rates'
59 | end
60 | end
61 | end.join
62 | end
63 | end
64 |
65 | # Return the exchange rate of a single currency from different banks
66 | # @param [Symbol] sym, 3 charachter ISO symbol of the currency
67 | # @param [Boolean] cache_result, a boolean to indicate whether or not
68 | # the result of the exchange_rates call be cached
69 | # @return [Hash] of the exchange rates in different banks for a specific
70 | # currency
71 | def self.exchange_rate(sym = :USD, cache_result = true)
72 | @exchange_rates ||= exchange_rates if cache_result
73 | @exchange_rates = exchange_rates unless cache_result
74 |
75 | @exchange_rates.each_with_object({}) do |rates, result|
76 | begin
77 | result[rates[0]] = {
78 | sell: rates[1][:sell].fetch(sym.upcase, 'N/A'),
79 | buy: rates[1][:buy].fetch(sym.upcase, 'N/A')
80 | }
81 | rescue TypeError
82 | result[rates[0]] = rates[1]
83 | end
84 | end
85 | end
86 | end
87 |
--------------------------------------------------------------------------------
/lib/egp_rates/nbe.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | module EGPRates
3 | # National Bank of Egypt
4 | class NBE < EGPRates::Bank
5 | def initialize
6 | @sym = :NBE
7 | @uri = URI.parse('http://www.nbe.com.eg/en/ExchangeRate.aspx')
8 | end
9 |
10 | # @return [Hash] of exchange rates for selling and buying
11 | # {
12 | # { sell: { SYM: rate }, { SYM: rate }, ... },
13 | # { buy: { SYM: rate }, { SYM: rate }, ... }
14 | # }
15 | def exchange_rates
16 | @exchange_rates ||= parse(raw_exchange_rates)
17 | end
18 |
19 | private
20 |
21 | # Send the request to the URL and retrun raw data of the response
22 | # @return [Enumerator::Lazy] with the table row in HTML that evaluates to
23 | # [
24 | # "\r\n\t\t",
25 | # "US DOLLAR",
26 | # "USD ",
27 | # "\r\n\t\t\t\t\t\t\t\t\t15.9\r\n\t\t\t\t\t\t\t\t",
28 | # "\r\n\t\t\t\t\t\t\t\t\t16.05\r\n\t\t\t\t\t\t\t\t",
29 | # "\r\n\t\t\t\t\t\t\t\t\t15.9\r\n\t\t\t\t\t\t\t\t",
30 | # "\r\n\t\t\t\t\t\t\t\t\t16.05\r\n\t\t\t\t\t\t\t\t",
31 | # "\r\n\t"
32 | # ], [
33 | # "\r\n\t\t",
34 | # "EURO",
35 | # "EUR ",
36 | # "\r\n\t\t\t\t\t\t\t\t\t17.2213\r\n\t\t\t\t\t\t\t\t",
37 | # "\r\n\t\t\t\t\t\t\t\t\t17.5314\r\n\t\t\t\t\t\t\t\t",
38 | # "\r\n\t\t\t\t\t\t\t\t\t17.2213\r\n\t\t\t\t\t\t\t\t",
39 | # "\r\n\t\t\t\t\t\t\t\t\t17.5314\r\n\t\t\t\t\t\t\t\t",
40 | # "\r\n\t"
41 | # ], [
42 | # ...
43 | # ]
44 | def raw_exchange_rates
45 | table_rows = Oga.parse_html(response.body).css('#idts_content tr')
46 | # NBE provide 17 currencies only
47 | fail ResponseError, 'Unknown HTML' unless table_rows&.size == 18
48 | # Drop 1 remove the table headers
49 | table_rows.lazy.drop(1).map(&:children).map { |cell| cell.map(&:text) }
50 | end
51 |
52 | # Parse the #raw_exchange_rates returned in response
53 | # @param [Array] of the raw_data scraped
54 | # @return [Hash] of exchange rates for selling and buying
55 | # {
56 | # { sell: { SYM: rate }, { SYM: rate }, ... },
57 | # { buy: { SYM: rate }, { SYM: rate }, ... }
58 | # }
59 | def parse(raw_data)
60 | raw_data.each_with_object(sell: {}, buy: {}) do |row, result|
61 | sell_rate = row[4].strip.to_f
62 | buy_rate = row[3].strip.to_f
63 | currency = row[2].strip.to_sym
64 | # Bahraini Dinar is BHD not BAD
65 | # Also Qatar Rial is QAR not QTR
66 | # Changing them for consistency
67 | if currency == :BAD
68 | currency = :BHD
69 | elsif currency == :QTR
70 | currency = :QAR
71 | end
72 |
73 | result[:sell][currency] = sell_rate
74 | result[:buy][currency] = buy_rate
75 | end
76 | end
77 | end
78 | end
79 |
--------------------------------------------------------------------------------
/spec/egp_rates/nbe_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | describe EGPRates::NBE do
3 | subject(:bank) { described_class.new }
4 |
5 | it 'Live Testing', :live do
6 | expect(bank.exchange_rates).to include(:buy, :sell)
7 | expect(bank.exchange_rates[:buy].size).to eq 17
8 | expect(bank.exchange_rates[:sell].size).to eq 17
9 | end
10 |
11 | describe '.new' do
12 | it 'initialize instance variables' do
13 | expect(bank.sym).to eq :NBE
14 | expect(bank.instance_variable_get(:@uri)).to be_a URI
15 | end
16 | end
17 |
18 | describe '#exchange_rates' do
19 | it 'calls #parse with #raw_exchange_rates' do
20 | expect(bank).to receive(:raw_exchange_rates)
21 | expect(bank).to receive(:parse)
22 | bank.exchange_rates
23 | end
24 | end
25 |
26 | describe '#raw_exchange_rates' do
27 | it 'raises ResponseError unless Net::HTTPSuccess', :no_vcr do
28 | stub_request(:get, /.*nbe.*/).to_return(body: '', status: 500)
29 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
30 | EGPRates::ResponseError, '500'
31 | end
32 |
33 | it 'raises ResponseError if HTML structure changed', :no_vcr do
34 | stub_request(:get, /.*nbe.*/).to_return(body: '', status: 200)
35 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
36 | EGPRates::ResponseError, 'Unknown HTML'
37 | end
38 |
39 | it 'returns <#Enumerator::Lazy> of 17 rows', vcr: { cassette_name: :NBE } do
40 | lazy_enumerator = bank.send(:raw_exchange_rates)
41 | expect(lazy_enumerator).to be_a Enumerator::Lazy
42 | expect(lazy_enumerator.size).to eq 17
43 | end
44 | end
45 |
46 | describe '#parse', vcr: { cassette_name: :NBE } do
47 | let(:raw_data) { bank.send(:raw_exchange_rates) }
48 |
49 | it 'returns sell: hash of selling prices' do
50 | expect(bank.send(:parse, raw_data)[:sell]).to match(
51 | AED: 4.8327,
52 | AUD: 13.2557,
53 | BHD: 47.086,
54 | CAD: 13.3902,
55 | CHF: 17.6144,
56 | DKK: 2.5503,
57 | EUR: 18.973,
58 | GBP: 22.6082,
59 | JOD: 25.0565,
60 | JPY: 15.6595,
61 | KWD: 58.2254,
62 | NOK: 2.1132,
63 | OMR: 46.1506,
64 | QAR: 4.8748,
65 | SAR: 4.7327,
66 | SEK: 1.9331,
67 | USD: 17.75
68 | )
69 | end
70 |
71 | it 'returns buy: hash of buying prices' do
72 | expect(bank.send(:parse, raw_data)[:buy]).to match(
73 | AED: 4.7645,
74 | AUD: 12.9535,
75 | BHD: 46.4166,
76 | CAD: 13.1381,
77 | CHF: 17.2891,
78 | DKK: 2.4995,
79 | EUR: 18.5955,
80 | GBP: 21.9993,
81 | JOD: 24.6827,
82 | JPY: 15.3227,
83 | KWD: 57.377,
84 | NOK: 2.0682,
85 | OMR: 45.4133,
86 | QAR: 4.8053,
87 | SAR: 4.6654,
88 | SEK: 1.8968,
89 | USD: 17.5
90 | )
91 | end
92 | end
93 | end
94 |
--------------------------------------------------------------------------------
/spec/egp_rates/cae_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | describe EGPRates::CAE do
3 | subject(:bank) { described_class.new }
4 |
5 | it 'Live Testing', :live do
6 | expect(bank.exchange_rates).to include(:buy, :sell)
7 | expect(bank.exchange_rates[:buy].size).to eq 17
8 | expect(bank.exchange_rates[:sell].size).to eq 17
9 | end
10 |
11 | describe '.new' do
12 | it 'initialize instance variables' do
13 | expect(bank.sym).to eq :CAE
14 | expect(bank.instance_variable_get(:@uri)).to be_a URI
15 | end
16 | end
17 |
18 | describe '#exchange_rates' do
19 | it 'calls #parse with #raw_exchange_rates' do
20 | expect(bank).to receive(:raw_exchange_rates)
21 | expect(bank).to receive(:parse)
22 | bank.exchange_rates
23 | end
24 | end
25 |
26 | describe '#raw_exchange_rates' do
27 | it 'raises ResponseError unless Net::HTTPSuccess', :no_vcr do
28 | stub_request(:get, /.*ca-egypt.*/).to_return(body: '', status: 500)
29 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
30 | EGPRates::ResponseError, '500'
31 | end
32 |
33 | it 'raises ResponseError if HTML structure changed', :no_vcr do
34 | stub_request(:get, /.*ca-egypt.*/).to_return(body: '', status: 200)
35 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
36 | EGPRates::ResponseError, 'Unknown HTML'
37 | end
38 |
39 | it 'returns <#Enumerator::Lazy> of 17 rows', vcr: { cassette_name: :CAE } do
40 | lazy_enumerator = bank.send(:raw_exchange_rates)
41 | expect(lazy_enumerator).to be_a Enumerator::Lazy
42 | expect(lazy_enumerator.size).to eq 17
43 | end
44 | end
45 |
46 | describe '#parse', vcr: { cassette_name: :CAE } do
47 | let(:raw_data) { bank.send(:raw_exchange_rates) }
48 |
49 | it 'returns sell: hash of selling prices' do
50 | expect(bank.send(:parse, raw_data)[:sell]).to match(
51 | AED: 4.969,
52 | AUD: 13.5171,
53 | BHD: 48.0106,
54 | CAD: 13.6542,
55 | CHF: 17.9617,
56 | DKK: 2.6006,
57 | EUR: 19.3471,
58 | GBP: 23.054,
59 | JOD: 25.493,
60 | JPY: 0.1597,
61 | KWD: 59.3735,
62 | NOK: 2.1549,
63 | OMR: 47.0118,
64 | QAR: 4.9703,
65 | SAR: 4.8264,
66 | SEK: 1.9712,
67 | USD: 18.1
68 | )
69 | end
70 |
71 | it 'returns buy: hash of buying prices' do
72 | expect(bank.send(:parse, raw_data)[:buy]).to match(
73 | AED: 4.8326,
74 | AUD: 13.0645,
75 | BHD: 46.7922,
76 | CAD: 13.2508,
77 | CHF: 17.4373,
78 | DKK: 2.5209,
79 | EUR: 18.7549,
80 | GBP: 22.1878,
81 | JOD: 24.8592,
82 | JPY: 0.1545,
83 | KWD: 57.8689,
84 | NOK: 2.0842,
85 | OMR: 45.8382,
86 | QAR: 4.8465,
87 | SAR: 4.7057,
88 | SEK: 1.9131,
89 | USD: 17.65
90 | )
91 | end
92 | end
93 | end
94 |
--------------------------------------------------------------------------------
/spec/egp_rates/egb_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | describe EGPRates::EGB do
3 | subject(:bank) { described_class.new }
4 |
5 | it 'Live Testing', :live do
6 | expect(bank.exchange_rates).to include(:buy, :sell)
7 | expect(bank.exchange_rates[:buy].size).to eq 17
8 | expect(bank.exchange_rates[:sell].size).to eq 17
9 | end
10 |
11 | describe '.new' do
12 | it 'initialize instance variables' do
13 | expect(bank.sym).to eq :EGB
14 | expect(bank.instance_variable_get(:@uri)).to be_a URI
15 | end
16 | end
17 |
18 | describe '#exchange_rates' do
19 | it 'calls #parse with #raw_exchange_rates' do
20 | expect(bank).to receive(:raw_exchange_rates)
21 | expect(bank).to receive(:parse)
22 | bank.exchange_rates
23 | end
24 | end
25 |
26 | describe '#raw_exchange_rates' do
27 | it 'raises ResponseError unless Net::HTTPSuccess', :no_vcr do
28 | stub_request(:get, /.*eg-bank.*/).to_return(body: '', status: 500)
29 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
30 | EGPRates::ResponseError, '500'
31 | end
32 |
33 | it 'raises ResponseError if HTML structure changed', :no_vcr do
34 | stub_request(:get, /.*eg-bank.*/).to_return(body: '', status: 200)
35 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
36 | EGPRates::ResponseError, 'Unknown HTML'
37 | end
38 |
39 | it 'returns <#Enumerator::Lazy> of 17 rows', vcr: { cassette_name: :EGB } do
40 | lazy_enumerator = bank.send(:raw_exchange_rates)
41 | expect(lazy_enumerator).to be_a Enumerator::Lazy
42 | expect(lazy_enumerator.size).to eq 17
43 | end
44 | end
45 |
46 | describe '#parse', vcr: { cassette_name: :EGB } do
47 | let(:raw_data) { bank.send(:raw_exchange_rates) }
48 |
49 | it 'returns sell: hash of selling prices' do
50 | expect(bank.send(:parse, raw_data)[:sell]).to match(
51 | AED: 4.9421,
52 | AUD: 13.5544,
53 | BHD: 48.156,
54 | CAD: 13.6971,
55 | CHF: 18.0238,
56 | DKK: 2.6084,
57 | EUR: 19.4005,
58 | GBP: 23.1177,
59 | JOD: 25.6356,
60 | JPY: 0.1602,
61 | KWD: 59.5472,
62 | NOK: 2.1634,
63 | OMR: 47.1551,
64 | QAR: 4.9853,
65 | SAR: 4.8394,
66 | SEK: 1.9775,
67 | USD: 18.15
68 | )
69 | end
70 |
71 | it 'returns buy: hash of buying prices' do
72 | expect(bank.send(:parse, raw_data)[:buy]).to match(
73 | AED: 4.7917,
74 | AUD: 13.0152,
75 | BHD: 46.6844,
76 | CAD: 13.2132,
77 | CHF: 17.3879,
78 | DKK: 2.5137,
79 | EUR: 18.6965,
80 | GBP: 22.1144,
81 | JOD: 24.7887,
82 | JPY: 0.1541,
83 | KWD: 57.7049,
84 | NOK: 2.08,
85 | OMR: 45.7143,
86 | QAR: 4.8329,
87 | SAR: 4.6926,
88 | SEK: 1.9077,
89 | USD: 17.6
90 | )
91 | end
92 | end
93 | end
94 |
--------------------------------------------------------------------------------
/spec/egp_rates/al_baraka_bank_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | describe EGPRates::AlBarakaBank do
3 | subject(:bank) { described_class.new }
4 |
5 | it 'Live Testing', :live do
6 | expect(bank.exchange_rates).to include(:buy, :sell)
7 | expect(bank.exchange_rates[:buy].size).to eq 7
8 | expect(bank.exchange_rates[:sell].size).to eq 7
9 | end
10 |
11 | describe '.new' do
12 | it 'initialize instance variables' do
13 | expect(bank.sym).to eq :AlBarakaBank
14 | expect(bank.instance_variable_get(:@uri)).to be_a URI
15 | end
16 | end
17 |
18 | describe '#exchange_rates' do
19 | it 'calls #parse with #raw_exchange_rates' do
20 | expect(bank).to receive(:raw_exchange_rates)
21 | expect(bank).to receive(:parse)
22 | bank.exchange_rates
23 | end
24 | end
25 |
26 | describe '#raw_exchange_rates' do
27 | it 'raises ResponseError unless Net::HTTPSuccess', :no_vcr do
28 | stub_request(:get, /.*albaraka.*/).to_return(body: '', status: 500)
29 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
30 | EGPRates::ResponseError, '500'
31 | end
32 |
33 | it 'raises ResponseError if HTML structure changed', :no_vcr do
34 | stub_request(:get, /.*albaraka.*/).to_return(body: '', status: 200)
35 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
36 | EGPRates::ResponseError, 'Unknown HTML'
37 | end
38 |
39 | it 'returns <#Enumerator::Lazy> of 7 rows',
40 | vcr: { cassette_name: :AlBarakaBank } do
41 | lazy_enumerator = bank.send(:raw_exchange_rates)
42 | expect(lazy_enumerator).to be_a Enumerator::Lazy
43 | expect(lazy_enumerator.size).to eq 7
44 | end
45 | end
46 |
47 | describe '#currency_symbol' do
48 | %w(USD EURO GBP CHF JPY SAR BHD)\
49 | .each do |currency|
50 | it "returns currency :SYM for #{currency}" do
51 | symbols = %i(USD EUR GBP CHF JPY SAR BHD)
52 | expect(symbols).to include(bank.send(:currency_symbol, currency))
53 | end
54 | end
55 |
56 | it 'raises ResponseError when Unknown Currency' do
57 | expect { bank.send(:currency_symbol, 'Egyptian pound') }.to raise_error\
58 | EGPRates::ResponseError, 'Unknown currency Egyptian pound'
59 | end
60 | end
61 |
62 | describe '#parse', vcr: { cassette_name: :AlBarakaBank } do
63 | let(:raw_data) { bank.send(:raw_exchange_rates) }
64 |
65 | it 'returns sell: hash of selling prices' do
66 | expect(bank.send(:parse, raw_data)[:sell]).to match(
67 | BHD: 48.3615,
68 | CHF: 18.4535,
69 | EUR: 19.4932,
70 | GBP: 23.2589,
71 | JPY: 16.0489,
72 | SAR: 4.8618,
73 | USD: 18.09
74 | )
75 | end
76 |
77 | it 'returns buy: hash of buying prices' do
78 | expect(bank.send(:parse, raw_data)[:buy]).to match(
79 | BHD: 46.3908,
80 | CHF: 17.2842,
81 | EUR: 18.6618,
82 | GBP: 22.2669,
83 | JPY: 15.3949,
84 | SAR: 4.588,
85 | USD: 17.74
86 | )
87 | end
88 | end
89 | end
90 |
--------------------------------------------------------------------------------
/spec/egp_rates/cbe_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | describe EGPRates::CBE do
3 | subject(:bank) { described_class.new }
4 |
5 | it 'Live Testing', :live do
6 | expect(bank.exchange_rates).to include(:buy, :sell)
7 | expect(bank.exchange_rates[:buy].size).to eq 9
8 | expect(bank.exchange_rates[:sell].size).to eq 9
9 | end
10 |
11 | describe '.new' do
12 | it 'initialize instance variables' do
13 | expect(bank.sym).to eq :CBE
14 | expect(bank.instance_variable_get(:@uri)).to be_a URI
15 | end
16 | end
17 |
18 | describe '#exchange_rates' do
19 | it 'calls #parse with #raw_exchange_rates' do
20 | expect(bank).to receive(:raw_exchange_rates)
21 | expect(bank).to receive(:parse)
22 | bank.exchange_rates
23 | end
24 | end
25 |
26 | describe '#raw_exchange_rates' do
27 | it 'raises ResponseError unless Net::HTTPSuccess', :no_vcr do
28 | stub_request(:get, /.*cbe.*/).to_return(body: '', status: 500)
29 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
30 | EGPRates::ResponseError, '500'
31 | end
32 |
33 | it 'raises ResponseError if HTML structure changed', :no_vcr do
34 | stub_request(:get, /.*cbe.*/).to_return(body: '', status: 200)
35 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
36 | EGPRates::ResponseError, 'Unknown HTML'
37 | end
38 |
39 | it 'returns <#Enumerator::Lazy> of 9 rows', vcr: { cassette_name: :CBE } do
40 | lazy_enumerator = bank.send(:raw_exchange_rates)
41 | expect(lazy_enumerator).to be_a Enumerator::Lazy
42 | expect(lazy_enumerator.size).to eq 9
43 | end
44 | end
45 |
46 | describe '#currency_symbol' do
47 | %W(#{'US Dollar'} Euro Sterling Swiss Japanese Saudi Kuwait UAE Chinese)\
48 | .each do |currency|
49 | it "returns currency :SYM for #{currency}" do
50 | symbols = %i(USD EUR GBP CHF JPY SAR KWD AED CNY)
51 | expect(symbols).to include(bank.send(:currency_symbol, currency))
52 | end
53 | end
54 |
55 | it 'raises ResponseError when Unknown Currency' do
56 | expect { bank.send(:currency_symbol, 'Egyptian pound') }.to raise_error\
57 | EGPRates::ResponseError, 'Unknown currency Egyptian pound'
58 | end
59 | end
60 |
61 | describe '#parse', vcr: { cassette_name: :CBE } do
62 | let(:raw_data) { bank.send(:raw_exchange_rates) }
63 |
64 | it 'returns sell: hash of selling prices' do
65 | expect(bank.send(:parse, raw_data)[:sell]).to match(
66 | AED: 4.9155,
67 | CHF: 17.8556,
68 | CNY: 2.6227,
69 | EUR: 19.2687,
70 | GBP: 22.9982,
71 | JPY: 15.8992,
72 | KWD: 59.2257,
73 | SAR: 4.8132,
74 | USD: 18.052
75 | )
76 | end
77 |
78 | it 'returns buy: hash of buying prices' do
79 | expect(bank.send(:parse, raw_data)[:buy]).to match(
80 | AED: 4.7994,
81 | CHF: 17.4193,
82 | CNY: 2.5585,
83 | EUR: 18.8076,
84 | GBP: 22.4408,
85 | JPY: 15.5151,
86 | KWD: 57.7977,
87 | SAR: 4.7001,
88 | USD: 17.6283
89 | )
90 | end
91 | end
92 | end
93 |
--------------------------------------------------------------------------------
/spec/egp_rates_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | describe EGPRates do
3 | describe '.exchange_rates' do
4 | # rubocop:disable RSpec/VerifiedDoubles
5 | context 'all Banks' do
6 | let(:bank) { double(EGPRates::Bank) }
7 |
8 | it 'calls #exchange_rates on all Bank Classes' do
9 | expect(described_class).to receive(:const_get).exactly(18).times
10 | .and_return bank
11 | expect(bank).to receive(:new).exactly(18).times.and_return bank
12 | expect(bank).to receive(:exchange_rates).exactly(18).times
13 |
14 | described_class.exchange_rates
15 | end
16 | end
17 | # rubocop:enable RSpec/VerifiedDoubles
18 |
19 | context '1 Bank' do
20 | before { allow(described_class).to receive(:constants).and_return [:CBE] }
21 |
22 | it 'returns [Hash] of exchange_rates', vcr: { cassette_name: :CBE } do
23 | exchange_rates = described_class.exchange_rates
24 |
25 | expect(exchange_rates).to include(:CBE)
26 | expect(exchange_rates[:CBE]).to include(:buy, :sell)
27 | expect(exchange_rates[:CBE][:buy].size).to eq 9
28 | expect(exchange_rates[:CBE][:sell].size).to eq 9
29 | end
30 |
31 | it 'returns [Hash] of Bank: "Failed to get exchange rates"', :no_vcr do
32 | stub_request(:get, /.*/).to_return(body: '', status: 500)
33 |
34 | exchange_rates = described_class.exchange_rates
35 | expect(exchange_rates).to match(CBE: 'Failed to get exchange rates')
36 | end
37 | end
38 | end
39 |
40 | describe '.exchange_rate(:SYM, cache_result)' do
41 | before do
42 | described_class.instance_variable_set(:@exchange_rates, nil)
43 | allow(described_class).to receive(:constants).and_return [:NBE]
44 | end
45 |
46 | context 'cache_result = true' do
47 | it 'calls .exchange_rates once' do
48 | expect(described_class).to receive(:exchange_rates).once.and_return({})
49 |
50 | described_class.exchange_rate(:USD)
51 | described_class.exchange_rate(:USD)
52 | end
53 |
54 | it 'calls .exchange_rates twice' do
55 | expect(described_class).to receive(:exchange_rates).twice.and_return({})
56 |
57 | described_class.exchange_rate(:USD)
58 | described_class.exchange_rate(:USD, false)
59 | end
60 |
61 | it 'returns [Hash] of Bank: "Failed to get exchange rates"', :no_vcr do
62 | stub_request(:get, /.*/).to_return(body: '', status: 500)
63 |
64 | exchange_rate = described_class.exchange_rate(:USD)
65 | expect(exchange_rate).to match(NBE: 'Failed to get exchange rates')
66 | end
67 |
68 | it 'returns [Hash] of Bank: { sell: rate, buy: rate }',
69 | vcr: { cassette_name: :NBE } do
70 | exchange_rate = described_class.exchange_rate(:USD)
71 | expect(exchange_rate).to match(NBE: { sell: 17.75, buy: 17.5 })
72 | end
73 |
74 | it 'returns [Hash] of Bank: { sell: "N/A" ... }',
75 | vcr: { cassette_name: :NBE } do
76 | exchange_rate = described_class.exchange_rate(:SYM)
77 | expect(exchange_rate).to match(
78 | NBE: { sell: 'N/A', buy: 'N/A' }
79 | )
80 | end
81 | end
82 | end
83 | end
84 |
--------------------------------------------------------------------------------
/spec/egp_rates/cib_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | describe EGPRates::CIB do
3 | subject(:bank) { described_class.new }
4 |
5 | it 'Live Testing', :live do
6 | expect(bank.exchange_rates).to include(:buy, :sell)
7 | expect(bank.exchange_rates[:buy].size).to eq 6
8 | expect(bank.exchange_rates[:sell].size).to eq 6
9 | end
10 |
11 | describe '.new' do
12 | it 'initialize instance variables' do
13 | expect(bank.sym).to eq :CIB
14 | expect(bank.instance_variable_get(:@uri)).to be_a URI
15 | end
16 | end
17 |
18 | describe '#exchange_rates' do
19 | it 'calls #parse with #raw_exchange_rates' do
20 | expect(bank).to receive(:raw_exchange_rates)
21 | expect(bank).to receive(:parse)
22 | bank.exchange_rates
23 | end
24 | end
25 |
26 | describe '#raw_exchange_rates' do
27 | it 'raises ResponseError unless Net::HTTPSuccess', :no_vcr do
28 | stub_request(:post, /.*cib.*/).to_return(body: '', status: 500)
29 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
30 | EGPRates::ResponseError, '500'
31 | end
32 |
33 | it 'raises ResponseError if JSON respnonse changed', :no_vcr do
34 | stub_request(:post, /.*cib.*/).to_return(
35 | body: { d: { USD: 1 } }.to_json,
36 | status: 200
37 | )
38 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
39 | EGPRates::ResponseError, /Unknown JSON/
40 | end
41 |
42 | it 'raises ResponseError if empty JSON respnonse', :no_vcr do
43 | stub_request(:post, /.*cib.*/).to_return(body: '"{}"', status: 200)
44 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
45 | EGPRates::ResponseError, /Unknown JSON/
46 | end
47 |
48 | it 'raises ResponseError if malformed JSON respnonse', :no_vcr do
49 | stub_request(:post, /.*cib.*/).to_return(body: '{ data', status: 200)
50 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
51 | EGPRates::ResponseError, /Unknown JSON/
52 | end
53 |
54 | it 'raises ResponseError if empty respnonse', :no_vcr do
55 | stub_request(:post, /.*cib.*/).to_return(body: '""', status: 200)
56 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
57 | EGPRates::ResponseError, /Unknown JSON/
58 | end
59 |
60 | it 'returns Hash of 6 currencies rates', vcr: { cassette_name: :CIB } do
61 | response = bank.send(:raw_exchange_rates)
62 | expect(response.size).to eq 1
63 | expect(response['d'].size).to eq 6
64 | end
65 | end
66 |
67 | describe '#parse', vcr: { cassette_name: :CIB } do
68 | let(:raw_data) { bank.send(:raw_exchange_rates) }
69 |
70 | it 'returns sell: hash of selling prices' do
71 | expect(bank.send(:parse, raw_data)[:sell]).to match(
72 | CHF: 17.6266,
73 | EUR: 18.973,
74 | GBP: 22.6082,
75 | KWD: 58.2254,
76 | SAR: 4.7331,
77 | USD: 17.75
78 | )
79 | end
80 |
81 | it 'returns buy: hash of buying prices' do
82 | expect(bank.send(:parse, raw_data)[:buy]).to match(
83 | CHF: 17.2891,
84 | EUR: 18.5903,
85 | GBP: 21.9888,
86 | KWD: 57.3667,
87 | SAR: 4.659,
88 | USD: 17.5
89 | )
90 | end
91 | end
92 | end
93 |
--------------------------------------------------------------------------------
/lib/egp_rates/bank.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | module EGPRates
3 | # Class Representing the bank to get the data from
4 | class Bank
5 | attr_reader :sym
6 |
7 | # Abstract method
8 | # Subclasses banks define the logic to get the exchange rates hash
9 | # it should return [Hash] sell: { SYM: rate, ... } , buy: { SYM: rate, ... }
10 | # for the available currencies (represented by :SYM) on the bank pages
11 | def exchange_rates
12 | raise NotImplementedError
13 | end
14 |
15 | private
16 |
17 | # Make a call to the @uri to get the raw_response
18 | # @return [Net::HTTPSuccess] of the raw response
19 | # @raises [ResponseError] if response is not 200 OK
20 | def response
21 | response = Net::HTTP.get_response(@uri)
22 | if response.is_a? Net::HTTPRedirection
23 | response = Net::HTTP.get_response(URI.parse(response['location']))
24 | end
25 | fail ResponseError, response.code unless response.is_a? Net::HTTPSuccess
26 | response
27 | end
28 |
29 | # Convert currency string to ISO symbol
30 | # @param currency [String] "US Dollar"
31 | # @return [Symbol] :USD ISO currency name
32 | # rubocop:disable Metrics/CyclomaticComplexity
33 | # rubocop:disable Metrics/MethodLength
34 | def currency_symbol(currency)
35 | case currency
36 | when /UAE|EMIRATES|Dirham|AED/i then :AED
37 | when /Australian/i then :AUD
38 | when /Bahrain|BHD/i then :BHD
39 | when /Canadian|CANAD\. Dollar/i then :CAD
40 | when /Swiss|CHF/i then :CHF
41 | when /Chinese/ then :CNY
42 | when /Danish/i then :DKK
43 | when /Euro|EUR/i then :EUR
44 | when /British|Sterl.|GBP/i then :GBP
45 | when /Jordanian/i then :JOD
46 | when /Japanese|JPY|YEN/i then :JPY
47 | when /Kuwait/i then :KWD
48 | when /Norwegian|NORWEG\./i then :NOK
49 | when /Omani/i then :OMR
50 | when /Qatar/i then :QAR
51 | when /SAR|Saudi/i then :SAR
52 | when /Swidish|Swedish/i then :SEK
53 | when /U(\.)?S(\.)? Dollar|USD/i then :USD
54 | else fail ResponseError, "Unknown currency #{currency}"
55 | end
56 | end
57 | # rubocop:enable Metrics/CyclomaticComplexity
58 | # rubocop:enable Metrics/MethodLength
59 |
60 | # Parse the #raw_exchange_rates returned in response
61 | # @param [Array] of the raw_data scraped
62 | # [
63 | # [ 'Currency_1', 'BuyRate', 'SellRate', ... ],
64 | # [ 'Currency_2', 'BuyRate', 'SellRate', ... ],
65 | # [ 'Currency_3', 'BuyRate', 'SellRate', ... ],
66 | # ...
67 | # ]
68 | #
69 | # @return [Hash] of exchange rates for selling and buying
70 | # {
71 | # { sell: { SYM: rate }, { SYM: rate }, ... },
72 | # { buy: { SYM: rate }, { SYM: rate }, ... }
73 | # }
74 | def parse(raw_data)
75 | raw_data.each_with_object(sell: {}, buy: {}) do |row, result|
76 | sell_rate = row[2].to_f
77 | buy_rate = row[1].to_f
78 | currency = currency_symbol(row[0])
79 |
80 | result[:sell][currency] = sell_rate
81 | result[:buy][currency] = buy_rate
82 | end
83 | end
84 | end
85 | end
86 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, gender identity and expression, level of experience,
9 | nationality, personal appearance, race, religion, or sexual identity and
10 | orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at [Github](https://github.com/mad-raz). All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at [http://contributor-covenant.org/version/1/4][version]
72 |
73 | [homepage]: http://contributor-covenant.org
74 | [version]: http://contributor-covenant.org/version/1/4/
75 |
--------------------------------------------------------------------------------
/spec/egp_rates/suez_canal_bank_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | describe EGPRates::SuezCanalBank do
3 | subject(:bank) { described_class.new }
4 |
5 | it 'Live Testing', :live do
6 | expect(bank.exchange_rates).to include(:buy, :sell)
7 | expect(bank.exchange_rates[:buy].size).to eq 13
8 | expect(bank.exchange_rates[:sell].size).to eq 13
9 | end
10 |
11 | describe '.new' do
12 | it 'initialize instance variables' do
13 | expect(bank.sym).to eq :SuezCanalBank
14 | expect(bank.instance_variable_get(:@uri)).to be_a URI
15 | end
16 | end
17 |
18 | describe '#exchange_rates' do
19 | it 'calls #parse with #raw_exchange_rates' do
20 | expect(bank).to receive(:raw_exchange_rates)
21 | expect(bank).to receive(:parse)
22 | bank.exchange_rates
23 | end
24 | end
25 |
26 | describe '#raw_exchange_rates' do
27 | it 'raises ResponseError unless Net::HTTPSuccess', :no_vcr do
28 | stub_request(:get, /.*scbank.*/).to_return(body: '', status: 500)
29 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
30 | EGPRates::ResponseError, '500'
31 | end
32 |
33 | it 'raises ResponseError if HTML structure changed', :no_vcr do
34 | stub_request(:get, /.*scbank.*/).to_return(body: '', status: 200)
35 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
36 | EGPRates::ResponseError, 'Unknown HTML'
37 | end
38 |
39 | it 'returns <#Enumerator::Lazy> of 13 rows',
40 | vcr: { cassette_name: :SuezCanalBank } do
41 | lazy_enumerator = bank.send(:raw_exchange_rates)
42 | expect(lazy_enumerator).to be_a Enumerator::Lazy
43 | expect(lazy_enumerator.size).to eq 13
44 | end
45 | end
46 |
47 | describe '#currency_symbol' do
48 | %W(#{'UAE Dirham'} Australian Canadian Swedish Danish EUR YEN Swiss
49 | Sterling Kuwaiti Norwegian Saudi #{'US Dollar'})
50 | .each do |currency|
51 | it "returns currency :SYM for #{currency}" do
52 | symbols = %i(USD AUD GBP CAD DKK AED EUR CHF SEK JPY NOK SAR KWD)
53 | expect(symbols).to include(bank.send(:currency_symbol, currency))
54 | end
55 | end
56 |
57 | it 'raises ResponseError when Unknown Currency' do
58 | expect { bank.send(:currency_symbol, 'Egyptian Pound') }.to raise_error\
59 | EGPRates::ResponseError, 'Unknown currency Egyptian Pound'
60 | end
61 | end
62 |
63 | describe '#parse', vcr: { cassette_name: :SuezCanalBank } do
64 | let(:raw_data) { bank.send(:raw_exchange_rates) }
65 |
66 | it 'returns sell: hash of selling prices' do
67 | expect(bank.send(:parse, raw_data)[:sell]).to match(
68 | AED: 0.0,
69 | AUD: 0.0,
70 | CAD: 0.0,
71 | CHF: 17.8749,
72 | DKK: 0.0,
73 | EUR: 19.2402,
74 | GBP: 22.9266,
75 | JPY: 0.0,
76 | KWD: 0.0,
77 | NOK: 0.0,
78 | SAR: 4.8003,
79 | SEK: 0.0,
80 | USD: 18.0
81 | )
82 | end
83 |
84 | it 'returns buy: hash of buying prices' do
85 | expect(bank.send(:parse, raw_data)[:buy]).to match(
86 | AED: 0.0,
87 | AUD: 0.0,
88 | CAD: 0.0,
89 | CHF: 17.3879,
90 | DKK: 0.0,
91 | EUR: 18.6965,
92 | GBP: 22.1144,
93 | JPY: 0.0,
94 | KWD: 0.0,
95 | NOK: 0.0,
96 | SAR: 4.6714,
97 | SEK: 0.0,
98 | USD: 17.6
99 | )
100 | end
101 | end
102 | end
103 |
--------------------------------------------------------------------------------
/spec/egp_rates/aaib_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | describe EGPRates::AAIB do
3 | subject(:bank) { described_class.new }
4 |
5 | it 'Live Testing', :live do
6 | expect(bank.exchange_rates).to include(:buy, :sell)
7 | expect(bank.exchange_rates[:buy].size).to eq 7
8 | expect(bank.exchange_rates[:sell].size).to eq 7
9 | end
10 |
11 | describe '.new' do
12 | it 'initialize instance variables' do
13 | expect(bank.sym).to eq :AAIB
14 | expect(bank.instance_variable_get(:@uri)).to be_a URI
15 | end
16 | end
17 |
18 | describe '#response' do
19 | it 'Follows redirects' do
20 | stub_request(:get, /.*aaib.*/).to_return(
21 | status: 301,
22 | headers: {
23 | Location: 'http://aaib.com/services/rates'
24 | }
25 | )
26 | expect(Net::HTTP).to receive(:get_response).twice.and_call_original
27 | expect { bank.send(:response) }.to raise_error \
28 | EGPRates::ResponseError, '301'
29 | end
30 | end
31 |
32 | describe '#exchange_rates' do
33 | it 'calls #parse with #raw_exchange_rates' do
34 | expect(bank).to receive(:raw_exchange_rates)
35 | expect(bank).to receive(:parse)
36 | bank.exchange_rates
37 | end
38 | end
39 |
40 | describe '#raw_exchange_rates' do
41 | it 'raises ResponseError unless Net::HTTPSuccess', :no_vcr do
42 | stub_request(:get, /.*aaib.*/).to_return(body: '', status: 500)
43 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
44 | EGPRates::ResponseError, '500'
45 | end
46 |
47 | it 'raises ResponseError if HTML structure changed', :no_vcr do
48 | stub_request(:get, /.*aaib.*/).to_return(body: '', status: 200)
49 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
50 | EGPRates::ResponseError, 'Unknown HTML'
51 | end
52 |
53 | it 'returns <#Enumerator::Lazy> of 7 rows', vcr: { cassette_name: :AAIB } do
54 | lazy_enumerator = bank.send(:raw_exchange_rates)
55 | expect(lazy_enumerator).to be_a Enumerator::Lazy
56 | expect(lazy_enumerator.size).to eq 7
57 | end
58 | end
59 |
60 | describe '#currency_symbol' do
61 | %W(#{'US DOLLAR'} EURO STERLING SWISS SAUDI KUWAITI DIRHAM)\
62 | .each do |currency|
63 | it "returns currency :SYM for #{currency}" do
64 | symbols = %i(USD EUR GBP CHF SAR KWD AED)
65 | expect(symbols).to include(bank.send(:currency_symbol, currency))
66 | end
67 | end
68 |
69 | it 'raises ResponseError when Unknown Currency' do
70 | expect { bank.send(:currency_symbol, 'EGYPTIAN POUND') }.to raise_error\
71 | EGPRates::ResponseError, 'Unknown currency EGYPTIAN POUND'
72 | end
73 | end
74 |
75 | describe '#parse', vcr: { cassette_name: :AAIB } do
76 | let(:raw_data) { bank.send(:raw_exchange_rates) }
77 |
78 | it 'returns sell: hash of selling prices' do
79 | expect(bank.send(:parse, raw_data)[:sell]).to match(
80 | AED: 4.8788,
81 | CHF: 17.7831,
82 | EUR: 19.1547,
83 | GBP: 22.8247,
84 | KWD: 59.4954,
85 | SAR: 4.7783,
86 | USD: 17.92
87 | )
88 | end
89 |
90 | it 'returns buy: hash of buying prices' do
91 | expect(bank.send(:parse, raw_data)[:buy]).to match(
92 | AED: 4.778,
93 | CHF: 17.4373,
94 | EUR: 18.7549,
95 | GBP: 22.1878,
96 | KWD: 57.9515,
97 | SAR: 4.6797,
98 | USD: 17.65
99 | )
100 | end
101 | end
102 | end
103 |
--------------------------------------------------------------------------------
/spec/egp_rates/alex_bank_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | describe EGPRates::AlexBank do
3 | subject(:bank) { described_class.new }
4 |
5 | it 'Live Testing', :live do
6 | expect(bank.exchange_rates).to include(:buy, :sell)
7 | expect(bank.exchange_rates[:buy].size).to eq 17
8 | expect(bank.exchange_rates[:sell].size).to eq 17
9 | end
10 |
11 | describe '.new' do
12 | it 'initialize instance variables' do
13 | expect(bank.sym).to eq :AlexBank
14 | expect(bank.instance_variable_get(:@uri)).to be_a URI
15 | end
16 | end
17 |
18 | describe '#exchange_rates' do
19 | it 'calls #parse with #raw_exchange_rates' do
20 | expect(bank).to receive(:raw_exchange_rates)
21 | expect(bank).to receive(:parse)
22 | bank.exchange_rates
23 | end
24 | end
25 |
26 | describe '#raw_exchange_rates' do
27 | it 'raises ResponseError unless Net::HTTPSuccess', :no_vcr do
28 | stub_request(:get, /.*alexbank.*/).to_return(body: '', status: 500)
29 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
30 | EGPRates::ResponseError, '500'
31 | end
32 |
33 | it 'raises ResponseError if HTML structure changed', :no_vcr do
34 | stub_request(:get, /.*alexbank.*/).to_return(body: '', status: 200)
35 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
36 | EGPRates::ResponseError, 'Unknown HTML'
37 | end
38 |
39 | it 'returns <#Enumerator::Lazy> of 17 rows',
40 | vcr: { cassette_name: :AlexBank } do
41 | lazy_enumerator = bank.send(:raw_exchange_rates)
42 | expect(lazy_enumerator).to be_a Enumerator::Lazy
43 | expect(lazy_enumerator.size).to eq 17
44 | end
45 | end
46 |
47 | describe '#currency_symbol' do
48 | %W(#{'UAE Dirham'} Australian Bahraini Canadian Swidish Danish Euro
49 | Japanese Swiss British Jordanian Kuwaiti Norwegian Omani Qatari Saudi
50 | #{'US Dollar'})
51 | .each do |currency|
52 | it "returns currency :SYM for #{currency}" do
53 | symbols = %i(USD AUD BHD GBP CAD DKK AED EUR CHF SEK JPY JOD NOK OMR QAR
54 | SAR KWD)
55 | expect(symbols).to include(bank.send(:currency_symbol, currency))
56 | end
57 | end
58 |
59 | it 'raises ResponseError when Unknown Currency' do
60 | expect { bank.send(:currency_symbol, 'EGYPTIAN POUND') }.to raise_error\
61 | EGPRates::ResponseError, 'Unknown currency EGYPTIAN POUND'
62 | end
63 | end
64 |
65 | describe '#parse', vcr: { cassette_name: :AlexBank } do
66 | let(:raw_data) { bank.send(:raw_exchange_rates) }
67 |
68 | it 'returns sell: hash of selling prices' do
69 | expect(bank.send(:parse, raw_data)[:sell]).to match(
70 | AED: 4.91437,
71 | AUD: 13.47974,
72 | BHD: 0.0,
73 | CAD: 13.61648,
74 | CHF: 17.91208,
75 | DKK: 2.59343,
76 | EUR: 19.29365,
77 | GBP: 22.97765,
78 | JOD: 0.0,
79 | JPY: 15.92413,
80 | KWD: 59.21916,
81 | NOK: 2.14896,
82 | OMR: 0.0,
83 | QAR: 0.0,
84 | SAR: 4.81269,
85 | SEK: 1.9658,
86 | USD: 18.05
87 | )
88 | end
89 |
90 | it 'returns buy: hash of buying prices' do
91 | expect(bank.send(:parse, raw_data)[:buy]).to match(
92 | AED: 4.77717,
93 | AUD: 13.04232,
94 | BHD: 0.0,
95 | CAD: 13.22823,
96 | CHF: 17.40763,
97 | DKK: 2.5166,
98 | EUR: 18.72301,
99 | GBP: 22.44788,
100 | JOD: 0.0,
101 | JPY: 15.42772,
102 | KWD: 57.29892,
103 | NOK: 2.08237,
104 | OMR: 0.0,
105 | QAR: 0.0,
106 | SAR: 4.68342,
107 | SEK: 1.90982,
108 | USD: 17.62
109 | )
110 | end
111 | end
112 | end
113 |
--------------------------------------------------------------------------------
/spec/egp_rates/banque_du_caire_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | describe EGPRates::BanqueDuCaire do
3 | subject(:bank) { described_class.new }
4 |
5 | it 'Live Testing', :live do
6 | expect(bank.exchange_rates).to include(:buy, :sell)
7 | expect(bank.exchange_rates[:buy].size).to eq 17
8 | expect(bank.exchange_rates[:sell].size).to eq 17
9 | end
10 |
11 | describe '.new' do
12 | it 'initialize instance variables' do
13 | expect(bank.sym).to eq :BanqueDuCaire
14 | expect(bank.instance_variable_get(:@uri)).to be_a URI
15 | end
16 | end
17 |
18 | describe '#exchange_rates' do
19 | it 'calls #parse with #raw_exchange_rates' do
20 | expect(bank).to receive(:raw_exchange_rates)
21 | expect(bank).to receive(:parse)
22 | bank.exchange_rates
23 | end
24 | end
25 |
26 | describe '#raw_exchange_rates' do
27 | it 'raises ResponseError unless Net::HTTPSuccess', :no_vcr do
28 | stub_request(:get, /.*banqueducaire.*/).to_return(body: '', status: 500)
29 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
30 | EGPRates::ResponseError, '500'
31 | end
32 |
33 | it 'raises ResponseError if HTML structure changed', :no_vcr do
34 | stub_request(:get, /.*banqueducaire.*/).to_return(body: '', status: 200)
35 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
36 | EGPRates::ResponseError, 'Unknown HTML'
37 | end
38 |
39 | it 'returns <#Enumerator::Lazy> of 17 rows',
40 | vcr: { cassette_name: :BanqueDuCaire } do
41 | lazy_enumerator = bank.send(:raw_exchange_rates)
42 | expect(lazy_enumerator).to be_a Enumerator::Lazy
43 | expect(lazy_enumerator.size).to eq 17
44 | end
45 | end
46 |
47 | describe '#currency_symbol' do
48 | %W(#{'US DOLLAR'} AUSTRALIAN BAHRAIN BRITISH CANADIAN DANISH EMIRATES EURO
49 | JAPANESE JORDANIAN NORWEGIAN OMANI QATAR SAUDI KUWAITI SWISS SWEDISH)
50 | .each do |currency|
51 | it "returns currency :SYM for #{currency}" do
52 | symbols = %i(USD AUD BHD GBP CAD DKK AED EUR CHF SEK JPY JOD NOK OMR QAR
53 | SAR KWD)
54 | expect(symbols).to include(bank.send(:currency_symbol, currency))
55 | end
56 | end
57 |
58 | it 'raises ResponseError when Unknown Currency' do
59 | expect { bank.send(:currency_symbol, 'EGYPTIAN POUND') }.to raise_error\
60 | EGPRates::ResponseError, 'Unknown currency EGYPTIAN POUND'
61 | end
62 | end
63 |
64 | describe '#parse', vcr: { cassette_name: :BanqueDuCaire } do
65 | let(:raw_data) { bank.send(:raw_exchange_rates) }
66 |
67 | it 'returns sell: hash of selling prices' do
68 | expect(bank.send(:parse, raw_data)[:sell]).to match(
69 | AED: 4.8332,
70 | AUD: 13.2557,
71 | BHD: 47.088,
72 | CAD: 13.3952,
73 | CHF: 17.6266,
74 | DKK: 2.5509,
75 | EUR: 18.973,
76 | GBP: 22.6082,
77 | JOD: 25.071,
78 | JPY: 15.6678,
79 | KWD: 58.244,
80 | NOK: 2.1157,
81 | OMR: 46.11,
82 | QAR: 4.876,
83 | SAR: 4.7352,
84 | SEK: 1.934,
85 | USD: 17.75
86 | )
87 | end
88 |
89 | it 'returns buy: hash of buying prices' do
90 | expect(bank.send(:parse, raw_data)[:buy]).to match(
91 | AED: 4.7587,
92 | AUD: 12.9413,
93 | BHD: 44.872,
94 | CAD: 13.1381,
95 | CHF: 17.2891,
96 | DKK: 2.4995,
97 | EUR: 18.5903,
98 | GBP: 21.9888,
99 | JOD: 24.39,
100 | JPY: 15.3227,
101 | KWD: 55.476,
102 | NOK: 2.0682,
103 | OMR: 43.75,
104 | QAR: 4.781,
105 | SAR: 4.6174,
106 | SEK: 1.8968,
107 | USD: 17.5
108 | )
109 | end
110 | end
111 | end
112 |
--------------------------------------------------------------------------------
/spec/egp_rates/banque_misr_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | describe EGPRates::BanqueMisr do
3 | subject(:bank) { described_class.new }
4 |
5 | it 'Live Testing', :live do
6 | expect(bank.exchange_rates).to include(:buy, :sell)
7 | expect(bank.exchange_rates[:buy].size).to eq 17
8 | expect(bank.exchange_rates[:sell].size).to eq 17
9 | expect(bank.exchange_rates[:buy].keys).to include(
10 | :USD, :AUD, :BHD, :GBP, :CAD, :DKK, :AED, :EUR, :CHF, :SEK,
11 | :JPY, :JOD, :NOK, :OMR, :QAR, :SAR, :KWD
12 | )
13 | expect(bank.exchange_rates[:sell].keys).to include(
14 | :USD, :AUD, :BHD, :GBP, :CAD, :DKK, :AED, :EUR, :CHF, :SEK,
15 | :JPY, :JOD, :NOK, :OMR, :QAR, :SAR, :KWD
16 | )
17 | end
18 |
19 | describe '.new' do
20 | it 'initialize instance variables' do
21 | expect(bank.sym).to eq :BanqueMisr
22 | expect(bank.instance_variable_get(:@uri)).to be_a URI
23 | end
24 | end
25 |
26 | describe '#exchange_rates' do
27 | it 'calls #parse with #raw_exchange_rates' do
28 | expect(bank).to receive(:raw_exchange_rates)
29 | expect(bank).to receive(:parse)
30 | bank.exchange_rates
31 | end
32 | end
33 |
34 | describe '#raw_exchange_rates' do
35 | it 'raises ResponseError unless Net::HTTPSuccess', :no_vcr do
36 | stub_request(:get, /.*banquemisr.*/).to_return(body: '', status: 500)
37 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
38 | EGPRates::ResponseError, '500'
39 | end
40 |
41 | it 'raises ResponseError if HTML structure changed', :no_vcr do
42 | stub_request(:get, /.*banquemisr.*/).to_return(body: '', status: 200)
43 | expect { bank.send(:raw_exchange_rates) }.to raise_error\
44 | EGPRates::ResponseError, 'Unknown HTML'
45 | end
46 |
47 | it 'returns <#Enumerator::Lazy> of 17 rows',
48 | vcr: { cassette_name: :BanqueMisr } do
49 | lazy_enumerator = bank.send(:raw_exchange_rates)
50 | expect(lazy_enumerator).to be_a Enumerator::Lazy
51 | expect(lazy_enumerator.size).to eq 17
52 | end
53 | end
54 |
55 | describe '#currency_symbol' do
56 | %W(#{'UAE DIRHAM'} AUSTRALIA BAHRAIN CANADA SWEDISH DENMARK EURO JAPAN SWISS
57 | #{'GB POUND'} JORDANIAN KUWAIT NORWAY OMAN QATARI SAUDI #{'US DOLLAR'})
58 | .each do |currency|
59 | it "returns currency :SYM for #{currency}" do
60 | symbols = %i(USD AUD BHD GBP CAD DKK AED EUR CHF SEK JPY JOD NOK OMR QAR
61 | SAR KWD)
62 | expect(symbols).to include(bank.send(:currency_symbol, currency))
63 | end
64 | end
65 |
66 | it 'raises ResponseError when Unknown Currency' do
67 | expect { bank.send(:currency_symbol, 'EGYPTIAN POUND') }.to raise_error\
68 | EGPRates::ResponseError, 'Unknown currency EGYPTIAN POUND'
69 | end
70 | end
71 |
72 | describe '#parse', vcr: { cassette_name: :BanqueMisr } do
73 | let(:raw_data) { bank.send(:raw_exchange_rates) }
74 |
75 | it 'returns sell: hash of selling prices' do
76 | expect(bank.send(:parse, raw_data)[:sell]).to match(
77 | AED: 4.8303,
78 | AUD: 13.2491,
79 | BHD: 47.0624,
80 | CAD: 13.3835,
81 | CHF: 17.6056,
82 | DKK: 2.549,
83 | EUR: 18.9635,
84 | GBP: 22.5969,
85 | JOD: 25.0439,
86 | JPY: 15.6516,
87 | KWD: 58.1962,
88 | NOK: 2.1122,
89 | OMR: 46.1276,
90 | QAR: 4.8723,
91 | SAR: 4.7303,
92 | SEK: 1.9322,
93 | USD: 17.75
94 | )
95 | end
96 |
97 | it 'returns buy: hash of buying prices' do
98 | expect(bank.send(:parse, raw_data)[:buy]).to match(
99 | AED: 4.7645,
100 | AUD: 12.9535,
101 | BHD: 46.4166,
102 | CAD: 13.1381,
103 | CHF: 17.2891,
104 | DKK: 2.4995,
105 | EUR: 18.5955,
106 | GBP: 21.9993,
107 | JOD: 24.6827,
108 | JPY: 15.3227,
109 | KWD: 57.377,
110 | NOK: 2.0682,
111 | OMR: 45.4133,
112 | QAR: 4.8053,
113 | SAR: 4.6654,
114 | SEK: 1.8968,
115 | USD: 17.5
116 | )
117 | end
118 | end
119 | end
120 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # EGPRates
2 | [](https://app.wercker.com/project/byKey/d6ca4529f0d563e82898ace1f2b3de25)
3 | [](https://codeclimate.com/github/mad-raz/EGP-Rates)
4 | [](https://codeclimate.com/github/mad-raz/EGP-Rates/coverage)
5 | [](/LICENSE.md)
6 |
7 | [CLI available here](https://github.com/mad-raz/EGP-Rates-CLI)
8 |
9 | ## Installation
10 |
11 | Add this line to your application's Gemfile:
12 | ```ruby
13 | gem 'EGP_Rates'
14 | ```
15 | And then execute:
16 | ```sh
17 | $ bundle
18 | ```
19 | Or install it yourself as:
20 | ```sh
21 | $ gem install EGP_Rates
22 | ```
23 |
24 | ## Usage
25 | - [Get all the available banks rates](/lib/egp_rates.rb)
26 | - [Central Bank of Egypt (CBE)](/lib/egp_rates/cbe.rb)
27 | - [National Bank of Egypt (NBE)](/lib/egp_rates/nbe.rb)
28 | - [Commercial International Bank (CIB)](/lib/egp_rates/cib.rb)
29 | - [Arab African International Bank (AAIB)](/lib/egp_rates/aaib.rb)
30 | - [Banque Du Caire](/lib/egp_rates/banque_du_caire.rb)
31 | - [Banque Misr](/lib/egp_rates/banque_misr.rb)
32 | - [Suez Canal Bank](/lib/egp_rates/suez_canal_bank.rb)
33 | - [Al Baraka Bank](/lib/egp_rates/al_baraka_bank.rb)
34 | - [Al Ahli Bank of Kuwait](/lib/egp_rates/al_ahli_bank_of_kuwait.rb)
35 | - [Misr Iran Development Bank (MIDB)](/lib/egp_rates/midb.rb)
36 | - [The United Bank of Egypt (UBE)](/lib/egp_rates/ube.rb)
37 | - [Crédit Agricole Egypt (CAE)](/lib/egp_rates/cae.rb)
38 | - [Export Development Bank of Egypt (EDBE)](/lib/egp_rates/edbe.rb)
39 | - [Bank of Alexandria (AlexBank)](/lib/egp_rates/alex_bank.rb)
40 | - [Blom Bank Egypt (Blom)](/lib/egp_rates/blom.rb)
41 | - [Abu Dhabi Islamic Bank (ADIB)](/lib/egp_rates/adib.rb)
42 | - [Egyptian Gulf Bank (EGB)](/lib/egp_rates/egb.rb)
43 | - [National Bank of Greece (NBG)](/lib/egp_rates/nbg.rb)
44 |
45 | ```rb
46 | require 'egp_rates'
47 | # All Available Banks Data (Threaded execution)
48 | # For all the currencies that the currently showing on their pages
49 | EGPRates.exchange_rates
50 |
51 | # All Available Banks Data about specific currency
52 | # (by default it caches the response for later use)
53 | EGPRates.exchange_rate :USD # call and cache response
54 | EGPRates.exchange_rate :eur # from cached response
55 | EGPRates.exchange_rate :EUR, false # refresh cache
56 |
57 | # Specific Bank Data
58 | EGPRates::CBE.new.exchange_rates
59 | EGPRates::NBE.new.exchange_rates
60 | EGPRates::CIB.new.exchange_rates
61 | EGPRates::AAIB.new.exchange_rates
62 | EGPRates::BanqueDuCaire.new.exchange_rates
63 | EGPRates::BanqueMisr.new.exchange_rates
64 | EGPRates::SuezCanalBank.new.exchange_rates
65 | EGPRates::AlBarakaBank.new.exchange_rates
66 | EGPRates::AlAhliBankOfKuwait.new.exchange_rates
67 | EGPRates::MIDB.new.exchange_rates
68 | EGPRates::UBE.new.exchange_rates
69 | EGPRates::CAE.new.exchange_rates
70 | EGPRates::EDBE.new.exchange_rates
71 | EGPRates::AlexBank.new.exchange_rates
72 | EGPRates::Blom.new.exchange_rates
73 | EGPRates::ADIB.new.exchange_rates
74 | EGPRates::EGB.new.exchange_rates
75 | EGPRates::NBG.new.exchange_rates
76 | ```
77 |
78 | ## Development
79 | - clone the repo
80 | - to install dependencies run `bundle install`
81 | - to run the test suite `bundle exec rake spec` (local testing and live)
82 | - to run the live test suite `bundle exec rake spec_live`
83 | (or `bundle exec rspec -t live`)
84 | - to run the local test suite `bundle exec rake spec_local`
85 | (or `bundle exec rspec -t ~live`)
86 | - to run rubocop linter `bundle exec rake rubocop`
87 |
88 | ## Contributing
89 |
90 | Bug reports and pull requests are welcome on GitHub at
91 | https://github.com/mad-raz/EGP-Rates
92 |
93 | This project is intended to be a safe,
94 | welcoming space for collaboration,
95 | and contributors are expected to adhere to the
96 | Contributor Covenant [code of conduct.](/CODE_OF_CONDUCT.md)
97 |
98 | - Read the previous [code of conduct](/CODE_OF_CONDUCT.md) once again.
99 | - Write clean code.
100 | - Write clean tests.
101 | - Make sure your code is covered by test.
102 | - Make sure you follow the code style mentioned by
103 | [rubocop](http://batsov.com/rubocop/) (run `bundle exec rake rubocop`)
104 | - A pre-commit hook included with repo can be used to remember rubocop
105 | it won't disable commits, but will remind you of violations.
106 | you can set it up using `chmod +x pre-commit && cp pre-commit .git/hooks/`
107 | - Be nice to your fellow human-beings/bots contributing to this repo.
108 |
109 | ## License
110 |
111 | The project is available as open source under the terms of the
112 | [MIT License](/LICENSE.md)
113 |
--------------------------------------------------------------------------------