1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

number_to_rounded_converter: extract rounding logic

This commit is contained in:
Michael Hoy 2016-09-26 16:51:52 -05:00
parent b9c399de22
commit 8bdc9e8d87
3 changed files with 71 additions and 26 deletions

View file

@ -4,6 +4,7 @@ module ActiveSupport
eager_autoload do
autoload :NumberConverter
autoload :RoundingHelper
autoload :NumberToRoundedConverter
autoload :NumberToDelimitedConverter
autoload :NumberToHumanConverter

View file

@ -5,26 +5,14 @@ module ActiveSupport
self.validate_float = true
def convert
precision = options.delete :precision
helper = RoundingHelper.new(options)
rounded_number = helper.round(number)
if precision
case number
when Float, String
@number = BigDecimal(number.to_s)
when Rational
@number = BigDecimal(number, digit_count(number.to_i) + precision)
else
@number = number.to_d
end
if options.delete(:significant) && precision > 0
digits, rounded_number = digits_and_rounded_number(precision)
if precision = options[:precision]
if options[:significant] && precision > 0
digits = helper.digit_count(rounded_number)
precision -= digits
precision = 0 if precision < 0 # don't let it be negative
else
rounded_number = number.round(precision)
rounded_number = rounded_number.to_i if precision == 0 && rounded_number.finite?
rounded_number = rounded_number.abs if rounded_number.zero? # prevent showing negative zeros
end
formatted_string =
@ -38,7 +26,7 @@ module ActiveSupport
"%00.#{precision}f" % rounded_number
end
else
formatted_string = number
formatted_string = rounded_number
end
delimited_number = NumberToDelimitedConverter.convert(formatted_string, options)
@ -79,14 +67,6 @@ module ActiveSupport
number
end
end
def absolute_number(number)
number.respond_to?(:abs) ? number.abs : number.to_d.abs
end
def zero?
number.respond_to?(:zero?) ? number.zero? : number.to_d.zero?
end
end
end
end

View file

@ -0,0 +1,64 @@
module ActiveSupport
module NumberHelper
class RoundingHelper # :nodoc:
attr_reader :options
def initialize(options)
@options = options
end
def round(number)
return number unless precision
number = convert_to_decimal(number)
if significant && precision > 0
round_significant(number)
else
round_without_significant(number)
end
end
def digit_count(number)
return 1 if number.zero?
(Math.log10(absolute_number(number)) + 1).floor
end
private
def round_without_significant(number)
number = number.round(precision)
number = number.to_i if precision == 0 && number.finite?
number = number.abs if number.zero? # prevent showing negative zeros
number
end
def round_significant(number)
return 0 if number.zero?
digits = digit_count(number)
multiplier = 10**(digits - precision)
(number / BigDecimal.new(multiplier.to_f.to_s)).round * multiplier
end
def convert_to_decimal(number)
case number
when Float, String
number = BigDecimal(number.to_s)
when Rational
number = BigDecimal(number, digit_count(number.to_i) + precision)
else
number = number.to_d
end
end
def precision
options[:precision]
end
def significant
options[:significant]
end
def absolute_number(number)
number.respond_to?(:abs) ? number.abs : number.to_d.abs
end
end
end
end