From 24a7e609437d9e6ea61140492461631c4d5bd665 Mon Sep 17 00:00:00 2001 From: Jack Xu Date: Wed, 28 Aug 2013 23:46:53 -0500 Subject: [PATCH] Enable number_to_percentage to keep the number's precision by allowing :precision to be nil number_helper.number_to_percentage(1000, precision: nil) # => "1000%" --- activesupport/CHANGELOG.md | 5 +++ .../lib/active_support/number_helper.rb | 40 +++++++++++-------- activesupport/test/number_helper_test.rb | 4 ++ 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index 81c6246c5c..7825e69394 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -184,4 +184,9 @@ *Daniel Schierbeck* +* Enable number_to_percentage to keep the number's precision by allowing :precision to be nil + + + *Jack Xu* + Please check [4-0-stable](https://github.com/rails/rails/blob/4-0-stable/activesupport/CHANGELOG.md) for previous changes. diff --git a/activesupport/lib/active_support/number_helper.rb b/activesupport/lib/active_support/number_helper.rb index 54cff6d394..237ef7087f 100644 --- a/activesupport/lib/active_support/number_helper.rb +++ b/activesupport/lib/active_support/number_helper.rb @@ -228,7 +228,7 @@ module ActiveSupport # * :locale - Sets the locale to be used for formatting # (defaults to current locale). # * :precision - Sets the precision of the number - # (defaults to 3). + # (defaults to 3). Keeps the number's precision if nil. # * :significant - If +true+, precision will be the # # of significant_digits. If +false+, the # of fractional # digits (defaults to +false+). @@ -250,6 +250,7 @@ module ActiveSupport # number_to_percentage(1000, delimiter: '.', separator: ',') # => 1.000,000% # number_to_percentage(302.24398923423, precision: 5) # => 302.24399% # number_to_percentage(1000, locale: :fr) # => 1 000,000% + # number_to_percentage:(1000, precision: nil) # => 1000% # number_to_percentage('98a') # => 98a% # number_to_percentage(100, format: '%n %') # => 100 % def number_to_percentage(number, options = {}) @@ -310,7 +311,7 @@ module ActiveSupport # * :locale - Sets the locale to be used for formatting # (defaults to current locale). # * :precision - Sets the precision of the number - # (defaults to 3). + # (defaults to 3). Keeps the number's precision if nil. # * :significant - If +true+, precision will be the # # of significant_digits. If +false+, the # of fractional # digits (defaults to +false+). @@ -331,6 +332,7 @@ module ActiveSupport # number_to_rounded(111.2345, significant: true) # => 111 # number_to_rounded(111.2345, precision: 1, significant: true) # => 100 # number_to_rounded(13, precision: 5, significant: true) # => 13.000 + # number_to_rounded(13, precision: nil) # => 13 # number_to_rounded(111.234, locale: :fr) # => 111,234 # # number_to_rounded(13, precision: 5, significant: true, strip_insignificant_zeros: true) @@ -341,7 +343,6 @@ module ActiveSupport # # => 1.111,23 def number_to_rounded(number, options = {}) return number unless valid_float?(number) - number = Float(number) options = options.symbolize_keys defaults = format_options(options[:locale], :precision) @@ -351,22 +352,27 @@ module ActiveSupport significant = options.delete :significant strip_insignificant_zeros = options.delete :strip_insignificant_zeros - if significant && precision > 0 - if number == 0 - digits, rounded_number = 1, 0 - else - digits = (Math.log10(number.abs) + 1).floor - multiplier = 10 ** (digits - precision) - rounded_number = (BigDecimal.new(number.to_s) / BigDecimal.new(multiplier.to_f.to_s)).round.to_f * multiplier - digits = (Math.log10(rounded_number.abs) + 1).floor # After rounding, the number of digits may have changed - end - precision -= digits - precision = 0 if precision < 0 # don't let it be negative + if precision.nil? + formatted_number = self.number_to_delimited(number, options) 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 + number = Float(number) + if significant && precision > 0 + if number == 0 + digits, rounded_number = 1, 0 + else + digits = (Math.log10(number.abs) + 1).floor + multiplier = 10 ** (digits - precision) + rounded_number = (BigDecimal.new(number.to_s) / BigDecimal.new(multiplier.to_f.to_s)).round.to_f * multiplier + digits = (Math.log10(rounded_number.abs) + 1).floor # After rounding, the number of digits may have changed + end + 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 + formatted_number = self.number_to_delimited("%01.#{precision}f" % rounded_number, options) end - formatted_number = self.number_to_delimited("%01.#{precision}f" % rounded_number, options) if strip_insignificant_zeros escaped_separator = Regexp.escape(options[:separator]) formatted_number.sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '') diff --git a/activesupport/test/number_helper_test.rb b/activesupport/test/number_helper_test.rb index 1fadef3637..a30e8178c7 100644 --- a/activesupport/test/number_helper_test.rb +++ b/activesupport/test/number_helper_test.rb @@ -79,6 +79,10 @@ module ActiveSupport assert_equal("123.4%", number_helper.number_to_percentage(123.400, :precision => 3, :strip_insignificant_zeros => true)) assert_equal("1.000,000%", number_helper.number_to_percentage(1000, :delimiter => '.', :separator => ',')) assert_equal("1000.000 %", number_helper.number_to_percentage(1000, :format => "%n %")) + assert_equal("1000%", number_helper.number_to_percentage(1000, precision: nil)) + assert_equal("1000%", number_helper.number_to_percentage(1000, precision: nil)) + assert_equal("1000.1%", number_helper.number_to_percentage(1000.1, precision: nil)) + assert_equal("-0.13 %", number_helper.number_to_percentage("-0.13", precision: nil, :format => "%n %")) end end