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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 93feca2af8fb931f0c8e62b0f3aea2bf24eaaf9c
4
- data.tar.gz: 4bcdfbf6645958ed69b014d6d5f737728b6e36b0
3
+ metadata.gz: 00740a9067c4044fd55665b0c61059c090cb1657
4
+ data.tar.gz: 61dc5c53fc2d376d850efe43e3397d43f5ab6be5
5
5
  SHA512:
6
- metadata.gz: 1e52c5a8b4c5c7895ff69da56cb93c8807e8fd8b47dbcbc8636254e9772c99c216b7518eb05295ed02750e34a6202c303de81e3518d598ed4d5676a99e393f9f
7
- data.tar.gz: 240f24101ace83b8f0829d77bfb14896490b227ac4e8aa61a38b8374f38d464dfc14c60c3e877f44596d60e7b76b92bf3e778477e0e7e34ce048fc00cb50f0c6
6
+ metadata.gz: 7c3a0cea20e949601b2115f9fd533922d5a81565f576a9903a6d62d0fa237553645d5d423d88f1b4000f172462342560baec3225dccf37d6698dd2cd9c4dda70
7
+ data.tar.gz: b22882852ddb68ce273973f90e17b67be2ecfdfcd7a23d8543c048c63193d64ffca22ce9e801a1b9cef71cd0f2252aaea388c289acb810926a5180e778a26b21
data/README.md CHANGED
@@ -2,13 +2,15 @@
2
2
 
3
3
  [![Build Status](https://travis-ci.org/FrankKair/fafx.svg?branch=master)](https://travis-ci.org/FrankKair/fafx)
4
4
 
5
- ### Installation
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
- `$ gem install fafx`
7
+ ## Installation
8
8
 
9
- ### CLI
9
+ $ gem install fafx
10
10
 
11
- `$ fafx`
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
- ### Example of client usage
23
+ ## Example of client usage
22
24
 
23
25
  ```ruby
24
26
  require 'Date'
25
27
  require 'fafx'
26
28
 
27
- puts Fafx::ExchangeRate.at(Date.today, 'GBP', 'USD')
28
- puts Fafx::ExchangeRate.currencies_available
29
- puts Fafx::ExchangeRate.dates_available
30
- puts Fafx::ExchangeRate.most_recent
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
- This code outputs:
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
- USD
39
- JPY
40
- BGN
41
- CZK
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
- 2018-09-07
45
- 2018-09-06
46
- 2018-09-05
47
- 2018-09-04
48
- ...
50
+ $ rake update_data
49
51
 
50
- {"USD"=>1.1615, "JPY"=>128.74, "BGN"=>1.9558, "CZK"=>25.697 ... }
52
+ ```ruby
53
+ require 'fafx'
54
+
55
+ Fafx::ExchangeRate.fetch_data_and_save_to_disk
51
56
  ```
52
57
 
53
- ### Updating the exchange rates data
58
+ ---
54
59
 
55
- You can update the exchange rates values via the CLI using:
60
+ One can also schedule a **cron job** (the following example fetches the data every minute):
56
61
 
57
- `$ fafx --update`
62
+ ```
63
+ * * * * * . ~/.zshrc; fafx -u
64
+ ```
58
65
 
59
- One can also use the `$ rake update_data` task as well.
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
@@ -7,5 +7,6 @@ RSpec::Core::RakeTask.new(:spec)
7
7
  task default: :spec
8
8
 
9
9
  task :update_data do
10
- Fafx::DataFetcher.save_to_disk
10
+ Fafx::ExchangeRate.fetch_data_and_save_to_disk
11
+ puts 'Exchange rates data updated!'
11
12
  end
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
- puts "invalid option: #{ARGV[0]}" unless ARGV[0].include?('--') || ARGV[0].include?('-')
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') { |o| options[:recent] = o }
11
- opt.on('--currencies', 'Lists available currencies') { |o| options[:currencies] = o }
12
- opt.on('--dates', 'Lists available dates') { |o| options[:dates] = o }
13
- opt.on('--update', 'Fetches new data from the web') { |o| options[:update] = o }
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::DataFetcher.save_to_disk
39
+ Fafx::ExchangeRate.fetch_data_and_save_to_disk
40
+ puts 'Exchange rates data updated!'
30
41
  end
31
42
  end
32
- rescue Exception => e
43
+ rescue StandardError => e
33
44
  puts e.to_s unless e.message == 'exit'
34
45
  end
@@ -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 = "https://github.com/frankkair/fafx"
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
 
@@ -1,31 +1,28 @@
1
1
  require 'open-uri'
2
2
  require 'nokogiri'
3
3
 
4
- module Fafx
5
- module DataFetcher
6
- def save_to_disk
7
- url = 'https://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist-90d.xml'
8
- doc = Nokogiri::XML(open(url))
9
- rates = process_currencies_xml(doc)
10
- dir = "#{File.join(File.dirname(__FILE__))}/rates.yaml"
11
- File.open(dir, 'w') { |f| f << rates.to_yaml }
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
- private
13
+ private
15
14
 
16
- def process_currencies_xml(doc)
17
- rates = {}
18
- doc.css('Cube>Cube[time]').each do |day|
19
- time = day[:time]
20
- rates[time] = {}
21
- day.css('Cube').each do |currency|
22
- # TODO: Think about float value - type safety
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
@@ -1,29 +1,25 @@
1
1
  require 'yaml'
2
2
 
3
- # TODO: Create a currency class?
4
- module Fafx
5
- class ER
6
- attr_reader :rates, :dates, :currencies
7
- def initialize
8
- data = load_data
9
- @rates = data
10
- @dates = data.keys
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
- def rates_at(date, curr)
15
- raise KeyError, 'Date not available' unless @dates.include?(date)
16
- raise KeyError, "#{curr} not found" unless @currencies.include?(curr)
17
- @rates[date][curr]
18
- end
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
- private
18
+ private
21
19
 
22
- # -> Hash[String => Float]
23
- def load_data
24
- rates = "#{File.join(File.dirname(__FILE__))}/rates.yaml"
25
- DataFetcher.save_to_disk unless File.exist?(rates)
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
@@ -1,9 +1,9 @@
1
1
  module Fafx
2
2
  module ExchangeRate
3
3
  def at(date, base, other)
4
- er = ER.new
5
- base = er.rates_at(date.to_s, base)
6
- other = er.rates_at(date.to_s, 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
- er = ER.new
20
- k = er.dates.first
21
- er.rates[k]
19
+ ex_rates = ER.new
20
+ first_date = ex_rates.dates.first
21
+ ex_rates.rates[first_date]
22
22
  end
23
- module_function :at, :currencies_available, :dates_available, :most_recent
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
@@ -1,3 +1,3 @@
1
1
  module Fafx
2
- VERSION = '0.1.0'.freeze
2
+ VERSION = '0.1.1'.freeze
3
3
  end
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.0
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 00:00:00.000000000 Z
11
+ date: 2018-09-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler