From 13fdf639bc4debf725c57710ac718d08b5332fc1 Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Mon, 29 Jul 2019 16:22:00 -0700 Subject: [PATCH] Make Range#=== operate like cover? instead of include? for string ranges Previously, Range#=== treated string ranges that were not endless or beginless the same as include?, instead of the same as cover?. I think this was an oversight in 989e07c0f2fa664a54e52a475c2fcc145f06539d, as the commit message did not indicate this behavior was desired. This also makes some previously dead code no longer dead. Previously, the conditionals were doing this: if (RB_TYPE_P(beg, T_STRING) if (NIL_P(beg)) # can never be true This restructures it so at the NIL_P(beg) check, beg could possibly be nil (beginless ranges). Fixes [Bug #15449] --- range.c | 23 ++++++++++++++--------- test/ruby/test_range.rb | 8 ++++++++ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/range.c b/range.c index e8515e0b8a..065cd4b646 100644 --- a/range.c +++ b/range.c @@ -1348,7 +1348,7 @@ range_inspect(VALUE range) return rb_exec_recursive(inspect_range, range, 0); } -static VALUE range_include_internal(VALUE range, VALUE val); +static VALUE range_include_internal(VALUE range, VALUE val, int string_use_cover); /* * call-seq: @@ -1372,7 +1372,7 @@ static VALUE range_include_internal(VALUE range, VALUE val); static VALUE range_eqq(VALUE range, VALUE val) { - VALUE ret = range_include_internal(range, val); + VALUE ret = range_include_internal(range, val, 1); if (ret != Qundef) return ret; return r_cover_p(range, RANGE_BEG(range), RANGE_END(range), val); } @@ -1395,13 +1395,13 @@ range_eqq(VALUE range, VALUE val) static VALUE range_include(VALUE range, VALUE val) { - VALUE ret = range_include_internal(range, val); + VALUE ret = range_include_internal(range, val, 0); if (ret != Qundef) return ret; return rb_call_super(1, &val); } static VALUE -range_include_internal(VALUE range, VALUE val) +range_include_internal(VALUE range, VALUE val, int string_use_cover) { VALUE beg = RANGE_BEG(range); VALUE end = RANGE_END(range); @@ -1413,11 +1413,16 @@ range_include_internal(VALUE range, VALUE val) !NIL_P(rb_check_to_integer(end, "to_int"))) { return r_cover_p(range, beg, end, val); } - else if (RB_TYPE_P(beg, T_STRING)) { - if (RB_TYPE_P(end, T_STRING)) { - VALUE rb_str_include_range_p(VALUE beg, VALUE end, VALUE val, VALUE exclusive); - return rb_str_include_range_p(beg, end, val, RANGE_EXCL(range)); - } + else if (RB_TYPE_P(beg, T_STRING) || RB_TYPE_P(end, T_STRING)) { + if (RB_TYPE_P(beg, T_STRING) && RB_TYPE_P(end, T_STRING)) { + if (string_use_cover) { + return r_cover_p(range, beg, end, val); + } + else { + VALUE rb_str_include_range_p(VALUE beg, VALUE end, VALUE val, VALUE exclusive); + return rb_str_include_range_p(beg, end, val, RANGE_EXCL(range)); + } + } else if (NIL_P(beg)) { VALUE r = rb_funcall(val, id_cmp, 1, end); if (NIL_P(r)) return Qfalse; diff --git a/test/ruby/test_range.rb b/test/ruby/test_range.rb index 14fd136aa6..47ca58d06a 100644 --- a/test/ruby/test_range.rb +++ b/test/ruby/test_range.rb @@ -507,6 +507,14 @@ def test_eqq assert_not_operator(5..nil, :===, 0) end + def test_eqq_string + assert_operator('A'..'Z', :===, 'ANA') + assert_not_operator('A'..'Z', :===, 'ana') + assert_operator('A'.., :===, 'ANA') + assert_operator(..'Z', :===, 'ANA') + assert_operator(nil..nil, :===, 'ANA') + end + def test_eqq_time bug11113 = '[ruby-core:69052] [Bug #11113]' t = Time.now -- 2.21.0