money 6.5.1 → 6.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +209 -5
  3. data/LICENSE +18 -16
  4. data/README.md +321 -70
  5. data/config/currency_backwards_compatible.json +65 -0
  6. data/config/currency_iso.json +280 -94
  7. data/config/currency_non_iso.json +101 -3
  8. data/lib/money/bank/base.rb +1 -3
  9. data/lib/money/bank/variable_exchange.rb +88 -96
  10. data/lib/money/currency/heuristics.rb +1 -143
  11. data/lib/money/currency/loader.rb +15 -13
  12. data/lib/money/currency.rb +98 -81
  13. data/lib/money/locale_backend/base.rb +7 -0
  14. data/lib/money/locale_backend/currency.rb +11 -0
  15. data/lib/money/locale_backend/errors.rb +6 -0
  16. data/lib/money/locale_backend/i18n.rb +25 -0
  17. data/lib/money/locale_backend/legacy.rb +28 -0
  18. data/lib/money/money/allocation.rb +46 -0
  19. data/lib/money/money/arithmetic.rb +97 -52
  20. data/lib/money/money/constructors.rb +5 -6
  21. data/lib/money/money/formatter.rb +399 -0
  22. data/lib/money/money/formatting_rules.rb +142 -0
  23. data/lib/money/money/locale_backend.rb +22 -0
  24. data/lib/money/money.rb +268 -194
  25. data/lib/money/rates_store/memory.rb +120 -0
  26. data/lib/money/version.rb +1 -1
  27. data/money.gemspec +15 -20
  28. metadata +36 -59
  29. data/.coveralls.yml +0 -1
  30. data/.gitignore +0 -22
  31. data/.travis.yml +0 -13
  32. data/AUTHORS +0 -116
  33. data/CONTRIBUTING.md +0 -17
  34. data/Gemfile +0 -7
  35. data/Rakefile +0 -17
  36. data/lib/money/money/formatting.rb +0 -386
  37. data/spec/bank/base_spec.rb +0 -77
  38. data/spec/bank/single_currency_spec.rb +0 -11
  39. data/spec/bank/variable_exchange_spec.rb +0 -275
  40. data/spec/currency/heuristics_spec.rb +0 -84
  41. data/spec/currency_spec.rb +0 -321
  42. data/spec/money/arithmetic_spec.rb +0 -568
  43. data/spec/money/constructors_spec.rb +0 -75
  44. data/spec/money/formatting_spec.rb +0 -667
  45. data/spec/money_spec.rb +0 -745
  46. data/spec/spec_helper.rb +0 -23
