money 5.0.0 → 5.1.0.beta1

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.
@@ -6,9 +6,9 @@ class Money
6
6
  # @return [Money]
7
7
  #
8
8
  # @example
9
- # - Money.new(100) #=> #<Money @cents=-100>
9
+ # - Money.new(100) #=> #<Money @fractional=-100>
10
10
  def -@
11
- Money.new(-cents, currency)
11
+ Money.new(-fractional, currency)
12
12
  end
13
13
 
14
14
 
@@ -26,7 +26,7 @@ class Money
26
26
  def ==(other_money)
27
27
  if other_money.respond_to?(:to_money)
28
28
  other_money = other_money.to_money
29
- cents == other_money.cents && self.currency == other_money.currency
29
+ fractional == other_money.fractional && self.currency == other_money.currency
30
30
  else
31
31
  false
32
32
  end
@@ -47,9 +47,9 @@ class Money
47
47
  if other_money.respond_to?(:to_money)
48
48
  other_money = other_money.to_money
49
49
  if self.currency == other_money.currency
50
- cents <=> other_money.cents
50
+ fractional <=> other_money.fractional
51
51
  else
52
- cents <=> other_money.exchange_to(currency).cents
52
+ fractional <=> other_money.exchange_to(currency).fractional
53
53
  end
54
54
  else
55
55
  raise ArgumentError, "Comparison of #{self.class} with #{other_money.inspect} failed"
@@ -66,7 +66,7 @@ class Money
66
66
  # Money.new(0).positive? #=> false
67
67
  # Money.new(-1).positive? #=> false
68
68
  def positive?
69
- cents > 0
69
+ fractional > 0
70
70
  end
71
71
 
72
72
  # Test if the amount is negative. Returns +true+ if the money amount is
@@ -79,7 +79,7 @@ class Money
79
79
  # Money.new(0).negative? #=> false
80
80
  # Money.new(1).negative? #=> false
81
81
  def negative?
82
- cents < 0
82
+ fractional < 0
83
83
  end
84
84
 
85
85
  # Returns a new Money object containing the sum of the two operands' monetary
@@ -91,12 +91,12 @@ class Money
91
91
  # @return [Money]
92
92
  #
93
93
  # @example
94
- # Money.new(100) + Money.new(100) #=> #<Money @cents=200>
94
+ # Money.new(100) + Money.new(100) #=> #<Money @fractional=200>
95
95
  def +(other_money)
96
96
  if currency == other_money.currency
97
- Money.new(cents + other_money.cents, other_money.currency)
97
+ Money.new(fractional + other_money.fractional, other_money.currency)
98
98
  else
99
- Money.new(cents + other_money.exchange_to(currency).cents, currency)
99
+ Money.new(fractional + other_money.exchange_to(currency).fractional, currency)
100
100
  end
101
101
  end
102
102
 
@@ -110,12 +110,12 @@ class Money
110
110
  # @return [Money]
111
111
  #
112
112
  # @example
113
- # Money.new(100) - Money.new(99) #=> #<Money @cents=1>
113
+ # Money.new(100) - Money.new(99) #=> #<Money @fractional=1>
114
114
  def -(other_money)
115
115
  if currency == other_money.currency
116
- Money.new(cents - other_money.cents, other_money.currency)
116
+ Money.new(fractional - other_money.fractional, other_money.currency)
117
117
  else
118
- Money.new(cents - other_money.exchange_to(currency).cents, currency)
118
+ Money.new(fractional - other_money.exchange_to(currency).fractional, currency)
119
119
  end
120
120
  end
121
121
 
@@ -131,13 +131,13 @@ class Money
131
131
  # @raise [ArgumentError] If +value+ is a Money instance.
132
132
  #
133
133
  # @example
134
- # Money.new(100) * 2 #=> #<Money @cents=200>
134
+ # Money.new(100) * 2 #=> #<Money @fractional=200>
135
135
  #
