diff --git a/spec/std/sprintf_spec.cr b/spec/std/sprintf_spec.cr index 674a32c2ab30..520cb642bb50 100644 --- a/spec/std/sprintf_spec.cr +++ b/spec/std/sprintf_spec.cr @@ -372,6 +372,18 @@ describe "::sprintf" do assert_sprintf "%300.250d", 10.to_big_i ** 200, "#{" " * 50}#{"0" * 49}1#{"0" * 200}" assert_sprintf "%- #300.250X", 16.to_big_i ** 200 - 1, " 0X#{"0" * 50}#{"F" * 200}#{" " * 47}" end + + it "works with BigFloat" do + assert_sprintf "%d", 123.to_big_f, "123" + assert_sprintf "%80.70d", 2.to_big_i ** 200, " 0000000001606938044258990275541962092341162602522202993782792835301376" + assert_sprintf "%- #70.60X", 2.to_big_f ** 200 - 2.to_big_f ** 120, " 0X0000000000FFFFFFFFFFFFFFFFFFFF000000000000000000000000000000 " + end + + it "works with BigDecimal" do + assert_sprintf "%d", 123.to_big_d, "123" + assert_sprintf "%300.250d", 10.to_big_d ** 200, "#{" " * 50}#{"0" * 49}1#{"0" * 200}" + assert_sprintf "%- #300.250X", 16.to_big_d ** 200 - 1, " 0X#{"0" * 50}#{"F" * 200}#{" " * 47}" + end end it "doesn't stop at null character when doing '%'" do diff --git a/src/big/big_decimal.cr b/src/big/big_decimal.cr index a2c95fac2fff..bc33c9eaf617 100644 --- a/src/big/big_decimal.cr +++ b/src/big/big_decimal.cr @@ -894,3 +894,10 @@ struct Crystal::Hasher v &* value.sign end end + +# :nodoc: +struct String::Formatter(A) + def int(flags, arg : BigDecimal) : Nil + int(flags, arg.to_big_i) + end +end diff --git a/src/big/big_float.cr b/src/big/big_float.cr index 5a57500fbdd7..4f0feeb7e50d 100644 --- a/src/big/big_float.cr +++ b/src/big/big_float.cr @@ -671,3 +671,10 @@ module Math BigFloat.new { |mpf| LibGMP.mpf_sqrt(mpf, value) } end end + +# :nodoc: +struct String::Formatter(A) + def int(flags, arg : BigFloat) : Nil + int(flags, arg.to_big_i) + end +end diff --git a/src/string/formatter.cr b/src/string/formatter.cr index 347d65bcb340..48d99925f0bd 100644 --- a/src/string/formatter.cr +++ b/src/string/formatter.cr @@ -269,33 +269,35 @@ struct String::Formatter(A) pad arg.to_s.size, flags if flags.right_padding? end - def int(flags, arg) : Nil - raise ArgumentError.new("Expected an integer, not #{arg.inspect}") unless arg.responds_to?(:to_i) - int = arg.is_a?(Int) ? arg : arg.to_i - - precision = int_precision(int, flags) - base_str = int.to_s(flags.base, precision: precision, upcase: flags.uppercase?) + def int(flags, arg : Int) : Nil + precision = int_precision(arg, flags) + base_str = arg.to_s(flags.base, precision: precision, upcase: flags.uppercase?) str_size = base_str.bytesize - str_size += 1 if int >= 0 && (flags.plus || flags.space) - str_size += 2 if flags.sharp && flags.base != 10 && int != 0 + str_size += 1 if arg >= 0 && (flags.plus || flags.space) + str_size += 2 if flags.sharp && flags.base != 10 && arg != 0 - # If `int` is zero-padded, we let the precision argument do the right-justification + # If `arg` is zero-padded, we let the precision argument do the right-justification pad(str_size, flags) if flags.left_padding? && flags.padding_char != '0' - write_plus_or_space(int, flags) + write_plus_or_space(arg, flags) - if flags.sharp && int < 0 + if flags.sharp && arg < 0 @io << '-' write_base_prefix(flags) @io.write_string base_str.unsafe_byte_slice(1) else - write_base_prefix(flags) if flags.sharp && int != 0 + write_base_prefix(flags) if flags.sharp && arg != 0 @io << base_str end pad(str_size, flags) if flags.right_padding? end + def int(flags, arg) : Nil + raise ArgumentError.new("Expected an integer, not #{arg.inspect}") unless arg.responds_to?(:to_i) + int(flags, arg.to_i) + end + private def write_plus_or_space(arg, flags) if arg >= 0 if flags.plus