Module: EasyAttributes::FixedPoint

Defined in:
lib/easy_attributes.rb

Overview

Private Module: FixedPoint handles integer<->fixed-point numbers Fixed-Point rules are a hash of these values

:units          Use this as an alternative suffix name to the money methods ('dollars' gives 'xx_dollars')
:precision      The number of digits implied after the decimal, default is 2
:separator      The character to use after the integer part, default is '.'
:delimiter      The character to use between every 3 digits of the integer part, default none
:positive       The sprintf format to use for positive numbers, default is based on precision
:negative       The sprintf format to use for negative numbers, default is same as :positive
:zero           The sprintf format to use for zero, default is same as :positive
:nil            The sprintf format to use for nil values, default none
:unit           Prepend this to the front of the money value, say '$', default none
:blank          Return this value when the money string is empty or has no digits on assignment
:negative_regex A Regular Expression used to determine if a number is negative (and without a - sign)

Class Method Summary collapse

Class Method Details

.fixed_point_to_integer(value, *args) ⇒ Object

Private: Takes a string of a fixed-point representation (from editing) and converts it to the integer representation according to the passed rules hash rules - hash of fixed-point conversion rules

Returns the integer of the given money string. Uses relevant options from #easy_money



617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
# File 'lib/easy_attributes.rb', line 617

def self.fixed_point_to_integer(value, *args)
  opt = args.last.is_a?(Hash) ? args.pop : {}
  value = value.to_s
  value = value.gsub(opt[:delimiter],'') if opt[:delimiter]
  value = value.gsub(opt[:separator],'.') if opt[:separator]
  value = value.gsub(/^[^\d\.\-\,]+/,'')
  return (opt[:blank]||nil) unless value =~ /\d/
  m = value.to_s.match(opt[:negative_regex]||/^(-?)(.+\d)\s*cr/i)
  value = value.match(/^-/) ? m[2] : "-#{m[2]}" if m && m[2]

  # Money string ("123.45") to proper integer withough passing through the float transformation
  match = value.match(/(-?\d*)\.?(\d*)/)
  return 0 unless match
  value = match[1].to_i * (10 ** (opt[:precision]||2))
  cents = match[2]
  cents = cents + '0' while cents.length < (opt[:precision]||2)
  cents = cents.to_s[0,opt[:precision]||2]
  value += cents.to_i * (value<0 ? -1 : 1)
  value
end

.float_to_integer(value, *args) ⇒ Object

Returns the integer (cents) value from a Float rules - hash of fixed-point conversion rules



640
641
642
643
644
# File 'lib/easy_attributes.rb', line 640

def self.float_to_integer(value, *args)
  opt = args.last.is_a?(Hash) ? args.pop : {}
  return (opt[:blank]||nil) if value.nil?
  value = (value.to_f*(10**((opt[:precision]||2)+1))).to_i/10 # helps rounding 4.56 -> 455 ouch!
end

.format_fixed_point(value, pattern = "%.2m", *args) ⇒ Object

Replacing the sprintf function to deal with money as float. “… %[flags]m …” rules - hash of fixed-point conversion rules



648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
# File 'lib/easy_attributes.rb', line 648

def self.format_fixed_point(value, pattern="%.2m", *args)
  opt = args.last.is_a?(Hash) ? args.pop : {}
  sign = value < 0 ? -1 : 1
  dollars, cents = value.abs.divmod( 10 ** (opt[:precision]||2))
  dollars *= sign
  parts = pattern.match(/^(.*)%([-\. \d+]*)[fm](.*)/)
  return pattern unless parts
  intdec = parts[2].match(/(.*)\.(\d*)/)
  dprec, cprec = intdec ? [intdec[1], intdec[2]] : ['', '']
  dollars = sprintf("%#{dprec}d", dollars)
  cents = '0' + cents.to_s while cents.to_s.length < (opt[:precision]||2)
  cents = cents.to_s[0,cprec.to_i]
  cents = cents + '0' while cents.length < cprec.to_i
  value = parts[1] + "#{(dollars.to_i==0 && sign==-1) ? '-' : '' }#{dollars}#{cents>' '? '.':''}#{cents}" + parts[3]
  value
end

.integer_to_fixed_point(value, *args) ⇒ Object

Private: Formats an integer value as the defined fixed-point representation value - integer representation of number rules - hash of fixed-point conversion rules

Returns the fixed-point representation as a string for editing



573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
# File 'lib/easy_attributes.rb', line 573

def self.integer_to_fixed_point(value, *args)
  opt = args.last.is_a?(Hash) ? args.pop : {}
  opt[:positive] ||= "%.#{opt[:precision]||2}f"
  pattern =
  if value.nil?
    value = 0
    opt[:nil] || opt[:positive]
  else
    case value <=> 0
    when 1 then opt[:positive]
    when 0 then opt[:zero] || opt[:positive]
    else
      value = -value if opt[:negative] && opt[:negative] != opt[:positive]
      opt[:negative] || opt[:positive]
    end
  end
  value = self.format_fixed_point( value, pattern, opt)
  value = opt[:unit]+value if opt[:unit]
  value.gsub!(/\./,opt[:separator]) if opt[:separator]
  if opt[:delimiter] && (m = value.match(/^(\D*)(\d+)(.*)/))
    # Adapted From Rails' ActionView::Helpers::NumberHelper
    n = m[2].gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{opt[:delimiter]}")
    value=m[1]+n+m[3]
  end
  value
end

.integer_to_float(value, *args) ⇒ Object

Private: Converts the integer into a float value with the given fixed-point definition

value - integer to convert rules - hash of fixed-point conversion rules

Returns a float of the converted value



606
607
608
609
610
# File 'lib/easy_attributes.rb', line 606

def self.integer_to_float(value, *args)
  opt = args.last.is_a?(Hash) ? args.pop : {}
  return (opt[:blank]||nil) if value.nil?
  value = 1.0 * value / (10**(opt[:precision]||2))
end