eu_central_bank 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 739f04adc1c5623cc7b81bc647aedfda0bdd3d32
4
- data.tar.gz: e1856709ab6f5705100d21dda36e52a4a8f3e29d
3
+ metadata.gz: 4dbcc0a2aa33d3b41142677ca45615eeb9345633
4
+ data.tar.gz: cc9c0d602fcdbb84f904964cd3c6a5cd5d5bd0b4
5
5
  SHA512:
6
- metadata.gz: 367913b58f6e98eddd33adfd0b96887b2cbf794911b13c67289edfd2ccf3ce3f4de18f2716cc05fcb14d828cde3f64314097112c1d57d2c89312c8129a2d2eab
7
- data.tar.gz: 7c80e5bc1125fe13c2ca57146a780e73c6610df90430973307503bc44e852193a5b44a5655f1850dd30a396b91976ed2ada68753e66bfe0aeb696b2a4d261b25
6
+ metadata.gz: 096495025aa42d1e675990694465f4980a00e81622efa05d93ffc6d8b24fb24beb8b9f2db9a6aaed295bc4f9a741b5842d1761a72eb41dc1ab95275670c1bc0a
7
+ data.tar.gz: 2d484be4e3aa08ac418a0d2f7d0c7f3a51fa126a8269c49057df19906a237437ed2aea27641c8cb9fc2e28180eae597d732c50a1353f6b28eb98c70848b83bc3
data/CHANGELOG.md CHANGED
@@ -1,10 +1,13 @@
1
1
  # eu_central_bank changelog
2
2
 
3
- ## 1.0.0
3
+ ## 1.0.1 (May 20 2016)
4
+
5
+ * Fixed compatibility with recent Money gem
6
+
7
+ ## 1.0.0 (Jan 15 2016)
4
8
 
5
9
  * Update to Money 6.7.0
6
10
  * Not Support for LTL
7
- * Update money version
8
11
  * Fix a couple of Ruby warnings found in specs
9
12
 
10
13
  ## 0.3.8 (Feb 12 2014)
@@ -1,6 +1,7 @@
1
1
  require 'open-uri'
2
2
  require 'nokogiri'
3
3
  require 'money'
4
+ require 'money/rates_store/eu_central_bank_historical_data_support'
4
5
 
5
6
  class InvalidCache < StandardError ; end
6
7
 
@@ -11,10 +12,17 @@ class EuCentralBank < Money::Bank::VariableExchange
11
12
  attr_accessor :historical_last_updated
12
13
  attr_accessor :historical_rates_updated_at
13
14
 
15
+ SERIALIZER_DATE_SEPARATOR = '_AT_'
16
+
14
17
  CURRENCIES = %w(USD JPY BGN CZK DKK GBP HUF ILS PLN RON SEK CHF NOK HRK RUB TRY AUD BRL CAD CNY HKD IDR INR KRW MXN MYR NZD PHP SGD THB ZAR).map(&:freeze).freeze
15
18
  ECB_RATES_URL = 'http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml'.freeze
16
19
  ECB_90_DAY_URL = 'http://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist-90d.xml'.freeze
17
20
 
21
+ def initialize(*)
22
+ super
23
+ @store.extend Money::RatesStore::EuCentralBankHistoricalDataSupport
24
+ end
25
+
18
26
  def update_rates(cache=nil)
19
27
  update_parsed_rates(doc(cache))
20
28
  end
@@ -45,13 +53,12 @@ class EuCentralBank < Money::Bank::VariableExchange
45
53
 
46
54
  def exchange_with(from, to_currency, date=nil)
47
55
  from_base_rate, to_base_rate = nil, nil
48
- rate = get_rate(from, to_currency, {:date => date})
56
+ rate = get_rate(from.currency, to_currency, date)
49
57
 
50
58
  unless rate
51
- @mutex.synchronize do
52
- opts = { :date => date, :without_mutex => true }
53
- from_base_rate = get_rate("EUR", from.currency.to_s, opts)
54
- to_base_rate = get_rate("EUR", to_currency, opts)
59
+ store.transaction true do
60
+ from_base_rate = get_rate("EUR", from.currency.to_s, date)
61
+ to_base_rate = get_rate("EUR", to_currency, date)
55
62
  end
56
63
  rate = to_base_rate / from_base_rate
57
64
  end
@@ -59,26 +66,76 @@ class EuCentralBank < Money::Bank::VariableExchange
59
66
  calculate_exchange(from, to_currency, rate)
60
67
  end
61
68
 