136
136
  def *(value)
137
137
  if value.is_a?(Money)
138
138
  raise ArgumentError, "Can't multiply a Money by a Money"
139
139
  else
140
- Money.new(cents * value, currency)
140
+ Money.new(fractional * value, currency)
141
141
  end
142
142
  end
143
143
 
@@ -153,18 +153,18 @@ class Money
153
153
  # @return [Float] The resulting number if you divide Money by a Money.
154
154
  #
155
155
  # @example
156
- # Money.new(100) / 10 #=> #<Money @cents=10>
156
+ # Money.new(100) / 10 #=> #<Money @fractional=10>
157
157
  # Money.new(100) / Money.new(10) #=> 10.0
158
158
  #
159
159
  def /(value)
160
160
  if value.is_a?(Money)
161
161
  if currency == value.currency
162
- (cents / BigDecimal.new(value.cents.to_s)).to_f
162
+ (fractional / BigDecimal.new(value.fractional.to_s)).to_f
163
163
  else
164
- (cents / BigDecimal(value.exchange_to(currency).cents.to_s)).to_f
164
+ (fractional / BigDecimal(value.exchange_to(currency).fractional.to_s)).to_f
165
165
  end
166
166
  else
167
- Money.new(cents / value, currency)
167
+ Money.new(fractional / value, currency)
168
168
  end
169
169
  end
170
170
 
@@ -189,16 +189,21 @@ class Money
189
189
  # @return [Array<Money,Money>,Array<Fixnum,Money>]
190
190
  #
191
191
  # @example
192
- # Money.new(100).divmod(9) #=> [#<Money @cents=11>, #<Money @cents=1>]
193
- # Money.new(100).divmod(Money.new(9)) #=> [11, #<Money @cents=1>]
192
+ # Money.new(100).divmod(9) #=> [#<Money @fractional=11>, #<Money @fractional=1>]
193
+ # Money.new(100).divmod(Money.new(9)) #=> [11, #<Money @fractional=1>]
194
194
  def divmod(val)
195
195
  if val.is_a?(Money)
196
- a = self.cents
197
- b = self.currency == val.currency ? val.cents : val.exchange_to(self.currency).cents
196
+ a = self.fractional
197
+ b = self.currency == val.currency ? val.fractional : val.exchange_to(self.currency).cents
198
198
  q, m = a.divmod(b)
199
199
  return [q, Money.new(m, self.currency)]
200
200
  else
201
- return [self.div(val), Money.new(self.cents.modulo(val), self.currency)]
201
+ if self.class.infinite_precision
202
+ q, m = self.fractional.divmod(BigDecimal(val.to_s))
203
+ return [Money.new(q, self.currency), Money.new(m, self.currency)]
204
+ else
205
+ return [self.div(val), Money.new(self.fractional.modulo(val), self.currency)]
206
+ end
202
207
  end
203
208
  end
204
209
 
@@ -209,8 +214,8 @@ class Money
209
214
  # @return [Money]
210
215
  #
211
216
  # @example
212
- # Money.new(100).modulo(9) #=> #<Money @cents=1>
213
- # Money.new(100).modulo(Money.new(9)) #=> #<Money @cents=1>
217
+ # Money.new(100).modulo(9) #=> #<Money @fractional=1>
218
+ # Money.new(100).modulo(Money.new(9)) #=> #<Money @fractional=1>
214
219
  def modulo(val)
215
220
  self.divmod(val)[1]
216
221
  end
@@ -233,14 +238,14 @@ class Money
233
238
  # @return [Money]
234
239
  #
235
240
  # @example
236
- # Money.new(100).remainder(9) #=> #<Money @cents=1>
241
+ # Money.new(100).remainder(9) #=> #<Money @fractional=1>
237
242
  def remainder(val)
238
243
  a, b = self, val
