summaryrefslogtreecommitdiff
path: root/range.c
diff options
context:
space:
mode:
authorzverok <[email protected]>2024-09-08 19:26:23 +0300
committerAkinori Musha <[email protected]>2024-09-09 17:46:13 +0900
commitd7b0f269636749fdae2ba155ba5f9b752aa17341 (patch)
tree12cf7a325dafb84ecbe36339c6a0071cbce52d36 /range.c
parent155989415b660caba247db74f96b299e0cea66c1 (diff)
Return back legacy Range#step behavior for symbol ranges
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/11573
Diffstat (limited to 'range.c')
-rw-r--r--range.c39
1 files changed, 30 insertions, 9 deletions
diff --git a/range.c b/range.c
index a52418d2cb..e8a35c22cc 100644
--- a/range.c
+++ b/range.c
@@ -309,8 +309,8 @@ range_each_func(VALUE range, int (*func)(VALUE, VALUE), VALUE arg)
}
}
-// NB: Two functions below (step_i_iter and step_i) are used only to maintain the
-// backward-compatible behavior for string ranges with integer steps. If that branch
+// NB: Two functions below (step_i_iter, sym_step_i and step_i) are used only to maintain the
+// backward-compatible behavior for string and symbol ranges with integer steps. If that branch
// will be removed from range_step, these two can go, too.
static bool
step_i_iter(VALUE arg)
@@ -329,6 +329,15 @@ step_i_iter(VALUE arg)
}
static int
+sym_step_i(VALUE i, VALUE arg)
+{
+ if (step_i_iter(arg)) {
+ rb_yield(rb_str_intern(i));
+ }
+ return 0;
+}
+
+static int
step_i(VALUE i, VALUE arg)
{
if (step_i_iter(arg)) {
@@ -482,15 +491,16 @@ range_step(int argc, VALUE *argv, VALUE range)
const VALUE b_num_p = rb_obj_is_kind_of(b, rb_cNumeric);
const VALUE e_num_p = rb_obj_is_kind_of(e, rb_cNumeric);
- // For backward compatibility reasons (conforming to behavior before 3.4), String supports
- // both old behavior ('a'..).step(1) and new behavior ('a'..).step('a')
+ // For backward compatibility reasons (conforming to behavior before 3.4), String/Symbol
+ // supports both old behavior ('a'..).step(1) and new behavior ('a'..).step('a')
// Hence the additional conversion/addional checks.
- const VALUE sb = rb_check_string_type(b);
+ const VALUE str_b = rb_check_string_type(b);
+ const VALUE sym_b = SYMBOL_P(b) ? rb_sym2str(b) : Qnil;
if (rb_check_arity(argc, 0, 1))
step = argv[0];
else {
- if (b_num_p || !NIL_P(sb) || (NIL_P(b) && e_num_p))
+ if (b_num_p || !NIL_P(str_b) || !NIL_P(sym_b) || (NIL_P(b) && e_num_p))
step = INT2FIX(1);
else
rb_raise(rb_eArgError, "step is required for non-numeric ranges");
@@ -561,17 +571,28 @@ range_step(int argc, VALUE *argv, VALUE range)
}
else if (b_num_p && step_num_p && ruby_float_step(b, e, step, EXCL(range), TRUE)) {
/* done */
- } else if (!NIL_P(sb) && FIXNUM_P(step)) {
+ } else if (!NIL_P(str_b) && FIXNUM_P(step)) {
// backwards compatibility behavior for String only, when no step/Integer step is passed
// See discussion in https://bugs.ruby-lang.org/issues/18368
VALUE iter[2] = {INT2FIX(1), step};
if (NIL_P(e)) {
- rb_str_upto_endless_each(sb, step_i, (VALUE)iter);
+ rb_str_upto_endless_each(str_b, step_i, (VALUE)iter);
+ }
+ else {
+ rb_str_upto_each(str_b, e, EXCL(range), step_i, (VALUE)iter);
+ }
+ } else if (!NIL_P(sym_b) && FIXNUM_P(step)) {
+ // same as above: backward compatibility for symbols
+
+ VALUE iter[2] = {INT2FIX(1), step};
+
+ if (NIL_P(e)) {
+ rb_str_upto_endless_each(sym_b, sym_step_i, (VALUE)iter);
}
else {
- rb_str_upto_each(sb, e, EXCL(range), step_i, (VALUE)iter);
+ rb_str_upto_each(sym_b, rb_sym2str(e), EXCL(range), sym_step_i, (VALUE)iter);
}
} else {
v = b;