exchange 1.1.0 → 1.1.1
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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/README.rdoc +4 -4
- data/exchange.gemspec +1 -1
- data/lib/exchange/base.rb +1 -1
- data/lib/exchange/core_extensions/float/error_safe.rb +4 -4
- data/lib/exchange/iso.rb +20 -4
- data/lib/exchange/money.rb +1 -1
- data/spec/exchange/cache/base_spec.rb +1 -1
- data/spec/exchange/cache/memcached_spec.rb +4 -4
- data/spec/exchange/cache/memory_spec.rb +2 -2
- data/spec/exchange/cache/rails_spec.rb +3 -3
- data/spec/exchange/cache/redis_spec.rb +2 -2
- data/spec/exchange/core_extensions/float/error_safe_spec.rb +1 -1
- data/spec/exchange/core_extensions/numeric/conversability_spec.rb +1 -1
- data/spec/exchange/external_api/call_spec.rb +2 -2
- data/spec/exchange/external_api/ecb_spec.rb +1 -1
- data/spec/exchange/external_api/random_spec.rb +1 -1
- data/spec/exchange/helper_spec.rb +1 -1
- data/spec/exchange/iso_spec.rb +26 -0
- data/spec/exchange/money_spec.rb +4 -4
- data/spec/spec_helper.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 91f5a8992aa043b158277a444d70b03dcc83dba6
|
4
|
+
data.tar.gz: 1666ddfa3deca602192b2ac49a9171f329b25d9c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d301bbf1ef608479b9b51e5ca4eab45f1a35c62265f445c37f1c82e628aa8a884f4063fc3f6865c2afdd593c429f30fe32f2b26d629856ef36f59478d4fcba90
|
7
|
+
data.tar.gz: 6c51362dfbdb84d89feb15d8c4b9a34f01bf39cded31ae93ea50dfbc6930ea461d2c1f11e0b13da61a83ced54581f01ca6ef0e2e01ec02e54ccb369a1e250db6
|
data/.travis.yml
CHANGED
data/README.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= exchange {<img src="https://secure.travis-ci.org/beatrichartz/exchange.png?branch=master" />}[http://travis-ci.org/beatrichartz/exchange] {<img src="https://gemnasium.com/beatrichartz/exchange.png" alt="Dependency Status" />}[https://gemnasium.com/beatrichartz/exchange] {<img src="https://codeclimate.com/github/beatrichartz/exchange.png" />}[https://codeclimate.com/github/beatrichartz/exchange]
|
2
2
|
|
3
|
-
The Exchange Gem gives you easy access to currency functions directly on your Numbers. {It is tested against}[http://travis-ci.org/beatrichartz/exchange]: ruby 2.0, 1.9,
|
3
|
+
The Exchange Gem gives you easy access to currency functions directly on your Numbers. {It is tested against}[http://travis-ci.org/beatrichartz/exchange]: ruby 2.0, 1.9, ree and rubinius (1.9 and 2.0 mode). Exchange will in future versions take advantage of 2.1 features like refinements, be sure to check this page for updates!
|
4
4
|
|
5
5
|
You can use it with just plain ruby projects, in Rails 2 and 3, Sinatra or whatever Framework you like.
|
6
6
|
|
@@ -9,7 +9,7 @@ You can use it with just plain ruby projects, in Rails 2 and 3, Sinatra or whate
|
|
9
9
|
== Installation
|
10
10
|
=== Bundler / Rails
|
11
11
|
Add it to your Gemfile
|
12
|
-
gem "exchange", ">=
|
12
|
+
gem "exchange", ">= 1.1.0"
|
13
13
|
=== Manually
|
14
14
|
Just install it as a gem
|
15
15
|
gem install exchange
|
@@ -52,7 +52,7 @@ Exchange uses BigDecimal in all its currency and conversion operations, so you w
|
|
52
52
|
|
53
53
|
=== BigDecimal? Sounds slow to me
|
54
54
|
|
55
|
-
If performance combined with conversion is your concern,
|
55
|
+
If performance combined with conversion is your concern, don't worry. With ruby 1.9.3, you'll get about the following results for money instantiation (e.g. 1.in(:eur))
|
56
56
|
|
57
57
|
1000 operations
|
58
58
|
|
@@ -426,6 +426,6 @@ Please note that only open source APIs can be accepted as contributions to this
|
|
426
426
|
|
427
427
|
== Copyright
|
428
428
|
|
429
|
-
Copyright (c)
|
429
|
+
Copyright (c) 2013 Beat Richartz. See LICENSE.txt for
|
430
430
|
further details.
|
431
431
|
|
data/exchange.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.authors = ["Beat Richartz"]
|
9
9
|
s.description = "Simple Money handling for your ruby app – ISO4217-compatible Currency instantiation, conversion, string formatting and more via an intuitive DSL: 1.in(:usd).to(:eur)"
|
10
10
|
s.email = "attr_accessor@gmail.com"
|
11
|
-
s.homepage = "http://beatrichartz.github.
|
11
|
+
s.homepage = "http://beatrichartz.github.io/exchange"
|
12
12
|
s.licenses = ["MIT"]
|
13
13
|
s.require_paths = ["lib"]
|
14
14
|
s.summary = "Simple Money handling for your ruby app"
|
data/lib/exchange/base.rb
CHANGED
@@ -8,8 +8,8 @@ module Exchange
|
|
8
8
|
# Installs a method chain that overwrites the old error prone meth with the new one
|
9
9
|
#
|
10
10
|
def self.money_error_preventing_method_chain base, meth
|
11
|
-
base.send :alias_method, :"#{meth}
|
12
|
-
base.send :alias_method, meth, :"#{meth}
|
11
|
+
base.send :alias_method, :"#{meth}_with_errors", meth
|
12
|
+
base.send :alias_method, meth, :"#{meth}_without_errors"
|
13
13
|
end
|
14
14
|
|
15
15
|
# @!macro prevent_errors_with_exchange_for
|
@@ -18,11 +18,11 @@ module Exchange
|
|
18
18
|
# @method $1(other)
|
19
19
|
#
|
20
20
|
def self.prevent_errors_with_exchange_for base, meth
|
21
|
-
base.send(:define_method, :"#{meth}
|
21
|
+
base.send(:define_method, :"#{meth}_without_errors", lambda { |other|
|
22
22
|
if other.is_a?(Exchange::Money)
|
23
23
|
BigDecimal.new(self.to_s).send(meth, other.value).to_f
|
24
24
|
else
|
25
|
-
send(:"#{meth}
|
25
|
+
send(:"#{meth}_with_errors", other)
|
26
26
|
end
|
27
27
|
})
|
28
28
|
money_error_preventing_method_chain base, meth
|
data/lib/exchange/iso.rb
CHANGED
@@ -180,19 +180,35 @@ module Exchange
|
|
180
180
|
new_hsh
|
181
181
|
end
|
182
182
|
|
183
|
-
# Interpolates a string with separators every 3 characters
|
184
|
-
#
|
185
|
-
|
186
183
|
# get a precision for a specified amount and a specified currency
|
184
|
+
#
|
187
185
|
# @params [Float, Integer] amount The amount to get the precision for
|
188
186
|
# @params [Symbol] currency the currency to get the precision for
|
189
187
|
#
|
190
188
|
def precision_for amount, currency
|
191
189
|
defined_minor_precision = definitions[currency][:minor_unit]
|
192
|
-
|
190
|
+
match = amount.to_s.match(/^-?(\d*)\.?(\d*)e?(-?\d+)?$/).to_a[1..3]
|
191
|
+
given_major_precision, given_minor_precision = precision_from_match *match
|
193
192
|
|
194
193
|
given_major_precision + [defined_minor_precision, given_minor_precision].max
|
195
194
|
end
|
196
195
|
|
196
|
+
# Get the precision from a match with /^-?(\d*)\.?(\d*)e?(-?\d+)?$/
|
197
|
+
#
|
198
|
+
# @params [String] major The major amount of the match as a string
|
199
|
+
# @params [String] minor The minor amount of the match as a string
|
200
|
+
# @params [String] rational The rational of the match as a string
|
201
|
+
# @return [Array] An array containing the major and the minor precision in this order
|
202
|
+
#
|
203
|
+
def precision_from_match major, minor, rational=nil
|
204
|
+
if rational
|
205
|
+
leftover_minor_precision = minor.eql?('0') ? 0 : minor.size
|
206
|
+
rational_precision = rational.delete('-').to_i
|
207
|
+
[major.size, leftover_minor_precision.send(rational.start_with?('-') ? :+ : :-, rational_precision)]
|
208
|
+
else
|
209
|
+
[major, minor].map(&:size)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
197
213
|
end
|
198
214
|
end
|
data/lib/exchange/money.rb
CHANGED
@@ -86,7 +86,7 @@ module Exchange
|
|
86
86
|
def to other, options={}
|
87
87
|
other = ISO.assert_currency!(other)
|
88
88
|
|
89
|
-
if api_supports_currency?(
|
89
|
+
if api_supports_currency?(currency) && api_supports_currency?(other)
|
90
90
|
opts = { :at => time, :from => self }.merge(options)
|
91
91
|
Money.new(api.new.convert(value, currency, other, opts), other, opts)
|
92
92
|
elsif fallback!
|
@@ -6,7 +6,7 @@ describe "Exchange::Cache::Base" do
|
|
6
6
|
describe "key generation" do
|
7
7
|
before(:each) do
|
8
8
|
time = Time.gm 2012, 03, 01, 23, 23, 23
|
9
|
-
Time.stub
|
9
|
+
Time.stub :now => time
|
10
10
|
end
|
11
11
|
context "with a daily cache" do
|
12
12
|
it "should build a timestamped key with the class given, the yearday and the year" do
|
@@ -15,7 +15,7 @@ describe "Exchange::CacheDalli::Client" do
|
|
15
15
|
Exchange.configuration.reset
|
16
16
|
end
|
17
17
|
describe "client" do
|
18
|
-
let(:client) {
|
18
|
+
let(:client) { double('memcached') }
|
19
19
|
before(:each) do
|
20
20
|
Exchange::GemLoader.new('dalli').try_load
|
21
21
|
end
|
@@ -28,7 +28,7 @@ describe "Exchange::CacheDalli::Client" do
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
describe "wipe_client!" do
|
31
|
-
let(:client) {
|
31
|
+
let(:client) { double('memcached') }
|
32
32
|
|
33
33
|
it "should set the client to nil" do
|
34
34
|
Dalli::Client.should_receive(:new).with("HOST:PORT").and_return(client)
|
@@ -38,7 +38,7 @@ describe "Exchange::CacheDalli::Client" do
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
describe "cached" do
|
41
|
-
let(:client) {
|
41
|
+
let(:client) { double('memcached', :get => '') }
|
42
42
|
before(:each) do
|
43
43
|
Dalli::Client.should_receive(:new).with("HOST:PORT").and_return(client)
|
44
44
|
end
|
@@ -69,7 +69,7 @@ describe "Exchange::CacheDalli::Client" do
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
context "when no cached result exists" do
|
72
|
-
let(:client) {
|
72
|
+
let(:client) { double('memcached') }
|
73
73
|
context "when returning nil" do
|
74
74
|
before(:each) do
|
75
75
|
subject.should_receive(:key).with('API_CLASS', {}).twice.and_return('KEY')
|
@@ -15,7 +15,7 @@ describe "Exchange::Cache::Memory" do
|
|
15
15
|
context "with a class" do
|
16
16
|
before(:each) do
|
17
17
|
@time = Time.gm(2012,10,10,12)
|
18
|
-
Time.stub
|
18
|
+
Time.stub :now => @time
|
19
19
|
end
|
20
20
|
it "should yield a valid instance variable name" do
|
21
21
|
subject.send(:instance_variable_name, Exchange::ExternalAPI::Ecb, {}).should == '@exchange_externalapi_ecb_2012_284_2012_284'
|
@@ -25,7 +25,7 @@ describe "Exchange::Cache::Memory" do
|
|
25
25
|
describe "clean_out_cache" do
|
26
26
|
before(:each) do
|
27
27
|
@time = Time.gm(2012,10,10,12)
|
28
|
-
Time.stub
|
28
|
+
Time.stub :now => @time
|
29
29
|
subject.instance_variable_set '@exchange_externalapi_someapi_2011_284_2011_284_chfeur', 'Expired'
|
30
30
|
subject.instance_variable_set '@exchange_externalapi_someapi_2010_284_2012_284_chfeur', 'Valid1'
|
31
31
|
subject.instance_variable_set '@exchange_externalapi_ecb_2012_283_2011_283', 'Expired'
|
@@ -18,7 +18,7 @@ describe "Exchange::Cache::Rails" do
|
|
18
18
|
Exchange.configuration.reset
|
19
19
|
end
|
20
20
|
describe "client" do
|
21
|
-
let(:client) {
|
21
|
+
let(:client) { double('rails_cache') }
|
22
22
|
it "should set up a client on the specified host and port for the cache" do
|
23
23
|
::Rails.should_receive(:cache).and_return(client)
|
24
24
|
subject.client.should == client
|
@@ -29,7 +29,7 @@ describe "Exchange::Cache::Rails" do
|
|
29
29
|
lambda { subject.cached('API_CLASS') }.should raise_error(Exchange::Cache::CachingWithoutBlockError)
|
30
30
|
end
|
31
31
|
context "when a result is returned" do
|
32
|
-
let(:client) {
|
32
|
+
let(:client) { double('rails_cache') }
|
33
33
|
context "with a daily cache" do
|
34
34
|
before(:each) do
|
35
35
|
subject.should_receive(:key).with('API_CLASS', {}).and_return('KEY')
|
@@ -56,7 +56,7 @@ describe "Exchange::Cache::Rails" do
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
context "when no result is returned" do
|
59
|
-
let(:client) {
|
59
|
+
let(:client) { double('rails_cache') }
|
60
60
|
before(:each) do
|
61
61
|
subject.should_receive(:key).with('API_CLASS', {}).at_most(3).times.and_return('KEY')
|
62
62
|
::Rails.should_receive(:cache).twice.and_return(client)
|
@@ -17,7 +17,7 @@ describe "Exchange::Cache::Redis" do
|
|
17
17
|
Exchange.configuration.reset
|
18
18
|
end
|
19
19
|
describe "client" do
|
20
|
-
let(:client) {
|
20
|
+
let(:client) { double('redis') }
|
21
21
|
after(:each) do
|
22
22
|
subject.instance_variable_set "@client", nil
|
23
23
|
end
|
@@ -27,7 +27,7 @@ describe "Exchange::Cache::Redis" do
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
describe "cached" do
|
30
|
-
let(:client) {
|
30
|
+
let(:client) { double('redis', :get => nil) }
|
31
31
|
before(:each) do
|
32
32
|
::Redis.should_receive(:new).with(:host => 'HOST', :port => 'PORT').and_return(client)
|
33
33
|
end
|
@@ -27,7 +27,7 @@ describe "Exchange::ExternalAPI::Call" do
|
|
27
27
|
@count = 0
|
28
28
|
@uri_mock.should_receive(:open).at_most(3).times.and_return do
|
29
29
|
@count += 1
|
30
|
-
@count == 3 ?
|
30
|
+
@count == 3 ? double('opened', :read => fixture('api_responses/example_json_api.json')) : raise(OpenURI::HTTPError.new('404', 'URI'))
|
31
31
|
end
|
32
32
|
Exchange::ExternalAPI::Call.new('JSON_API') do |result|
|
33
33
|
result.should == JSON.load(fixture('api_responses/example_json_api.json'))
|
@@ -62,7 +62,7 @@ describe "Exchange::ExternalAPI::Call" do
|
|
62
62
|
@count = 0
|
63
63
|
@uri_mock.should_receive(:open).at_most(3).times.and_return do
|
64
64
|
@count += 1
|
65
|
-
@count == 3 ?
|
65
|
+
@count == 3 ? double('opened', :read => fixture('api_responses/example_xml_api.xml')) : raise(OpenURI::HTTPError.new('404', 'URI'))
|
66
66
|
end
|
67
67
|
Exchange::ExternalAPI::Call.new('XML_API', :format => :xml) do |result|
|
68
68
|
result.to_s.should == Nokogiri::XML.parse(fixture('api_responses/example_xml_api.xml').sub("\n", '')).to_s
|
data/spec/exchange/iso_spec.rb
CHANGED
@@ -737,6 +737,32 @@ describe "Exchange::ISO" do
|
|
737
737
|
end
|
738
738
|
end
|
739
739
|
end
|
740
|
+
context "given a float with scientific notation" do
|
741
|
+
context "with bigger precision than the definition" do
|
742
|
+
it "should instantiate a big decimal with the given precision" do
|
743
|
+
BigDecimal.should_receive(:new).with("6.0e-05",6).and_return('INSTANCE')
|
744
|
+
subject.instantiate(6.0e-05, :tnd).should == 'INSTANCE'
|
745
|
+
BigDecimal.should_receive(:new).with("600000.0",8).and_return('INSTANCE')
|
746
|
+
subject.instantiate(6.0e05, :sar).should == 'INSTANCE'
|
747
|
+
BigDecimal.should_receive(:new).with("1.456e-08",12).and_return('INSTANCE')
|
748
|
+
subject.instantiate(1.456e-08, :omr).should == 'INSTANCE'
|
749
|
+
BigDecimal.should_receive(:new).with("145600000.0",12).and_return('INSTANCE')
|
750
|
+
subject.instantiate(1.456e08, :omr).should == 'INSTANCE'
|
751
|
+
end
|
752
|
+
end
|
753
|
+
context "with smaller precision than the definition" do
|
754
|
+
it "should instantiate a big decimal with the defined precision" do
|
755
|
+
BigDecimal.should_receive(:new).with("0.6",4).and_return('INSTANCE')
|
756
|
+
subject.instantiate(6.0e-01, :tnd).should == 'INSTANCE'
|
757
|
+
BigDecimal.should_receive(:new).with("60.0",4).and_return('INSTANCE')
|
758
|
+
subject.instantiate(6.0e01, :sar).should == 'INSTANCE'
|
759
|
+
BigDecimal.should_receive(:new).with("0.14",4).and_return('INSTANCE')
|
760
|
+
subject.instantiate(1.4e-01, :omr).should == 'INSTANCE'
|
761
|
+
BigDecimal.should_receive(:new).with("14.56",5).and_return('INSTANCE')
|
762
|
+
subject.instantiate(1.456e01, :omr).should == 'INSTANCE'
|
763
|
+
end
|
764
|
+
end
|
765
|
+
end
|
740
766
|
context "given a big decimal" do
|
741
767
|
let!(:bigdecimal) { BigDecimal.new("23.23") }
|
742
768
|
it "should instantiate a big decimal according to the iso standards" do
|
data/spec/exchange/money_spec.rb
CHANGED
@@ -92,7 +92,7 @@ describe "Exchange::Money" do
|
|
92
92
|
context "with a 'to' currency not provided by the given api" do
|
93
93
|
context "but provided by a fallback api" do
|
94
94
|
it "should use the fallback" do
|
95
|
-
subject.api::CURRENCIES.stub
|
95
|
+
subject.api::CURRENCIES.stub :include? => false
|
96
96
|
mock_api("http://api.finance.xaviermedia.com/api/#{Time.now.strftime("%Y/%m/%d")}.xml", fixture('api_responses/example_xml_api.xml'), 3)
|
97
97
|
subject.to(:chf).value.round(2).should == 36.36
|
98
98
|
subject.to(:chf).currency.should == :chf
|
@@ -101,9 +101,9 @@ describe "Exchange::Money" do
|
|
101
101
|
end
|
102
102
|
context "but not provided by any fallback api" do
|
103
103
|
it "should raise the no rate error" do
|
104
|
-
Exchange::ExternalAPI::OpenExchangeRates::CURRENCIES.stub
|
105
|
-
Exchange::ExternalAPI::XavierMedia::CURRENCIES.stub
|
106
|
-
Exchange::ExternalAPI::Ecb::CURRENCIES.stub
|
104
|
+
Exchange::ExternalAPI::OpenExchangeRates::CURRENCIES.stub :include? => false
|
105
|
+
Exchange::ExternalAPI::XavierMedia::CURRENCIES.stub :include? => false
|
106
|
+
Exchange::ExternalAPI::Ecb::CURRENCIES.stub :include? => false
|
107
107
|
lambda { subject.to(:xaf) }.should raise_error Exchange::NoRateError
|
108
108
|
end
|
109
109
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -21,7 +21,7 @@ module HelperMethods
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def mock_api(adress, response, count=1)
|
24
|
-
@uri_mock =
|
24
|
+
@uri_mock = double('uri', :open => double('opened_uri', :read => response))
|
25
25
|
URI.should_receive(:parse).with(adress).at_most(count).times.and_return(@uri_mock)
|
26
26
|
end
|
27
27
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: exchange
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Beat Richartz
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-11-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -155,7 +155,7 @@ files:
|
|
155
155
|
- spec/support/api_responses/example_historic_json.json
|
156
156
|
- spec/support/api_responses/example_json_api.json
|
157
157
|
- spec/support/api_responses/example_xml_api.xml
|
158
|
-
homepage: http://beatrichartz.github.
|
158
|
+
homepage: http://beatrichartz.github.io/exchange
|
159
159
|
licenses:
|
160
160
|
- MIT
|
161
161
|
metadata: {}
|
@@ -175,7 +175,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
175
175
|
version: '0'
|
176
176
|
requirements: []
|
177
177
|
rubyforge_project:
|
178
|
-
rubygems_version: 2.0.
|
178
|
+
rubygems_version: 2.0.7
|
179
179
|
signing_key:
|
180
180
|
specification_version: 4
|
181
181
|
summary: Simple Money handling for your ruby app
|