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 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.2.2
1
+ 1.3.0
@@ -1,3 +1,3 @@
1
- class Numeric
1
+ class Fixnum
2
2
  include CurrencyConvertible
3
3
  end
@@ -0,0 +1,3 @@
1
+ class Float
2
+ include CurrencyConvertible
3
+ end
@@ -1,2 +1,3 @@
1
1
  require 'simple_currency/currency_convertible'
2
- require 'core_ext/numeric'
2
+ require 'core_ext/fixnum'
3
+ require 'core_ext/float'
@@ -4,53 +4,82 @@ require 'crack/xml'
4
4
 
5
5
  module CurrencyConvertible
6
6
 
7
- def method_missing(method, *args, &block)
8
- return _from(method.to_s) if method.to_s.length == 3 # Presumably a currency ("eur", "gbp"...)
7
+ Operators = {:+ => :add,
8
+ :- => :subtract}
9
9
 
10
- # Now capture methods like to_eur, to_gbp, to_usd...
11
- if @original && !(method.to_s =~ /^to_(utc|int|str|ary)/) && method.to_s =~/^to_/ && method.to_s.length == 6
12
- return _to(method.to_s.gsub('to_',''))
13
- end
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
- super(method,*args,&block)
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
- # Historical exchange lookup
19
- def at(exchange = nil)
20
- begin
21
-
22
- @exchange_date = exchange.send(:to_date)
23
- rescue
24
- raise "Must use 'at' with a time or date object"
25
- end
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
- private
30
-
31
- # Called from first currency metamethod to set the original currency.
32
- #
33
- # 30.eur # => Calls _from and sets @original to 'eur'
34
- #
35
- def _from(currency)
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
- @original = currency
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
- # Called from last currency metamethod to set the target currency.
42
- #
43
- # 30.eur.to_usd
44
- # # => Calls _to and returns the final value, say 38.08
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 @original # Must be called after a _from have set the @original currency
76
+ raise unless @currency
48
77
 
49
- return 0.0 if self == 0 # Obviously
78
+ return 0.0 if @numeric == 0 # Obviously
50
79
 
51
- original = @original
80
+ original = @currency
52
81
 
53
- amount = self
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 or Xurrency strategies
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 = (self < 0)
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
 
@@ -5,45 +5,47 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{simple_currency}
8
- s.version = "1.2.2"
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-14}
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
- "README.md"
17
+ "README.md"
18
18
  ]
19
19
  s.files = [
20
20
  ".autotest",
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/numeric.rb",
33
- "lib/simple_currency.rb",
34
- "lib/simple_currency/currency_convertible.rb",
35
- "simple_currency.gemspec",
36
- "spec/simple_currency_spec.rb",
37
- "spec/spec_helper.rb",
38
- "spec/support/xavier.xml"
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
- "spec/spec_helper.rb"
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("404 Not Found")
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
- - 2
9
- - 2
10
- version: 1.2.2
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-14 00:00:00 +02:00
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
- name: crack
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
- requirement: *id002
37
+ type: :runtime
38
+ version_requirements: *id001
53
39
  - !ruby/object:Gem::Dependency
54
- type: :development
55
- prerelease: false
56
40
  name: jeweler
57
- version_requirements: &id003 !ruby/object:Gem::Requirement
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
- prerelease: false
54
+ version_requirements: *id002
55
+ - !ruby/object:Gem::Dependency
72
56
  name: rspec
73
- version_requirements: &id004 !ruby/object:Gem::Requirement
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: 62196431
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
- prerelease: false
72
+ version_requirements: *id003
73
+ - !ruby/object:Gem::Dependency
90
74
  name: fakeweb
91
- version_requirements: &id005 !ruby/object:Gem::Requirement
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
- prerelease: false
88
+ version_requirements: *id004
89
+ - !ruby/object:Gem::Dependency
106
90
  name: rails
107
- version_requirements: &id006 !ruby/object:Gem::Requirement
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
- prerelease: false
104
+ version_requirements: *id005
105
+ - !ruby/object:Gem::Dependency
122
106
  name: bundler
123
- version_requirements: &id007 !ruby/object:Gem::Requirement
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
- requirement: *id007
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/numeric.rb
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