mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	Introduce beginless range [Feature#14799]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@67422 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
		
							parent
							
								
									dd2479bcea
								
							
						
					
					
						commit
						95f7992b89
					
				
					 8 changed files with 123 additions and 19 deletions
				
			
		
							
								
								
									
										6
									
								
								NEWS
									
										
									
									
									
								
							
							
						
						
									
										6
									
								
								NEWS
									
										
									
									
									
								
							|  | @ -28,6 +28,12 @@ sufficient information, see the ChangeLog file or Redmine | ||||||
| * Numbered parameter as the default block parameter is introduced as an | * Numbered parameter as the default block parameter is introduced as an | ||||||
|   experimental feature.  [Feature #4475] |   experimental feature.  [Feature #4475] | ||||||
| 
 | 
 | ||||||
|  | * A beginless range is experimentally introduced.  It might not be as useful | ||||||
|  |   as an endless range, but would be good for DSL purpose. | ||||||
|  | 
 | ||||||
|  |      ary[..3]  # identical to ary[0..3] | ||||||
|  |      where(sales: ..100) | ||||||
|  | 
 | ||||||
| === Core classes updates (outstanding ones only) | === Core classes updates (outstanding ones only) | ||||||
| 
 | 
 | ||||||
| Enumerable:: | Enumerable:: | ||||||
|  |  | ||||||
|  | @ -76,6 +76,8 @@ firstline, predefined = __LINE__+1, %[\ | ||||||
| token_ops = %[\ | token_ops = %[\ | ||||||
|   Dot2          ..      DOT2 |   Dot2          ..      DOT2 | ||||||
|   Dot3          ...     DOT3 |   Dot3          ...     DOT3 | ||||||
|  |   BDot2         ..      BDOT2 | ||||||
|  |   BDot3         ...     BDOT3 | ||||||
|   UPlus         +@      UPLUS |   UPlus         +@      UPLUS | ||||||
|   UMinus        -@      UMINUS |   UMinus        -@      UMINUS | ||||||
|   Pow           **      POW |   Pow           **      POW | ||||||
|  |  | ||||||
|  | @ -334,6 +334,7 @@ its ending value. | ||||||
|   (1..2)  # includes its ending value |   (1..2)  # includes its ending value | ||||||
|   (1...2) # excludes its ending value |   (1...2) # excludes its ending value | ||||||
|   (1..)   # endless range, representing infinite sequence from 1 to Infinity |   (1..)   # endless range, representing infinite sequence from 1 to Infinity | ||||||
|  |   (..1)   # beginless range, representing infinite sequence from -Infinity to 1 | ||||||
| 
 | 
 | ||||||
| You may create a range of any object.  See the Range documentation for details | You may create a range of any object.  See the Range documentation for details | ||||||
| on the methods you need to implement. | on the methods you need to implement. | ||||||
|  |  | ||||||
							
								
								
									
										36
									
								
								parse.y
									
										
									
									
									
								
							
							
						
						
									
										36
									
								
								parse.y
									
										
									
									
									
								
							|  | @ -922,6 +922,8 @@ static void token_info_warn(struct parser_params *p, const char *token, token_in | ||||||
| %token tNMATCH		RUBY_TOKEN(NMATCH) "!~" | %token tNMATCH		RUBY_TOKEN(NMATCH) "!~" | ||||||
| %token tDOT2		RUBY_TOKEN(DOT2)   ".." | %token tDOT2		RUBY_TOKEN(DOT2)   ".." | ||||||
| %token tDOT3		RUBY_TOKEN(DOT3)   "..." | %token tDOT3		RUBY_TOKEN(DOT3)   "..." | ||||||
|  | %token tBDOT2		RUBY_TOKEN(BDOT2)   "(.." | ||||||
|  | %token tBDOT3		RUBY_TOKEN(BDOT3)   "(..." | ||||||
| %token tAREF		RUBY_TOKEN(AREF)   "[]" | %token tAREF		RUBY_TOKEN(AREF)   "[]" | ||||||
| %token tASET		RUBY_TOKEN(ASET)   "[]=" | %token tASET		RUBY_TOKEN(ASET)   "[]=" | ||||||
| %token tLSHFT		RUBY_TOKEN(LSHFT)  "<<" | %token tLSHFT		RUBY_TOKEN(LSHFT)  "<<" | ||||||
|  | @ -968,7 +970,7 @@ static void token_info_warn(struct parser_params *p, const char *token, token_in | ||||||
| %right '=' tOP_ASGN | %right '=' tOP_ASGN | ||||||
| %left modifier_rescue | %left modifier_rescue | ||||||
| %right '?' ':' | %right '?' ':' | ||||||
| %nonassoc tDOT2 tDOT3 | %nonassoc tDOT2 tDOT3 tBDOT2 tBDOT3 | ||||||
| %left  tOROP | %left  tOROP | ||||||
| %left  tANDOP | %left  tANDOP | ||||||
| %nonassoc  tCMP tEQ tEQQ tNEQ tMATCH tNMATCH | %nonassoc  tCMP tEQ tEQQ tNEQ tMATCH tNMATCH | ||||||
|  | @ -1996,6 +1998,30 @@ arg		: lhs '=' arg_rhs | ||||||
| 		    /*% %*/ | 		    /*% %*/ | ||||||
| 		    /*% ripper: dot3!($1, Qnil) %*/ | 		    /*% ripper: dot3!($1, Qnil) %*/ | ||||||
| 		    } | 		    } | ||||||
|  | 		| tBDOT2 arg | ||||||
|  | 		    { | ||||||
|  | 		    /*%%%*/ | ||||||
|  |                         YYLTYPE loc; | ||||||
|  |                         loc.beg_pos = @1.beg_pos; | ||||||
|  |                         loc.end_pos = @1.beg_pos; | ||||||
|  | 
 | ||||||
|  | 			value_expr($2); | ||||||
|  | 			$$ = NEW_DOT2(new_nil(&loc), $2, &@$); | ||||||
|  | 		    /*% %*/ | ||||||
|  | 		    /*% ripper: dot2!(Qnil, $2) %*/ | ||||||
|  | 		    } | ||||||
|  | 		| tBDOT3 arg | ||||||
|  | 		    { | ||||||
|  | 		    /*%%%*/ | ||||||
|  |                         YYLTYPE loc; | ||||||
|  |                         loc.beg_pos = @1.beg_pos; | ||||||
|  |                         loc.end_pos = @1.beg_pos; | ||||||
|  | 
 | ||||||
|  | 			value_expr($2); | ||||||
|  | 			$$ = NEW_DOT3(new_nil(&loc), $2, &@$); | ||||||
|  | 		    /*% %*/ | ||||||
|  | 		    /*% ripper: dot3!(Qnil, $2) %*/ | ||||||
|  | 		    } | ||||||
| 		| arg '+' arg | 		| arg '+' arg | ||||||
| 		    { | 		    { | ||||||
| 			$$ = call_bin_op(p, $1, '+', $3, &@2, &@$); | 			$$ = call_bin_op(p, $1, '+', $3, &@2, &@$); | ||||||
|  | @ -8241,15 +8267,16 @@ parser_yylex(struct parser_params *p) | ||||||
| 	pushback(p, c); | 	pushback(p, c); | ||||||
| 	return warn_balanced('-', "-", "unary operator"); | 	return warn_balanced('-', "-", "unary operator"); | ||||||
| 
 | 
 | ||||||
|       case '.': |       case '.': { | ||||||
|  |         int is_beg = IS_BEG(); | ||||||
| 	SET_LEX_STATE(EXPR_BEG); | 	SET_LEX_STATE(EXPR_BEG); | ||||||
| 	switch (c = nextc(p)) { | 	switch (c = nextc(p)) { | ||||||
| 	  case '.': | 	  case '.': | ||||||
| 	    if ((c = nextc(p)) == '.') { | 	    if ((c = nextc(p)) == '.') { | ||||||
| 		return tDOT3; | 		return is_beg ? tBDOT3 : tDOT3; | ||||||
| 	    } | 	    } | ||||||
| 	    pushback(p, c); | 	    pushback(p, c); | ||||||
| 	    return tDOT2; | 	    return is_beg ? tBDOT2 : tDOT2; | ||||||
| 	  case ':': | 	  case ':': | ||||||
| 	    switch (c = nextc(p)) { | 	    switch (c = nextc(p)) { | ||||||
| 	      default: | 	      default: | ||||||
|  | @ -8275,6 +8302,7 @@ parser_yylex(struct parser_params *p) | ||||||
| 	set_yylval_id('.'); | 	set_yylval_id('.'); | ||||||
| 	SET_LEX_STATE(EXPR_DOT); | 	SET_LEX_STATE(EXPR_DOT); | ||||||
| 	return '.'; | 	return '.'; | ||||||
|  |       } | ||||||
| 
 | 
 | ||||||
|       case '0': case '1': case '2': case '3': case '4': |       case '0': case '1': case '2': case '3': case '4': | ||||||
|       case '5': case '6': case '7': case '8': case '9': |       case '5': case '6': case '7': case '8': case '9': | ||||||
|  |  | ||||||
							
								
								
									
										49
									
								
								range.c
									
										
									
									
									
								
							
							
						
						
									
										49
									
								
								range.c
									
										
									
									
									
								
							|  | @ -35,7 +35,7 @@ static VALUE r_cover_p(VALUE, VALUE, VALUE, VALUE); | ||||||
| static void | static void | ||||||
| range_init(VALUE range, VALUE beg, VALUE end, VALUE exclude_end) | range_init(VALUE range, VALUE beg, VALUE end, VALUE exclude_end) | ||||||
| { | { | ||||||
|     if ((!FIXNUM_P(beg) || !FIXNUM_P(end)) && !NIL_P(end)) { |     if ((!FIXNUM_P(beg) || !FIXNUM_P(end)) && !NIL_P(beg) && !NIL_P(end)) { | ||||||
| 	VALUE v; | 	VALUE v; | ||||||
| 
 | 
 | ||||||
| 	v = rb_funcall(beg, id_cmp, 1, end); | 	v = rb_funcall(beg, id_cmp, 1, end); | ||||||
|  | @ -704,8 +704,8 @@ range_bsearch(VALUE range) | ||||||
|     } |     } | ||||||
| #if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T) | #if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T) | ||||||
|     else if (RB_TYPE_P(beg, T_FLOAT) || RB_TYPE_P(end, T_FLOAT)) { |     else if (RB_TYPE_P(beg, T_FLOAT) || RB_TYPE_P(end, T_FLOAT)) { | ||||||
| 	int64_t low  = double_as_int64(RFLOAT_VALUE(rb_Float(beg))); | 	int64_t low  = double_as_int64(NIL_P(beg) ? -HUGE_VAL : RFLOAT_VALUE(rb_Float(beg))); | ||||||
| 	int64_t high = double_as_int64(NIL_P(end) ? HUGE_VAL : RFLOAT_VALUE(rb_Float(end))); | 	int64_t high = double_as_int64(NIL_P(end) ?  HUGE_VAL : RFLOAT_VALUE(rb_Float(end))); | ||||||
| 	int64_t mid, org_high; | 	int64_t mid, org_high; | ||||||
| 	BSEARCH(int64_as_double_to_num); | 	BSEARCH(int64_as_double_to_num); | ||||||
|     } |     } | ||||||
|  | @ -726,6 +726,18 @@ range_bsearch(VALUE range) | ||||||
| 	    diff = rb_funcall(diff, '*', 1, LONG2FIX(2)); | 	    diff = rb_funcall(diff, '*', 1, LONG2FIX(2)); | ||||||
| 	} | 	} | ||||||
|     } |     } | ||||||
|  |     else if (NIL_P(beg) && is_integer_p(end)) { | ||||||
|  | 	VALUE diff = LONG2FIX(-1); | ||||||
|  | 	RETURN_ENUMERATOR(range, 0, 0); | ||||||
|  | 	while (1) { | ||||||
|  | 	    VALUE mid = rb_funcall(end, '+', 1, diff); | ||||||
|  | 	    BSEARCH_CHECK(mid); | ||||||
|  | 	    if (!smaller) { | ||||||
|  | 		return bsearch_integer_range(mid, end, 0); | ||||||
|  | 	    } | ||||||
|  | 	    diff = rb_funcall(diff, '*', 1, LONG2FIX(2)); | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|     else { |     else { | ||||||
| 	rb_raise(rb_eTypeError, "can't do binary search for %s", rb_obj_classname(beg)); | 	rb_raise(rb_eTypeError, "can't do binary search for %s", rb_obj_classname(beg)); | ||||||
|     } |     } | ||||||
|  | @ -770,6 +782,9 @@ range_size(VALUE range) | ||||||
|             return DBL2NUM(HUGE_VAL); |             return DBL2NUM(HUGE_VAL); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |     else if (NIL_P(b)) { | ||||||
|  |         return DBL2NUM(HUGE_VAL); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     return Qnil; |     return Qnil; | ||||||
| } | } | ||||||
|  | @ -1230,7 +1245,7 @@ rb_range_beg_len(VALUE range, long *begp, long *lenp, long len, int err) | ||||||
| 
 | 
 | ||||||
|     if (!rb_range_values(range, &b, &e, &excl)) |     if (!rb_range_values(range, &b, &e, &excl)) | ||||||
| 	return Qfalse; | 	return Qfalse; | ||||||
|     beg = NUM2LONG(b); |     beg = NIL_P(b) ? 0 : NUM2LONG(b); | ||||||
|     end = NIL_P(e) ? -1 : NUM2LONG(e); |     end = NIL_P(e) ? -1 : NUM2LONG(e); | ||||||
|     if (NIL_P(e)) excl = 0; |     if (NIL_P(e)) excl = 0; | ||||||
|     origbeg = beg; |     origbeg = beg; | ||||||
|  | @ -1392,6 +1407,12 @@ range_include_internal(VALUE range, VALUE val) | ||||||
| 	    VALUE rb_str_include_range_p(VALUE beg, VALUE end, VALUE val, VALUE exclusive); | 	    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)); | 	    return rb_str_include_range_p(beg, end, val, RANGE_EXCL(range)); | ||||||
| 	} | 	} | ||||||
|  |         else if (NIL_P(beg)) { | ||||||
|  | 	    VALUE r = rb_funcall(val, id_cmp, 1, end); | ||||||
|  | 	    if (NIL_P(r)) return Qfalse; | ||||||
|  | 	    if (rb_cmpint(r, val, end) <= 0) return Qtrue; | ||||||
|  | 	    return Qfalse; | ||||||
|  |         } | ||||||
| 	else if (NIL_P(end)) { | 	else if (NIL_P(end)) { | ||||||
| 	    VALUE r = rb_funcall(beg, id_cmp, 1, val); | 	    VALUE r = rb_funcall(beg, id_cmp, 1, val); | ||||||
| 	    if (NIL_P(r)) return Qfalse; | 	    if (NIL_P(r)) return Qfalse; | ||||||
|  | @ -1487,7 +1508,7 @@ r_cover_range_p(VALUE range, VALUE beg, VALUE end, VALUE val) | ||||||
| static VALUE | static VALUE | ||||||
| r_cover_p(VALUE range, VALUE beg, VALUE end, VALUE val) | r_cover_p(VALUE range, VALUE beg, VALUE end, VALUE val) | ||||||
| { | { | ||||||
|     if (r_less(beg, val) <= 0) { |     if (NIL_P(beg) || r_less(beg, val) <= 0) { | ||||||
| 	int excl = EXCL(range); | 	int excl = EXCL(range); | ||||||
| 	if (NIL_P(end) || r_less(val, end) <= -excl) | 	if (NIL_P(end) || r_less(val, end) <= -excl) | ||||||
| 	    return Qtrue; | 	    return Qtrue; | ||||||
|  | @ -1550,9 +1571,15 @@ range_alloc(VALUE klass) | ||||||
|  *     ('a'..'e').to_a    #=> ["a", "b", "c", "d", "e"] |  *     ('a'..'e').to_a    #=> ["a", "b", "c", "d", "e"] | ||||||
|  *     ('a'...'e').to_a   #=> ["a", "b", "c", "d"] |  *     ('a'...'e').to_a   #=> ["a", "b", "c", "d"] | ||||||
|  * |  * | ||||||
|  *  == Endless Ranges |  *  == Beginless/Endless Ranges | ||||||
|  |  * | ||||||
|  |  *  A "beginless range" and "endless range" represents a semi-infinite | ||||||
|  |  *  range.  Literal notation for a beginless range is: | ||||||
|  |  * | ||||||
|  |  *     (..1) | ||||||
|  |  *     # or | ||||||
|  |  *     (...1) | ||||||
|  * |  * | ||||||
|  *  An "endless range" represents a semi-infinite range. |  | ||||||
|  *  Literal notation for an endless range is: |  *  Literal notation for an endless range is: | ||||||
|  * |  * | ||||||
|  *     (1..) |  *     (1..) | ||||||
|  | @ -1564,14 +1591,16 @@ range_alloc(VALUE klass) | ||||||
|  *     (1..nil)  # or similarly (1...nil) |  *     (1..nil)  # or similarly (1...nil) | ||||||
|  *     Range.new(1, nil) # or Range.new(1, nil, true) |  *     Range.new(1, nil) # or Range.new(1, nil, true) | ||||||
|  * |  * | ||||||
|  *  Endless ranges are useful, for example, for idiomatic slicing of |  *  Beginless/endless ranges are useful, for example, for idiomatic | ||||||
|  *  arrays: |  *  slicing of arrays: | ||||||
|  * |  * | ||||||
|  |  *    [1, 2, 3, 4, 5][...2]   # => [1, 2] | ||||||
|  *    [1, 2, 3, 4, 5][2...]   # => [3, 4, 5] |  *    [1, 2, 3, 4, 5][2...]   # => [3, 4, 5] | ||||||
|  * |  * | ||||||
|  *  Some implementation details: |  *  Some implementation details: | ||||||
|  * |  * | ||||||
|  *  * +end+ of endless range is +nil+; |  *  * +begin+ of beginless range and +end+ of endless range are +nil+; | ||||||
|  |  *  * +each+ of beginless range raises an exception; | ||||||
|  *  * +each+ of endless range enumerates infinite sequence (may be |  *  * +each+ of endless range enumerates infinite sequence (may be | ||||||
|  *    useful in combination with Enumerable#take_while or similar |  *    useful in combination with Enumerable#take_while or similar | ||||||
|  *    methods); |  *    methods); | ||||||
|  |  | ||||||
|  | @ -43,9 +43,25 @@ describe "Range.new" do | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   describe "endless range" do |   describe "beginless/endless range" do | ||||||
|     it "does not allow range without left boundary" do |     ruby_version_is ""..."2.7" do | ||||||
|       -> { Range.new(nil, 1) }.should raise_error(ArgumentError, /bad value for range/) |       it "does not allow range without left boundary" do | ||||||
|  |         -> { Range.new(nil, 1) }.should raise_error(ArgumentError, /bad value for range/) | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     ruby_version_is "2.7" do | ||||||
|  |       it "allows beginless left boundary" do | ||||||
|  |         range = Range.new(nil, 1) | ||||||
|  |         range.begin.should == nil | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it "distinguishes ranges with included and excluded right boundary" do | ||||||
|  |         range_exclude = Range.new(nil, 1, true) | ||||||
|  |         range_include = Range.new(nil, 1, false) | ||||||
|  | 
 | ||||||
|  |         range_exclude.should_not == range_include | ||||||
|  |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     ruby_version_is ""..."2.6" do |     ruby_version_is ""..."2.6" do | ||||||
|  |  | ||||||
|  | @ -42,6 +42,8 @@ class TestArray < Test::Unit::TestCase | ||||||
|     assert_equal([1, 2, 3], x[1..3]) |     assert_equal([1, 2, 3], x[1..3]) | ||||||
|     assert_equal([1, 2, 3], x[1,3]) |     assert_equal([1, 2, 3], x[1,3]) | ||||||
|     assert_equal([3, 4, 5], x[3..]) |     assert_equal([3, 4, 5], x[3..]) | ||||||
|  |     assert_equal([0, 1, 2], x[..2]) | ||||||
|  |     assert_equal([0, 1], x[...2]) | ||||||
| 
 | 
 | ||||||
|     x[0, 2] = 10 |     x[0, 2] = 10 | ||||||
|     assert_equal([10, 2, 3, 4, 5], x) |     assert_equal([10, 2, 3, 4, 5], x) | ||||||
|  | @ -375,8 +377,11 @@ class TestArray < Test::Unit::TestCase | ||||||
| 
 | 
 | ||||||
|     assert_equal(@cls[10, 11, 12], a[9..11]) |     assert_equal(@cls[10, 11, 12], a[9..11]) | ||||||
|     assert_equal(@cls[98, 99, 100], a[97..]) |     assert_equal(@cls[98, 99, 100], a[97..]) | ||||||
|  |     assert_equal(@cls[1, 2, 3], a[..2]) | ||||||
|  |     assert_equal(@cls[1, 2], a[...2]) | ||||||
|     assert_equal(@cls[10, 11, 12], a[-91..-89]) |     assert_equal(@cls[10, 11, 12], a[-91..-89]) | ||||||
|     assert_equal(@cls[98, 99, 100], a[-3..]) |     assert_equal(@cls[1, 2, 3], a[..-98]) | ||||||
|  |     assert_equal(@cls[1, 2], a[...-98]) | ||||||
| 
 | 
 | ||||||
|     assert_nil(a[10, -3]) |     assert_nil(a[10, -3]) | ||||||
|     assert_equal [], a[10..7] |     assert_equal [], a[10..7] | ||||||
|  | @ -462,6 +467,14 @@ class TestArray < Test::Unit::TestCase | ||||||
|     assert_equal(nil, a[10..] = nil) |     assert_equal(nil, a[10..] = nil) | ||||||
|     assert_equal(@cls[*(0..9).to_a] + @cls[nil], a) |     assert_equal(@cls[*(0..9).to_a] + @cls[nil], a) | ||||||
| 
 | 
 | ||||||
|  |     a = @cls[*(0..99).to_a] | ||||||
|  |     assert_equal(nil, a[..10] = nil) | ||||||
|  |     assert_equal(@cls[nil] + @cls[*(11..99).to_a], a) | ||||||
|  | 
 | ||||||
|  |     a = @cls[*(0..99).to_a] | ||||||
|  |     assert_equal(nil, a[...10] = nil) | ||||||
|  |     assert_equal(@cls[nil] + @cls[*(10..99).to_a], a) | ||||||
|  | 
 | ||||||
|     a = @cls[1, 2, 3] |     a = @cls[1, 2, 3] | ||||||
|     a[1, 0] = a |     a[1, 0] = a | ||||||
|     assert_equal([1, 1, 2, 3, 2, 3], a) |     assert_equal([1, 1, 2, 3, 2, 3], a) | ||||||
|  |  | ||||||
|  | @ -691,6 +691,8 @@ class TestRange < Test::Unit::TestCase | ||||||
| 
 | 
 | ||||||
|     assert_equal Float::INFINITY, (1...).size |     assert_equal Float::INFINITY, (1...).size | ||||||
|     assert_equal Float::INFINITY, (1.0...).size |     assert_equal Float::INFINITY, (1.0...).size | ||||||
|  |     assert_equal Float::INFINITY, (...1).size | ||||||
|  |     assert_equal Float::INFINITY, (...1.0).size | ||||||
|     assert_nil ("a"...).size |     assert_nil ("a"...).size | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  | @ -735,6 +737,7 @@ class TestRange < Test::Unit::TestCase | ||||||
|     assert_equal(1, (0...ary.size).bsearch {|i| ary[i] >= 100 }) |     assert_equal(1, (0...ary.size).bsearch {|i| ary[i] >= 100 }) | ||||||
| 
 | 
 | ||||||
|     assert_equal(1_000_001, (0...).bsearch {|i| i > 1_000_000 }) |     assert_equal(1_000_001, (0...).bsearch {|i| i > 1_000_000 }) | ||||||
|  |     assert_equal( -999_999, (...0).bsearch {|i| i > -1_000_000 }) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def test_bsearch_for_float |   def test_bsearch_for_float | ||||||
|  | @ -787,7 +790,8 @@ class TestRange < Test::Unit::TestCase | ||||||
|     assert_in_delta(1.0, (0.0..inf).bsearch {|x| Math.log(x) >= 0 }) |     assert_in_delta(1.0, (0.0..inf).bsearch {|x| Math.log(x) >= 0 }) | ||||||
|     assert_in_delta(7.0, (0.0..10).bsearch {|x| 7.0 - x }) |     assert_in_delta(7.0, (0.0..10).bsearch {|x| 7.0 - x }) | ||||||
| 
 | 
 | ||||||
|     assert_equal(1_000_000.0.next_float, (0.0..).bsearch {|x| x > 1_000_000 }) |     assert_equal( 1_000_000.0.next_float, (0.0..).bsearch {|x| x > 1_000_000 }) | ||||||
|  |     assert_equal(-1_000_000.0.next_float, (..0.0).bsearch {|x| x > -1_000_000 }) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def check_bsearch_values(range, search, a) |   def check_bsearch_values(range, search, a) | ||||||
|  | @ -890,6 +894,7 @@ class TestRange < Test::Unit::TestCase | ||||||
|     assert_equal(bignum + 0, (bignum...bignum+ary.size).bsearch {|i| true }) |     assert_equal(bignum + 0, (bignum...bignum+ary.size).bsearch {|i| true }) | ||||||
|     assert_equal(nil, (bignum...bignum+ary.size).bsearch {|i| false }) |     assert_equal(nil, (bignum...bignum+ary.size).bsearch {|i| false }) | ||||||
|     assert_equal(bignum * 2 + 1, (bignum...).bsearch {|i| i > bignum * 2 }) |     assert_equal(bignum * 2 + 1, (bignum...).bsearch {|i| i > bignum * 2 }) | ||||||
|  |     assert_equal(-bignum * 2 + 1, (...-bignum).bsearch {|i| i > -bignum * 2 }) | ||||||
| 
 | 
 | ||||||
|     assert_raise(TypeError) { ("a".."z").bsearch {} } |     assert_raise(TypeError) { ("a".."z").bsearch {} } | ||||||
|   end |   end | ||||||
|  | @ -907,4 +912,8 @@ class TestRange < Test::Unit::TestCase | ||||||
|     assert_equal([1,2,3,4], (1...5).to_a) |     assert_equal([1,2,3,4], (1...5).to_a) | ||||||
|     assert_raise(RangeError) { (1..).to_a } |     assert_raise(RangeError) { (1..).to_a } | ||||||
|   end |   end | ||||||
|  | 
 | ||||||
|  |   def test_beginless_range_iteration | ||||||
|  |     assert_raise(TypeError) { (..1).each { } } | ||||||
|  |   end | ||||||
| end | end | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 mame
						mame