google_currency 2.0.0 → 2.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +7 -0
- data/CHANGELOG.md +97 -79
- data/LICENSE +20 -20
- data/README.md +38 -38
- data/Rakefile +49 -49
- data/google_currency.gemspec +26 -26
- data/lib/money/bank/google_currency.rb +169 -120
- data/spec/google_currency_with_json_spec.rb +61 -53
- data/spec/google_currency_with_yajl_spec.rb +60 -53
- data/spec/spec_helper.rb +2 -2
- metadata +20 -18
data/AUTHORS
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,79 +1,97 @@
|
|
1
|
-
Google Currency 2.0.
|
2
|
-
=====================
|
3
|
-
|
4
|
-
|
5
|
-
--------
|
6
|
-
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
1
|
+
Google Currency 2.0.2
|
2
|
+
=====================
|
3
|
+
|
4
|
+
Bugfixes
|
5
|
+
--------
|
6
|
+
- Fix encoding issue
|
7
|
+
|
8
|
+
Google Currency 2.0.1
|
9
|
+
=====================
|
10
|
+
|
11
|
+
Features
|
12
|
+
--------
|
13
|
+
- Handles funky exchange rates (Arnaud Joubay)
|
14
|
+
|
15
|
+
Bugfixes
|
16
|
+
--------
|
17
|
+
- Fix for running under 1.9.2 in TextMate (larspind)
|
18
|
+
|
19
|
+
Google Currency 2.0.0
|
20
|
+
=====================
|
21
|
+
|
22
|
+
Features
|
23
|
+
--------
|
24
|
+
- Added multi_json to allow users to select their own JSON parsing engine.
|
25
|
+
- Removed deprecated method #get_google_rate.
|
26
|
+
|
27
|
+
Bugfixes
|
28
|
+
--------
|
29
|
+
- Updated deprecated rake tasks
|
30
|
+
|
31
|
+
Google Currency 1.1.1
|
32
|
+
=====================
|
33
|
+
|
34
|
+
Bugfixes
|
35
|
+
--------
|
36
|
+
- Built gem using Ruby 1.8.7 to bypass a known error with RubyGems 1.5.0 and
|
37
|
+
Ruby 1.9.2
|
38
|
+
|
39
|
+
Google Currency 1.1.0
|
40
|
+
=====================
|
41
|
+
|
42
|
+
Features
|
43
|
+
--------
|
44
|
+
- Deprecated #get_google_rate, use #get_rate (thanks RMU Alumni)
|
45
|
+
|
46
|
+
Bugfixes
|
47
|
+
---------
|
48
|
+
- Fixed an issue when rates over 1000 did not parse correctly (thanks Brandon
|
49
|
+
Anderson)
|
50
|
+
|
51
|
+
Google Currency 1.0.3
|
52
|
+
=====================
|
53
|
+
|
54
|
+
Features
|
55
|
+
--------
|
56
|
+
- Update `money` requirement to `~> 3.5`
|
57
|
+
|
58
|
+
Google Currency 1.0.2
|
59
|
+
=====================
|
60
|
+
|
61
|
+
Features
|
62
|
+
--------
|
63
|
+
- Replace `eval` with `JSON.parse`
|
64
|
+
- Use BigDecimal instead of Float
|
65
|
+
|
66
|
+
Bugfixes
|
67
|
+
--------
|
68
|
+
- Quell parenthetical warnings in specs
|
69
|
+
|
70
|
+
Google Currency 1.0.1
|
71
|
+
=====================
|
72
|
+
|
73
|
+
Features
|
74
|
+
--------
|
75
|
+
- Update `money` requirement to `~> 3.1.5`
|
76
|
+
|
77
|
+
Google Currency 1.0.0
|
78
|
+
=====================
|
79
|
+
|
80
|
+
Features
|
81
|
+
--------
|
82
|
+
- Updated `money` requirement to `~> 3.1.0`
|
83
|
+
|
84
|
+
Google Currency 0.1.1
|
85
|
+
=====================
|
86
|
+
|
87
|
+
Features
|
88
|
+
--------
|
89
|
+
- Added #flush_rates
|
90
|
+
- Added #flush_rate
|
91
|
+
|
92
|
+
Google Currency 0.1.0
|
93
|
+
=====================
|
94
|
+
|
95
|
+
Features
|
96
|
+
--------
|
97
|
+
- Initial release
|
data/LICENSE
CHANGED
@@ -1,20 +1,20 @@
|
|
1
|
-
Copyright (c) 2010 Shane Emmons
|
2
|
-
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
-
a copy of this software and associated documentation files (the
|
5
|
-
"Software"), to deal in the Software without restriction, including
|
6
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
-
permit persons to whom the Software is furnished to do so, subject to
|
9
|
-
the following conditions:
|
10
|
-
|
11
|
-
The above copyright notice and this permission notice shall be
|
12
|
-
included in all copies or substantial portions of the Software.
|
13
|
-
|
14
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
1
|
+
Copyright (c) 2010 Shane Emmons
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -1,38 +1,38 @@
|
|
1
|
-
Google Currency
|
2
|
-
===============
|
3
|
-
|
4
|
-
[![Build Status](https://secure.travis-ci.org/RubyMoney/google_currency.png)](http://travis-ci.org/RubyMoney/google_currency)
|
5
|
-
|
6
|
-
This gem extends Money::Bank::VariableExchange with Money::Bank::GoogleCurrency
|
7
|
-
and gives you access to the current Google Currency exchange rates.
|
8
|
-
|
9
|
-
You have to load one of the JSON libraries supported by
|
10
|
-
[MultiJSON](https://github.com/intridea/multi_json) (`json` for example)
|
11
|
-
if it's not already loaded by your application. In a Rails application,
|
12
|
-
ActiveSupport provides a JSON implementation that is automatically recognized.
|
13
|
-
|
14
|
-
Usage
|
15
|
-
-----
|
16
|
-
|
17
|
-
require 'money'
|
18
|
-
require 'money/bank/google_currency'
|
19
|
-
require 'json'
|
20
|
-
MultiJson.engine = :json_gem # or :yajl
|
21
|
-
|
22
|
-
# set default bank to instance of GoogleCurrency
|
23
|
-
Money.default_bank = Money::Bank::GoogleCurrency.new
|
24
|
-
|
25
|
-
# create a new money object, and use the standard #exchange_to method
|
26
|
-
n = 1.to_money(:USD)
|
27
|
-
n.exchange_to(:EUR)
|
28
|
-
|
29
|
-
An `UnknownRate` will be thrown if `#exchange_to` is called with a `Currency`
|
30
|
-
that `Money` knows, but Google does not.
|
31
|
-
|
32
|
-
An `UnknownCurrency` will be thrown if `#exchange_to` is called with a
|
33
|
-
`Currency` that `Money` does not know.
|
34
|
-
|
35
|
-
Copyright
|
36
|
-
---------
|
37
|
-
|
38
|
-
Copyright (c) 2011 Shane Emmons. See {file:LICENSE} for details.
|
1
|
+
Google Currency
|
2
|
+
===============
|
3
|
+
|
4
|
+
[![Build Status](https://secure.travis-ci.org/RubyMoney/google_currency.png)](http://travis-ci.org/RubyMoney/google_currency)
|
5
|
+
|
6
|
+
This gem extends Money::Bank::VariableExchange with Money::Bank::GoogleCurrency
|
7
|
+
and gives you access to the current Google Currency exchange rates.
|
8
|
+
|
9
|
+
You have to load one of the JSON libraries supported by
|
10
|
+
[MultiJSON](https://github.com/intridea/multi_json) (`json` for example)
|
11
|
+
if it's not already loaded by your application. In a Rails application,
|
12
|
+
ActiveSupport provides a JSON implementation that is automatically recognized.
|
13
|
+
|
14
|
+
Usage
|
15
|
+
-----
|
16
|
+
|
17
|
+
require 'money'
|
18
|
+
require 'money/bank/google_currency'
|
19
|
+
require 'json'
|
20
|
+
MultiJson.engine = :json_gem # or :yajl
|
21
|
+
|
22
|
+
# set default bank to instance of GoogleCurrency
|
23
|
+
Money.default_bank = Money::Bank::GoogleCurrency.new
|
24
|
+
|
25
|
+
# create a new money object, and use the standard #exchange_to method
|
26
|
+
n = 1.to_money(:USD)
|
27
|
+
n.exchange_to(:EUR)
|
28
|
+
|
29
|
+
An `UnknownRate` will be thrown if `#exchange_to` is called with a `Currency`
|
30
|
+
that `Money` knows, but Google does not.
|
31
|
+
|
32
|
+
An `UnknownCurrency` will be thrown if `#exchange_to` is called with a
|
33
|
+
`Currency` that `Money` does not know.
|
34
|
+
|
35
|
+
Copyright
|
36
|
+
---------
|
37
|
+
|
38
|
+
Copyright (c) 2011 Shane Emmons. See {file:LICENSE} for details.
|
data/Rakefile
CHANGED
@@ -1,49 +1,49 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'rake/clean'
|
3
|
-
|
4
|
-
CLOBBER.include('.yardoc', 'doc')
|
5
|
-
|
6
|
-
def gemspec
|
7
|
-
@gemspec ||= begin
|
8
|
-
file = File.expand_path("../google_currency.gemspec", __FILE__)
|
9
|
-
eval(File.read(file), binding, file)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
begin
|
14
|
-
require 'rspec/core/rake_task'
|
15
|
-
RSpec::Core::RakeTask.new
|
16
|
-
rescue LoadError
|
17
|
-
task(:spec){abort "`gem install rspec` to run specs"}
|
18
|
-
end
|
19
|
-
task :default => :spec
|
20
|
-
task :test => :spec
|
21
|
-
|
22
|
-
begin
|
23
|
-
require 'yard'
|
24
|
-
YARD::Rake::YardocTask.new do |t|
|
25
|
-
t.options << "--files" << "CHANGELOG.md,LICENSE"
|
26
|
-
end
|
27
|
-
rescue LoadError
|
28
|
-
task(:yard){abort "`gem install yard` to generate documentation"}
|
29
|
-
end
|
30
|
-
|
31
|
-
begin
|
32
|
-
require 'rubygems/package_task'
|
33
|
-
Gem::PackageTask.new(gemspec) do |pkg|
|
34
|
-
pkg.gem_spec = gemspec
|
35
|
-
end
|
36
|
-
task :gem => :gemspec
|
37
|
-
rescue LoadError
|
38
|
-
task(:gem){abort "`gem install rake` to package gems"}
|
39
|
-
end
|
40
|
-
|
41
|
-
desc "Install the gem locally"
|
42
|
-
task :install => :gem do
|
43
|
-
sh "gem install pkg/#{gemspec.full_name}.gem"
|
44
|
-
end
|
45
|
-
|
46
|
-
desc "Validate the gemspec"
|
47
|
-
task :gemspec do
|
48
|
-
gemspec.validate
|
49
|
-
end
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/clean'
|
3
|
+
|
4
|
+
CLOBBER.include('.yardoc', 'doc')
|
5
|
+
|
6
|
+
def gemspec
|
7
|
+
@gemspec ||= begin
|
8
|
+
file = File.expand_path("../google_currency.gemspec", __FILE__)
|
9
|
+
eval(File.read(file), binding, file)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
begin
|
14
|
+
require 'rspec/core/rake_task'
|
15
|
+
RSpec::Core::RakeTask.new
|
16
|
+
rescue LoadError
|
17
|
+
task(:spec){abort "`gem install rspec` to run specs"}
|
18
|
+
end
|
19
|
+
task :default => :spec
|
20
|
+
task :test => :spec
|
21
|
+
|
22
|
+
begin
|
23
|
+
require 'yard'
|
24
|
+
YARD::Rake::YardocTask.new do |t|
|
25
|
+
t.options << "--files" << "CHANGELOG.md,LICENSE"
|
26
|
+
end
|
27
|
+
rescue LoadError
|
28
|
+
task(:yard){abort "`gem install yard` to generate documentation"}
|
29
|
+
end
|
30
|
+
|
31
|
+
begin
|
32
|
+
require 'rubygems/package_task'
|
33
|
+
Gem::PackageTask.new(gemspec) do |pkg|
|
34
|
+
pkg.gem_spec = gemspec
|
35
|
+
end
|
36
|
+
task :gem => :gemspec
|
37
|
+
rescue LoadError
|
38
|
+
task(:gem){abort "`gem install rake` to package gems"}
|
39
|
+
end
|
40
|
+
|
41
|
+
desc "Install the gem locally"
|
42
|
+
task :install => :gem do
|
43
|
+
sh "gem install pkg/#{gemspec.full_name}.gem"
|
44
|
+
end
|
45
|
+
|
46
|
+
desc "Validate the gemspec"
|
47
|
+
task :gemspec do
|
48
|
+
gemspec.validate
|
49
|
+
end
|
data/google_currency.gemspec
CHANGED
@@ -1,26 +1,26 @@
|
|
1
|
-
Gem::Specification.new do |s|
|
2
|
-
s.name = "google_currency"
|
3
|
-
s.version = "2.0.
|
4
|
-
s.platform = Gem::Platform::RUBY
|
5
|
-
s.authors = ["Shane Emmons"
|
6
|
-
s.email = ["semmons99
|
7
|
-
s.homepage = "http://rubymoney.github.com/google_currency"
|
8
|
-
s.summary = "Access the Google Currency exchange rate data."
|
9
|
-
s.description = "GoogleCurrency extends Money::Bank::Base and gives you access to the current Google Currency exchange rates."
|
10
|
-
|
11
|
-
s.required_rubygems_version = ">= 1.3.6"
|
12
|
-
|
13
|
-
s.add_development_dependency "rspec", ">= 2.0.0"
|
14
|
-
s.add_development_dependency "yard", ">= 0.5.8"
|
15
|
-
s.add_development_dependency "json", ">= 1.4.0"
|
16
|
-
s.add_development_dependency "yajl-ruby", ">= 1.0.0"
|
17
|
-
|
18
|
-
s.add_dependency "money", "~> 3.5"
|
19
|
-
s.add_dependency "multi_json", ">= 1.0.0"
|
20
|
-
|
21
|
-
s.files = Dir.glob("{lib,spec}/**/*")
|
22
|
-
s.files += %w(LICENSE README.md CHANGELOG.md)
|
23
|
-
s.files += %w(Rakefile .gemtest google_currency.gemspec)
|
24
|
-
|
25
|
-
s.require_path = "lib"
|
26
|
-
end
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "google_currency"
|
3
|
+
s.version = "2.0.2"
|
4
|
+
s.platform = Gem::Platform::RUBY
|
5
|
+
s.authors = ["Shane Emmons"]
|
6
|
+
s.email = ["semmons99@gmail.com"]
|
7
|
+
s.homepage = "http://rubymoney.github.com/google_currency"
|
8
|
+
s.summary = "Access the Google Currency exchange rate data."
|
9
|
+
s.description = "GoogleCurrency extends Money::Bank::Base and gives you access to the current Google Currency exchange rates."
|
10
|
+
|
11
|
+
s.required_rubygems_version = ">= 1.3.6"
|
12
|
+
|
13
|
+
s.add_development_dependency "rspec", ">= 2.0.0"
|
14
|
+
s.add_development_dependency "yard", ">= 0.5.8"
|
15
|
+
s.add_development_dependency "json", ">= 1.4.0"
|
16
|
+
s.add_development_dependency "yajl-ruby", ">= 1.0.0"
|
17
|
+
|
18
|
+
s.add_dependency "money", "~> 3.5"
|
19
|
+
s.add_dependency "multi_json", ">= 1.0.0"
|
20
|
+
|
21
|
+
s.files = Dir.glob("{lib,spec}/**/*")
|
22
|
+
s.files += %w(LICENSE README.md CHANGELOG.md AUTHORS)
|
23
|
+
s.files += %w(Rakefile .gemtest google_currency.gemspec)
|
24
|
+
|
25
|
+
s.require_path = "lib"
|
26
|
+
end
|
@@ -1,120 +1,169 @@
|
|
1
|
-
require 'money'
|
2
|
-
require 'open-uri'
|
3
|
-
require 'multi_json'
|
4
|
-
|
5
|
-
class Money
|
6
|
-
module Bank
|
7
|
-
class GoogleCurrency < Money::Bank::VariableExchange
|
8
|
-
|
9
|
-
SERVICE_HOST = "www.google.com"
|
10
|
-
SERVICE_PATH = "/ig/calculator"
|
11
|
-
|
12
|
-
# @return [Hash] Stores the currently known rates.
|
13
|
-
attr_reader :rates
|
14
|
-
|
15
|
-
##
|
16
|
-
# Clears all rates stored in @rates
|
17
|
-
#
|
18
|
-
# @return [Hash] The empty @rates Hash.
|
19
|
-
#
|
20
|
-
# @example
|
21
|
-
# @bank = GoogleCurrency.new #=> <Money::Bank::GoogleCurrency...>
|
22
|
-
# @bank.get_rate(:USD, :EUR) #=> 0.776337241
|
23
|
-
# @bank.flush_rates #=> {}
|
24
|
-
def flush_rates
|
25
|
-
@mutex.synchronize{
|
26
|
-
@rates = {}
|
27
|
-
}
|
28
|
-
end
|
29
|
-
|
30
|
-
##
|
31
|
-
# Clears the specified rate stored in @rates.
|
32
|
-
#
|
33
|
-
# @param [String, Symbol, Currency] from Currency to convert from (used
|
34
|
-
# for key into @rates).
|
35
|
-
# @param [String, Symbol, Currency] to Currency to convert to (used for
|
36
|
-
# key into @rates).
|
37
|
-
#
|
38
|
-
# @return [Float] The flushed rate.
|
39
|
-
#
|
40
|
-
# @example
|
41
|
-
# @bank = GoogleCurrency.new #=> <Money::Bank::GoogleCurrency...>
|
42
|
-
# @bank.get_rate(:USD, :EUR) #=> 0.776337241
|
43
|
-
# @bank.flush_rate(:USD, :EUR) #=> 0.776337241
|
44
|
-
def flush_rate(from, to)
|
45
|
-
key = rate_key_for(from, to)
|
46
|
-
@mutex.synchronize{
|
47
|
-
@rates.delete(key)
|
48
|
-
}
|
49
|
-
end
|
50
|
-
|
51
|
-
##
|
52
|
-
# Returns the requested rate.
|
53
|
-
#
|
54
|
-
# @param [String, Symbol, Currency] from Currency to convert from
|
55
|
-
# @param [String, Symbol, Currency] to Currency to convert to
|
56
|
-
#
|
57
|
-
# @return [Float] The requested rate.
|
58
|
-
#
|
59
|
-
# @example
|
60
|
-
# @bank = GoogleCurrency.new #=> <Money::Bank::GoogleCurrency...>
|
61
|
-
# @bank.get_rate(:USD, :EUR) #=> 0.776337241
|
62
|
-
def get_rate(from, to)
|
63
|
-
@mutex.synchronize{
|
64
|
-
@rates[rate_key_for(from, to)] ||= fetch_rate(from, to)
|
65
|
-
}
|
66
|
-
end
|
67
|
-
|
68
|
-
private
|
69
|
-
|
70
|
-
##
|
71
|
-
# Queries for the requested rate and returns it.
|
72
|
-
#
|
73
|
-
# @param [String, Symbol, Currency] from Currency to convert from
|
74
|
-
# @param [String, Symbol, Currency] to Currency to convert to
|
75
|
-
#
|
76
|
-
# @return [
|
77
|
-
def fetch_rate(from, to)
|
78
|
-
from, to = Currency.wrap(from), Currency.wrap(to)
|
79
|
-
|
80
|
-
data = build_uri(from, to).read
|
81
|
-
data = fix_response_json_data(data)
|
82
|
-
|
83
|
-
error = data['error']
|
84
|
-
raise UnknownRate unless error == '' || error == '0'
|
85
|
-
|
86
|
-
end
|
87
|
-
|
88
|
-
##
|
89
|
-
# Build a URI for the given arguments.
|
90
|
-
#
|
91
|
-
# @param [Currency] from The currency to convert from.
|
92
|
-
# @param [Currency] to The currency to convert to.
|
93
|
-
#
|
94
|
-
# @return [URI::HTTP]
|
95
|
-
def build_uri(from, to)
|
96
|
-
uri = URI::HTTP.build(
|
97
|
-
:host => SERVICE_HOST,
|
98
|
-
:path => SERVICE_PATH,
|
99
|
-
:query => "hl=en&q=1#{from.iso_code}%3D%3F#{to.iso_code}"
|
100
|
-
)
|
101
|
-
end
|
102
|
-
|
103
|
-
##
|
104
|
-
# Takes the invalid JSON returned by Google and fixes it.
|
105
|
-
#
|
106
|
-
# @param [String] data The JSON string to fix.
|
107
|
-
#
|
108
|
-
# @return [Hash]
|
109
|
-
def fix_response_json_data(data)
|
110
|
-
data.gsub!(/lhs:/, '"lhs":')
|
111
|
-
data.gsub!(/rhs:/, '"rhs":')
|
112
|
-
data.gsub!(/error:/, '"error":')
|
113
|
-
data.gsub!(/icc:/, '"icc":')
|
114
|
-
data.gsub!(
|
115
|
-
|
116
|
-
MultiJson.decode(data)
|
117
|
-
end
|
118
|
-
|
119
|
-
|
120
|
-
|
1
|
+
require 'money'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'multi_json'
|
4
|
+
|
5
|
+
class Money
|
6
|
+
module Bank
|
7
|
+
class GoogleCurrency < Money::Bank::VariableExchange
|
8
|
+
|
9
|
+
SERVICE_HOST = "www.google.com"
|
10
|
+
SERVICE_PATH = "/ig/calculator"
|
11
|
+
|
12
|
+
# @return [Hash] Stores the currently known rates.
|
13
|
+
attr_reader :rates
|
14
|
+
|
15
|
+
##
|
16
|
+
# Clears all rates stored in @rates
|
17
|
+
#
|
18
|
+
# @return [Hash] The empty @rates Hash.
|
19
|
+
#
|
20
|
+
# @example
|
21
|
+
# @bank = GoogleCurrency.new #=> <Money::Bank::GoogleCurrency...>
|
22
|
+
# @bank.get_rate(:USD, :EUR) #=> 0.776337241
|
23
|
+
# @bank.flush_rates #=> {}
|
24
|
+
def flush_rates
|
25
|
+
@mutex.synchronize{
|
26
|
+
@rates = {}
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# Clears the specified rate stored in @rates.
|
32
|
+
#
|
33
|
+
# @param [String, Symbol, Currency] from Currency to convert from (used
|
34
|
+
# for key into @rates).
|
35
|
+
# @param [String, Symbol, Currency] to Currency to convert to (used for
|
36
|
+
# key into @rates).
|
37
|
+
#
|
38
|
+
# @return [Float] The flushed rate.
|
39
|
+
#
|
40
|
+
# @example
|
41
|
+
# @bank = GoogleCurrency.new #=> <Money::Bank::GoogleCurrency...>
|
42
|
+
# @bank.get_rate(:USD, :EUR) #=> 0.776337241
|
43
|
+
# @bank.flush_rate(:USD, :EUR) #=> 0.776337241
|
44
|
+
def flush_rate(from, to)
|
45
|
+
key = rate_key_for(from, to)
|
46
|
+
@mutex.synchronize{
|
47
|
+
@rates.delete(key)
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# Returns the requested rate.
|
53
|
+
#
|
54
|
+
# @param [String, Symbol, Currency] from Currency to convert from
|
55
|
+
# @param [String, Symbol, Currency] to Currency to convert to
|
56
|
+
#
|
57
|
+
# @return [Float] The requested rate.
|
58
|
+
#
|
59
|
+
# @example
|
60
|
+
# @bank = GoogleCurrency.new #=> <Money::Bank::GoogleCurrency...>
|
61
|
+
# @bank.get_rate(:USD, :EUR) #=> 0.776337241
|
62
|
+
def get_rate(from, to)
|
63
|
+
@mutex.synchronize{
|
64
|
+
@rates[rate_key_for(from, to)] ||= fetch_rate(from, to)
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
##
|
71
|
+
# Queries for the requested rate and returns it.
|
72
|
+
#
|
73
|
+
# @param [String, Symbol, Currency] from Currency to convert from
|
74
|
+
# @param [String, Symbol, Currency] to Currency to convert to
|
75
|
+
#
|
76
|
+
# @return [BigDecimal] The requested rate.
|
77
|
+
def fetch_rate(from, to)
|
78
|
+
from, to = Currency.wrap(from), Currency.wrap(to)
|
79
|
+
|
80
|
+
data = build_uri(from, to).read
|
81
|
+
data = fix_response_json_data(data)
|
82
|
+
|
83
|
+
error = data['error']
|
84
|
+
raise UnknownRate unless error == '' || error == '0'
|
85
|
+
decode_rate data['rhs']
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# Build a URI for the given arguments.
|
90
|
+
#
|
91
|
+
# @param [Currency] from The currency to convert from.
|
92
|
+
# @param [Currency] to The currency to convert to.
|
93
|
+
#
|
94
|
+
# @return [URI::HTTP]
|
95
|
+
def build_uri(from, to)
|
96
|
+
uri = URI::HTTP.build(
|
97
|
+
:host => SERVICE_HOST,
|
98
|
+
:path => SERVICE_PATH,
|
99
|
+
:query => "hl=en&q=1#{from.iso_code}%3D%3F#{to.iso_code}"
|
100
|
+
)
|
101
|
+
end
|
102
|
+
|
103
|
+
##
|
104
|
+
# Takes the invalid JSON returned by Google and fixes it.
|
105
|
+
#
|
106
|
+
# @param [String] data The JSON string to fix.
|
107
|
+
#
|
108
|
+
# @return [Hash]
|
109
|
+
def fix_response_json_data(data)
|
110
|
+
data.gsub!(/lhs:/, '"lhs":')
|
111
|
+
data.gsub!(/rhs:/, '"rhs":')
|
112
|
+
data.gsub!(/error:/, '"error":')
|
113
|
+
data.gsub!(/icc:/, '"icc":')
|
114
|
+
data.gsub!(Regexp.new("(\\\\x..|\\\\240)"), '')
|
115
|
+
|
116
|
+
MultiJson.decode(data)
|
117
|
+
end
|
118
|
+
|
119
|
+
##
|
120
|
+
# Takes the 'rhs' response from Google and decodes it.
|
121
|
+
#
|
122
|
+
# @param [String] rhs The google rate string to decode.
|
123
|
+
#
|
124
|
+
# @return [BigDecimal]
|
125
|
+
def decode_rate(rhs)
|
126
|
+
if complex_rate?(rhs)
|
127
|
+
decode_complex_rate(rhs)
|
128
|
+
else
|
129
|
+
decode_basic_rate(rhs)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
##
|
134
|
+
# Takes the 'rhs' response from Google and decides if it's a complex rate
|
135
|
+
#
|
136
|
+
# @param [String] rhs The google rate string to check.
|
137
|
+
#
|
138
|
+
# @return [Boolean]
|
139
|
+
def complex_rate?(rhs)
|
140
|
+
rhs.match(/10x3csupx3e(-?\d+)x3c\/supx3e/)
|
141
|
+
end
|
142
|
+
|
143
|
+
##
|
144
|
+
# Takes a complex 'rhs' response from Google and converts it to a numeric
|
145
|
+
# rate.
|
146
|
+
#
|
147
|
+
# @param [String] rhs The complex google rate string to convert.
|
148
|
+
#
|
149
|
+
# @return [BigDecimal]
|
150
|
+
def decode_complex_rate(rhs)
|
151
|
+
rate = BigDecimal(rhs.match(/\d[\d\s]*\.?\d*/)[0])
|
152
|
+
power = rhs.match(/10x3csupx3e(-?\d+)x3c\/supx3e/)
|
153
|
+
|
154
|
+
rate * 10**power[1].to_i
|
155
|
+
end
|
156
|
+
|
157
|
+
##
|
158
|
+
# Takes a basic 'rhs' response from Google and converts it to a numeric
|
159
|
+
# rate.
|
160
|
+
#
|
161
|
+
# @param [String] rhs The basic google rate string to convert.
|
162
|
+
#
|
163
|
+
# @return [BigDecimal]
|
164
|
+
def decode_basic_rate(rhs)
|
165
|
+
BigDecimal(rhs.gsub(/[^\d\.]/, ''))
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -1,53 +1,61 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
-
|
3
|
-
require 'money'
|
4
|
-
require 'money/bank/google_currency'
|
5
|
-
|
6
|
-
require 'json'
|
7
|
-
MultiJson.engine = :json_gem
|
8
|
-
|
9
|
-
describe "GoogleCurrency" do
|
10
|
-
before :each do
|
11
|
-
@bank = Money::Bank::GoogleCurrency.new
|
12
|
-
end
|
13
|
-
|
14
|
-
describe "#get_rate" do
|
15
|
-
it "should use #fetch_rate when rate is unknown" do
|
16
|
-
@bank.should_receive(:fetch_rate).once
|
17
|
-
@bank.get_rate('USD', 'USD')
|
18
|
-
end
|
19
|
-
|
20
|
-
it "should not use #fetch_rate when rate is known" do
|
21
|
-
@bank.get_rate('USD', 'USD')
|
22
|
-
@bank.should_not_receive(:fetch_rate)
|
23
|
-
@bank.get_rate('USD', 'USD')
|
24
|
-
end
|
25
|
-
|
26
|
-
it "should return the correct rate" do
|
27
|
-
@bank.get_rate('USD', 'USD').should == 1.0
|
28
|
-
end
|
29
|
-
|
30
|
-
it "should store the rate for faster retreival" do
|
31
|
-
@bank.get_rate('USD', 'EUR')
|
32
|
-
@bank.rates.should include('USD_TO_EUR')
|
33
|
-
end
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
@bank.
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
describe "#
|
45
|
-
it "should
|
46
|
-
@bank.get_rate('USD', 'EUR')
|
47
|
-
@bank.
|
48
|
-
@bank.
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
require 'money'
|
4
|
+
require 'money/bank/google_currency'
|
5
|
+
|
6
|
+
require 'json'
|
7
|
+
MultiJson.engine = :json_gem
|
8
|
+
|
9
|
+
describe "GoogleCurrency" do
|
10
|
+
before :each do
|
11
|
+
@bank = Money::Bank::GoogleCurrency.new
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#get_rate" do
|
15
|
+
it "should use #fetch_rate when rate is unknown" do
|
16
|
+
@bank.should_receive(:fetch_rate).once
|
17
|
+
@bank.get_rate('USD', 'USD')
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should not use #fetch_rate when rate is known" do
|
21
|
+
@bank.get_rate('USD', 'USD')
|
22
|
+
@bank.should_not_receive(:fetch_rate)
|
23
|
+
@bank.get_rate('USD', 'USD')
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should return the correct rate" do
|
27
|
+
@bank.get_rate('USD', 'USD').should == 1.0
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should store the rate for faster retreival" do
|
31
|
+
@bank.get_rate('USD', 'EUR')
|
32
|
+
@bank.rates.should include('USD_TO_EUR')
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should handle complex rates" do
|
36
|
+
uri = double('uri')
|
37
|
+
@bank.stub(:build_uri){|from,to| uri }
|
38
|
+
uri.stub(:read) { %q({lhs: "1 Vietnamese dong",rhs: "4.8 \x26#215; 10\x3csup\x3e-5\x3c/sup\x3e U.S. dollars",error: "",icc: true}) }
|
39
|
+
|
40
|
+
@bank.get_rate('VND', 'USD').should == BigDecimal("0.48215105E1")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "#flush_rates" do
|
45
|
+
it "should empty @rates" do
|
46
|
+
@bank.get_rate('USD', 'EUR')
|
47
|
+
@bank.flush_rates
|
48
|
+
@bank.rates.should == {}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#flush_rate" do
|
53
|
+
it "should remove a specific rate from @rates" do
|
54
|
+
@bank.get_rate('USD', 'EUR')
|
55
|
+
@bank.get_rate('USD', 'JPY')
|
56
|
+
@bank.flush_rate('USD', 'EUR')
|
57
|
+
@bank.rates.should include('USD_TO_JPY')
|
58
|
+
@bank.rates.should_not include('USD_TO_EUR')
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -1,53 +1,60 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
-
|
3
|
-
require 'money'
|
4
|
-
require 'money/bank/google_currency'
|
5
|
-
|
6
|
-
require 'yajl'
|
7
|
-
MultiJson.engine = :yajl
|
8
|
-
|
9
|
-
describe "GoogleCurrency" do
|
10
|
-
before :each do
|
11
|
-
@bank = Money::Bank::GoogleCurrency.new
|
12
|
-
end
|
13
|
-
|
14
|
-
describe "#get_rate" do
|
15
|
-
it "should use #fetch_rate when rate is unknown" do
|
16
|
-
@bank.should_receive(:fetch_rate).once
|
17
|
-
@bank.get_rate('USD', 'USD')
|
18
|
-
end
|
19
|
-
|
20
|
-
it "should not use #fetch_rate when rate is known" do
|
21
|
-
@bank.get_rate('USD', 'USD')
|
22
|
-
@bank.should_not_receive(:fetch_rate)
|
23
|
-
@bank.get_rate('USD', 'USD')
|
24
|
-
end
|
25
|
-
|
26
|
-
it "should return the correct rate" do
|
27
|
-
@bank.get_rate('USD', 'USD').should == 1.0
|
28
|
-
end
|
29
|
-
|
30
|
-
it "should store the rate for faster retreival" do
|
31
|
-
@bank.get_rate('USD', 'EUR')
|
32
|
-
@bank.rates.should include('USD_TO_EUR')
|
33
|
-
end
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
@bank.
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
@bank.
|
47
|
-
@bank.
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
require 'money'
|
4
|
+
require 'money/bank/google_currency'
|
5
|
+
|
6
|
+
require 'yajl'
|
7
|
+
MultiJson.engine = :yajl
|
8
|
+
|
9
|
+
describe "GoogleCurrency" do
|
10
|
+
before :each do
|
11
|
+
@bank = Money::Bank::GoogleCurrency.new
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#get_rate" do
|
15
|
+
it "should use #fetch_rate when rate is unknown" do
|
16
|
+
@bank.should_receive(:fetch_rate).once
|
17
|
+
@bank.get_rate('USD', 'USD')
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should not use #fetch_rate when rate is known" do
|
21
|
+
@bank.get_rate('USD', 'USD')
|
22
|
+
@bank.should_not_receive(:fetch_rate)
|
23
|
+
@bank.get_rate('USD', 'USD')
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should return the correct rate" do
|
27
|
+
@bank.get_rate('USD', 'USD').should == 1.0
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should store the rate for faster retreival" do
|
31
|
+
@bank.get_rate('USD', 'EUR')
|
32
|
+
@bank.rates.should include('USD_TO_EUR')
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should handle complex rates" do
|
36
|
+
uri = double('uri')
|
37
|
+
@bank.stub(:build_uri){|from,to| uri }
|
38
|
+
uri.stub(:read) { %q({lhs: "1 Vietnamese dong",rhs: "4.8 \x26#215; 10\x3csup\x3e-5\x3c/sup\x3e U.S. dollars",error: "",icc: true}) }
|
39
|
+
@bank.get_rate('VND', 'USD').should == BigDecimal("0.48215105E1")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "#flush_rates" do
|
44
|
+
it "should empty @rates" do
|
45
|
+
@bank.get_rate('USD', 'EUR')
|
46
|
+
@bank.flush_rates
|
47
|
+
@bank.rates.should == {}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#flush_rate" do
|
52
|
+
it "should remove a specific rate from @rates" do
|
53
|
+
@bank.get_rate('USD', 'EUR')
|
54
|
+
@bank.get_rate('USD', 'JPY')
|
55
|
+
@bank.flush_rate('USD', 'EUR')
|
56
|
+
@bank.rates.should include('USD_TO_JPY')
|
57
|
+
@bank.rates.should_not include('USD_TO_EUR')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
RSpec.configure do |config|
|
2
|
-
end
|
1
|
+
RSpec.configure do |config|
|
2
|
+
end
|
metadata
CHANGED
@@ -1,20 +1,19 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: google_currency
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Shane Emmons
|
9
|
-
- Donald Ball
|
10
9
|
autorequire:
|
11
10
|
bindir: bin
|
12
11
|
cert_chain: []
|
13
|
-
date: 2011-
|
12
|
+
date: 2011-12-08 00:00:00.000000000Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: rspec
|
17
|
-
requirement: &
|
16
|
+
requirement: &70141932037880 !ruby/object:Gem::Requirement
|
18
17
|
none: false
|
19
18
|
requirements:
|
20
19
|
- - ! '>='
|
@@ -22,10 +21,10 @@ dependencies:
|
|
22
21
|
version: 2.0.0
|
23
22
|
type: :development
|
24
23
|
prerelease: false
|
25
|
-
version_requirements: *
|
24
|
+
version_requirements: *70141932037880
|
26
25
|
- !ruby/object:Gem::Dependency
|
27
26
|
name: yard
|
28
|
-
requirement: &
|
27
|
+
requirement: &70141932037400 !ruby/object:Gem::Requirement
|
29
28
|
none: false
|
30
29
|
requirements:
|
31
30
|
- - ! '>='
|
@@ -33,10 +32,10 @@ dependencies:
|
|
33
32
|
version: 0.5.8
|
34
33
|
type: :development
|
35
34
|
prerelease: false
|
36
|
-
version_requirements: *
|
35
|
+
version_requirements: *70141932037400
|
37
36
|
- !ruby/object:Gem::Dependency
|
38
37
|
name: json
|
39
|
-
requirement: &
|
38
|
+
requirement: &70141932036840 !ruby/object:Gem::Requirement
|
40
39
|
none: false
|
41
40
|
requirements:
|
42
41
|
- - ! '>='
|
@@ -44,10 +43,10 @@ dependencies:
|
|
44
43
|
version: 1.4.0
|
45
44
|
type: :development
|
46
45
|
prerelease: false
|
47
|
-
version_requirements: *
|
46
|
+
version_requirements: *70141932036840
|
48
47
|
- !ruby/object:Gem::Dependency
|
49
48
|
name: yajl-ruby
|
50
|
-
requirement: &
|
49
|
+
requirement: &70141932036380 !ruby/object:Gem::Requirement
|
51
50
|
none: false
|
52
51
|
requirements:
|
53
52
|
- - ! '>='
|
@@ -55,10 +54,10 @@ dependencies:
|
|
55
54
|
version: 1.0.0
|
56
55
|
type: :development
|
57
56
|
prerelease: false
|
58
|
-
version_requirements: *
|
57
|
+
version_requirements: *70141932036380
|
59
58
|
- !ruby/object:Gem::Dependency
|
60
59
|
name: money
|
61
|
-
requirement: &
|
60
|
+
requirement: &70141932035780 !ruby/object:Gem::Requirement
|
62
61
|
none: false
|
63
62
|
requirements:
|
64
63
|
- - ~>
|
@@ -66,10 +65,10 @@ dependencies:
|
|
66
65
|
version: '3.5'
|
67
66
|
type: :runtime
|
68
67
|
prerelease: false
|
69
|
-
version_requirements: *
|
68
|
+
version_requirements: *70141932035780
|
70
69
|
- !ruby/object:Gem::Dependency
|
71
70
|
name: multi_json
|
72
|
-
requirement: &
|
71
|
+
requirement: &70141932035300 !ruby/object:Gem::Requirement
|
73
72
|
none: false
|
74
73
|
requirements:
|
75
74
|
- - ! '>='
|
@@ -77,12 +76,11 @@ dependencies:
|
|
77
76
|
version: 1.0.0
|
78
77
|
type: :runtime
|
79
78
|
prerelease: false
|
80
|
-
version_requirements: *
|
79
|
+
version_requirements: *70141932035300
|
81
80
|
description: GoogleCurrency extends Money::Bank::Base and gives you access to the
|
82
81
|
current Google Currency exchange rates.
|
83
82
|
email:
|
84
|
-
- semmons99
|
85
|
-
- donald.ball@gmail.com
|
83
|
+
- semmons99@gmail.com
|
86
84
|
executables: []
|
87
85
|
extensions: []
|
88
86
|
extra_rdoc_files: []
|
@@ -94,6 +92,7 @@ files:
|
|
94
92
|
- LICENSE
|
95
93
|
- README.md
|
96
94
|
- CHANGELOG.md
|
95
|
+
- AUTHORS
|
97
96
|
- Rakefile
|
98
97
|
- .gemtest
|
99
98
|
- google_currency.gemspec
|
@@ -109,6 +108,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
109
108
|
- - ! '>='
|
110
109
|
- !ruby/object:Gem::Version
|
111
110
|
version: '0'
|
111
|
+
segments:
|
112
|
+
- 0
|
113
|
+
hash: -2496966604320701607
|
112
114
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
115
|
none: false
|
114
116
|
requirements:
|
@@ -117,7 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
117
119
|
version: 1.3.6
|
118
120
|
requirements: []
|
119
121
|
rubyforge_project:
|
120
|
-
rubygems_version: 1.8.
|
122
|
+
rubygems_version: 1.8.10
|
121
123
|
signing_key:
|
122
124
|
specification_version: 3
|
123
125
|
summary: Access the Google Currency exchange rate data.
|