exchangeratesapi 0.1.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 +7 -0
- data/CHANGELOG.md +23 -0
- data/LICENSE +21 -0
- data/README.md +214 -0
- data/lib/exchangeratesapi/client.rb +175 -0
- data/lib/exchangeratesapi/errors.rb +36 -0
- data/lib/exchangeratesapi/payload_wrapper.rb +67 -0
- data/lib/exchangeratesapi/version.rb +5 -0
- data/lib/exchangeratesapi.rb +17 -0
- metadata +166 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ef9e9997eae5b2ccf694e05a3366d5962d2193705eaf56ae332794bf05b79920
|
4
|
+
data.tar.gz: c2a7b9ecb02a80da408c7f20689b4725330477a59db832a769599993c97f6cbf
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cebb2c92e30e7d28688a29c7d476cf69ad1c0e1fe29fce9460618c7eb8485abf8b2609bef3ae6d0f62ea3b56708fd1c4eef95c34b6bf6cbef7345b3ce18f3166
|
7
|
+
data.tar.gz: fd8a9be97cb2533a8fa6b08d943a7b8412330b1e468285d56d6b825eac715e4c98a5ae0853a2deaf4ed58faad10dea8cc347634e442e96166caeac7ee96c91b3
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
|
+
|
8
|
+
## [Unreleased]
|
9
|
+
|
10
|
+
## [0.1.0] - 2025-01-XX
|
11
|
+
|
12
|
+
### Added
|
13
|
+
- Initial release of the Exchange Rates API client gem
|
14
|
+
- Support for latest exchange rates
|
15
|
+
- Support for historical exchange rates
|
16
|
+
- Support for currency conversion
|
17
|
+
- Support for getting supported currencies
|
18
|
+
- Support for time series data (paid plan)
|
19
|
+
- Support for fluctuation data (paid plan)
|
20
|
+
- Comprehensive error handling with custom error classes
|
21
|
+
- PayloadWrapper for easy response handling
|
22
|
+
- Full test coverage with RSpec
|
23
|
+
- VCR integration for API testing
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 Mehul Jain
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,214 @@
|
|
1
|
+
# Exchange Rates API Client
|
2
|
+
|
3
|
+
A simple and efficient Ruby client for the [Exchange Rates API](https://exchangeratesapi.io/).
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'exchangeratesapi'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
```bash
|
16
|
+
$ bundle install
|
17
|
+
```
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
```bash
|
22
|
+
$ gem install exchangeratesapi
|
23
|
+
```
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
### Basic Setup
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
require 'exchangeratesapi'
|
31
|
+
|
32
|
+
# Initialize with API key
|
33
|
+
client = ExchangeRatesAPI.new('your_api_key_here')
|
34
|
+
|
35
|
+
# Or use environment variable
|
36
|
+
ENV['EXCHANGE_RATE_API_KEY'] = 'your_api_key_here'
|
37
|
+
client = ExchangeRatesAPI.new
|
38
|
+
```
|
39
|
+
|
40
|
+
### Get Latest Exchange Rates
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
# Get latest rates with USD as base currency
|
44
|
+
response = client.latest(from_currency: 'USD', to_currency: 'EUR,GBP')
|
45
|
+
|
46
|
+
puts response.success? # => true
|
47
|
+
puts response.base # => "USD"
|
48
|
+
puts response.date # => "2024-01-15"
|
49
|
+
puts response.rates['EUR'] # => 0.85
|
50
|
+
puts response.rates['GBP'] # => 0.73
|
51
|
+
|
52
|
+
# Get all available rates (no to_currency specified)
|
53
|
+
response = client.latest(from_currency: 'USD')
|
54
|
+
```
|
55
|
+
|
56
|
+
### Get Historical Exchange Rates
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
# Get rates for a specific date
|
60
|
+
response = client.historical('2024-01-01', from_currency: 'USD', to_currency: 'EUR')
|
61
|
+
|
62
|
+
puts response.historical? # => true
|
63
|
+
puts response.date # => "2024-01-01"
|
64
|
+
puts response.rates['EUR'] # => 0.84
|
65
|
+
```
|
66
|
+
|
67
|
+
### Currency Conversion
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
# Convert 100 USD to EUR
|
71
|
+
result = client.convert(amount: 100, from_currency: 'USD', to_currency: 'EUR')
|
72
|
+
|
73
|
+
puts result[:amount] # => 100
|
74
|
+
puts result[:from_currency] # => "USD"
|
75
|
+
puts result[:to_currency] # => "EUR"
|
76
|
+
puts result[:rate] # => 0.85
|
77
|
+
puts result[:converted_amount] # => 85.0
|
78
|
+
puts result[:date] # => "2024-01-15"
|
79
|
+
|
80
|
+
# Convert with historical rates
|
81
|
+
result = client.convert(
|
82
|
+
amount: 100,
|
83
|
+
from_currency: 'USD',
|
84
|
+
to_currency: 'EUR',
|
85
|
+
date: '2024-01-01'
|
86
|
+
)
|
87
|
+
```
|
88
|
+
|
89
|
+
### Get Supported Currencies
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
response = client.currencies
|
93
|
+
|
94
|
+
response.symbols.each do |code, info|
|
95
|
+
puts "#{code}: #{info['description']}"
|
96
|
+
end
|
97
|
+
# => USD: United States Dollar
|
98
|
+
# => EUR: Euro
|
99
|
+
# => GBP: British Pound Sterling
|
100
|
+
# ...
|
101
|
+
```
|
102
|
+
|
103
|
+
### Get Exchange Rate for Specific Currencies
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
# Get current rate
|
107
|
+
response = client.exchange_rate(from_currency: 'USD', to_currency: 'EUR')
|
108
|
+
|
109
|
+
# Get historical rate
|
110
|
+
response = client.exchange_rate(
|
111
|
+
from_currency: 'USD',
|
112
|
+
to_currency: 'EUR',
|
113
|
+
date: '2024-01-01'
|
114
|
+
)
|
115
|
+
```
|
116
|
+
|
117
|
+
### Advanced Features (Paid Plans)
|
118
|
+
|
119
|
+
#### Time Series Data
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
response = client.time_series(
|
123
|
+
start_date: '2024-01-01',
|
124
|
+
end_date: '2024-01-31',
|
125
|
+
from_currency: 'USD',
|
126
|
+
to_currency: 'EUR'
|
127
|
+
)
|
128
|
+
```
|
129
|
+
|
130
|
+
#### Fluctuation Data
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
response = client.fluctuation(
|
134
|
+
start_date: '2024-01-01',
|
135
|
+
end_date: '2024-01-31',
|
136
|
+
from_currency: 'USD',
|
137
|
+
to_currency: 'EUR'
|
138
|
+
)
|
139
|
+
```
|
140
|
+
|
141
|
+
## Error Handling
|
142
|
+
|
143
|
+
The gem provides specific error classes for different types of errors:
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
begin
|
147
|
+
response = client.latest
|
148
|
+
rescue ExchangeRatesAPI::AuthenticationError => e
|
149
|
+
puts "Authentication failed: #{e.message}"
|
150
|
+
rescue ExchangeRatesAPI::RateLimitError => e
|
151
|
+
puts "Rate limit exceeded: #{e.message}"
|
152
|
+
rescue ExchangeRatesAPI::ServerError => e
|
153
|
+
puts "Server error: #{e.message}"
|
154
|
+
rescue ExchangeRatesAPI::RequestError => e
|
155
|
+
puts "Request error: #{e.message}"
|
156
|
+
end
|
157
|
+
```
|
158
|
+
|
159
|
+
## Response Wrapper
|
160
|
+
|
161
|
+
All API responses are wrapped in a `PayloadWrapper` object that provides convenient access to response data:
|
162
|
+
|
163
|
+
```ruby
|
164
|
+
response = client.latest(from_currency: 'USD', to_currency: 'EUR')
|
165
|
+
|
166
|
+
# Direct access to response data
|
167
|
+
response.success? # => true/false
|
168
|
+
response.base # => base currency
|
169
|
+
response.date # => date of rates
|
170
|
+
response.rates # => hash of rates
|
171
|
+
response.timestamp # => Unix timestamp
|
172
|
+
response.historical? # => true for historical data
|
173
|
+
|
174
|
+
# Check for errors
|
175
|
+
if response.error?
|
176
|
+
error_info = response.error_info
|
177
|
+
puts "Error: #{error_info['message']} (Code: #{error_info['code']})"
|
178
|
+
end
|
179
|
+
|
180
|
+
# Convert to hash or JSON
|
181
|
+
response.to_h # => original response hash
|
182
|
+
response.to_json # => JSON string
|
183
|
+
```
|
184
|
+
|
185
|
+
## Configuration
|
186
|
+
|
187
|
+
### Environment Variables
|
188
|
+
|
189
|
+
- `EXCHANGE_RATE_API_KEY`: Your API key from exchangeratesapi.io
|
190
|
+
- `EXCHANGE_RATE_API_BASE`: Custom base URL (optional, defaults to https://api.exchangeratesapi.io/v1)
|
191
|
+
|
192
|
+
### Custom Base URL
|
193
|
+
|
194
|
+
```ruby
|
195
|
+
client = ExchangeRatesAPI.new('your_api_key', 'https://custom.api.com/v1')
|
196
|
+
```
|
197
|
+
|
198
|
+
## Development
|
199
|
+
|
200
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
201
|
+
|
202
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
203
|
+
|
204
|
+
## Contributing
|
205
|
+
|
206
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/mehul/exchangeratesapi. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/mehul/exchangeratesapi/blob/main/CODE_OF_CONDUCT.md).
|
207
|
+
|
208
|
+
## License
|
209
|
+
|
210
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
211
|
+
|
212
|
+
## Code of Conduct
|
213
|
+
|
214
|
+
Everyone interacting in the ExchangeRatesAPI project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/mehul/exchangeratesapi/blob/main/CODE_OF_CONDUCT.md).
|
@@ -0,0 +1,175 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ExchangeRatesAPI
|
4
|
+
class Client
|
5
|
+
include HTTParty
|
6
|
+
base_uri "https://api.exchangeratesapi.io/v1"
|
7
|
+
|
8
|
+
attr_reader :api_key, :base_url
|
9
|
+
|
10
|
+
def initialize(api_key = nil, base_url = nil)
|
11
|
+
@api_key = api_key || ENV.fetch("EXCHANGE_RATE_API_KEY", nil)
|
12
|
+
@base_url = base_url || ENV.fetch("EXCHANGE_RATE_API_BASE", "https://api.exchangeratesapi.io/v1")
|
13
|
+
|
14
|
+
# Set the base URI for HTTParty
|
15
|
+
self.class.base_uri @base_url
|
16
|
+
end
|
17
|
+
|
18
|
+
# Get latest exchange rates
|
19
|
+
# @param from_currency [String] Base currency (e.g., "USD")
|
20
|
+
# @param to_currency [String] Target currency (e.g., "EUR") or comma-separated list
|
21
|
+
# @return [PayloadWrapper] Response wrapped in PayloadWrapper
|
22
|
+
def latest(from_currency: "EUR", to_currency: nil)
|
23
|
+
params = { base: from_currency }
|
24
|
+
params[:symbols] = to_currency if to_currency
|
25
|
+
|
26
|
+
response = execute_request("get", "/latest", params)
|
27
|
+
parse_and_raise_error(response) unless success_response?(response)
|
28
|
+
PayloadWrapper.new(response.parsed_response)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Get historical exchange rates
|
32
|
+
# @param date [String] Date in YYYY-MM-DD format
|
33
|
+
# @param from_currency [String] Base currency (e.g., "USD")
|
34
|
+
# @param to_currency [String] Target currency (e.g., "EUR") or comma-separated list
|
35
|
+
# @return [PayloadWrapper] Response wrapped in PayloadWrapper
|
36
|
+
def historical(date, from_currency: "EUR", to_currency: nil)
|
37
|
+
params = { base: from_currency }
|
38
|
+
params[:symbols] = to_currency if to_currency
|
39
|
+
|
40
|
+
response = execute_request("get", "/#{date}", params)
|
41
|
+
parse_and_raise_error(response) unless success_response?(response)
|
42
|
+
PayloadWrapper.new(response.parsed_response)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Get exchange rate for specific currencies
|
46
|
+
# @param from_currency [String] Base currency (e.g., "USD")
|
47
|
+
# @param to_currency [String] Target currency (e.g., "EUR")
|
48
|
+
# @param date [String, nil] Optional date in YYYY-MM-DD format for historical rates
|
49
|
+
# @return [PayloadWrapper] Response wrapped in PayloadWrapper
|
50
|
+
def exchange_rate(from_currency:, to_currency:, date: nil)
|
51
|
+
if date
|
52
|
+
historical(date, from_currency: from_currency, to_currency: to_currency)
|
53
|
+
else
|
54
|
+
latest(from_currency: from_currency, to_currency: to_currency)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Get supported currencies
|
59
|
+
# @return [PayloadWrapper] Response wrapped in PayloadWrapper
|
60
|
+
def currencies
|
61
|
+
response = execute_request("get", "/symbols")
|
62
|
+
parse_and_raise_error(response) unless success_response?(response)
|
63
|
+
PayloadWrapper.new(response.parsed_response)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Convert amount between currencies
|
67
|
+
# @param amount [Numeric] Amount to convert
|
68
|
+
# @param from_currency [String] Source currency (e.g., "USD")
|
69
|
+
# @param to_currency [String] Target currency (e.g., "EUR")
|
70
|
+
# @param date [String, nil] Optional date in YYYY-MM-DD format for historical rates
|
71
|
+
# @return [Hash] Conversion result with amount and rate
|
72
|
+
def convert(amount:, from_currency:, to_currency:, date: nil)
|
73
|
+
response = exchange_rate(
|
74
|
+
from_currency: from_currency,
|
75
|
+
to_currency: to_currency,
|
76
|
+
date: date
|
77
|
+
)
|
78
|
+
|
79
|
+
rate = response.rates[to_currency]
|
80
|
+
raise ExchangeRatesAPI::Error.new("Rate not found for #{to_currency}") if rate.nil?
|
81
|
+
converted_amount = amount * rate
|
82
|
+
|
83
|
+
{
|
84
|
+
amount: amount,
|
85
|
+
from_currency: from_currency,
|
86
|
+
to_currency: to_currency,
|
87
|
+
rate: rate,
|
88
|
+
converted_amount: converted_amount,
|
89
|
+
date: response.date
|
90
|
+
}
|
91
|
+
end
|
92
|
+
|
93
|
+
# Get time series data (requires paid plan)
|
94
|
+
# @param start_date [String] Start date in YYYY-MM-DD format
|
95
|
+
# @param end_date [String] End date in YYYY-MM-DD format
|
96
|
+
# @param from_currency [String] Base currency (e.g., "USD")
|
97
|
+
# @param to_currency [String] Target currency (e.g., "EUR")
|
98
|
+
# @return [PayloadWrapper] Response wrapped in PayloadWrapper
|
99
|
+
def time_series(start_date:, end_date:, from_currency: "EUR", to_currency:)
|
100
|
+
params = {
|
101
|
+
base: from_currency,
|
102
|
+
symbols: to_currency,
|
103
|
+
start_date: start_date,
|
104
|
+
end_date: end_date
|
105
|
+
}
|
106
|
+
|
107
|
+
response = execute_request("get", "/timeseries", params)
|
108
|
+
parse_and_raise_error(response) unless success_response?(response)
|
109
|
+
PayloadWrapper.new(response.parsed_response)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Get fluctuation data (requires paid plan)
|
113
|
+
# @param start_date [String] Start date in YYYY-MM-DD format
|
114
|
+
# @param end_date [String] End date in YYYY-MM-DD format
|
115
|
+
# @param from_currency [String] Base currency (e.g., "USD")
|
116
|
+
# @param to_currency [String] Target currency (e.g., "EUR")
|
117
|
+
# @return [PayloadWrapper] Response wrapped in PayloadWrapper
|
118
|
+
def fluctuation(start_date:, end_date:, from_currency: "EUR", to_currency:)
|
119
|
+
params = {
|
120
|
+
base: from_currency,
|
121
|
+
symbols: to_currency,
|
122
|
+
start_date: start_date,
|
123
|
+
end_date: end_date
|
124
|
+
}
|
125
|
+
|
126
|
+
response = execute_request("get", "/fluctuation", params)
|
127
|
+
parse_and_raise_error(response) unless success_response?(response)
|
128
|
+
PayloadWrapper.new(response.parsed_response)
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
def execute_request(method, endpoint, params = {})
|
134
|
+
# Add API key to params if available
|
135
|
+
params[:access_key] = api_key if api_key
|
136
|
+
|
137
|
+
# Build URL with query parameters
|
138
|
+
uri = URI("#{base_url}#{endpoint}")
|
139
|
+
uri.query = URI.encode_www_form(params) unless params.empty?
|
140
|
+
|
141
|
+
self.class.send(method, uri.to_s, headers: default_headers)
|
142
|
+
end
|
143
|
+
|
144
|
+
def default_headers
|
145
|
+
{ "Content-Type" => "application/json" }
|
146
|
+
end
|
147
|
+
|
148
|
+
def parse_and_raise_error(response)
|
149
|
+
if response.code.to_s.start_with?("5")
|
150
|
+
raise_error(ServerError, response)
|
151
|
+
elsif response.code == 401
|
152
|
+
raise_error(AuthenticationError, response)
|
153
|
+
elsif response.code == 429
|
154
|
+
raise_error(RateLimitError, response)
|
155
|
+
else
|
156
|
+
raise_error(RequestError, response)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def raise_error(error_class, response)
|
161
|
+
error_message = "Error processing request: #{response.code}"
|
162
|
+
|
163
|
+
if response.parsed_response && response.parsed_response["error"]
|
164
|
+
error_info = response.parsed_response["error"]
|
165
|
+
error_message = "#{error_message} - #{error_info['info']} (Code: #{error_info['code']})"
|
166
|
+
end
|
167
|
+
|
168
|
+
raise error_class.new(error_message, error_response: response)
|
169
|
+
end
|
170
|
+
|
171
|
+
def success_response?(response)
|
172
|
+
response.code == 200
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ExchangeRatesAPI
|
4
|
+
class Error < StandardError
|
5
|
+
attr_reader :error_response
|
6
|
+
|
7
|
+
def initialize(message = nil, error_response: nil)
|
8
|
+
@error_response = error_response
|
9
|
+
super(message || "Exchange Rates API error")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class RequestError < Error
|
14
|
+
def initialize(message = nil, error_response: nil)
|
15
|
+
super(message, error_response: error_response)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class ServerError < Error
|
20
|
+
def initialize(message = nil, error_response: nil)
|
21
|
+
super(message, error_response: error_response)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class AuthenticationError < Error
|
26
|
+
def initialize(message = nil, error_response: nil)
|
27
|
+
super(message || "Authentication failed", error_response: error_response)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class RateLimitError < Error
|
32
|
+
def initialize(message = nil, error_response: nil)
|
33
|
+
super(message || "Rate limit exceeded", error_response: error_response)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ExchangeRatesAPI
|
4
|
+
class PayloadWrapper
|
5
|
+
attr_reader :data
|
6
|
+
|
7
|
+
def initialize(data)
|
8
|
+
@data = data
|
9
|
+
end
|
10
|
+
|
11
|
+
def success?
|
12
|
+
data["success"] == true
|
13
|
+
end
|
14
|
+
|
15
|
+
def base
|
16
|
+
data["base"]
|
17
|
+
end
|
18
|
+
|
19
|
+
def date
|
20
|
+
data["date"]
|
21
|
+
end
|
22
|
+
|
23
|
+
def rates
|
24
|
+
data["rates"] || {}
|
25
|
+
end
|
26
|
+
|
27
|
+
def timestamp
|
28
|
+
data["timestamp"]
|
29
|
+
end
|
30
|
+
|
31
|
+
def historical?
|
32
|
+
data["historical"] == true
|
33
|
+
end
|
34
|
+
|
35
|
+
def error?
|
36
|
+
!data["error"].nil?
|
37
|
+
end
|
38
|
+
|
39
|
+
def error_info
|
40
|
+
return nil unless error?
|
41
|
+
{
|
42
|
+
"code" => data["error"]["code"],
|
43
|
+
"message" => data["error"]["info"]
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_h
|
48
|
+
data
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_json
|
52
|
+
data.to_json
|
53
|
+
end
|
54
|
+
|
55
|
+
def method_missing(method_name, *args, &block)
|
56
|
+
if data.respond_to?(method_name)
|
57
|
+
data.send(method_name, *args, &block)
|
58
|
+
else
|
59
|
+
super
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def respond_to_missing?(method_name, include_private = false)
|
64
|
+
data.respond_to?(method_name) || super
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "httparty"
|
4
|
+
require "json"
|
5
|
+
|
6
|
+
require_relative "exchangeratesapi/version"
|
7
|
+
require_relative "exchangeratesapi/client"
|
8
|
+
require_relative "exchangeratesapi/errors"
|
9
|
+
require_relative "exchangeratesapi/payload_wrapper"
|
10
|
+
|
11
|
+
module ExchangeRatesAPI
|
12
|
+
class << self
|
13
|
+
def new(api_key = nil, base_url = nil)
|
14
|
+
Client.new(api_key, base_url)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: exchangeratesapi
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mehul Jain
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2025-07-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: httparty
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.21'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.21'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: json
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.6'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '13.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '13.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: webmock
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.18'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.18'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: vcr
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '6.0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '6.0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rubocop
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '1.0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '1.0'
|
125
|
+
description: A simple and efficient Ruby client for the Exchange Rates API (exchangeratesapi.io)
|
126
|
+
email:
|
127
|
+
- mehul@example.com
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- CHANGELOG.md
|
133
|
+
- LICENSE
|
134
|
+
- README.md
|
135
|
+
- lib/exchangeratesapi.rb
|
136
|
+
- lib/exchangeratesapi/client.rb
|
137
|
+
- lib/exchangeratesapi/errors.rb
|
138
|
+
- lib/exchangeratesapi/payload_wrapper.rb
|
139
|
+
- lib/exchangeratesapi/version.rb
|
140
|
+
homepage: https://github.com/mehul/exchangeratesapi
|
141
|
+
licenses:
|
142
|
+
- MIT
|
143
|
+
metadata:
|
144
|
+
homepage_uri: https://github.com/mehul/exchangeratesapi
|
145
|
+
source_code_uri: https://github.com/mehul/exchangeratesapi
|
146
|
+
changelog_uri: https://github.com/mehul/exchangeratesapi/blob/main/CHANGELOG.md
|
147
|
+
post_install_message:
|
148
|
+
rdoc_options: []
|
149
|
+
require_paths:
|
150
|
+
- lib
|
151
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
152
|
+
requirements:
|
153
|
+
- - ">="
|
154
|
+
- !ruby/object:Gem::Version
|
155
|
+
version: 2.6.0
|
156
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
157
|
+
requirements:
|
158
|
+
- - ">="
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '0'
|
161
|
+
requirements: []
|
162
|
+
rubygems_version: 3.3.5
|
163
|
+
signing_key:
|
164
|
+
specification_version: 4
|
165
|
+
summary: Ruby client for the Exchange Rates API
|
166
|
+
test_files: []
|