62
- def get_rate(from, to, opts = {})
63
- fn = -> { @rates[rate_key_for(from, to, opts)] }
69
+ def get_rate(from, to, date = nil)
70
+ if date.is_a?(Hash)
71
+ # Backwards compatibility for the opts hash
72
+ date = date[:date]
73
+ end
74
+ store.get_rate(::Money::Currency.wrap(from).iso_code, ::Money::Currency.wrap(to).iso_code, date)
75
+ end
64
76
 
65
- if opts[:without_mutex]
66
- fn.call
67
- else
68
- @mutex.synchronize { fn.call }
77
+ def set_rate(from, to, rate, date = nil)
78
+ if date.is_a?(Hash)
79
+ # Backwards compatibility for the opts hash
80
+ date = date[:date]
69
81
  end
82
+ store.add_rate(::Money::Currency.wrap(from).iso_code, ::Money::Currency.wrap(to).iso_code, rate, date)
70
83
  end
71
84
 
72
- def set_rate(from, to, rate, opts = {})
73
- fn = -> { @rates[rate_key_for(from, to, opts)] = rate }
85
+ def rates
86
+ store.each_rate.each_with_object({}) do |(from,to,rate,date),hash|
87
+ key = [from, to].join(SERIALIZER_SEPARATOR)
88
+ key = [key, date.to_s].join(SERIALIZER_DATE_SEPARATOR) if date
89
+ hash[key] = rate
90
+ end
91
+ end
92
+
93
+ def export_rates(format, file = nil, opts = {})
94
+ raise Money::Bank::UnknownRateFormat unless
95
+ RATE_FORMATS.include? format
96
+
97
+ store.transaction true do
98
+ s = case format
99
+ when :json
100
+ JSON.dump(rates)
101
+ when :ruby
102
+ Marshal.dump(rates)
103
+ when :yaml
104
+ YAML.dump(rates)
105
+ end
106
+
107
+ unless file.nil?
108
+ File.open(file, "w") {|f| f.write(s) }
109
+ end
74
110
 
75
- if opts[:without_mutex]
76
- fn.call
77
- else
78
- @mutex.synchronize { fn.call }
111
+ s
79
112
  end
80
113
  end
81
114
 
115
+ def import_rates(format, s, opts = {})
116
+ raise Money::Bank::UnknownRateFormat unless
117
+ RATE_FORMATS.include? format
118
+
119
+ store.transaction true do
120
+ data = case format
121
+ when :json
122
+ JSON.load(s)
123
+ when :ruby
124
+ Marshal.load(s)
125
+ when :yaml
126
+ YAML.load(s)
127
+ end
128
+
129
+ data.each do |key, rate|
130
+ from, to = key.split(SERIALIZER_SEPARATOR)
131
+ to, date = to.split(SERIALIZER_DATE_SEPARATOR)
132
+ store.add_rate from, to, rate, date
133
+ end
134
+ end
135
+
136
+ self
137
+ end
138
+
82
139
  protected
83
140
 
84
141
  def doc(cache, url=ECB_RATES_URL)
@@ -95,13 +152,13 @@ class EuCentralBank < Money::Bank::VariableExchange
95
152
  def update_parsed_rates(doc)
96
153
  rates = doc.xpath('gesmes:Envelope/xmlns:Cube/xmlns:Cube//xmlns:Cube')
97
154
 
98
- @mutex.synchronize do
155
+ store.transaction true do
99
156
  rates.each do |exchange_rate|
100
157
  rate = BigDecimal(exchange_rate.attribute("rate").value)
101
158
  currency = exchange_rate.attribute("currency").value
102
- set_rate("EUR", currency, rate, :without_mutex => true)
159
+ set_rate("EUR", currency, rate)
103
160
  end
104
- set_rate("EUR", "EUR", 1, :without_mutex => true)
161
+ set_rate("EUR", "EUR", 1)
105
162
  end
106
163
 
107
164
  rates_updated_at = doc.xpath('gesmes:Envelope/xmlns:Cube/xmlns:Cube/@time').first.value
@@ -113,14 +170,12 @@ class EuCentralBank < Money::Bank::VariableExchange
113
170
  def update_parsed_historical_rates(doc)
114
171
  rates = doc.xpath('gesmes:Envelope/xmlns:Cube/xmlns:Cube//xmlns:Cube')
115
172
 
116
- @mutex.synchronize do
173
+ store.transaction true do
117
174
  rates.each do |exchange_rate|
118
175
  rate = BigDecimal(exchange_rate.attribute("rate").value)
119
176
  currency = exchange_rate.attribute("currency").value
120
- opts = { :without_mutex => true }
121
- opts[:date] = exchange_rate.parent.attribute("time").value
122
- set_rate("EUR", currency, rate, opts)
123
- set_rate("EUR", "EUR", 1, opts)
177
+ date = exchange_rate.parent.attribute("time").value
178
+ set_rate("EUR", currency, rate, date)
124
179
  end
