diff options
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | NEWS | 5 | ||||
-rw-r--r-- | range.c | 53 | ||||
-rw-r--r-- | string.c | 18 |
4 files changed, 56 insertions, 30 deletions
@@ -1,3 +1,13 @@ +Wed May 28 17:48:28 2008 Akinori MUSHA <knu@iDaemons.org> + + * range.c (range_step): Fix brokenness when a non-integer numeric + value is specified as step. [rubyspec] + (range_step): Make use of String#step internally if a string (or + string-alike) range is given. + + * string.c (rb_str_upto_m, Init_String): Add an optional second + argument to specify if the last value should be included. + Wed May 28 16:53:39 2008 Akinori MUSHA <knu@iDaemons.org> * array.c (rb_ary_slice_bang): Call rb_ary_modify_check() at the @@ -246,6 +246,11 @@ with all sufficient information, see the ChangeLog file. Return an enumerator if no block is given. + * String#upto + + An optional second argument is added to specify if the last value + should be included. + * StopIteration New exception class that causes Kernel#loop to stop iteration when @@ -278,7 +278,7 @@ step_i(i, arg) * rng.step(n=1) {| obj | block } => rng * * Iterates over <i>rng</i>, passing each <i>n</i>th element to the block. If - * the range contains numbers or strings, natural ordering is used. Otherwise + * the range contains numbers, <i>n</i> is added for each iteration. Otherwise * <code>step</code> invokes <code>succ</code> to iterate through range * elements. The following code uses class <code>Xs</code>, which is defined * in the class-level documentation. @@ -308,7 +308,6 @@ range_step(argc, argv, range) VALUE range; { VALUE b, e, step, tmp; - long unit; RETURN_ENUMERATOR(range, argc, argv); @@ -316,49 +315,56 @@ range_step(argc, argv, range) e = rb_ivar_get(range, id_end); if (argc == 0) { step = INT2FIX(1); - unit = 1; } else { rb_scan_args(argc, argv, "01", &step); - tmp = rb_check_to_integer(step, "to_int"); - if (!NIL_P(tmp)) { - step = tmp; - unit = NUM2LONG(step); + if (!rb_obj_is_kind_of(step, rb_cNumeric)) { + step = rb_to_int(step); } - else { - tmp = rb_funcall(rb_funcall(b, '+', 1, step), '-', 1, b); - unit = rb_cmpint(tmp, step, INT2FIX(0)); + if (rb_funcall(step, '<', 1, INT2FIX(0))) { + rb_raise(rb_eArgError, "step can't be negative"); + } + else if (!rb_funcall(step, '>', 1, INT2FIX(0))) { + rb_raise(rb_eArgError, "step can't be 0"); } } - if (unit < 0) { - rb_raise(rb_eArgError, "step can't be negative"); - } - if (unit == 0) - rb_raise(rb_eArgError, "step can't be 0"); + if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) { /* fixnums are special */ long end = FIX2LONG(e); - long i; + long i, unit = FIX2LONG(step); - if (unit == 0) rb_raise(rb_eArgError, "step can't be 0"); - if (!EXCL(range)) end += 1; + if (!EXCL(range)) + end += 1; i = FIX2LONG(b); while (i < end) { rb_yield(LONG2NUM(i)); if (i + unit < i) break; i += unit; } + + } + else if (rb_obj_is_kind_of(b, rb_cNumeric) || + !NIL_P(rb_check_to_integer(b, "to_int")) || + !NIL_P(rb_check_to_integer(e, "to_int"))) { + ID op = EXCL(range) ? '<' : rb_intern("<="); + + while (RTEST(rb_funcall(b, op, 1, e))) { + rb_yield(b); + b = rb_funcall(b, '+', 1, step); + } } else { - VALUE tmp = rb_check_string_type(b); + tmp = rb_check_string_type(b); if (!NIL_P(tmp)) { VALUE args[5], iter[2]; b = tmp; - args[0] = b; args[1] = e; args[2] = range; - iter[0] = INT2FIX(1); iter[1] = step; - rb_iterate((VALUE(*)_((VALUE)))str_step, (VALUE)args, step_i, - (VALUE)iter); + 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); } else if (rb_obj_is_kind_of(b, rb_cNumeric) || !NIL_P(rb_check_to_integer(b, "to_int")) || @@ -377,7 +383,6 @@ range_step(argc, argv, range) rb_raise(rb_eTypeError, "can't iterate from %s", rb_obj_classname(b)); } - args[0] = INT2FIX(1); args[1] = step; range_each_func(range, step_i, b, e, args); @@ -1492,12 +1492,13 @@ rb_str_upto(beg, end, excl) /* * call-seq: - * str.upto(other_str) {|s| block } => str + * str.upto(other_str, exclusive=false) {|s| block } => str * * Iterates through successive values, starting at <i>str</i> and * ending at <i>other_str</i> inclusive, passing each value in turn to * the block. The <code>String#succ</code> method is used to generate - * each value. + * each value. If optional second argument exclusive is omitted or is <code>false</code>, + * the last value will be included; otherwise it will be excluded. * * "a8".upto("b6") {|s| print s, ' ' } * for s in "a8".."b6" @@ -1511,10 +1512,15 @@ rb_str_upto(beg, end, excl) */ static VALUE -rb_str_upto_m(beg, end) - VALUE beg, end; +rb_str_upto_m(argc, argv, beg) + int argc; + VALUE argv, beg; { - return rb_str_upto(beg, end, Qfalse); + VALUE end, exclusive; + + rb_scan_args(argc, argv, "11", &end, &exclusive); + + return rb_str_upto(beg, end, RTEST(exclusive)); } static VALUE @@ -4929,7 +4935,7 @@ Init_String() rb_define_method(rb_cString, "succ!", rb_str_succ_bang, 0); rb_define_method(rb_cString, "next", rb_str_succ, 0); rb_define_method(rb_cString, "next!", rb_str_succ_bang, 0); - rb_define_method(rb_cString, "upto", rb_str_upto_m, 1); + rb_define_method(rb_cString, "upto", rb_str_upto_m, -1); rb_define_method(rb_cString, "index", rb_str_index_m, -1); rb_define_method(rb_cString, "rindex", rb_str_rindex_m, -1); rb_define_method(rb_cString, "replace", rb_str_replace, 1); |