google_currency 2.0.0 → 2.0.2
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/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
|
-
[](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
|
+
[](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.
|