money-open-exchange-rates 1.3.0 → 1.4.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
  SHA256:
3
- metadata.gz: 936862d5f32115f726c00579e6e248fd972d4d399d5e5866be087186cdfe2ade
4
- data.tar.gz: 2ad7d8ff2636e13aa19284c23a1eb26da74dd7c5ddc5ad3bff9bbec91dc026ff
3
+ metadata.gz: a8d1aa20a7e00ad9b92ff6f516af74c9f26a0b4a4cfacdbab246833806976cb7
4
+ data.tar.gz: 61646aab5bbcfb00e362df9f6fe8e0bc80b9ef553a99ac6bfd26fa1c7d8f5c93
5
5
  SHA512:
6
- metadata.gz: daf9beece860326d2fcdb8413cdbf8b878e799d3c2fb3ecb5d858342d5cfc2b9a052d6e5147abcde56f34529fdcc51cd02e2552253b0944a381f583af8dd59be
7
- data.tar.gz: 234054fbc3bbb9e55db3f69976113eb4691806e98e0e7365074e730941932164bc41cc7cd47d5e540200dac8a65af3c9a42e880b3778f89b92fd8415189f9ca4
6
+ metadata.gz: 61eea8294a9b0b0a311db01d9b792c3831adc1d1711af486f9c43bac434bb5ced1dde20527624f16054e56cda867306bbf43f63dda9a17ef536da302cc77c250
7
+ data.tar.gz: 118f24d214bd24f7264aa575e87de2f04e115ebca9d83ce70c24abdd1cc0d93b2995f192ec760314717bbbed846ab75273ff851812a9fb6fd16a114043f63d76
data/Gemfile CHANGED
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  gemspec
4
6
 
5
- gem 'coveralls', require: false
7
+ gem 'simplecov', require: false
data/History.md CHANGED
@@ -1,4 +1,37 @@
1
1
 
2
+ 1.4.1 / 2023-05-07
3
+ ==================
4
+
5
+ * Merge pull request #69 from @fuentesjr / identify-access-restricted-errors
6
+ * Fixing typo in scoping of must_raise in access restricted test
7
+ * Raise a new AccessRestricted error when account is restricted by oer
8
+
9
+ 1.4.0 / 2020-09-11
10
+ ==================
11
+
12
+ * Fix jruby test for cross courses
13
+ * Fix deprecation global use of must_equal
14
+ * Merge pull request #66 from @korun / clear-cross-courses
15
+ * Update rates inside transaction, to prevent RC issues
16
+ * Merge pull request #65 from @korun / ensure-file-closed
17
+ * Fix unclosed file descriptor after read_from_cache
18
+ * Merge pull request #64 from @anton-smagin / clear-cross-courses
19
+ * Set old rates to nil on #update_rates before set new one to expire pair rates using base
20
+ * Add coverage stage on ci
21
+ * Remove Ruby 2.3 support
22
+ * Switch to gitlab ci
23
+ * Update README
24
+ * Fix rubocop to 0.76.0 and remove minitest-focus
25
+ * Update gitlab ci gem install does not have --no-ri anymore
26
+ * README add more doc about update_rates
27
+ * Fix deprecation for minitest 6
28
+ * Fix flaky test about Money::Bank::NoAppId
29
+ * Support Pathname for cache
30
+ * Update rubocop to 0.76
31
+ * Remove Ruby 2.2 support and update rubocop
32
+ * Update travis list
33
+ * README: improve refresh doc
34
+
2
35
  1.3.0 / 2019-01-20
3
36
  ==================
4
37
 
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License
2
2
 
3
- Copyright (c) 2011-2019 Laurent Arnoud <laurent@spkdev.net>
3
+ Copyright (c) 2011-2020 Laurent Arnoud <laurent@spkdev.net>
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining
6
6
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -30,15 +30,15 @@ gem 'money-open-exchange-rates'
30
30
 
31
31
  And then execute:
32
32
 
33
- ~~~
33
+ ```
34
34
  bundle
35
- ~~~
35
+ ```
36
36
 
37
37
  Or install it yourself as:
38
38
 
39
- ~~~
39
+ ```
40
40
  gem install money-open-exchange-rates
41
- ~~~
41
+ ```
42
42
 
43
43
  ## Usage
44
44
 
@@ -47,8 +47,14 @@ require 'money/bank/open_exchange_rates_bank'
47
47
 
48
48
  # Memory store per default; for others just pass as argument a class like
49
49
  # explained in https://github.com/RubyMoney/money#exchange-rate-stores
50
- oxr = Money::Bank::OpenExchangeRatesBank.new
50
+ oxr = Money::Bank::OpenExchangeRatesBank.new(Money::RatesStore::Memory.new)
51
51
  oxr.app_id = 'your app id from https://openexchangerates.org/signup'
52
+
53
+ # Update the rates for the current rates storage
54
+ # If the storage is memory you will have to restart the server to be taken into
55
+ # account.
56
+ # If the storage is a database, file, this can be added to
57
+ # crontab/worker/scheduler `Money.default_bank.update_rates`
52
58
  oxr.update_rates
