diff --git a/ext/date/date_core.c b/ext/date/date_core.c index 3b18bbd5b1..dbc7c29446 100644 --- a/ext/date/date_core.c +++ b/ext/date/date_core.c @@ -20,7 +20,7 @@ #define USE_PACK -static ID id_cmp, id_le_p, id_ge_p, id_eqeq_p; +static ID id_cmp, id_le_p, id_ge_p, id_eqeq_p, id_to, id_by; static VALUE cDate, cDateTime; static VALUE half_days_in_day, day_in_nanoseconds; static double positive_inf, negative_inf; @@ -6153,20 +6153,37 @@ static VALUE d_lite_cmp(VALUE, VALUE); static VALUE d_lite_step(int argc, VALUE *argv, VALUE self) { - VALUE limit, step, date; + VALUE limit, step, hash, date; - rb_scan_args(argc, argv, "11", &limit, &step); + RETURN_ENUMERATOR(self, argc, argv); - if (argc < 2) + argc = rb_scan_args(argc, argv, "02:", &limit, &step, &hash); + + if (!NIL_P(hash)) { + ID keys[2]; + VALUE values[2]; + keys[0] = id_to; + keys[1] = id_by; + rb_get_kwargs(hash, keys, 0, 2, values); + if (values[0] != Qundef) { + if (argc > 0) rb_raise(rb_eArgError, "to is given twice"); + limit = values[0]; + } + if (values[1] != Qundef) { + if (argc > 1) rb_raise(rb_eArgError, "step is given twice"); + step = values[1]; + } + } + + if (NIL_P(step)) { step = INT2FIX(1); + } #if 0 if (f_zero_p(step)) rb_raise(rb_eArgError, "step can't be 0"); #endif - RETURN_ENUMERATOR(self, argc, argv); - date = self; switch (FIX2INT(f_cmp(step, INT2FIX(0)))) { case -1: @@ -9664,6 +9681,9 @@ Init_date_core(void) date_s_test_unit_conv, 0); de_define_singleton_method(cDate, "test_all", date_s_test_all, 0); #endif + + id_to = rb_intern("to"); + id_by = rb_intern("by"); } /* diff --git a/test/date/test_date_arith.rb b/test/date/test_date_arith.rb index 96622ba065..b37a6f4ed3 100644 --- a/test/date/test_date_arith.rb +++ b/test/date/test_date_arith.rb @@ -245,21 +245,53 @@ def test_step end assert_equal(4, i) + i = 0 + p.step(q, by: 2) do + i += 1 + end + assert_equal(4, i) + + i = 0 + p.step(to: q, by: 2) do + i += 1 + end + assert_equal(4, i) + i = 0 p.step(q) do i += 1 end assert_equal(8, i) + + i = 0 + p.step(to: q) do + i += 1 + end + assert_equal(8, i) + + assert_raise(ArgumentError) { p.step(q, to: q) { } } + assert_raise(ArgumentError) { p.step(q, 1, by: 1) { } } + assert_raise(ArgumentError) { p.step(q, foo: nil) { } } end def test_step__noblock p = Date.new(2001,1,14) q = Date.new(2001,1,21) + e = p.step(q, 2) assert_equal(4, e.to_a.size) + e = p.step(q, by: 2) + assert_equal(4, e.to_a.size) + + e = p.step(to: q, by: 2) + assert_equal(4, e.to_a.size) + e = p.step(q) assert_equal(8, e.to_a.size) + + e = p.step(to: q) + assert_equal(8, e.to_a.size) end end