mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
range.c: Range#cover? accepts Range object. [Feature #14473]
* range.c (range_cover): add code for range argument. If the argument is a Range, check it is or is not covered by the reciver. If it can be treated as a sequence, this method treats it that way. * test/ruby/test_range.rb (class TestRange): add tests for this feature. This patch is written by Owen Stephens. thank you! git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@64640 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
19dec2a19c
commit
9ca7389272
3 changed files with 104 additions and 4 deletions
1
NEWS
1
NEWS
|
@ -176,6 +176,7 @@ sufficient information, see the ChangeLog file or Redmine
|
|||
|
||||
* `Range#===` now uses `#cover?` instead of `#include?` method.
|
||||
[Feature #14575]
|
||||
* `Range#cover?` now accepts Range object. [Feature #14473]
|
||||
|
||||
* `RubyVM::AST`
|
||||
|
||||
|
|
61
range.c
61
range.c
|
@ -1334,10 +1334,12 @@ range_include_internal(VALUE range, VALUE val)
|
|||
return Qundef;
|
||||
}
|
||||
|
||||
static int r_cover_range_p(VALUE range, VALUE beg, VALUE end, VALUE val);
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* rng.cover?(obj) -> true or false
|
||||
* rng.cover?(obj) -> true or false
|
||||
* rng.cover?(range) -> true or false
|
||||
*
|
||||
* Returns <code>true</code> if +obj+ is between the begin and end of
|
||||
* the range.
|
||||
|
@ -1345,9 +1347,21 @@ range_include_internal(VALUE range, VALUE val)
|
|||
* This tests <code>begin <= obj <= end</code> when #exclude_end? is +false+
|
||||
* and <code>begin <= obj < end</code> when #exclude_end? is +true+.
|
||||
*
|
||||
* ("a".."z").cover?("c") #=> true
|
||||
* ("a".."z").cover?("5") #=> false
|
||||
* ("a".."z").cover?("cc") #=> true
|
||||
* Returns <code>true</code> for a Range when it is covered by the reciver,
|
||||
* by comparing the begin and end values. If the argument can be treated as
|
||||
* a sequence, this method treats it that way. In the specific case of
|
||||
* <code>(a..b).cover?(c...d)</code> with <code>a <= c && b < d</code>,
|
||||
* end of sequence must be calculated, which may exhibit poor performance if
|
||||
* c is non-numeric. Returns <code>false</code> if the begin value of the
|
||||
* Range is larger than the end value.
|
||||
*
|
||||
* Return
|
||||
* ("a".."z").cover?("c") #=> true
|
||||
* ("a".."z").cover?("5") #=> false
|
||||
* ("a".."z").cover?("cc") #=> true
|
||||
* (1..5).cover?(2..3) #=> true
|
||||
* (1..5).cover?(0..6) #=> false
|
||||
* (1..5).cover?(1...6) #=> true
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
|
@ -1357,9 +1371,48 @@ range_cover(VALUE range, VALUE val)
|
|||
|
||||
beg = RANGE_BEG(range);
|
||||
end = RANGE_END(range);
|
||||
|
||||
if (rb_obj_is_kind_of(val, rb_cRange)) {
|
||||
return RBOOL(r_cover_range_p(range, beg, end, val));
|
||||
}
|
||||
return r_cover_p(range, beg, end, val);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
r_call_max(VALUE r)
|
||||
{
|
||||
return rb_funcallv(r, rb_intern("max"), 0, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
r_cover_range_p(VALUE range, VALUE beg, VALUE end, VALUE val)
|
||||
{
|
||||
VALUE val_beg, val_end, val_max;
|
||||
int cmp_end;
|
||||
|
||||
val_beg = RANGE_BEG(val);
|
||||
val_end = RANGE_END(val);
|
||||
|
||||
if (!NIL_P(end) && NIL_P(val_end)) return FALSE;
|
||||
if (!NIL_P(val_end) && r_less(val_beg, val_end) > -EXCL(val)) return FALSE;
|
||||
if (!r_cover_p(range, beg, end, val_beg)) return FALSE;
|
||||
|
||||
cmp_end = r_less(end, val_end);
|
||||
|
||||
if (EXCL(range) == EXCL(val)) {
|
||||
return cmp_end >= 0;
|
||||
} else if (EXCL(range)) {
|
||||
return cmp_end > 0;
|
||||
} else if (cmp_end >= 0) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
val_max = rb_rescue2(r_call_max, val, NULL, Qnil, rb_eTypeError, (VALUE)0);
|
||||
if (val_max == Qnil) return FALSE;
|
||||
|
||||
return r_less(end, val_max) >= 0;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
r_cover_p(VALUE range, VALUE beg, VALUE end, VALUE val)
|
||||
{
|
||||
|
|
|
@ -525,6 +525,52 @@ class TestRange < Test::Unit::TestCase
|
|||
assert_not_operator(5..., :cover?, 0)
|
||||
assert_not_operator(5..., :cover?, "a")
|
||||
assert_operator(5.., :cover?, 10)
|
||||
|
||||
assert_operator(2..5, :cover?, 2..5)
|
||||
assert_operator(2...6, :cover?, 2...6)
|
||||
assert_operator(2...6, :cover?, 2..5)
|
||||
assert_operator(2..5, :cover?, 2...6)
|
||||
assert_operator(2..5, :cover?, 2..4)
|
||||
assert_operator(2..5, :cover?, 2...4)
|
||||
assert_operator(2..5, :cover?, 2...5)
|
||||
assert_operator(2..5, :cover?, 3..5)
|
||||
assert_operator(2..5, :cover?, 3..4)
|
||||
assert_operator(2..5, :cover?, 3...6)
|
||||
assert_operator(2...6, :cover?, 2...5)
|
||||
assert_operator(2...6, :cover?, 2..5)
|
||||
assert_operator(2..6, :cover?, 2...6)
|
||||
assert_operator(2.., :cover?, 2..)
|
||||
assert_operator(2.., :cover?, 3..)
|
||||
assert_operator(1.., :cover?, 1..10)
|
||||
assert_operator(2.0..5.0, :cover?, 2..3)
|
||||
assert_operator(2..5, :cover?, 2.0..3.0)
|
||||
assert_operator(2..5, :cover?, 2.0...3.0)
|
||||
assert_operator(2..5, :cover?, 2.0...5.0)
|
||||
assert_operator(2.0..5.0, :cover?, 2.0...3.0)
|
||||
assert_operator(2.0..5.0, :cover?, 2.0...5.0)
|
||||
assert_operator('aa'..'zz', :cover?, 'aa'...'bb')
|
||||
|
||||
assert_not_operator(2..5, :cover?, 1..5)
|
||||
assert_not_operator(2...6, :cover?, 1..5)
|
||||
assert_not_operator(2..5, :cover?, 1...6)
|
||||
assert_not_operator(1..3, :cover?, 1...6)
|
||||
assert_not_operator(2..5, :cover?, 2..6)
|
||||
assert_not_operator(2...6, :cover?, 2..6)
|
||||
assert_not_operator(2...6, :cover?, 2...7)
|
||||
assert_not_operator(2..3, :cover?, 1..4)
|
||||
assert_not_operator(1..2, :cover?, 1.0..3.0)
|
||||
assert_not_operator(1.0..2.9, :cover?, 1.0..3.0)
|
||||
assert_not_operator(1..2, :cover?, 4..3)
|
||||
assert_not_operator(2..1, :cover?, 1..2)
|
||||
assert_not_operator(1...2, :cover?, 1...3)
|
||||
assert_not_operator(2.., :cover?, 1..)
|
||||
assert_not_operator(2.., :cover?, 1..10)
|
||||
assert_not_operator(1..10, :cover?, 1..)
|
||||
assert_not_operator(1..5, :cover?, 3..2)
|
||||
assert_not_operator(1..10, :cover?, 3...2)
|
||||
assert_not_operator(1..10, :cover?, 3...3)
|
||||
assert_not_operator('aa'..'zz', :cover?, 'aa'...'zzz')
|
||||
assert_not_operator(1..10, :cover?, 1...10.1)
|
||||
end
|
||||
|
||||
def test_beg_len
|
||||
|
|
Loading…
Reference in a new issue