danconia 0.2.9 → 0.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +104 -0
- data/Gemfile.lock +25 -2
- data/README.md +16 -2
- data/danconia.gemspec +5 -1
- data/examples/bna.rb +35 -0
- data/examples/currency_layer.rb +7 -2
- data/examples/single_currency.rb +3 -2
- data/lib/danconia.rb +6 -4
- data/lib/danconia/currency.rb +2 -2
- data/lib/danconia/exchange.rb +47 -0
- data/lib/danconia/exchanges/bna.rb +61 -0
- data/lib/danconia/exchanges/currency_layer.rb +14 -2
- data/lib/danconia/exchanges/fixed_rates.rb +2 -4
- data/lib/danconia/integrations/active_record.rb +13 -14
- data/lib/danconia/money.rb +25 -18
- data/lib/danconia/stores/active_record.rb +31 -4
- data/lib/danconia/stores/in_memory.rb +6 -7
- data/lib/danconia/version.rb +1 -1
- data/spec/danconia/exchanges/bna_spec.rb +36 -0
- data/spec/danconia/exchanges/currency_layer_spec.rb +26 -18
- data/spec/danconia/exchanges/exchange_spec.rb +15 -3
- data/spec/danconia/exchanges/fixtures/bna/home.html +124 -0
- data/spec/danconia/integrations/active_record_spec.rb +25 -5
- data/spec/danconia/money_spec.rb +41 -11
- data/spec/danconia/stores/active_record_spec.rb +79 -13
- data/spec/danconia/stores/in_memory_spec.rb +18 -0
- data/spec/spec_helper.rb +2 -1
- metadata +57 -6
- data/lib/danconia/exchanges/exchange.rb +0 -47
@@ -1,12 +1,10 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
1
|
module Danconia
|
4
2
|
describe Integrations::ActiveRecord, active_record: true do
|
5
3
|
context 'single currency' do
|
6
4
|
it 'setter' do
|
7
|
-
expect(Product.new(price: 1.536).read_attribute
|
8
|
-
expect(Product.new(price: nil).read_attribute
|
9
|
-
expect(Product.new(price: Money(3)).read_attribute
|
5
|
+
expect(Product.new(price: 1.536).read_attribute(:price)).to eq 1.54
|
6
|
+
expect(Product.new(price: nil).read_attribute(:price)).to eq nil
|
7
|
+
expect(Product.new(price: Money(3)).read_attribute(:price)).to eq 3
|
10
8
|
end
|
11
9
|
|
12
10
|
it 'getter' do
|
@@ -34,6 +32,28 @@ module Danconia
|
|
34
32
|
end
|
35
33
|
end
|
36
34
|
|
35
|
+
context 'exchange options support' do
|
36
|
+
let(:exchange) do
|
37
|
+
Class.new(Exchange) do
|
38
|
+
def rates rate_type:
|
39
|
+
case rate_type
|
40
|
+
when 'divisa' then {'USDARS' => 7}
|
41
|
+
when 'billete' then {'USDARS' => 8}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end.new
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'allows to specify options that will be pass to the exchange when exchanging to other currencies' do
|
48
|
+
klass = Class.new(ActiveRecord::Base) do
|
49
|
+
self.table_name = 'products'
|
50
|
+
money :price, rate_type: 'divisa'
|
51
|
+
end
|
52
|
+
|
53
|
+
expect(klass.new(price: Money(10, 'USD')).price.exchange_to('ARS', exchange: exchange)).to eq Money(70, 'ARS')
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
37
57
|
class Product < ActiveRecord::Base
|
38
58
|
money :price, :tax, :discount, :cost
|
39
59
|
end
|
data/spec/danconia/money_spec.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
1
|
module Danconia
|
4
2
|
describe Money do
|
5
3
|
context 'instantiation' do
|
@@ -39,16 +37,15 @@ module Danconia
|
|
39
37
|
end
|
40
38
|
|
41
39
|
it 'should exchange the other currency if it is different' do
|
42
|
-
|
40
|
+
m1 = Money(1, 'ARS', exchange_opts: {exchange: fake_exchange(rate: 4)})
|
41
|
+
expect(m1 + Money(1, 'USD')).to eq Money(5, 'ARS')
|
43
42
|
end
|
44
43
|
|
45
44
|
it 'should return a new object with the same options' do
|
46
|
-
|
47
|
-
m1 = Money(4, decimals: 3, exchange: e)
|
45
|
+
m1 = Money(4, decimals: 3)
|
48
46
|
m2 = m1 * 2
|
49
47
|
expect(m2).to_not eql m1
|
50
48
|
expect(m2.decimals).to eq 3
|
51
|
-
expect(m2.exchange).to eq e
|
52
49
|
end
|
53
50
|
|
54
51
|
it 'round should return a money object with the same currency' do
|
@@ -72,7 +69,7 @@ module Danconia
|
|
72
69
|
end
|
73
70
|
|
74
71
|
it 'should exchange to the source currency if they differ' do
|
75
|
-
TestHelpers.with_rates 'USDARS' => 4 do |
|
72
|
+
TestHelpers.with_rates 'USDARS' => 4 do |_config|
|
76
73
|
expect(Money(3, 'ARS') < Money(1, 'USD')).to be true
|
77
74
|
expect(Money(4, 'ARS') < Money(1, 'USD')).to be false
|
78
75
|
end
|
@@ -129,7 +126,8 @@ module Danconia
|
|
129
126
|
end
|
130
127
|
|
131
128
|
it 'should allow to pass the exchange to the instance' do
|
132
|
-
|
129
|
+
m = Money(2, 'USD', exchange_opts: {exchange: fake_exchange(rate: 3)})
|
130
|
+
expect(m.exchange_to('ARS')).to eq Money(6, 'ARS')
|
133
131
|
end
|
134
132
|
|
135
133
|
it 'should allow to pass the exchange when converting' do
|
@@ -153,8 +151,8 @@ module Danconia
|
|
153
151
|
end
|
154
152
|
|
155
153
|
it 'should return a new object with the same opts' do
|
156
|
-
m1 = Money(1, 'USD', decimals: 0
|
157
|
-
m2 = m1.exchange_to('ARS')
|
154
|
+
m1 = Money(1, 'USD', decimals: 0)
|
155
|
+
m2 = m1.exchange_to('ARS', exchange: fake_exchange(rate: 3))
|
158
156
|
expect(m2).to_not eql m1
|
159
157
|
expect(m2.decimals).to eq 0
|
160
158
|
expect(m1).to eq Money(1, 'USD')
|
@@ -164,6 +162,38 @@ module Danconia
|
|
164
162
|
expect(Money(1, 'USD').exchange_to('')).to eq Money(1, 'USD')
|
165
163
|
expect(Money(1, 'ARS').exchange_to('')).to eq Money(1, 'ARS')
|
166
164
|
end
|
165
|
+
|
166
|
+
context 'opts' do
|
167
|
+
let(:exchange) do
|
168
|
+
Class.new(Exchange) do
|
169
|
+
def rates opts
|
170
|
+
case opts[:type]
|
171
|
+
when 'divisa' then {'USDARS' => 7}
|
172
|
+
when 'billete' then {'USDARS' => 8}
|
173
|
+
else {}
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end.new
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'allows to specify opts to pass to the exchange (filters for example)' do
|
180
|
+
expect(Money(1, 'USD').exchange_to('ARS', type: 'divisa', exchange: exchange)).to eq Money(7, 'ARS')
|
181
|
+
expect { Money(1, 'USD').exchange_to('ARS', exchange: exchange) }.to raise_error Errors::ExchangeRateNotFound
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'should be preserved after operations' do
|
185
|
+
m1 = Money(1, 'USD').exchange_to('ARS', type: 'divisa', exchange: exchange)
|
186
|
+
m2 = m1 + Money(2, 'USD')
|
187
|
+
|
188
|
+
expect(m2).to eq Money(21, 'ARS')
|
189
|
+
expect(m1 < Money(2, 'USD')).to eq true
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'should use the instance exchange_opts by default' do
|
193
|
+
m = Money(1, 'USD', exchange_opts: {exchange: exchange, type: 'billete'})
|
194
|
+
expect(m.exchange_to('ARS')).to eq Money(8, 'ARS')
|
195
|
+
end
|
196
|
+
end
|
167
197
|
end
|
168
198
|
|
169
199
|
context 'default_currency?' do
|
@@ -190,7 +220,7 @@ module Danconia
|
|
190
220
|
end
|
191
221
|
|
192
222
|
def fake_exchange args = {}
|
193
|
-
double 'Danconia::
|
223
|
+
double 'Danconia::Exchange', args.reverse_merge(rate: nil)
|
194
224
|
end
|
195
225
|
end
|
196
226
|
end
|
@@ -1,31 +1,97 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
1
|
module Danconia
|
4
2
|
module Stores
|
5
3
|
describe ActiveRecord, active_record: true do
|
4
|
+
before do
|
5
|
+
::ActiveRecord::Schema.define do
|
6
|
+
create_table :exchange_rates do |t|
|
7
|
+
t.string :pair, limit: 6
|
8
|
+
t.decimal :rate, precision: 12, scale: 6
|
9
|
+
t.string :rate_type
|
10
|
+
t.date :date
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
6
15
|
context 'save_rates' do
|
7
16
|
it 'should create or update the rates' do
|
8
17
|
ExchangeRate.create! pair: 'USDEUR', rate: 2
|
9
|
-
|
10
|
-
expect
|
18
|
+
|
19
|
+
expect do
|
20
|
+
subject.save_rates [{pair: 'USDEUR', rate: 3}, {pair: 'USDARS', rate: 4}]
|
21
|
+
end.to change { ExchangeRate.count }.by 1
|
22
|
+
|
23
|
+
expect(subject.rates).to match [
|
24
|
+
include(pair: 'USDEUR', rate: 3),
|
25
|
+
include(pair: 'USDARS', rate: 4)
|
26
|
+
]
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'allows to specify other keys to use as unique' do
|
30
|
+
store = ActiveRecord.new(unique_keys: %i[pair rate_type])
|
31
|
+
store.save_rates [
|
32
|
+
{pair: 'USDARS', rate: 3, rate_type: 'billetes'},
|
33
|
+
{pair: 'USDARS', rate: 4, rate_type: 'divisas'}
|
34
|
+
]
|
35
|
+
store.save_rates [
|
36
|
+
{pair: 'USDARS', rate: 33, rate_type: 'billetes'}
|
37
|
+
]
|
38
|
+
expect(subject.rates).to match [
|
39
|
+
include(pair: 'USDARS', rate: 33, rate_type: 'billetes'),
|
40
|
+
include(pair: 'USDARS', rate: 4, rate_type: 'divisas')
|
41
|
+
]
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'ignores fields not present in the database table' do
|
45
|
+
subject.save_rates [{pair: 'USDEUR', rate: 3, non_existant: 'ignoreme'}]
|
11
46
|
end
|
12
47
|
end
|
13
48
|
|
14
49
|
context 'rates' do
|
15
|
-
it 'returns
|
50
|
+
it 'returns an array like the one it received' do
|
16
51
|
ExchangeRate.create! pair: 'USDEUR', rate: 2
|
17
52
|
ExchangeRate.create! pair: 'USDARS', rate: 40
|
18
|
-
|
53
|
+
|
54
|
+
expect(subject.rates).to match [
|
55
|
+
include(pair: 'USDEUR', rate: 2),
|
56
|
+
include(pair: 'USDARS', rate: 40)
|
57
|
+
]
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'allows to pass filters' do
|
61
|
+
store = ActiveRecord.new(unique_keys: %i[pair date])
|
62
|
+
store.save_rates [
|
63
|
+
{pair: 'USDEUR', rate: 10, date: Date.new(2020, 1, 1)},
|
64
|
+
{pair: 'USDEUR', rate: 20, date: Date.new(2020, 1, 2)},
|
65
|
+
{pair: 'USDEUR', rate: 30, date: Date.new(2020, 1, 3)}
|
66
|
+
]
|
67
|
+
|
68
|
+
expect(store.rates.size).to eq 3
|
69
|
+
expect(store.rates(date: Date.new(2020, 1, 2))).to match [include(rate: 20)]
|
19
70
|
end
|
20
71
|
end
|
21
72
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
73
|
+
context 'special date field' do
|
74
|
+
let(:store) do
|
75
|
+
store = ActiveRecord.new(unique_keys: %i[pair date], date_field: :date)
|
76
|
+
store.save_rates [
|
77
|
+
{pair: 'USDEUR', rate: 10, date: Date.new(2000, 1, 1)},
|
78
|
+
{pair: 'USDEUR', rate: 20, date: Date.new(2000, 1, 2)},
|
79
|
+
{pair: 'USDEUR', rate: 30, date: Date.new(2000, 1, 4)}
|
80
|
+
]
|
81
|
+
store
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'calling #rates with a particular date when there are rates for that date' do
|
85
|
+
expect(store.rates(date: Date.new(2000, 1, 2))).to match [include(rate: 20)]
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'calling #rates with a particular date when there are not rates for that date should return the previous' do
|
89
|
+
expect(store.rates(date: Date.new(2000, 1, 3))).to match [include(rate: 20)]
|
90
|
+
expect(store.rates(date: Date.new(1999, 12, 31))).to eq []
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'calling #rates without a particular date, uses today' do
|
94
|
+
expect(store.rates).to match [include(rate: 30)]
|
29
95
|
end
|
30
96
|
end
|
31
97
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Danconia
|
2
|
+
module Stores
|
3
|
+
describe InMemory do
|
4
|
+
context 'rates' do
|
5
|
+
it 'filters rates by type' do
|
6
|
+
subject.save_rates [
|
7
|
+
{pair: 'USDARS', rate: 3, rate_type: 'divisas'},
|
8
|
+
{pair: 'USDARS', rate: 4, rate_type: 'billetes'}
|
9
|
+
]
|
10
|
+
|
11
|
+
expect(subject.rates(rate_type: 'divisas')).to match [include(rate: 3)]
|
12
|
+
expect(subject.rates(rate_type: 'billetes')).to match [include(rate: 4)]
|
13
|
+
expect(subject.rates).to match [include(rate: 3), include(rate: 4)]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
require 'danconia'
|
2
2
|
require 'danconia/test_helpers'
|
3
|
+
require 'danconia/integrations/active_record'
|
3
4
|
require 'webmock/rspec'
|
4
5
|
|
5
|
-
Dir["#{__dir__}/support/*.rb"].each { |f| require f }
|
6
|
+
Dir["#{__dir__}/support/*.rb"].sort.each { |f| require f }
|
6
7
|
|
7
8
|
RSpec.configure do |config|
|
8
9
|
config.filter_run_when_matching :focus
|
metadata
CHANGED
@@ -1,29 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: danconia
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Emmanuel Nicolau
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-09-
|
11
|
+
date: 2020-09-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: activesupport
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: '4.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: '4.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activerecord
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '4.0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: sqlite3
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,6 +122,34 @@ dependencies:
|
|
108
122
|
- - ">="
|
109
123
|
- !ruby/object:Gem::Version
|
110
124
|
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: nokogiri
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rubocop
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: 0.80.0
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 0.80.0
|
111
153
|
description: Multi-currency money library backed by BigDecimal
|
112
154
|
email: emmanicolau@gmail.com
|
113
155
|
executables:
|
@@ -117,6 +159,7 @@ extra_rdoc_files: []
|
|
117
159
|
files:
|
118
160
|
- ".gitignore"
|
119
161
|
- ".rspec"
|
162
|
+
- ".rubocop.yml"
|
120
163
|
- ".ruby-version"
|
121
164
|
- ".travis.yml"
|
122
165
|
- Gemfile
|
@@ -127,6 +170,7 @@ files:
|
|
127
170
|
- Rakefile
|
128
171
|
- bin/console
|
129
172
|
- danconia.gemspec
|
173
|
+
- examples/bna.rb
|
130
174
|
- examples/currency_layer.rb
|
131
175
|
- examples/fixed_rates.rb
|
132
176
|
- examples/single_currency.rb
|
@@ -135,8 +179,9 @@ files:
|
|
135
179
|
- lib/danconia/currency.rb
|
136
180
|
- lib/danconia/errors/api_error.rb
|
137
181
|
- lib/danconia/errors/exchange_rate_not_found.rb
|
182
|
+
- lib/danconia/exchange.rb
|
183
|
+
- lib/danconia/exchanges/bna.rb
|
138
184
|
- lib/danconia/exchanges/currency_layer.rb
|
139
|
-
- lib/danconia/exchanges/exchange.rb
|
140
185
|
- lib/danconia/exchanges/fixed_rates.rb
|
141
186
|
- lib/danconia/integrations/active_record.rb
|
142
187
|
- lib/danconia/kernel.rb
|
@@ -146,13 +191,16 @@ files:
|
|
146
191
|
- lib/danconia/stores/in_memory.rb
|
147
192
|
- lib/danconia/test_helpers.rb
|
148
193
|
- lib/danconia/version.rb
|
194
|
+
- spec/danconia/exchanges/bna_spec.rb
|
149
195
|
- spec/danconia/exchanges/currency_layer_spec.rb
|
150
196
|
- spec/danconia/exchanges/exchange_spec.rb
|
197
|
+
- spec/danconia/exchanges/fixtures/bna/home.html
|
151
198
|
- spec/danconia/exchanges/fixtures/currency_layer/failure.json
|
152
199
|
- spec/danconia/exchanges/fixtures/currency_layer/success.json
|
153
200
|
- spec/danconia/integrations/active_record_spec.rb
|
154
201
|
- spec/danconia/money_spec.rb
|
155
202
|
- spec/danconia/stores/active_record_spec.rb
|
203
|
+
- spec/danconia/stores/in_memory_spec.rb
|
156
204
|
- spec/spec_helper.rb
|
157
205
|
- spec/support/database.rb
|
158
206
|
homepage: https://github.com/eeng/danconia
|
@@ -180,12 +228,15 @@ signing_key:
|
|
180
228
|
specification_version: 4
|
181
229
|
summary: Multi-currency money library backed by BigDecimal
|
182
230
|
test_files:
|
231
|
+
- spec/danconia/exchanges/bna_spec.rb
|
183
232
|
- spec/danconia/exchanges/currency_layer_spec.rb
|
184
233
|
- spec/danconia/exchanges/exchange_spec.rb
|
234
|
+
- spec/danconia/exchanges/fixtures/bna/home.html
|
185
235
|
- spec/danconia/exchanges/fixtures/currency_layer/failure.json
|
186
236
|
- spec/danconia/exchanges/fixtures/currency_layer/success.json
|
187
237
|
- spec/danconia/integrations/active_record_spec.rb
|
188
238
|
- spec/danconia/money_spec.rb
|
189
239
|
- spec/danconia/stores/active_record_spec.rb
|
240
|
+
- spec/danconia/stores/in_memory_spec.rb
|
190
241
|
- spec/spec_helper.rb
|
191
242
|
- spec/support/database.rb
|
@@ -1,47 +0,0 @@
|
|
1
|
-
require 'danconia/pair'
|
2
|
-
|
3
|
-
module Danconia
|
4
|
-
module Exchanges
|
5
|
-
class Exchange
|
6
|
-
attr_reader :store
|
7
|
-
|
8
|
-
def initialize store: Stores::InMemory.new
|
9
|
-
@store = store
|
10
|
-
end
|
11
|
-
|
12
|
-
def rate from, to
|
13
|
-
return 1.0 if from == to
|
14
|
-
|
15
|
-
pair = Pair.new(from, to)
|
16
|
-
rates = direct_and_inverted_rates()
|
17
|
-
rates[pair] or indirect_rate(pair, rates) or raise Errors::ExchangeRateNotFound.new(from, to)
|
18
|
-
end
|
19
|
-
|
20
|
-
def rates
|
21
|
-
@store.rates
|
22
|
-
end
|
23
|
-
|
24
|
-
def update_rates!
|
25
|
-
@store.save_rates fetch_rates
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
# Returns the original rates plus the inverted ones, to simplify rate finding logic.
|
31
|
-
def direct_and_inverted_rates
|
32
|
-
rates.each_with_object({}) do |(pair_str, rate), rs|
|
33
|
-
pair = Pair.parse(pair_str)
|
34
|
-
rs[pair] = rate
|
35
|
-
rs[pair.invert] ||= 1.0 / rate
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def indirect_rate ind_pair, rates
|
40
|
-
if (from_pair = rates.keys.detect { |(pair, rate)| pair.from == ind_pair.from }) &&
|
41
|
-
(to_pair = rates.keys.detect { |(pair, rate)| pair.to == ind_pair.to })
|
42
|
-
rates[from_pair] * rates[to_pair]
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|