Module: Money::Parsing::ClassMethods
- Defined in:
- lib/money/money/parsing.rb
Instance Method Summary collapse
-
#extract_cents(input, currency = Money.default_currency) ⇒ Integer
Takes a number string and attempts to massage out the number.
-
#from_bigdecimal(value, currency = Money.default_currency) ⇒ Money
Converts a BigDecimal into a Money object treating the
value
as dollars and converting them to the corresponding cents value, according tocurrency
subunit property, before instantiating the Money object. -
#from_fixnum(value, currency = Money.default_currency) ⇒ Money
Converts a Fixnum into a Money object treating the
value
as dollars and converting them to the corresponding cents value, according tocurrency
subunit property, before instantiating the Money object. -
#from_float(value, currency = Money.default_currency) ⇒ Money
Converts a Float into a Money object treating the
value
as dollars and converting them to the corresponding cents value, according tocurrency
subunit property, before instantiating the Money object. -
#from_numeric(value, currency = Money.default_currency) ⇒ Money
Converts a Numeric value into a Money object treating the
value
as dollars and converting them to the corresponding cents value, according tocurrency
subunit property, before instantiating the Money object. -
#from_string(value, currency = Money.default_currency) ⇒ Money
Converts a String into a Money object treating the
value
as dollars and converting them to the corresponding cents value, according tocurrency
subunit property, before instantiating the Money object. -
#parse(input, currency = nil) ⇒ Money
Parses the current string and converts it to a
Money
object.
Instance Method Details
#extract_cents(input, currency = Money.default_currency) ⇒ Integer
Takes a number string and attempts to massage out the number.
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 |
# File 'lib/money/money/parsing.rb', line 228 def extract_cents(input, currency = Money.default_currency) # remove anything that's not a number, potential thousands_separator, or minus sign num = input.gsub(/[^\d|\.|,|\'|\-]/, '').strip # set a boolean flag for if the number is negative or not negative = num.split(//).first == "-" # if negative, remove the minus sign from the number # if it's not negative, the hyphen makes the value invalid if negative num = num.gsub(/^-/, '') else raise ArgumentError, "Invalid currency amount (hyphen)" if num.include?('-') end #if the number ends with punctuation, just throw it out. If it means decimal, #it won't hurt anything. If it means a literal period or comma, this will #save it from being mis-interpreted as a decimal. num.chop! if num.match /[\.|,]$/ # gather all decimal_marks within the result number used_decimal_marks = num.scan /[^\d]/ # determine the number of unique decimal_marks within the number # # e.g. # $1,234,567.89 would return 2 (, and .) # $125,00 would return 1 # $199 would return 0 # $1 234,567.89 would raise an error (decimal_marks are space, comma, and period) case used_decimal_marks.uniq.length # no decimal_mark or thousands_separator; major (dollars) is the number, and minor (cents) is 0 when 0 then major, minor = num, 0 # two decimal_marks, so we know the last item in this array is the # major/minor thousands_separator and the rest are decimal_marks when 2 decimal_mark, thousands_separator = used_decimal_marks.uniq # remove all decimal_marks, split on the thousands_separator major, minor = num.gsub(decimal_mark, '').split(thousands_separator) min = 0 unless min when 1 # we can't determine if the comma or period is supposed to be a decimal_mark or a thousands_separator # e.g. # 1,00 - comma is a thousands_separator # 1.000 - period is a thousands_separator # 1,000 - comma is a decimal_mark # 1,000,000 - comma is a decimal_mark # 10000,00 - comma is a thousands_separator # 1000,000 - comma is a thousands_separator # assign first decimal_mark for reusability decimal_mark = used_decimal_marks.first # decimal_mark is used as a decimal_mark when there are multiple instances, always if num.scan(decimal_mark).length > 1 # multiple matches; treat as decimal_mark major, minor = num.gsub(decimal_mark, ''), 0 else # ex: 1,000 - 1.0000 - 10001.000 # split number into possible major (dollars) and minor (cents) values possible_major, possible_minor = num.split(decimal_mark) possible_major ||= "0" possible_minor ||= "00" # if the minor (cents) length isn't 3, assign major/minor from the possibles # e.g. # 1,00 => 1.00 # 1.0000 => 1.00 # 1.2 => 1.20 if possible_minor.length != 3 # thousands_separator major, minor = possible_major, possible_minor else # minor length is three # let's try to figure out intent of the thousands_separator # the major length is greater than three, which means # the comma or period is used as a thousands_separator # e.g. # 1000,000 # 100000,000 if possible_major.length > 3 major, minor = possible_major, possible_minor else # number is in format ###{sep}### or ##{sep}### or #{sep}### # handle as , is sep, . is thousands_separator if decimal_mark == '.' major, minor = possible_major, possible_minor else major, minor = "#{possible_major}#{possible_minor}", 0 end end end end else # TODO: ParseError raise ArgumentError, "Invalid currency amount" end # build the string based on major/minor since decimal_mark/thousands_separator have been removed # avoiding floating point arithmetic here to ensure accuracy cents = (major.to_i * currency.subunit_to_unit) # Because of an bug in JRuby, we can't just call #floor minor = minor.to_s minor = if minor.size < currency.decimal_places (minor + ("0" * currency.decimal_places))[0,currency.decimal_places].to_i elsif minor.size > currency.decimal_places if minor[currency.decimal_places,1].to_i >= 5 minor[0,currency.decimal_places].to_i+1 else minor[0,currency.decimal_places].to_i end else minor.to_i end cents += minor # if negative, multiply by -1; otherwise, return positive cents negative ? cents * -1 : cents end |
#from_bigdecimal(value, currency = Money.default_currency) ⇒ Money
Converts a BigDecimal into a Money object treating the value
as dollars and converting them to the corresponding cents value, according to currency
subunit property, before instantiating the Money object.
172 173 174 175 176 |
# File 'lib/money/money/parsing.rb', line 172 def from_bigdecimal(value, currency = Money.default_currency) currency = Money::Currency.wrap(currency) amount = value * currency.subunit_to_unit new(amount.fix, currency) end |
#from_fixnum(value, currency = Money.default_currency) ⇒ Money
Converts a Fixnum into a Money object treating the value
as dollars and converting them to the corresponding cents value, according to currency
subunit property, before instantiating the Money object.
113 114 115 116 117 |
# File 'lib/money/money/parsing.rb', line 113 def from_fixnum(value, currency = Money.default_currency) currency = Money::Currency.wrap(currency) amount = value * currency.subunit_to_unit new(amount, currency) end |
#from_float(value, currency = Money.default_currency) ⇒ Money
Converts a Float into a Money object treating the value
as dollars and converting them to the corresponding cents value, according to currency
subunit property, before instantiating the Money object.
Behind the scenes, this method relies on Money.from_bigdecimal to avoid problems with floating point precision.
145 146 147 |
# File 'lib/money/money/parsing.rb', line 145 def from_float(value, currency = Money.default_currency) from_bigdecimal(BigDecimal.new(value.to_s), currency) end |
#from_numeric(value, currency = Money.default_currency) ⇒ Money
Converts a Numeric value into a Money object treating the value
as dollars and converting them to the corresponding cents value, according to currency
subunit property, before instantiating the Money object.
This method relies on various Money.from_*
methods and tries to forwards the call to the most appropriate method in order to reduce computation effort. For instance, if value
is an Integer, this method calls Money.from_fixnum instead of using the default Money.from_bigdecimal which adds the overload to converts the value into a slower BigDecimal instance.
211 212 213 214 215 216 217 218 219 220 |
# File 'lib/money/money/parsing.rb', line 211 def from_numeric(value, currency = Money.default_currency) case value when Fixnum from_fixnum(value, currency) when Numeric from_bigdecimal(BigDecimal.new(value.to_s), currency) else raise ArgumentError, "`value' should be a Numeric object" end end |
#from_string(value, currency = Money.default_currency) ⇒ Money
Converts a String into a Money object treating the value
as dollars and converting them to the corresponding cents value, according to currency
subunit property, before instantiating the Money object.
Behind the scenes, this method relies on Money.from_bigdecimal to avoid problems with string-to-numeric conversion.
86 87 88 |
# File 'lib/money/money/parsing.rb', line 86 def from_string(value, currency = Money.default_currency) from_bigdecimal(BigDecimal.new(value.to_s), currency) end |
#parse(input, currency = nil) ⇒ Money
Parses the current string and converts it to a Money
object. Excess characters will be discarded.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/money/money/parsing.rb', line 34 def parse(input, currency = nil) i = input.to_s # Get the currency. m = i.scan /([A-Z]{2,3})/ c = m[0] ? m[0][0] : nil # check that currency passed and embedded currency are the same, # and negotiate the final currency if currency.nil? and c.nil? currency = Money.default_currency elsif currency.nil? currency = c elsif c.nil? currency = currency elsif currency != c # TODO: ParseError raise ArgumentError, "Mismatching Currencies" end currency = Money::Currency.wrap(currency) cents = extract_cents(i, currency) new(cents, currency) end |