mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Add Integer.try_convert [Feature #15211]
This commit is contained in:
parent
eee709595c
commit
301d194ee3
Notes:
git
2021-07-16 17:50:23 +09:00
6 changed files with 83 additions and 3 deletions
5
NEWS.md
5
NEWS.md
|
@ -92,6 +92,10 @@ Outstanding ones only.
|
|||
* File.dirname now accepts an optional argument for the level to
|
||||
strip path components. [[Feature #12194]]
|
||||
|
||||
* Integer
|
||||
|
||||
* Integer.try_convert is added. [[Feature #15211]]
|
||||
|
||||
* Module
|
||||
|
||||
* Module#prepend now modifies the ancestor chain if the receiver
|
||||
|
@ -191,6 +195,7 @@ Excluding feature bug fixes.
|
|||
[Feature #12194]: https://bugs.ruby-lang.org/issues/12194
|
||||
[Feature #14256]: https://bugs.ruby-lang.org/issues/14256
|
||||
[Feature #15198]: https://bugs.ruby-lang.org/issues/15198
|
||||
[Feature #15211]: https://bugs.ruby-lang.org/issues/15211
|
||||
[Feature #16043]: https://bugs.ruby-lang.org/issues/16043
|
||||
[Feature #16806]: https://bugs.ruby-lang.org/issues/16806
|
||||
[Feature #17312]: https://bugs.ruby-lang.org/issues/17312
|
||||
|
|
|
@ -77,6 +77,7 @@ VALUE rb_int_lshift(VALUE x, VALUE y);
|
|||
VALUE rb_int_div(VALUE x, VALUE y);
|
||||
int rb_int_positive_p(VALUE num);
|
||||
int rb_int_negative_p(VALUE num);
|
||||
VALUE rb_check_integer_type(VALUE);
|
||||
VALUE rb_num_pow(VALUE x, VALUE y);
|
||||
VALUE rb_float_ceil(VALUE num, int ndigits);
|
||||
VALUE rb_float_floor(VALUE x, int ndigits);
|
||||
|
|
|
@ -5247,6 +5247,12 @@ rb_int_s_isqrt(VALUE self, VALUE num)
|
|||
}
|
||||
}
|
||||
|
||||
static VALUE
|
||||
int_s_try_convert(VALUE self, VALUE num)
|
||||
{
|
||||
return rb_check_integer_type(num);
|
||||
}
|
||||
|
||||
/*
|
||||
* Document-class: ZeroDivisionError
|
||||
*
|
||||
|
@ -5473,6 +5479,7 @@ Init_Numeric(void)
|
|||
rb_undef_alloc_func(rb_cInteger);
|
||||
rb_undef_method(CLASS_OF(rb_cInteger), "new");
|
||||
rb_define_singleton_method(rb_cInteger, "sqrt", rb_int_s_isqrt, 1);
|
||||
rb_define_singleton_method(rb_cInteger, "try_convert", int_s_try_convert, 1);
|
||||
|
||||
rb_define_method(rb_cInteger, "to_s", int_to_s, -1);
|
||||
rb_define_alias(rb_cInteger, "inspect", "to_s");
|
||||
|
|
16
object.c
16
object.c
|
@ -3232,19 +3232,23 @@ rb_check_convert_type_with_id(VALUE val, int type, const char *tname, ID method)
|
|||
#define try_to_int(val, mid, raise) \
|
||||
convert_type_with_id(val, "Integer", mid, raise, -1)
|
||||
|
||||
ALWAYS_INLINE(static VALUE rb_to_integer(VALUE val, const char *method, ID mid));
|
||||
ALWAYS_INLINE(static VALUE rb_to_integer_with_id_exception(VALUE val, const char *method, ID mid, int raise));
|
||||
/* Integer specific rb_check_convert_type_with_id */
|
||||
static inline VALUE
|
||||
rb_to_integer(VALUE val, const char *method, ID mid)
|
||||
rb_to_integer_with_id_exception(VALUE val, const char *method, ID mid, int raise)
|
||||
{
|
||||
VALUE v;
|
||||
|
||||
if (RB_INTEGER_TYPE_P(val)) return val;
|
||||
v = try_to_int(val, mid, TRUE);
|
||||
v = try_to_int(val, mid, raise);
|
||||
if (!raise && NIL_P(v)) return Qnil;
|
||||
if (!RB_INTEGER_TYPE_P(v)) {
|
||||
conversion_mismatch(val, "Integer", method, v);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
#define rb_to_integer(val, method, mid) \
|
||||
rb_to_integer_with_id_exception(val, method, mid, TRUE)
|
||||
|
||||
/**
|
||||
* Tries to convert \a val into \c Integer.
|
||||
|
@ -3371,6 +3375,12 @@ rb_Integer(VALUE val)
|
|||
return rb_convert_to_integer(val, 0, TRUE);
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_check_integer_type(VALUE val)
|
||||
{
|
||||
return rb_to_integer_with_id_exception(val, "to_int", idTo_int, FALSE);
|
||||
}
|
||||
|
||||
int
|
||||
rb_bool_expected(VALUE obj, const char *flagname)
|
||||
{
|
||||
|
|
40
spec/ruby/core/integer/try_convert_spec.rb
Normal file
40
spec/ruby/core/integer/try_convert_spec.rb
Normal file
|
@ -0,0 +1,40 @@
|
|||
require_relative '../../spec_helper'
|
||||
require_relative 'fixtures/classes'
|
||||
|
||||
ruby_version_is "3.1" do
|
||||
describe "Integer.try_convert" do
|
||||
it "returns the argument if it's an Integer" do
|
||||
x = 42
|
||||
Integer.try_convert(x).should equal(x)
|
||||
end
|
||||
|
||||
it "returns nil when the argument does not respond to #to_int" do
|
||||
Integer.try_convert(Object.new).should be_nil
|
||||
end
|
||||
|
||||
it "sends #to_int to the argument and returns the result if it's nil" do
|
||||
obj = mock("to_int")
|
||||
obj.should_receive(:to_int).and_return(nil)
|
||||
Integer.try_convert(obj).should be_nil
|
||||
end
|
||||
|
||||
it "sends #to_int to the argument and returns the result if it's an Integer" do
|
||||
x = 234
|
||||
obj = mock("to_int")
|
||||
obj.should_receive(:to_int).and_return(x)
|
||||
Integer.try_convert(obj).should equal(x)
|
||||
end
|
||||
|
||||
it "sends #to_int to the argument and raises TypeError if it's not a kind of Integer" do
|
||||
obj = mock("to_int")
|
||||
obj.should_receive(:to_int).and_return(Object.new)
|
||||
-> { Integer.try_convert obj }.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "does not rescue exceptions raised by #to_int" do
|
||||
obj = mock("to_int")
|
||||
obj.should_receive(:to_int).and_raise(RuntimeError)
|
||||
-> { Integer.try_convert obj }.should raise_error(RuntimeError)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -660,4 +660,21 @@ class TestInteger < Test::Unit::TestCase
|
|||
def o.fdiv(x); 1; end
|
||||
assert_equal(1.0, 1.fdiv(o))
|
||||
end
|
||||
|
||||
def test_try_convert
|
||||
assert_equal(1, Integer.try_convert(1))
|
||||
assert_equal(1, Integer.try_convert(1.0))
|
||||
assert_nil Integer.try_convert("1")
|
||||
o = Object.new
|
||||
assert_nil Integer.try_convert(o)
|
||||
def o.to_i; 1; end
|
||||
assert_nil Integer.try_convert(o)
|
||||
o = Object.new
|
||||
def o.to_int; 1; end
|
||||
assert_equal(1, Integer.try_convert(o))
|
||||
|
||||
o = Object.new
|
||||
def o.to_int; Object.new; end
|
||||
assert_raise_with_message(TypeError, /can't convert Object to Integer/) {Integer.try_convert(o)}
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue