exchangerate_host 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2b733284dbe5f7ac5c8a2319d805f045441b8584dd6ef32ab949bb872313ca2d
4
+ data.tar.gz: 0c32fc76a35080bb289fccc759c5a48f9de752508ae78198a7fafe2705306241
5
+ SHA512:
6
+ metadata.gz: d19e19648209895fb2e998550487e71df88b961702ac2be96847200ca0b181824fb9d41f197990842976b21647fa49e44cffa27ad5f3104342e919279a4da18b
7
+ data.tar.gz: 25b9af691b46c5d06474e04d65fef70b30b34439df2390509825310abff16e04db2155302aa09d28af5a9966f2b327ec5eedf3d336ad4d78c8b3f18b588f5f22
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,200 @@
1
+ AllCops:
2
+ # RuboCop has a bunch of cops enabled by default. This setting tells RuboCop
3
+ # to ignore them, so only the ones explicitly set in this file are enabled.
4
+ DisabledByDefault: true
5
+
6
+ # Prefer &&/|| over and/or.
7
+ Style/AndOr:
8
+ Enabled: true
9
+
10
+ # Align `when` with `case`.
11
+ Layout/CaseIndentation:
12
+ Enabled: true
13
+
14
+ Layout/ClosingHeredocIndentation:
15
+ Enabled: true
16
+
17
+ # Align comments with method definitions.
18
+ Layout/CommentIndentation:
19
+ Enabled: true
20
+
21
+ # Align if else statements.
22
+ Layout/ElseAlignment:
23
+ Enabled: true
24
+
25
+ # Align `end` with the matching keyword or starting expression except for
26
+ # assignments, where it should be aligned with the LHS.
27
+ Layout/EndAlignment:
28
+ Enabled: true
29
+ EnforcedStyleAlignWith: variable
30
+ AutoCorrect: true
31
+
32
+ # Leave a line after frozenstring comment.
33
+ Layout/EmptyLineAfterMagicComment:
34
+ Enabled: true
35
+
36
+ # Leave a line before access modifiers.
37
+ Layout/EmptyLinesAroundAccessModifier:
38
+ Enabled: true
39
+ EnforcedStyle: only_before
40
+
41
+ # In a regular block, no empty lines around the body.
42
+ Layout/EmptyLinesAroundBlockBody:
43
+ Enabled: true
44
+
45
+ # In a regular class definition, no empty lines around the body.
46
+ Layout/EmptyLinesAroundClassBody:
47
+ Enabled: true
48
+
49
+ # In a regular method definition, no empty lines around the body.
50
+ Layout/EmptyLinesAroundMethodBody:
51
+ Enabled: true
52
+
53
+ # In a regular module definition, no empty lines around the body.
54
+ Layout/EmptyLinesAroundModuleBody:
55
+ Enabled: true
56
+
57
+ # Use Ruby >= 1.9 syntax for hashes. Prefer { a: :b } over { :a => :b }.
58
+ Style/HashSyntax:
59
+ Enabled: true
60
+
61
+ Layout/FirstArgumentIndentation:
62
+ Enabled: true
63
+
64
+ # Method definitions after `private` or `protected` isolated calls need one
65
+ # extra level of indentation.
66
+ Layout/IndentationConsistency:
67
+ Enabled: true
68
+ EnforcedStyle: indented_internal_methods
69
+
70
+ # Two spaces, no tabs (for indentation).
71
+ Layout/IndentationWidth:
72
+ Enabled: true
73
+
74
+ Layout/LeadingCommentSpace:
75
+ Enabled: true
76
+
77
+ Layout/SpaceAfterColon:
78
+ Enabled: true
79
+
80
+ Layout/SpaceAfterComma:
81
+ Enabled: true
82
+
83
+ Layout/SpaceAfterSemicolon:
84
+ Enabled: true
85
+
86
+ Layout/SpaceAroundEqualsInParameterDefault:
87
+ Enabled: true
88
+
89
+ Layout/SpaceAroundKeyword:
90
+ Enabled: true
91
+
92
+ Layout/SpaceBeforeComma:
93
+ Enabled: true
94
+
95
+ Layout/SpaceBeforeComment:
96
+ Enabled: true
97
+
98
+ Layout/SpaceBeforeFirstArg:
99
+ Enabled: true
100
+
101
+ Style/DefWithParentheses:
102
+ Enabled: true
103
+
104
+ # Defining a method with parameters needs parentheses.
105
+ Style/MethodDefParentheses:
106
+ Enabled: true
107
+
108
+ Style/RedundantFreeze:
109
+ Enabled: true
110
+
111
+ # Use `foo {}` not `foo{}`.
112
+ Layout/SpaceBeforeBlockBraces:
113
+ Enabled: true
114
+
115
+ # Use `foo { bar }` not `foo {bar}`.
116
+ Layout/SpaceInsideBlockBraces:
117
+ Enabled: true
118
+ EnforcedStyleForEmptyBraces: space
119
+
120
+ # Use `{ a: 1 }` not `{a:1}`.
121
+ Layout/SpaceInsideHashLiteralBraces:
122
+ Enabled: true
123
+
124
+ Layout/SpaceInsideParens:
125
+ Enabled: true
126
+
127
+ # TODO: What quote style????
128
+ # Check quotes usage according to lint rule below.
129
+ # Style/StringLiterals:
130
+ # Enabled: true
131
+ # EnforcedStyle: single_quotes
132
+
133
+ # Detect hard tabs, no hard tabs.
134
+ Layout/IndentationStyle:
135
+ Enabled: true
136
+
137
+ # Blank lines should not have any spaces.
138
+ Layout/TrailingEmptyLines:
139
+ Enabled: true
140
+
141
+ # No trailing whitespace.
142
+ Layout/TrailingWhitespace:
143
+ Enabled: true
144
+
145
+ # Use quotes for string literals when they are enough.
146
+ Style/RedundantPercentQ:
147
+ Enabled: true
148
+
149
+ Lint/AmbiguousOperator:
150
+ Enabled: true
151
+
152
+ Lint/AmbiguousRegexpLiteral:
153
+ Enabled: true
154
+
155
+ Lint/ErbNewArguments:
156
+ Enabled: true
157
+
158
+ # Use my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
159
+ Lint/RequireParentheses:
160
+ Enabled: true
161
+
162
+ # Check for outer and inner local block barivales sharing a name.
163
+ # https://www.rubydoc.info/github/bbatsov/RuboCop/RuboCop/Cop/Lint/ShadowingOuterLocalVariable
164
+ Lint/ShadowingOuterLocalVariable:
165
+ Enabled: true
166
+
167
+ Lint/RedundantStringCoercion:
168
+ Enabled: true
169
+
170
+ Lint/UriEscapeUnescape:
171
+ Enabled: true
172
+
173
+ Lint/UselessAssignment:
174
+ Enabled: true
175
+
176
+ # Checks for depricated ruby class methods.
177
+ # https://www.rubydoc.info/github/bbatsov/RuboCop/RuboCop/Cop/Lint/DeprecatedClassMethods
178
+ Lint/DeprecatedClassMethods:
179
+ Enabled: true
180
+
181
+ Style/ParenthesesAroundCondition:
182
+ Enabled: true
183
+
184
+ Style/RedundantBegin:
185
+ Enabled: true
186
+
187
+ Style/RedundantReturn:
188
+ Enabled: true
189
+ AllowMultipleReturnValues: true
190
+
191
+ Style/Semicolon:
192
+ Enabled: true
193
+ AllowAsExpressionSeparator: true
194
+
195
+ # Prefer Foo.method over Foo::method
196
+ Style/ColonMethodCall:
197
+ Enabled: true
198
+
199
+ Style/TrivialAccessors:
200
+ Enabled: true
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ ---
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.7.2
6
+ before_install: gem install bundler -v 2.1.4
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in exchangerate_host.gemspec
4
+ gemspec
5
+
6
+ gem "rake", "~> 12.0"
7
+ gem "rspec", "~> 3.0"
8
+
9
+ gem 'httparty'
data/Gemfile.lock ADDED
@@ -0,0 +1,43 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ exchangerate_host (0.0.1)
5
+ httparty
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ diff-lcs (1.4.4)
11
+ httparty (0.18.1)
12
+ mime-types (~> 3.0)
13
+ multi_xml (>= 0.5.2)
14
+ mime-types (3.3.1)
15
+ mime-types-data (~> 3.2015)
16
+ mime-types-data (3.2021.0704)
17
+ multi_xml (0.6.0)
18
+ rake (12.3.3)
19
+ rspec (3.10.0)
20
+ rspec-core (~> 3.10.0)
21
+ rspec-expectations (~> 3.10.0)
22
+ rspec-mocks (~> 3.10.0)
23
+ rspec-core (3.10.1)
24
+ rspec-support (~> 3.10.0)
25
+ rspec-expectations (3.10.1)
26
+ diff-lcs (>= 1.2.0, < 2.0)
27
+ rspec-support (~> 3.10.0)
28
+ rspec-mocks (3.10.2)
29
+ diff-lcs (>= 1.2.0, < 2.0)
30
+ rspec-support (~> 3.10.0)
31
+ rspec-support (3.10.2)
32
+
33
+ PLATFORMS
34
+ ruby
35
+
36
+ DEPENDENCIES
37
+ exchangerate_host!
38
+ httparty
39
+ rake (~> 12.0)
40
+ rspec (~> 3.0)
41
+
42
+ BUNDLED WITH
43
+ 2.1.4
data/README.md ADDED
@@ -0,0 +1,136 @@
1
+ # ExchangerateHost
2
+
3
+ ExchangerateHost is a very simple gem to integrate your ruby application with [exchangerate.host](https://exchangerate.host) 🚀
4
+ [exchangerate.host](https://exchangerate.host) is a great service that provide us completely free curreny exhange rates APIs (you don't even need to make an account & api key!! Really easy to get started 🙂 ).
5
+
6
+ Let's [support](https://exchangerate.host/#/donate) their mission if you're happy with the service and willing to donate 👼
7
+
8
+ ## Installation
9
+ Install with the following command:
10
+
11
+ $ gem install exchangerate_host
12
+
13
+ For rails appliactions, add this line to your application's Gemfile:
14
+
15
+ ```ruby
16
+ gem 'exchangerate_host'
17
+ ```
18
+
19
+ And then execute:
20
+
21
+ $ bundle install
22
+
23
+ ## Supported services
24
+ | Service | Descriptoin | Supported |
25
+ | ------------- | ------ |:-------------:|
26
+ | Latest rates | The latest exchage rate data updated on daily basis | ✔️ |
27
+ | Convert currency | Convert any amount from one currency to another | ✔️ |
28
+ | Historical rates | Currency rates histrical data all the way back to the year of `1999` | ✔️ |
29
+ | Time-Series data | Historical rates between two dates of your choic. (maximum time frame of `366 days`) | ✔️ |
30
+ | Fluctuation data | Historical data about how currencies fluctuate on a day-to-day basis (maximum time frame of `366 days`) | ✔️ |
31
+ | Supported symbols | All available currencies | ✔️ |
32
+ | EU VAT Rates | Request a single by country code or entire set EU VAT rates | WIP |
33
+
34
+ You can find details about services in [here](https://exchangerate.host/#/#our-services)
35
+ ## Parameters
36
+ | Parameter | Description | Example | Note |
37
+ | ------------- |:-------------:| :---: | :-----: |
38
+ | base | Your preferred base currency | JPY | non case sensitive |
39
+ | symbols | Currency codes to limit output currencies | [:JPY, :AUD, :USD] | non case sensitive |
40
+ | amount | The amount to be converted | 123.45 | - |
41
+ | places | Decimal places | 2 | - |
42
+ | format | Output format | CSV | CSV, TSV or XML |
43
+ | from | The currecny you would like to convert from | JPY | non case sensitive |
44
+ | to | The currecny you would like to convert to | AUD | non case sensitive |
45
+ | date | Historical exchange rate date | 2020-12-21 | format YYYY-MM-DD |
46
+ | start_date | The start date of your preferred timeframe | 2020-12-21 | format YYYY-MM-DD |
47
+ | end_date | The end date of your preferred timeframe | 2020-12-21 | format YYYY-MM-DD |
48
+
49
+ ## Service Paramters
50
+ 🟢 _optional_ 🔴 _required_
51
+ | Service | base | symbols | amount | places | format | from | to | date | start_date | end_date |
52
+ |:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|
53
+ | Latest rates | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | - | - | - | - | - |
54
+ | Convert currency | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | - | - |
55
+ | Historical rates | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | - | - | 🔴 | - | - |
56
+ | Time-Series data | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | - | - | - | 🔴 | 🔴 |
57
+ | Fluctuation data | 🟢 | 🟢 | 🟢 | 🟢 | 🟢 | - | - | - | 🔴 | 🔴 |
58
+ | Supported symbols | - | - | - | - | 🟢 | - | - | - | - | - |
59
+
60
+
61
+ If `base` option is not given, `EUR` will be assigned
62
+ If `amount` option is not given, `1` will be assigned
63
+
64
+ ## Usage
65
+ You can make call supporetd survices with following APIs
66
+ | Service | method | arguments |
67
+ | ------------- |:-------------:| :-------------:|
68
+ | Latest rates | ExchangerateHost.latest_rates(options) | options: Hash |
69
+ | Convert currency | ExchangerateHost.convert_currency(options) | options: Hash |
70
+ | Historical rates | ExchangerateHost.historical_rates(options) | options: Hash |
71
+ | Time-Series data | ExchangerateHost.time_series(options) | options: Hash |
72
+ | Fluctuation data | ExchangerateHost.fluctuation(options) | options: Hash |
73
+ | Supported symbols |ExchangerateHost.supported_symbols(options) | options: Hash |
74
+
75
+
76
+
77
+ _exmaples_
78
+ ```ruby
79
+ # Decimal place 2
80
+ ExchangerateHost.configurations.places = 2
81
+
82
+ # How much is 1000 yen in AUD and USD with the latest currency rates
83
+ res = ExchangerateHost.latest_rates({ base: :JPY, amount: 1000, symbols: [:AUD, :USD] })
84
+ res['rates'] #=> {"AUD"=>12.59, "USD"=>9.1}
85
+
86
+ # How much is 150 AUD in JPY on 2015 December 21st
87
+ res = ExchangerateHost.convert_currency({ from: :AUD, to: :JPY, date: '2015-12-21', amount: 150 })
88
+ res['result'] #=> 13038.47
89
+
90
+ # What were the all supported currency rates for 1 AUD on 2020 December 21st
91
+ res = ExchangerateHost.historical_rates({date: '2020-12-21', base: :USD })
92
+ res['rates'] #=> { "AED"=>3.69, "AFN"=>77.4, "ALL"=>101.52... }
93
+
94
+ # What were the JPY and USD rates based on 1 AUD between 2021 January 1st ~ 2021 Febrary 1st
95
+ res = ExchangerateHost.time_series({ base: :AUD, symbols: [:JPY, :USD], start_date: '2021-01-01', end_date: '2021-02-01' })
96
+ res['rates'] #=> {"2021-01-01"=>{"JPY"=>79.56, "USD"=>0.77}, "2021-01-02"=>{"JPY"=>79.29, "USD"=>0.77}, "2021-01-03"=>{"JPY"=>79.42, "USD"=>0.77},... }
97
+
98
+ # How much JPY and USD rates based on 1 AUD fluctuated between 2020 January 1st ~ 2020 October 1st
99
+ res = ExchangerateHost.fluctuation({ base: :AUD, symbols: [:JPY, :USD], start_date: '2020-01-01', end_date: '2020-10-01' })
100
+ res['rates'] #=> {"USD"=>{"start_rate"=>0.7, "end_rate"=>0.72, "change"=>-0.02, "change_pct"=>-0.03}, "JPY"=>{... }
101
+
102
+ # What are the suported currencies
103
+ res = ExchangerateHost.supported_symbols
104
+ res['symbols'] #=> {"AED"=>{"description"=>"United Arab Emirates Dirham", "code"=>"AED"}, "AFN"=>{"description"=>"Afghan Afghani", "code"=>"AFN"}... }
105
+ ```
106
+
107
+ ## Setup default parameter options
108
+ You can set default parameter options so that you don't need to pass the same options everytime.
109
+ ```ruby
110
+ ExchangerateHost.configure do |conf|
111
+ conf.base = :JPY
112
+ conf.symbols = [:AUD, :USD]
113
+ end
114
+ # or
115
+ ExchangerateHost.configurations.base = :JPY
116
+
117
+ # print currernt configuratoins
118
+ ExchangerateHost.configurations.to_options_hash #=> {:base=>:JPY, :symbols=>[:AUD, :USD]}
119
+
120
+ # reset configurations
121
+ ExchangerateHost.reset_configurations
122
+ ExchangerateHost.configurations.to_options_hash #=> {}
123
+
124
+ # default options will be overwritten by the passed option value
125
+ ExchangerateHost.configurations.base = :JPY
126
+
127
+ ExchangerateHost.latest_rates #=> the base option for the request is JPY
128
+ ExchangerateHost.latest_rates({ base: :AUD }) #=> the base option for the request is now AUD
129
+ ```
130
+
131
+
132
+
133
+ ## Contributing
134
+
135
+ Bug reports and pull requests are welcome on GitHub at https://github.com/MizukiZ/exchangerate_host. 🙏
136
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "exchangerate_host"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,29 @@
1
+ require_relative 'lib/exchangerate_host/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "exchangerate_host"
5
+ spec.version = ExchangerateHost::VERSION
6
+ spec.authors = ["Mizuki Zenta"]
7
+ spec.email = ["mizukisb@gmail.com"]
8
+
9
+ spec.summary = 'A Ruby library to integrate ruby application with exchangerate.host'
10
+ spec.description = 'A Ruby library to integrate ruby application with exchangerate.host'
11
+ spec.homepage = 'https://github.com/MizukiZ/exchangerate_host'
12
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
13
+ spec.license = 'MIT'
14
+
15
+ spec.metadata["homepage_uri"] = spec.homepage
16
+ spec.metadata["source_code_uri"] = 'https://github.com/MizukiZ/exchangerate_host'
17
+ spec.metadata["changelog_uri"] = 'https://github.com/MizukiZ/exchangerate_host'
18
+
19
+ # Specify which files should be added to the gem when it is released.
20
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
22
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
23
+ end
24
+ spec.bindir = "exe"
25
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
+ spec.require_paths = ["lib"]
27
+
28
+ spec.add_dependency "httparty"
29
+ end
@@ -0,0 +1,16 @@
1
+ module ExchangerateHost
2
+ class Configurations
3
+ attr_accessor :base, :symbols, :places, :amount, :format, :from, :to, :date, :start_date, :end_date
4
+
5
+ def initialize
6
+ # Default value can be set here.
7
+ # @places = 2
8
+ end
9
+
10
+ def to_options_hash
11
+ self.instance_variables.map do |var|
12
+ [var[1..-1].to_sym, self.instance_variable_get(var)]
13
+ end.to_h
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,54 @@
1
+ require 'httparty'
2
+ require 'date'
3
+ require 'exchangerate_host/endpoints/validation'
4
+
5
+ module ExchangerateHost
6
+ module Endpoints
7
+ class Base
8
+ include HTTParty
9
+ extend Endpoints::Validation
10
+
11
+ base_uri 'https://api.exchangerate.host'
12
+
13
+ class << self
14
+ def available_options
15
+ required_options + optional_options
16
+ end
17
+
18
+ def endpoint_path
19
+ ''
20
+ end
21
+
22
+ def optional_options
23
+ raise NotImplementedError
24
+ end
25
+
26
+ def required_options
27
+ []
28
+ end
29
+
30
+ def request(options)
31
+ @query = query_options(options)
32
+ res = get(
33
+ "/#{endpoint_path}",
34
+ { query: @query }
35
+ )
36
+ .body
37
+
38
+ res = JSON.parse(res) unless @query[:format]
39
+ res
40
+ end
41
+
42
+ def query_options(options)
43
+ config_options = ExchangerateHost.configurations.to_options_hash.slice(*available_options)
44
+ merged_options = config_options.merge(options)
45
+
46
+ validate(merged_options)
47
+ merged_options[:symbols] = to_upcase_csv(merged_options[:symbols]) if merged_options.key?(:symbols)
48
+
49
+ merged_options
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,20 @@
1
+ require 'exchangerate_host/endpoints/base'
2
+ module ExchangerateHost
3
+ module Endpoints
4
+ class ConvertCurrency < Base
5
+ class << self
6
+ def optional_options
7
+ [:base, :symbols, :places, :amount, :format, :date]
8
+ end
9
+
10
+ def required_options
11
+ [:from, :to]
12
+ end
13
+
14
+ def endpoint_path
15
+ 'convert'
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ require 'exchangerate_host/endpoints/base'
2
+ module ExchangerateHost
3
+ module Endpoints
4
+ class Fluctuation < Base
5
+ class << self
6
+ def optional_options
7
+ [:base, :symbols, :places, :amount, :format]
8
+ end
9
+
10
+ def required_options
11
+ [:start_date, :end_date]
12
+ end
13
+
14
+ def endpoint_path
15
+ 'fluctuation'
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ require 'exchangerate_host/endpoints/base'
2
+ module ExchangerateHost
3
+ module Endpoints
4
+ class HistoricalRates < Base
5
+ class << self
6
+ def optional_options
7
+ [:base, :symbols, :places, :amount, :format]
8
+ end
9
+
10
+ def required_options
11
+ [:date]
12
+ end
13
+
14
+ def endpoint_path
15
+ @query[:date]
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,16 @@
1
+ require 'exchangerate_host/endpoints/base'
2
+ module ExchangerateHost
3
+ module Endpoints
4
+ class LatestRates < Base
5
+ class << self
6
+ def optional_options
7
+ [:base, :symbols, :places, :amount, :format]
8
+ end
9
+
10
+ def endpoint_path
11
+ 'latest'
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ require 'exchangerate_host/endpoints/base'
2
+ module ExchangerateHost
3
+ module Endpoints
4
+ class SupportedSymbols < Base
5
+ class << self
6
+ def optional_options
7
+ [:format]
8
+ end
9
+
10
+ def endpoint_path
11
+ 'symbols'
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ require 'exchangerate_host/endpoints/base'
2
+ module ExchangerateHost
3
+ module Endpoints
4
+ class TimeSeries < Base
5
+ class << self
6
+ def optional_options
7
+ [:base, :symbols, :places, :amount, :format]
8
+ end
9
+
10
+ def required_options
11
+ [:start_date, :end_date]
12
+ end
13
+
14
+ def endpoint_path
15
+ 'timeseries'
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,106 @@
1
+ module ExchangerateHost
2
+ module Endpoints
3
+ module Validation
4
+ ACCEPTABLE_DATE_FORMAT = /^\d{4}\-(0[1-9]|1[012])\-(0[1-9]|[12][0-9]|3[01])$/.freeze
5
+
6
+ VALID_SYMBOLS = [
7
+ :AED, :AFN, :ALL, :AMD, :ANG, :AOA, :ARS, :AUD, :AWG, :AZN, :BAM, :BBD,
8
+ :BDT, :BGN, :BHD, :BIF, :BMD, :BND, :BOB, :BRL, :BSD, :BTC, :BTN, :BWP,
9
+ :BYN, :BZD, :CAD, :CDF, :CHF, :CLF, :CLP, :CNH, :CNY, :COP, :CRC, :CUC,
10
+ :CUP, :CVE, :CZK, :DJF, :DKK, :DOP, :DZD, :EGP, :ERN, :ETB, :EUR, :FJD,
11
+ :FKP, :GBP, :GEL, :GGP, :GHS, :GIP, :GMD, :GNF, :GTQ, :GYD, :HKD, :HNL,
12
+ :HRK, :HTG, :HUF, :IDR, :ILS, :IMP, :INR, :IQD, :IRR, :ISK, :JEP, :JMD,
13
+ :JOD, :JPY, :KES, :KGS, :KHR, :KMF, :KPW, :KRW, :KWD, :KYD, :KZT, :LAK,
14
+ :LBP, :LKR, :LRD, :LSL, :LYD, :MAD, :MDL, :MGA, :MKD, :MMK, :MNT, :MOP,
15
+ :MRO, :MRU, :MUR, :MVR, :MWK, :MXN, :MYR, :MZN, :NAD, :NGN, :NIO, :NOK,
16
+ :NPR, :NZD, :OMR, :PAB, :PEN, :PGK, :PHP, :PKR, :PLN, :PYG, :QAR, :RON,
17
+ :RSD, :RUB, :RWF, :SAR, :SBD, :SCR, :SDG, :SEK, :SGD, :SHP, :SLL, :SOS,
18
+ :SRD, :SSP, :STD, :STN, :SVC, :SYP, :SZL, :THB, :TJS, :TMT, :TND, :TOP,
19
+ :TRY, :TTD, :TWD, :TZS, :UAH, :UGX, :USD, :UYU, :UZS, :VEF, :VES, :VND,
20
+ :VUV, :WST, :XAF, :XAG, :XAU, :XCD, :XDR, :XOF, :XPD, :XPF, :XPT, :YER,
21
+ :ZAR, :ZMW, :ZWL].freeze
22
+
23
+ VALID_FORMAT = [:CSV, :TSV, :XML].freeze
24
+
25
+ ALL_OPTIONS_WITH_VALIDATE_METHODS = {
26
+ from: { validate_with: VALID_SYMBOLS, action: :subset },
27
+ to: { validate_with: VALID_SYMBOLS, action: :subset },
28
+ date: { validate_with: ACCEPTABLE_DATE_FORMAT, action: :date },
29
+ start_date: { validate_with: ACCEPTABLE_DATE_FORMAT, action: :date },
30
+ end_date: { validate_with: ACCEPTABLE_DATE_FORMAT, action: :date },
31
+ base: { validate_with: VALID_SYMBOLS, action: :subset },
32
+ symbols: { validate_with: VALID_SYMBOLS, action: :subset },
33
+ places: { validate_with: :PositiveInteger, action: :type },
34
+ amount: { validate_with: :Numeric, action: :type },
35
+ format: { validate_with: VALID_FORMAT, action: :subset },
36
+ }.freeze
37
+
38
+ def to_upcase_csv(array)
39
+ return '' unless array
40
+
41
+ array.map(&:upcase).join(',')
42
+ end
43
+
44
+ def validate_with_type(option, validate_with, v)
45
+ if validate_with == :PositiveInteger
46
+ raise "#{option} must be a positive whole number" unless is_positive_integer?(v)
47
+ elsif validate_with == :Numeric
48
+ raise "#{option} must be a number" unless v.is_a?(Numeric)
49
+ end
50
+ end
51
+
52
+ def is_positive_integer?(v)
53
+ v.is_a?(Integer) && v > 0
54
+ end
55
+
56
+ def non_subset_values(array, original_array)
57
+ array.map(&:to_sym) - original_array
58
+ end
59
+
60
+ def validate_subset(array, original_array)
61
+ invalid_values = non_subset_values(array, original_array)
62
+ raise "Invalid options/values detected: #{invalid_values.join(', ')}" if invalid_values.any?
63
+ end
64
+
65
+ def validate_date(date)
66
+ raise 'Invalid date format. Please use YYYY-MM-DD' unless date =~ ACCEPTABLE_DATE_FORMAT
67
+ Date.parse(date) # this is only for validation purpose
68
+ end
69
+
70
+ def validate(options)
71
+ validate_options(options)
72
+
73
+ options.each do |option, value|
74
+ validate_option_values(option, value)
75
+ end
76
+ end
77
+
78
+ def validate_options(options)
79
+ option_keys = options.keys
80
+
81
+ validate_required_options(option_keys) if required_options.any?
82
+
83
+ return if option_keys.empty?
84
+ validate_subset(option_keys, available_options)
85
+ end
86
+
87
+ def validate_option_values(option, v)
88
+ validate_with = ALL_OPTIONS_WITH_VALIDATE_METHODS[option][:validate_with]
89
+ validate_action = ALL_OPTIONS_WITH_VALIDATE_METHODS[option][:action]
90
+
91
+ if validate_action == :subset
92
+ validate_subset(Array(v).map(&:upcase), validate_with)
93
+ elsif validate_action == :type
94
+ validate_with_type(option, validate_with, v)
95
+ elsif validate_action == :date
96
+ validate_date(v)
97
+ end
98
+ end
99
+
100
+ def validate_required_options(option_keys)
101
+ missing_required_options = required_options - option_keys
102
+ raise "Missing required options: #{missing_required_options.join(', ')}" if missing_required_options.any?
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,3 @@
1
+ module ExchangerateHost
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,50 @@
1
+ require 'exchangerate_host/endpoints/latest_rates'
2
+ require 'exchangerate_host/endpoints/supported_symbols'
3
+ require 'exchangerate_host/endpoints/convert_currency'
4
+ require 'exchangerate_host/endpoints/historical_rates'
5
+ require 'exchangerate_host/endpoints/time_series'
6
+ require 'exchangerate_host/endpoints/fluctuation'
7
+ require 'exchangerate_host/version'
8
+ require 'exchangerate_host/configurations'
9
+
10
+ module ExchangerateHost
11
+ class << self
12
+ attr_accessor :configurations
13
+
14
+ def configurations
15
+ @configurations ||= Configurations.new
16
+ end
17
+
18
+ def configure
19
+ yield(configurations)
20
+ end
21
+
22
+ def reset_configurations
23
+ @configurations = Configurations.new
24
+ end
25
+
26
+ def latest_rates(options = {})
27
+ Endpoints::LatestRates.request(options)
28
+ end
29
+
30
+ def convert_currency(options = {})
31
+ Endpoints::ConvertCurrency.request(options)
32
+ end
33
+
34
+ def historical_rates(options = {})
35
+ Endpoints::HistoricalRates.request(options)
36
+ end
37
+
38
+ def time_series(options = {})
39
+ Endpoints::TimeSeries.request(options)
40
+ end
41
+
42
+ def fluctuation(options = {})
43
+ Endpoints::Fluctuation.request(options)
44
+ end
45
+
46
+ def supported_symbols(options = {})
47
+ Endpoints::SupportedSymbols.request(options)
48
+ end
49
+ end
50
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: exchangerate_host
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Mizuki Zenta
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-09-12 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'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: A Ruby library to integrate ruby application with exchangerate.host
28
+ email:
29
+ - mizukisb@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - ".gitignore"
35
+ - ".rspec"
36
+ - ".rubocop.yml"
37
+ - ".travis.yml"
38
+ - Gemfile
39
+ - Gemfile.lock
40
+ - README.md
41
+ - Rakefile
42
+ - bin/console
43
+ - bin/setup
44
+ - exchangerate_host.gemspec
45
+ - lib/exchangerate_host.rb
46
+ - lib/exchangerate_host/configurations.rb
47
+ - lib/exchangerate_host/endpoints/base.rb
48
+ - lib/exchangerate_host/endpoints/convert_currency.rb
49
+ - lib/exchangerate_host/endpoints/fluctuation.rb
50
+ - lib/exchangerate_host/endpoints/historical_rates.rb
51
+ - lib/exchangerate_host/endpoints/latest_rates.rb
52
+ - lib/exchangerate_host/endpoints/supported_symbols.rb
53
+ - lib/exchangerate_host/endpoints/time_series.rb
54
+ - lib/exchangerate_host/endpoints/validation.rb
55
+ - lib/exchangerate_host/version.rb
56
+ homepage: https://github.com/MizukiZ/exchangerate_host
57
+ licenses:
58
+ - MIT
59
+ metadata:
60
+ homepage_uri: https://github.com/MizukiZ/exchangerate_host
61
+ source_code_uri: https://github.com/MizukiZ/exchangerate_host
62
+ changelog_uri: https://github.com/MizukiZ/exchangerate_host
63
+ post_install_message:
64
+ rdoc_options: []
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: 2.3.0
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ requirements: []
78
+ rubygems_version: 3.1.4
79
+ signing_key:
80
+ specification_version: 4
81
+ summary: A Ruby library to integrate ruby application with exchangerate.host
82
+ test_files: []