ruby-changes:50987
From: mame <ko1@a...>
Date: Fri, 20 Apr 2018 00:18:59 +0900 (JST)
Subject: [ruby-changes:50987] mame:r63194 (trunk): Make Range#min, max, include?, cover?, and === to support endless range
mame 2018-04-20 00:18:53 +0900 (Fri, 20 Apr 2018) New Revision: 63194 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=63194 Log: Make Range#min, max, include?, cover?, and === to support endless range Modified files: trunk/range.c trunk/test/ruby/test_range.rb Index: range.c =================================================================== --- range.c (revision 63193) +++ range.c (revision 63194) @@ -960,7 +960,7 @@ range_min(int argc, VALUE *argv, VALUE r https://github.com/ruby/ruby/blob/trunk/range.c#L960 struct cmp_opt_data cmp_opt = { 0, 0 }; VALUE b = RANGE_BEG(range); VALUE e = RANGE_END(range); - int c = OPTIMIZED_CMP(b, e, cmp_opt); + int c = NIL_P(e) ? -1 : OPTIMIZED_CMP(b, e, cmp_opt); if (c > 0 || (c == 0 && EXCL(range))) return Qnil; @@ -991,6 +991,8 @@ range_max(int argc, VALUE *argv, VALUE r https://github.com/ruby/ruby/blob/trunk/range.c#L991 VALUE e = RANGE_END(range); int nm = FIXNUM_P(e) || rb_obj_is_kind_of(e, rb_cNumeric); + if (NIL_P(e)) return Qnil; + if (rb_block_given_p() || (EXCL(range) && !nm) || argc) { return rb_call_super(argc, argv); } @@ -1200,9 +1202,17 @@ range_include(VALUE range, VALUE val) https://github.com/ruby/ruby/blob/trunk/range.c#L1202 !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) && 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)) { + 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 (NIL_P(end)) { + VALUE r = rb_funcall(beg, id_cmp, 1, val); + if (NIL_P(r)) return Qfalse; + if (rb_cmpint(r, beg, val) <= 0) return Qtrue; + return Qfalse; + } } /* TODO: ruby_frame->this_func = rb_intern("include?"); */ return rb_call_super(1, &val); @@ -1239,7 +1249,7 @@ r_cover_p(VALUE range, VALUE beg, VALUE https://github.com/ruby/ruby/blob/trunk/range.c#L1249 { if (r_less(beg, val) <= 0) { int excl = EXCL(range); - if (r_less(val, end) <= -excl) + if (NIL_P(end) || r_less(val, end) <= -excl) return Qtrue; } return Qfalse; Index: test/ruby/test_range.rb =================================================================== --- test/ruby/test_range.rb (revision 63193) +++ test/ruby/test_range.rb (revision 63194) @@ -79,22 +79,27 @@ class TestRange < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_range.rb#L79 assert_equal(1, (1..2).min) assert_equal(nil, (2..1).min) assert_equal(1, (1...2).min) + assert_equal(1, (1..).min) assert_equal(1.0, (1.0..2.0).min) assert_equal(nil, (2.0..1.0).min) assert_equal(1, (1.0...2.0).min) + assert_equal(1, (1.0..).min) assert_equal(0, (0..0).min) assert_equal(nil, (0...0).min) assert_equal([0,1,2], (0..10).min(3)) assert_equal([0,1], (0..1).min(3)) + assert_equal([0,1,2], (0..).min(3)) end def test_max assert_equal(2, (1..2).max) assert_equal(nil, (2..1).max) assert_equal(1, (1...2).max) + assert_equal(nil, (1..).max) + assert_equal(nil, (1...).max) assert_equal(2.0, (1.0..2.0).max) assert_equal(nil, (2.0..1.0).max) @@ -109,6 +114,7 @@ class TestRange < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_range.rb#L114 assert_equal([10,9,8], (0..10).max(3)) assert_equal([9,8,7], (0...10).max(3)) + # XXX: How should (0...).max(3) behave? end def test_initialize_twice @@ -360,6 +366,11 @@ class TestRange < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_range.rb#L366 assert_equal("a", ("a"..."c").first) assert_equal("c", ("a"..."c").last) assert_equal(0, (2...0).last) + + assert_equal([0, 1, 2], (0..nil).first(3)) + assert_equal(0, (0..nil).first) + assert_equal("a", ("a"..nil).first) + # XXX: How should (0...).last(3) behave? end def test_to_s @@ -389,6 +400,8 @@ class TestRange < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_range.rb#L400 def test_eqq assert_operator(0..10, :===, 5) assert_not_operator(0..10, :===, 11) + assert_operator(5..nil, :===, 11) + assert_not_operator(5..nil, :===, 0) end def test_eqq_time @@ -396,6 +409,8 @@ class TestRange < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_range.rb#L409 t = Time.now assert_nothing_raised(TypeError, bug11113) { assert_operator(t..(t+10), :===, t+5) + assert_operator(t.., :===, t+5) + assert_not_operator(t.., :===, t-5) } end @@ -430,6 +445,8 @@ class TestRange < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_range.rb#L445 assert_not_include("a"..."z", "z") assert_not_include("a".."z", "cc") assert_include(0...10, 5) + assert_include(5..., 10) + assert_not_include(5..., 0) end def test_cover @@ -438,6 +455,9 @@ class TestRange < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_range.rb#L455 assert_operator("a"..."z", :cover?, "y") assert_not_operator("a"..."z", :cover?, "z") assert_operator("a".."z", :cover?, "cc") + assert_not_operator(5..., :cover?, 0) + assert_not_operator(5..., :cover?, "a") + assert_operator(5.., :cover?, 10) end def test_beg_len @@ -515,6 +535,11 @@ class TestRange < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_range.rb#L535 assert_equal 6, (1...6.3).size assert_equal 5, (1.1...6).size assert_equal 42, (1..42).each.size + assert_nil ("a"..."z").size + + assert_nil (1...).size + assert_nil (1.0...).size + assert_nil ("a"...).size end def test_bsearch_typechecks_return_values -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/