omni_exchange 1.6.0 → 1.7.0
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 +4 -4
- data/Gemfile.lock +5 -5
- data/lib/omni_exchange/provider.rb +1 -1
- data/lib/omni_exchange/providers/open_exchange_rates.rb +55 -30
- data/lib/omni_exchange/providers/xe.rb +74 -30
- data/lib/omni_exchange/version.rb +1 -1
- data/lib/omni_exchange.rb +19 -4
- data/omni_exchange.gemspec +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a9e96486f0fec5e014b79827ca801fc70c717ad3f3c36a333fc2d1248ea7b3f6
|
4
|
+
data.tar.gz: f52a460e18ad19a5cfeefe507dbce77563faf8e81ad5c2b23701fa7fec058190
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e948110df897320119664e7dadd069a9b32a74c9f683f21d9af48c4166eda64dfd6494fee2719c11c670088b91276de8f8659e7248aa324297219981ae18865f
|
7
|
+
data.tar.gz: 218e427ae203f24f0eeb4e74235b63fadaf47638061d6735f52d854b9413d5bfbcb08d5e541365cfcdeb9e4dfc481b2aedba145f6bfcf1f69b4a880a0e1451e9
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
omni_exchange (1.
|
4
|
+
omni_exchange (1.7.0)
|
5
5
|
faraday (< 2)
|
6
6
|
money (~> 6.13.1)
|
7
7
|
|
@@ -13,7 +13,7 @@ GEM
|
|
13
13
|
concurrent-ruby (1.1.10)
|
14
14
|
diff-lcs (1.5.0)
|
15
15
|
dotenv (2.8.1)
|
16
|
-
faraday (1.10.
|
16
|
+
faraday (1.10.3)
|
17
17
|
faraday-em_http (~> 1.0)
|
18
18
|
faraday-em_synchrony (~> 1.0)
|
19
19
|
faraday-excon (~> 1.1)
|
@@ -41,7 +41,7 @@ GEM
|
|
41
41
|
method_source (1.0.0)
|
42
42
|
money (6.13.8)
|
43
43
|
i18n (>= 0.6.4, <= 2)
|
44
|
-
multipart-post (2.
|
44
|
+
multipart-post (2.3.0)
|
45
45
|
parallel (1.22.1)
|
46
46
|
parser (3.1.2.1)
|
47
47
|
ast (~> 2.4.1)
|
@@ -49,7 +49,7 @@ GEM
|
|
49
49
|
coderay (~> 1.1)
|
50
50
|
method_source (~> 1.0)
|
51
51
|
rainbow (3.1.1)
|
52
|
-
rake (
|
52
|
+
rake (12.3.3)
|
53
53
|
regexp_parser (2.5.0)
|
54
54
|
rexml (3.2.5)
|
55
55
|
rspec (3.11.0)
|
@@ -89,7 +89,7 @@ DEPENDENCIES
|
|
89
89
|
dotenv
|
90
90
|
omni_exchange!
|
91
91
|
pry
|
92
|
-
rake (~>
|
92
|
+
rake (~> 12.3)
|
93
93
|
rspec (~> 3.0)
|
94
94
|
rubocop (~> 0.80)
|
95
95
|
vcr
|
@@ -36,7 +36,7 @@ module OmniExchange
|
|
36
36
|
|
37
37
|
# Each provider class should inherit from Provider and have a .get_exchange_rates method. If a provider class
|
38
38
|
# doesn't have a .get_exchange_rates method, the method below will be called and an error will be raised.
|
39
|
-
def self.get_exchange_rate
|
39
|
+
def self.get_exchange_rate(base_currency:, target_currency:) # rubocop:disable Lint/UnusedMethodArgument
|
40
40
|
raise 'method not implemented...'
|
41
41
|
end
|
42
42
|
|
@@ -4,42 +4,67 @@ require 'omni_exchange'
|
|
4
4
|
|
5
5
|
module OmniExchange
|
6
6
|
class OpenExchangeRates < Provider
|
7
|
-
ENDPOINT_URL = 'https://openexchangerates.org/api/
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
begin
|
25
|
-
response = api.get do |req|
|
26
|
-
req.url "?app_id=#{app_id}&base=#{base_currency}"
|
27
|
-
req.options.timeout = config[:read_timeout] || OmniExchange::Configuration::DEFAULT_READ_TIMEOUT
|
28
|
-
req.options.open_timeout = config[:connect_timeout] || OmniExchange::Configuration::DEFAULT_CONNECTION_TIMEOUT
|
7
|
+
ENDPOINT_URL = 'https://openexchangerates.org/api/'
|
8
|
+
|
9
|
+
class << self
|
10
|
+
# This method returns the exchange rate, the rate at which the smallest unit of one currency (the base currency)
|
11
|
+
# will be exchanged for another currency (the target currency), from Open Exchange Rate's API.
|
12
|
+
# This method is called in the OmniExchange.exchange_currency method.
|
13
|
+
#
|
14
|
+
# @param base_currency: [String] the ISO Currency Code of the currency that you're exchanging from. ie. "USD", "JPY"
|
15
|
+
# @param target_currency: [String] the ISO Currency Code of the currency that you're exchanging to. ie. "EUR", "KRW"
|
16
|
+
# @ return [BigDecimal] an exchange rate is returned as a BigDecimal for precise calculation since this exchange
|
17
|
+
# rate will be used to calculate an convert an exchange of currencies. However, an exception will be raised
|
18
|
+
# if there is a timeout while connecting to xe.com or a timeout while reading Open Exchange Rate's API.
|
19
|
+
def get_exchange_rate(base_currency:, target_currency:)
|
20
|
+
body = api_get do |req|
|
21
|
+
req.url 'latest.json'
|
22
|
+
req.params['base'] = base_currency
|
23
|
+
req.params['symbols'] = target_currency
|
29
24
|
end
|
30
|
-
|
31
|
-
|
25
|
+
|
26
|
+
exchange_rate = body['rates'][target_currency].to_d
|
27
|
+
currency_unit = get_currency_unit(base_currency).to_d
|
28
|
+
|
29
|
+
(exchange_rate * currency_unit).to_d
|
32
30
|
end
|
33
31
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
32
|
+
def get_historic_rate(base_currency:, target_currencies:, date:)
|
33
|
+
body = api_get do |req|
|
34
|
+
req.url "historical/#{date.strftime('%Y-%m-%d')}.json"
|
35
|
+
|
36
|
+
req.params['base'] = base_currency
|
37
|
+
req.params['symbols'] = target_currencies.join(',')
|
38
|
+
end
|
39
|
+
|
40
|
+
currency_unit = get_currency_unit(base_currency).to_d
|
41
|
+
body['rates'].transform_values do |rate|
|
42
|
+
(rate * currency_unit).to_d
|
43
|
+
end
|
38
44
|
end
|
39
45
|
|
40
|
-
|
46
|
+
private
|
47
|
+
|
48
|
+
def api_get(&blk)
|
49
|
+
api = Faraday.new(OmniExchange::OpenExchangeRates::ENDPOINT_URL)
|
41
50
|
|
42
|
-
|
51
|
+
response = api.get do |req|
|
52
|
+
blk.call(req)
|
53
|
+
|
54
|
+
req.params['app_id'] = config[:app_id]
|
55
|
+
|
56
|
+
req.options.timeout = config[:read_timeout] ||
|
57
|
+
OmniExchange::Configuration::DEFAULT_READ_TIMEOUT
|
58
|
+
req.options.open_timeout = config[:connect_timeout] ||
|
59
|
+
OmniExchange::Configuration::DEFAULT_CONNECTION_TIMEOUT
|
60
|
+
end
|
61
|
+
|
62
|
+
JSON.parse(response.body)
|
63
|
+
end
|
64
|
+
|
65
|
+
def config
|
66
|
+
OmniExchange.configuration.provider_config[:open_exchange_rates]
|
67
|
+
end
|
43
68
|
end
|
44
69
|
|
45
70
|
# when this file is required at the top of lib/omni_exchange.rb, this method call is run and allows
|
@@ -6,45 +6,89 @@ module OmniExchange
|
|
6
6
|
class Xe < Provider
|
7
7
|
ENDPOINT_URL = 'https://xecdapi.xe.com/'
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
9
|
+
class << self
|
10
|
+
# This method returns the exchange rate, the rate at which the smallest unit of one currency (the base currency)
|
11
|
+
# will be exchanged for another currency (the target currency), from xe.com's API.
|
12
|
+
# This method is called in the OmniExchange.exchange_currency method.
|
13
|
+
#
|
14
|
+
# @param base_currency: [String] the ISO Currency Code of the currency that you're exchanging from. ie. "USD", "JPY"
|
15
|
+
# @param target_currency: [String] the ISO Currency Code of the currency that you're exchanging to. ie. "EUR", "KRW"
|
16
|
+
# @ return [BigDecimal] an exchange rate is returned as a BigDecimal for precise calculation since this exchange
|
17
|
+
# rate will be used to calculate an convert an exchange of currencies. However, an exception will be raised
|
18
|
+
# if there is a timeout while connecting to xe.com or a timeout while reading xe.com's API.
|
19
|
+
def get_exchange_rate(base_currency:, target_currency:)
|
20
|
+
currency_unit = get_currency_unit(base_currency)
|
21
|
+
|
22
|
+
body = api_get do |req|
|
23
|
+
req.url 'v1/convert_from.json'
|
24
|
+
|
25
|
+
req.params['from'] = base_currency
|
26
|
+
req.params['to'] = target_currency
|
27
|
+
req.params['amount'] = currency_unit
|
28
|
+
end
|
29
|
+
|
30
|
+
body[:to][0][:mid].to_d
|
27
31
|
end
|
28
32
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
33
|
+
# This method returns the historic exchange rate for multiple currencies for a given date.
|
34
|
+
#
|
35
|
+
# @param base_currency: [String] the ISO Currency Code of the currency that you're exchanging from.
|
36
|
+
# ie. "USD", "JPY"
|
37
|
+
# @param target_currencies: [Array] an array of ISO Currency Codes of the currencies that you're
|
38
|
+
# exchanging to. ie. ["EUR", "KRW"]
|
39
|
+
# @param date: [Date] the date for which you want the historic exchange rate.
|
40
|
+
def get_historic_rate(base_currency:, target_currencies:, date:)
|
41
|
+
currency_unit = get_currency_unit(base_currency)
|
42
|
+
|
43
|
+
body = api_get do |req|
|
44
|
+
req.url 'v1/historic_rate.json'
|
45
|
+
|
46
|
+
req.params['from'] = base_currency
|
47
|
+
req.params['to'] = target_currencies.join(',')
|
48
|
+
req.params['amount'] = currency_unit
|
49
|
+
req.params['date'] = date.strftime('%Y-%m-%d')
|
50
|
+
end
|
51
|
+
|
52
|
+
rates = {}
|
53
|
+
body[:to].each do |rate|
|
54
|
+
rates[rate[:quotecurrency]] = rate[:mid].to_d
|
34
55
|
end
|
35
|
-
|
36
|
-
|
56
|
+
|
57
|
+
rates
|
37
58
|
end
|
38
59
|
|
39
|
-
|
60
|
+
private
|
61
|
+
|
62
|
+
def api_get(&blk)
|
63
|
+
response = api.get do |req|
|
64
|
+
blk.call(req)
|
65
|
+
|
66
|
+
req.options.timeout = config[:read_timeout] ||
|
67
|
+
OmniExchange::Configuration::DEFAULT_READ_TIMEOUT
|
68
|
+
req.options.open_timeout = config[:connect_timeout] ||
|
69
|
+
OmniExchange::Configuration::DEFAULT_CONNECTION_TIMEOUT
|
70
|
+
end
|
71
|
+
|
40
72
|
body = JSON.parse(response.body, symbolize_names: true)
|
41
|
-
|
42
|
-
raise
|
73
|
+
|
74
|
+
raise OmniExchange::XeMonthlyLimit, 'Xe.com monthly limit has been exceeded' if body[:code] == 3
|
75
|
+
|
76
|
+
body
|
43
77
|
end
|
44
78
|
|
45
|
-
|
79
|
+
def api
|
80
|
+
api_id = config[:api_id]
|
81
|
+
api_key = config[:api_key]
|
46
82
|
|
47
|
-
|
83
|
+
Faraday.new(OmniExchange::Xe::ENDPOINT_URL) do |f|
|
84
|
+
f.request :basic_auth, api_id, api_key
|
85
|
+
f.adapter :net_http
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def config
|
90
|
+
OmniExchange.configuration.provider_config[:xe]
|
91
|
+
end
|
48
92
|
end
|
49
93
|
|
50
94
|
# when this file is required at the top of lib/omni_exchange.rb, this method call is run and allows
|
data/lib/omni_exchange.rb
CHANGED
@@ -34,7 +34,16 @@ module OmniExchange
|
|
34
34
|
end
|
35
35
|
|
36
36
|
# if a provider raises one of these exceptions, OmniExchange will gracefully attempt to use another provider
|
37
|
-
EXCEPTIONS = [
|
37
|
+
EXCEPTIONS = [
|
38
|
+
Faraday::Error,
|
39
|
+
Faraday::ConnectionFailed,
|
40
|
+
Faraday::TimeoutError,
|
41
|
+
Faraday::SSLError,
|
42
|
+
Net::OpenTimeout,
|
43
|
+
Net::WriteTimeout,
|
44
|
+
Net::ReadTimeout,
|
45
|
+
OpenSSL::SSL::SSLError
|
46
|
+
]
|
38
47
|
|
39
48
|
module_function
|
40
49
|
|
@@ -76,12 +85,18 @@ module OmniExchange
|
|
76
85
|
|
77
86
|
exchanged_amount = rate.to_d * amount.to_d
|
78
87
|
|
79
|
-
return {
|
88
|
+
return {
|
89
|
+
converted_amount: exchanged_amount,
|
90
|
+
exchange_rate: rate,
|
91
|
+
non_subunit_fx_rate: plain_format_rate,
|
92
|
+
provider: OmniExchange::Provider.all.key(klass)
|
93
|
+
}
|
80
94
|
rescue *EXCEPTIONS, OmniExchange::XeMonthlyLimit, JSON::ParserError => e
|
81
95
|
error_messages << e.inspect
|
82
96
|
end
|
83
|
-
|
84
|
-
raise OmniExchange::HttpError, "Failed to load #{base_currency}->#{target_currency}:\n
|
97
|
+
|
98
|
+
raise OmniExchange::HttpError, "Failed to load #{base_currency}->#{target_currency}:\n" \
|
99
|
+
"#{error_messages.join("\n")}"
|
85
100
|
end
|
86
101
|
end
|
87
102
|
# rubocop:enable Lint/Syntax
|
data/omni_exchange.gemspec
CHANGED
@@ -32,7 +32,7 @@ Gem::Specification.new do |spec|
|
|
32
32
|
|
33
33
|
spec.add_development_dependency 'dotenv'
|
34
34
|
spec.add_development_dependency 'pry'
|
35
|
-
spec.add_development_dependency 'rake', '~>
|
35
|
+
spec.add_development_dependency 'rake', '~> 12.3'
|
36
36
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
37
37
|
spec.add_development_dependency 'rubocop', '~> 0.80'
|
38
38
|
spec.add_development_dependency 'vcr'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: omni_exchange
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yun Chung
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-06-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -72,14 +72,14 @@ dependencies:
|
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
75
|
+
version: '12.3'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
82
|
+
version: '12.3'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: rspec
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -175,7 +175,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
175
175
|
- !ruby/object:Gem::Version
|
176
176
|
version: '0'
|
177
177
|
requirements: []
|
178
|
-
rubygems_version: 3.2.
|
178
|
+
rubygems_version: 3.2.33
|
179
179
|
signing_key:
|
180
180
|
specification_version: 4
|
181
181
|
summary: OmniExchange converts currencies using up-to-the-minute foreign exchange
|