From 989e07c0f2fa664a54e52a475c2fcc145f06539d Mon Sep 17 00:00:00 2001 From: nobu Date: Thu, 17 May 2018 10:46:21 +0000 Subject: [PATCH] range.c: === by cover? * range.c (range_eqq): switch `Range#===` to use `cover?` instead of `include?`. [Feature #14575] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@63453 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- NEWS | 4 ++++ range.c | 17 ++++++++++++++--- spec/ruby/core/range/case_compare_spec.rb | 17 +++++++++++++---- test/ruby/test_range.rb | 10 ++++++++++ 4 files changed, 41 insertions(+), 7 deletions(-) diff --git a/NEWS b/NEWS index 0b8caca210..85ccdac4e5 100644 --- a/NEWS +++ b/NEWS @@ -116,6 +116,10 @@ with all sufficient information, see the ChangeLog file or Redmine * added Random.bytes. [Feature #4938] +* Range + + * Range#=== now uses #cover? instead of #include? method. [Feature #14575] + * String * String#split yields each substring to the block if given. [Feature #4780] diff --git a/range.c b/range.c index 917d24bd83..dcae2b2397 100644 --- a/range.c +++ b/range.c @@ -1212,6 +1212,8 @@ range_inspect(VALUE range) return rb_exec_recursive(inspect_range, range, 0); } +static VALUE range_include_internal(VALUE range, VALUE val); + /* * call-seq: * rng === obj -> true or false @@ -1234,7 +1236,9 @@ range_inspect(VALUE range) static VALUE range_eqq(VALUE range, VALUE val) { - return rb_funcall(range, rb_intern("include?"), 1, val); + VALUE ret = range_include_internal(range, val); + if (ret != Qundef) return ret; + return r_cover_p(range, RANGE_BEG(range), RANGE_END(range), val); } @@ -1254,6 +1258,14 @@ range_eqq(VALUE range, VALUE val) static VALUE range_include(VALUE range, VALUE val) +{ + VALUE ret = range_include_internal(range, val); + if (ret != Qundef) return ret; + return rb_call_super(1, &val); +} + +static VALUE +range_include_internal(VALUE range, VALUE val) { VALUE beg = RANGE_BEG(range); VALUE end = RANGE_END(range); @@ -1277,8 +1289,7 @@ range_include(VALUE range, VALUE val) return Qfalse; } } - /* TODO: ruby_frame->this_func = rb_intern("include?"); */ - return rb_call_super(1, &val); + return Qundef; } diff --git a/spec/ruby/core/range/case_compare_spec.rb b/spec/ruby/core/range/case_compare_spec.rb index e0da683649..9a33c5b73b 100644 --- a/spec/ruby/core/range/case_compare_spec.rb +++ b/spec/ruby/core/range/case_compare_spec.rb @@ -3,9 +3,18 @@ require_relative 'shared/cover_and_include' require_relative 'shared/cover' describe "Range#===" do - it "returns the result of calling #include? on self" do - range = 0...10 - range.should_receive(:include?).with(2).and_return(:true) - (range === 2).should == :true + ruby_version_is ""..."2.6" do + it "returns the result of calling #include? on self" do + range = 0...10 + range.should_receive(:include?).with(2).and_return(:true) + (range === 2).should == :true + end + end + + ruby_version_is "2.6" do + it "returns the result of calling #cover? on self" do + range = RangeSpecs::Custom.new(0)..RangeSpecs::Custom.new(10) + (range === RangeSpecs::Custom.new(2)).should == true + end end end diff --git a/test/ruby/test_range.rb b/test/ruby/test_range.rb index 5f2e970324..c98b130456 100644 --- a/test/ruby/test_range.rb +++ b/test/ruby/test_range.rb @@ -473,6 +473,16 @@ class TestRange < Test::Unit::TestCase assert_operator(c.new(0)..c.new(10), :===, c.new(5), bug12003) end + def test_eqq_non_iteratable + k = Class.new do + include Comparable + attr_reader :i + def initialize(i) @i = i; end + def <=>(o); i <=> o.i; end + end + assert_operator(k.new(0)..k.new(2), :===, k.new(1)) + end + def test_include assert_include("a".."z", "c") assert_not_include("a".."z", "5")