53
59
 
54
60
  # (optional)
@@ -97,7 +103,8 @@ oxr.refresh_rates
97
103
  # (optional)
98
104
  # Force refresh rates cache and store on the fly when ttl is expired
99
105
  # This will slow down request on get_rate, so use at your on risk, if you don't
100
- # want to setup crontab/worker/scheduler for your application
106
+ # want to setup crontab/worker/scheduler for your application.
107
+ # Again this is not safe with multiple servers and could increase API usage.
101
108
  oxr.force_refresh_rate_on_expire = true
102
109
 
103
110
  Money.default_bank = oxr
@@ -105,6 +112,31 @@ Money.default_bank = oxr
105
112
  Money.default_bank.get_rate('USD', 'CAD')
106
113
  ```
107
114
 
115
+ ## Refresh rates
116
+
117
+ ### With [whenever](https://github.com/javan/whenever)
118
+
119
+ ``` ruby
120
+ every :hour do
121
+ runner "Money.default_bank.refresh_rates"
122
+ # you will have to restart the server if you are using memory rate store
123
+ runner "Money.default_bank.update_rates"
124
+ end
125
+ ```
126
+
127
+ ### With rake task
128
+
129
+ ``` ruby
130
+ namespace :open_exchange_rates do
131
+ desc "Refresh rates from cache and update rates"
132
+ task :refresh_rates => :environment do
133
+ Money.default_bank.refresh_rates
134
+ # you will have to restart the server if you are using memory rate store
135
+ Money.default_bank.update_rates
136
+ end
137
+ end
138
+ ```
139
+
108
140
  ## Cache
109
141
 
110
142
  You can also provide a `Proc` as a cache to provide your own caching mechanism
@@ -162,11 +194,15 @@ end
162
194
  oxr.app_id = ENV['OXR_API_KEY']
163
195
  oxr.show_alternative = true
164
196
  oxr.prettyprint = false
197
+
198
+ # This can be removed if you have data to avoid http call on boot for production
165
199
  oxr.update_rates
166
200
 
167
201
  Money.default_bank = oxr
168
202
  ```
169
203
 
