money 5.1.1 → 6.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 88dd59a388f0deda85a64606f284c552825752ee
4
+ data.tar.gz: 95521d4753cb2dd4d03d8f17860b65457c96e40b
5
+ SHA512:
6
+ metadata.gz: 29413cd78ec039b35a772c0c12b1161b023f83a5fd4ce6ec54e30fd11709a1ab58e457f476a59e5bdd757bc144c44d8b2a321a08240037763a1fc3d2ca2afad4
7
+ data.tar.gz: 9b08dea3b163c0c655454143adb0f59d865de445b7b9cc328a3679069de4ab945d49efe8c0ff648b5619a79278c21bab1aef4dab4aed5895d2be1400955156c6
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## master
4
+ - Fix typo
5
+ - Wrap the currency symbol in a span if :html is specified in the rules
6
+ - Added Money::Currency.all method
7
+ - Allow combined comparison operator to handle zero values without rates
8
+ - Added Money::Currency.unregister method
9
+ - Works on Ruby 1.8.7
10
+ - Update deps
11
+ - Depreciate Money.parse
12
+
3
13
  ## 5.1.1
4
14
 
5
15
  - Added :sign_before_symbol option to format negative numbers as -£1 rather than £-1
@@ -42,6 +52,7 @@
42
52
  - TravisBot is now watching Pull Request!!! (GH-171)
43
53
  - Minor code cleaning
44
54
  - Remove subunit from South Korean won (KRW)
55
+ - Fixed bug where bankers rounding wasn't being used everywhere.
45
56
 
46
57
  ## 5.0.0
47
58
 
data/README.md CHANGED
@@ -34,7 +34,7 @@ This library aids one in handling money and different currencies.
34
34
 
35
35
  - Your app must use UTF-8 to function with this library. There are a
36
36
  number of non-ASCII currency attributes.
37
- - This app requires Ruby 1.9 and JSON. If you're using JRuby < 1.7.0
37
+ - This app requires JSON. If you're using JRuby < 1.7.0
38
38
  you'll need to add `gem "json"` to your Gemfile or similar.
39
39
 
40
40
  ## Downloading
