diff options
-rw-r--r-- | ChangeLog | 14 | ||||
-rw-r--r-- | common.mk | 3 | ||||
-rw-r--r-- | enum.c | 42 | ||||
-rw-r--r-- | enumerator.c | 414 | ||||
-rw-r--r-- | ext/enumerator/.cvsignore | 2 | ||||
-rw-r--r-- | ext/enumerator/enumerator.c | 298 | ||||
-rw-r--r-- | ext/enumerator/enumerator.txt | 102 | ||||
-rw-r--r-- | ext/enumerator/extconf.rb | 2 | ||||
-rw-r--r-- | inits.c | 2 | ||||
-rw-r--r-- | intern.h | 8 | ||||
-rw-r--r-- | ruby.h | 3 |
11 files changed, 484 insertions, 406 deletions
@@ -1,3 +1,17 @@ +Wed Apr 9 19:58:31 2008 Akinori MUSHA <knu@iDaemons.org> + + * enumerator.c, inits.c (rb_call_inits), ruby.h, intern.h, + ext/enumerator, common.mk (OBJS, enumerator.$(OBJEXT)): Make the + enumerator module built-in, + + * enumerator.c: New method: Enumerable::Enumerator#with_index. + + * enum.c (enum_each_with_index): Enumerable#each_with_index now + returns an enumerator instead of raising an exception if no + block is given. Enumerable#enum_with_index, formerly defined in + the enumerator module, is kept as an alias to each_with_index + for backward compatibility. + Wed Apr 9 19:43:51 2008 Akinori MUSHA <knu@iDaemons.org> * eval.c (rb_obj_method, rb_proc_call), intern.h: Export. @@ -23,6 +23,7 @@ OBJS = array.$(OBJEXT) \ dir.$(OBJEXT) \ dln.$(OBJEXT) \ enum.$(OBJEXT) \ + enumerator.$(OBJEXT) \ error.$(OBJEXT) \ eval.$(OBJEXT) \ file.$(OBJEXT) \ @@ -370,6 +371,8 @@ dmyext.$(OBJEXT): {$(VPATH)}dmyext.c enum.$(OBJEXT): {$(VPATH)}enum.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}node.h {$(VPATH)}util.h +enumerator.$(OBJEXT): {$(VPATH)}enumerator.c {$(VPATH)}ruby.h config.h \ + {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h error.$(OBJEXT): {$(VPATH)}error.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}env.h {$(VPATH)}st.h @@ -17,6 +17,41 @@ VALUE rb_mEnumerable; static ID id_each, id_eqq, id_cmp; +struct iter_method_arg { + VALUE obj; + ID mid; + int argc; + VALUE *argv; +}; + +static VALUE +iterate_method(obj) + VALUE obj; +{ + struct iter_method_arg *arg; + + arg = (struct iter_method_arg *)obj; + return rb_funcall2(arg->obj, arg->mid, arg->argc, arg->argv); +} + +VALUE +rb_block_call(obj, mid, argc, argv, bl_proc, data2) + VALUE obj; + ID mid; + int argc; + VALUE *argv; + VALUE (*bl_proc) (ANYARGS); + VALUE data2; +{ + struct iter_method_arg arg; + + arg.obj = obj; + arg.mid = mid; + arg.argc = argc; + arg.argv = argv; + return rb_iterate(iterate_method, (VALUE)&arg, bl_proc, data2); +} + VALUE rb_each(obj) VALUE obj; @@ -813,9 +848,11 @@ static VALUE enum_each_with_index(obj) VALUE obj; { - VALUE memo = 0; + VALUE memo; + + RETURN_ENUMERATOR(obj, 0, 0); - rb_need_block(); + memo = 0; rb_iterate(rb_each, obj, each_with_index_i, (VALUE)&memo); return obj; } @@ -928,6 +965,7 @@ Init_Enumerable() rb_define_method(rb_mEnumerable,"member?", enum_member, 1); rb_define_method(rb_mEnumerable,"include?", enum_member, 1); rb_define_method(rb_mEnumerable,"each_with_index", enum_each_with_index, 0); + rb_define_method(rb_mEnumerable,"enum_with_index", enum_each_with_index, 0); rb_define_method(rb_mEnumerable, "zip", enum_zip, -1); id_eqq = rb_intern("==="); diff --git a/enumerator.c b/enumerator.c new file mode 100644 index 0000000000..e5bf538f0c --- /dev/null +++ b/enumerator.c @@ -0,0 +1,414 @@ +/************************************************ + + enumerator.c - provides Enumerator class + + $Author$ + + Copyright (C) 2001-2003 Akinori MUSHA + + $Idaemons: /home/cvs/rb/enumerator/enumerator.c,v 1.1.1.1 2001/07/15 10:12:48 knu Exp $ + $RoughId: enumerator.c,v 1.6 2003/07/27 11:03:24 nobu Exp $ + $Id$ + +************************************************/ + +#include "ruby.h" + +/* + * Document-class: Enumerable::Enumerator + * + * A class which provides a method `each' to be used as an Enumerable + * object. + */ +VALUE rb_cEnumerator; +static VALUE sym_each, sym_call; + +static VALUE +proc_call(proc, args) + VALUE proc; + VALUE args; +{ + if (TYPE(args) != T_ARRAY) { + args = rb_ary_new3(1, args); + } + return rb_proc_call(proc, args); +} + +struct enumerator { + VALUE method; + VALUE proc; + VALUE args; + rb_block_call_func *iter; +}; + +static void +enumerator_mark(p) + void *p; +{ + struct enumerator *ptr = p; + rb_gc_mark(ptr->method); + rb_gc_mark(ptr->proc); + rb_gc_mark(ptr->args); +} + +static struct enumerator * +enumerator_ptr(obj) + VALUE obj; +{ + struct enumerator *ptr; + + Data_Get_Struct(obj, struct enumerator, ptr); + if (RDATA(obj)->dmark != enumerator_mark) { + rb_raise(rb_eTypeError, + "wrong argument type %s (expected Enumerable::Enumerator)", + rb_obj_classname(obj)); + } + if (!ptr) { + rb_raise(rb_eArgError, "uninitialized enumerator"); + } + return ptr; +} + +static VALUE +enumerator_iter_i(i, enum_obj, argc, argv) + VALUE i; + VALUE enum_obj; + int argc; + VALUE *argv; +{ + struct enumerator *e = (struct enumerator *)enum_obj; + return rb_yield(proc_call(e->proc, i)); +} + +/* + * call-seq: + * obj.to_enum(method = :each, *args) + * obj.enum_for(method = :each, *args) + * + * Returns Enumerable::Enumerator.new(self, method, *args). + * + * e.g.: + * + * str = "xyz" + * + * enum = str.enum_for(:each_byte) + * a = enum.map {|b| '%02x' % b } #=> ["78", "79", "7a"] + * + * # protects an array from being modified + * a = [1, 2, 3] + * some_method(a.to_enum) + * + */ +static VALUE +obj_to_enum(argc, argv, obj) + int argc; + VALUE *argv; + VALUE obj; +{ + VALUE meth = sym_each; + + if (argc > 0) { + --argc; + meth = *argv++; + } + return rb_enumeratorize(obj, meth, argc, argv); +} + +static VALUE +each_slice_i(val, memo) + VALUE val; + VALUE *memo; +{ + VALUE ary = memo[0]; + VALUE v = Qnil; + long size = (long)memo[1]; + + rb_ary_push(ary, val); + + if (RARRAY_LEN(ary) == size) { + v = rb_yield(ary); + memo[0] = rb_ary_new2(size); + } + + return v; +} + +/* + * call-seq: + * e.each_slice(n) {...} + * + * Iterates the given block for each slice of <n> elements. + * + * e.g.: + * (1..10).each_slice(3) {|a| p a} + * # outputs below + * [1, 2, 3] + * [4, 5, 6] + * [7, 8, 9] + * [10] + * + */ +static VALUE +enum_each_slice(obj, n) + VALUE obj, n; +{ + long size = NUM2LONG(n); + VALUE args[2], ary; + + if (size <= 0) rb_raise(rb_eArgError, "invalid slice size"); + RETURN_ENUMERATOR(obj, 1, &n); + args[0] = rb_ary_new2(size); + args[1] = (VALUE)size; + + rb_block_call(obj, SYM2ID(sym_each), 0, 0, each_slice_i, (VALUE)args); + + ary = args[0]; + if (RARRAY_LEN(ary) > 0) rb_yield(ary); + + return Qnil; +} + +static VALUE +each_cons_i(val, memo) + VALUE val; + VALUE *memo; +{ + VALUE ary = memo[0]; + VALUE v = Qnil; + long size = (long)memo[1]; + + if (RARRAY_LEN(ary) == size) { + rb_ary_shift(ary); + } + rb_ary_push(ary, val); + if (RARRAY_LEN(ary) == size) { + v = rb_yield(rb_ary_dup(ary)); + } + return v; +} + +/* + * call-seq: + * each_cons(n) {...} + * + * Iterates the given block for each array of consecutive <n> + * elements. + * + * e.g.: + * (1..10).each_cons(3) {|a| p a} + * # outputs below + * [1, 2, 3] + * [2, 3, 4] + * [3, 4, 5] + * [4, 5, 6] + * [5, 6, 7] + * [6, 7, 8] + * [7, 8, 9] + * [8, 9, 10] + * + */ +static VALUE +enum_each_cons(obj, n) + VALUE obj, n; +{ + long size = NUM2LONG(n); + VALUE args[2]; + + if (size <= 0) rb_raise(rb_eArgError, "invalid size"); + RETURN_ENUMERATOR(obj, 1, &n); + args[0] = rb_ary_new2(size); + args[1] = (VALUE)size; + + rb_block_call(obj, SYM2ID(sym_each), 0, 0, each_cons_i, (VALUE)args); + + return Qnil; +} + +static VALUE +enumerator_allocate(klass) + VALUE klass; +{ + struct enumerator *ptr; + return Data_Make_Struct(klass, struct enumerator, + enumerator_mark, -1, ptr); +} + +static VALUE +enumerator_each_i(v, enum_obj) + VALUE v; + VALUE enum_obj; +{ + return rb_yield(v); +} + +static VALUE +enumerator_init(enum_obj, obj, meth, argc, argv) + VALUE enum_obj; + VALUE obj; + VALUE meth; + int argc; + VALUE *argv; +{ + struct enumerator *ptr = enumerator_ptr(enum_obj); + + ptr->method = rb_obj_method(obj, meth); + if (rb_block_given_p()) { + ptr->proc = rb_block_proc(); + ptr->iter = enumerator_iter_i; + } + else { + ptr->iter = enumerator_each_i; + } + if (argc) ptr->args = rb_ary_new4(argc, argv); + + return enum_obj; +} + +/* + * call-seq: + * Enumerable::Enumerator.new(obj, method = :each, *args) + * + * Creates a new Enumerable::Enumerator object, which is to be + * used as an Enumerable object using the given object's given + * method with the given arguments. + * + * e.g.: + * str = "xyz" + * + * enum = Enumerable::Enumerator.new(str, :each_byte) + * a = enum.map {|b| '%02x' % b } #=> ["78", "79", "7a"] + * + */ +static VALUE +enumerator_initialize(argc, argv, obj) + int argc; + VALUE *argv; + VALUE obj; +{ + VALUE recv, meth = sym_each; + + if (argc == 0) + rb_raise(rb_eArgError, "wrong number of argument (0 for 1)"); + recv = *argv++; + if (--argc) { + meth = *argv++; + --argc; + } + return enumerator_init(obj, recv, meth, argc, argv); +} + +/* :nodoc: */ +static VALUE +enumerator_init_copy(obj, orig) + VALUE obj; + VALUE orig; +{ + struct enumerator *ptr0, *ptr1; + + ptr0 = enumerator_ptr(orig); + ptr1 = enumerator_ptr(obj); + + ptr1->method = ptr0->method; + ptr1->proc = ptr0->proc; + ptr1->iter = ptr0->iter; + ptr1->args = ptr0->args; + + return obj; +} + +VALUE +rb_enumeratorize(obj, meth, argc, argv) + VALUE obj; + VALUE meth; + int argc; + VALUE *argv; +{ + return enumerator_init(enumerator_allocate(rb_cEnumerator), obj, meth, argc, argv); +} + +/* + * call-seq: + * enum.each {...} + * + * Iterates the given block using the object and the method specified + * in the first place. + * + */ +static VALUE +enumerator_each(obj) + VALUE obj; +{ + struct enumerator *e; + int argc = 0; + VALUE *argv = 0; + + if (!rb_block_given_p()) return obj; + e = enumerator_ptr(obj); + if (e->args) { + argc = RARRAY_LEN(e->args); + argv = RARRAY_PTR(e->args); + } + return rb_block_call(e->method, SYM2ID(sym_call), argc, argv, e->iter, (VALUE)e); +} + +static VALUE +enumerator_with_index_i(val, memo) + VALUE val; + VALUE *memo; +{ + val = rb_yield_values(2, val, INT2FIX(*memo)); + ++*memo; + return val; +} + +/* + * call-seq: + * e.with_index {|(*args), idx| ... } + * + * Iterates the given block for each elements with an index, which + * start from 0. + * + */ +static VALUE +enumerator_with_index(obj) + VALUE obj; +{ + struct enumerator *e = enumerator_ptr(obj); + VALUE memo = 0; + int argc = 0; + VALUE *argv = 0; + + RETURN_ENUMERATOR(obj, 0, 0); + if (e->args) { + argc = RARRAY_LEN(e->args); + argv = RARRAY_PTR(e->args); + } + return rb_block_call(e->method, SYM2ID(sym_call), argc, argv, + enumerator_with_index_i, (VALUE)&memo); +} + +void +Init_Enumerator() +{ + rb_define_method(rb_mKernel, "to_enum", obj_to_enum, -1); + rb_define_method(rb_mKernel, "enum_for", obj_to_enum, -1); + + rb_define_method(rb_mEnumerable, "each_slice", enum_each_slice, 1); + rb_define_method(rb_mEnumerable, "enum_slice", enum_each_slice, 1); + rb_define_method(rb_mEnumerable, "each_cons", enum_each_cons, 1); + rb_define_method(rb_mEnumerable, "enum_cons", enum_each_cons, 1); + + rb_cEnumerator = rb_define_class_under(rb_mEnumerable, "Enumerator", rb_cObject); + rb_include_module(rb_cEnumerator, rb_mEnumerable); + + rb_define_alloc_func(rb_cEnumerator, enumerator_allocate); + rb_define_method(rb_cEnumerator, "initialize", enumerator_initialize, -1); + rb_define_method(rb_cEnumerator, "initialize_copy", enumerator_init_copy, 1); + rb_define_method(rb_cEnumerator, "each", enumerator_each, 0); + rb_define_method(rb_cEnumerator, "with_index", enumerator_with_index, 0); + + sym_each = ID2SYM(rb_intern("each")); + sym_call = ID2SYM(rb_intern("call")); + + rb_provide("enumerator.so"); /* for backward compatibility */ +} diff --git a/ext/enumerator/.cvsignore b/ext/enumerator/.cvsignore deleted file mode 100644 index fc802ff1c2..0000000000 --- a/ext/enumerator/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -Makefile -mkmf.log diff --git a/ext/enumerator/enumerator.c b/ext/enumerator/enumerator.c deleted file mode 100644 index 1c6e1d1ace..0000000000 --- a/ext/enumerator/enumerator.c +++ /dev/null @@ -1,298 +0,0 @@ -/************************************************ - - enumerator.c - provides Enumerator class - - $Author$ - - Copyright (C) 2001-2003 Akinori MUSHA - - $Idaemons: /home/cvs/rb/enumerator/enumerator.c,v 1.1.1.1 2001/07/15 10:12:48 knu Exp $ - $RoughId: enumerator.c,v 1.6 2003/07/27 11:03:24 nobu Exp $ - $Id$ - -************************************************/ - -#include "ruby.h" -#include "node.h" - -/* - * Document-class: Enumerable::Enumerator - * - * A class which provides a method `each' to be used as an Enumerable - * object. - */ -static VALUE rb_cEnumerator; -static ID sym_each, sym_each_with_index, sym_each_slice, sym_each_cons; -static ID id_new, id_enum_obj, id_enum_method, id_enum_args; - -/* - * call-seq: - * obj.to_enum(method = :each, *args) - * obj.enum_for(method = :each, *args) - * - * Returns Enumerable::Enumerator.new(self, method, *args). - * - * e.g.: - * str = "xyz" - * - * enum = str.enum_for(:each_byte) - * a = enum.map {|b| '%02x' % b } #=> ["78", "79", "7a"] - * - * # protects an array from being modified - * a = [1, 2, 3] - * some_method(a.to_enum) - * - */ -static VALUE -obj_to_enum(obj, enum_args) - VALUE obj, enum_args; -{ - rb_ary_unshift(enum_args, obj); - - return rb_apply(rb_cEnumerator, id_new, enum_args); -} - -/* - * call-seq: - * enum_with_index - * - * Returns Enumerable::Enumerator.new(self, :each_with_index). - * - */ -static VALUE -enumerator_enum_with_index(obj) - VALUE obj; -{ - return rb_funcall(rb_cEnumerator, id_new, 2, obj, sym_each_with_index); -} - -static VALUE -each_slice_i(val, memo) - VALUE val; - NODE *memo; -{ - VALUE ary = memo->u1.value; - long size = memo->u3.cnt; - - rb_ary_push(ary, val); - - if (RARRAY(ary)->len == size) { - rb_yield(ary); - memo->u1.value = rb_ary_new2(size); - } - - return Qnil; -} - -/* - * call-seq: - * e.each_slice(n) {...} - * - * Iterates the given block for each slice of <n> elements. - * - * e.g.: - * (1..10).each_slice(3) {|a| p a} - * # outputs below - * [1, 2, 3] - * [4, 5, 6] - * [7, 8, 9] - * [10] - * - */ -static VALUE -enum_each_slice(obj, n) - VALUE obj, n; -{ - long size = NUM2LONG(n); - NODE *memo; - VALUE ary; - - if (size <= 0) rb_raise(rb_eArgError, "invalid slice size"); - - memo = rb_node_newnode(NODE_MEMO, rb_ary_new2(size), 0, size); - - rb_iterate(rb_each, obj, each_slice_i, (VALUE)memo); - - ary = memo->u1.value; - if (RARRAY(ary)->len > 0) rb_yield(ary); - - return Qnil; -} - -/* - * call-seq: - * e.enum_slice(n) - * - * Returns Enumerable::Enumerator.new(self, :each_slice, n). - * - */ -static VALUE -enumerator_enum_slice(obj, n) - VALUE obj, n; -{ - return rb_funcall(rb_cEnumerator, id_new, 3, obj, sym_each_slice, n); -} - -static VALUE -each_cons_i(val, memo) - VALUE val; - NODE *memo; -{ - VALUE ary = memo->u1.value; - long size = memo->u3.cnt; - - if (RARRAY(ary)->len == size) { - rb_ary_shift(ary); - } - rb_ary_push(ary, val); - if (RARRAY(ary)->len == size) { - rb_yield(rb_ary_dup(ary)); - } - return Qnil; -} - -/* - * call-seq: - * each_cons(n) {...} - * - * Iterates the given block for each array of consecutive <n> - * elements. - * - * e.g.: - * (1..10).each_cons(3) {|a| p a} - * # outputs below - * [1, 2, 3] - * [2, 3, 4] - * [3, 4, 5] - * [4, 5, 6] - * [5, 6, 7] - * [6, 7, 8] - * [7, 8, 9] - * [8, 9, 10] - * - */ -static VALUE -enum_each_cons(obj, n) - VALUE obj, n; -{ - long size = NUM2LONG(n); - NODE *memo; - - if (size <= 0) rb_raise(rb_eArgError, "invalid size"); - memo = rb_node_newnode(NODE_MEMO, rb_ary_new2(size), 0, size); - - rb_iterate(rb_each, obj, each_cons_i, (VALUE)memo); - - return Qnil; -} - -/* - * call-seq: - * e.enum_cons(n) - * - * Returns Enumerable::Enumerator.new(self, :each_cons, n). - * - */ -static VALUE -enumerator_enum_cons(obj, n) - VALUE obj, n; -{ - return rb_funcall(rb_cEnumerator, id_new, 3, obj, sym_each_cons, n); -} - -/* - * call-seq: - * Enumerable::Enumerator.new(obj, method = :each, *args) - * - * Creates a new Enumerable::Enumerator object, which is to be - * used as an Enumerable object using the given object's given - * method with the given arguments. - * - * e.g.: - * str = "xyz" - * - * enum = Enumerable::Enumerator.new(str, :each_byte) - * a = enum.map {|b| '%02x' % b } #=> ["78", "79", "7a"] - * - */ -static VALUE -enumerator_initialize(argc, argv, obj) - int argc; - VALUE *argv; - VALUE obj; -{ - VALUE enum_obj, enum_method, enum_args; - - rb_scan_args(argc, argv, "11*", &enum_obj, &enum_method, &enum_args); - - if (enum_method == Qnil) - enum_method = sym_each; - - rb_ivar_set(obj, id_enum_obj, enum_obj); - rb_ivar_set(obj, id_enum_method, enum_method); - rb_ivar_set(obj, id_enum_args, enum_args); - - return Qnil; -} - -static VALUE -enumerator_iter(memo) - NODE *memo; -{ - return rb_apply(memo->u1.value, memo->u2.id, memo->u3.value); -} - -/* - * call-seq: - * enum.each {...} - * - * Iterates the given block using the object and the method specified - * in the first place. - * - */ -static VALUE -enumerator_each(obj) - VALUE obj; -{ - VALUE val; - - obj = (VALUE)rb_node_newnode(NODE_MEMO, - rb_ivar_get(obj, id_enum_obj), - rb_to_id(rb_ivar_get(obj, id_enum_method)), - rb_ivar_get(obj, id_enum_args)); - val = rb_iterate((VALUE (*)_((VALUE)))enumerator_iter, obj, rb_yield, 0); - return val; -} - -void -Init_enumerator() -{ - VALUE rb_mEnumerable; - - rb_define_method(rb_mKernel, "to_enum", obj_to_enum, -2); - rb_define_method(rb_mKernel, "enum_for", obj_to_enum, -2); - - rb_mEnumerable = rb_path2class("Enumerable"); - - rb_define_method(rb_mEnumerable, "enum_with_index", enumerator_enum_with_index, 0); - rb_define_method(rb_mEnumerable, "each_slice", enum_each_slice, 1); - rb_define_method(rb_mEnumerable, "enum_slice", enumerator_enum_slice, 1); - rb_define_method(rb_mEnumerable, "each_cons", enum_each_cons, 1); - rb_define_method(rb_mEnumerable, "enum_cons", enumerator_enum_cons, 1); - - rb_cEnumerator = rb_define_class_under(rb_mEnumerable, "Enumerator", rb_cObject); - rb_include_module(rb_cEnumerator, rb_mEnumerable); - - rb_define_method(rb_cEnumerator, "initialize", enumerator_initialize, -1); - rb_define_method(rb_cEnumerator, "each", enumerator_each, 0); - - sym_each = ID2SYM(rb_intern("each")); - sym_each_with_index = ID2SYM(rb_intern("each_with_index")); - sym_each_slice = ID2SYM(rb_intern("each_slice")); - sym_each_cons = ID2SYM(rb_intern("each_cons")); - - id_new = rb_intern("new"); - id_enum_obj = rb_intern("enum_obj"); - id_enum_method = rb_intern("enum_method"); - id_enum_args = rb_intern("enum_args"); -} diff --git a/ext/enumerator/enumerator.txt b/ext/enumerator/enumerator.txt deleted file mode 100644 index 64c7d50226..0000000000 --- a/ext/enumerator/enumerator.txt +++ /dev/null @@ -1,102 +0,0 @@ -.\" enumerator.txt - -*- Indented-Text -*- -$Idaemons: /home/cvs/rb/enumerator/enumerator.txt,v 1.2 2001/07/15 10:19:24 knu Exp $ -$RoughId: enumerator.txt,v 1.5 2003/02/20 12:24:51 knu Exp $ -$Id$ - -** Enumerable::Enumerator(Class) - -A class which provides a method `each' to be used as an Enumerable -object. - -Superclass: Object - -Mix-ins: Enumerable - -require 'enumerator' - -Class Methods: - - new(obj, method = :each, *args) - - Creates a new Enumerable::Enumerator object, which is to be - used as an Enumerable object using the given object's given - method with the given arguments. - - e.g.: - str = "xyz" - - enum = Enumerable::Enumerator.new(str, :each_byte) - a = enum.map {|b| '%02x' % b } #=> ["78", "79", "7a"] - -Methods: - - each {...} - - Iterates the given block using the object and the method - specified in the first place. - - -Requiring this module also adds some methods to the Object class: - - to_enum(method = :each, *args) - enum_for(method = :each, *args) - - Returns Enumerable::Enumerator.new(self, method, *args). - - e.g.: - str = "xyz" - - enum = str.enum_for(:each_byte) - a = enum.map {|b| '%02x' % b } #=> ["78", "79", "7a"] - - # protects an array from being modified - a = [1, 2, 3] - some_method(a.to_enum) - -And the Enumerable module. - - each_slice(n) {...} - - Iterates the given block for each slice of <n> elements. - - e.g.: - (1..10).each_slice(3) {|a| p a} - # outputs below - [1, 2, 3] - [4, 5, 6] - [7, 8, 9] - [10] - - enum_slice(n) - - Returns Enumerable::Enumerator.new(self, :each_slice, n). - - each_cons(n) {...} - - Iterates the given block for each array of consecutive <n> - elements. - - e.g.: - (1..10).each_cons(3) {|a| p a} - # outputs below - [1, 2, 3] - [2, 3, 4] - [3, 4, 5] - [4, 5, 6] - [5, 6, 7] - [6, 7, 8] - [7, 8, 9] - [8, 9, 10] - - enum_cons(n) - - Returns Enumerable::Enumerator.new(self, :each_cons, n). - - enum_with_index - - Returns Enumerable::Enumerator.new(self, :each_with_index). - -------------------------------------------------------- -Local variables: -fill-column: 70 -end: diff --git a/ext/enumerator/extconf.rb b/ext/enumerator/extconf.rb deleted file mode 100644 index 94e2ee38b2..0000000000 --- a/ext/enumerator/extconf.rb +++ /dev/null @@ -1,2 +0,0 @@ -require 'mkmf' -create_makefile('enumerator') @@ -18,6 +18,7 @@ void Init_Binding _((void)); void Init_Comparable _((void)); void Init_Dir _((void)); void Init_Enumerable _((void)); +void Init_Enumerator _((void)); void Init_Exception _((void)); void Init_syserr _((void)); void Init_eval _((void)); @@ -79,6 +80,7 @@ rb_call_inits() Init_Binding(); Init_Math(); Init_GC(); + Init_Enumerator(); Init_marshal(); Init_version(); } @@ -128,6 +128,14 @@ VALUE rb_singleton_class _((VALUE)); int rb_cmpint _((VALUE, VALUE, VALUE)); NORETURN(void rb_cmperr _((VALUE, VALUE))); /* enum.c */ +VALUE rb_block_call _((VALUE, ID, int, VALUE*, VALUE (*)(ANYARGS), VALUE)); +/* enumerator.c */ +VALUE rb_enumeratorize _((VALUE, VALUE, int, VALUE *)); +#define RETURN_ENUMERATOR(obj, argc, argv) do { \ + if (!rb_block_given_p()) \ + return rb_enumeratorize(obj, ID2SYM(rb_frame_last_func()), \ + argc, argv); \ + } while (0) /* error.c */ RUBY_EXTERN int ruby_nerrs; VALUE rb_exc_new _((VALUE, const char*, long)); @@ -574,6 +574,8 @@ void rb_warning __((const char*, ...)); /* reports if `-w' specified */ void rb_sys_warning __((const char*, ...)); /* reports if `-w' specified */ void rb_warn __((const char*, ...)); /* reports always */ +typedef VALUE rb_block_call_func _((VALUE, VALUE, int, VALUE*)); + VALUE rb_each _((VALUE)); VALUE rb_yield _((VALUE)); VALUE rb_yield_values __((int n, ...)); @@ -622,6 +624,7 @@ RUBY_EXTERN VALUE rb_cClass; RUBY_EXTERN VALUE rb_cCont; RUBY_EXTERN VALUE rb_cDir; RUBY_EXTERN VALUE rb_cData; +RUBY_EXTERN VALUE rb_cEnumerator; RUBY_EXTERN VALUE rb_cFalseClass; RUBY_EXTERN VALUE rb_cFile; RUBY_EXTERN VALUE rb_cFixnum; |