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.
- checksums.yaml +7 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +19 -0
- data/.travis.yml +11 -0
- data/AUTHORS +101 -0
- data/CHANGELOG.md +6 -0
- data/CONTRIBUTING.md +17 -0
- data/Gemfile +6 -0
- data/README.md +9 -10
- data/Rakefile +4 -45
- data/config/currency_iso.json +1 -1
- data/lib/money/bank/variable_exchange.rb +67 -28
- data/lib/money/core_extensions/numeric.rb +7 -0
- data/lib/money/core_extensions/string.rb +13 -0
- data/lib/money/core_extensions/symbol.rb +7 -0
- data/lib/money/core_extensions.rb +5 -78
- data/lib/money/currency/heuristics.rb +121 -117
- data/lib/money/currency/loader.rb +19 -17
- data/lib/money/currency.rb +91 -101
- data/lib/money/deprecations.rb +6 -1
- data/lib/money/money/arithmetic.rb +45 -31
- data/lib/money/money/formatting.rb +41 -55
- data/lib/money/money/parsing.rb +14 -344
- data/lib/money/money.rb +167 -143
- data/lib/money/version.rb +3 -0
- data/lib/money.rb +4 -2
- data/money.gemspec +25 -23
- data/spec/bank/variable_exchange_spec.rb +42 -0
- data/spec/core_extensions_spec.rb +2 -2
- data/spec/currency_spec.rb +16 -0
- data/spec/money/deprecations_spec.rb +51 -0
- data/spec/money/parsing_spec.rb +3 -6
- data/spec/money_spec.rb +75 -9
- data/spec/spec_helper.rb +7 -4
- metadata +120 -65
|
@@ -1,149 +1,153 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
18
|
+
private
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
64
|
-
|
|
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
|
-
|
|
80
|
-
|
|
81
|
-
|
|
71
|
+
class Analyzer
|
|
72
|
+
attr_reader :search_tree, :words
|
|
73
|
+
attr_accessor :str, :currencies
|
|
82
74
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
75
|
+
def initialize str, search_tree
|
|
76
|
+
@str = (str||'').dup
|
|
77
|
+
@search_tree = search_tree
|
|
78
|
+
@currencies = []
|
|
79
|
+
end
|
|
86
80
|
|
|
87
|
-
|
|
88
|
-
|
|
81
|
+
def process
|
|
82
|
+
format
|
|
83
|
+
return [] if str.empty?
|
|
89
84
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
-
|
|
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
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
-
|
|
127
|
-
|
|
128
|
-
if
|
|
129
|
-
currencies.concat(
|
|
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
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
2
|
-
|
|
1
|
+
class Money
|
|
2
|
+
class Currency
|
|
3
|
+
module Loader
|
|
4
|
+
DATA_PATH = File.expand_path("../../../../config", __FILE__)
|
|
3
5
|
|
|
4
|
-
|
|
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
|
-
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
data/lib/money/currency.rb
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
|
|
3
|
-
require
|
|
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
|
-
|
|
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)
|
|
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)
|
|
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,
|
|
132
|
-
# +iso_code+ attribute.
|
|
133
|
-
#
|
|
134
|
-
#
|
|
135
|
-
attr_reader
|
|
136
|
-
|
|
137
|
-
#
|
|
138
|
-
#
|
|
139
|
-
# @
|
|
140
|
-
attr_reader
|
|
141
|
-
|
|
142
|
-
#
|
|
143
|
-
#
|
|
144
|
-
#
|
|
145
|
-
# @
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
#
|
|
149
|
-
#
|
|
150
|
-
#
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
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
|
|
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
|
data/lib/money/deprecations.rb
CHANGED
|
@@ -5,6 +5,11 @@ class Money
|
|
|
5
5
|
#
|
|
6
6
|
# @return [nil]
|
|
7
7
|
def self.deprecate(message)
|
|
8
|
-
|
|
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
|