money 6.0.0 → 6.0.1

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.
@@ -1,149 +1,153 @@
1
1
  # encoding: utf-8
2
2
 
3
- module Money::Currency::Heuristics
4
-
5
- # An robust and efficient algorithm for finding currencies in
6
- # text. Using several algorithms it can find symbols, iso codes and
7
- # even names of currencies.
8
- # Although not recommendable, it can also attempt to find the given
9
- # currency in an entire sentence
10
- #
11
- # Returns: Array (matched results)
12
- def analyze(str)
13
- return Analyzer.new(str, search_tree).process
14
- end
3
+ class Money
4
+ class Currency
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
+ def analyze(str)
15
+ return Analyzer.new(str, search_tree).process
16
+ end
15
17
 
16
- private
18
+ private
17
19
 
18
- # Build a search tree from the currency database
19
- def search_tree
20
- @_search_tree ||= {
21
- :by_symbol => currencies_by_symbol,
22
- :by_iso_code => currencies_by_iso_code,
23
- :by_name => currencies_by_name
24
- }
25
- end
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
26
28
 
27
- def currencies_by_symbol
28
- {}.tap do |r|
29
- table.each do |dummy, c|
30
- symbol = (c[:symbol]||"").downcase
31
- symbol.chomp!('.')
32
- (r[symbol] ||= []) << c
33
-
34
- (c[:alternate_symbols]||[]).each do |ac|
35
- ac = ac.downcase
36
- ac.chomp!('.')
37
- (r[ac] ||= []) << c
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
38
42
  end
39
43
  end
40
- end
41
- end
42
44
 
43
- def currencies_by_iso_code
44
- {}.tap do |r|
45
- table.each do |dummy,c|
46
- (r[c[:iso_code].downcase] ||= []) << c
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
47
51
  end
48
- end
49
- end
50
52
 
51
- def currencies_by_name
52
- {}.tap do |r|
53
- table.each do |dummy,c|
54
- name_parts = c[:name].downcase.split
55
- name_parts.each {|part| part.chomp!('.')}
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!('.')}
56
58
 
57
- # construct one branch per word
58
- root = r
59
- while name_part = name_parts.shift
60
- root = (root[name_part] ||= {})
61
- end
59
+ # construct one branch per word
60
+ root = r
61
+ while name_part = name_parts.shift
62
+ root = (root[name_part] ||= {})
63
+ end
62
64
 
63
- # the leaf is a currency
64
- (root[:value] ||= []) << c
65
+ # the leaf is a currency
66
+ (root[:value] ||= []) << c
67
+ end
68
+ end
65
69
  end
66
- end
67
- end
68
-
69
- class Analyzer
70
- attr_reader :search_tree, :words
71
- attr_accessor :str, :currencies
72
-
73
- def initialize str, search_tree
74
- @str = (str||'').dup
75
- @search_tree = search_tree
76
- @currencies = []
77
- end
78
70
 
79
- def process
80
- format
81
- return [] if str.empty?
71
+ class Analyzer
72
+ attr_reader :search_tree, :words
73
+ attr_accessor :str, :currencies
82
74
 
83
- search_by_symbol
84
- search_by_iso_code
85
- search_by_name
75
+ def initialize str, search_tree
76
+ @str = (str||'').dup
77
+ @search_tree = search_tree
78
+ @currencies = []
79
+ end
86
80
 
87
- prepare_reply
88
- end
81
+ def process
82
+ format
83
+ return [] if str.empty?
89
84
 
90
- def format
91
- str.gsub!(/[\r\n\t]/,'')
92
- str.gsub!(/[0-9][\.,:0-9]*[0-9]/,'')
93
- str.gsub!(/[0-9]/, '')
94
- str.downcase!
95
- @words = str.split
96
- @words.each {|word| word.chomp!('.'); word.chomp!(',') }
97
- end
85
+ search_by_symbol
86
+ search_by_iso_code
87
+ search_by_name
98
88
 
99
- def search_by_symbol
100
- words.each do |word|
101
- if found = search_tree[:by_symbol][word]
102
- currencies.concat(found)
89
+ prepare_reply
103
90
  end
104
- end
105
- end
106
91
 
107
- def search_by_iso_code
108
- words.each do |word|
109
- if found = search_tree[:by_iso_code][word]
110
- currencies.concat(found)
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!(',') }
111
99
  end
112
- end
113
- end
114
-
115
- def search_by_name
116
- # remember, the search tree by name is a construct of branches and leaf!
117
- # We need to try every combination of words within the sentence, so we
118
- # end up with a x^2 equation, which should be fine as most names are either
119
- # one or two words, and this is multiplied with the words of given sentence
120
100
 
121
- search_words = words.dup
122
-
123
- while search_words.length > 0
124
- root = search_tree[:by_name]
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
125
108
 
126
- search_words.each do |word|
127
- if root = root[word]
128
- if root[:value]
129
- currencies.concat(root[:value])
109
+ def search_by_iso_code
110
+ words.each do |word|
111
+ if found = search_tree[:by_iso_code][word]
112
+ currencies.concat(found)
130
113
  end
131
- else
132
- break
133
114
  end
134
115
  end
135
116
 
136
- search_words.delete_at(0)
137
- end
138
- end
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
139
137
 
140
- def prepare_reply
141
- codes = currencies.map do |currency|
142
- currency[:iso_code]
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
143
150
  end
144
- codes.uniq!
145
- codes.sort!
146
- codes
147
151
  end
148
152
  end
149
153
  end
@@ -1,22 +1,24 @@
1
- module Money::Currency::Loader
2
- extend self
1
+ class Money
2
+ class Currency
3
+ module Loader
4
+ DATA_PATH = File.expand_path("../../../../config", __FILE__)
3
5
 
4
- DATA_PATH = File.expand_path("../../../../config", __FILE__)
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
5
14
 
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
14
-
15
- private
15
+ private
16
16
 
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)
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)
21
+ end
22
+ end
21
23
  end
22
24
  end
@@ -1,20 +1,19 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'json'
3
+ require "json"
4
+ require "money/currency/loader"
5
+ require "money/currency/heuristics"
4
6
 
5
7
  class Money
6
8
 
7
9
  # Represents a specific currency unit.
8
10
  #
9
11
  # @see http://en.wikipedia.org/wiki/Currency
12
+ # @see http://iso4217.net/
10
13
  class Currency
11
14
  include Comparable
12
-
13
- require "money/currency/loader"
14
- extend Loader
15
-
16
- require "money/currency/heuristics"
17
- extend Heuristics
15
+ extend Money::Currency::Loader
16
+ extend Money::Currency::Heuristics
18
17
 
19
18
  # Thrown when an unknown currency is requested.
20
19
  class UnknownCurrency < StandardError; end
@@ -34,7 +33,9 @@ class Money
34
33
  # Money::Currency.find(:foo) #=> nil
35
34
  def find(id)
36
35
  id = id.to_s.downcase.to_sym
37
- new(id) if self.table[id]
36
+ new(id)
37
+ rescue UnknownCurrency
38
+ nil
38
39
  end
39
40
 
40
41
  # Lookup a currency with given +num+ as an ISO 4217 numeric and returns an
@@ -51,7 +52,9 @@ class Money
51
52
  def find_by_iso_numeric(num)
52
53
  num = num.to_s
53
54
  id, _ = self.table.find{|key, currency| currency[:iso_numeric] == num}
54
- new(id) if self.table[id]
55
+ new(id)
56
+ rescue UnknownCurrency
57
+ nil
55
58
  end
56
59
 
57
60
  # Wraps the object in a +Currency+ unless it's already a +Currency+
@@ -68,9 +71,7 @@ class Money
68
71
  # Money::Currency.wrap(c1) #=> #<Money::Currency id: usd ...>
69
72
  # Money::Currency.wrap("usd") #=> #<Money::Currency id: usd ...>
70
73
  def wrap(object)
71
- if object.nil?
72
- nil
73
- elsif object.is_a?(Currency)
74
+ if object.nil? || object.is_a?(Currency)
74
75
  object
75
76
  else
76
77
  Currency.new(object)
@@ -128,71 +129,33 @@ class Money
128
129
  end
129
130
  end
130
131
 