@@ -1,17 +1,35 @@
1
1
  {
2
+ "bch": {
3
+ "priority": 100,
4
+ "iso_code": "BCH",
5
+ "name": "Bitcoin Cash",
6
+ "symbol": "₿",
7
+ "disambiguate_symbol": "₿CH",
8
+ "alternate_symbols": ["BCH"],
9
+ "subunit": "Satoshi",
10
+ "subunit_to_unit": 100000000,
11
+ "symbol_first": false,
12
+ "format": "%n %u",
13
+ "html_entity": "₿",
14
+ "decimal_mark": ".",
15
+ "thousands_separator": ",",
16
+ "iso_numeric": "",
17
+ "smallest_denomination": 1
18
+ },
2
19
  "btc": {
3
20
  "priority": 100,
4
21
  "iso_code": "BTC",
5
22
  "name": "Bitcoin",
6
- "symbol": "B⃦",
23
+ "symbol": "",
7
24
  "alternate_symbols": [],
8
25
  "subunit": "Satoshi",
9
26
  "subunit_to_unit": 100000000,
10
27
  "symbol_first": true,
11
- "html_entity": "",
28
+ "html_entity": "₿",
12
29
  "decimal_mark": ".",
13
30
  "thousands_separator": ",",
14
- "iso_numeric": ""
31
+ "iso_numeric": "",
32
+ "smallest_denomination": 1
15
33
  },
16
34
  "jep": {
17
35
  "priority": 100,
@@ -28,5 +46,85 @@
28
46
  "thousands_separator": ",",
29
47
  "iso_numeric": "",
30
48
  "smallest_denomination": 1
49
+ },
50
+ "ggp": {
51
+ "priority": 100,
52
+ "iso_code": "GGP",
53
+ "name": "Guernsey Pound",
54
+ "symbol": "£",
55
+ "disambiguate_symbol": "GGP",
56
+ "alternate_symbols": [],
57
+ "subunit": "Penny",
58
+ "subunit_to_unit": 100,
59
+ "symbol_first": true,
60
+ "html_entity": "£",
61
+ "decimal_mark": ".",
62
+ "thousands_separator": ",",
63
+ "iso_numeric": "",
64
+ "smallest_denomination": 1
65
+ },
66
+ "imp": {
67
+ "priority": 100,
68
+ "iso_code": "IMP",
69
+ "name": "Isle of Man Pound",
70
+ "symbol": "£",
71
+ "disambiguate_symbol": "IMP",
72
+ "alternate_symbols": ["M£"],
73
+ "subunit": "Penny",
74
+ "subunit_to_unit": 100,
75
+ "symbol_first": true,
76
+ "html_entity": "£",
77
+ "decimal_mark": ".",
78
+ "thousands_separator": ",",
79
+ "iso_numeric": "",
80
+ "smallest_denomination": 1
81
+ },
82
+ "xfu": {
83
+ "priority": 100,
84
+ "iso_code": "XFU",
85
+ "name": "UIC Franc",
86
+ "symbol": "",
87
+ "disambiguate_symbol": "XFU",
88
+ "alternate_symbols": [],
89
+ "subunit": "",
90
+ "subunit_to_unit": 100,
91
+ "symbol_first": true,
92
+ "html_entity": "",
93
+ "decimal_mark": ".",
94
+ "thousands_separator": ",",
95
+ "iso_numeric": "",
96
+ "smallest_denomination": ""
97
+ },
98
+ "gbx": {
99
+ "priority": 100,
100
+ "iso_code": "GBX",
101
+ "name": "British Penny",
102
+ "symbol": "",
103
+ "disambiguate_symbol": "GBX",
104
+ "alternate_symbols": [],
105
+ "subunit": "",
106
+ "subunit_to_unit": 1,
107
+ "symbol_first": true,
108
+ "html_entity": "",
109
+ "decimal_mark": ".",
110
+ "thousands_separator": ",",
111
+ "iso_numeric": "",
112
+ "smallest_denomination": 1
113
+ },
114
+ "cnh": {
115
+ "priority": 100,
116
+ "iso_code": "CNH",
117
+ "name": "Chinese Renminbi Yuan Offshore",
118
+ "symbol": "¥",
119
+ "disambiguate_symbol": "CNH",
120
+ "alternate_symbols": ["CN¥", "元", "CN元"],
121
+ "subunit": "Fen",
122
+ "subunit_to_unit": 100,
123
+ "symbol_first": true,
124
+ "html_entity": "¥",
125
+ "decimal_mark": ".",
126
+ "thousands_separator": ",",
127
+ "iso_numeric": "",
128
+ "smallest_denomination": 1
31
129
  }
32
130
  }
@@ -1,5 +1,3 @@
1
- require 'thread'
2
-
3
1
  class Money
4
2
  # Provides classes that aid in the ability of exchange one currency with
5
3
  # another.
@@ -120,7 +118,7 @@ class Money
120
118
  # @example
121
119
  # same_currency?("usd", "USD") #=> true
122
120
  # same_currency?("usd", "EUR") #=> false
123
- # same_currency?("usd", Currency.new("USD") #=> true
121
+ # same_currency?("usd", Currency.new("USD")) #=> true
124
122
  # same_currency?("usd", "USD") #=> true
125
123
  def same_currency?(currency1, currency2)
126
124
  Currency.wrap(currency1) == Currency.wrap(currency2)
@@ -1,4 +1,5 @@
1
1
  require 'money/bank/base'
2
+ require 'money/rates_store/memory'
2
3
  require 'json'
3
4
  require 'yaml'
4
5
 
