aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib/active_support/number_helper/number_to_rounded.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport/lib/active_support/number_helper/number_to_rounded.rb')
-rw-r--r--activesupport/lib/active_support/number_helper/number_to_rounded.rb62
1 files changed, 62 insertions, 0 deletions
diff --git a/activesupport/lib/active_support/number_helper/number_to_rounded.rb b/activesupport/lib/active_support/number_helper/number_to_rounded.rb
new file mode 100644
index 0000000000..817ac1ebb2
--- /dev/null
+++ b/activesupport/lib/active_support/number_helper/number_to_rounded.rb
@@ -0,0 +1,62 @@
+require 'active_support/number_helper/number_converter'
+
+module ActiveSupport
+ module NumberHelper
+ class NumberToRoundedConverter < NumberConverter # :nodoc:
+
+ self.namespace = :precision
+ self.need_valid_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.new("%01.#{precision}f" % rounded_number, options).execute
+ format_number(delimited_number)
+ end
+
+ private
+
+ def digits_and_rounded_number(precision)
+ return [1,0] if @number.zero?
+ 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
+
+ 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