From d2241ad65fbf0b6d3b6dfb699bab0ce15b76fd00 Mon Sep 17 00:00:00 2001 From: Konstantinos Tsanaktsidis Date: Wed, 16 Mar 2022 12:15:44 +1100 Subject: [PATCH] Fix number formatter following removal of Fixnum / Bignum from ruby-next (#50) The current ruby head in CI removes Fixnum and Bignum classes, which has led to broken builds. This fix attempts to coalesce the passed-in number to an `int64_t`; if that fails, it falls back to calling `unum_format_decimal` - if the versions of ICU does not support `unum_format_decimal`, a `RangeError` will be raised (which should not be an issue for modern versions of ICU) --- lib/ffi-icu/number_formatting.rb | 17 +++++++++++++---- spec/number_formatting_spec.rb | 5 +++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/lib/ffi-icu/number_formatting.rb b/lib/ffi-icu/number_formatting.rb index 2225afd..5614dd0 100644 --- a/lib/ffi-icu/number_formatting.rb +++ b/lib/ffi-icu/number_formatting.rb @@ -68,8 +68,19 @@ module ICU case number when Float needed_length = Lib.unum_format_double(@f, number, out_ptr, needed_length, nil, error) - when Fixnum - needed_length = Lib.unum_format_int32(@f, number, out_ptr, needed_length, nil, error) + when Integer + begin + # Try doing it fast, for integers that can be marshaled into an int64_t + needed_length = Lib.unum_format_int64(@f, number, out_ptr, needed_length, nil, error) + rescue RangeError + # Fall back to stringifying in Ruby and passing that to ICU + unless defined? Lib.unum_format_decimal + raise RangeError,"Number #{number} is too big to fit in int64_t and your "\ + "ICU version is too old to have unum_format_decimal" + end + string_version = number.to_s + needed_length = Lib.unum_format_decimal(@f, string_version, string_version.bytesize, out_ptr, needed_length, nil, error) + end when BigDecimal string_version = number.to_s('F') if Lib.respond_to? :unum_format_decimal @@ -77,8 +88,6 @@ module ICU else needed_length = Lib.unum_format_double(@f, number.to_f, out_ptr, needed_length, nil, error) end - when Bignum - needed_length = Lib.unum_format_int64(@f, number, out_ptr, needed_length, nil, error) end end out_ptr.string needed_length diff --git a/spec/number_formatting_spec.rb b/spec/number_formatting_spec.rb index 27e759c..03bff01 100644 --- a/spec/number_formatting_spec.rb +++ b/spec/number_formatting_spec.rb @@ -69,6 +69,11 @@ module ICU expect { NumberFormatting.create('en-US', :currency, style: :iso) }.to raise_error(StandardError) end end + + it 'should format a bignum' do + str = NumberFormatting.format_number("en", 1_000_000_000_000_000_000_000_000_000_000_000_000_000) + expect(str).to eq('1,000,000,000,000,000,000,000,000,000,000,000,000,000') + end end end # NumberFormatting end # ICU