239
244
  b = b.exchange_to(a.currency) if b.is_a?(Money) and a.currency != b.currency
240
245
 
241
246
  a_sign, b_sign = :pos, :pos
242
- a_sign = :neg if a.cents < 0
243
- b_sign = :neg if (b.is_a?(Money) and b.cents < 0) or (b < 0)
247
+ a_sign = :neg if a.fractional < 0
248
+ b_sign = :neg if (b.is_a?(Money) and b.fractional < 0) or (b < 0)
244
249
 
245
250
  return a.modulo(b) if a_sign == b_sign
246
251
  a.modulo(b) - (b.is_a?(Money) ? b : Money.new(b, a.currency))
@@ -251,9 +256,9 @@ class Money
251
256
  # @return [Money]
252
257
  #
253
258
  # @example
254
- # Money.new(-100).abs #=> #<Money @cents=100>
259
+ # Money.new(-100).abs #=> #<Money @fractional=100>
255
260
  def abs
256
- Money.new(self.cents.abs, self.currency)
261
+ Money.new(self.fractional.abs, self.currency)
257
262
  end
258
263
 
259
264
  # Test if the money amount is zero.
@@ -264,7 +269,7 @@ class Money
264
269
  # Money.new(100).zero? #=> false
265
270
  # Money.new(0).zero? #=> true
266
271
  def zero?
267
- cents == 0
272
+ fractional == 0
268
273
  end
269
274
 
270
275
  # Test if the money amount is non-zero. Returns this money object if it is
@@ -273,10 +278,10 @@ class Money
273
278
  # @return [Money, nil]
274
279
  #
275
280
  # @example
276
- # Money.new(100).nonzero? #=> #<Money @cents=100>
281
+ # Money.new(100).nonzero? #=> #<Money @fractional=100>
277
282
  # Money.new(0).nonzero? #=> nil
278
283
  def nonzero?
279
- cents != 0 ? self : nil
284
+ fractional != 0 ? self : nil
280
285
  end
281
286
 
282
287
  end
@@ -73,7 +73,7 @@ class Money
73
73
  # Money.ca_dollar(100).format(:no_cents => true) #=> "$1"
74
74
  # Money.ca_dollar(599).format(:no_cents => true) #=> "$5"
75
75
  #
76
- # @option *rules [Boolean] :no_cents_if_whole (false) Whether cents should be
76
+ # @option *rules [Boolean] :no_cents_if_whole (false) Whether cents should be
77
77
  # omitted if the cent value is zero
78
78
  #
79
79
  # @example
@@ -107,6 +107,10 @@ class Money
107
107
  # # You can specify a string as value to enforce using a particular symbol.
108
108
  # Money.new(100, "AWG").format(:symbol => "ƒ") #=> "ƒ1.00"
109
109
  #
110
+ # # You can specify a indian currency format
111
+ # Money.new(10000000, "INR").format(:south_asian_number_formatting => true) #=> "1,00,000.00"
112
+ # Money.new(10000000).format(:south_asian_number_formatting => true) #=> "$1,00,000.00"
113
+ #
110
114
  # @option *rules [Boolean, String, nil] :decimal_mark (true) Whether the
111
115
  # currency should be separated by the specified character or '.'
112
116
  #
@@ -145,7 +149,7 @@ class Money
145
149
  rules = normalize_formatting_rules(rules)
146
150
  rules = localize_formatting_rules(rules)
147
151
 
148
- if cents == 0
152
+ if fractional == 0
149
153
  if rules[:display_free].respond_to?(:to_str)
150
154
  return rules[:display_free]
151
155
  elsif rules[:display_free]
@@ -184,7 +188,7 @@ class Money
184
188
  end
185
189
 
186
190
  if symbol_value && !symbol_value.empty?
187
- formatted = if symbol_position == :before
191
+ formatted = if symbol_position == :before
188
192
  "#{symbol_value}#{formatted}"
189
193
  else
190
194
  symbol_space = rules[:symbol_after_without_space] ? "" : " "
@@ -192,7 +196,7 @@ class Money
192
196
  end
193
197
  end
194
198
 
195
- if rules.has_key?(:decimal_mark) and rules[:decimal_mark] and
199
+ if rules.has_key?(:decimal_mark) && rules[:decimal_mark] &&
196
200
  rules[:decimal_mark] != decimal_mark
197
201
  formatted.sub!(decimal_mark, rules[:decimal_mark])
198
202
  end
@@ -204,13 +208,7 @@ class Money
204
208
  end
205
209
 
206
210
  # Apply thousands_separator
207
- regexp_decimal = Regexp.escape(decimal_mark)
208
- regexp_format = if formatted =~ /#{regexp_decimal}/
209
- /(\d)(?=(?:\d{3})+(?:#{regexp_decimal}))/
210
- else
211
- /(\d)(?=(?:\d{3})+(?:[^\d]{1}|$))/
212
- end
213
- formatted.gsub!(regexp_format, "\\1#{thousands_separator_value}")
211
+ formatted.gsub!(regexp_format(formatted, rules, decimal_mark), "\\1#{thousands_separator_value}")
214
212
 
215
213
  if rules[:with_currency]
216
214
  formatted << " "
@@ -236,16 +234,29 @@ class Money
236
234
  rules = rules.pop
237
235
  rules = { rules => true } if rules.is_a?(Symbol)
238
236
  end
239
- if not rules.include?(:decimal_mark) and rules.include?(:separator)
237
+ if !rules.include?(:decimal_mark) && rules.include?(:separator)
240
238
  rules[:decimal_mark] = rules[:separator]
241
239
  end
242
- if not rules.include?(:thousands_separator) and rules.include?(:delimiter)
240
+ if !rules.include?(:thousands_separator) && rules.include?(:delimiter)
243
241
  rules[:thousands_separator] = rules[:delimiter]
244
242
  end
245
243
  rules
246
244
  end
247
245
  end
248
246
 
247
+ def regexp_format(formatted, rules, decimal_mark)
248
+ regexp_decimal = Regexp.escape(decimal_mark)
249
+ if rules[:south_asian_number_formatting]
250
+ /(\d+?)(?=(\d\d)+(\d)(?:\.))/
251
+ else
252
+ if formatted =~ /#{regexp_decimal}/
253
+ /(\d)(?=(?:\d{3})+(?:#{regexp_decimal}))/
254
+ else
255
+ /(\d)(?=(?:\d{3})+(?:[^\d]{1}|$))/
256
+ end
257
+ end
258
+ end
259
+
249
260
  def localize_formatting_rules(rules)
250
261
  if currency.iso_code == "JPY" && I18n.locale == :ja
251
262
  rules[:symbol] = "円"
@@ -21,12 +21,12 @@ class Money
21
21
  # the +input+ string.
22
22
  #
23
23
  # @example
24
- # '100'.to_money #=> #<Money @cents=10000>
25
- # '100.37'.to_money #=> #<Money @cents=10037>
26
- # '100 USD'.to_money #=> #<Money @cents=10000, @currency=#<Money::Currency id: usd>>
27
- # 'USD 100'.to_money #=> #<Money @cents=10000, @currency=#<Money::Currency id: usd>>
28
- # '$100 USD'.to_money #=> #<Money @cents=10000, @currency=#<Money::Currency id: usd>>
29
- # 'hello 2000 world'.to_money #=> #<Money @cents=200000 @currency=#<Money::Currency id: usd>>
24
+ # '100'.to_money #=> #<Money @fractional=10000>
25
+ # '100.37'.to_money #=> #<Money @fractional=10037>
26
+ # '100 USD'.to_money #=> #<Money @fractional=10000, @currency=#<Money::Currency id: usd>>
27
+ # 'USD 100'.to_money #=> #<Money @fractional=10000, @currency=#<Money::Currency id: usd>>
28
+ # '$100 USD'.to_money #=> #<Money @fractional=10000, @currency=#<Money::Currency id: usd>>
29
+ # 'hello 2000 world'.to_money #=> #<Money @fractional=200000 @currency=#<Money::Currency id: usd>>
30
30
  #
31
31
  # @example Mismatching currencies
32
32
  # 'USD 2000'.to_money("EUR") #=> ArgumentError
@@ -64,12 +64,12 @@ class Money
64
64
  end
65
65
  currency = Money::Currency.wrap(currency)
66
66
 
67
- cents = extract_cents(i, currency)
68
- new(cents, currency)
67
+ fractional = extract_cents(i, currency)
68
+ new(fractional, currency)
69
69
  end
70
70
 
71
71
  # Converts a String into a Money object treating the +value+
72
- # as dollars and converting them to the corresponding cents value,
72
+ # as amount and converting to fractional unit,
73
73
  # according to +currency+ subunit property,
74
74
  # before instantiating the Money object.
75
75
  #
@@ -84,13 +84,13 @@ class Money
84
84
  #
85
85
  # @example
86
86
  # Money.from_string("100")
87
- # #=> #<Money @cents=10000 @currency="USD">
87
+ # #=> #<Money @fractional=10000 @currency="USD">
88
88
  # Money.from_string("100", "USD")
89
- # #=> #<Money @cents=10000 @currency="USD">
89
+ # #=> #<Money @fractional=10000 @currency="USD">
90
90
  # Money.from_string("100", "EUR")
91
- # #=> #<Money @cents=10000 @currency="EUR">
91
+ # #=> #<Money @fractional=10000 @currency="EUR">
92
92
  # Money.from_string("100", "BHD")
93
- # #=> #<Money @cents=100 @currency="BHD">
93
+ # #=> #<Money @fractional=100 @currency="BHD">
94
94
  #
95
95
  # @see String#to_money
96
96
  # @see Money.parse
@@ -100,7 +100,7 @@ class Money
100
100
  end
101
101
 
102
102
  # Converts a Fixnum into a Money object treating the +value+
103
- # as dollars and converting them to the corresponding cents value,
103
+ # as amount and to corresponding fractional unit,
104
104
  # according to +currency+ subunit property,
105
105
  # before instantiating the Money object.
106
106
  #
@@ -111,13 +111,13 @@ class Money
111
111
  #
112
112
  # @example
113
113
  # Money.from_fixnum(100)
114
- # #=> #<Money @cents=10000 @currency="USD">
114
+ # #=> #<Money @fractional=10000 @currency="USD">
115
115
  # Money.from_fixnum(100, "USD")
116
- # #=> #<Money @cents=10000 @currency="USD">
116
+ # #=> #<Money @fractional=10000 @currency="USD">
117
117
  # Money.from_fixnum(100, "EUR")
118
- # #=> #<Money @cents=10000 @currency="EUR">
118
+ # #=> #<Money @fractional=10000 @currency="EUR">
119
119
  # Money.from_fixnum(100, "BHD")
120
- # #=> #<Money @cents=100 @currency="BHD">
120
+ # #=> #<Money @fractional=100 @currency="BHD">
121
121
  #
122
122
  # @see Fixnum#to_money
123
123
  # @see Money.from_numeric
@@ -129,7 +129,7 @@ class Money
129
129
  end
130
130
 
131
131
  # Converts a Float into a Money object treating the +value+
132
- # as dollars and converting them to the corresponding cents value,
132
+ # as dollars and to corresponding fractional unit,
133
133
  # according to +currency+ subunit property,
134
134
  # before instantiating the Money object.
135
135
  #
@@ -143,13 +143,13 @@ class Money
143
143
  #
144
144
  # @example
145
145
  # Money.from_float(100.0)
146
- # #=> #<Money @cents=10000 @currency="USD">
146
+ # #=> #<Money @fractional=10000 @currency="USD">
147
147
  # Money.from_float(100.0, "USD")
148
- # #=> #<Money @cents=10000 @currency="USD">
148
+ # #=> #<Money @fractional=10000 @currency="USD">
149
149
  # Money.from_float(100.0, "EUR")
150
- # #=> #<Money @cents=10000 @currency="EUR">
150
+ # #=> #<Money @fractional=10000 @currency="EUR">
151
151
  # Money.from_float(100.0, "BHD")
152
- # #=> #<Money @cents=100 @currency="BHD">
152
+ # #=> #<Money @fractional=100 @currency="BHD">
153
153
  #
154
154
  # @see Float#to_money
155
155
  # @see Money.from_numeric
@@ -159,7 +159,7 @@ class Money
159
159
  end
160
160
 
161
161
  # Converts a BigDecimal into a Money object treating the +value+
162
- # as dollars and converting them to the corresponding cents value,
162
+ # as dollars and converting to corresponding fractional unit,
163
163
  # according to +currency+ subunit property,
164
164
  # before instantiating the Money object.
165
165
  #
@@ -170,13 +170,13 @@ class Money
170
170
  #
171
171
  # @example
172
172
  # Money.from_bigdecimal(BigDecimal.new("100")
173
- # #=> #<Money @cents=10000 @currency="USD">
173
+ # #=> #<Money @fractional=10000 @currency="USD">
174
174
  # Money.from_bigdecimal(BigDecimal.new("100", "USD")
175
- # #=> #<Money @cents=10000 @currency="USD">
175
+ # #=> #<Money @fractional=10000 @currency="USD">
176
176
  # Money.from_bigdecimal(BigDecimal.new("100", "EUR")
177
- # #=> #<Money @cents=10000 @currency="EUR">
177
+ # #=> #<Money @fractional=10000 @currency="EUR">
178
178
  # Money.from_bigdecimal(BigDecimal.new("100", "BHD")
179
- # #=> #<Money @cents=100 @currency="BHD">
179
+ # #=> #<Money @fractional=100 @currency="BHD">
180
180
  #
181
181
  # @see BigDecimal#to_money
182
182
  # @see Money.from_numeric
@@ -188,7 +188,7 @@ class Money
188
188
  end
189
189
 
190
190
  # Converts a Numeric value into a Money object treating the +value+
191
- # as dollars and converting them to the corresponding cents value,
191
+ # as dollars and converting to corresponding fractional unit,
192
192
  # according to +currency+ subunit property,
193
193
  # before instantiating the Money object.
194
194
  #
@@ -209,9 +209,9 @@ class Money
209
209
  #
210
210
  # @example
211
211
  # Money.from_numeric(100)
212
- # #=> #<Money @cents=10000 @currency="USD">
212
+ # #=> #<Money @fractional=10000 @currency="USD">
213
213
  # Money.from_numeric(100.00)
214
- # #=> #<Money @cents=10000 @currency="USD">
214
+ # #=> #<Money @fractional=10000 @currency="USD">
215
215
  # Money.from_numeric("100")
216
216
  # #=> ArgumentError
217
217
  #
@@ -258,10 +258,10 @@ class Money
258
258
  #if the number ends with punctuation, just throw it out. If it means decimal,
259
259
  #it won't hurt anything. If it means a literal period or comma, this will
260
260
  #save it from being mis-interpreted as a decimal.
261
- num.chop! if num.match /[\.|,]$/
261
+ num.chop! if num.match(/[\.|,]$/)
262
262
 
263
263
  # gather all decimal_marks within the result number
264
- used_decimal_marks = num.scan /[^\d]/
264
+ used_decimal_marks = num.scan(/[^\d]/)
265
265
 
266
266
  # determine the number of unique decimal_marks within the number
267
267
  #