131
- # The symbol used to identify the currency, usually the lowercase
132
- # +iso_code+ attribute.
133
- #
134
- # @return [Symbol]
135
- attr_reader :id
136
-
137
- # A numerical value you can use to sort/group the currency list.
138
- #
139
- # @return [Integer]
140
- attr_reader :priority
141
-
142
- # The international 3-letter code as defined by the ISO 4217 standard.
143
- #
144
- # @return [String]
145
- # @see http://iso4217.net/
146
- attr_reader :iso_code
147
-
148
- #
149
- # The international 3-numeric code as defined by the ISO 4217 standard.
150
- #
151
- # @return [String]
152
- # @see http://iso4217.net/
153
- attr_reader :iso_numeric
154
-
155
- # The currency name.
156
- #
157
- # @return [String]
158
- attr_reader :name
159
-
160
- # The currency symbol (UTF-8 encoded).
161
- #
162
- # @return [String]
163
- attr_reader :symbol
164
-
165
- # The html entity for the currency symbol
166
- #
167
- # @return [String]
168
- attr_reader :html_entity
169
-
170
- # The name of the fractional monetary unit.
171
- #
172
- # @return [String]
173
- attr_reader :subunit
174
-
175
- # The proportion between the unit and the subunit
176
- #
177
- # @return [Integer]
178
- attr_reader :subunit_to_unit
179
-
180
- # The decimal mark, or character used to separate the whole unit from the subunit.
181
- #
182
- # @return [String]
183
- attr_reader :decimal_mark
184
- alias :separator :decimal_mark
185
-
186
- # The character used to separate thousands grouping of the whole unit.
187
- #
188
- # @return [String]
189
- attr_reader :thousands_separator
190
- alias :delimiter :thousands_separator
191
-
192
- # Should the currency symbol precede the amount, or should it come after?
193
- #
194
- # @return [Boolean]
195
- attr_reader :symbol_first
132
+ # @attr_reader [Symbol] id The symbol used to identify the currency,
133
+ # usually the lowercase +iso_code+ attribute.
134
+ # @attr_reader [Integer] priority A numerical value you can use to
135
+ # sort/group the currency list.
136
+ # @attr_reader [String] iso_code The international 3-letter code as defined
137
+ # by the ISO 4217 standard.
138
+ # @attr_reader [String] iso_numeric The international 3-numeric code as
139
+ # defined by the ISO 4217 standard.
140
+ # @attr_reader [String] name The currency name.
141
+ # @attr_reader [String] symbol The currency symbol (UTF-8 encoded).
142
+ # @attr_reader [String] html_entity The html entity for the currency symbol
143
+ # @attr_reader [String] subunit The name of the fractional monetary unit.
144
+ # @attr_reader [Integer] subunit_to_unit The proportion between the unit
145
+ # and the subunit
146
+ # @attr_reader [String] decimal_mark The decimal mark, or character used to
147
+ # separate the whole unit from the subunit.
148
+ # @attr_reader [String] The character used to separate thousands grouping
149
+ # of the whole unit.
150
+ # @attr_reader [Boolean] symbol_first Should the currency symbol precede
151
+ # the amount, or should it come after?
152
+
153
+ attr_reader :id, :priority, :iso_code, :iso_numeric, :name, :symbol,
154
+ :html_entity, :subunit, :subunit_to_unit, :decimal_mark,
155
+ :thousands_separator, :symbol_first
156
+
157
+ alias_method :separator, :decimal_mark
158
+ alias_method :delimiter, :thousands_separator
196
159
 
197
160
  # Create a new +Currency+ object.
198
161
  #
@@ -205,12 +168,15 @@ class Money
205
168
  # Money::Currency.new(:usd) #=> #<Money::Currency id: usd ...>
206
169
  def initialize(id)
207
170
  id = id.to_s.downcase
208
- raise(UnknownCurrency, "Unknown currency `#{id}'") unless self.class.stringified_keys.include?(id)
209
171
 
210
- @id = id.to_sym
211
- data = self.class.table[@id]
212
- data.each_pair do |key, value|
213
- instance_variable_set(:"@#{key}", value)
172
+ if self.class.stringified_keys.include?(id)
173
+ @id = id.to_sym
174
+ data = self.class.table[@id]
175
+ data.each_pair do |key, value|
176
+ instance_variable_set(:"@#{key}", value)
177
+ end
178
+ else
179
+ raise UnknownCurrency, "Unknown currency '#{id}'"
214
180
  end
215
181
  end
216
182
 
@@ -244,10 +210,19 @@ class Money
244
210
  # c1 == c1 #=> true
245
211
  # c1 == c2 #=> false
246
212
  def ==(other_currency)
