EGP_Rates 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/egp_rates/bank.rb +15 -0
- data/lib/egp_rates/cbe.rb +77 -0
- data/lib/egp_rates/nbe.rb +71 -0
- data/lib/egp_rates.rb +14 -0
- data/spec/cassettes/CBE.yml +1598 -0
- data/spec/cassettes/NBE.yml +861 -0
- data/spec/egp_rates/bank_spec.rb +10 -0
- data/spec/egp_rates/cbe_spec.rb +90 -0
- data/spec/egp_rates/nbe_spec.rb +91 -0
- data/spec/egp_rates_spec.rb +3 -0
- data/spec/spec_helper.rb +39 -0
- metadata +209 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 226e463d104ebab0ea975d16d7c26ed424e32bd8
|
4
|
+
data.tar.gz: cb8050bc07da0baaaf33eae5d72beac437eb3265
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 85c46b4e3f81dcb391025a11c385cbf7b6d4d43e41183e35c8dca094d9ab3c3a605bf1abca1660ee6c7272603d286b90dd0633fe1cb2985d9e265cdfb2d652c7
|
7
|
+
data.tar.gz: 08e538c1e7f2daf8f9f82353a84da28aee54245a78a01dd9454407619ba358e3bb2db14688364866cb0ed58a8a5d2f5b46ff00900454f4cb61fbc91b4f07b57a
|
@@ -0,0 +1,15 @@
|
|
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
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module EGPRates
|
3
|
+
# Central Bank of Egypt
|
4
|
+
class CBE < EGPRates::Bank
|
5
|
+
def initialize
|
6
|
+
@sym = :CBE
|
7
|
+
@uri = URI.parse('http://www.cbe.org.eg/en/EconomicResearch/Statistics/Pages/ExchangeRatesListing.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
|
+
# "US Dollar \r\n ", "15.7297", "16.3929",
|
25
|
+
# "Euro \r\n, ", "17.5308", "18.1938",
|
26
|
+
# ...
|
27
|
+
# ]
|
28
|
+
#
|
29
|
+
def raw_exchange_rates
|
30
|
+
response = Net::HTTP.get_response(@uri)
|
31
|
+
fail ResponseError, response.code unless response.is_a? Net::HTTPSuccess
|
32
|
+
table_rows = Oga.parse_html(response.body).css('tbody').last&.children
|
33
|
+
# CBE porvide 9 currencies on the home page
|
34
|
+
fail ResponseError, 'Unknown HTML' unless table_rows&.size == 9
|
35
|
+
table_rows.lazy.map(&:children).map { |cell| cell.map(&:text) }
|
36
|
+
end
|
37
|
+
|
38
|
+
# Convert currency string to ISO symbol
|
39
|
+
# @param currency [String] "US Dollar"
|
40
|
+
# @return [Symbol] :USD ISO currency name
|
41
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
42
|
+
# rubocop:disable Metrics/MethodLength
|
43
|
+
def currency_symbol(currency)
|
44
|
+
case currency
|
45
|
+
when /US/ then :USD
|
46
|
+
when /Euro/ then :EUR
|
47
|
+
when /Sterling/ then :GBP
|
48
|
+
when /Swiss/ then :CHF
|
49
|
+
when /Japanese/ then :JPY
|
50
|
+
when /Saudi/ then :SAR
|
51
|
+
when /Kuwait/ then :KWD
|
52
|
+
when /UAE/ then :AED
|
53
|
+
when /Chinese/ then :CNY
|
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
|
+
# @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.each_with_object(sell: {}, buy: {}) do |row, result|
|
68
|
+
sell_rate = row[2].to_f
|
69
|
+
buy_rate = row[1].to_f
|
70
|
+
currency = currency_symbol(row[0])
|
71
|
+
|
72
|
+
result[:sell][currency] = sell_rate
|
73
|
+
result[:buy][currency] = buy_rate
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,71 @@
|
|
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
|
+
response = Net::HTTP.get_response(@uri)
|
46
|
+
fail ResponseError, response.code unless response.is_a? Net::HTTPSuccess
|
47
|
+
table_rows = Oga.parse_html(response.body).css('#idts_content tr')
|
48
|
+
# NBE provide 17 currencies only
|
49
|
+
fail ResponseError, 'Unknown HTML' unless table_rows&.size == 18
|
50
|
+
# Drop 1 remove the table headers
|
51
|
+
table_rows.lazy.drop(1).map(&:children).map { |cell| cell.map(&:text) }
|
52
|
+
end
|
53
|
+
|
54
|
+
# Parse the #raw_exchange_rates returned in response
|
55
|
+
# @return [Hash] of exchange rates for selling and buying
|
56
|
+
# {
|
57
|
+
# { sell: { SYM: rate }, { SYM: rate }, ... },
|
58
|
+
# { buy: { SYM: rate }, { SYM: rate }, ... }
|
59
|
+
# }
|
60
|
+
def parse(raw_data)
|
61
|
+
raw_data.each_with_object(sell: {}, buy: {}) do |row, result|
|
62
|
+
sell_rate = row[4].strip.to_f
|
63
|
+
buy_rate = row[3].strip.to_f
|
64
|
+
currency = row[2].strip.to_sym
|
65
|
+
|
66
|
+
result[:sell][currency] = sell_rate
|
67
|
+
result[:buy][currency] = buy_rate
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/egp_rates.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'oga'
|
4
|
+
require 'egp_rates/bank'
|
5
|
+
require 'egp_rates/cbe'
|
6
|
+
require 'egp_rates/nbe'
|
7
|
+
|
8
|
+
# Base Module
|
9
|
+
module EGPRates
|
10
|
+
# Class Idicating HTTPResponseErrors when unexpected behaviour encountered
|
11
|
+
# while scraping the [Bank] data
|
12
|
+
class ResponseError < StandardError
|
13
|
+
end
|
14
|
+
end
|