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 989e07c0f2,
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]
This commit is contained in:
Jeremy Evans 2019-07-29 16:22:00 -07:00
Родитель 082424ef58
Коммит 6954ff1dcb
2 изменённых файлов: 22 добавлений и 9 удалений

23
range.c
Просмотреть файл

@ -1369,7 +1369,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:
@ -1393,7 +1393,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);
}
@ -1416,13 +1416,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);
@ -1434,11 +1434,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;

Просмотреть файл

@ -528,6 +528,14 @@ class TestRange < Test::Unit::TestCase
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