247
- self.equal?(other_currency) ||
248
- self.id.to_s.downcase == (other_currency.is_a?(Currency) ? other_currency.id.to_s.downcase : other_currency.to_s.downcase)
213
+ self.equal?(other_currency) || compare_ids(other_currency)
249
214
  end
250
215
 
216
+ def compare_ids(other_currency)
217
+ other_currency_id = if other_currency.is_a?(Currency)
218
+ other_currency.id.to_s.downcase
219
+ else
220
+ other_currency.to_s.downcase
221
+ end
222
+ self.id.to_s.downcase == other_currency_id
223
+ end
224
+ private :compare_ids
225
+
251
226
  # Compares +self+ with +other_currency+ and returns +true+ if the are the
252
227
  # same or if their +id+ attributes match.
253
228
  #
@@ -288,7 +263,7 @@ class Money
288
263
  # Returns a string representation corresponding to the upcase +id+
289
264
  # attribute.
290
265
  #
291
- # -–
266
+ # --
292
267
  # DEV: id.to_s.upcase corresponds to iso_code but don't use ISO_CODE for consistency.
293
268
  #
294
269
  # @return [String]
@@ -300,6 +275,30 @@ class Money
300
275
  id.to_s.upcase
301
276
  end
302
277
 
278
+ # Returns a string representation corresponding to the upcase +id+
279
+ # attribute. Useful in cases where only implicit conversions are made.
280
+ #
281
+ # @return [String]
282
+ #
283
+ # @example
284
+ # Money::Currency.new(:usd).to_str #=> "USD"
285
+ # Money::Currency.new(:eur).to_str #=> "EUR"
286
+ def to_str
287
+ id.to_s.upcase
288
+ end
289
+
290
+ # Returns a symbol representation corresponding to the upcase +id+
291
+ # attribute.
292
+ #
293
+ # @return [Symbol]
294
+ #
295
+ # @example
296
+ # Money::Currency.new(:usd).to_sym #=> :USD
297
+ # Money::Currency.new(:eur).to_sym #=> :EUR
298
+ def to_sym
299
+ id.to_s.upcase.to_sym
300
+ end
301
+
303
302
  # Conversation to +self+.
304
303
  #
305
304
  # @return [self]
@@ -307,7 +306,6 @@ class Money
307
306
  self
308
307
  end
309
308
 
310
-
311
309
  # Returns currency symbol or iso code for currencies with no symbol.
312
310
  #
313
311
  # @return [String]
@@ -328,31 +326,24 @@ class Money
328
326
 
329
327
  # Cache decimal places for subunit_to_unit values. Common ones pre-cached.
330
328
  def self.decimal_places_cache
331
- @decimal_places_cache ||= {
332
- 1 => 0,
333
- 10 => 1,
334
- 100 => 2,
335
- 1000 => 3
336
- }
329
+ @decimal_places_cache ||= {1 => 0, 10 => 1, 100 => 2, 1000 => 3}
337
330
  end
338
331
 
339
332
  # The number of decimal places needed.
340
333
  #
341
334
  # @return [Integer]
342
335
  def decimal_places
343
- cache = self.class.decimal_places_cache
344
- places = cache[subunit_to_unit]
345
- unless places
346
- places = calculate_decimal_places(subunit_to_unit)
347
- cache[subunit_to_unit] = places
348
- end
349
- places
336
+ cache[subunit_to_unit] ||= calculate_decimal_places(subunit_to_unit)
350
337
  end
351
338
 
339
+ def cache
340
+ self.class.decimal_places_cache
341
+ end
342
+ private :cache
343
+
352
344
  # If we need to figure out how many decimal places we need we
353
345
  # use repeated integer division.
354
346
  def calculate_decimal_places(num)
355
- return 0 if num == 1
356
347
  i = 1
357
348
  while num >= 10
358
349
  num /= 10
@@ -361,6 +352,5 @@ class Money
361
352
  i
362
353
  end
363
354
  private :calculate_decimal_places
364
-
365
355
  end
366
356
  end
@@ -5,6 +5,11 @@ class Money
5
5
  #
6
6
  # @return [nil]
7
7
  def self.deprecate(message)
8
- warn "DEPRECATION WARNING: #{message}"
8
+ unless Money.silence_core_extensions_deprecations
9
+ file, line = caller(2).first.split(':', 2)
10
+ line = line.to_i
11
+
12
+ warn "DEPRECATION WARNING: #{message} (called from: #{file}:#{line})"
13
+ end
9
14
  end
10
15
  end