summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--enumerator.c26
-rw-r--r--ext/-test-/enumerator_kw/depend14
-rw-r--r--ext/-test-/enumerator_kw/enumerator_kw.c21
-rwxr-xr-xext/-test-/enumerator_kw/extconf.rb1
-rw-r--r--include/ruby/intern.h11
-rw-r--r--test/-ext-/test_enumerator_kw.rb11
-rw-r--r--test/ruby/test_enumerator.rb8
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 }