125
180
  end
126
181
 
@@ -139,10 +194,4 @@ class EuCentralBank < Money::Bank::VariableExchange
139
194
  money = (decimal_money * from.cents * rate).round
140
195
  Money.new(money, to_currency)
141
196
  end
142
-
143
- def rate_key_for(from, to, opts)
144
- key = "#{from}_TO_#{to}"
145
- key << "_#{opts[:date].to_s}" if opts[:date]
146
- key.upcase
147
- end
148
197
  end
@@ -0,0 +1,70 @@
1
+ module Money::RatesStore
2
+ module EuCentralBankHistoricalDataSupport
3
+ INDEX_DATE_SEPARATOR = '_AT_'.freeze
4
+
5
+ def add_rate(currency_iso_from, currency_iso_to, rate, date = nil)
6
+ transaction { index[rate_key_for(currency_iso_from, currency_iso_to, date)] = rate }
7
+ end
8
+
9
+ def get_rate(currency_iso_from, currency_iso_to, date = nil)
10
+ transaction { index[rate_key_for(currency_iso_from, currency_iso_to, date)] }
11
+ end
12
+
13
+ # Wraps block execution in a thread-safe transaction
14
+ def transaction(force_sync = false, &block)
15
+ # Ruby 1.9.3 does not support @mutex.owned?
16
+ if @mutex.respond_to?(:owned?)
17
+ force_sync = false if @mutex.locked? && @mutex.owned?
18
+ else
19
+ # If we allowed this in Ruby 1.9.3, it might possibly cause recursive
20
+ # locking within the same thread.
21
+ force_sync = false
22
+ end
23
+ if !force_sync && (@in_transaction || options[:without_mutex])
24
+ block.call self
25
+ else
26
+ @mutex.synchronize do
27
+ @in_transaction = true
28
+ result = block.call
29
+ @in_transaction = false
30
+ result
31
+ end
32
+ end
33
+ end
34
+
35
+ # Iterate over rate tuples (iso_from, iso_to, rate)
36
+ #
37
+ # @yieldparam iso_from [String] Currency ISO string.
38
+ # @yieldparam iso_to [String] Currency ISO string.
39
+ # @yieldparam rate [Numeric] Exchange rate.
40
+ # @yieldparam date [Date] Historical date for the exchange rate. Nil if the rate is not historical rate.
41
+ #
42
+ # @return [Enumerator]
43
+ #
44
+ # @example
45
+ # store.each_rate do |iso_from, iso_to, rate, date|
46
+ # puts [iso_from, iso_to, rate, date].join
47
+ # end
48
+ def each_rate(&block)
49
+ enum = Enumerator.new do |yielder|
50
+ index.each do |key, rate|
51
+ iso_from, iso_to = key.split(Memory::INDEX_KEY_SEPARATOR)
52
+ iso_to, date = iso_to.split(INDEX_DATE_SEPARATOR)
53
+ date = Date.parse(date) if date
54
+ yielder.yield iso_from, iso_to, rate, date
55
+ end
56
+ end
57
+
58
+ block_given? ? enum.each(&block) : enum
59
+ end
60
+
61
+ private
62
+
63
+ def rate_key_for(currency_iso_from, currency_iso_to, date = nil)
64
+ key = [currency_iso_from, currency_iso_to].join(Memory::INDEX_KEY_SEPARATOR)
65
+ key = [key, date.to_s].join(INDEX_DATE_SEPARATOR) if date
66
+ key.upcase
67
+ end
68
+
69
+ end
70
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eu_central_bank
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shane Emmons
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-15 00:00:00.000000000 Z
11
+ date: 2016-05-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 3.3.0
47
+ version: 3.4.0
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 3.3.0
54
+ version: 3.4.0
55
55
  description: This gem reads exchange rates from the european central bank website.
56
56
  It uses it to calculates exchange rates. It is compatible with the money gem
57
57
  email:
@@ -64,6 +64,7 @@ files:
64
64
  - LICENSE
65
65
  - README.md
66
66
  - lib/eu_central_bank.rb
67
+ - lib/money/rates_store/eu_central_bank_historical_data_support.rb
67
68
  homepage: https://github.com/RubyMoney/eu_central_bank
68
69
  licenses: []
69
70
  metadata: {}
@@ -83,10 +84,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
83
84
  version: '0'
84
85
  requirements: []
85
86
  rubyforge_project:
86
- rubygems_version: 2.4.5.1
87
+ rubygems_version: 2.5.1
87
88
  signing_key:
88
89
  specification_version: 4
89
90
  summary: Calculates exchange rates based on rates from european central bank. Money
90
91
  gem compatible.
91
92
  test_files: []
92
- has_rdoc: