fafx 0.1.0 → 0.1.1
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/README.md +34 -27
- data/Rakefile +2 -1
- data/bin/fafx +18 -7
- data/fafx.gemspec +1 -13
- data/lib/fafx/data_fetcher.rb +19 -22
- data/lib/fafx/er.rb +18 -22
- data/lib/fafx/exchange_rate.rb +15 -7
- data/lib/fafx/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 00740a9067c4044fd55665b0c61059c090cb1657
|
4
|
+
data.tar.gz: 61dc5c53fc2d376d850efe43e3397d43f5ab6be5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7c3a0cea20e949601b2115f9fd533922d5a81565f576a9903a6d62d0fa237553645d5d423d88f1b4000f172462342560baec3225dccf37d6698dd2cd9c4dda70
|
7
|
+
data.tar.gz: b22882852ddb68ce273973f90e17b67be2ecfdfcd7a23d8543c048c63193d64ffca22ce9e801a1b9cef71cd0f2252aaea388c289acb810926a5180e778a26b21
|
data/README.md
CHANGED
@@ -2,13 +2,15 @@
|
|
2
2
|
|
3
3
|
[](https://travis-ci.org/FrankKair/fafx)
|
4
4
|
|
5
|
-
|
5
|
+
FAFX fetches data from the 90 day European Central Bank (ECB) feed and offers a simple CLI and API to interect with.
|
6
6
|
|
7
|
-
|
7
|
+
## Installation
|
8
8
|
|
9
|
-
|
9
|
+
$ gem install fafx
|
10
10
|
|
11
|
-
|
11
|
+
## CLI
|
12
|
+
|
13
|
+
$ fafx
|
12
14
|
|
13
15
|
```
|
14
16
|
Usage: fafx [options]
|
@@ -18,42 +20,47 @@ Usage: fafx [options]
|
|
18
20
|
--update Fetches new data from the web
|
19
21
|
```
|
20
22
|
|
21
|
-
|
23
|
+
## Example of client usage
|
22
24
|
|
23
25
|
```ruby
|
24
26
|
require 'Date'
|
25
27
|
require 'fafx'
|
26
28
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
Fafx::ExchangeRate.at(Date.today, 'GBP', 'USD')
|
30
|
+
# => 1.2951645399597045
|
31
|
+
|
32
|
+
Fafx::ExchangeRate.currencies_available
|
33
|
+
# => ["USD", "JPY", "BGN", "CZK", ...]
|
32
34
|
|
33
|
-
|
35
|
+
Fafx::ExchangeRate.dates_available
|
36
|
+
# => ["2018-09-10", "2018-09-07", "2018-09-06", "2018-09-05", ...]
|
34
37
|
|
38
|
+
Fafx::ExchangeRate.most_recent
|
39
|
+
# => {"USD"=>1.1571, "JPY"=>128.54, "BGN"=>1.9558, "CZK"=>25.648, ...}
|
35
40
|
```
|
36
|
-
1.2951995012468827
|
37
41
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
42
|
+
The `at` function may raise a `KeyError` exception, should the date or currency be unavailable.
|
43
|
+
|
44
|
+
## Updating the exchange rates data
|
45
|
+
|
46
|
+
You can update the exchange rates values either via the **CLI**, **Rake task** or **programmatically**:
|
47
|
+
|
48
|
+
$ fafx --update
|
43
49
|
|
44
|
-
|
45
|
-
2018-09-06
|
46
|
-
2018-09-05
|
47
|
-
2018-09-04
|
48
|
-
...
|
50
|
+
$ rake update_data
|
49
51
|
|
50
|
-
|
52
|
+
```ruby
|
53
|
+
require 'fafx'
|
54
|
+
|
55
|
+
Fafx::ExchangeRate.fetch_data_and_save_to_disk
|
51
56
|
```
|
52
57
|
|
53
|
-
|
58
|
+
---
|
54
59
|
|
55
|
-
|
60
|
+
One can also schedule a **cron job** (the following example fetches the data every minute):
|
56
61
|
|
57
|
-
|
62
|
+
```
|
63
|
+
* * * * * . ~/.zshrc; fafx -u
|
64
|
+
```
|
58
65
|
|
59
|
-
|
66
|
+
Note: `. ~/.zshrc` is used to load the environment with the Ruby gems path, because cron uses `PATH=/usr/bin:/usr/sbin` and `SHELL=/usr/bin/sh by default`. Fonts: [here](http://man7.org/linux/man-pages/man5/crontab.5.html) and [here](http://www.adminschoice.com/crontab-quick-reference)
|
data/Rakefile
CHANGED
data/bin/fafx
CHANGED
@@ -3,14 +3,24 @@ require 'optparse'
|
|
3
3
|
require 'fafx'
|
4
4
|
|
5
5
|
ARGV[0] = '--help' if ARGV.empty?
|
6
|
-
|
6
|
+
unless ARGV[0].include?('--') || ARGV[0].include?('-')
|
7
|
+
puts "invalid option: #{ARGV[0]}"
|
8
|
+
end
|
7
9
|
|
8
10
|
options = {}
|
9
11
|
opt_parser = OptionParser.new do |opt|
|
10
|
-
opt.on('--recent', 'Lists most recent rates')
|
11
|
-
|
12
|
-
|
13
|
-
opt.on('--
|
12
|
+
opt.on('--recent', 'Lists most recent rates') do |o|
|
13
|
+
options[:recent] = o
|
14
|
+
end
|
15
|
+
opt.on('--currencies', 'Lists available currencies') do |o|
|
16
|
+
options[:currencies] = o
|
17
|
+
end
|
18
|
+
opt.on('--dates', 'Lists available dates') do |o|
|
19
|
+
options[:dates] = o
|
20
|
+
end
|
21
|
+
opt.on('--update', 'Fetches new data from the web') do |o|
|
22
|
+
options[:update] = o
|
23
|
+
end
|
14
24
|
end
|
15
25
|
|
16
26
|
begin
|
@@ -26,9 +36,10 @@ begin
|
|
26
36
|
when :dates
|
27
37
|
puts Fafx::ExchangeRate.dates_available
|
28
38
|
when :update
|
29
|
-
Fafx::
|
39
|
+
Fafx::ExchangeRate.fetch_data_and_save_to_disk
|
40
|
+
puts 'Exchange rates data updated!'
|
30
41
|
end
|
31
42
|
end
|
32
|
-
rescue
|
43
|
+
rescue StandardError => e
|
33
44
|
puts e.to_s unless e.message == 'exit'
|
34
45
|
end
|
data/fafx.gemspec
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
lib = File.expand_path('lib', __dir__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
3
|
require 'fafx/version'
|
@@ -11,23 +10,12 @@ Gem::Specification.new do |spec|
|
|
11
10
|
|
12
11
|
spec.summary = 'Exchange Rates from the European Central Bank'
|
13
12
|
spec.description = 'Lib and CLI to get exchange rates from the European Central Bank'
|
14
|
-
spec.homepage =
|
13
|
+
spec.homepage = 'https://github.com/frankkair/fafx'
|
15
14
|
spec.license = 'MIT'
|
16
15
|
|
17
|
-
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
18
|
-
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
19
|
-
# if spec.respond_to?(:metadata)
|
20
|
-
# spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
|
21
|
-
# else
|
22
|
-
# raise 'RubyGems 2.0 or newer is required to protect against ' \
|
23
|
-
# 'public gem pushes.'
|
24
|
-
# end
|
25
|
-
|
26
16
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
27
17
|
f.match(%r{^(test|spec|features)/})
|
28
18
|
end
|
29
|
-
# spec.bindir = "exe"
|
30
|
-
# spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
31
19
|
spec.executables = ['fafx']
|
32
20
|
spec.require_paths = ['lib']
|
33
21
|
|
data/lib/fafx/data_fetcher.rb
CHANGED
@@ -1,31 +1,28 @@
|
|
1
1
|
require 'open-uri'
|
2
2
|
require 'nokogiri'
|
3
3
|
|
4
|
-
module
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
end
|
4
|
+
module DataFetcher
|
5
|
+
def save_to_disk
|
6
|
+
url = 'https://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist-90d.xml'
|
7
|
+
doc = Nokogiri::XML(open(url))
|
8
|
+
rates = process_currencies_xml(doc)
|
9
|
+
dir = "#{File.join(File.dirname(__FILE__))}/rates.yaml"
|
10
|
+
File.open(dir, 'w') { |f| f << rates.to_yaml }
|
11
|
+
end
|
13
12
|
|
14
|
-
|
13
|
+
private
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
rates[time][currency[:currency]] = currency[:rate].to_f
|
24
|
-
end
|
15
|
+
def process_currencies_xml(doc)
|
16
|
+
rates = {}
|
17
|
+
doc.css('Cube>Cube[time]').each do |day|
|
18
|
+
time = day[:time]
|
19
|
+
rates[time] = {}
|
20
|
+
day.css('Cube').each do |currency|
|
21
|
+
rates[time][currency[:currency]] = currency[:rate].to_f
|
25
22
|
end
|
26
|
-
rates
|
27
23
|
end
|
28
|
-
|
29
|
-
module_function :save_to_disk, :process_currencies_xml
|
24
|
+
rates
|
30
25
|
end
|
26
|
+
|
27
|
+
module_function :save_to_disk, :process_currencies_xml
|
31
28
|
end
|
data/lib/fafx/er.rb
CHANGED
@@ -1,29 +1,25 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
@currencies = @rates[@dates.first].keys
|
12
|
-
end
|
3
|
+
class ER
|
4
|
+
attr_reader :rates, :dates, :currencies
|
5
|
+
def initialize
|
6
|
+
data = load_data
|
7
|
+
@rates = data
|
8
|
+
@dates = data.keys
|
9
|
+
@currencies = @rates[@dates.first].keys
|
10
|
+
end
|
13
11
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
12
|
+
def rates_at(date, curr)
|
13
|
+
raise KeyError, 'Date not available' unless @dates.include?(date)
|
14
|
+
raise KeyError, "#{curr} not found" unless @currencies.include?(curr)
|
15
|
+
@rates[date][curr]
|
16
|
+
end
|
19
17
|
|
20
|
-
|
18
|
+
private
|
21
19
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
YAML.load_file(rates)
|
27
|
-
end
|
20
|
+
def load_data
|
21
|
+
rates = "#{File.join(File.dirname(__FILE__))}/rates.yaml"
|
22
|
+
Fafx::ExchangeRate.fetch_data_and_save_to_disk unless File.exist?(rates)
|
23
|
+
YAML.load_file(rates)
|
28
24
|
end
|
29
25
|
end
|
data/lib/fafx/exchange_rate.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
module Fafx
|
2
2
|
module ExchangeRate
|
3
3
|
def at(date, base, other)
|
4
|
-
|
5
|
-
base =
|
6
|
-
other =
|
4
|
+
ex_rates = ER.new
|
5
|
+
base = ex_rates.rates_at(date.to_s, base)
|
6
|
+
other = ex_rates.rates_at(date.to_s, other)
|
7
7
|
other / base
|
8
8
|
end
|
9
9
|
|
@@ -16,10 +16,18 @@ module Fafx
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def most_recent
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
ex_rates = ER.new
|
20
|
+
first_date = ex_rates.dates.first
|
21
|
+
ex_rates.rates[first_date]
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
|
+
def fetch_data_and_save_to_disk
|
25
|
+
DataFetcher.save_to_disk
|
26
|
+
end
|
27
|
+
module_function :at,
|
28
|
+
:currencies_available,
|
29
|
+
:dates_available,
|
30
|
+
:most_recent,
|
31
|
+
:fetch_data_and_save_to_disk
|
24
32
|
end
|
25
33
|
end
|
data/lib/fafx/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fafx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Frank Kair
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-09-
|
11
|
+
date: 2018-09-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|