blob: 273667fdae2f01d9a38c59b2c2abb39f83db1040 (
plain) (
tree)
|
|
module ActiveSupport
module NumberHelper
class NumberToRoundedConverter < NumberConverter # :nodoc:
self.namespace = :precision
self.validate_float = true
def convert
@number = Float(number)
precision = options.delete :precision
significant = options.delete :significant
if significant && precision > 0
digits, rounded_number = digits_and_rounded_number(precision)
precision -= digits
precision = 0 if precision < 0 # don't let it be negative
else
rounded_number = BigDecimal.new(number.to_s).round(precision).to_f
rounded_number = rounded_number.abs if rounded_number.zero? # prevent showing negative zeros
end
delimited_number = NumberToDelimitedConverter.convert("%01.#{precision}f" % rounded_number, options)
format_number(delimited_number)
end
private
def digits_and_rounded_number(precision)
if number.zero?
[1, 0]
else
digits = digit_count(number)
multiplier = 10 ** (digits - precision)
rounded_number = calculate_rounded_number(multiplier)
digits = digit_count(rounded_number) # After rounding, the number of digits may have changed
[digits, rounded_number]
end
end
def calculate_rounded_number(multiplier)
(BigDecimal.new(number.to_s) / BigDecimal.new(multiplier.to_f.to_s)).round.to_f * multiplier
end
def digit_count(number)
(Math.log10(number.abs) + 1).floor
end
def strip_insignificant_zeros
options[:strip_insignificant_zeros]
end
def format_number(number)
if strip_insignificant_zeros
escaped_separator = Regexp.escape(options[:separator])
number.sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '')
else
number
end
end
end
end
end
|