active_currency 1.0.0 → 1.2.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
- SHA1:
3
- metadata.gz: c07e2a76dae93079049c2140345f1e38a64d81ac
4
- data.tar.gz: 179ad081203f6de02d2b44a74f1449d9eead1d52
2
+ SHA256:
3
+ metadata.gz: 938c7b875052bf9d26b9ade8d9f1f268a94da7949a1685961a4265b01ed70a1c
4
+ data.tar.gz: cd167c1b911156c2025d75b29be92cfdfceed15aac7533b736db5bb63a59d3bc
5
5
  SHA512:
6
- metadata.gz: e31ee097e49beaaad38f1c714d1893ca80a6b09b8ef1211bc37545d0470a000470b99e1b3583ee62f4be269e9e23d4eb7413a9ca8d2e31cc0d5c8d44e41ff9cf
7
- data.tar.gz: 1258f0d28a6be18644b1d19452ede084f439257b50b35bab6138bef3c9b0fc5bfa9b8019c9ee53b85f83bf34c46a204be315f36b63209576558dfb05f2d7e5ac
6
+ metadata.gz: 51af4e890792d65780f3ce822ca6bef58465b2a34578b7edb0c6776d8d104ba569ef282dd7004715944e7d388b44a3935c5e0659ae87fdbf3f01ce1b36fd1cec
7
+ data.tar.gz: 2b66ea9433ccf5e35b54e22296b95a765dd9b249930e02c056d49afcc0c9f8a6731e7340db6db606fcbda33be7b4bc5d4f6fac53dc75dbae7e4a1b6991f634cc
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # ActiveCurrency
2
2
 
3
+ [![CircleCI](https://circleci.com/gh/sunny/active_currency.svg?style=svg)](https://circleci.com/gh/sunny/active_currency)
4
+
3
5
  Rails plugin to retrieve and store the currency rates daily to integrate
4
6
  with the `money-rails` gem.
5
7
 
@@ -8,34 +10,35 @@ with the `money-rails` gem.
8
10
  Storing the current currency rates in the database using ActiveCurrency
9
11
  provides the following advantages:
10
12
 
11
- - Lets you find out what the currency rate you used in your application was
12
- at any given time.
13
+ - Lets you query for the currency rate you actually used in your application at
14
+ any given time.
13
15
  - Does not need to call an API to get the rates when starting or restarting
14
16
  your web server.
15
- - Choose how often you want to check for a currency (daily for example).
17
+ - Does not depend on the file system to store cached rates.
18
+ - Choose how often you want to update the currency rates (daily for example).
16
19
  - Your users do not suffer the cost of making calls to the bank rates API.
17
20
  - Your app does not go down when the bank rates API does.
18
- - When fetching the current rate, it uses your application cache in order not
19
- to have to do a database query.
20
21
 
21
- To fetch the rates, it uses the [eu_central_bank] gem.
22
+ To fetch the *current* rate it uses your application cache instead of making
23
+ a call to the database.
22
24
 
23
25
  ## Usage
24
26
 
25
27
  Store the current rate regularly by calling in a scheduled job (using something
26
- like `sidekiq-scheduler` or `whenever`) with the currencies you want to store:
28
+ like `sidekiq-scheduler`, `whenever`, or `active_scheduler`) with the currencies
29
+ you want to store:
27
30
 
28
31
  ```rb
29
32
  ActiveCurrency::AddRates.call(%w[EUR USD])
30
33
  ```
31
34
 
32
- You can then exchange money by using the Money gem:
35
+ You can then exchange money by using the Money gem helpers:
33
36
 
34
37
  ```rb
35
38
  10.to_money('EUR').exchange_to('USD').cents
36
39
  ```
37
40
 
38
- Or look up the currency rate:
41
+ If you need to look up the previous currency rates:
39
42
 
40
43
  ```rb
41
44
  ActiveCurrency::Rate.value_for('EUR', 'USD', 1.month.ago)
@@ -61,21 +64,41 @@ MoneyRails.configure do |config|
61
64
  end
62
65
  ```
63
66
 
64
- Then call `bundle exec rake db:migrate` to create the table that holds
67
+ Then call `bin/rake db:migrate` to create the table that holds
65
68
  the currency rates and fill it for the first time.
66
69
 
70
+ ## Fetching rates
71
+
72
+ By defaut it uses the [eu_central_bank] to update the currency rates.
73
+
74
+ If you prefer another API, you can provide any Money-compatible bank when
75
+ calling `ActiveCurrency::AddRates`. For example with the
76
+ [money-open-exchange-rates] gem:
77
+
78
+ ```rb
79
+ require 'money/bank/open_exchange_rates_bank'
80
+
81
+ bank = Money::Bank::OpenExchangeRatesBank.new(Money::RatesStore::Memory.new)
82
+ bank.app_id = '…'
83
+
84
+ ActiveCurrency::AddRates.call(%w[EUR USD], bank: bank)
85
+ ```
86
+
87
+ The first currency you give to `AddRates` is considered the default currency
88
+ against which other currency rates will be guessed if they are unavailable.
89
+
67
90
  ## Tests
68
91
 
69
92
  In your app test suite you may not want to have to fill your database to be
70
93
  able to exchange currencies.
71
94
 
72
- For that, you should use a fake rate store in `config/initializers/money.rb`:
95
+ For that, you can use a fake rate store in your `rails_helper.rb`:
73
96
 
74
97
  ```rb
75
- if Rails.env.test?
98
+ MoneyRails.configure do |config|
76
99
  rate_store = Money::RatesStore::Memory.new.tap do |store|
77
- store.add_rate('USD', 'EUR', 0.5)
78
- store.add_rate('EUR', 'USD', 1.5)
100
+ store.add_rate('USD', 'EUR', 1.5)
101
+ store.add_rate('EUR', 'USD', 1.4)
79
102
  end
80
103
  config.default_bank = Money::Bank::VariableExchange.new(rate_store)
81
104
  end
@@ -86,10 +109,38 @@ end
86
109
  Please file issues and pull requests
87
110
  [on GitHub](https://github.com/sunny/active_currency).
88
111
 
89
- In developemnt, launch specs and code linter by calling:
112
+ ## Development
113
+
114
+ Install:
90
115
 
91
116
  ```sh
92
- BUNDLE_GEMFILE=Gemfile-rails3.2 bundle exec rspec && bundle exec rake
117
+ BUNDLE_GEMFILE=Gemfile-rails6.0 bundle install
118
+ ```
119
+
120
+ Launch specs and linters:
121
+
122
+ ```sh
123
+ BUNDLE_GEMFILE=Gemfile-rails6.0 bin/rake
124
+ ```
125
+
126
+ ## Release
127
+
128
+ Update `CHANGELOG.md`, update version in `lib/active_currency/version.rb`.
129
+
130
+ Then:
131
+
132
+ ```sh
133
+ gem install bundler:1.3.0
134
+ BUNDLE_GEMFILE=Gemfile-rails3.2 bundle update
135
+ BUNDLE_GEMFILE=Gemfile-rails4.2 bundle update
136
+ BUNDLE_GEMFILE=Gemfile-rails5.2 bundle update
137
+
138
+ gem install bundler:2.1.2
139
+ BUNDLE_GEMFILE=Gemfile-rails6.0 bundle update
140
+
141
+ git add CHANGELOG.md lib/active_currency/version.rb Gemfile-rails*.lock
142
+ git commit -m v`ruby -r./lib/active_currency/version <<< 'puts ActiveCurrency::VERSION'`
143
+ bin/rake release
93
144
  ```
94
145
 
95
146
  ## License
@@ -98,3 +149,4 @@ The gem is available as open source under the terms of the
98
149
  [MIT License](http://opensource.org/licenses/MIT).
99
150
 
100
151
  [eu_central_bank]: https://github.com/RubyMoney/eu_central_bank
152
+ [money-open-exchange-rates]: https://github.com/spk/money-open-exchange-rates
@@ -2,18 +2,22 @@
2
2
 
3
3
  module ActiveCurrency
4
4
  class Rate < ActiveRecord::Base
5
- validates :from,
6
- :to,
7
- presence: true
5
+ validates :from, presence: true
6
+ validates :to, presence: true
8
7
  validates :value, numericality: { greater_than: 0 }
9
8
 
10
- scope :before, ->(date) { where(arel_table[:created_at].lt(date)) }
9
+ scope :before, ->(date) {
10
+ where(arel_table[:created_at].lt(date))
11
+ }
11
12
 
12
13
  def self.value_for(from, to, date = nil)
13
- scope = date ? before(date) : all_scope
14
+ from = Money::Currency.new(from)
15
+ to = Money::Currency.new(to)
16
+ return 1 if from == to
14
17
 
18
+ scope = date ? before(date) : all_scope
15
19
  scope
16
- .where(from: from, to: to)
20
+ .where(from: from.iso_code, to: to.iso_code)
17
21
  .order(:created_at)
18
22
  .last
19
23
  &.value
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'active_currency/migration'
4
+
3
5
  class CreateActiveCurrencyRates < ActiveCurrency::Migration
4
6
  def change
5
7
  create_table :active_currency_rates do |t|
@@ -9,6 +11,8 @@ class CreateActiveCurrencyRates < ActiveCurrency::Migration
9
11
  t.datetime :created_at
10
12
  end
11
13
 
12
- add_index :active_currency_rates, %i[from to created_at]
14
+ add_index :active_currency_rates,
15
+ %i[from to created_at],
16
+ name: 'index_active_currency_rates'
13
17
  end
14
18
  end
@@ -3,7 +3,6 @@
3
3
  require 'money-rails'
4
4
  require 'eu_central_bank'
5
5
 
6
- require 'active_currency/migration'
7
6
  require 'active_currency/engine'
8
7
  require 'active_currency/database_store'
9
8
  require 'active_currency/cacheable_store'
@@ -3,36 +3,61 @@
3
3
  module ActiveCurrency
4
4
  # Store the latest currency rates.
5
5
  class AddRates
6
- def initialize(currencies)
7
- @currencies = currencies
6
+ def initialize(currencies, bank: EuCentralBank.new)
7
+ @currencies = currencies.map(&:to_s).map(&:upcase)
8
+ @bank = bank
8
9
  end
9
10
 
10
11
  def call
11
- bank = EuCentralBank.new
12
12
  bank.update_rates
13
13
 
14
- from = 'EUR'
15
- currencies.map(&:to_s).each do |to|
16
- next if to == from
17
-
18
- rate = bank.get_rate(from, to)
14
+ rates_hash.each do |(from, to), rate|
19
15
  store.add_rate(from, to, rate)
20
- store.add_rate(to, from, 1 / rate)
21
16
  end
17
+
18
+ nil
22
19
  end
23
20
 
24
- def self.call(currencies)
25
- new(currencies).call
21
+ def self.call(currencies, *options)
22
+ new(currencies, *options).call
26
23
  end
27
24
 
28
25
  private
29
26
 
30
- def currencies
31
- @currencies.map(&:to_s).map(&:upcase)
32
- end
27
+ attr_accessor :bank, :currencies
33
28
 
34
29
  def store
35
30
  @store ||= ActiveCurrency::RateStore.new
36
31
  end
32
+
33
+ def rates_hash
34
+ currencies.each_with_object({}) do |from, hash|
35
+ currencies.each do |to|
36
+ next if from == to
37
+
38
+ hash[[from, to]] = get_rate(hash, from, to)
39
+ end
40
+ end
41
+ end
42
+
43
+ def get_rate(hash, from, to)
44
+ rate = bank.get_rate(from, to)
45
+ return rate if rate
46
+
47
+ # Inverse rate (not so good)
48
+ inverse = hash[[to, from]]
49
+ return 1.fdiv(inverse) if inverse
50
+
51
+ # Rate going through the first currency (desperate)
52
+ from_main = hash[[from, main_currency]]
53
+ to_main = hash[[main_currency, to]]
54
+ return from_main * to_main if from_main && to_main
55
+
56
+ raise "Unknown rate between #{from} and #{to}"
57
+ end
58
+
59
+ def main_currency
60
+ currencies.first
61
+ end
37
62
  end
38
63
  end
@@ -5,13 +5,13 @@ module ActiveCurrency
5
5
  isolate_namespace ActiveCurrency
6
6
 
7
7
  initializer :append_migrations do |app|
8
- # This prevents migrations from being loaded twice from the inside of the
9
- # gem itself (dummy test app)
10
- if app.root.to_s !~ /#{root}/
11
- config.paths['db/migrate'].expanded.each do |migration_path|
12
- app.config.paths['db/migrate'] << migration_path
13
- end
8
+ next if app.root.to_s.match(root.to_s)
9
+
10
+ paths = ActiveRecord::Migrator.migrations_paths
11
+ config.paths['db/migrate'].expanded.each do |path|
12
+ paths << path
14
13
  end
14
+ paths.uniq!
15
15
  end
16
16
  end
17
17
  end
@@ -2,8 +2,8 @@
2
2
 
3
3
  module ActiveCurrency
4
4
  # Helps support previous version of Rails in migrations.
5
- if Rails.version > '4.1'
6
- class Migration < ActiveRecord::Migration[4.2]; end
5
+ if Rails.version > '5.0'
6
+ class Migration < ActiveRecord::Migration[5.0]; end
7
7
  else
8
8
  class Migration < ActiveRecord::Migration; end
9
9
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveCurrency
4
- VERSION = '1.0.0'
4
+ VERSION = '1.2.1'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_currency
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sunny Ripert
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-02 00:00:00.000000000 Z
11
+ date: 2020-09-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: rspec-rails
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +94,20 @@ dependencies:
80
94
  - - ">="
81
95
  - !ruby/object:Gem::Version
82
96
  version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec_junit_formatter
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
83
111
  - !ruby/object:Gem::Dependency
84
112
  name: timecop
85
113
  requirement: !ruby/object:Gem::Requirement
@@ -122,6 +150,20 @@ dependencies:
122
150
  - - ">="
123
151
  - !ruby/object:Gem::Version
124
152
  version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rubocop-rails
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
125
167
  description: Store your currency.
126
168
  email:
127
169
  - sunny@sunfox.org
@@ -161,8 +203,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
161
203
  - !ruby/object:Gem::Version
162
204
  version: '0'
163
205
  requirements: []
164
- rubyforge_project:
165
- rubygems_version: 2.5.2.3
206
+ rubygems_version: 3.0.3
166
207
  signing_key:
167
208
  specification_version: 4
168
209
  summary: Rails plugin to store your currency regularly