204
+ See also how to [refresh and update rates](#refresh-rates)
205
+
170
206
  ### Tests
171
207
 
172
208
  To avoid to hit the API we can use the cache option with a saved file like this:
@@ -194,9 +230,9 @@ or using base currency rate to both currencies forming the pair.
194
230
 
195
231
  ## Tests
196
232
 
197
- ~~~
233
+ ```
198
234
  bundle exec rake
199
- ~~~
235
+ ```
200
236
 
201
237
  ## Refs
202
238
 
@@ -213,12 +249,12 @@ See [GitHub](https://github.com/spk/money-open-exchange-rates/graphs/contributor
213
249
 
214
250
  The MIT License
215
251
 
216
- Copyright © 2011-2019 Laurent Arnoud <laurent@spkdev.net>
252
+ Copyright © 2011-2020 Laurent Arnoud <laurent@spkdev.net>
217
253
 
218
254
  ---
219
- [![Build](https://img.shields.io/travis-ci/spk/money-open-exchange-rates.svg)](https://travis-ci.org/spk/money-open-exchange-rates)
255
+ [![Build](https://img.shields.io/gitlab/pipeline/spkdev/money-open-exchange-rates/master)](https://gitlab.com/spkdev/money-open-exchange-rates/-/commits/master)
256
+ [![Coverage](https://gitlab.com/spkdev/money-open-exchange-rates/badges/master/coverage.svg)](https://gitlab.com/spkdev/money-open-exchange-rates/-/commits/master)
220
257
  [![Version](https://img.shields.io/gem/v/money-open-exchange-rates.svg)](https://rubygems.org/gems/money-open-exchange-rates)
221
258
  [![Documentation](https://img.shields.io/badge/doc-rubydoc-blue.svg)](http://www.rubydoc.info/gems/money-open-exchange-rates)
222
259
  [![License](https://img.shields.io/badge/license-MIT-blue.svg)](http://opensource.org/licenses/MIT "MIT")
223
- [![Coverage Status](https://img.shields.io/coveralls/github/spk/money-open-exchange-rates.svg)](https://coveralls.io/github/spk/money-open-exchange-rates?branch=master)
224
260
  [![Inline docs](https://inch-ci.org/github/spk/money-open-exchange-rates.svg?branch=master)](http://inch-ci.org/github/spk/money-open-exchange-rates)
@@ -7,7 +7,7 @@ require 'json'
7
7
  require File.expand_path('../../open_exchange_rates_bank/version', __dir__)
8
8
 
9
9
  # Money gem class
10
- # rubocop:disable ClassLength
10
+ # rubocop:disable Metrics/ClassLength
11
11
  class Money
12
12
  # https://github.com/RubyMoney/money#exchange-rate-stores
13
13
  module Bank
@@ -17,19 +17,22 @@ class Money
17
17
  # APP_ID not set error
18
18
  class NoAppId < StandardError; end
19
19
 
20
+ # Access restricted (e.g. usage/request limit exceeded for account)
21
+ class AccessRestricted < StandardError; end
22
+
20
23
  # OpenExchangeRatesBank base class
21
24
  class OpenExchangeRatesBank < Money::Bank::VariableExchange
22
25
  VERSION = ::OpenExchangeRatesBank::VERSION
23
- BASE_URL = 'https://openexchangerates.org/api/'.freeze
26
+ BASE_URL = 'https://openexchangerates.org/api/'
24
27
 
25
28
  # OpenExchangeRates urls
26
29
  OER_URL = URI.join(BASE_URL, 'latest.json')
27
30
  OER_HISTORICAL_URL = URI.join(BASE_URL, 'historical/')
28
31
 
29
32
  # Default base currency "base": "USD"
30
- OE_SOURCE = 'USD'.freeze
31
- RATES_KEY = 'rates'.freeze
32
- TIMESTAMP_KEY = 'timestamp'.freeze
33
+ OE_SOURCE = 'USD'
34
+ RATES_KEY = 'rates'
35
+ TIMESTAMP_KEY = 'timestamp'
33
36
 
34
37
  # As of the end of August 2012 all requests to the Open Exchange Rates
35
38
  # API must have a valid app_id
@@ -174,13 +177,16 @@ class Money
174
177
  #
175
178
  # @return [Array] Array of exchange rates
176
179
  def update_rates
177
- exchange_rates.each do |exchange_rate|
178
- rate = exchange_rate.last
179
- currency = exchange_rate.first
180
- next unless Money::Currency.find(currency)
181
-
182
- set_rate(source, currency, rate)
183
- set_rate(currency, source, 1.0 / rate)
180
+ store.transaction do
181
+ clear_rates!
182
+ exchange_rates.each do |exchange_rate|
183
+ rate = exchange_rate.last
184
+ currency = exchange_rate.first
185
+ next unless Money::Currency.find(currency)
186
+
187
+ set_rate(source, currency, rate)
188
+ set_rate(currency, source, 1.0 / rate)
189
+ end
184
190
  end
185
191
  end
186
192
 
@@ -255,9 +261,7 @@ class Money
255
261
  str = "#{str}&base=#{source}" unless source == OE_SOURCE
256
262
  str = "#{str}&show_alternative=#{show_alternative}"
257
263
  str = "#{str}&prettyprint=#{prettyprint}"
258
- if symbols && symbols.is_a?(Array)
259
- str = "#{str}&symbols=#{symbols.join(',')}"
260
- end
264
+ str = "#{str}&symbols=#{symbols.join(',')}" if symbols&.is_a?(Array)
261
265
  str
262
266
  end
263
267
 
@@ -300,6 +304,7 @@ class Money
300
304
 
301
305
  # Store the provided text data by calling the proc method provided
302
306
  # for the cache, or write to the cache file.
307
+ # Can raise InvalidCache
303
308
  #
304
309
  # @example
305
310
  # oxr.store_in_cache("{\"rates\": {\"AED\": 3.67304}}")
@@ -309,10 +314,12 @@ class Money
309
314
  def store_in_cache(text)
310
315
  if cache.is_a?(Proc)
311
316
  cache.call(text)
312
- elsif cache.is_a?(String)
313
- File.open(cache, 'w') do |f|
317
+ elsif cache.is_a?(String) || cache.is_a?(Pathname)
318
+ File.open(cache.to_s, 'w') do |f|
314
319
  f.write(text)
315
320
  end
321
+ else
322
+ raise InvalidCache
316
323
  end
317
324
  end
318
325
 
@@ -322,8 +329,8 @@ class Money
322
329
  def read_from_cache
323
330
  result = if cache.is_a?(Proc)
324
331
  cache.call(nil)
325
- elsif cache.is_a?(String) && File.exist?(cache)
326
- File.open(cache).read
332
+ elsif File.exist?(cache.to_s)
333
+ File.read(cache)
327
334
  end
328
335
  result if valid_rates?(result)
329
336
  end
@@ -357,7 +364,7 @@ class Money
357
364
  return false unless text
358
365
 
359
366
  parsed = JSON.parse(text)
360
- parsed && parsed.key?(RATES_KEY) && parsed.key?(TIMESTAMP_KEY)
367
+ parsed&.key?(RATES_KEY) && parsed&.key?(TIMESTAMP_KEY)
361
368
  rescue JSON::ParserError
362
369
  false
363
370
  end
@@ -367,6 +374,10 @@ class Money
367
374
  # @return [Hash] key is country code (ISO 3166-1 alpha-3) value Float
368
375
  def exchange_rates
369
376
  doc = JSON.parse(read_from_cache || read_from_url)
377
+ if doc['error'] && doc['message'] == 'access_restricted'
378
+ raise AccessRestricted
379
+ end
380
+
370
381
  self.rates_timestamp = doc[TIMESTAMP_KEY]
371
382
  @oer_rates = doc[RATES_KEY]
372
383
  end
@@ -413,7 +424,16 @@ class Money
413
424
  add_rate(from_currency, to_currency, rate)
414
425
  rate
415
426
  end
427
+
428
+ # Clears cached rates in store
429
+ #
430
+ # @return [Hash] All rates from store as Hash
431
+ def clear_rates!
432
+ store.each_rate do |iso_from, iso_to|
433
+ add_rate(iso_from, iso_to, nil)
434
+ end
435
+ end
416
436
  end
417
437
  end
418
438
  end
419
- # rubocop:enable ClassLength
439
+ # rubocop:enable Metrics/ClassLength
@@ -2,5 +2,5 @@
2
2
 
3
3
  # Module for version constant
4
4
  module OpenExchangeRatesBank
5
- VERSION = '1.3.0'.freeze
5
+ VERSION = '1.4.1'
6
6
  end
@@ -0,0 +1,6 @@
1
+ {
2
+ "error": true,
3
+ "status": 429,
4
+ "message": "access_restricted",
5
+ "description": "Access restricted until 2050-01-01 (reason: too_many_requests). If there has been a mistake, please contact support@openexchangerates.org."
6
+ }
@@ -1,2 +1,4 @@
1
+ # frozen_string_literal: true
2
+
1
3
  gem 'money', '~> 6.7'
2
4
  gem 'money-open-exchange-rates', path: '../../'
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'json'
2
4
  require 'money/bank/open_exchange_rates_bank'
3
5
 
4
- ERROR_MSG = 'Integration test failed!'.freeze
6
+ ERROR_MSG = 'Integration test failed!'
5
7
  cache_path = '/tmp/latest.json'
6
8
  to_currency = 'CAD'
7
9
  app_id = ENV['OXR_APP_ID']
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
2
4
 
3
5
  # rubocop:disable Metrics/BlockLength
@@ -14,12 +16,18 @@ describe Money::Bank::OpenExchangeRatesBank do
14
16
  let(:temp_cache_path) do
15
17
  data_file('tmp.json')
16
18
  end
19
+ let(:temp_cache_pathname) do
20
+ Pathname.new('test/data/tmp.json')
21
+ end
17
22
  let(:oer_latest_path) do
18
23
  data_file('latest.json')
19
24
  end
20
25
  let(:oer_historical_path) do
21
26
  data_file('2015-01-01.json')
22
27
  end
28
+ let(:oer_access_restricted_error_path) do
29
+ data_file('access_restricted_error.json')
30
+ end
23
31
 
24
32
  describe 'exchange' do
25
33
  before do
@@ -35,12 +43,12 @@ describe Money::Bank::OpenExchangeRatesBank do
35
43
  describe 'without rates' do
36
44
  it 'able to exchange a money to its own currency even without rates' do
37
45
  money = Money.new(0, 'USD')
38
- subject.exchange_with(money, 'USD').must_equal money
46
+ _(subject.exchange_with(money, 'USD')).must_equal money
39
47
  end
40
48
 
41
49
  it "raise if it can't find an exchange rate" do
42
50
  money = Money.new(0, 'USD')
43
- proc { subject.exchange_with(money, 'SSP') }
51
+ _(proc { subject.exchange_with(money, 'SSP') })
44
52
  .must_raise Money::Bank::UnknownRate
45
53
  end
46
54
  end
@@ -52,33 +60,33 @@ describe Money::Bank::OpenExchangeRatesBank do
52
60
 
53
61
  it 'should be able to exchange money from USD to a known exchange rate' do
54
62
  money = Money.new(100, 'USD')
55
- subject.exchange_with(money, 'BBD').must_equal Money.new(200, 'BBD')
63
+ _(subject.exchange_with(money, 'BBD')).must_equal Money.new(200, 'BBD')
56
64
  end
57
65
 
58
66
  it 'should be able to exchange money from a known exchange rate to USD' do
59
67
  money = Money.new(200, 'BBD')
60
- subject.exchange_with(money, 'USD').must_equal Money.new(100, 'USD')
68
+ _(subject.exchange_with(money, 'USD')).must_equal Money.new(100, 'USD')
61
69
  end
62
70
 
63
71
  it 'should be able to exchange money when direct rate is unknown' do
64
72
  money = Money.new(100, 'BBD')
65
- subject.exchange_with(money, 'BMD').must_equal Money.new(50, 'BMD')
73
+ _(subject.exchange_with(money, 'BMD')).must_equal Money.new(50, 'BMD')
66
74
  end
67
75
 
68
76
  it 'should be able to handle non integer rates' do
69
77
  money = Money.new(100, 'BBD')
70
- subject.exchange_with(money, 'TJS').must_equal Money.new(250, 'TJS')
78
+ _(subject.exchange_with(money, 'TJS')).must_equal Money.new(250, 'TJS')
71
79
  end
72
80
 
73
81
  it "should raise if it can't find an currency" do
74
82
  money = Money.new(0, 'USD')
75
- proc { subject.exchange_with(money, 'PLP') }
83
+ _(proc { subject.exchange_with(money, 'PLP') })
76
84
  .must_raise Money::Currency::UnknownCurrency
77
85
  end
78
86
 
79
87
  it "should raise if it can't find an exchange rate" do
80
88
  money = Money.new(0, 'USD')
81
- proc { subject.exchange_with(money, 'SSP') }
89
+ _(proc { subject.exchange_with(money, 'SSP') })
82
90
  .must_raise Money::Bank::UnknownRate
83
91
  end
84
92
  end
@@ -91,11 +99,18 @@ describe Money::Bank::OpenExchangeRatesBank do
91
99
  subject.update_rates
92
100
  end
93
101
 
102
+ it 'should raise AccessRestricted error when restricted by oer' do
103
+ subject.cache = nil
104
+ filepath = oer_access_restricted_error_path
105
+ subject.stubs(:api_response).returns File.read(filepath)
106
+ _(proc { subject.update_rates }).must_raise Money::Bank::AccessRestricted
107
+ end
108
+
94
109
  it 'should update itself with exchange rates from OpenExchangeRates' do
95
110
  subject.oer_rates.keys.each do |currency|
96
111
  next unless Money::Currency.find(currency)
97
112
 
98
- subject.get_rate('USD', currency).must_be :>, 0
113
+ _(subject.get_rate('USD', currency)).must_be :>, 0
99
114
  end
100
115
  end
101
116
 
@@ -113,7 +128,7 @@ describe Money::Bank::OpenExchangeRatesBank do
113
128
  Money::Currency.register(wtf)
114
129
  subject.add_rate('USD', 'WTF', 2)
115
130
  subject.add_rate('WTF', 'USD', 2)
116
- subject.exchange_with(5000.to_money('WTF'), 'USD').cents.wont_equal 0
131
+ _(subject.exchange_with(5000.to_money('WTF'), 'USD').cents).wont_equal 0
117
132
  end
118
133
 
119
134
  # in response to #4
@@ -132,17 +147,50 @@ describe Money::Bank::OpenExchangeRatesBank do
132
147
  rate = 13.7603
133
148
  subject.add_rate('USD', 'BTC', 1 / 13.7603)
134
149
  subject.add_rate('BTC', 'USD', rate)
135
- subject.exchange_with(100.to_money('BTC'), 'USD').cents.must_equal 137_603
150
+ _(subject.exchange_with(100.to_money('BTC'), 'USD').cents)
151
+ .must_equal 137_603
136
152
  end
137
153
  end
138
154
 
139
155
  describe 'App ID' do
156
+ describe 'nil' do
157
+ before do
158
+ subject.app_id = nil
159
+ end
160
+
161
+ it 'should raise an error if no App ID is set' do
162
+ _(proc { subject.update_rates }).must_raise Money::Bank::NoAppId
163
+ end
164
+ end
165
+
166
+ describe 'empty' do
167
+ before do
168
+ subject.app_id = ''
169
+ end
170
+
171
+ it 'should raise an error if no App ID is set' do
172
+ _(proc { subject.update_rates }).must_raise Money::Bank::NoAppId
173
+ end
174
+ end
175
+ end
176
+
177
+ describe '#cache' do
140
178
  before do
141
- subject.cache = temp_cache_path
179
+ subject.app_id = TEST_APP_ID
180
+ end
181
+
182
+ it 'support Pathname object' do
183
+ subject.cache = temp_cache_pathname
184
+ subject.stubs(:api_response).returns File.read(oer_latest_path)
185
+ subject.update_rates
186
+ subject.expects(:read_from_url).never
187
+ subject.update_rates
142
188
  end
143
189
 
144
- it 'should raise an error if no App ID is set' do
145
- proc { subject.update_rates }.must_raise Money::Bank::NoAppId
190
+ it 'raise InvalidCache when the arg is not known' do
191
+ subject.cache = Array
192
+ add_to_webmock(subject)
193
+ _(proc { subject.update_rates }).must_raise Money::Bank::InvalidCache
146
194
  end
147
195
  end
148
196
 
@@ -155,7 +203,7 @@ describe Money::Bank::OpenExchangeRatesBank do
155
203
  it 'should get from url' do
156
204
  subject.expects(:save_cache).never
157
205
  subject.update_rates
158
- subject.oer_rates.wont_be_empty
206
+ _(subject.oer_rates).wont_be_empty
159
207
  end
160
208
  end
161
209
 
@@ -181,17 +229,18 @@ describe Money::Bank::OpenExchangeRatesBank do
181
229
  end
182
230
 
183
231
  it 'should use the secure https url' do
184
- subject.source_url.must_equal historical_url
185
- subject.source_url.must_include 'https://'
186
- subject.source_url.must_include "/api/historical/#{subject.date}.json"
232
+ _(subject.source_url).must_equal historical_url
233
+ _(subject.source_url).must_include 'https://'
234
+ exp_url = "/api/historical/#{subject.date}.json"
235
+ _(subject.source_url).must_include exp_url
187
236
  end
188
237
  end
189
238
 
190
239
  describe 'latest' do
191
240
  it 'should use the secure https url' do
192
- subject.source_url.must_equal source_url
193
- subject.source_url.must_include 'https://'
194
- subject.source_url.must_include '/api/latest.json'
241
+ _(subject.source_url).must_equal source_url
242
+ _(subject.source_url).must_include 'https://'
243
+ _(subject.source_url).must_include '/api/latest.json'
195
244
  end
196
245
  end
197
246
  end
@@ -203,7 +252,7 @@ describe Money::Bank::OpenExchangeRatesBank do
203
252
  end
204
253
 
205
254
  it 'should raise an error if invalid path is given to update_rates' do
206
- proc { subject.update_rates }.must_raise Money::Bank::InvalidCache
255
+ _(proc { subject.update_rates }).must_raise Money::Bank::InvalidCache
207
256
  end
208
257
  end
209
258
 
@@ -222,14 +271,14 @@ describe Money::Bank::OpenExchangeRatesBank do
222
271
  end
223
272
 
224
273
  it 'should get from url normally' do
225
- subject.oer_rates.wont_be_empty
274
+ _(subject.oer_rates).wont_be_empty
226
275
  end
227
276
 
228
277
  it 'should save from url and get from cache' do
229
- @global_rates.wont_be_empty
278
+ _(@global_rates).wont_be_empty
230
279
  subject.expects(:source_url).never
231
280
  subject.update_rates
232
- subject.oer_rates.wont_be_empty
281
+ _(subject.oer_rates).wont_be_empty
233
282
  end
234
283
  end
235
284
 
@@ -259,21 +308,21 @@ describe Money::Bank::OpenExchangeRatesBank do
259
308
  initial_size = File.read(temp_cache_path).size
260
309
  subject.stubs(:api_response).returns ''
261
310
  subject.refresh_rates
262
- File.open(temp_cache_path).read.size.must_equal initial_size
311
+ _(File.open(temp_cache_path).read.size).must_equal initial_size
263
312
  end
264
313
 
265
314
  it 'should not break an existing file if save returns json without rates' do
266
315
  initial_size = File.read(temp_cache_path).size
267
316
  subject.stubs(:api_response).returns '{"error": "An error"}'
268
317
  subject.refresh_rates
269
- File.open(temp_cache_path).read.size.must_equal initial_size
318
+ _(File.open(temp_cache_path).read.size).must_equal initial_size
270
319
  end
271
320
 
272
321
  it 'should not break an existing file if save returns a invalid json' do
273
322
  initial_size = File.read(temp_cache_path).size
274
323
  subject.stubs(:api_response).returns '{invalid_json: "An error"}'
275
324
  subject.refresh_rates
276
- File.open(temp_cache_path).read.size.must_equal initial_size
325
+ _(File.open(temp_cache_path).read.size).must_equal initial_size
277
326
  end
278
327
  end
279
328
 
@@ -283,12 +332,12 @@ describe Money::Bank::OpenExchangeRatesBank do
283
332
  end
284
333
 
285
334
  it 'should be now when not updated from api' do
286
- subject.rates_timestamp.must_be :>, Time.at(1_414_008_044)
335
+ _(subject.rates_timestamp).must_be :>, Time.at(1_414_008_044)
287
336
  end
288
337
 
289
338
  it 'should be set on update_rates' do
290
339
  subject.update_rates
291
- subject.rates_timestamp.must_equal Time.at(1_414_008_044)
340
+ _(subject.rates_timestamp).must_equal Time.at(1_414_008_044)
292
341
  end
293
342
  end
294
343
 
@@ -316,21 +365,21 @@ describe Money::Bank::OpenExchangeRatesBank do
316
365
  describe 'when the ttl has expired' do
317
366
  it 'should update the rates' do
318
367
  Timecop.freeze(subject.rates_timestamp) do
319
- subject.get_rate('USD', 'EUR').must_equal @old_usd_eur_rate
368
+ _(subject.get_rate('USD', 'EUR')).must_equal @old_usd_eur_rate
320
369
  end
321
370
  Timecop.freeze(subject.rates_timestamp + (@ttl_in_seconds + 1)) do
322
- subject.get_rate('USD', 'EUR').wont_equal @old_usd_eur_rate
323
- subject.get_rate('USD', 'EUR').must_equal @new_usd_eur_rate
371
+ _(subject.get_rate('USD', 'EUR')).wont_equal @old_usd_eur_rate
372
+ _(subject.get_rate('USD', 'EUR')).must_equal @new_usd_eur_rate
324
373
  end
325
374
  end
326
375
 
327
376
  it 'should save rates' do
328
377
  Timecop.freeze(subject.rates_timestamp) do
329
- subject.get_rate('USD', 'EUR').must_equal @old_usd_eur_rate
378
+ _(subject.get_rate('USD', 'EUR')).must_equal @old_usd_eur_rate
330
379
  end
331
380
  Timecop.freeze(subject.rates_timestamp + (@ttl_in_seconds + 1)) do
332
- subject.get_rate('USD', 'EUR').must_equal @new_usd_eur_rate
333
- @global_rates.wont_be_empty
381
+ _(subject.get_rate('USD', 'EUR')).must_equal @new_usd_eur_rate
382
+ _(@global_rates).wont_be_empty
334
383
  end
335
384
  end
336
385
 
@@ -338,7 +387,7 @@ describe Money::Bank::OpenExchangeRatesBank do
338
387
  Timecop.freeze(subject.rates_timestamp + (@ttl_in_seconds + 1)) do
339
388
  exp_time = subject.rates_timestamp + @ttl_in_seconds
340
389
  subject.expire_rates
341
- subject.rates_expiration.must_equal exp_time
390
+ _(subject.rates_expiration).must_equal exp_time
342
391
  end
343
392
  end
344
393
 
@@ -346,12 +395,12 @@ describe Money::Bank::OpenExchangeRatesBank do
346
395
  it 'should save rates and force refresh' do
347
396
  subject.force_refresh_rate_on_expire = true
348
397
  Timecop.freeze(subject.rates_timestamp) do
349
- subject.get_rate('USD', 'EUR').must_equal @old_usd_eur_rate
398
+ _(subject.get_rate('USD', 'EUR')).must_equal @old_usd_eur_rate
350
399
  end
351
400
  Timecop.freeze(Time.now + 1001) do
352
401
  @global_rates = []
353
- subject.get_rate('USD', 'EUR').must_equal @new_usd_eur_rate
354
- @global_rates.wont_be_empty
402
+ _(subject.get_rate('USD', 'EUR')).must_equal @new_usd_eur_rate
403
+ _(@global_rates).wont_be_empty
355
404
  end
356
405
  end
357
406
  end
@@ -364,7 +413,7 @@ describe Money::Bank::OpenExchangeRatesBank do
364
413
  subject.expects(:update_rates).never
365
414
  subject.expects(:refresh_rates_expiration).never
366
415
  subject.expire_rates
367
- subject.rates_expiration.must_equal exp_time
416
+ _(subject.rates_expiration).must_equal exp_time
368
417
  end
369
418
  end
370
419
  end
@@ -373,19 +422,31 @@ describe Money::Bank::OpenExchangeRatesBank do
373
422
  describe 'historical' do
374
423
  before do
375
424
  add_to_webmock(subject)
376
- # see test/latest.json +52
425
+ # see test/data/latest.json +52
377
426
  @latest_usd_eur_rate = 0.79085
378
- # see test/2015-01-01.json +52
427
+ @latest_chf_eur_rate = 0.830792859
428
+ # see test/data/2015-01-01.json +52
379
429
  @old_usd_eur_rate = 0.830151
430
+ @old_chf_eur_rate = 0.832420177
380
431
  subject.update_rates
381
432
  end
382
433
 
383
434
  it 'should be different than the latest' do
384
- subject.get_rate('USD', 'EUR').must_equal @latest_usd_eur_rate
435
+ _(subject.get_rate('USD', 'EUR')).must_equal @latest_usd_eur_rate
436
+ subject.date = '2015-01-01'
437
+ add_to_webmock(subject, oer_historical_path)
438
+ subject.update_rates
439
+ _(subject.get_rate('USD', 'EUR')).must_equal @old_usd_eur_rate
440
+ end
441
+
442
+ it 'should update cross courses' do
443
+ _(subject.get_rate('CHF', 'EUR').round(9).to_f)
444
+ .must_equal @latest_chf_eur_rate
385
445
  subject.date = '2015-01-01'
386
446
  add_to_webmock(subject, oer_historical_path)
387
447
  subject.update_rates
388
- subject.get_rate('USD', 'EUR').must_equal @old_usd_eur_rate
448
+ _(subject.get_rate('CHF', 'EUR').round(9).to_f)
449
+ .must_equal @old_chf_eur_rate
389
450
  end
390
451
  end
391
452
 
@@ -393,15 +454,15 @@ describe Money::Bank::OpenExchangeRatesBank do
393
454
  it 'should be changed when a known currency is given' do
394
455
  source = 'EUR'
395
456
  subject.source = source
396
- subject.source.must_equal source
397
- subject.source_url.must_include "base=#{source}"
457
+ _(subject.source).must_equal source
458
+ _(subject.source_url).must_include "base=#{source}"
398
459
  end
399
460
 
400
461
  it 'should use USD when given unknown currency' do
401
462
  source = 'invalid'
402
463
  subject.source = source
403
- subject.source.must_equal default_source
404
- subject.source_url.wont_include "base=#{default_source}"
464
+ _(subject.source).must_equal default_source
465
+ _(subject.source_url).wont_include "base=#{default_source}"
405
466
  end
406
467
  end
407
468
 
@@ -412,11 +473,11 @@ describe Money::Bank::OpenExchangeRatesBank do
412
473
  end
413
474
 
414
475
  it 'should return the default value' do
415
- subject.prettyprint.must_equal true
476
+ _(subject.prettyprint).must_equal true
416
477
  end
417
478
 
418
479
  it 'should include prettyprint param as true' do
419
- subject.source_url.must_include 'prettyprint=true'
480
+ _(subject.source_url).must_include 'prettyprint=true'
420
481
  end
421
482
  end
422
483
 
@@ -426,11 +487,11 @@ describe Money::Bank::OpenExchangeRatesBank do
426
487
  end
427
488
 
428
489
  it 'should return the value' do
429
- subject.prettyprint.must_equal false
490
+ _(subject.prettyprint).must_equal false
430
491
  end
431
492
 
432
493
  it 'should include prettyprint param as false' do
433
- subject.source_url.must_include 'prettyprint=false'
494
+ _(subject.source_url).must_include 'prettyprint=false'
434
495
  end
435
496
  end
436
497
  end
@@ -442,11 +503,11 @@ describe Money::Bank::OpenExchangeRatesBank do
442
503
  end
443
504
 
444
505
  it 'should return the default value' do
445
- subject.show_alternative.must_equal false
506
+ _(subject.show_alternative).must_equal false
446
507
  end
447
508
 
448
509
  it 'should include show_alternative param as false' do
449
- subject.source_url.must_include 'show_alternative=false'
510
+ _(subject.source_url).must_include 'show_alternative=false'
450
511
  end
451
512
  end
452
513
 
@@ -456,11 +517,11 @@ describe Money::Bank::OpenExchangeRatesBank do
456
517
  end
457
518
 
458
519
  it 'should return the value' do
459
- subject.show_alternative.must_equal true
520
+ _(subject.show_alternative).must_equal true
460
521
  end
461
522
 
462
523
  it 'should include show_alternative param as true' do
463
- subject.source_url.must_include 'show_alternative=true'
524
+ _(subject.source_url).must_include 'show_alternative=true'
464
525
  end
465
526
  end
466
527
  end
data/test/test_helper.rb CHANGED
@@ -1,21 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  begin
4
- require 'coveralls'
5
- Coveralls.wear!
4
+ require 'simplecov'
5
+ SimpleCov.start
6
6
  rescue LoadError
7
- STDERR.puts 'coveralls not loaded'
7
+ warn 'simplecov not loaded'
8
8
  end
9
9
 
10
10
  require 'minitest/autorun'
11
- require 'minitest/focus'
12
11
  require 'mocha/minitest'
13
12
  require 'webmock/minitest'
14
13
  require 'money/bank/open_exchange_rates_bank'
15
14
  require 'monetize'
16
15
  require 'timecop'
17
16
 
18
- TEST_APP_ID = 'TEST_APP_ID'.freeze
17
+ TEST_APP_ID = 'TEST_APP_ID'
19
18
 
20
19
  def data_file(file)
21
20
  File.expand_path(File.join(File.dirname(__FILE__), 'data', file))
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: money-open-exchange-rates
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Laurent Arnoud
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-20 00:00:00.000000000 Z
11
+ date: 2023-05-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: money
@@ -38,20 +38,6 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '5'
41
- - !ruby/object:Gem::Dependency
42
- name: minitest-focus
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '1'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '1'
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: mocha
57
43
  requirement: !ruby/object:Gem::Requirement
@@ -106,14 +92,14 @@ dependencies:
106
92
  requirements:
107
93
  - - "~>"
108
94
  - !ruby/object:Gem::Version
109
- version: '0.63'
95
+ version: 0.76.0
110
96
  type: :development
111
97
  prerelease: false
112
98
  version_requirements: !ruby/object:Gem::Requirement
113
99
  requirements:
114
100
  - - "~>"
115
101
  - !ruby/object:Gem::Version
116
- version: '0.63'
102
+ version: 0.76.0
117
103
  - !ruby/object:Gem::Dependency
118
104
  name: timecop
119
105
  requirement: !ruby/object:Gem::Requirement
@@ -157,6 +143,7 @@ files:
157
143
  - lib/money/bank/open_exchange_rates_bank.rb
158
144
  - lib/open_exchange_rates_bank/version.rb
159
145
  - test/data/2015-01-01.json
146
+ - test/data/access_restricted_error.json
160
147
  - test/data/latest.json
161
148
  - test/integration/Gemfile
162
149
  - test/integration/Gemfile.lock
@@ -167,7 +154,7 @@ homepage: http://github.com/spk/money-open-exchange-rates
167
154
  licenses:
168
155
  - MIT
169
156
  metadata: {}
170
- post_install_message:
157
+ post_install_message:
171
158
  rdoc_options: []
172
159
  require_paths:
173
160
  - lib
@@ -175,16 +162,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
175
162
  requirements:
176
163
  - - ">="
177
164
  - !ruby/object:Gem::Version
178
- version: '2.2'
165
+ version: '2.4'
179
166
  required_rubygems_version: !ruby/object:Gem::Requirement
180
167
  requirements:
181
168
  - - ">="
182
169
  - !ruby/object:Gem::Version
183
170
  version: '0'
184
171
  requirements: []
185
- rubyforge_project:
186
- rubygems_version: 2.7.6
187
- signing_key:
172
+ rubygems_version: 3.3.15
173
+ signing_key:
188
174
  specification_version: 4
189
175
  summary: A gem that calculates the exchange rate using published rates from open-exchange-rates.
190
176
  test_files: