[前][次][番号順一覧][スレッド一覧]

ruby-changes:62211

From: Jeremy <ko1@a...>
Date: Tue, 14 Jul 2020 02:09:53 +0900 (JST)
Subject: [ruby-changes:62211] 8900a25581 (master): Fix Range#{max, minmax} for range with integer beginning and non-integer end

https://git.ruby-lang.org/ruby.git/commit/?id=8900a25581

From 8900a25581822759daca528d46a75e0b743fc22e Mon Sep 17 00:00:00 2001
From: Jeremy Evans <code@j...>
Date: Mon, 13 Jul 2020 10:09:38 -0700
Subject: Fix Range#{max,minmax} for range with integer beginning and
 non-integer end

Previously, for inclusive ranges, the max would show up as the
end of the range, even though the end was not an integer and would
not be the maximum value.  For exclusive ranges, max/minmax would
previously raise a TypeError, even though it is possible to get the
correct maximum.

This change to max/minmax also uncovered a similar error in cover?,
which calls max in certain cases, so adjust the code there so that
cover? still works as expected.

Fixes [Bug #17017]

diff --git a/range.c b/range.c
index 59cae0a..93cf126 100644
--- a/range.c
+++ b/range.c
@@ -1234,6 +1234,13 @@ range_max(int argc, VALUE *argv, VALUE range) https://github.com/ruby/ruby/blob/trunk/range.c#L1234
         if (c > 0)
             return Qnil;
         if (EXCL(range)) {
+            if (RB_INTEGER_TYPE_P(b) && !RB_INTEGER_TYPE_P(e)) {
+                VALUE end = e;
+                e = rb_funcall(e, rb_intern("floor"), 0);
+                if (!RTEST(rb_funcall(e, rb_intern("=="), 1, end))) {
+                    return e;
+                }
+            }
             if (!RB_INTEGER_TYPE_P(e)) {
                 rb_raise(rb_eTypeError, "cannot exclude non Integer end value");
             }
@@ -1246,6 +1253,9 @@ range_max(int argc, VALUE *argv, VALUE range) https://github.com/ruby/ruby/blob/trunk/range.c#L1253
             }
             return rb_funcall(e, '-', 1, INT2FIX(1));
         }
+        if (RB_INTEGER_TYPE_P(b) && !RB_INTEGER_TYPE_P(e)) {
+            e = rb_funcall(e, rb_intern("floor"), 0);
+        }
         return e;
     }
 }
@@ -1593,9 +1603,14 @@ r_cover_range_p(VALUE range, VALUE beg, VALUE end, VALUE val) https://github.com/ruby/ruby/blob/trunk/range.c#L1603
     else if (cmp_end >= 0) {
         return TRUE;
     }
-
-    val_max = rb_rescue2(r_call_max, val, 0, Qnil, rb_eTypeError, (VALUE)0);
-    if (val_max == Qnil) return FALSE;
+    if (RB_INTEGER_TYPE_P(val_beg) && RB_INTEGER_TYPE_P(beg) &&
+            RB_INTEGER_TYPE_P(val_end) != RB_INTEGER_TYPE_P(end)) {
+        val_max = val_end;
+    }
+    else {
+        val_max = rb_rescue2(r_call_max, val, 0, Qnil, rb_eTypeError, (VALUE)0);
+        if (val_max == Qnil) return FALSE;
+    }
 
     return r_less(end, val_max) >= 0;
 }
diff --git a/test/ruby/test_range.rb b/test/ruby/test_range.rb
index 3953b3e..9052fe6 100644
--- a/test/ruby/test_range.rb
+++ b/test/ruby/test_range.rb
@@ -107,11 +107,13 @@ class TestRange < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_range.rb#L107
     assert_equal(1, (1...2).max)
     assert_raise(RangeError) { (1..).max }
     assert_raise(RangeError) { (1...).max }
+    assert_equal(2, (1..2.1).max)
+    assert_equal(2, (1...2.1).max)
 
     assert_equal(2.0, (1.0..2.0).max)
     assert_equal(nil, (2.0..1.0).max)
     assert_raise(TypeError) { (1.0...2.0).max }
-    assert_raise(TypeError) { (1...1.5).max }
+    assert_equal(1, (1...1.5).max)
     assert_raise(TypeError) { (1.5...2).max }
 
     assert_equal(-0x80000002, ((-0x80000002)...(-0x80000001)).max)
@@ -133,11 +135,13 @@ class TestRange < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_range.rb#L135
     assert_equal([1, 1], (1...2).minmax)
     assert_raise(RangeError) { (1..).minmax }
     assert_raise(RangeError) { (1...).minmax }
+    assert_equal([1, 2], (1..2.1).minmax)
+    assert_equal([1, 2], (1...2.1).minmax)
 
     assert_equal([1.0, 2.0], (1.0..2.0).minmax)
     assert_equal([nil, nil], (2.0..1.0).minmax)
     assert_raise(TypeError) { (1.0...2.0).minmax }
-    assert_raise(TypeError) { (1...1.5).minmax }
+    assert_equal([1, 1], (1..1.5).minmax)
     assert_raise(TypeError) { (1.5...2).minmax }
 
     assert_equal([-0x80000002, -0x80000002], ((-0x80000002)...(-0x80000001)).minmax)
@@ -652,7 +656,12 @@ class TestRange < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_range.rb#L656
     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)
+    assert_not_operator(1...10.1, :cover?, 1..10.1)
+    assert_operator(1..10.1, :cover?, 1...10.1)
+    assert_operator(1..10.1, :cover?, 1...10)
+    assert_operator(1..10.1, :cover?, 1..10)
   end
 
   def test_beg_len
-- 
cgit v0.10.2


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]