diff --git a/range.c b/range.c index b18a25ea35..946da0c4de 100644 --- a/range.c +++ b/range.c @@ -2151,6 +2151,34 @@ range_count(int argc, VALUE *argv, VALUE range) } } +/* + * call-seq: + * overlap?(range) -> true or false + * + * Returns +true+ if +range+ overlaps with +self+, +false+ otherwise: + * + * (0..2).overlap?(1..3) #=> true + * (0..2).overlap?(3..4) #=> false + * (0..).overlap?(..0) #=> true + * + * Related: Range#cover?. + */ + +static VALUE +range_overlap(VALUE range, VALUE other) +{ + if (!rb_obj_is_kind_of(other, rb_cRange)) { + rb_raise(rb_eTypeError, "argument must be Range"); + } + + VALUE beg_self, beg_other; + + beg_self = RANGE_BEG(range); + beg_other = RANGE_BEG(other); + + return RBOOL(rb_equal(beg_self, beg_other) || range_cover(range, beg_other) || range_cover(other, beg_self)); +} + /* A \Range object represents a collection of values * that are between given begin and end values. * @@ -2417,4 +2445,5 @@ Init_Range(void) rb_define_method(rb_cRange, "include?", range_include, 1); rb_define_method(rb_cRange, "cover?", range_cover, 1); rb_define_method(rb_cRange, "count", range_count, -1); + rb_define_method(rb_cRange, "overlap?", range_overlap, 1); } diff --git a/test/ruby/test_range.rb b/test/ruby/test_range.rb index 820ca9e9c2..17d1e3a431 100644 --- a/test/ruby/test_range.rb +++ b/test/ruby/test_range.rb @@ -1051,4 +1051,32 @@ class TestRange < Test::Unit::TestCase def test_count assert_equal(Float::INFINITY, (1..).count) end + + def test_overlap? + assert_not_operator(0..2, :overlap?, -2..-1) + assert_not_operator(0..2, :overlap?, -2...0) + assert_operator(0..2, :overlap?, -1..0) + assert_operator(0..2, :overlap?, 1..2) + assert_operator(0..2, :overlap?, 2..3) + assert_not_operator(0..2, :overlap?, 3..4) + assert_not_operator(0...2, :overlap?, 2..3) + + assert_operator(..0, :overlap?, -1..0) + assert_operator(...0, :overlap?, -1..0) + assert_operator(..0, :overlap?, 0..1) + assert_operator(..0, :overlap?, ..1) + assert_not_operator(..0, :overlap?, 1..2) + assert_not_operator(...0, :overlap?, 0..1) + + assert_not_operator(0.., :overlap?, -2..-1) + assert_not_operator(0.., :overlap?, ...0) + assert_operator(0.., :overlap?, -1..0) + assert_operator(0.., :overlap?, ..0) + assert_operator(0.., :overlap?, 0..1) + assert_operator(0.., :overlap?, 1..2) + assert_operator(0.., :overlap?, 1..) + + assert_raise(TypeError) { (0..).overlap?(1) } + assert_raise(TypeError) { (0..).overlap?(nil) } + end end