aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib/active_support/number_helper/number_to_human.rb
diff options
context:
space:
mode:
authorMatt Bridges <mbridges.91@gmail.com>2013-06-12 11:53:29 -0500
committerMatt Bridges <mbridges.91@gmail.com>2013-07-01 12:31:36 -0500
commit2da9d67c278b0f37d2dea89ff557dc07cbb3a7b0 (patch)
tree8e657d583379a482f25719fed62a0960deb3e8a8 /activesupport/lib/active_support/number_helper/number_to_human.rb
parente47b6dee858e62dceba867dd160b968d679c82e8 (diff)
downloadrails-2da9d67c278b0f37d2dea89ff557dc07cbb3a7b0.tar.gz
rails-2da9d67c278b0f37d2dea89ff557dc07cbb3a7b0.tar.bz2
rails-2da9d67c278b0f37d2dea89ff557dc07cbb3a7b0.zip
Extract ActiveSupport::NumberHelper methods to classes
Due to the overall complexity of each method individually as well as the global shared private module methods, this pulls each helper into it's own converter class inheriting from a generic `NumberBuilder` class. * The `NumberBuilder` class contains the private methods needed for each helper method an eliminates the need for special definition of specialized private module methods. * The `ActiveSupport::NumberHelper::DEFAULTS` constant has been moved into the `NumberBuilder` class because the `NumberBuilder` is the only class which needs access to it. * For each of the builders, the `#convert` method is broken down to smaller parts and extracted into private methods for clarity of purpose. * Most of the mutation that once was necessary has now been eliminated. * Several of the mathematical operations for percentage, delimited, and rounded have been moved into private methods to ease readability and clarity. * Internationalization is still a bit crufty, and definitely could be improved, but it is functional and a bit easier to follow. The following helpers were extracted into their respective classes. * `#number_to_percentage` -> `NumberToPercentageConverter` * `#number_to_delimited` -> `NumberToDelimitedConverter` * `#number_to_phone` -> `NumberToPhoneConverter` * `#number_to_currency` -> `NumberToCurrencyConverter` * `#number_to_rounded` -> `NumberToRoundedConverter` * `#number_to_human_size` -> `NumberToHumanSizeConverter` * `#number_to_human` -> `NumberToHumanConverter`
Diffstat (limited to 'activesupport/lib/active_support/number_helper/number_to_human.rb')
-rw-r--r--activesupport/lib/active_support/number_helper/number_to_human.rb71
1 files changed, 71 insertions, 0 deletions
diff --git a/activesupport/lib/active_support/number_helper/number_to_human.rb b/activesupport/lib/active_support/number_helper/number_to_human.rb
new file mode 100644
index 0000000000..2b57c75720
--- /dev/null
+++ b/activesupport/lib/active_support/number_helper/number_to_human.rb
@@ -0,0 +1,71 @@
+require 'active_support/number_helper/number_converter'
+require 'active_support/number_helper/number_to_rounded'
+
+module ActiveSupport
+ module NumberHelper
+ class NumberToHumanConverter < NumberConverter # :nodoc:
+
+ DECIMAL_UNITS = { 0 => :unit, 1 => :ten, 2 => :hundred, 3 => :thousand, 6 => :million, 9 => :billion, 12 => :trillion, 15 => :quadrillion,
+ -1 => :deci, -2 => :centi, -3 => :mili, -6 => :micro, -9 => :nano, -12 => :pico, -15 => :femto }
+
+ self.namespace = :human
+ self.need_valid_float = true
+
+ def convert # :nodoc:
+ @number = Float(@number)
+
+ # for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
+ unless options.key?(:strip_insignificant_zeros)
+ options[:strip_insignificant_zeros] = true
+ end
+
+ units = opts[:units]
+ exponent = calculate_exponent(units)
+ @number = @number / (10 ** exponent)
+
+ unit = determine_unit(units, exponent)
+
+ rounded_number = NumberToRoundedConverter.new(@number, options).execute
+ format.gsub(/%n/, rounded_number).gsub(/%u/, unit).strip
+ end
+
+ private
+
+ def format
+ options[:format] || translate_in_locale('human.decimal_units.format')
+ end
+
+ def determine_unit(units, exponent)
+ exp = DECIMAL_UNITS[exponent]
+ case units
+ when Hash
+ units[exp] || ''
+ when String, Symbol
+ I18n.translate("#{units}.#{exp}", :locale => options[:locale], :count => number.to_i)
+ else
+ translate_in_locale("human.decimal_units.units.#{exp}", count: number.to_i)
+ end
+ end
+
+ def calculate_exponent(units)
+ exponent = number != 0 ? Math.log10(number.abs).floor : 0
+ unit_exponents(units).find { |e| exponent >= e } || 0
+ end
+
+ def unit_exponents(units)
+ inverted_decimal_units = DECIMAL_UNITS.invert
+ case units
+ when Hash
+ units
+ when String, Symbol
+ I18n.translate(units.to_s, :locale => options[:locale], :raise => true)
+ when nil
+ translate_in_locale("human.decimal_units.units", raise: true)
+ else
+ raise ArgumentError, ":units must be a Hash or String translation scope."
+ end.keys.map { |e_name| inverted_decimal_units[e_name] }.sort_by{ |e| -e }
+ end
+
+ end
+ end
+end