@@ -15,42 +16,63 @@ class Money
15
16
  # conversion rates. One must manually specify them with +add_rate+, after
16
17
  # which one can perform exchanges with +#exchange_with+.
17
18
  #
19
+ # Exchange rates are stored in memory using +Money::RatesStore::Memory+ by default.
20
+ # Pass custom rates stores for other types of storage (file, database, etc)
21
+ #
18
22
  # @example
19
23
  # bank = Money::Bank::VariableExchange.new
20
24
  # bank.add_rate("USD", "CAD", 1.24515)
21
25
  # bank.add_rate("CAD", "USD", 0.803115)
22
26
  #
23
- # c1 = 100_00.to_money("USD")
24
- # c2 = 100_00.to_money("CAD")
27
+ # c1 = Money.new(100_00, "USD")
28
+ # c2 = Money.new(100_00, "CAD")
25
29
  #
26
30
  # # Exchange 100 USD to CAD:
27
- # bank.exchange_with(c1, "CAD") #=> #<Money @fractional=1245150>
31
+ # bank.exchange_with(c1, "CAD") #=> #<Money fractional:12451 currency:CAD>
28
32
  #
29
33
  # # Exchange 100 CAD to USD:
30
- # bank.exchange_with(c2, "USD") #=> #<Money @fractional=803115>
34
+ # bank.exchange_with(c2, "USD") #=> #<Money fractional:8031 currency:USD>
35
+ #
36
+ # # With custom exchange rates storage
37
+ # redis_store = MyCustomRedisStore.new(host: 'localhost:6379')
38
+ # bank = Money::Bank::VariableExchange.new(redis_store)
39
+ # # Store rates in redis
40
+ # bank.add_rate 'USD', 'CAD', 0.98
41
+ # # Get rate from redis
42
+ # bank.get_rate 'USD', 'CAD'
31
43
  class VariableExchange < Base
32
44
 
33
- attr_reader :rates, :mutex
45
+ attr_reader :mutex
34
46
 
35
47
  # Available formats for importing/exporting rates.
36
- RATE_FORMATS = [:json, :ruby, :yaml]
48
+ RATE_FORMATS = [:json, :ruby, :yaml].freeze
49
+ SERIALIZER_SEPARATOR = '_TO_'.freeze
50
+ FORMAT_SERIALIZERS = {json: JSON, ruby: Marshal, yaml: YAML}.freeze
37
51
 
38
- # Setup rates hash and mutex for rates locking
52
+ # Initializes a new +Money::Bank::VariableExchange+ object.
53
+ # It defaults to using an in-memory, thread safe store instance for
54
+ # storing exchange rates.
39
55
  #
40
- # @return [self]
41
- def setup
42
- @rates = {}
43
- @mutex = Mutex.new
44
- self
56
+ # @param [RateStore] st An exchange rate store, used to persist exchange rate pairs.
57
+ # @yield [n] Optional block to use when rounding after exchanging one
58
+ # currency for another. See +Money::bank::base+
59
+ def initialize(st = Money::RatesStore::Memory.new, &block)
60
+ @store = st
61
+ super(&block)
62
+ end
63
+
64
+ def store
65
+ @store.is_a?(String) ? Object.const_get(@store) : @store
45
66
  end
46
67
 
47
68
  def marshal_dump
48
- [@rates, @rounding_method]
69
+ [store.marshal_dump, @rounding_method]
49
70
  end
50
71
 
51
72
  def marshal_load(arr)
52
- @rates, @rounding_method = arr
53
- @mutex = Mutex.new
73
+ store_info = arr[0]
74
+ @store = store_info.shift.new(*store_info)
75
+ @rounding_method = arr[1]
54
76
  end
55
77
 
56
78
  # Exchanges the given +Money+ object to a new +Money+ object in
@@ -76,14 +98,14 @@ class Money
76
98
  # bank.add_rate("USD", "CAD", 1.24515)
77
99
  # bank.add_rate("CAD", "USD", 0.803115)
78
100
  #
79
- # c1 = 100_00.to_money("USD")
80
- # c2 = 100_00.to_money("CAD")
101
+ # c1 = Money.new(100_00, "USD")
102
+ # c2 = Money.new(100_00, "CAD")
81
103
  #
82
104
  # # Exchange 100 USD to CAD:
83
- # bank.exchange_with(c1, "CAD") #=> #<Money @fractional=1245150>
105
+ # bank.exchange_with(c1, "CAD") #=> #<Money fractional:12451 currency:CAD>
84
106
  #
85
107
  # # Exchange 100 CAD to USD:
86
- # bank.exchange_with(c2, "USD") #=> #<Money @fractional=803115>
108
+ # bank.exchange_with(c2, "USD") #=> #<Money fractional:8031 currency:USD>
87
109
  def exchange_with(from, to_currency, &block)
88
110
  to_currency = Currency.wrap(to_currency)
89
111
  if from.currency == to_currency
@@ -91,8 +113,10 @@ class Money
91
113
  else
92
114
  if rate = get_rate(from.currency, to_currency)
93
115
  fractional = calculate_fractional(from, to_currency)
94
- Money.new(
95
- exchange(fractional, rate, &block), to_currency
116
+ from.dup_with(
117
+ fractional: exchange(fractional, rate, &block),
118
+ currency: to_currency,
119
+ bank: self
96
120
  )
97
121
  else
98
122
  raise UnknownRate, "No conversion rate known for '#{from.currency.iso_code}' -> '#{to_currency}'"
@@ -101,24 +125,25 @@ class Money
101
125
  end
102
126
 
103
127
  def calculate_fractional(from, to_currency)
104
- BigDecimal.new(from.fractional.to_s) / (
105
- BigDecimal.new(from.currency.subunit_to_unit.to_s) /
106
- BigDecimal.new(to_currency.subunit_to_unit.to_s)
128
+ BigDecimal(from.fractional.to_s) / (
129
+ BigDecimal(from.currency.subunit_to_unit.to_s) /
130
+ BigDecimal(to_currency.subunit_to_unit.to_s)
107
131
  )
108
132
  end
109
133
 
110
134
  def exchange(fractional, rate, &block)
111
- ex = (fractional * BigDecimal.new(rate.to_s)).to_f
135
+ ex = fractional * BigDecimal(rate.to_s)
112
136
  if block_given?
113
137
  yield ex
114
138
  elsif @rounding_method
115
139
  @rounding_method.call(ex)
116
140
  else
117
- ex.to_s.to_i
141
+ ex
118
142
  end
119
143
  end
120
144
 
121
145
  # Registers a conversion rate and returns it (uses +#set_rate+).
146
+ # Delegates to +Money::RatesStore::Memory+
122
147
  #
123
148
  # @param [Currency, String, Symbol] from Currency to exchange from.
124
149
  # @param [Currency, String, Symbol] to Currency to exchange to.
@@ -134,14 +159,14 @@ class Money
134
159
  set_rate(from, to, rate)
135
160
  end
136
161
 
137
- # Set the rate for the given currencies. Uses +Mutex+ to synchronize data
162
+ # Set the rate for the given currencies.
138
163
  # access.
164
+ # Delegates to +Money::RatesStore::Memory+
139
165
  #
140
166
  # @param [Currency, String, Symbol] from Currency to exchange from.
141
167
  # @param [Currency, String, Symbol] to Currency to exchange to.
142
168
  # @param [Numeric] rate Rate to use when exchanging currencies.
143
- # @param [Hash] opts Options hash to set special parameters
144
- # @option opts [Boolean] :without_mutex disables the usage of a mutex
169
+ # @param [Hash] opts Options hash to set special parameters. Backwards compatibility only.
145
170
  #
146
171
  # @return [Numeric]
147
172
  #
@@ -150,21 +175,16 @@ class Money
150
175
  # bank.set_rate("USD", "CAD", 1.24515)
151
176
  # bank.set_rate("CAD", "USD", 0.803115)
152
177
  def set_rate(from, to, rate, opts = {})
153
- fn = -> { @rates[rate_key_for(from, to)] = rate }
154
- if opts[:without_mutex]
155
- fn.call
156
- else
157
- @mutex.synchronize { fn.call }
158
- end
178
+ store.add_rate(Currency.wrap(from).iso_code, Currency.wrap(to).iso_code, rate)
159
179
  end
160
180
 
161
- # Retrieve the rate for the given currencies. Uses +Mutex+ to synchronize
181
+ # Retrieve the rate for the given currencies.
162
182
  # data access.
183
+ # Delegates to +Money::RatesStore::Memory+
163
184
  #
164
185
  # @param [Currency, String, Symbol] from Currency to exchange from.
165
186
  # @param [Currency, String, Symbol] to Currency to exchange to.
166
- # @param [Hash] opts Options hash to set special parameters
167
- # @option opts [Boolean] :without_mutex disables the usage of a mutex
187
+ # @param [Hash] opts Options hash to set special parameters. Backwards compatibility only.
168
188
  #
169
189
  # @return [Numeric]
170
190
  #
@@ -176,12 +196,7 @@ class Money
176
196
  # bank.get_rate("USD", "CAD") #=> 1.24515
177
197
  # bank.get_rate("CAD", "USD") #=> 0.803115
178
198
  def get_rate(from, to, opts = {})
179
- fn = -> { @rates[rate_key_for(from, to)] }
180
- if opts[:without_mutex]
181
- fn.call
182
- else
183
- @mutex.synchronize { fn.call }
184
- end
199
+ store.get_rate(Currency.wrap(from).iso_code, Currency.wrap(to).iso_code)
185
200
  end
186
201
 
187
202
  # Return the known rates as a string in the format specified. If +file+
@@ -190,8 +205,7 @@ class Money
190
205
  #
191
206
  # @param [Symbol] format Request format for the resulting string.
192
207
  # @param [String] file Optional file location to write the rates to.
193
- # @param [Hash] opts Options hash to set special parameters
194
- # @option opts [Boolean] :without_mutex disables the usage of a mutex
208
+ # @param [Hash] opts Options hash to set special parameters. Backwards compatibility only.
195
209
  #
196
210
  # @return [String]
197
211
  #
@@ -205,39 +219,33 @@ class Money
205
219
  # s = bank.export_rates(:json)
206
220
  # s #=> "{\"USD_TO_CAD\":1.24515,\"CAD_TO_USD\":0.803115}"
207
221
  def export_rates(format, file = nil, opts = {})
208
- raise Money::Bank::UnknownRateFormat unless
209
- RATE_FORMATS.include? format
222
+ raise Money::Bank::UnknownRateFormat unless RATE_FORMATS.include?(format)
210
223
 
211
- s = ""
212
- fn = -> {
213
- s = case format
214
- when :json
215
- JSON.dump(@rates)
216
- when :ruby
217
- Marshal.dump(@rates)
218
- when :yaml
219
- YAML.dump(@rates)
220
- end
224
+ store.transaction do
225
+ s = FORMAT_SERIALIZERS[format].dump(rates)
221
226
 
222
227
  unless file.nil?
223
228
  File.open(file, "w") {|f| f.write(s) }
224
229
  end
225
- }
226
- if opts[:without_mutex]
227
- fn.call
228
- else
229
- @mutex.synchronize { fn.call }
230
+
231
+ s
232
+ end
233
+ end
234
+
235
+ # This should be deprecated.
236
+ def rates
237
+ store.each_rate.each_with_object({}) do |(from,to,rate),hash|
238
+ hash[[from, to].join(SERIALIZER_SEPARATOR)] = rate
230
239
  end
231
- s
232
240
  end
233
241
 
234
242
  # Loads rates provided in +s+ given the specified format. Available
235
243
  # formats are +:json+, +:ruby+ and +:yaml+.
244
+ # Delegates to +Money::RatesStore::Memory+
236
245
  #
237
246
  # @param [Symbol] format The format of +s+.
238
247
  # @param [String] s The rates string.
239
- # @param [Hash] opts Options hash to set special parameters
240
- # @option opts [Boolean] :without_mutex disables the usage of a mutex
248
+ # @param [Hash] opts Options hash to set special parameters. Backwards compatibility only.
241
249
  #
242
250
  # @return [self]
243
251
  #
@@ -251,40 +259,24 @@ class Money
251
259
  # bank.get_rate("USD", "CAD") #=> 1.24515
252
260
  # bank.get_rate("CAD", "USD") #=> 0.803115
253
261
  def import_rates(format, s, opts = {})
254
- raise Money::Bank::UnknownRateFormat unless
255
- RATE_FORMATS.include? format
262
+ raise Money::Bank::UnknownRateFormat unless RATE_FORMATS.include?(format)
256
263
 
257
- fn = -> {
258
- @rates = case format
259
- when :json
260
- JSON.load(s)
261
- when :ruby
262
- Marshal.load(s)
263
- when :yaml
264
- YAML.load(s)
265
- end
266
- }
267
- if opts[:without_mutex]
268
- fn.call
269
- else
270
- @mutex.synchronize { fn.call }
264
+ if format == :ruby
265
+ warn '[WARNING] Using :ruby format when importing rates is potentially unsafe and ' \
266
+ 'might lead to remote code execution via Marshal.load deserializer. Consider using ' \
267
+ 'safe alternatives such as :json and :yaml.'
271
268
  end
272
- self
273
- end
274
269
 
275
- private
270
+ store.transaction do
271
+ data = FORMAT_SERIALIZERS[format].load(s)
276
272
 
277
- # Return the rate hashkey for the given currencies.
278
- #
279
- # @param [Currency, String, Symbol] from The currency to exchange from.
280
- # @param [Currency, String, Symbol] to The currency to exchange to.
281
- #
282
- # @return [String]
283
- #
284
- # @example
285
- # rate_key_for("USD", "CAD") #=> "USD_TO_CAD"
286
- def rate_key_for(from, to)
287
- "#{Currency.wrap(from).iso_code}_TO_#{Currency.wrap(to).iso_code}".upcase
273
+ data.each do |key, rate|
274
+ from, to = key.split(SERIALIZER_SEPARATOR)
275
+ store.add_rate from, to, rate
276
+ end
277
+ end
278
+
279
+ self
288
280
  end
289
281
  end
290
282
  end
@@ -3,150 +3,8 @@
3
3
  class Money
4
4
  class Currency
5
5
  module Heuristics
6
-
7
- # An robust and efficient algorithm for finding currencies in
8
- # text. Using several algorithms it can find symbols, iso codes and
9
- # even names of currencies.
10
- # Although not recommendable, it can also attempt to find the given
11
- # currency in an entire sentence
12
- #
13
- # Returns: Array (matched results)
14
6
  def analyze(str)
15
- return Analyzer.new(str, search_tree).process
16
- end
17
-
18
- private
19
-
20
- # Build a search tree from the currency database
21
- def search_tree
22
- @_search_tree ||= {
23
- :by_symbol => currencies_by_symbol,
24
- :by_iso_code => currencies_by_iso_code,
25
- :by_name => currencies_by_name
26
- }
27
- end
28
-
29
- def currencies_by_symbol
30
- {}.tap do |r|
31
- table.each do |dummy, c|
32
- symbol = (c[:symbol]||"").downcase
33
- symbol.chomp!('.')
34
- (r[symbol] ||= []) << c
35
-
36
- (c[:alternate_symbols]||[]).each do |ac|
37
- ac = ac.downcase
38
- ac.chomp!('.')
39
- (r[ac] ||= []) << c
40
- end
41
- end
42
- end
43
- end
44
-
45
- def currencies_by_iso_code
46
- {}.tap do |r|
47
- table.each do |dummy,c|
48
- (r[c[:iso_code].downcase] ||= []) << c
49
- end
50
- end
51
- end
52
-
53
- def currencies_by_name
54
- {}.tap do |r|
55
- table.each do |dummy,c|
56
- name_parts = c[:name].downcase.split
57
- name_parts.each {|part| part.chomp!('.')}
58
-
59
- # construct one branch per word
60
- root = r
61
- while name_part = name_parts.shift
62
- root = (root[name_part] ||= {})
63
- end
64
-
65
- # the leaf is a currency
66
- (root[:value] ||= []) << c
67
- end
68
- end
69
- end
70
-
71
- class Analyzer
72
- attr_reader :search_tree, :words
73
- attr_accessor :str, :currencies
74
-
75
- def initialize str, search_tree
76
- @str = (str||'').dup
77
- @search_tree = search_tree
78
- @currencies = []
79
- end
80
-
81
- def process
82
- format
83
- return [] if str.empty?
84
-
85
- search_by_symbol
86
- search_by_iso_code
87
- search_by_name
88
-
89
- prepare_reply
90
- end
91
-
92
- def format
93
- str.gsub!(/[\r\n\t]/,'')
94
- str.gsub!(/[0-9][\.,:0-9]*[0-9]/,'')
95
- str.gsub!(/[0-9]/, '')
96
- str.downcase!
97
- @words = str.split
98
- @words.each {|word| word.chomp!('.'); word.chomp!(',') }
99
- end
100
-
101
- def search_by_symbol
102
- words.each do |word|
103
- if found = search_tree[:by_symbol][word]
104
- currencies.concat(found)
105
- end
106
- end
107
- end
108
-
109
- def search_by_iso_code
110
- words.each do |word|
111
- if found = search_tree[:by_iso_code][word]
112
- currencies.concat(found)
113
- end
114
- end
115
- end
116
-
117
- def search_by_name
118
- # remember, the search tree by name is a construct of branches and leaf!
119
- # We need to try every combination of words within the sentence, so we
120
- # end up with a x^2 equation, which should be fine as most names are either
121
- # one or two words, and this is multiplied with the words of given sentence
122
-
123
- search_words = words.dup
124
-
125
- while search_words.length > 0
126
- root = search_tree[:by_name]
127
-
128
- search_words.each do |word|
129
- if root = root[word]
130
- if root[:value]
131
- currencies.concat(root[:value])
132
- end
133
- else
134
- break
135
- end
136
- end
137
-
138
- search_words.delete_at(0)
139
- end
140
- end
141
-
142
- def prepare_reply
143
- codes = currencies.map do |currency|
144
- currency[:iso_code]
145
- end
146
- codes.uniq!
147
- codes.sort!
148
- codes
149
- end
7
+ raise StandardError, 'Heuristics deprecated, add `gem "money-heuristics"` to Gemfile'
150
8
  end
151
9
  end
152
10
  end
@@ -3,21 +3,23 @@ class Money
3
3
  module Loader
4
4
  DATA_PATH = File.expand_path("../../../../config", __FILE__)
5
5
 
6
- # Loads and returns the currencies stored in JSON files in the config directory.
7
- #
8
- # @return [Hash]
9
- def load_currencies
10
- currencies = parse_currency_file("currency_iso.json")
11
- currencies.merge! parse_currency_file("currency_non_iso.json")
12
- currencies.merge! parse_currency_file("currency_backwards_compatible.json")
13
- end
6
+ class << self
7
+ # Loads and returns the currencies stored in JSON files in the config directory.
8
+ #
9
+ # @return [Hash]
10
+ def load_currencies
11
+ currencies = parse_currency_file("currency_iso.json")
12
+ currencies.merge! parse_currency_file("currency_non_iso.json")
13
+ currencies.merge! parse_currency_file("currency_backwards_compatible.json")
14
+ end
14
15
 
15
- private
16
+ private
16
17
 
17
- def parse_currency_file(filename)
18
- json = File.read("#{DATA_PATH}/#{filename}")
19
- json.force_encoding(::Encoding::UTF_8) if defined?(::Encoding)
20
- JSON.parse(json, :symbolize_names => true)
18
+ def parse_currency_file(filename)
19
+ json = File.read("#{DATA_PATH}/#{filename}")
20
+ json.force_encoding(::Encoding::UTF_8) if defined?(::Encoding)
21
+ JSON.parse(json, symbolize_names: true)
22
+ end
21
23
  end
22
24
  end
23
25
  end