diff --git a/CHANGELOG.md b/CHANGELOG.md index d8d7b4f76a41..a28d052ab49b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ Bug fixes: * Fixed File.fnmatch causes ArrayIndexOutOfBoundsException (#1845). * Make `String#concat` work with no or multiple arguments (#1519). * Make `Array#concat` work with no or multiple arguments (#1519). +* Fixed BigDecimal coerce initial argument using `to_str` (#1826). Compatibility: diff --git a/lib/truffle/bigdecimal.rb b/lib/truffle/bigdecimal.rb index 7f50ca143269..c79a24a7755e 100644 --- a/lib/truffle/bigdecimal.rb +++ b/lib/truffle/bigdecimal.rb @@ -326,8 +326,50 @@ def self.new(*args) end module Kernel - def BigDecimal(value, precision = Truffle::UNDEFINED) - TrufflePrimitive.bigdecimal_new value, precision, true + def BigDecimal(value, precision = Truffle::UNDEFINED, exception: true) + if !TrufflePrimitive.undefined?(precision) + precision = Truffle::Type.rb_num2int(precision) + if precision < 0 + if exception + raise ArgumentError, 'negative precision' + else + return nil + end + end + end + + case value + when nil + if exception + raise TypeError, "can't convert nil into BigDecimal" + else + return nil + end + when true + if exception + raise TypeError, "can't convert true into BigDecimal" + else + return nil + end + when false + if exception + raise TypeError, "can't convert false into BigDecimal" + else + return nil + end + when BigDecimal, Integer, Float, Rational, String + # conversion handled in primitive + else + if exception + value = StringValue(value) + else + value = Truffle::Type.rb_check_convert_type(count, String, :to_str) + if value.nil? + return nil + end + end + end + TrufflePrimitive.bigdecimal_new value, precision, exception end end diff --git a/spec/ruby/library/bigdecimal/BigDecimal_spec.rb b/spec/ruby/library/bigdecimal/BigDecimal_spec.rb index 179bde1aed45..0c07e46f5907 100644 --- a/spec/ruby/library/bigdecimal/BigDecimal_spec.rb +++ b/spec/ruby/library/bigdecimal/BigDecimal_spec.rb @@ -46,6 +46,12 @@ BigDecimal(" \t\n \r-Infinity \n").infinite?.should == -1 end + it "coerces the value argument with #to_str" do + initial = mock("value") + initial.should_receive(:to_str).and_return("123") + BigDecimal(initial).should == BigDecimal("123") + end + ruby_version_is ""..."2.6" do it "ignores trailing garbage" do BigDecimal("123E45ruby").should == BigDecimal("123E45")