fixer 0.3.0 → 0.4
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.
- data/.gitignore +1 -1
- data/.rvmrc +1 -1
- data/README.md +72 -4
- data/Rakefile +0 -1
- data/fixer.gemspec +3 -3
- data/lib/fixer.rb +15 -29
- data/lib/fixer/builder.rb +19 -0
- data/lib/fixer/feed.rb +27 -0
- data/lib/fixer/version.rb +1 -1
- data/spec/fixer_spec.rb +17 -16
- data/spec/spec_helper.rb +7 -1
- metadata +9 -11
- data/Gemfile.lock +0 -27
data/.gitignore
CHANGED
data/.rvmrc
CHANGED
@@ -1 +1 @@
|
|
1
|
-
rvm use 1.9.2
|
1
|
+
rvm --create use 1.9.2@fixer
|
data/README.md
CHANGED
@@ -1,11 +1,79 @@
|
|
1
1
|
Fixer
|
2
2
|
====
|
3
3
|
|
4
|
-
Fixer wraps the current and historical
|
4
|
+
Fixer wraps the current and historical
|
5
|
+
[foreign exchange rate feeds](http://www.ecb.europa.eu/stats/exchange/eurofxref/html/index.en.html)
|
6
|
+
of the European Central Bank.
|
5
7
|
|
6
8
|
Usage
|
7
9
|
-----
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
-
|
11
|
+
```ruby
|
12
|
+
Fixer.daily
|
13
|
+
Fixer.ninety_days
|
14
|
+
Fixer.historical
|
15
|
+
```
|
16
|
+
|
17
|
+
A sample implementation:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
# Migration
|
21
|
+
class CreateForeignExchanges < ActiveRecord::Migration
|
22
|
+
def self.up
|
23
|
+
create_table :foreign_exchanges do |t|
|
24
|
+
t.string :iso_code
|
25
|
+
t.float :rate
|
26
|
+
|
27
|
+
t.timestamps
|
28
|
+
end
|
29
|
+
|
30
|
+
add_index :foreign_exchanges, :iso_code
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.down
|
34
|
+
drop_table :foreign_exchanges
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Model
|
39
|
+
class ForeignExchange < ActiveRecord::Base
|
40
|
+
class << self
|
41
|
+
# Returns an exchange rate quote.
|
42
|
+
#
|
43
|
+
# Accepts a counter currency code and an optional base currency code.
|
44
|
+
# Latter defaults to EUR if none is specified.
|
45
|
+
def quote(counter, base='EUR')
|
46
|
+
find_rate_by_currency(counter) / find_rate_by_currency(base)
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def find_rate_by_currency(iso_code)
|
52
|
+
where(:iso_code => iso_code).first.rate
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Bank
|
58
|
+
class ECB < Money::Bank::Base
|
59
|
+
class << self
|
60
|
+
def refresh
|
61
|
+
hashes = Fixer.daily.first[:rates]
|
62
|
+
hashes.push({ :currency => "EUR", :rate => 1.0 })
|
63
|
+
hashes.each do |hash|
|
64
|
+
fx = ForeignExchange.find_or_initialize_by_iso_code(hash[:currency])
|
65
|
+
fx.rate = hash[:rate]
|
66
|
+
fx.save
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def exchange_with(from, to_currency)
|
72
|
+
rate = ForeignExchange.quote(to_currency.iso_code, from.currency.iso_code)
|
73
|
+
Money.new((from.cents * rate).floor, to_currency)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Initializer
|
78
|
+
Money.default_bank = ECB.new
|
79
|
+
```
|
data/Rakefile
CHANGED
data/fixer.gemspec
CHANGED
@@ -6,7 +6,7 @@ Gem::Specification.new do |s|
|
|
6
6
|
s.name = "fixer"
|
7
7
|
s.version = Fixer::VERSION
|
8
8
|
s.platform = Gem::Platform::RUBY
|
9
|
-
s.authors = ["
|
9
|
+
s.authors = ["Paper Cavalier"]
|
10
10
|
s.email = ["code@papercavalier.com"]
|
11
11
|
s.homepage = "http://fixer.heroku.com"
|
12
12
|
s.summary = "A Ruby wrapper to the European Central Bank exchange rate feeds"
|
@@ -14,8 +14,8 @@ Gem::Specification.new do |s|
|
|
14
14
|
|
15
15
|
s.rubyforge_project = "fixer"
|
16
16
|
|
17
|
-
s.add_dependency("nokogiri", ["~> 1.4
|
18
|
-
s.add_development_dependency("rspec", ["~> 2.
|
17
|
+
s.add_dependency("nokogiri", ["~> 1.4"])
|
18
|
+
s.add_development_dependency("rspec", ["~> 2.6"])
|
19
19
|
|
20
20
|
s.files = `git ls-files`.split("\n")
|
21
21
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
data/lib/fixer.rb
CHANGED
@@ -1,37 +1,23 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
1
|
+
require 'fixer/feed'
|
2
|
+
require 'fixer/builder'
|
3
3
|
|
4
4
|
module Fixer
|
5
|
-
|
6
|
-
def daily
|
7
|
-
get('daily')
|
8
|
-
end
|
5
|
+
extend self
|
9
6
|
|
10
|
-
|
11
|
-
|
12
|
-
|
7
|
+
def daily
|
8
|
+
Feed.new('daily').get
|
9
|
+
end
|
13
10
|
|
14
|
-
|
15
|
-
|
16
|
-
|
11
|
+
def historical
|
12
|
+
Feed.new('hist').get
|
13
|
+
end
|
17
14
|
|
18
|
-
|
15
|
+
def historical_90
|
16
|
+
Kernel.warn("[DEPRECATION] `historical_90` is deprecated. Please use `ninety_days` instead.")
|
17
|
+
ninety_days
|
18
|
+
end
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
feed = open(path).read
|
23
|
-
doc = Nokogiri::XML(feed)
|
24
|
-
doc.xpath('/gesmes:Envelope/xmlns:Cube/xmlns:Cube', doc.root.namespaces).map do |snapshot|
|
25
|
-
{
|
26
|
-
:date => snapshot['time'],
|
27
|
-
:rates => snapshot.xpath('./xmlns:Cube').map do |fx|
|
28
|
-
{
|
29
|
-
:currency => fx['currency'],
|
30
|
-
:rate => fx['rate']
|
31
|
-
}
|
32
|
-
end
|
33
|
-
}
|
34
|
-
end
|
35
|
-
end
|
20
|
+
def ninety_days
|
21
|
+
Feed.new('hist-90d').get
|
36
22
|
end
|
37
23
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Fixer
|
2
|
+
class Builder
|
3
|
+
def initialize(node)
|
4
|
+
@node = node
|
5
|
+
end
|
6
|
+
|
7
|
+
def build
|
8
|
+
{
|
9
|
+
:date => @node['time'],
|
10
|
+
:rates => @node.xpath('./xmlns:Cube').map do |fx|
|
11
|
+
{
|
12
|
+
:currency => fx['currency'],
|
13
|
+
:rate => fx['rate']
|
14
|
+
}
|
15
|
+
end
|
16
|
+
}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/fixer/feed.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'open-uri'
|
3
|
+
|
4
|
+
module Fixer
|
5
|
+
class Feed
|
6
|
+
def initialize(type)
|
7
|
+
@type = type
|
8
|
+
end
|
9
|
+
|
10
|
+
def get
|
11
|
+
doc = Nokogiri::XML(feed)
|
12
|
+
doc.xpath('/gesmes:Envelope/xmlns:Cube/xmlns:Cube', doc.root.namespaces).map do |node|
|
13
|
+
Builder.new(node).build
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def feed
|
20
|
+
open(path).read
|
21
|
+
end
|
22
|
+
|
23
|
+
def path
|
24
|
+
"http://www.ecb.europa.eu/stats/eurofxref/eurofxref-#{@type}.xml"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/fixer/version.rb
CHANGED
data/spec/fixer_spec.rb
CHANGED
@@ -1,33 +1,34 @@
|
|
1
|
-
require
|
1
|
+
require "spec_helper"
|
2
2
|
|
3
3
|
describe Fixer do
|
4
|
-
|
5
|
-
|
4
|
+
describe ".daily" do
|
5
|
+
it "downloads daily rates" do
|
6
|
+
rates = Fixer.daily
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
rates.size.should eql 1
|
9
|
+
rates.first.should be_a_snapshot
|
10
|
+
end
|
10
11
|
end
|
11
12
|
|
12
|
-
|
13
|
-
rates
|
13
|
+
describe ".ninety_days" do
|
14
|
+
it "downloads rates for the past 90 days" do
|
15
|
+
rates = Fixer.ninety_days
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
# We should have more than 50 working days in a three-month period
|
18
|
+
rates.size.should > 50
|
19
|
+
rates.each do |rate|
|
20
|
+
rate.should be_a_snapshot
|
21
|
+
end
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
23
|
-
it "downloads
|
25
|
+
it "downloads all rates since January 1st, 1999" do
|
24
26
|
rates = Fixer.historical
|
25
27
|
|
26
28
|
# We should have a lot of working days in history
|
27
29
|
rates.size.should > 1000
|
28
30
|
rates.each do |rate|
|
29
|
-
rate.should
|
30
|
-
rate.should have_key :rates
|
31
|
+
rate.should be_a_snapshot
|
31
32
|
end
|
32
33
|
end
|
33
34
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,4 +1,10 @@
|
|
1
|
-
require "bundler"
|
1
|
+
require "bundler/setup"
|
2
2
|
require "rspec"
|
3
3
|
|
4
4
|
require File.expand_path("../../lib/fixer", __FILE__)
|
5
|
+
|
6
|
+
RSpec::Matchers.define :be_a_snapshot do
|
7
|
+
match do |actual|
|
8
|
+
actual.keys.include?(:date) && actual.keys.include?(:rates)
|
9
|
+
end
|
10
|
+
end
|
metadata
CHANGED
@@ -4,17 +4,16 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
|
9
|
-
version: 0.3.0
|
7
|
+
- 4
|
8
|
+
version: "0.4"
|
10
9
|
platform: ruby
|
11
10
|
authors:
|
12
|
-
-
|
11
|
+
- Paper Cavalier
|
13
12
|
autorequire:
|
14
13
|
bindir: bin
|
15
14
|
cert_chain: []
|
16
15
|
|
17
|
-
date:
|
16
|
+
date: 2011-07-08 00:00:00 +01:00
|
18
17
|
default_executable:
|
19
18
|
dependencies:
|
20
19
|
- !ruby/object:Gem::Dependency
|
@@ -28,8 +27,7 @@ dependencies:
|
|
28
27
|
segments:
|
29
28
|
- 1
|
30
29
|
- 4
|
31
|
-
|
32
|
-
version: 1.4.0
|
30
|
+
version: "1.4"
|
33
31
|
type: :runtime
|
34
32
|
version_requirements: *id001
|
35
33
|
- !ruby/object:Gem::Dependency
|
@@ -42,9 +40,8 @@ dependencies:
|
|
42
40
|
- !ruby/object:Gem::Version
|
43
41
|
segments:
|
44
42
|
- 2
|
45
|
-
-
|
46
|
-
|
47
|
-
version: 2.1.0
|
43
|
+
- 6
|
44
|
+
version: "2.6"
|
48
45
|
type: :development
|
49
46
|
version_requirements: *id002
|
50
47
|
description: Fixer is a Ruby wrapper to the current and historical foreign exchange or FX rate feeds of the European Central Bank.
|
@@ -61,12 +58,13 @@ files:
|
|
61
58
|
- .rspec
|
62
59
|
- .rvmrc
|
63
60
|
- Gemfile
|
64
|
-
- Gemfile.lock
|
65
61
|
- LICENSE
|
66
62
|
- README.md
|
67
63
|
- Rakefile
|
68
64
|
- fixer.gemspec
|
69
65
|
- lib/fixer.rb
|
66
|
+
- lib/fixer/builder.rb
|
67
|
+
- lib/fixer/feed.rb
|
70
68
|
- lib/fixer/version.rb
|
71
69
|
- spec/fixer_spec.rb
|
72
70
|
- spec/spec_helper.rb
|
data/Gemfile.lock
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
fixer (0.3.0)
|
5
|
-
nokogiri (~> 1.4.0)
|
6
|
-
|
7
|
-
GEM
|
8
|
-
remote: http://rubygems.org/
|
9
|
-
specs:
|
10
|
-
diff-lcs (1.1.2)
|
11
|
-
nokogiri (1.4.3.1)
|
12
|
-
rspec (2.1.0)
|
13
|
-
rspec-core (~> 2.1.0)
|
14
|
-
rspec-expectations (~> 2.1.0)
|
15
|
-
rspec-mocks (~> 2.1.0)
|
16
|
-
rspec-core (2.1.0)
|
17
|
-
rspec-expectations (2.1.0)
|
18
|
-
diff-lcs (~> 1.1.2)
|
19
|
-
rspec-mocks (2.1.0)
|
20
|
-
|
21
|
-
PLATFORMS
|
22
|
-
ruby
|
23
|
-
|
24
|
-
DEPENDENCIES
|
25
|
-
fixer!
|
26
|
-
nokogiri (~> 1.4.0)
|
27
|
-
rspec (~> 2.1.0)
|