Skip to content

Commit

Permalink
Add unit_separator to Int#humanize and #humanize_bytes (#15176)
Browse files Browse the repository at this point in the history
  • Loading branch information
CTC97 authored Dec 3, 2024
1 parent aca8dd4 commit 22eb886
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 16 deletions.
13 changes: 13 additions & 0 deletions spec/std/humanize_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,16 @@ describe Number do
it { assert_prints 1.0e+34.humanize, "10,000Q" }
it { assert_prints 1.0e+35.humanize, "100,000Q" }

it { assert_prints 0.humanize(unit_separator: '_'), "0.0" }
it { assert_prints 0.123_456_78.humanize(5, unit_separator: '\u00A0'), "123.46\u00A0m" }
it { assert_prints 1.0e-14.humanize(unit_separator: ' '), "10.0 f" }
it { assert_prints 0.000_001.humanize(unit_separator: '\u2009'), "1.0\u2009µ" }
it { assert_prints 1_000_000_000_000.humanize(unit_separator: "__"), "1.0__T" }
it { assert_prints 0.000_000_001.humanize(unit_separator: "."), "1.0.n" }
it { assert_prints 1.0e+9.humanize(unit_separator: "\t"), "1.0\tG" }
it { assert_prints 123_456_789_012.humanize(unit_separator: 0), "1230G" }
it { assert_prints 123_456_789_012.humanize(unit_separator: nil), "123G" }

it { assert_prints Float32::INFINITY.humanize, "Infinity" }
it { assert_prints (-Float32::INFINITY).humanize, "-Infinity" }
it { assert_prints Float32::NAN.humanize, "NaN" }
Expand Down Expand Up @@ -261,6 +271,7 @@ describe Number do
it { assert_prints 1.0e+8.humanize(prefixes: CUSTOM_PREFIXES), "100d" }
it { assert_prints 1.0e+9.humanize(prefixes: CUSTOM_PREFIXES), "1,000d" }
it { assert_prints 1.0e+10.humanize(prefixes: CUSTOM_PREFIXES), "10,000d" }
it { assert_prints 1.0e+10.humanize(prefixes: CUSTOM_PREFIXES, unit_separator: '\u00A0'), "10,000\u00A0d" }
end
end
end
Expand All @@ -281,6 +292,7 @@ describe Int do
it { assert_prints 1025.humanize_bytes(format: Int::BinaryPrefixFormat::JEDEC), "1.0KB" }
it { assert_prints 1026.humanize_bytes(format: Int::BinaryPrefixFormat::JEDEC), "1.01KB" }
it { assert_prints 2048.humanize_bytes(format: Int::BinaryPrefixFormat::JEDEC), "2.0KB" }
it { assert_prints 2048.humanize_bytes(format: Int::BinaryPrefixFormat::JEDEC, unit_separator: '\u202F'), "2.0\u202FKB" }

it { assert_prints 1536.humanize_bytes(format: Int::BinaryPrefixFormat::JEDEC), "1.5KB" }
it { assert_prints 524288.humanize_bytes(format: Int::BinaryPrefixFormat::JEDEC), "512KB" }
Expand All @@ -289,6 +301,7 @@ describe Int do
it { assert_prints 1099511627776.humanize_bytes(format: Int::BinaryPrefixFormat::JEDEC), "1.0TB" }
it { assert_prints 1125899906842624.humanize_bytes(format: Int::BinaryPrefixFormat::JEDEC), "1.0PB" }
it { assert_prints 1152921504606846976.humanize_bytes(format: Int::BinaryPrefixFormat::JEDEC), "1.0EB" }
it { assert_prints 1152921504606846976.humanize_bytes(format: Int::BinaryPrefixFormat::JEDEC, unit_separator: '\u2009'), "1.0\u2009EB" }

it { assert_prints 1024.humanize_bytes(format: Int::BinaryPrefixFormat::IEC), "1.0kiB" }
it { assert_prints 1073741824.humanize_bytes(format: Int::BinaryPrefixFormat::IEC), "1.0GiB" }
Expand Down
36 changes: 20 additions & 16 deletions src/humanize.cr
Original file line number Diff line number Diff line change
Expand Up @@ -151,18 +151,21 @@ struct Number
# *separator* describes the decimal separator, *delimiter* the thousands
# delimiter (see `#format`).
#
# *unit_separator* is inserted between the value and the unit.
# Users are encouraged to use a non-breaking space ('\u00A0') to prevent output being split across lines.
#
# See `Int#humanize_bytes` to format a file size.
def humanize(io : IO, precision = 3, separator = '.', delimiter = ',', *, base = 10 ** 3, significant = true, prefixes : Indexable = SI_PREFIXES) : Nil
humanize(io, precision, separator, delimiter, base: base, significant: significant) do |magnitude, _|
def humanize(io : IO, precision = 3, separator = '.', delimiter = ',', *, base = 10 ** 3, significant = true, unit_separator = nil, prefixes : Indexable = SI_PREFIXES) : Nil
humanize(io, precision, separator, delimiter, base: base, significant: significant, unit_separator: unit_separator) do |magnitude, _|
magnitude = Number.prefix_index(magnitude, prefixes: prefixes)
{magnitude, Number.si_prefix(magnitude, prefixes)}
end
end

