diff options
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.rb | 71 |
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 |