fixer 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ .DS_Store
2
+ .bundle
3
+ pkg
4
+ *.gem
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ -cfd
data/.rvmrc ADDED
@@ -0,0 +1,2 @@
1
+ rvm use 1.9.2
2
+ rvm wrapper 1.9.2
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "http://rubygems.org"
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,31 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ fixer (0.2.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
+ rake (0.8.7)
13
+ rspec (2.0.0.rc)
14
+ rspec-core (= 2.0.0.rc)
15
+ rspec-expectations (= 2.0.0.rc)
16
+ rspec-mocks (= 2.0.0.rc)
17
+ rspec-core (2.0.0.rc)
18
+ rspec-expectations (2.0.0.rc)
19
+ diff-lcs (>= 1.1.2)
20
+ rspec-mocks (2.0.0.rc)
21
+ rspec-core (= 2.0.0.rc)
22
+ rspec-expectations (= 2.0.0.rc)
23
+
24
+ PLATFORMS
25
+ ruby
26
+
27
+ DEPENDENCIES
28
+ fixer!
29
+ nokogiri (~> 1.4.0)
30
+ rake
31
+ rspec (= 2.0.0.rc)
data/README.markdown CHANGED
@@ -3,18 +3,28 @@ Fixer
3
3
 
4
4
  Fixer is a Ruby wrapper to the [current and historical foreign exchange rate feeds provided by the European Central Bank](http://www.ecb.europa.eu/stats/exchange/eurofxref/html/index.en.html).
5
5
 
6
- Implement your own caching.
6
+ I am also throwing in a *minimal* cache. Use if it suits you or implement your own.
7
+
8
+ Bonus: Use the Money gem.
7
9
 
8
10
  Usage
9
11
  -----
10
12
 
11
- # Get daily rate
12
- Fixer.get('daily')
13
+ # Download the daily rates.
14
+ Fixer.daily
15
+
16
+ # Download the 90-day historical rates.
17
+ Fixer.historical_90
13
18
 
14
- # Get 90-day historical
15
- Fixer.get('hist-90d')
19
+ # Download all historical rates.
20
+ Fixer.historical
16
21
 
17
- # Get historical
18
- Fixer.get('hist')
22
+ # Use the built-in cache.
23
+ cache = Fixer::Cache
24
+ cache.to_usd
25
+ => 1.397
26
+ cache.base = "EUR"
27
+ cache.to_eur
28
+ => 0.7158
19
29
 
20
- # It doesn't get simpler than this.
30
+ # It doesn't get any simpler than this.
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+ require "bundler"
3
+ require "rspec/core/rake_task"
4
+
5
+ Bundler::GemHelper.install_tasks
6
+
7
+ desc "Run all specs in spec directory"
8
+ RSpec::Core::RakeTask.new(:spec) do |spec|
9
+ spec.pattern = "spec/**/*_spec.rb"
10
+ end
11
+
12
+ task :default => :spec
data/fixer.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "fixer/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "fixer"
7
+ s.version = Fixer::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Hakan Ensari"]
10
+ s.email = ["code@papercavalier.com"]
11
+ s.homepage = "http://fixer.heroku.com"
12
+ s.summary = "A Ruby wrapper to the European Central Bank exchange rate feeds"
13
+ s.description = "Fixer is a Ruby wrapper to the current and historical foreign exchange or FX rate feeds provided by the European Central Bank."
14
+
15
+ s.rubyforge_project = "fixer"
16
+
17
+ s.add_dependency("nokogiri", ["~> 1.4.0"])
18
+
19
+ s.add_development_dependency("rake")
20
+ s.add_development_dependency("rspec", ["= 2.0.0.rc"])
21
+
22
+ s.files = `git ls-files`.split("\n")
23
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
25
+ s.require_paths = ["lib"]
26
+ end
@@ -0,0 +1,52 @@
1
+ # encoding: utf-8
2
+ module Fixer
3
+ class Cache
4
+ class << self
5
+ def base
6
+ @base || "EUR"
7
+ end
8
+
9
+ def base=(name)
10
+ @base = name
11
+ end
12
+
13
+ def expire
14
+ @rates = nil
15
+ end
16
+
17
+ def method_missing(sym, *args, &block)
18
+ if sym.to_s =~ /^to_(.*)$/
19
+ counter = $1.upcase
20
+ var_name = "@#{base}_#{counter}".to_sym
21
+ rate = instance_variable_get(var_name)
22
+ return rate unless rate.nil?
23
+
24
+ rate = quote(counter) / quote(base)
25
+ rate = (rate * 10000).round.to_f / 10000
26
+ instance_variable_set(var_name, rate)
27
+ rate
28
+ else
29
+ super
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def rates
36
+ begin
37
+ @rates ||= Fixer.daily.first[:rates].push({ :currency => "EUR", :rate => "1.0" })
38
+ rescue
39
+ raise Error, "Cache not valid"
40
+ end
41
+ end
42
+
43
+ def quote(counter)
44
+ rate = rates.detect { |rate| rate[:currency] == counter }
45
+ raise(Error, "Currency not valid") if rate.nil?
46
+ rate[:rate].to_f
47
+ end
48
+ end
49
+ end
50
+
51
+ class Error < StandardError; end
52
+ end
data/lib/fixer/version.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  module Fixer
2
- VERSION = '0.1.1'
3
+ VERSION = "0.2.0"
3
4
  end
data/lib/fixer.rb CHANGED
@@ -1,10 +1,9 @@
1
1
  # encoding: utf-8
2
2
  require 'open-uri'
3
3
  require 'nokogiri'
4
+ require File.dirname(__FILE__) + '/fixer/cache'
4
5
 
5
6
  module Fixer
6
- BASE_URL = 'http://www.ecb.europa.eu/stats/eurofxref/'
7
-
8
7
  class << self
9
8
  def daily
10
9
  get('daily')
@@ -17,20 +16,20 @@ module Fixer
17
16
  def historical_90
18
17
  get('hist-90d')
19
18
  end
20
-
19
+
21
20
  private
22
21
 
23
22
  def get(type)
24
- url = BASE_URL + "eurofxref-#{type}.xml"
25
- feed = open(url).read
26
- doc = Nokogiri::XML(feed)
23
+ path = "http://www.ecb.europa.eu/stats/eurofxref/eurofxref-#{type}.xml"
24
+ feed = open(path).read
25
+ doc = Nokogiri::XML(feed)
27
26
  doc.xpath('/gesmes:Envelope/xmlns:Cube/xmlns:Cube', doc.root.namespaces).map do |snapshot|
28
27
  {
29
28
  :date => snapshot['time'],
30
29
  :rates => snapshot.xpath('./xmlns:Cube').map do |fx|
31
30
  {
32
- :currency => fx['currency'],
33
- :rate => fx['rate']
31
+ :currency => fx['currency'],
32
+ :rate => fx['rate']
34
33
  }
35
34
  end
36
35
  }
@@ -0,0 +1,80 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ module Fixer
5
+ describe Cache do
6
+ let(:mock_rates) do
7
+ [
8
+ { :currency=>"USD", :rate=>"1.3856" },
9
+ { :currency=>"JPY", :rate=>"114.98" },
10
+ { :currency=>"GBP", :rate=>"0.87260" },
11
+ { :currency=>"CAD", :rate=>"1.4018" },
12
+ { :currency=>"EUR", :rate=>"1.0" }
13
+ ]
14
+ end
15
+
16
+ let(:cache) do
17
+ cache = Fixer::Cache
18
+ cache.base = "EUR"
19
+ cache.expire
20
+ cache
21
+ end
22
+
23
+ it "sets base currency" do
24
+ cache.base = "USD"
25
+ cache.base.should eql "USD"
26
+ end
27
+
28
+ it "quotes" do
29
+ cache.instance_variable_set(:@rates, mock_rates)
30
+ cache.send(:quote, "USD").should eql 1.3856
31
+ end
32
+
33
+ it "caches" do
34
+ cache.instance_variable_set(:@rates, "foo")
35
+ cache.send(:rates).should eql "foo"
36
+ end
37
+
38
+ it "seeds cache" do
39
+ cache.send(:rates).detect { |rate| rate[:currency] == "USD" }[:rate].should_not be_nil
40
+ end
41
+
42
+ it "expires cache" do
43
+ cache.instance_variable_set(:@rates, "foo")
44
+ cache.expire
45
+ cache.instance_variable_get(:@rates).should be_nil
46
+ end
47
+
48
+ it "raises an error if cache not valid" do
49
+ Fixer.stub!(:daily).and_return("foo")
50
+ lambda { cache.send(:rates) }.should raise_error Fixer::Error, "Cache not valid"
51
+ end
52
+
53
+ it "returns an exchange rate" do
54
+ cache.instance_variable_set(:@rates, mock_rates)
55
+ cache.to_eur.should eql 1.0
56
+ cache.to_usd.should eql 1.3856
57
+
58
+ cache.base = "GBP"
59
+ cache.to_gbp.should eql 1.0
60
+ cache.to_usd.should eql 1.5879
61
+ end
62
+
63
+ it "caches requested exchange rates" do
64
+ cache.instance_variable_set(:@rates, mock_rates)
65
+ cache.to_usd
66
+ cache.instance_variable_get(:@EUR_USD).should eql 1.3856
67
+ end
68
+
69
+ it "raises an error if counter currency not valid" do
70
+ cache.instance_variable_set(:@rates, mock_rates)
71
+ lambda { cache.to_foo }.should raise_error Fixer::Error, "Currency not valid"
72
+ end
73
+
74
+ it "raises an error if base currency not valid" do
75
+ cache.instance_variable_set(:@rates, mock_rates)
76
+ cache.base = "FOO"
77
+ lambda { cache.to_usd }.should raise_error Fixer::Error, "Currency not valid"
78
+ end
79
+ end
80
+ end
data/spec/fixer_spec.rb CHANGED
@@ -1,32 +1,31 @@
1
+ # encoding: utf-8
1
2
  require 'spec_helper'
2
3
 
3
4
  describe Fixer do
4
- context ".download" do
5
- it "downloads daily rates" do
6
- rates = Fixer.daily
7
- rates.size.should eql 1
8
- rates.first.should have_key :date
9
- rates.first.should have_key :rates
10
- end
5
+ it "downloads daily rates" do
6
+ rates = Fixer.daily
7
+ rates.size.should eql 1
8
+ rates.first.should have_key :date
9
+ rates.first.should have_key :rates
10
+ end
11
11
 
12
- it "downloads 90-day historical" do
13
- rates = Fixer.historical_90
14
- # We should have more than 50 working days in a three-month period
15
- rates.size.should > 50
16
- rates.each do |rate|
17
- rate.should have_key :date
18
- rate.should have_key :rates
19
- end
12
+ it "downloads 90-day historical" do
13
+ rates = Fixer.historical_90
14
+ # We should have more than 50 working days in a three-month period
15
+ rates.size.should > 50
16
+ rates.each do |rate|
17
+ rate.should have_key :date
18
+ rate.should have_key :rates
20
19
  end
20
+ end
21
21
 
22
- it "downloads historical" do
23
- rates = Fixer.historical
24
- # We should have a lot of working days in history
25
- rates.size.should > 1000
26
- rates.each do |rate|
27
- rate.should have_key :date
28
- rate.should have_key :rates
29
- end
22
+ it "downloads historical" do
23
+ rates = Fixer.historical
24
+ # We should have a lot of working days in history
25
+ rates.size.should > 1000
26
+ rates.each do |rate|
27
+ rate.should have_key :date
28
+ rate.should have_key :rates
30
29
  end
31
30
  end
32
31
  end
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  require "rubygems"
2
3
  require "bundler/setup"
3
4
  require "rspec"
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 1
8
- - 1
9
- version: 0.1.1
7
+ - 2
8
+ - 0
9
+ version: 0.2.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Hakan Ensari
@@ -14,11 +14,12 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-10-06 00:00:00 +01:00
17
+ date: 2010-10-07 00:00:00 +01:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: nokogiri
22
+ prerelease: false
22
23
  requirement: &id001 !ruby/object:Gem::Requirement
23
24
  none: false
24
25
  requirements:
@@ -30,10 +31,10 @@ dependencies:
30
31
  - 0
31
32
  version: 1.4.0
32
33
  type: :runtime
33
- prerelease: false
34
34
  version_requirements: *id001
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: rake
37
+ prerelease: false
37
38
  requirement: &id002 !ruby/object:Gem::Requirement
38
39
  none: false
39
40
  requirements:
@@ -43,10 +44,10 @@ dependencies:
43
44
  - 0
44
45
  version: "0"
45
46
  type: :development
46
- prerelease: false
47
47
  version_requirements: *id002
48
48
  - !ruby/object:Gem::Dependency
49
49
  name: rspec
50
+ prerelease: false
50
51
  requirement: &id003 !ruby/object:Gem::Requirement
51
52
  none: false
52
53
  requirements:
@@ -59,7 +60,6 @@ dependencies:
59
60
  - rc
60
61
  version: 2.0.0.rc
61
62
  type: :development
62
- prerelease: false
63
63
  version_requirements: *id003
64
64
  description: Fixer is a Ruby wrapper to the current and historical foreign exchange or FX rate feeds provided by the European Central Bank.
65
65
  email:
@@ -71,10 +71,19 @@ extensions: []
71
71
  extra_rdoc_files: []
72
72
 
73
73
  files:
74
- - lib/fixer/version.rb
75
- - lib/fixer.rb
74
+ - .gitignore
75
+ - .rspec
76
+ - .rvmrc
77
+ - Gemfile
78
+ - Gemfile.lock
76
79
  - LICENSE
77
80
  - README.markdown
81
+ - Rakefile
82
+ - fixer.gemspec
83
+ - lib/fixer.rb
84
+ - lib/fixer/cache.rb
85
+ - lib/fixer/version.rb
86
+ - spec/fixer/cache_spec.rb
78
87
  - spec/fixer_spec.rb
79
88
  - spec/spec_helper.rb
80
89
  has_rdoc: true
@@ -82,8 +91,8 @@ homepage: http://fixer.heroku.com
82
91
  licenses: []
83
92
 
84
93
  post_install_message:
85
- rdoc_options:
86
- - --charset=UTF-8
94
+ rdoc_options: []
95
+
87
96
  require_paths:
88
97
  - lib
89
98
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -91,7 +100,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
91
100
  requirements:
92
101
  - - ">="
93
102
  - !ruby/object:Gem::Version
94
- hash: -4559416944163579922
95
103
  segments:
96
104
  - 0
97
105
  version: "0"
@@ -101,17 +109,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement
101
109
  - - ">="
102
110
  - !ruby/object:Gem::Version
103
111
  segments:
104
- - 1
105
- - 3
106
- - 7
107
- version: 1.3.7
112
+ - 0
113
+ version: "0"
108
114
  requirements: []
109
115
 
110
- rubyforge_project:
116
+ rubyforge_project: fixer
111
117
  rubygems_version: 1.3.7
112
118
  signing_key:
113
119
  specification_version: 3
114
120
  summary: A Ruby wrapper to the European Central Bank exchange rate feeds
115
121
  test_files:
122
+ - spec/fixer/cache_spec.rb
116
123
  - spec/fixer_spec.rb
117
124
  - spec/spec_helper.rb