# :ditto:
def humanize(precision = 3, separator = '.', delimiter = ',', *, base = 10 ** 3, significant = true, prefixes = SI_PREFIXES) : String
def humanize(precision = 3, separator = '.', delimiter = ',', *, base = 10 ** 3, significant = true, unit_separator = nil, prefixes = SI_PREFIXES) : String
String.build do |io|
humanize(io, precision, separator, delimiter, base: base, significant: significant, prefixes: prefixes)
humanize(io, precision, separator, delimiter, base: base, significant: significant, unit_separator: unit_separator, prefixes: prefixes)
end
end

Expand Down Expand Up @@ -215,7 +218,7 @@ struct Number
# ```
#
# See `Int#humanize_bytes` to format a file size.
def humanize(io : IO, precision = 3, separator = '.', delimiter = ',', *, base = 10 ** 3, significant = true, &prefixes : (Int32, Float64) -> {Int32, _} | {Int32, _, Bool}) : Nil
def humanize(io : IO, precision = 3, separator = '.', delimiter = ',', *, base = 10 ** 3, significant = true, unit_separator = nil, &prefixes : (Int32, Float64) -> {Int32, _} | {Int32, _, Bool}) : Nil
if zero? || (responds_to?(:infinite?) && self.infinite?) || (responds_to?(:nan?) && self.nan?)
digits = 0
else
Expand Down Expand Up @@ -259,29 +262,30 @@ struct Number

number.format(io, separator, delimiter, decimal_places: decimal_places, only_significant: significant)

io << unit_separator if unit
io << unit
end

# :ditto:
def humanize(precision = 3, separator = '.', delimiter = ',', *, base = 10 ** 3, significant = true, &) : String
def humanize(precision = 3, separator = '.', delimiter = ',', *, base = 10 ** 3, significant = true, unit_separator = nil, &) : String
String.build do |io|
humanize(io, precision, separator, delimiter, base: base, significant: significant) do |magnitude, number|
humanize(io, precision, separator, delimiter, base: base, significant: significant, unit_separator: unit_separator) do |magnitude, number|
yield magnitude, number
end
end
end

# :ditto:
def humanize(io : IO, precision = 3, separator = '.', delimiter = ',', *, base = 10 ** 3, significant = true, prefixes : Proc) : Nil
humanize(io, precision, separator, delimiter, base: base, significant: significant) do |magnitude, number|
def humanize(io : IO, precision = 3, separator = '.', delimiter = ',', *, base = 10 ** 3, significant = true, unit_separator = nil, prefixes : Proc) : Nil
humanize(io, precision, separator, delimiter, base: base, significant: significant, unit_separator: unit_separator) do |magnitude, number|
prefixes.call(magnitude, number)
end
end

# :ditto:
def humanize(precision = 3, separator = '.', delimiter = ',', *, base = 10 ** 3, significant = true, prefixes : Proc) : String
def humanize(precision = 3, separator = '.', delimiter = ',', *, base = 10 ** 3, significant = true, unit_separator = nil, prefixes : Proc) : String
String.build do |io|
humanize(io, precision, separator, delimiter, base: base, significant: significant, prefixes: prefixes)
humanize(io, precision, separator, delimiter, base: base, significant: significant, unit_separator: unit_separator, prefixes: prefixes)
end
end
end
Expand Down Expand Up @@ -321,7 +325,7 @@ struct Int
# ```
#
# See `Number#humanize` for more details on the behaviour and arguments.
def humanize_bytes(io : IO, precision : Int = 3, separator = '.', *, significant : Bool = true, format : BinaryPrefixFormat = :IEC) : Nil
def humanize_bytes(io : IO, precision : Int = 3, separator = '.', *, significant : Bool = true, unit_separator = nil, format : BinaryPrefixFormat = :IEC) : Nil
humanize(io, precision, separator, nil, base: 1024, significant: significant) do |magnitude|
magnitude = Number.prefix_index(magnitude)

Expand All @@ -330,19 +334,19 @@ struct Int
unit = "B"
else
if format.iec?
unit = "#{prefix}iB"
unit = "#{unit_separator}#{prefix}iB"
else
unit = "#{prefix.upcase}B"
unit = "#{unit_separator}#{prefix.upcase}B"
end
end
{magnitude, unit, magnitude > 0}
end
end

# :ditto:
def humanize_bytes(precision : Int = 3, separator = '.', *, significant : Bool = true, format : BinaryPrefixFormat = :IEC) : String
def humanize_bytes(precision : Int = 3, separator = '.', *, significant : Bool = true, unit_separator = nil, format : BinaryPrefixFormat = :IEC) : String
String.build do |io|
humanize_bytes(io, precision, separator, significant: significant, format: format)
humanize_bytes(io, precision, separator, significant: significant, unit_separator: unit_separator, format: format)
end
end
end

0 comments on commit 22eb886

Please sign in to comment.