lib/reckon/money.rb in reckon-0.6.0 vs lib/reckon/money.rb in reckon-0.6.1

- old
+ new

@@ -3,75 +3,76 @@ module Reckon class Money include Comparable attr_accessor :amount, :currency, :suffixed - def initialize( amount, options = {} ) - if options[:inverse] - @amount = -1*amount.to_f - else - @amount = amount.to_f - end + def initialize(amount, options = {}) + @options = options + @amount_raw = amount + @raw = options[:raw] + + @amount = parse(amount, options) + @amount = -@amount if options[:inverse] @currency = options[:currency] || "$" @suffixed = options[:suffixed] end def to_f return @amount end + def to_s + return @options[:raw] ? "#{@amount_raw} | #{@amount}" : @amount + end + + # unary minus + # ex + # m = Money.new + # -m def -@ - Money.new( -@amount, :currency => @currency, :suffixed => @suffixed ) + Money.new(-@amount, :currency => @currency, :suffixed => @suffixed) end - def <=>( mon ) + def <=>(mon) other_amount = mon.to_f if @amount < other_amount -1 elsif @amount > other_amount 1 else 0 end end - def pretty( negate = false ) + def pretty(negate = false) + if @raw + return @amount_raw unless negate + + return @amount_raw[0] == '-' ? @amount_raw[1..-1] : "-#{@amount_raw}" + end + if @suffixed (@amount >= 0 ? " " : "") + sprintf("%0.2f #{@currency}", @amount * (negate ? -1 : 1)) else (@amount >= 0 ? " " : "") + sprintf("%0.2f", @amount * (negate ? -1 : 1)).gsub(/^((\-)|)(?=\d)/, "\\1#{@currency}") end end - def Money::from_s( value, options = {} ) + def parse(value, options = {}) + value = value.to_s # Empty string is treated as money with value 0 - return Money.new( 0.00, options ) if value.empty? + return value.to_f if value.to_s.empty? - # Remove 1000 separaters and replace , with . if comma_separates_cents - # 1.000,00 -> 1000.00 - value = value.gsub(/\./, '').gsub(/,/, '.') if options[:comma_separates_cents] - value = value.gsub(/,/, '') - - money_format_regex = /^(.*?)(\d+\.\d\d)/ # Money has two decimal precision - any_number_regex = /^(.*?)([\d\.]+)/ - - # Prefer matching the money_format, match any number otherwise - m = value.match( money_format_regex ) || - value.match( any_number_regex ) - if m - amount = m[2].to_f - # Check whether the money had a - or (, which indicates negative amounts - if (m[1].match( /^[\(-]/ ) || m[1].match( /-$/ )) - amount *= -1 - end - return Money.new( amount, options ) - else - return nil - end + invert = value.match(/^\(.*\)$/) + value = value.gsub(/[^0-9,.-]/, '') + value = value.tr('.', '').tr(',', '.') if options[:comma_separates_cents] + value = value.tr(',', '') + value = value.to_f + return invert ? -value : value end - def Money::likelihood( entry ) + def Money::likelihood(entry) money_score = 0 # digits separated by , or . with no more than 2 trailing digits money_score += 40 if entry.match(/\d+[,.]\d{2}[^\d]*$/) money_score += 10 if entry[/^\$?\-?\$?\d+[\.,\d]*?[\.,]\d\d$/] money_score += 10 if entry[/\d+[\.,\d]*?[\.,]\d\d$/] @@ -81,34 +82,33 @@ money_score end end class MoneyColumn < Array - def initialize( arr = [], options = {} ) - arr.each { |str| self.push( Money.from_s( str, options ) ) } + def initialize(arr = [], options = {}) + arr.each { |str| push(Money.new(str, options)) } end def positive? - self.each do |money| - return false if money < 0 if money + each do |money| + return false if money && money < 0 end true end - def merge!( other_column ) + def merge!(other_column) invert = false - invert = true if self.positive? && other_column.positive? - self.each_with_index do |mon, i| + invert = true if positive? && other_column.positive? + each_with_index do |mon, i| other = other_column[i] - return nil if (!mon || !other) - if mon != 0.00 && other == 0.0 - if invert - self[i]= -mon - end - elsif mon == 0.00 && other != 0.00 + return nil if !mon || !other + + if mon != 0.0 && other == 0.0 + self[i] = -mon if invert + elsif mon == 0.0 && other != 0.0 self[i] = other else - return nil + self[i] = Money.new(0) end end self end end