simple_currency 1.2.2 → 1.3.0
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/README.md +9 -0
- data/VERSION +1 -1
- data/lib/core_ext/{numeric.rb → fixnum.rb} +1 -1
- data/lib/core_ext/float.rb +3 -0
- data/lib/simple_currency.rb +2 -1
- data/lib/simple_currency/currency_convertible.rb +72 -51
- data/simple_currency.gemspec +24 -25
- data/spec/simple_currency_spec.rb +42 -1
- metadata +32 -45
data/README.md
CHANGED
@@ -37,6 +37,15 @@ in the past? Just do this:
|
|
37
37
|
42.eur.at(Time.parse('2009-09-01')).to_usd
|
38
38
|
# => 60.12
|
39
39
|
|
40
|
+
You can also add an subtract money expressions, which will return a result
|
41
|
+
converted to the former currency of the expression:
|
42
|
+
|
43
|
+
42.eur + 30.usd
|
44
|
+
# => The same as adding 42 and 30.usd.to_eur
|
45
|
+
|
46
|
+
10.gbp + 1.eur
|
47
|
+
# => The same as adding 10 and 1.eur.to_gbp
|
48
|
+
|
40
49
|
##Installation
|
41
50
|
|
42
51
|
###Rails 3
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.3.0
|
data/lib/simple_currency.rb
CHANGED
@@ -4,53 +4,82 @@ require 'crack/xml'
|
|
4
4
|
|
5
5
|
module CurrencyConvertible
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
Operators = {:+ => :add,
|
8
|
+
:- => :subtract}
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
def add_with_currency(arg)
|
11
|
+
return add_without_currency(arg) unless arg.is_a? CurrencyConvertible::Proxy
|
12
|
+
add_without_currency(arg)
|
13
|
+
end
|
14
14
|
|
15
|
-
|
15
|
+
def subtract_with_currency(arg)
|
16
|
+
return subtract_without_currency(arg) unless arg.is_a? CurrencyConvertible::Proxy
|
17
|
+
subtract_without_currency(arg)
|
16
18
|
end
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
self
|
20
|
+
def self.included(base)
|
21
|
+
base.send(:alias_method, :add_without_currency, :+)
|
22
|
+
base.send(:undef_method, :+)
|
23
|
+
base.send(:alias_method, :+, :add_with_currency)
|
24
|
+
|
25
|
+
base.send(:alias_method, :subtract_without_currency, :-)
|
26
|
+
base.send(:undef_method, :-)
|
27
|
+
base.send(:alias_method, :-, :subtract_with_currency)
|
27
28
|
end
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
30
|
+
def method_missing(method, *args, &block)
|
31
|
+
return CurrencyConvertible::Proxy.new(self,method.to_s) if method.to_s.length == 3 # Presumably a currency ("eur", "gbp"...)
|
32
|
+
super(method,*args,&block)
|
33
|
+
end
|
34
|
+
|
35
|
+
class Proxy
|
36
|
+
attr_reader :numeric
|
37
|
+
|
38
|
+
def initialize(numeric,currency)
|
39
|
+
@numeric = numeric
|
40
|
+
@currency = currency
|
36
41
|
@exchange_date = Time.now.send(:to_date)
|
37
|
-
|
42
|
+
end
|
43
|
+
|
44
|
+
def method_missing(method, *args, &block)
|
45
|
+
if !(method.to_s =~ /^to_(utc|int|str|ary)/) && method.to_s =~/^to_/ && method.to_s.length == 6
|
46
|
+
return _to(method.to_s.gsub('to_',''))
|
47
|
+
end
|
48
|
+
@numeric.send(method, *args, &block)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Historical exchange lookup
|
52
|
+
def at(exchange = nil)
|
53
|
+
begin
|
54
|
+
@exchange_date = exchange.send(:to_date)
|
55
|
+
rescue
|
56
|
+
raise "Must use 'at' with a time or date object"
|
57
|
+
end
|
38
58
|
self
|
39
59
|
end
|
40
60
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
61
|
+
def +(other)
|
62
|
+
return @numeric + other unless other.is_a? CurrencyConvertible::Proxy
|
63
|
+
converted = other.send(:"to_#{@currency}")
|
64
|
+
@numeric + converted
|
65
|
+
end
|
66
|
+
|
67
|
+
def -(other)
|
68
|
+
return @numeric - other unless other.is_a? CurrencyConvertible::Proxy
|
69
|
+
converted = other.send(:"to_#{@currency}")
|
70
|
+
@numeric - converted
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
46
75
|
def _to(target)
|
47
|
-
raise unless @
|
76
|
+
raise unless @currency
|
48
77
|
|
49
|
-
return 0.0 if
|
78
|
+
return 0.0 if @numeric == 0 # Obviously
|
50
79
|
|
51
|
-
original = @
|
80
|
+
original = @currency
|
52
81
|
|
53
|
-
amount =
|
82
|
+
amount = @numeric
|
54
83
|
|
55
84
|
# Check if there's a cached exchange rate for today
|
56
85
|
return cached_amount(original, target, amount) if cached_rate(original, target)
|
@@ -59,16 +88,16 @@ module CurrencyConvertible
|
|
59
88
|
result = exchange(original, target, amount.abs)
|
60
89
|
|
61
90
|
# Cache methods
|
62
|
-
cache_currency_methods(original, target)
|
91
|
+
#cache_currency_methods(original, target)
|
63
92
|
|
64
93
|
result
|
65
94
|
end
|
66
95
|
|
67
|
-
# Main method (called by _to) which calls Xavier
|
96
|
+
# Main method (called by _to) which calls Xavier API
|
68
97
|
# and returns a nice result.
|
69
98
|
#
|
70
99
|
def exchange(original, target, amount)
|
71
|
-
negative = (
|
100
|
+
negative = (@numeric < 0)
|
72
101
|
|
73
102
|
# Get the result and round it to 2 decimals
|
74
103
|
result = sprintf("%.2f", call_xavier_api(original, target, amount)).to_f
|
@@ -117,8 +146,10 @@ module CurrencyConvertible
|
|
117
146
|
uri = URI.parse(api_url)
|
118
147
|
retry
|
119
148
|
else
|
120
|
-
raise "404 Not Found"
|
149
|
+
raise NotFoundError.new("404 Not Found")
|
121
150
|
end
|
151
|
+
rescue SocketError
|
152
|
+
raise NotFoundError.new("Socket Error")
|
122
153
|
end
|
123
154
|
|
124
155
|
return nil unless xml_response && parsed_response = Crack::XML.parse(xml_response)
|
@@ -152,20 +183,6 @@ module CurrencyConvertible
|
|
152
183
|
rate.first['rate'].to_f
|
153
184
|
end
|
154
185
|
|
155
|
-
# Caches currency methods to avoid method missing abuse.
|
156
|
-
#
|
157
|
-
def cache_currency_methods(original, target)
|
158
|
-
# Cache the _from method for faster reuse
|
159
|
-
self.class.send(:define_method, original.to_sym) do
|
160
|
-
_from(original)
|
161
|
-
end unless self.respond_to?(original.to_sym)
|
162
|
-
|
163
|
-
# Cache the _to method for faster reuse
|
164
|
-
self.class.send(:define_method, :"to_#{target}") do
|
165
|
-
_to(target)
|
166
|
-
end unless self.respond_to?(:"to_#{target}")
|
167
|
-
end
|
168
|
-
|
169
186
|
##
|
170
187
|
# Cache helper methods (only useful in a Rails app)
|
171
188
|
##
|
@@ -209,6 +226,7 @@ module CurrencyConvertible
|
|
209
226
|
end
|
210
227
|
nil
|
211
228
|
end
|
229
|
+
end
|
212
230
|
|
213
231
|
end
|
214
232
|
|
@@ -222,4 +240,7 @@ end
|
|
222
240
|
class NoRatesFoundException < StandardError
|
223
241
|
end
|
224
242
|
|
243
|
+
class NotFoundError < StandardError
|
244
|
+
end
|
245
|
+
|
225
246
|
|
data/simple_currency.gemspec
CHANGED
@@ -5,45 +5,47 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{simple_currency}
|
8
|
-
s.version = "1.
|
8
|
+
s.version = "1.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Oriol Gual", "Josep M. Bach", "Josep Jaume Rey"]
|
12
|
-
s.date = %q{2010-10-
|
12
|
+
s.date = %q{2010-10-24}
|
13
13
|
s.description = %q{A really simple currency converter using XavierMedia API. It's Ruby 1.8, 1.9 and JRuby compatible, and it also takes advantage of Rails cache when available.}
|
14
14
|
s.email = %q{info@codegram.com}
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE",
|
17
|
-
|
17
|
+
"README.md"
|
18
18
|
]
|
19
19
|
s.files = [
|
20
20
|
".autotest",
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
21
|
+
".bundle/config",
|
22
|
+
".gitignore",
|
23
|
+
".rspec",
|
24
|
+
".rvmrc",
|
25
|
+
"Gemfile",
|
26
|
+
"Gemfile.lock",
|
27
|
+
"LICENSE",
|
28
|
+
"README.md",
|
29
|
+
"Rakefile",
|
30
|
+
"VERSION",
|
31
|
+
"autotest/discover.rb",
|
32
|
+
"lib/core_ext/fixnum.rb",
|
33
|
+
"lib/core_ext/float.rb",
|
34
|
+
"lib/simple_currency.rb",
|
35
|
+
"lib/simple_currency/currency_convertible.rb",
|
36
|
+
"simple_currency.gemspec",
|
37
|
+
"spec/simple_currency_spec.rb",
|
38
|
+
"spec/spec_helper.rb",
|
39
|
+
"spec/support/xavier.xml"
|
39
40
|
]
|
40
41
|
s.homepage = %q{http://github.com/codegram/simple_currency}
|
42
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
41
43
|
s.require_paths = ["lib"]
|
42
44
|
s.rubygems_version = %q{1.3.7}
|
43
45
|
s.summary = %q{A really simple currency converter using XavierMedia API.}
|
44
46
|
s.test_files = [
|
45
47
|
"spec/simple_currency_spec.rb",
|
46
|
-
|
48
|
+
"spec/spec_helper.rb"
|
47
49
|
]
|
48
50
|
|
49
51
|
if s.respond_to? :specification_version then
|
@@ -51,7 +53,6 @@ Gem::Specification.new do |s|
|
|
51
53
|
s.specification_version = 3
|
52
54
|
|
53
55
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
54
|
-
s.add_runtime_dependency(%q<crack>, [">= 0"])
|
55
56
|
s.add_runtime_dependency(%q<crack>, [">= 0.1.8"])
|
56
57
|
s.add_development_dependency(%q<jeweler>, [">= 1.4.0"])
|
57
58
|
s.add_development_dependency(%q<rspec>, [">= 2.0.0.beta.22"])
|
@@ -59,7 +60,6 @@ Gem::Specification.new do |s|
|
|
59
60
|
s.add_development_dependency(%q<rails>, [">= 3.0.0"])
|
60
61
|
s.add_development_dependency(%q<bundler>, [">= 1.0.0"])
|
61
62
|
else
|
62
|
-
s.add_dependency(%q<crack>, [">= 0"])
|
63
63
|
s.add_dependency(%q<crack>, [">= 0.1.8"])
|
64
64
|
s.add_dependency(%q<jeweler>, [">= 1.4.0"])
|
65
65
|
s.add_dependency(%q<rspec>, [">= 2.0.0.beta.22"])
|
@@ -68,7 +68,6 @@ Gem::Specification.new do |s|
|
|
68
68
|
s.add_dependency(%q<bundler>, [">= 1.0.0"])
|
69
69
|
end
|
70
70
|
else
|
71
|
-
s.add_dependency(%q<crack>, [">= 0"])
|
72
71
|
s.add_dependency(%q<crack>, [">= 0.1.8"])
|
73
72
|
s.add_dependency(%q<jeweler>, [">= 1.4.0"])
|
74
73
|
s.add_dependency(%q<rspec>, [">= 2.0.0.beta.22"])
|
@@ -10,6 +10,44 @@ describe "SimpleCurrency" do
|
|
10
10
|
0.usd.to_eur.should == 0.0
|
11
11
|
end
|
12
12
|
|
13
|
+
describe "operators" do
|
14
|
+
|
15
|
+
let(:today) { Time.now }
|
16
|
+
|
17
|
+
before(:each) do
|
18
|
+
mock_xavier_api(today)
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#+" do
|
22
|
+
it "adds two money expressions" do
|
23
|
+
(1.eur + 1.27.usd).should == 2
|
24
|
+
(1.27.usd + 1.eur).should == 2.54
|
25
|
+
(1.eur + 1.eur).should == 2
|
26
|
+
end
|
27
|
+
|
28
|
+
it "does not affect non-money expressions" do
|
29
|
+
(1 + 1.27).should == 2.27
|
30
|
+
(38.eur + 1.27).should == 39.27
|
31
|
+
(1.27.usd + 38).should == 39.27
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#-" do
|
36
|
+
it "subtracts two money expressions" do
|
37
|
+
(1.eur - 1.27.usd).should == 0
|
38
|
+
(1.27.usd - 1.eur).should == 0
|
39
|
+
(1.eur - 1.eur).should == 0
|
40
|
+
end
|
41
|
+
|
42
|
+
it "does not affect non-money expressions" do
|
43
|
+
(1 - 1.27).should == -0.27
|
44
|
+
(38.eur - 1.27).should == 36.73
|
45
|
+
(1.27.usd - 38).should == -36.73
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
13
51
|
context "using XavierMedia API for exchange" do
|
14
52
|
|
15
53
|
let(:today) { Time.now }
|
@@ -74,10 +112,12 @@ describe "SimpleCurrency" do
|
|
74
112
|
expect {
|
75
113
|
begin
|
76
114
|
1.usd.at(the_past).to_eur
|
115
|
+
rescue NotFoundError=>e
|
116
|
+
raise e
|
77
117
|
rescue Timeout::Error
|
78
118
|
retry
|
79
119
|
end
|
80
|
-
}.to raise_error(
|
120
|
+
}.to raise_error(NotFoundError)
|
81
121
|
|
82
122
|
end
|
83
123
|
|
@@ -139,4 +179,5 @@ describe "SimpleCurrency" do
|
|
139
179
|
|
140
180
|
end
|
141
181
|
|
182
|
+
|
142
183
|
end
|
metadata
CHANGED
@@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 1.
|
8
|
+
- 3
|
9
|
+
- 0
|
10
|
+
version: 1.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Oriol Gual
|
@@ -17,28 +17,13 @@ autorequire:
|
|
17
17
|
bindir: bin
|
18
18
|
cert_chain: []
|
19
19
|
|
20
|
-
date: 2010-10-
|
20
|
+
date: 2010-10-24 00:00:00 +02:00
|
21
21
|
default_executable:
|
22
22
|
dependencies:
|
23
23
|
- !ruby/object:Gem::Dependency
|
24
|
-
type: :runtime
|
25
|
-
prerelease: false
|
26
24
|
name: crack
|
27
|
-
version_requirements: &id001 !ruby/object:Gem::Requirement
|
28
|
-
none: false
|
29
|
-
requirements:
|
30
|
-
- - ">="
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
hash: 3
|
33
|
-
segments:
|
34
|
-
- 0
|
35
|
-
version: "0"
|
36
|
-
requirement: *id001
|
37
|
-
- !ruby/object:Gem::Dependency
|
38
|
-
type: :runtime
|
39
25
|
prerelease: false
|
40
|
-
|
41
|
-
version_requirements: &id002 !ruby/object:Gem::Requirement
|
26
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
42
27
|
none: false
|
43
28
|
requirements:
|
44
29
|
- - ">="
|
@@ -49,12 +34,12 @@ dependencies:
|
|
49
34
|
- 1
|
50
35
|
- 8
|
51
36
|
version: 0.1.8
|
52
|
-
|
37
|
+
type: :runtime
|
38
|
+
version_requirements: *id001
|
53
39
|
- !ruby/object:Gem::Dependency
|
54
|
-
type: :development
|
55
|
-
prerelease: false
|
56
40
|
name: jeweler
|
57
|
-
|
41
|
+
prerelease: false
|
42
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
58
43
|
none: false
|
59
44
|
requirements:
|
60
45
|
- - ">="
|
@@ -65,17 +50,17 @@ dependencies:
|
|
65
50
|
- 4
|
66
51
|
- 0
|
67
52
|
version: 1.4.0
|
68
|
-
requirement: *id003
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
53
|
type: :development
|
71
|
-
|
54
|
+
version_requirements: *id002
|
55
|
+
- !ruby/object:Gem::Dependency
|
72
56
|
name: rspec
|
73
|
-
|
57
|
+
prerelease: false
|
58
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
74
59
|
none: false
|
75
60
|
requirements:
|
76
61
|
- - ">="
|
77
62
|
- !ruby/object:Gem::Version
|
78
|
-
hash:
|
63
|
+
hash: 3192703827556712861
|
79
64
|
segments:
|
80
65
|
- 2
|
81
66
|
- 0
|
@@ -83,12 +68,12 @@ dependencies:
|
|
83
68
|
- beta
|
84
69
|
- 22
|
85
70
|
version: 2.0.0.beta.22
|
86
|
-
requirement: *id004
|
87
|
-
- !ruby/object:Gem::Dependency
|
88
71
|
type: :development
|
89
|
-
|
72
|
+
version_requirements: *id003
|
73
|
+
- !ruby/object:Gem::Dependency
|
90
74
|
name: fakeweb
|
91
|
-
|
75
|
+
prerelease: false
|
76
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
92
77
|
none: false
|
93
78
|
requirements:
|
94
79
|
- - ">="
|
@@ -99,12 +84,12 @@ dependencies:
|
|
99
84
|
- 3
|
100
85
|
- 0
|
101
86
|
version: 1.3.0
|
102
|
-
requirement: *id005
|
103
|
-
- !ruby/object:Gem::Dependency
|
104
87
|
type: :development
|
105
|
-
|
88
|
+
version_requirements: *id004
|
89
|
+
- !ruby/object:Gem::Dependency
|
106
90
|
name: rails
|
107
|
-
|
91
|
+
prerelease: false
|
92
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
108
93
|
none: false
|
109
94
|
requirements:
|
110
95
|
- - ">="
|
@@ -115,12 +100,12 @@ dependencies:
|
|
115
100
|
- 0
|
116
101
|
- 0
|
117
102
|
version: 3.0.0
|
118
|
-
requirement: *id006
|
119
|
-
- !ruby/object:Gem::Dependency
|
120
103
|
type: :development
|
121
|
-
|
104
|
+
version_requirements: *id005
|
105
|
+
- !ruby/object:Gem::Dependency
|
122
106
|
name: bundler
|
123
|
-
|
107
|
+
prerelease: false
|
108
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
124
109
|
none: false
|
125
110
|
requirements:
|
126
111
|
- - ">="
|
@@ -131,7 +116,8 @@ dependencies:
|
|
131
116
|
- 0
|
132
117
|
- 0
|
133
118
|
version: 1.0.0
|
134
|
-
|
119
|
+
type: :development
|
120
|
+
version_requirements: *id006
|
135
121
|
description: A really simple currency converter using XavierMedia API. It's Ruby 1.8, 1.9 and JRuby compatible, and it also takes advantage of Rails cache when available.
|
136
122
|
email: info@codegram.com
|
137
123
|
executables: []
|
@@ -154,7 +140,8 @@ files:
|
|
154
140
|
- Rakefile
|
155
141
|
- VERSION
|
156
142
|
- autotest/discover.rb
|
157
|
-
- lib/core_ext/
|
143
|
+
- lib/core_ext/fixnum.rb
|
144
|
+
- lib/core_ext/float.rb
|
158
145
|
- lib/simple_currency.rb
|
159
146
|
- lib/simple_currency/currency_convertible.rb
|
160
147
|
- simple_currency.gemspec
|
@@ -166,8 +153,8 @@ homepage: http://github.com/codegram/simple_currency
|
|
166
153
|
licenses: []
|
167
154
|
|
168
155
|
post_install_message:
|
169
|
-
rdoc_options:
|
170
|
-
|
156
|
+
rdoc_options:
|
157
|
+
- --charset=UTF-8
|
171
158
|
require_paths:
|
172
159
|
- lib
|
173
160
|
required_ruby_version: !ruby/object:Gem::Requirement
|