summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorknu <knu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-05-28 08:52:57 +0000
committerknu <knu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-05-28 08:52:57 +0000
commitacdda413ab35c13e85bd3cfe2ed45aacbb059932 (patch)
tree8d90a1c939819ebb18abd1c725c01457d4d18df7
parentd55bb05153a2fbc8b9b74636cd47351a3d51a4d7 (diff)
Merge from ruby_1_8.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8_7@16671 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog10
-rw-r--r--NEWS5
-rw-r--r--range.c53
-rw-r--r--string.c18
4 files changed, 56 insertions, 30 deletions
diff --git a/ChangeLog b/ChangeLog
index 355c8dae7b..a26643af79 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/NEWS b/NEWS
index 60eda7a813..067086ecc2 100644
--- a/NEWS
+++ b/NEWS
@@ -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
diff --git a/range.c b/range.c
index f460dcbb58..7526324da7 100644
--- a/range.c
+++ b/range.c
@@ -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);
diff --git a/string.c b/string.c
index c23f650496..7e26edb5b2 100644
--- a/string.c
+++ b/string.c
@@ -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);