diff --git a/actionpack/test/template/number_helper_test.rb b/actionpack/test/template/number_helper_test.rb index d8fffe75edc33..854fabd21f8ad 100644 --- a/actionpack/test/template/number_helper_test.rb +++ b/actionpack/test/template/number_helper_test.rb @@ -179,13 +179,24 @@ def test_number_to_human_size_with_si_prefix assert_equal '3 Bytes', number_to_human_size(3.14159265, :prefix => :si) assert_equal '123 Bytes', number_to_human_size(123.0, :prefix => :si) assert_equal '123 Bytes', number_to_human_size(123, :prefix => :si) - assert_equal '1.23 KB', number_to_human_size(1234, :prefix => :si) - assert_equal '12.3 KB', number_to_human_size(12345, :prefix => :si) + assert_equal '1.23 kB', number_to_human_size(1234, prefix: :si) + assert_equal '12.3 kB', number_to_human_size(12345, prefix: :si) assert_equal '1.23 MB', number_to_human_size(1234567, :prefix => :si) assert_equal '1.23 GB', number_to_human_size(1234567890, :prefix => :si) assert_equal '1.23 TB', number_to_human_size(1234567890123, :prefix => :si) end + def test_number_to_human_size_with_iso_prefix + assert_equal '3 Bytes', number_to_human_size(3.14159265, prefix: :iso) + assert_equal '123 Bytes', number_to_human_size(123.0, prefix: :iso) + assert_equal '123 Bytes', number_to_human_size(123, prefix: :iso) + assert_equal '1.21 KiB', number_to_human_size(1234, prefix: :iso) + assert_equal '12.1 KiB', number_to_human_size(12345, prefix: :iso) + assert_equal '1.18 MiB', number_to_human_size(1234567, prefix: :iso) + assert_equal '1.15 GiB', number_to_human_size(1234567890, prefix: :iso) + assert_equal '1.12 TiB', number_to_human_size(1234567890123, prefix: :iso) + end + def test_number_to_human_size_with_options_hash assert_equal '1.2 MB', number_to_human_size(1234567, :precision => 2) assert_equal '3 Bytes', number_to_human_size(3.14159265, :precision => 4) diff --git a/activesupport/lib/active_support/locale/en.yml b/activesupport/lib/active_support/locale/en.yml index f4900dc9359a1..979c55db07de4 100644 --- a/activesupport/lib/active_support/locale/en.yml +++ b/activesupport/lib/active_support/locale/en.yml @@ -106,6 +106,22 @@ en: mb: "MB" gb: "GB" tb: "TB" + si_units: + byte: + one: "Byte" + other: "Bytes" + kb: "kB" + mb: "MB" + gb: "GB" + tb: "TB" + iso_units: + byte: + one: "Byte" + other: "Bytes" + kb: "KiB" + mb: "MiB" + gb: "GiB" + tb: "TiB" # Used in NumberHelper.number_to_human() decimal_units: format: "%n %u" diff --git a/activesupport/lib/active_support/number_helper.rb b/activesupport/lib/active_support/number_helper.rb index 2191471daac23..afc4c76cc2af7 100644 --- a/activesupport/lib/active_support/number_helper.rb +++ b/activesupport/lib/active_support/number_helper.rb @@ -4,9 +4,19 @@ require 'active_support/i18n' module ActiveSupport + class << self + delegate :default_size_prefix, :default_size_prefix=, + to: :'ActiveSupport::NumberHelper' + end + module NumberHelper extend self + class << self + attr_accessor :default_size_prefix + end + self.default_size_prefix = :customary + DEFAULTS = { # Used in number_to_delimited # These are also the defaults for 'currency', 'percentage', 'precision', and 'human' @@ -74,6 +84,20 @@ module NumberHelper mb: "MB", gb: "GB", tb: "TB" + }, + iso_units: { + byte: "Bytes", + kb: "KiB", + mb: "MiB", + gb: "GiB", + tb: "TiB" + }, + si_units: { + byte: "Bytes", + kb: "kB", + mb: "MB", + gb: "GB", + tb: "TB" } }, # Used in number_to_human @@ -398,8 +422,12 @@ def number_to_rounded(number, options = {}) # * :strip_insignificant_zeros - If +true+ removes # insignificant zeros after the decimal separator (defaults to # +true+) - # * :prefix - If +:si+ formats the number using the SI - # prefix (defaults to :binary) + # * :prefix - If +:si+ formats the number using SI + # prefixes. If +:iec+ or +:iso+ formats the numbers using + # ISO/IEC 80000 binary prefixes. If +:customary+ formats the + # number to customary binary prefixes. Defaults to + # +ActiveSupport.default_size_prefix+, which is +:customary+, + # but can be set to one of the others. # # ==== Examples # @@ -432,10 +460,23 @@ def number_to_human_size(number, options = {}) storage_units_format = translate_number_value_with_default('human.storage_units.format', :locale => options[:locale], :raise => true) - base = options[:prefix] == :si ? 1000 : 1024 + options[:prefix] ||= ActiveSupport.default_size_prefix + case options[:prefix] + when :si + base = 1000 + system_key = "si_units" + when :iec, :iso + base = 1024 + system_key = "iso_units" + when :customary + base = 1024 + system_key = "units" + else + raise ArgumentError, ":prefix must be :customary, :si, :iec, or :iso" + end if number.to_i < base - unit = translate_number_value_with_default('human.storage_units.units.byte', :locale => options[:locale], :count => number.to_i, :raise => true) + unit = translate_number_value_with_default("human.storage_units.#{system_key}.byte", locale: options[:locale], count: number.to_i, raise: true) storage_units_format.gsub(/%n/, number.to_i.to_s).gsub(/%u/, unit) else max_exp = STORAGE_UNITS.size - 1 @@ -444,7 +485,7 @@ def number_to_human_size(number, options = {}) number /= base ** exponent unit_key = STORAGE_UNITS[exponent] - unit = translate_number_value_with_default("human.storage_units.units.#{unit_key}", :locale => options[:locale], :count => number, :raise => true) + unit = translate_number_value_with_default("human.storage_units.#{system_key}.#{unit_key}", locale: options[:locale], count: number, raise: true) formatted_number = self.number_to_rounded(number, options) storage_units_format.gsub(/%n/, formatted_number).gsub(/%u/, unit) diff --git a/activesupport/test/core_ext/numeric_ext_test.rb b/activesupport/test/core_ext/numeric_ext_test.rb index 435f4aa5a14b3..d5935a353dc44 100644 --- a/activesupport/test/core_ext/numeric_ext_test.rb +++ b/activesupport/test/core_ext/numeric_ext_test.rb @@ -344,13 +344,24 @@ def test_to_s__human_size_with_si_prefix assert_equal '3 Bytes', 3.14159265.to_s(:human_size, :prefix => :si) assert_equal '123 Bytes', 123.0.to_s(:human_size, :prefix => :si) assert_equal '123 Bytes', 123.to_s(:human_size, :prefix => :si) - assert_equal '1.23 KB', 1234.to_s(:human_size, :prefix => :si) - assert_equal '12.3 KB', 12345.to_s(:human_size, :prefix => :si) + assert_equal '1.23 kB', 1234.to_s(:human_size, prefix: :si) + assert_equal '12.3 kB', 12345.to_s(:human_size, prefix: :si) assert_equal '1.23 MB', 1234567.to_s(:human_size, :prefix => :si) assert_equal '1.23 GB', 1234567890.to_s(:human_size, :prefix => :si) assert_equal '1.23 TB', 1234567890123.to_s(:human_size, :prefix => :si) end + def test_to_s__human_size_with_iso_prefix + assert_equal '3 Bytes', 3.14159265.to_s(:human_size, prefix: :iso) + assert_equal '123 Bytes', 123.0.to_s(:human_size, prefix: :iso) + assert_equal '123 Bytes', 123.to_s(:human_size, prefix: :iso) + assert_equal '1.21 KiB', 1234.to_s(:human_size, prefix: :iso) + assert_equal '12.1 KiB', 12345.to_s(:human_size, prefix: :iso) + assert_equal '1.18 MiB', 1234567.to_s(:human_size, prefix: :iso) + assert_equal '1.15 GiB', 1234567890.to_s(:human_size, prefix: :iso) + assert_equal '1.12 TiB', 1234567890123.to_s(:human_size, prefix: :iso) + end + def test_to_s__human_size_with_options_hash assert_equal '1.2 MB', 1234567.to_s(:human_size, :precision => 2) assert_equal '3 Bytes', 3.14159265.to_s(:human_size, :precision => 4) diff --git a/activesupport/test/number_helper_test.rb b/activesupport/test/number_helper_test.rb index 5f54587f93ff6..f309dc1a81e9e 100644 --- a/activesupport/test/number_helper_test.rb +++ b/activesupport/test/number_helper_test.rb @@ -209,14 +209,51 @@ def test_number_to_human_size_with_si_prefix assert_equal '3 Bytes', number_helper.number_to_human_size(3.14159265, :prefix => :si) assert_equal '123 Bytes', number_helper.number_to_human_size(123.0, :prefix => :si) assert_equal '123 Bytes', number_helper.number_to_human_size(123, :prefix => :si) - assert_equal '1.23 KB', number_helper.number_to_human_size(1234, :prefix => :si) - assert_equal '12.3 KB', number_helper.number_to_human_size(12345, :prefix => :si) + assert_equal '1.23 kB', number_helper.number_to_human_size(1234, prefix: :si) + assert_equal '12.3 kB', number_helper.number_to_human_size(12345, prefix: :si) assert_equal '1.23 MB', number_helper.number_to_human_size(1234567, :prefix => :si) assert_equal '1.23 GB', number_helper.number_to_human_size(1234567890, :prefix => :si) assert_equal '1.23 TB', number_helper.number_to_human_size(1234567890123, :prefix => :si) end end + def test_number_to_human_size_with_iso_prefix + [:iec, :iso].each do |prefix| + [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| + assert_equal '3 Bytes', number_helper.number_to_human_size(3.14159265, prefix: prefix) + assert_equal '123 Bytes', number_helper.number_to_human_size(123.0, prefix: prefix) + assert_equal '123 Bytes', number_helper.number_to_human_size(123, prefix: prefix) + assert_equal '1.21 KiB', number_helper.number_to_human_size(1234, prefix: prefix) + assert_equal '12.1 KiB', number_helper.number_to_human_size(12345, prefix: prefix) + assert_equal '1.18 MiB', number_helper.number_to_human_size(1234567, prefix: prefix) + assert_equal '1.15 GiB', number_helper.number_to_human_size(1234567890, prefix: prefix) + assert_equal '1.12 TiB', number_helper.number_to_human_size(1234567890123, prefix: prefix) + end + end + end + + def test_number_to_human_size_using_active_support_default_size_prefix + begin + ActiveSupport.default_size_prefix = :iso + [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| + assert_equal '1.12 TiB', number_helper.number_to_human_size(1234567890123) + end + [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| + assert_equal '1.12 TB', number_helper.number_to_human_size(1234567890123, prefix: :customary) + end + ensure + ActiveSupport.default_size_prefix = :customary + end + end + + def test_number_to_human_size_with_invalid_prefix + [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| + assert_raise ArgumentError do + number_helper.number_to_human_size(1, prefix: :unknown_prefix) + end + end + end + def test_number_to_human_size_with_options_hash [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| assert_equal '1.2 MB', number_helper.number_to_human_size(1234567, :precision => 2)