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

ruby-changes:50986

From: mame <ko1@a...>
Date: Fri, 20 Apr 2018 00:18:58 +0900 (JST)
Subject: [ruby-changes:50986] mame:r63192 (trunk): Introduce endless range [Feature#12912]

mame	2018-04-20 00:18:50 +0900 (Fri, 20 Apr 2018)

  New Revision: 63192

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=63192

  Log:
    Introduce endless range [Feature#12912]
    
    Typical usages:
    ```
    p ary[1..]          # drop the first element; identical to ary[1..-1]
    (1..).each {|n|...} # iterate forever from 1; identical to 1.step{...}
    ```

  Modified files:
    trunk/internal.h
    trunk/numeric.c
    trunk/parse.y
    trunk/range.c
    trunk/string.c
    trunk/test/ruby/test_array.rb
    trunk/test/ruby/test_range.rb
Index: string.c
===================================================================
--- string.c	(revision 63191)
+++ string.c	(revision 63192)
@@ -4325,6 +4325,50 @@ str_upto_each(VALUE beg, VALUE end, int https://github.com/ruby/ruby/blob/trunk/string.c#L4325
     return beg;
 }
 
+VALUE
+rb_str_upto_endless_each(VALUE beg, VALUE (*each)(VALUE, VALUE), VALUE arg)
+{
+    VALUE current;
+    ID succ;
+
+    CONST_ID(succ, "succ");
+    /* both edges are all digits */
+    if (is_ascii_string(beg) && ISDIGIT(RSTRING_PTR(beg)[0]) &&
+	all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg))) {
+	VALUE b, args[2], fmt = rb_fstring_cstr("%.*d");
+	int width = RSTRING_LENINT(beg);
+	b = rb_str_to_inum(beg, 10, FALSE);
+	if (FIXNUM_P(b)) {
+	    long bi = FIX2LONG(b);
+	    rb_encoding *usascii = rb_usascii_encoding();
+
+	    while (FIXABLE(bi)) {
+		(*each)(rb_enc_sprintf(usascii, "%.*ld", width, bi), arg);
+		bi++;
+	    }
+	    b = LONG2NUM(bi);
+	}
+	args[0] = INT2FIX(width);
+	while (1) {
+	    args[1] = b;
+	    (*each)(rb_str_format(numberof(args), args, fmt), arg);
+	    b = rb_funcallv(b, succ, 0, 0);
+	}
+    }
+    /* normal case */
+    current = rb_str_dup(beg);
+    while (1) {
+	VALUE next = rb_funcallv(current, succ, 0, 0);
+	(*each)(current, arg);
+	current = next;
+	StringValue(current);
+	if (RSTRING_LEN(current) == 0)
+	    break;
+    }
+
+    return beg;
+}
+
 static int
 include_range_i(VALUE str, VALUE arg)
 {
Index: range.c
===================================================================
--- range.c	(revision 63191)
+++ range.c	(revision 63192)
@@ -37,7 +37,7 @@ static VALUE r_cover_p(VALUE, VALUE, VAL https://github.com/ruby/ruby/blob/trunk/range.c#L37
 static void
 range_init(VALUE range, VALUE beg, VALUE end, VALUE exclude_end)
 {
-    if (!FIXNUM_P(beg) || !FIXNUM_P(end)) {
+    if ((!FIXNUM_P(beg) || !FIXNUM_P(end)) && !NIL_P(end)) {
 	VALUE v;
 
 	v = rb_funcall(beg, id_cmp, 1, end);
@@ -400,7 +400,19 @@ range_step(int argc, VALUE *argv, VALUE https://github.com/ruby/ruby/blob/trunk/range.c#L400
 	step = check_step_domain(step);
     }
 
-    if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) { /* fixnums are special */
+    if (FIXNUM_P(b) && NIL_P(e) && FIXNUM_P(step)) {
+	long i = FIX2LONG(b), unit = FIX2LONG(step);
+	while (1) {
+	    rb_yield(LONG2FIX(i));
+	    if (i + unit < i) break;
+	    i += unit;
+	}
+	b = LONG2NUM(i);
+
+	for (;; b = rb_funcallv(b, id_succ, 0, 0))
+	    rb_yield(b);
+    }
+    else if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) { /* fixnums are special */
 	long end = FIX2LONG(e);
 	long i, unit = FIX2LONG(step);
 
@@ -414,16 +426,21 @@ range_step(int argc, VALUE *argv, VALUE https://github.com/ruby/ruby/blob/trunk/range.c#L426
 	}
 
     }
-    else if (SYMBOL_P(b) && SYMBOL_P(e)) { /* symbols are special */
+    else if (SYMBOL_P(b) && (NIL_P(e) || SYMBOL_P(e))) { /* symbols are special */
 	VALUE args[2], iter[2];
-
-	args[0] = rb_sym2str(e);
-	args[1] = EXCL(range) ? Qtrue : Qfalse;
 	iter[0] = INT2FIX(1);
 	iter[1] = step;
-	rb_block_call(rb_sym2str(b), rb_intern("upto"), 2, args, sym_step_i, (VALUE)iter);
+
+	if (NIL_P(e)) {
+	    rb_str_upto_endless_each(rb_sym2str(b), sym_step_i, (VALUE)iter);
+	}
+	else {
+	    args[0] = rb_sym2str(e);
+	    args[1] = EXCL(range) ? Qtrue : Qfalse;
+	    rb_block_call(rb_sym2str(b), rb_intern("upto"), 2, args, sym_step_i, (VALUE)iter);
+	}
     }
-    else if (ruby_float_step(b, e, step, EXCL(range))) {
+    else if (ruby_float_step(b, e, step, EXCL(range), TRUE)) {
 	/* done */
     }
     else if (rb_obj_is_kind_of(b, rb_cNumeric) ||
@@ -433,7 +450,7 @@ range_step(int argc, VALUE *argv, VALUE https://github.com/ruby/ruby/blob/trunk/range.c#L450
 	VALUE v = b;
 	int i = 0;
 
-	while (RTEST(rb_funcall(v, op, 1, e))) {
+	while (NIL_P(e) || RTEST(rb_funcall(v, op, 1, e))) {
 	    rb_yield(v);
 	    i++;
 	    v = rb_funcall(b, '+', 1, rb_funcall(INT2NUM(i), '*', 1, step));
@@ -446,11 +463,17 @@ range_step(int argc, VALUE *argv, VALUE https://github.com/ruby/ruby/blob/trunk/range.c#L463
 	    VALUE args[2], iter[2];
 
 	    b = tmp;
-	    args[0] = e;
-	    args[1] = EXCL(range) ? Qtrue : Qfalse;
 	    iter[0] = INT2FIX(1);
 	    iter[1] = step;
-	    rb_block_call(b, rb_intern("upto"), 2, args, step_i, (VALUE)iter);
+
+	    if (NIL_P(e)) {
+		rb_str_upto_endless_each(b, step_i, (VALUE)iter);
+	    }
+	    else {
+		args[0] = e;
+		args[1] = EXCL(range) ? Qtrue : Qfalse;
+		rb_block_call(b, rb_intern("upto"), 2, args, step_i, (VALUE)iter);
+	    }
 	}
 	else {
 	    VALUE args[2];
@@ -746,7 +769,18 @@ range_each(VALUE range) https://github.com/ruby/ruby/blob/trunk/range.c#L769
     beg = RANGE_BEG(range);
     end = RANGE_END(range);
 
-    if (FIXNUM_P(beg) && FIXNUM_P(end)) { /* fixnums are special */
+    if (FIXNUM_P(beg) && NIL_P(end)) {
+	long i = FIX2LONG(beg);
+	while (FIXABLE(i)) {
+	    rb_yield(LONG2FIX(i++));
+	}
+	beg = LONG2NUM(i);
+
+      inf_loop:
+	for (;; beg = rb_funcallv(beg, id_succ, 0, 0))
+	    rb_yield(beg);
+    }
+    else if (FIXNUM_P(beg) && FIXNUM_P(end)) { /* fixnums are special */
 	long lim = FIX2LONG(end);
 	long i;
 
@@ -767,18 +801,27 @@ range_each(VALUE range) https://github.com/ruby/ruby/blob/trunk/range.c#L801
 	VALUE tmp = rb_check_string_type(beg);
 
 	if (!NIL_P(tmp)) {
-	    VALUE args[2];
+	    if (!NIL_P(end)) {
+		VALUE args[2];
 
-	    args[0] = end;
-	    args[1] = EXCL(range) ? Qtrue : Qfalse;
-	    rb_block_call(tmp, rb_intern("upto"), 2, args, each_i, 0);
+		args[0] = end;
+		args[1] = EXCL(range) ? Qtrue : Qfalse;
+		rb_block_call(tmp, rb_intern("upto"), 2, args, each_i, 0);
+	    }
+	    else if (RB_TYPE_P(beg, T_STRING)) {
+		rb_str_upto_endless_each(beg, each_i, 0);
+	    }
+	    else goto inf_loop;
 	}
 	else {
 	    if (!discrete_object_p(beg)) {
 		rb_raise(rb_eTypeError, "can't iterate from %s",
 			 rb_obj_classname(beg));
 	    }
-	    range_each_func(range, each_i, 0);
+	    if (!NIL_P(end))
+		range_each_func(range, each_i, 0);
+	    else
+		goto inf_loop;
 	}
     }
     return range;
@@ -1012,7 +1055,8 @@ rb_range_beg_len(VALUE range, long *begp https://github.com/ruby/ruby/blob/trunk/range.c#L1055
     if (!rb_range_values(range, &b, &e, &excl))
 	return Qfalse;
     beg = NUM2LONG(b);
-    end = NUM2LONG(e);
+    end = NIL_P(e) ? -1 : NUM2LONG(e);
+    if (NIL_P(e)) excl = 0;
     origbeg = beg;
     origend = end;
     if (beg < 0) {
@@ -1072,16 +1116,16 @@ range_to_s(VALUE range) https://github.com/ruby/ruby/blob/trunk/range.c#L1116
 static VALUE
 inspect_range(VALUE range, VALUE dummy, int recur)
 {
-    VALUE str, str2;
+    VALUE str, str2 = Qundef;
 
     if (recur) {
 	return rb_str_new2(EXCL(range) ? "(... ... ...)" : "(... .. ...)");
     }
     str = rb_inspect(RANGE_BEG(range));
-    str2 = rb_inspect(RANGE_END(range));
+    if (!NIL_P(RANGE_END(range))) str2 = rb_inspect(RANGE_END(range));
     str = rb_str_dup(str);
     rb_str_cat(str, "...", EXCL(range) ? 3 : 2);
-    rb_str_append(str, str2);
+    if (str2 != Qundef) rb_str_append(str, str2);
     OBJ_INFECT(str, range);
 
     return str;
Index: parse.y
===================================================================
--- parse.y	(revision 63191)
+++ parse.y	(revision 63192)
@@ -1903,6 +1903,22 @@ arg		: lhs '=' arg_rhs https://github.com/ruby/ruby/blob/trunk/parse.y#L1903
 		    /*% %*/
 		    /*% ripper: dot3!($1, $3) %*/
 		    }
+		| arg tDOT2
+		    {
+		    /*%%%*/
+			value_expr($1);
+			$$ = NEW_DOT2($1, new_nil(&@$), &@$);
+		    /*% %*/
+		    /*% ripper: dot2!($1, Qnil) %*/
+		    }
+		| arg tDOT3
+		    {
+		    /*%%%*/
+			value_expr($1);
+			$$ = NEW_DOT3($1, new_nil(&@$), &@$);
+		    /*% %*/
+		    /*% ripper: dot3!($1, Qnil) %*/
+		    }
 		| arg '+' arg
 		    {
 			$$ = call_bin_op(p, $1, '+', $3, &@2, &@$);
Index: numeric.c
===================================================================
--- numeric.c	(revision 63191)
+++ numeric.c	(revision 63192)
@@ -2469,11 +2469,11 @@ ruby_float_step_size(double beg, double https://github.com/ruby/ruby/blob/trunk/numeric.c#L2469
 }
 
 int
-ruby_float_step(VALUE from, VALUE to, VALUE step, int excl)
+ruby_float_step(VALUE from, VALUE to, VALUE step, int excl, int allow_endless)
 {
     if (RB_TYPE_P(from, T_FLOAT) || RB_TYPE_P(to, T_FLOAT) || RB_TYPE_P(step, T_FLOAT)) {
 	double beg = NUM2DBL(from);
-	double end = NUM2DBL(to);
+	double end = (allow_endless && NIL_P(to)) ? HUGE_VAL : NUM2DBL(to);
 	double unit = NUM2DBL(step);
 	double n = ruby_float_step_size(beg, end, unit, excl);
 	long i;
@@ -2712,7 +2712,7 @@ num_step(int argc, VALUE *argv, VALUE fr https://github.com/ruby/ruby/blob/trunk/numeric.c#L2712
 	    }
 	}
     }
-    else if (!ruby_float_step(from, to, step, FALSE)) {
+    else if (!ruby_float_step(from, to, step, FALSE, FALSE)) {
 	VALUE i = from;
 
 	if (inf) {
Index: internal.h
===================================================================
--- internal.h	(revision 63191)
+++ internal.h	(revision 63192)
@@ -1404,7 +1404,7 @@ enum ruby_num_rounding_mode { https://github.com/ruby/ruby/blob/trunk/internal.h#L1404
 
 int rb_num_to_uint(VALUE val, unsigned int *ret);
 VALUE ruby_num_interval_step_size(VALUE from, VALUE to, VALUE step, int excl);
-int ruby_float_step(VALUE from, VALUE to, VALUE step, int excl);
+int ruby_float_step(VALUE from, VALUE to, VALUE step, int excl, int allow_endless);
 double ruby_float_mod(double x, double y);
 int rb_num_negative_p(VALUE);
 VALUE rb_int_succ(VALUE num);
@@ -2013,6 +2013,7 @@ VALUE rb_gcd_gmp(VALUE x, VALUE y); https://github.com/ruby/ruby/blob/trunk/internal.h#L2013
 /* internal use */
 VALUE rb_setup_fake_str(struct RString *fake_str, const char *name, long len, rb_encoding *enc);
 #endif
+VALUE rb_str_upto_endless_each(VALUE, VALUE (*each)(), VALUE);
 
 /* thread.c (export) */
 int ruby_thread_has_gvl_p(void); /* for ext/fiddle/closure.c */
Index: test/ruby/test_array.rb
===================================================================
--- test/ruby/test_array.rb	(revision 63191)
+++ test/ruby/test_array.rb	(revision 63192)
@@ -41,6 +41,7 @@ class TestArray < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_array.rb#L41
     assert_equal(2, x[2])
     assert_equal([1, 2, 3], x[1..3])
     assert_equal([1, 2, 3], x[1,3])
+    assert_equal([3, 4, 5], x[3..])
 
     x[0, 2] = 10
     assert_equal([10, 2, 3, 4, 5], x)
@@ -199,6 +200,8 @@ class TestArray < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_array.rb#L200
     assert_equal([0, 1, 2, 13, 4, 5], [0, 1, 2, 3, 4, 5].fill(3...4){|i| i+10})
     assert_equal([0, 1, 12, 13, 14, 5], [0, 1, 2, 3, 4, 5].fill(2..-2){|i| i+10})
     assert_equal([0, 1, 12, 13, 4, 5], [0, 1, 2, 3, 4, 5].fill(2...-2){|i| i+10})
+    assert_equal([0, 1, 2, 13, 14, 15], [0, 1, 2, 3, 4, 5].fill(3..){|i| i+10})
+    assert_equal([0, 1, 2, 13, 14, 15], [0, 1, 2, 3, 4, 5].fill(3...){|i| i+10})
   end
 
   # From rubicon
@@ -346,7 +349,9 @@ class TestArray < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_array.rb#L349
     assert_equal(@cls[99],  a[-2..-2])
 
     assert_equal(@cls[10, 11, 12], a[9..11])
+    assert_equal(@cls[98, 99, 100], a[97..])
     assert_equal(@cls[10, 11, 12], a[-91..-89])
+    assert_equal(@cls[98, 99, 100], a[-3..])
 
     assert_nil(a[10, -3])
     assert_equal [], a[10..7]
@@ -428,6 +433,10 @@ class TestArray < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_array.rb#L433
     assert_equal(nil, a[10..19] = nil)
     assert_equal(@cls[*(0..9).to_a] + @cls[nil] + @cls[*(20..99).to_a], a)
 
+    a = @cls[*(0..99).to_a]
+    assert_equal(nil, a[10..] = nil)
+    assert_equal(@cls[*(0..9).to_a] + @cls[nil], a)
+
     a = @cls[1, 2, 3]
     a[1, 0] = a
     assert_equal([1, 1, 2, 3, 2, 3], a)
@@ -1378,9 +1387,12 @@ class TestArray < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_array.rb#L1387
     assert_equal(@cls[99],  a.slice(-2..-2))
 
     assert_equal(@cls[10, 11, 12], a.slice(9..11))
+    assert_equal(@cls[98, 99, 100], a.slice(97..))
+    assert_equal(@cls[10, 11, 12], a.slice(-91..-89))
     assert_equal(@cls[10, 11, 12], a.slice(-91..-89))
 
     assert_nil(a.slice(-101..-1))
+    assert_nil(a.slice(-101..))
 
     assert_nil(a.slice(10, -3))
     assert_equal @cls[], a.slice(10..7)
@@ -2106,6 +2118,7 @@ class TestArray < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_array.rb#L2118
     assert_raise(IndexError) { [0][LONGP] = 2 }
     assert_raise(IndexError) { [0][(LONGP + 1) / 2 - 1] = 2 }
     assert_raise(IndexError) { [0][LONGP..-1] = 2 }
+    assert_raise(IndexError) { [0][LONGP..] = 2 }
     a = [0]
     a[2] = 4
     assert_equal([0, nil, 4], a)
Index: test/ruby/test_range.rb
===================================================================
--- test/ruby/test_range.rb	(revision 63191)
+++ test/ruby/test_range.rb	(revision 63192)
@@ -12,6 +12,9 @@ class TestRange < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_range.rb#L12
 
     assert_raise(ArgumentError) { (1.."3") }
 
+    assert_equal((0..nil), Range.new(0, nil, false))
+    assert_equal((0...nil), Range.new(0, nil, true))
+
     obj = Object.new
     def obj.<=>(other)
       raise RuntimeError, "cmp"
@@ -31,14 +34,17 @@ class TestRange < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_range.rb#L34
     assert_equal(["a"], ("a" .. "a").to_a)
     assert_equal(["a"], ("a" ... "b").to_a)
     assert_equal(["a", "b"], ("a" .. "b").to_a)
+    assert_equal([*"a".."z", "aa"], ("a"..).take(27))
   end
 
   def test_range_numeric_string
     assert_equal(["6", "7", "8"], ("6".."8").to_a, "[ruby-talk:343187]")
     assert_equal(["6", "7"], ("6"..."8").to_a)
     assert_equal(["9", "10"], ("9".."10").to_a)
+    assert_equal(["9", "10"], ("9"..).take(2))
     assert_equal(["09", "10"], ("09".."10").to_a, "[ruby-dev:39361]")
     assert_equal(["9", "10"], (SimpleDelegator.new("9").."10").to_a)
+    assert_equal(["9", "10"], (SimpleDelegator.new("9")..).take(2))
     assert_equal(["9", "10"], ("9"..SimpleDelegator.new("10")).to_a)
   end
 
@@ -123,9 +129,10 @@ class TestRange < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_range.rb#L129
     assert_equal(r, Marshal.load(Marshal.dump(r)))
     r = 1...2
     assert_equal(r, Marshal.load(Marshal.dump(r)))
-    s = Marshal.dump(r)
-    s.sub!(/endi./n, 'end0')
-    assert_raise(ArgumentError) {Marshal.load(s)}
+    r = (1..)
+    assert_equal(r, Marshal.load(Marshal.dump(r)))
+    r = (1...)
+    assert_equal(r, Marshal.load(Marshal.dump(r)))
   end
 
   def test_bad_value
@@ -135,6 +142,8 @@ class TestRange < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_range.rb#L142
   def test_exclude_end
     assert_not_predicate(0..1, :exclude_end?)
     assert_predicate(0...1, :exclude_end?)
+    assert_not_predicate(0.., :exclude_end?)
+    assert_predicate(0..., :exclude_end?)
   end
 
   def test_eq
@@ -145,8 +154,17 @@ class TestRange < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_range.rb#L154
     assert_not_equal(r, (1..2))
     assert_not_equal(r, (0..2))
     assert_not_equal(r, (0...1))
+    assert_not_equal(r, (0..nil))
     subclass = Class.new(Range)
     assert_equal(r, subclass.new(0,1))
+
+    r = (0..nil)
+    assert_equal(r, r)
+    assert_equal(r, (0..nil))
+    assert_not_equal(r, 0)
+    assert_not_equal(r, (0...nil))
+    subclass = Class.new(Range)
+    assert_equal(r, subclass.new(0,nil))
   end
 
   def test_eql
@@ -159,12 +177,22 @@ class TestRange < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_range.rb#L177
     assert_not_operator(r, :eql?, 0...1)
     subclass = Class.new(Range)
     assert_operator(r, :eql?, subclass.new(0,1))
+
+    r = (0..nil)
+    assert_operator(r, :eql?, r)
+    assert_operator(r, :eql?, 0..nil)
+    assert_not_operator(r, :eql?, 0)
+    assert_not_operator(r, :eql?, 0...nil)
+    subclass = Class.new(Range)
+    assert_operator(r, :eql?, subclass.new(0,nil))
   end
 
   def test_hash
     assert_kind_of(Integer, (0..1).hash)
     assert_equal((0..1).hash, (0..1).hash)
     assert_not_equal((0..1).hash, (0...1).hash)
+    assert_equal((0..nil).hash, (0..nil).hash)
+    assert_not_equal((0..nil).hash, (0...nil).hash)
   end
 
   def test_step
@@ -173,17 +201,31 @@ class TestRange < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_range.rb#L201
     assert_equal([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], a)
 
     a = []
+    (0..).step {|x| a << x; break if a.size == 10 }
+    assert_equal([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], a)
+
+    a = []
     (0..10).step(2) {|x| a << x }
     assert_equal([0, 2, 4, 6, 8, 10], a)
 
+    a = []
+    (0..).step(2) {|x| a << x; break if a.size == 10 }
+    assert_equal([0, 2, 4, 6, 8, 10, 12, 14, 16, 18], a)
+
     assert_raise(ArgumentError) { (0..10).step(-1) { } }
     assert_raise(ArgumentError) { (0..10).step(0) { } }
+    assert_raise(ArgumentError) { (0..).step(-1) { } }
+    assert_raise(ArgumentError) { (0..).step(0) { } }
 
     a = []
     ("a" .. "z").step(2) {|x| a << x }
     assert_equal(%w(a c e g i k m o q s u w y), a)
 
     a = []
+    ("a" .. ).step(2) {|x| a << x; break if a.size == 13 }
+    assert_equal(%w(a c e g i k m o q s u w y), a)
+
+    a = []
     ("a" .. "z").step(2**32) {|x| a << x }
     assert_equal(["a"], a)
 
@@ -192,12 +234,16 @@ class TestRange < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_range.rb#L234
     assert_equal([4294967295, 4294967297], a)
     zero = (2**32).coerce(0).first
     assert_raise(ArgumentError) { (2**32-1 .. 2**32+1).step(zero) { } }
+    a = []
+    (2**32-1 .. ).step(2) {|x| a << x; break if a.size == 2 }
+    assert_equal([4294967295, 4294967297], a)
 
     o1 = Object.new
     o2 = Object.new
     def o1.<=>(x); -1; end
     def o2.<=>(x); 0; end
     assert_raise(TypeError) { (o1..o2).step(1) { } }
+    assert_raise(TypeError) { (o1..).step(1) { } }
 
     class << o1; self; end.class_eval do
       define_method(:succ) { o2 }
@@ -217,6 +263,10 @@ class TestRange < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_range.rb#L263
     assert_equal([0, 0.5, 1.0, 1.5, 2.0], a)
 
     a = []
+    (0..).step(0.5) {|x| a << x; break if a.size == 5 }
+    assert_equal([0, 0.5, 1.0, 1.5, 2.0], a)
+
+    a = []
     (0x40000000..0x40000002).step(0.5) {|x| a << x }
     assert_equal([1073741824, 1073741824.5, 1073741825.0, 1073741825.5, 1073741826], a)
 
@@ -239,6 +289,10 @@ class TestRange < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_range.rb#L289
     (0..10).each {|x| a << x }
     assert_equal([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], a)
 
+    a = []
+    (0..).each {|x| a << x; break if a.size == 10 }
+    assert_equal([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], a)
+
     o1 = Object.new
     o2 = Object.new
     def o1.setcmp(v) @cmpresult = v end
@@ -285,6 +339,9 @@ class TestRange < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_range.rb#L339
     assert_equal(0, (0..1).begin)
     assert_equal(1, (0..1).end)
     assert_equal(1, (0...1).end)
+    assert_equal(0, (0..nil).begin)
+    assert_equal(nil, (0..nil).end)
+    assert_equal(nil, (0...nil).end)
   end
 
   def test_first_last
@@ -308,6 +365,8 @@ class TestRange < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_range.rb#L365
   def test_to_s
     assert_equal("0..1", (0..1).to_s)
     assert_equal("0...1", (0...1).to_s)
+    assert_equal("0..", (0..nil).to_s)
+    assert_equal("0...", (0...nil).to_s)
 
     bug11767 = '[ruby-core:71811] [Bug #11767]'
     assert_predicate(("0".taint.."1").to_s, :tainted?, bug11767)
@@ -318,6 +377,8 @@ class TestRange < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_ (... truncated)

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

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