diff options
-rw-r--r-- | enumerator.c | 26 | ||||
-rw-r--r-- | ext/-test-/enumerator_kw/depend | 14 | ||||
-rw-r--r-- | ext/-test-/enumerator_kw/enumerator_kw.c | 21 | ||||
-rwxr-xr-x | ext/-test-/enumerator_kw/extconf.rb | 1 | ||||
-rw-r--r-- | include/ruby/intern.h | 11 | ||||
-rw-r--r-- | test/-ext-/test_enumerator_kw.rb | 11 | ||||
-rw-r--r-- | test/ruby/test_enumerator.rb | 8 |
7 files changed, 85 insertions, 7 deletions
diff --git a/enumerator.c b/enumerator.c index 9eb530c91b..18d06bb3e9 100644 --- a/enumerator.c +++ b/enumerator.c @@ -513,7 +513,7 @@ rb_enumeratorize(VALUE obj, VALUE meth, int argc, const VALUE *argv) } static VALUE -lazy_to_enum_i(VALUE self, VALUE meth, int argc, const VALUE *argv, rb_enumerator_size_func *size_fn); +lazy_to_enum_i(VALUE self, VALUE meth, int argc, const VALUE *argv, rb_enumerator_size_func *size_fn, int kw_splat); VALUE rb_enumeratorize_with_size(VALUE obj, VALUE meth, int argc, const VALUE *argv, rb_enumerator_size_func *size_fn) @@ -521,12 +521,24 @@ rb_enumeratorize_with_size(VALUE obj, VALUE meth, int argc, const VALUE *argv, r /* Similar effect as calling obj.to_enum, i.e. dispatching to either Kernel#to_enum vs Lazy#to_enum */ if (RTEST(rb_obj_is_kind_of(obj, rb_cLazy))) - return lazy_to_enum_i(obj, meth, argc, argv, size_fn); + return lazy_to_enum_i(obj, meth, argc, argv, size_fn, PASS_KW_SPLAT); else return enumerator_init(enumerator_allocate(rb_cEnumerator), obj, meth, argc, argv, size_fn, Qnil, PASS_KW_SPLAT); } +VALUE +rb_enumeratorize_with_size_kw(VALUE obj, VALUE meth, int argc, const VALUE *argv, rb_enumerator_size_func *size_fn, int kw_splat) +{ + /* Similar effect as calling obj.to_enum, i.e. dispatching to either + Kernel#to_enum vs Lazy#to_enum */ + if (RTEST(rb_obj_is_kind_of(obj, rb_cLazy))) + return lazy_to_enum_i(obj, meth, argc, argv, size_fn, kw_splat); + else + return enumerator_init(enumerator_allocate(rb_cEnumerator), + obj, meth, argc, argv, size_fn, Qnil, kw_splat); +} + static VALUE enumerator_block_call(VALUE obj, rb_block_call_func *func, VALUE arg) { @@ -1868,17 +1880,17 @@ lazy_add_method(VALUE obj, int argc, VALUE *argv, VALUE args, VALUE memo, static VALUE enumerable_lazy(VALUE obj) { - VALUE result = lazy_to_enum_i(obj, sym_each, 0, 0, lazyenum_size); + VALUE result = lazy_to_enum_i(obj, sym_each, 0, 0, lazyenum_size, PASS_KW_SPLAT); /* Qfalse indicates that the Enumerator::Lazy has no method name */ rb_ivar_set(result, id_method, Qfalse); return result; } static VALUE -lazy_to_enum_i(VALUE obj, VALUE meth, int argc, const VALUE *argv, rb_enumerator_size_func *size_fn) +lazy_to_enum_i(VALUE obj, VALUE meth, int argc, const VALUE *argv, rb_enumerator_size_func *size_fn, int kw_splat) { return enumerator_init(enumerator_allocate(rb_cLazy), - obj, meth, argc, argv, size_fn, Qnil, PASS_KW_SPLAT); + obj, meth, argc, argv, size_fn, Qnil, kw_splat); } /* @@ -1916,7 +1928,7 @@ lazy_to_enum(int argc, VALUE *argv, VALUE self) if (RTEST((super_meth = rb_hash_aref(lazy_use_super_method, meth)))) { meth = super_meth; } - lazy = lazy_to_enum_i(self, meth, argc, argv, 0); + lazy = lazy_to_enum_i(self, meth, argc, argv, 0, PASS_KW_SPLAT); if (rb_block_given_p()) { enumerator_ptr(lazy)->size = rb_block_proc(); } @@ -2919,7 +2931,7 @@ enumerator_s_produce(int argc, VALUE *argv, VALUE klass) producer = producer_init(producer_allocate(rb_cEnumProducer), init, rb_block_proc()); - return rb_enumeratorize_with_size(producer, sym_each, 0, 0, producer_size); + return rb_enumeratorize_with_size_kw(producer, sym_each, 0, 0, producer_size, RB_NO_KEYWORDS); } /* diff --git a/ext/-test-/enumerator_kw/depend b/ext/-test-/enumerator_kw/depend new file mode 100644 index 0000000000..b7489eaf73 --- /dev/null +++ b/ext/-test-/enumerator_kw/depend @@ -0,0 +1,14 @@ +# AUTOGENERATED DEPENDENCIES START +enumerator_kw.o: $(RUBY_EXTCONF_H) +enumerator_kw.o: $(arch_hdrdir)/ruby/config.h +enumerator_kw.o: $(hdrdir)/ruby.h +enumerator_kw.o: $(hdrdir)/ruby/assert.h +enumerator_kw.o: $(hdrdir)/ruby/backward.h +enumerator_kw.o: $(hdrdir)/ruby/defines.h +enumerator_kw.o: $(hdrdir)/ruby/intern.h +enumerator_kw.o: $(hdrdir)/ruby/missing.h +enumerator_kw.o: $(hdrdir)/ruby/ruby.h +enumerator_kw.o: $(hdrdir)/ruby/st.h +enumerator_kw.o: $(hdrdir)/ruby/subst.h +enumerator_kw.o: enumerator_kw.c +# AUTOGENERATED DEPENDENCIES END diff --git a/ext/-test-/enumerator_kw/enumerator_kw.c b/ext/-test-/enumerator_kw/enumerator_kw.c new file mode 100644 index 0000000000..cd6099ffb3 --- /dev/null +++ b/ext/-test-/enumerator_kw/enumerator_kw.c @@ -0,0 +1,21 @@ +#include <ruby.h> + +static VALUE +enumerator_kw(int argc, VALUE *argv, VALUE self) +{ + VALUE obj, opt, enum_args[4]; + enum_args[0] = Qnil; + enum_args[1] = Qnil; + rb_scan_args(argc, argv, "01*:", enum_args, enum_args+1, &opt); + enum_args[3] = self; + enum_args[2] = opt; + RETURN_SIZED_ENUMERATOR_KW(self, 4, enum_args, 0, RB_NO_KEYWORDS); + return rb_yield_values_kw(4, enum_args, RB_NO_KEYWORDS); +} + +void +Init_enumerator_kw(void) { + VALUE module = rb_define_module("Bug"); + module = rb_define_module_under(module, "EnumeratorKw"); + rb_define_method(module, "m", enumerator_kw, -1); +} diff --git a/ext/-test-/enumerator_kw/extconf.rb b/ext/-test-/enumerator_kw/extconf.rb new file mode 100755 index 0000000000..ab2be73fa8 --- /dev/null +++ b/ext/-test-/enumerator_kw/extconf.rb @@ -0,0 +1 @@ +create_makefile("-test-/enumerator_kw") diff --git a/include/ruby/intern.h b/include/ruby/intern.h index 14543a9f4d..66c2ca6025 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -251,18 +251,29 @@ VALUE rb_enum_values_pack(int, const VALUE*); VALUE rb_enumeratorize(VALUE, VALUE, int, const VALUE *); typedef VALUE rb_enumerator_size_func(VALUE, VALUE, VALUE); VALUE rb_enumeratorize_with_size(VALUE, VALUE, int, const VALUE *, rb_enumerator_size_func *); +VALUE rb_enumeratorize_with_size_kw(VALUE, VALUE, int, const VALUE *, rb_enumerator_size_func *, int); #ifndef RUBY_EXPORT #define rb_enumeratorize_with_size(obj, id, argc, argv, size_fn) \ rb_enumeratorize_with_size(obj, id, argc, argv, (rb_enumerator_size_func *)(size_fn)) +#define rb_enumeratorize_with_size_kw(obj, id, argc, argv, size_fn, kw_splat) \ + rb_enumeratorize_with_size_kw(obj, id, argc, argv, (rb_enumerator_size_func *)(size_fn), kw_splat) #endif #define SIZED_ENUMERATOR(obj, argc, argv, size_fn) \ rb_enumeratorize_with_size((obj), ID2SYM(rb_frame_this_func()), \ (argc), (argv), (size_fn)) +#define SIZED_ENUMERATOR_KW(obj, argc, argv, size_fn, kw_splat) \ + rb_enumeratorize_with_size_kw((obj), ID2SYM(rb_frame_this_func()), \ + (argc), (argv), (size_fn), (kw_splat)) #define RETURN_SIZED_ENUMERATOR(obj, argc, argv, size_fn) do { \ if (!rb_block_given_p()) \ return SIZED_ENUMERATOR(obj, argc, argv, size_fn); \ } while (0) +#define RETURN_SIZED_ENUMERATOR_KW(obj, argc, argv, size_fn, kw_splat) do { \ + if (!rb_block_given_p()) \ + return SIZED_ENUMERATOR_KW(obj, argc, argv, size_fn, kw_splat); \ + } while (0) #define RETURN_ENUMERATOR(obj, argc, argv) RETURN_SIZED_ENUMERATOR(obj, argc, argv, 0) +#define RETURN_ENUMERATOR_KW(obj, argc, argv, kw_splat) RETURN_SIZED_ENUMERATOR_KW(obj, argc, argv, 0, kw_splat) typedef struct { VALUE begin; VALUE end; diff --git a/test/-ext-/test_enumerator_kw.rb b/test/-ext-/test_enumerator_kw.rb new file mode 100644 index 0000000000..fb47c2bcf8 --- /dev/null +++ b/test/-ext-/test_enumerator_kw.rb @@ -0,0 +1,11 @@ +require 'test/unit' +require '-test-/enumerator_kw' + +class TestEnumeratorKw < Test::Unit::TestCase + def test_enumerator_kw + o = Object.new + o.extend Bug::EnumeratorKw + assert_equal([nil, [], {:a=>1}, o], o.m(a: 1) { |*a| a }) + assert_equal([nil, [[], {:a=>1}, o], nil, o], o.m(a: 1).each { |*a| a }) + end +end diff --git a/test/ruby/test_enumerator.rb b/test/ruby/test_enumerator.rb index 1e306c33a2..65adb5a438 100644 --- a/test/ruby/test_enumerator.rb +++ b/test/ruby/test_enumerator.rb @@ -831,6 +831,14 @@ class TestEnumerator < Test::Unit::TestCase assert_equal [1, 2, 3], enum.take(3) assert_equal [1, 2], passed_args + # With initial keyword arguments + passed_args = [] + enum = Enumerator.produce(a: 1, b: 1) { |obj| passed_args << obj; obj.shift if obj.respond_to?(:shift)} + assert_instance_of(Enumerator, enum) + assert_equal Float::INFINITY, enum.size + assert_equal [{b: 1}, [1], :a, nil], enum.take(4) + assert_equal [{b: 1}, [1], :a], passed_args + # Raising StopIteration words = "The quick brown fox jumps over the lazy dog.".scan(/\w+/) enum = Enumerator.produce { words.shift or raise StopIteration } |