@@ -112,7 +112,7 @@ curr = {
112
112
  :iso_numeric => "840",
113
113
  :name => "United States Dollar",
114
114
  :symbol => "$",
115
- :subunit => "Cent"
115
+ :subunit => "Cent",
116
116
  :subunit_to_unit => 100,
117
117
  :separator => ".",
118
118
  :delimiter => ","
@@ -254,4 +254,4 @@ implementations.
254
254
 
255
255
  To integrate money in a Rails application use [money-rails](http://github.com/RubyMoney/money-rails).
256
256
 
257
- For depreceated methods of integrating with Rails, check [the wiki](https://github.com/RubyMoney/money/wiki).
257
+ For deprecated methods of integrating with Rails, check [the wiki](https://github.com/RubyMoney/money/wiki).
@@ -27,6 +27,20 @@
27
27
  "thousands_separator": ",",
28
28
  "iso_numeric": "288"
29
29
  },
30
+ "mtl": {
31
+ "priority": 100,
32
+ "iso_code": "MTL",
33
+ "name": "Maltese Lira",
34
+ "symbol": "₤",
35
+ "alternate_symbols": ["Lm"],
36
+ "subunit": "Cent",
37
+ "subunit_to_unit": 100,
38
+ "symbol_first": true,
39
+ "html_entity": "&#x00A3;",
40
+ "decimal_mark": ".",
41
+ "thousands_separator": ",",
42
+ "iso_numeric": "470"
43
+ },
30
44
  "tmm": {
31
45
  "priority": 100,
32
46
  "iso_code": "TMM",
@@ -390,6 +390,20 @@
390
390
  "thousands_separator": ",",
391
391
  "iso_numeric": "756"
392
392
  },
393
+ "clf": {
394
+ "priority": 100,
395
+ "iso_code": "CLF",
396
+ "name": "Unidad de Fomento",
397
+ "symbol": "UF",
398
+ "alternate_symbols": [],
399
+ "subunit": "Peso",
400
+ "subunit_to_unit": 1,
401
+ "symbol_first": true,
402
+ "html_entity": "&#x20B1;",
403
+ "decimal_mark": ",",
404
+ "thousands_separator": ".",
405
+ "iso_numeric": "990"
406
+ },
393
407
  "clp": {
394
408
  "priority": 100,
395
409
  "iso_code": "CLP",
@@ -1561,7 +1575,7 @@
1561
1575
  "subunit": "Grosz",
1562
1576
  "subunit_to_unit": 100,
1563
1577
  "symbol_first": false,
1564
- "html_entity": "",
1578
+ "html_entity": "z&#322;",
1565
1579
  "decimal_mark": ",",
1566
1580
  "thousands_separator": " ",
1567
1581
  "iso_numeric": "985"
@@ -1598,9 +1612,9 @@
1598
1612
  "priority": 100,
1599
1613
  "iso_code": "RON",
1600
1614
  "name": "Romanian Leu",
1601
- "symbol": "L",
1602
- "alternate_symbols": ["lei"],
1603
- "subunit": "Ban",
1615
+ "symbol": "Lei",
1616
+ "alternate_symbols": [],
1617
+ "subunit": "Bani",
1604
1618
  "subunit_to_unit": 100,
1605
1619
  "symbol_first": true,
1606
1620
  "html_entity": "",
@@ -1804,6 +1818,20 @@
1804
1818
  "thousands_separator": ",",
1805
1819
  "iso_numeric": "968"
1806
1820
  },
1821
+ "ssp": {
1822
+ "priority": 100,
1823
+ "iso_code": "SHP",
1824
+ "name": "South Sudanese Pound",
1825
+ "symbol": "£",
1826
+ "alternate_symbols": [],
1827
+ "subunit": "piaster",
1828
+ "subunit_to_unit": 100,
1829
+ "symbol_first": false,
1830
+ "html_entity": "&#x00A3;",
1831
+ "decimal_mark": ".",
1832
+ "thousands_separator": ",",
1833
+ "iso_numeric": "728"
1834
+ },
1807
1835
  "std": {
1808
1836
  "priority": 100,
1809
1837
  "iso_code": "STD",
@@ -1940,8 +1968,8 @@
1940
1968
  "subunit_to_unit": 100,
1941
1969
  "symbol_first": false,
1942
1970
  "html_entity": "",
1943
- "decimal_mark": ".",
1944
- "thousands_separator": ",",
1971
+ "decimal_mark": ",",
1972
+ "thousands_separator": ".",
1945
1973
  "iso_numeric": "949"
1946
1974
  },
1947
1975
  "ttd": {
@@ -2126,6 +2154,34 @@
2126
2154
  "thousands_separator": ",",
2127
2155
  "iso_numeric": "950"
2128
2156
  },
2157
+ "xag": {
2158
+ "priority": 100,
2159
+ "iso_code": "XAG",
2160
+ "name": "Silver (Troy Ounce)",
2161
+ "symbol": "oz t",
2162
+ "alternate_symbols": [],
2163
+ "subunit": "oz",
2164
+ "subunit_to_unit": 1,
2165
+ "symbol_first": false,
2166
+ "html_entity": "",
2167
+ "decimal_mark": ".",
2168
+ "thousands_separator": ",",
2169
+ "iso_numeric": "961"
2170
+ },
2171
+ "xau": {
2172
+ "priority": 100,
2173
+ "iso_code": "XAU",
2174
+ "name": "Gold (Troy Ounce)",
2175
+ "symbol": "oz t",
2176
+ "alternate_symbols": [],
2177
+ "subunit": "oz",
2178
+ "subunit_to_unit": 1,
2179
+ "symbol_first": false,
2180
+ "html_entity": "",
2181
+ "decimal_mark": ".",
2182
+ "thousands_separator": ",",
2183
+ "iso_numeric": "959"
2184
+ },
2129
2185
  "xcd": {
2130
2186
  "priority": 100,
2131
2187
  "iso_code": "XCD",
@@ -2140,6 +2196,20 @@
2140
2196
  "thousands_separator": ",",
2141
2197
  "iso_numeric": "951"
2142
2198
  },
2199
+ "xdr": {
2200
+ "priority": 100,
2201
+ "iso_code": "XDR",
2202
+ "name": "Special Drawing Rights",
2203
+ "symbol": "SDR",
2204
+ "alternate_symbols": ["XDR"],
2205
+ "subunit": "",
2206
+ "subunit_to_unit": 1,
2207
+ "symbol_first": false,
2208
+ "html_entity": "$",
2209
+ "decimal_mark": ".",
2210
+ "thousands_separator": ",",
2211
+ "iso_numeric": "960"
2212
+ },
2143
2213
  "xof": {
2144
2214
  "priority": 100,
2145
2215
  "iso_code": "XOF",
@@ -2209,5 +2279,19 @@
2209
2279
  "decimal_mark": ".",
2210
2280
  "thousands_separator": ",",
2211
2281
  "iso_numeric": "894"
2282
+ },
2283
+ "zmw": {
2284
+ "priority": 100,
2285
+ "iso_code": "ZMW",
2286
+ "name": "Zambian Kwacha",
2287
+ "symbol": "ZK",
2288
+ "alternate_symbols": [],
2289
+ "subunit": "Ngwee",
2290
+ "subunit_to_unit": 100,
2291
+ "symbol_first": false,
2292
+ "html_entity": "",
2293
+ "decimal_mark": ".",
2294
+ "thousands_separator": ",",
2295
+ "iso_numeric": "967"
2212
2296
  }
2213
2297
  }
@@ -0,0 +1,30 @@
1
+ {
2
+ "btc": {
3
+ "priority": 100,
4
+ "iso_code": "BTC",
5
+ "name": "Bitcoin",
6
+ "symbol": "B⃦",
7
+ "alternate_symbols": [],
8
+ "subunit": "Satoshi",
9
+ "subunit_to_unit": 10000000,
10
+ "symbol_first": true,
11
+ "html_entity": "",
12
+ "decimal_mark": ".",
13
+ "thousands_separator": ",",
14
+ "iso_numeric": ""
15
+ },
16
+ "jep": {
17
+ "priority": 100,
18
+ "iso_code": "JEP",
19
+ "name": "Jersey Pound",
20
+ "symbol": "£",
21
+ "alternate_symbols": [],
22
+ "subunit": "Penny",
23
+ "subunit_to_unit": 100,
24
+ "symbol_first": true,
25
+ "html_entity": "&#x00A3;",
26
+ "decimal_mark": ".",
27
+ "thousands_separator": ",",
28
+ "iso_numeric": ""
29
+ }
30
+ }
data/lib/money.rb CHANGED
@@ -4,3 +4,4 @@ require "i18n" rescue LoadError
4
4
  require "money/currency"
5
5
  require "money/money"
6
6
  require "money/core_extensions"
7
+ require "money/deprecations"
@@ -48,7 +48,7 @@ class Money
48
48
  # Money::Currency.find_by_iso_numeric('001') #=> nil
49
49
  def find_by_iso_numeric(num)
50
50
  num = num.to_s
51
- id, garbage = self.table.find{|key, currency| currency[:iso_numeric] == num}
51
+ id, _ = self.table.find{|key, currency| currency[:iso_numeric] == num}
52
52
  new(id) if self.table[id]
53
53
  end
54
54
 
@@ -90,6 +90,16 @@ class Money
90
90
  @table ||= load_currencies
91
91
  end
92
92
 
93
+ # List the currencies imported and registered
94
+ # @return [Array]
95
+ #
96
+ # @example
97
+ # Money::Currency.iso_codes()
98
+ # [#<Currency ..USD>, 'CAD', 'EUR']...
99
+ def all
100
+ table.keys.map {|curr| Currency.new(curr)}.sort_by(&:priority)
101
+ end
102
+
93
103
  # We need a string-based validator before creating an unbounded number of symbols.
94
104
  # http://www.randomhacks.net/articles/2007/01/20/13-ways-of-looking-at-a-ruby-symbol#11
95
105
  # https://github.com/RubyMoney/money/issues/132
@@ -103,6 +113,12 @@ class Money
103
113
  @stringified_keys = stringify_keys
104
114
  end
105
115
 
116
+ def unregister(curr)
117
+ key = curr[:iso_code].downcase.to_sym
118
+ @table.delete(key)
119
+ @stringified_keys = stringify_keys
120
+ end
121
+
106
122
  private
107
123
 
108
124
  def stringify_keys
@@ -156,11 +172,6 @@ class Money
156
172
  # @return [Integer]
157
173
  attr_reader :subunit_to_unit
158
174
 
159
- # The number of digits after the decimal separator.
160
- #
161
- # @return [Float]
162
- attr_reader :exponent
163
-
164
175
  # The decimal mark, or character used to separate the whole unit from the subunit.
165
176
  #
166
177
  # @return [String]
@@ -175,7 +186,7 @@ class Money
175
186
 
176
187
  # Should the currency symbol precede the amount, or should it come after?
177
188
  #
178
- # @return [boolean]
189
+ # @return [Boolean]
179
190
  attr_reader :symbol_first
180
191
 
181
192
  # Create a new +Currency+ object.
@@ -229,7 +240,7 @@ class Money
229
240
  # c1 == c2 #=> false
230
241
  def ==(other_currency)
231
242
  self.equal?(other_currency) ||
232
- self.id == other_currency.id
243
+ self.id.to_s.downcase == (other_currency.is_a?(Currency) ? other_currency.id.to_s.downcase : other_currency.to_s.downcase)
233
244
  end
234
245
 
235
246
  # Compares +self+ with +other_currency+ and returns +true+ if the are the
@@ -7,8 +7,9 @@ module Money::Currency::Loader
7
7
  #
8
8
  # @return [Hash]
9
9
  def load_currencies
10
- currencies = parse_currency_file("currency.json")
11
- currencies.merge! parse_currency_file("currency_bc.json")
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")
12
13
  end
13
14
 
14
15
  private
@@ -0,0 +1,10 @@
1
+ class Money
2
+ # Displays a deprecation warning message.
3
+ #
4
+ # @param [String] message The message to display.
5
+ #
6
+ # @return [nil]
7
+ def self.deprecate(message)
8
+ warn "DEPRECATION WARNING: #{message}"
9
+ end
10
+ end
data/lib/money/money.rb CHANGED
@@ -221,7 +221,7 @@ class Money
221
221
  # Alternatively you can use the convenience
222
222
  # methods like {Money.ca_dollar} and {Money.us_dollar}.
223
223
  #
224
- # @param [Integer] The value given in the fractional unit.
224
+ # @param [Numeric] fractional The value given in the fractional unit.
225
225
  # @param [Currency, String, Symbol] currency The currency format.
226
226
  # @param [Money::Bank::*] bank The exchange bank to use.
227
227
  #
@@ -468,7 +468,7 @@ class Money
468
468
  # be distributed round-robin amongst the parties. This means that parties
469
469
  # listed first will likely recieve more pennies then ones that are listed later
470
470
  #
471
- # @param [0.50, 0.25, 0.25] to give 50% of the cash to party1, 25% ot party2, and 25% to party3.
471
+ # @param [Array<Float, Float, Float>] splits [0.50, 0.25, 0.25] to give 50% of the cash to party1, 25% to party2, and 25% to party3.
472
472
  #
473
473
  # @return [Array<Money, Money, Money>]
474
474
  #
@@ -506,7 +506,7 @@ class Money
506
506
 
507
507
  # Split money amongst parties evenly without loosing pennies.
508
508
  #
509
- # @param [2] number of parties.
509
+ # @param [Numeric] num number of parties.
510
510
  #
511
511
  # @return [Array<Money, Money, Money>]
512
512
  #
@@ -46,7 +46,7 @@ class Money
46
46
  def <=>(other_money)
47
47
  if other_money.respond_to?(:to_money)
48
48
  other_money = other_money.to_money
49
- if self.currency == other_money.currency
49
+ if fractional == 0 || other_money.fractional == 0 || currency == other_money.currency
50
50
  fractional <=> other_money.fractional
51
51
  else
52
52
  fractional <=> other_money.exchange_to(currency).fractional
@@ -47,7 +47,7 @@ class Money
47
47
 
48
48
  # Creates a formatted price string according to several rules.
49
49
  #
50
- # @param [Hash] *rules The options used to format the string.
50
+ # @param [Hash] rules The options used to format the string.
51
51
  #
52
52
  # @return [String]
53
53
  #
@@ -214,6 +214,16 @@ class Money
214
214
  formatted = "#{self.to_s.to_i}"
215
215
  end
216
216
 
217
+ thousands_separator_value = thousands_separator
218
+ # Determine thousands_separator
219
+ if rules.has_key?(:thousands_separator)
220
+ thousands_separator_value = rules[:thousands_separator] || ''
221
+ end
222
+
223
+ # Apply thousands_separator
224
+ formatted.gsub!(regexp_format(formatted, rules, decimal_mark, symbol_value),
225
+ "\\1#{thousands_separator_value}")
226
+
217
227
  symbol_position =
218
228
  if rules.has_key?(:symbol_position)
219
229
  rules[:symbol_position]
@@ -230,6 +240,8 @@ class Money
230
240
  end
231
241
 
232
242
  if symbol_value && !symbol_value.empty?
243
+ symbol_value = "<span class=\"currency_symbol\">#{symbol_value}</span>" if rules[:html_wrap_symbol]
244
+
233
245
  formatted = if symbol_position == :before
234
246
  symbol_space = rules[:symbol_before_without_space] === false ? " " : ""
235
247
  "#{sign}#{symbol_value}#{symbol_space}#{formatted}"
@@ -244,16 +256,6 @@ class Money
244
256
  formatted.sub!(decimal_mark, rules[:decimal_mark])
245
257
  end
246
258
 
247
- thousands_separator_value = thousands_separator
248
- # Determine thousands_separator
249
- if rules.has_key?(:thousands_separator)
250
- thousands_separator_value = rules[:thousands_separator] || ''
251
- end
252
-
253
- # Apply thousands_separator
254
- formatted.gsub!(regexp_format(formatted, rules, decimal_mark, symbol_value),
255
- "\\1#{thousands_separator_value}")
256
-
257
259
  if rules[:with_currency]
258
260
  formatted << " "
259
261
  formatted << '<span class="currency">' if rules[:html]
@@ -268,7 +270,7 @@ class Money
268
270
 
269
271
  # Cleans up formatting rules.
270
272
  #
271
- # @param [Hash]
273
+ # @param [Hash] rules
272
274
  #
273
275
  # @return [Hash]
274
276
  def normalize_formatting_rules(rules)
@@ -294,7 +296,7 @@ class Money
294
296
  /(\d+?)(?=(\d\d)+(\d)(?:\.))/
295
297
  else
296
298
  # Symbols may contain decimal marks (E.g "դր.")
297
- if formatted.sub(symbol_value, "") =~ /#{regexp_decimal}/
299
+ if formatted.sub(symbol_value.to_s, "") =~ /#{regexp_decimal}/
298
300
  /(\d)(?=(?:\d{3})+(?:#{regexp_decimal}))/
299
301
  else
300
302
  /(\d)(?=(?:\d{3})+(?:[^\d]{1}|$))/
@@ -31,9 +31,10 @@ class Money
31
31
  # @example Mismatching currencies
32
32
  # 'USD 2000'.to_money("EUR") #=> ArgumentError
33
33
  #
34
- # @see Money.from_string
34
+ # @see #from_string
35
35
  #
36
36
  def parse(input, currency = nil)
37
+ Money.deprecate ".parse is depreciated and will be remove in 6.1.0. Please write your own parsing methods."
37
38
  i = input.to_s.strip
38
39
 
39
40
  # raise Money::Currency.table.collect{|c| c[1][:symbol]}.inspect
@@ -73,7 +74,7 @@ class Money
73
74
  # according to +currency+ subunit property,
74
75
  # before instantiating the Money object.
75
76
  #
76
- # Behind the scenes, this method relies on {Money.from_bigdecimal}
77
+ # Behind the scenes, this method relies on {#from_bigdecimal}
77
78
  # to avoid problems with string-to-numeric conversion.
78
79
  #
79
80
  # @param [String, #to_s] value The money amount, in dollars.
@@ -93,7 +94,7 @@ class Money
93
94
  # #=> #<Money @fractional=100 @currency="BHD">
94
95
  #
95
96
  # @see String#to_money
96
- # @see Money.parse
97
+ # @see #parse
97
98
  #
98
99
  def from_string(value, currency = Money.default_currency)
99
100
  from_bigdecimal(BigDecimal.new(value.to_s), currency)
@@ -120,7 +121,7 @@ class Money
120
121
  # #=> #<Money @fractional=100 @currency="BHD">
121
122
  #
122
123
  # @see Fixnum#to_money
123
- # @see Money.from_numeric
124
+ # @see #from_numeric
124
125
  #
125
126
  def from_fixnum(value, currency = Money.default_currency)
126
127
  currency = Money::Currency.wrap(currency)
@@ -152,7 +153,7 @@ class Money
152
153
  # #=> #<Money @fractional=100 @currency="BHD">
153
154
  #
154
155
  # @see Float#to_money
155
- # @see Money.from_numeric
156
+ # @see #from_numeric
156
157
  #
157
158
  def from_float(value, currency = Money.default_currency)
158
159
  from_bigdecimal(BigDecimal.new(value.to_s), currency)
@@ -179,7 +180,7 @@ class Money
179
180
  # #=> #<Money @fractional=100 @currency="BHD">
180
181
  #
181
182
  # @see BigDecimal#to_money
182
- # @see Money.from_numeric
183
+ # @see #from_numeric
183
184
  #
184
185
  def from_bigdecimal(value, currency = Money.default_currency)
185
186
  currency = Money::Currency.wrap(currency)
@@ -196,8 +197,8 @@ class Money
196
197
  # and tries to forwards the call to the most appropriate method
197
198
  # in order to reduce computation effort.
198
199
  # For instance, if +value+ is an Integer, this method calls
199
- # {Money.from_fixnum} instead of using the default
200
- # {Money.from_bigdecimal} which adds the overload to converts
200
+ # {#from_fixnum} instead of using the default
201
+ # {#from_bigdecimal} which adds the overload to converts
201
202
  # the value into a slower BigDecimal instance.
202
203
  #
203
204
  # @param [Numeric] value The money amount, in dollars.
@@ -216,9 +217,9 @@ class Money
216
217
  # #=> ArgumentError
217
218
  #
218
219
  # @see Numeric#to_money
219
- # @see Money.from_fixnum
220
- # @see Money.from_float
221
- # @see Money.from_bigdecimal
220
+ # @see #from_fixnum
221
+ # @see #from_float
222
+ # @see #from_bigdecimal
222
223
  #
223
224
  def from_numeric(value, currency = Money.default_currency)
224
225
  case value
@@ -260,89 +261,90 @@ class Money
260
261
  #save it from being mis-interpreted as a decimal.
261
262
  num.chop! if num.match(/[\.|,]$/)
262
263
 
263
- # gather all decimal_marks within the result number
264
- used_decimal_marks = num.scan(/[^\d]/)
264
+ # gather all decimal_marks within the result number
265
+ used_delimiters = num.scan(/[^\d]/)
265
266
 
266
- # determine the number of unique decimal_marks within the number
267
- #
268
- # e.g.
269
- # $1,234,567.89 would return 2 (, and .)
270
- # $125,00 would return 1
271
- # $199 would return 0
272
- # $1 234,567.89 would raise an error (decimal_marks are space, comma, and period)
273
- case used_decimal_marks.uniq.length
274
- # no decimal_mark or thousands_separator; major (dollars) is the number, and minor (cents) is 0
275
- when 0 then major, minor = num, 0
267
+ # determine the number of unique decimal_marks within the number
268
+ #
269
+ # e.g.
270
+ # $1,234,567.89 would return 2 (, and .)
271
+ # $125,00 would return 1
272
+ # $199 would return 0
273
+ # $1 234,567.89 would raise an error (decimal_marks are space, comma, and period)
274
+ case used_delimiters.uniq.length
275
+ # no decimal_mark or thousands_separator; major (dollars) is the number, and minor (cents) is 0
276
+ when 0 then major, minor = num, 0
277
+
278
+ # two decimal_marks, so we know the last item in this array is the
279
+ # major/minor thousands_separator and the rest are decimal_marks
280
+ when 2
281
+ thousands_separator, decimal_mark = used_delimiters.uniq
276
282
 
277
- # two decimal_marks, so we know the last item in this array is the
278
- # major/minor thousands_separator and the rest are decimal_marks
279
- when 2
280
- decimal_mark, thousands_separator = used_decimal_marks.uniq
281
- # remove all decimal_marks, split on the thousands_separator
282
- major, minor = num.gsub(decimal_mark, '').split(thousands_separator)
283
- min = 0 unless min
284
- when 1
285
- # we can't determine if the comma or period is supposed to be a decimal_mark or a thousands_separator
286
- # e.g.
287
- # 1,00 - comma is a thousands_separator
288
- # 1.000 - period is a thousands_separator
289
- # 1,000 - comma is a decimal_mark
290
- # 1,000,000 - comma is a decimal_mark
291
- # 10000,00 - comma is a thousands_separator
292
- # 1000,000 - comma is a thousands_separator
283
+ # remove all thousands_separator, split on the decimal_mark
284
+ major, minor = num.gsub(thousands_separator, '').split(decimal_mark)
285
+ min = 0 unless min
286
+ when 1
287
+ # we can't determine if the comma or period is supposed to be a decimal_mark or a thousands_separator
288
+ # e.g.
289
+ # 1,00 - comma is a thousands_separator
290
+ # 1.000 - period is a thousands_separator
291
+ # 1,000 - comma is a decimal_mark
292
+ # 1,000,000 - comma is a decimal_mark
293
+ # 10000,00 - comma is a thousands_separator
294
+ # 1000,000 - comma is a thousands_separator
293
295
 
294
- # assign first decimal_mark for reusability
295
- decimal_mark = used_decimal_marks.first
296
+ # assign first decimal_mark for reusability
297
+ decimal_mark = used_delimiters.first
296
298
 
297
- # When we have identified the decimal mark character
298
- if decimal_char == decimal_mark
299
- major, minor = num.split(decimal_char)
299
+ # When we have identified the decimal mark character
300
+ if decimal_char == decimal_mark
301
+ major, minor = num.split(decimal_char)
300
302
 
303
+ else
304
+ # decimal_mark is used as a decimal_mark when there are multiple instances, always
305
+ if num.scan(decimal_mark).length > 1 # multiple matches; treat as decimal_mark
306
+ major, minor = num.gsub(decimal_mark, ''), 0
301
307
  else
302
- # decimal_mark is used as a decimal_mark when there are multiple instances, always
303
- if num.scan(decimal_mark).length > 1 # multiple matches; treat as decimal_mark
304
- major, minor = num.gsub(decimal_mark, ''), 0
308
+ # ex: 1,000 - 1.0000 - 10001.000
309
+ # split number into possible major (dollars) and minor (cents) values
310
+ possible_major, possible_minor = num.split(decimal_mark)
311
+ possible_major ||= "0"
312
+ possible_minor ||= "00"
313
+
314
+ # if the minor (cents) length isn't 3, assign major/minor from the possibles
315
+ # e.g.
316
+ # 1,00 => 1.00
317
+ # 1.0000 => 1.00
318
+ # 1.2 => 1.20
319
+ if possible_minor.length != 3 # thousands_separator
320
+ major, minor = possible_major, possible_minor
305
321
  else
306
- # ex: 1,000 - 1.0000 - 10001.000
307
- # split number into possible major (dollars) and minor (cents) values
308
- possible_major, possible_minor = num.split(decimal_mark)
309
- possible_major ||= "0"
310
- possible_minor ||= "00"
322
+ # minor length is three
323
+ # let's try to figure out intent of the thousands_separator
311
324
 
312
- # if the minor (cents) length isn't 3, assign major/minor from the possibles
325
+ # the major length is greater than three, which means
326
+ # the comma or period is used as a thousands_separator
313
327
  # e.g.
314
- # 1,00 => 1.00
315
- # 1.0000 => 1.00
316
- # 1.2 => 1.20
317
- if possible_minor.length != 3 # thousands_separator
328
+ # 1000,000
329
+ # 100000,000
330
+ if possible_major.length > 3
318
331
  major, minor = possible_major, possible_minor
319
332
  else
320
- # minor length is three
321
- # let's try to figure out intent of the thousands_separator
322
-
323
- # the major length is greater than three, which means
324
- # the comma or period is used as a thousands_separator
325
- # e.g.
326
- # 1000,000
327
- # 100000,000
328
- if possible_major.length > 3
333
+ # number is in format ###{sep}### or ##{sep}### or #{sep}###
334
+ # handle as , is sep, . is thousands_separator
335
+ if decimal_mark == '.'
329
336
  major, minor = possible_major, possible_minor
330
337
  else
331
- # number is in format ###{sep}### or ##{sep}### or #{sep}###
332
- # handle as , is sep, . is thousands_separator
333
- if decimal_mark == '.'
334
- major, minor = possible_major, possible_minor
335
- else
336
- major, minor = "#{possible_major}#{possible_minor}", 0
337
- end
338
+ major, minor = "#{possible_major}#{possible_minor}", 0
338
339
  end
339
340
  end
340
341
  end
341
342
  end
342
- else
343
- # TODO: ParseError
344
- raise ArgumentError, "Invalid currency amount"
345
343
  end
344
+ else
345
+ # TODO: ParseError
346
+ raise ArgumentError, "Invalid currency amount"
347
+ end
346
348
 
347
349
  # build the string based on major/minor since decimal_mark/thousands_separator have been removed
348
350
  # avoiding floating point arithmetic here to ensure accuracy
data/money.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  Gem::Specification.new do |s|
3
3
  s.name = "money"
4
- s.version = "5.1.1"
4
+ s.version = "6.0.0.pre"
5
5
  s.platform = Gem::Platform::RUBY
6
6
  s.authors = ["Tobias Luetke", "Hongli Lai", "Jeremy McNevin",
7
7
  "Shane Emmons", "Simone Carletti"]
@@ -10,14 +10,15 @@ Gem::Specification.new do |s|
10
10
  s.summary = "Money and currency exchange support library."
11
11
  s.description = "This library aids one in handling money and different currencies."
12
12
 
13
- s.required_ruby_version = ">= 1.9.2"
14
- s.required_rubygems_version = ">= 1.3.6"
13
+ s.required_ruby_version = ">= 1.8.7"
15
14
 
16
- s.add_dependency "i18n", "~> 0.6.0"
15
+ s.add_dependency "i18n", "~> 0.6.4"
17
16
 
18
- s.add_development_dependency "rspec", "~> 2.11.0"
19
- s.add_development_dependency "yard", "~> 0.8.1"
20
- s.add_development_dependency "kramdown", "~> 0.14.0"
17
+ s.add_development_dependency "rspec", "~> 2.14"
18
+ s.add_development_dependency "yard", "~> 0.8"
19
+ s.add_development_dependency "kramdown", "~> 1.1"
20
+
21
+ s.license = "MIT"
21
22
 
22
23
  s.files = Dir.glob("{config,lib,spec}/**/*")
23
24
  s.files += %w(CHANGELOG.md LICENSE README.md)
@@ -145,7 +145,7 @@ describe Money::Bank::VariableExchange do
145
145
 
146
146
  context "with :file provided" do
147
147
  it "writes rates to file" do
148
- f = mock('IO')
148
+ f = double('IO')
149
149
  File.should_receive(:open).with('null', 'w').and_yield(f)
150
150
  f.should_receive(:write).with(JSON.dump(@rates))
151
151
 
@@ -7,8 +7,15 @@ describe Money::Currency do
7
7
  FOO = '{ "priority": 1, "iso_code": "FOO", "iso_numeric": "840", "name": "United States Dollar", "symbol": "$", "subunit": "Cent", "subunit_to_unit": 450, "symbol_first": true, "html_entity": "$", "decimal_mark": ".", "thousands_separator": "," }'
8
8
 
9
9
  describe ".find" do
10
- it "returns currency matching given id" do
10
+ before :each do
11
11
  Money::Currency.register(JSON.parse(FOO, :symbolize_names => true))
12
+ end
13
+
14
+ after :each do
15
+ Money::Currency.unregister(JSON.parse(FOO, :symbolize_names => true))
16
+ end
17
+
18
+ it "returns currency matching given id" do
12
19
 
13
20
  expected = Money::Currency.new(:foo)
14
21
  Money::Currency.find(:foo).should == expected
@@ -51,6 +58,19 @@ describe Money::Currency do
51
58
  end
52
59
  end
53
60
 
61
+ describe ".all" do
62
+ it "returns an array of currencies" do
63
+ Money::Currency.all.should include Money::Currency.new(:usd)
64
+ end
65
+ it "includes registered currencies" do
66
+ Money::Currency.register(JSON.parse(FOO, :symbolize_names => true))
67
+ Money::Currency.all.should include Money::Currency.new(:foo)
68
+ Money::Currency.unregister(JSON.parse(FOO, :symbolize_names => true))
69
+ end
70
+ it 'is sorted by priority' do
71
+ Money::Currency.all.first.priority.should == 1
72
+ end
73
+ end
54
74
 
55
75
  describe "#initialize" do
56
76
  it "lookups data from loaded config" do
@@ -84,10 +104,21 @@ describe Money::Currency do
84
104
  currency.should == currency
85
105
  end
86
106
 
87
- it "returns true if the id is equal" do
107
+ it "returns true if the id is equal ignorning case" do
88
108
  Money::Currency.new(:eur).should == Money::Currency.new(:eur)
109
+ Money::Currency.new(:eur).should == Money::Currency.new(:EUR)
89
110
  Money::Currency.new(:eur).should_not == Money::Currency.new(:usd)
90
111
  end
112
+
113
+ it "allows direct comparison of currencies and symbols/strings" do
114
+ Money::Currency.new(:eur).should == 'eur'
115
+ Money::Currency.new(:eur).should == :EUR
116
+ Money::Currency.new(:eur).should_not == 'usd'
117
+ end
118
+
119
+ it "allows comparison with nil and returns false" do
120
+ Money::Currency.new(:eur).should_not == nil
121
+ end
91
122
  end
92
123
 
93
124
  describe "#eql?" do
@@ -159,6 +190,7 @@ describe Money::Currency do
159
190
  it "proper places for custom currency" do
160
191
  Money::Currency.register(JSON.parse(FOO, :symbolize_names => true))
161
192
  Money::Currency.new(:foo).decimal_places == 3
193
+ Money::Currency.unregister(JSON.parse(FOO, :symbolize_names => true))
162
194
  end
163
195
  end
164
196
  end
@@ -126,18 +126,42 @@ describe Money do
126
126
  (Money.new(100_00, "USD") <=> target).should > 0
127
127
  end
128
128
 
129
- it "can be used to compare with a String money value" do
129
+ it "cannot compare objects with different currencies when no rate exists, unless one of the amounts is zero" do
130
+ expect { Money.new(100_00, "EUR") <=> Money.new(100_00, "USD") }.to raise_error(Money::Bank::UnknownRate)
131
+
132
+ (Money.new(100_00, "EUR") <=> Money.new(0, "USD")).should > 0
133
+ (Money.new(0, "EUR") <=> Money.new(100_00, "USD")).should < 0
134
+ (Money.new(0, "EUR") <=> Money.new(0, "USD")).should == 0
135
+ end
136
+
137
+ it "can be used to compare with a String money value when Money object is in default currency" do
130
138
  (Money.new(1_00) <=> "1.00").should == 0
131
139
  (Money.new(1_00) <=> ".99").should > 0
132
140
  (Money.new(1_00) <=> "2.00").should < 0
133
141
  end
134
142
 
135
- it "can be used to compare with a Numeric money value" do
143
+ it "can be used to compare with a String money value when Money object is not in default currency if String evaluates to zero" do
144
+ expect { Money.new(1_00, "EUR") <=> "1.00" }.to raise_error(Money::Bank::UnknownRate)
145
+
146
+ (Money.new(1_00, "EUR") <=> "0.00").should > 0
147
+ (Money.new(0_00, "EUR") <=> "0.00").should == 0
148
+ (Money.new(-1_00, "EUR") <=> "0.00").should < 0
149
+ end
150
+
151
+ it "can be used to compare with a Numeric money value when Money object is in default currency" do
136
152
  (Money.new(1_00) <=> 1).should == 0
137
153
  (Money.new(1_00) <=> 0.99).should > 0
138
154
  (Money.new(1_00) <=> 2.00).should < 0
139
155
  end
140
156
 
157
+ it "can be used to compare with a Numeric money value when Money object is not in default currency if String evaluates to zero" do
158
+ expect { Money.new(1_00, "EUR") <=> 1 }.to raise_error(Money::Bank::UnknownRate)
159
+
160
+ (Money.new(1_00, "EUR") <=> 0).should > 0
161
+ (Money.new(0_00, "EUR") <=> 0).should == 0
162
+ (Money.new(-1_00, "EUR") <=> 0).should < 0
163
+ end
164
+
141
165
  it "can be used to compare with an object that responds to #to_money" do
142
166
  klass = Class.new do
143
167
  def initialize(money)
@@ -167,9 +167,15 @@ describe Money, "formatting" do
167
167
  end
168
168
 
169
169
  it "inserts thousand separators if symbol contains decimal mark and no_cents is true" do
170
- Money.new(100000000, "AMD").format(no_cents: true).should == "1,000,000 դր."
171
- Money.new(100000000, "USD").format(no_cents: true).should == "$1,000,000"
172
- Money.new(100000000, "RUB").format(no_cents: true).should == "1.000.000 р."
170
+ Money.new(100000000, "AMD").format(:no_cents => true).should == "1,000,000 դր."
171
+ Money.new(100000000, "USD").format(:no_cents => true).should == "$1,000,000"
172
+ Money.new(100000000, "RUB").format(:no_cents => true).should == "1.000.000 р."
173
+ end
174
+
175
+ it "doesn't incorrectly format HTML" do
176
+ money = ::Money.new(1999, "RUB")
177
+ output = money.format(:html => true, :no_cents => true)
178
+ output.should == "19 &#x0440;&#x0443;&#x0431;"
173
179
  end
174
180
  end
175
181
 
@@ -294,6 +300,10 @@ describe Money, "formatting" do
294
300
  Money::Currency.register(JSON.parse(INDIAN_BAR, :symbolize_names => true))
295
301
  end
296
302
 
303
+ after(:each) do
304
+ Money::Currency.unregister(JSON.parse(INDIAN_BAR, :symbolize_names => true))
305
+ end
306
+
297
307
  specify "(:south_asian_number_formatting => true) works as documented" do
298
308
  Money.new(10000000, 'INR').format(:south_asian_number_formatting => true, :symbol => false).should == "1,00,000.00"
299
309
  Money.new(1000000000, 'INDIAN_BAR').format(:south_asian_number_formatting => true, :symbol => false).should == "1,00,000.0000"
@@ -339,6 +349,14 @@ describe Money, "formatting" do
339
349
  end
340
350
  end
341
351
 
352
+ describe ":html_wrap_symbol option" do
353
+ specify "(:html_wrap_symbol => true) works as documented" do
354
+ string = Money.ca_dollar(570).format(:html_wrap_symbol => true)
355
+ string.should == "<span class=\"currency_symbol\">$</span>5.70"
356
+ end
357
+ end
358
+
359
+
342
360
  describe ":symbol_position option" do
343
361
  it "inserts currency symbol before the amount when set to :before" do
344
362
  Money.euro(1_234_567_12).format(:symbol_position => :before).should == "€1.234.567,12"
@@ -418,6 +436,11 @@ describe Money, "formatting" do
418
436
  Money::Currency.register(JSON.parse(EU4, :symbolize_names => true))
419
437
  end
420
438
 
439
+ after :each do
440
+ Money::Currency.unregister(JSON.parse(BAR, :symbolize_names => true))
441
+ Money::Currency.unregister(JSON.parse(EU4, :symbolize_names => true))
442
+ end
443
+
421
444
  it "respects custom subunit to unit, decimal and thousands separator" do
422
445
  Money.new(4, "BAR").format.should == "$0.0004"
423
446
  Money.new(4, "EU4").format.should == "€0,0004"
@@ -8,6 +8,11 @@ describe Money, "parsing" do
8
8
  eu4 = '{ "priority": 1, "iso_code": "EU4", "iso_numeric": "841", "name": "Euro with 4 decimal places", "symbol": "€", "subunit": "Cent", "subunit_to_unit": 10000, "symbol_first": true, "html_entity": "€", "decimal_mark": ",", "thousands_separator": "." }'
9
9
 
10
10
  describe ".parse" do
11
+ it "is depreciated" do
12
+ Money.should_receive(:deprecate)
13
+ Money.parse("1.95")
14
+ end
15
+
11
16
  it "parses european-formatted inputs under 10EUR" do
12
17
  five_ninety_five = Money.new(595, 'EUR')
13
18
 
@@ -111,6 +116,11 @@ describe Money, "parsing" do
111
116
  Money::Currency.register(JSON.parse(eu4, :symbolize_names => true))
112
117
  end
113
118
 
119
+ after :each do
120
+ Money::Currency.unregister(JSON.parse(bar, :symbolize_names => true))
121
+ Money::Currency.unregister(JSON.parse(eu4, :symbolize_names => true))
122
+ end
123
+
114
124
  # String#to_money(Currency) is equivalent to Money.parse(String, Currency)
115
125
  it "parses strings respecting subunit to unit, decimal and thousands separator" do
116
126
  "$0.4".to_money("BAR").should == Money.new(4000, "BAR")
data/spec/money_spec.rb CHANGED
@@ -118,6 +118,15 @@ describe Money do
118
118
  end
119
119
 
120
120
  describe ".add_rate" do
121
+ before do
122
+ @default_bank = Money.default_bank
123
+ Money.default_bank = Money::Bank::VariableExchange.new
124
+ end
125
+
126
+ after do
127
+ Money.default_bank = @default_bank
128
+ end
129
+
121
130
  it "saves rate into current bank" do
122
131
  Money.add_rate("EUR", "USD", 10)
123
132
  Money.new(10_00, "EUR").exchange_to("USD").should == Money.new(100_00, "USD")
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: money
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.1
5
- prerelease:
4
+ version: 6.0.0.pre
6
5
  platform: ruby
7
6
  authors:
8
7
  - Tobias Luetke
@@ -13,72 +12,64 @@ authors:
13
12
  autorequire:
14
13
  bindir: bin
15
14
  cert_chain: []
16
- date: 2013-02-20 00:00:00.000000000 Z
15
+ date: 2013-07-24 00:00:00.000000000 Z
17
16
  dependencies:
18
17
  - !ruby/object:Gem::Dependency
19
18
  name: i18n
20
19
  requirement: !ruby/object:Gem::Requirement
21
- none: false
22
20
  requirements:
23
21
  - - ~>
24
22
  - !ruby/object:Gem::Version
25
- version: 0.6.0
23
+ version: 0.6.4
26
24
  type: :runtime
27
25
  prerelease: false
28
26
  version_requirements: !ruby/object:Gem::Requirement
29
- none: false
30
27
  requirements:
31
28
  - - ~>
32
29
  - !ruby/object:Gem::Version
33
- version: 0.6.0
30
+ version: 0.6.4
34
31
  - !ruby/object:Gem::Dependency
35
32
  name: rspec
36
33
  requirement: !ruby/object:Gem::Requirement
37
- none: false
38
34
  requirements:
39
35
  - - ~>
40
36
  - !ruby/object:Gem::Version
41
- version: 2.11.0
37
+ version: '2.14'
42
38
  type: :development
43
39
  prerelease: false
44
40
  version_requirements: !ruby/object:Gem::Requirement
45
- none: false
46
41
  requirements:
47
42
  - - ~>
48
43
  - !ruby/object:Gem::Version
49
- version: 2.11.0
44
+ version: '2.14'
50
45
  - !ruby/object:Gem::Dependency
51
46
  name: yard
52
47
  requirement: !ruby/object:Gem::Requirement
53
- none: false
54
48
  requirements:
55
49
  - - ~>
56
50
  - !ruby/object:Gem::Version
57
- version: 0.8.1
51
+ version: '0.8'
58
52
  type: :development
59
53
  prerelease: false
60
54
  version_requirements: !ruby/object:Gem::Requirement
61
- none: false
62
55
  requirements:
63
56
  - - ~>
64
57
  - !ruby/object:Gem::Version
65
- version: 0.8.1
58
+ version: '0.8'
66
59
  - !ruby/object:Gem::Dependency
67
60
  name: kramdown
68
61
  requirement: !ruby/object:Gem::Requirement
69
- none: false
70
62
  requirements:
71
63
  - - ~>
72
64
  - !ruby/object:Gem::Version
73
- version: 0.14.0
65
+ version: '1.1'
74
66
  type: :development
75
67
  prerelease: false
76
68
  version_requirements: !ruby/object:Gem::Requirement
77
- none: false
78
69
  requirements:
79
70
  - - ~>
80
71
  - !ruby/object:Gem::Version
81
- version: 0.14.0
72
+ version: '1.1'
82
73
  description: This library aids one in handling money and different currencies.
83
74
  email:
84
75
  - semmons99+RubyMoney@gmail.com
@@ -86,58 +77,59 @@ executables: []
86
77
  extensions: []
87
78
  extra_rdoc_files: []
88
79
  files:
89
- - config/currency_bc.json
90
- - config/currency.json
91
- - lib/money.rb
92
- - lib/money/money.rb
80
+ - config/currency_backwards_compatible.json
81
+ - config/currency_iso.json
82
+ - config/currency_non_iso.json
83
+ - lib/money/bank/base.rb
84
+ - lib/money/bank/variable_exchange.rb
93
85
  - lib/money/core_extensions.rb
94
- - lib/money/currency.rb
95
86
  - lib/money/currency/heuristics.rb
96
87
  - lib/money/currency/loader.rb
97
- - lib/money/money/formatting.rb
88
+ - lib/money/currency.rb
89
+ - lib/money/deprecations.rb
98
90
  - lib/money/money/arithmetic.rb
91
+ - lib/money/money/formatting.rb
99
92
  - lib/money/money/parsing.rb
100
- - lib/money/bank/variable_exchange.rb
101
- - lib/money/bank/base.rb
102
- - spec/money_spec.rb
103
- - spec/spec_helper.rb
93
+ - lib/money/money.rb
94
+ - lib/money.rb
95
+ - spec/bank/base_spec.rb
96
+ - spec/bank/variable_exchange_spec.rb
97
+ - spec/core_extensions_spec.rb
104
98
  - spec/currency/heuristics_spec.rb
105
99
  - spec/currency_spec.rb
106
100
  - spec/money/arithmetic_spec.rb
107
- - spec/money/parsing_spec.rb
108
101
  - spec/money/formatting_spec.rb
102
+ - spec/money/parsing_spec.rb
103
+ - spec/money_spec.rb
104
+ - spec/spec_helper.rb
109
105
  - spec/support/default_currency_helper.rb
110
- - spec/bank/base_spec.rb
111
- - spec/bank/variable_exchange_spec.rb
112
- - spec/core_extensions_spec.rb
113
106
  - CHANGELOG.md
114
107
  - LICENSE
115
108
  - README.md
116
109
  - Rakefile
117
110
  - money.gemspec
118
111
  homepage: http://rubymoney.github.com/money
119
- licenses: []
112
+ licenses:
113
+ - MIT
114
+ metadata: {}
120
115
  post_install_message:
121
116
  rdoc_options: []
122
117
  require_paths:
123
118
  - lib
124
119
  required_ruby_version: !ruby/object:Gem::Requirement
125
- none: false
126
120
  requirements:
127
- - - ! '>='
121
+ - - '>='
128
122
  - !ruby/object:Gem::Version
129
- version: 1.9.2
123
+ version: 1.8.7
130
124
  required_rubygems_version: !ruby/object:Gem::Requirement
131
- none: false
132
125
  requirements:
133
- - - ! '>='
126
+ - - '>'
134
127
  - !ruby/object:Gem::Version
135
- version: 1.3.6
128
+ version: 1.3.1
136
129
  requirements: []
137
130
  rubyforge_project:
138
- rubygems_version: 1.8.23
131
+ rubygems_version: 2.0.2
139
132
  signing_key:
140
- specification_version: 3
133
+ specification_version: 4
141
134
  summary: Money and currency exchange support library.
142
135
  test_files: []
143
- has_rdoc: