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:
parent
b9c399de22
commit
8bdc9e8d87
3 changed files with 71 additions and 26 deletions
|
@ -4,6 +4,7 @@ module ActiveSupport
|
|||
|
||||
eager_autoload do
|
||||
autoload :NumberConverter
|
||||
autoload :RoundingHelper
|
||||
autoload :NumberToRoundedConverter
|
||||
autoload :NumberToDelimitedConverter
|
||||
autoload :NumberToHumanConverter
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
Loading…
Reference in a new issue