# Enumerable object from a block

**URL:** <https://www.ruby-forum.com/t/enumerable-object-from-a-block/146478>\
**Category:** Development\
**Created:** [August 21, 2008, 3:23pm UTC](https://www.ruby-forum.com/t/enumerable-object-from-a-block/146478 "2008-08-21T15:23:40Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Akinori\_MUSHA](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/b782af/32.png) [@Akinori\_MUSHA](https://www.ruby-forum.com/u/Akinori_MUSHA)\
**Post date:** [August 21, 2008, 3:23pm UTC](https://www.ruby-forum.com/t/enumerable-object-from-a-block/146478/1 "2008-08-21T15:23:40Z")

</div>

ã€€ãƒ–ãƒ­ãƒƒã‚¯ã§ç°¡å˜ã« Enumerable ãªã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆã‚’ä½œã‚Œã‚‹æ©Ÿèƒ½ã‚’è¿½åŠ  
ã—ã‚ˆã†ã¨æ€ã„ã¾ã™ãŒã€ã©ã†ã§ã—ã‚‡ã†ã‹ã€‚

ã€€ã„ã¡ã„ã¡ã‚¯ãƒ©ã‚¹ã‚’ä½œã£ãŸã‚Šã€ extend(Enumerable) ã—ã¦ç‰¹ç•°ãƒ¡ã‚½ãƒƒãƒ‰  
each ã‚’å®šç¾©ã—ãŸã‚Šã—ãªãã¦æ¸ˆã¿ã¾ã™ã€‚

```
# ãƒ•ã‚£ãƒœãƒŠãƒƒãƒæ•°åˆ—(n>=1)
fib = Enumerator.new { |y|
  a = b = 1
  loop {
    y << a
    a, b = b, a + b
  }
}

p fib.take(10) #=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

```

ã€€å…ƒã¯ Ruby 1.8 ã® generator.rb ã«ã¤ã„ã¦ã„ãŸãŠã¾ã‘æ©Ÿèƒ½ã§ã™ãŒã€  
æ‰‹è»½ã«ç„¡é™ãƒªã‚¹ãƒˆã‚„æŸ”è»Ÿãªç¹°ã‚Šè¿”ã—ã‚’å®šç¾©ã§ãã‚‹ã®ã§ä¾¿åˆ©ã§ã™ã€‚

–  
Akinori MUSHA / [http://akinori.org/](http://akinori.org/)

# Index: enumerator.c

— enumerator.c (revision 18754)  
+++ enumerator.c (working copy)  
@@ -35,6 +35,22 @@ struct enumerator {  
VALUE no\_next;  
};

+static VALUE rb\_cGenerator, rb\_cYielder;  
+  
+struct generator {

- VALUE proc;  
+};
- 

+struct yielder {

- VALUE proc;  
+};
- 

+static VALUE generator\_allocate(VALUE klass);  
+static VALUE generator\_init(VALUE obj, VALUE proc);  
+  
+/\*

- 
  - Enumerator

- \*/  
static void  
enumerator\_mark(void _p)  
{  
@@ -242,25 +258,53 @@ enumerator\_init(VALUE enum\_obj, VALUE ob  
/_
  - call-seq:
  - Enumerator.new(obj, method = :each, \*args)

- 
  - Enumerator.new { |y| … }
  - 
  - Creates a new Enumerator object, which is to be used as an

- 
  - Enumerable object using the given object’s given method with the

- 
  - given arguments.

- 
  - Enumerable object iterating in a given way.
  - 

- 
  - Use of this method is discouraged. Use Kernel#enum\_for() instead.

- 
  - In the first form, a generated Enumerator iterates over the given

- 
  - object using the given method with the given arguments passed.

- 
  - Use of this form is discouraged. Use Kernel#enum\_for(), alias

- 
  - to\_enum, instead.

- 
  - 

- 
  - e = Enumerator.new(ObjectSpace, :each\_object)

- 
  - 

```
   #-> ObjectSpace.enum_for(:each_object)

```

- 
  - 

- 
  - e.select { |obj| obj.is\_a?(Class) } #=\> array of all classes

- 
  - 

- 
  - In the second form, iteration is defined by the given block, in

- 
  - which a “yielder” object given as block parameter can be used to

- 
  - yield a value by calling the +yield+ method, alias +\<\<+.

- 
  - 

- 
  - fib = Enumerator.new { |y|

- 
  - 

```
 a = b = 1

```

- 
  - 

```
 loop {

```

- 
  - 

```
   y << a

```

- 
  - 

```
   a, b = b, a + b

```

- 
  - 

```
 }

```

- 
  - }

- 
  - 

- 
  - p fib.take(10) #=\> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]  
\*/  
static VALUE  
enumerator\_initialize(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;

- if (argc == 0) {
- if (!rb\_block\_given\_p())
- 

```
 rb_raise(rb_eArgError, "wrong number of argument (0 for 1+)");

```

- 
- recv = generator\_init(generator\_allocate(rb\_cGenerator),  
rb\_block\_proc());
- } else {
- recv = \*argv++;
- if (–argc) {
- 

```
 meth = *argv++;

```

- 

```
 --argc;

```

- }  
}
- return enumerator\_init(obj, recv, meth, argc, argv);  
}

@@ -471,6 +515,217 @@ enumerator\_rewind(VALUE obj)  
return obj;  
}

+/\*

- 
  - Yielder

- \*/  
+static void  
+yielder\_mark(void \*p)  
+{
- struct yielder \*ptr = p;
- rb\_gc\_mark(ptr-\>proc);  
+}
- 

+static struct yielder \*  
+yielder\_ptr(VALUE obj)  
+{

- struct yielder \*ptr;
- 
- Data\_Get\_Struct(obj, struct yielder, ptr);
- if (RDATA(obj)-\>dmark != yielder\_mark) {
- rb\_raise(rb\_eTypeError,
- 

```
"wrong argument type %s (expected %s)",

```

- 

```
rb_obj_classname(obj), rb_class2name(rb_cYielder));

```

- }
- if (!ptr || ptr-\>proc == Qundef) {
- rb\_raise(rb\_eArgError, “uninitialized yielder”);
- }
- return ptr;  
+}
- 

+/\* :nodoc: \*/  
+static VALUE  
+yielder\_allocate(VALUE klass)  
+{

- struct yielder \*ptr;
- VALUE obj;
- 
- obj = Data\_Make\_Struct(klass, struct yielder, yielder\_mark, -1,  
ptr);
- ptr-\>proc = Qundef;
- 
- return obj;  
+}
- 

+static VALUE  
+yielder\_init(VALUE obj, VALUE proc)  
+{

- struct yielder \*ptr;
- 
- Data\_Get\_Struct(obj, struct yielder, ptr);
- 
- if (!ptr) {
- rb\_raise(rb\_eArgError, “unallocated yielder”);
- }
- 
- ptr-\>proc = proc;
- 
- return obj;  
+}
- 

+/\* :nodoc: \*/  
+static VALUE  
+yielder\_initialize(VALUE obj)  
+{

- rb\_need\_block();
- 
- return yielder\_init(obj, rb\_block\_proc());  
+}
- 

+/\* :nodoc: \*/  
+static VALUE  
+yielder\_yield(VALUE obj, VALUE args)  
+{

- struct yielder \*ptr = yielder\_ptr(obj);
- 
- rb\_proc\_call(ptr-\>proc, args);
- 
- return obj;  
+}
- 

+static VALUE  
+yielder\_new\_i(VALUE dummy)  
+{

- return yielder\_init(yielder\_allocate(rb\_cYielder),  
rb\_block\_proc());  
+}
- 

+static VALUE  
+yielder\_yield\_i(VALUE obj, VALUE memo, int argc, VALUE \*argv)  
+{

- return rb\_yield(obj);  
+}
- 

+static VALUE  
+yielder\_new(void)  
+{

- return rb\_iterate(yielder\_new\_i, (VALUE)0, yielder\_yield\_i,  
(VALUE)0);  
+}
- 

+/\*

- 
  - Generator

- \*/  
+static void  
+generator\_mark(void \*p)  
+{
- struct generator \*ptr = p;
- rb\_gc\_mark(ptr-\>proc);  
+}
- 

+static struct generator \*  
+generator\_ptr(VALUE obj)  
+{

- struct generator \*ptr;
- 
- Data\_Get\_Struct(obj, struct generator, ptr);
- if (RDATA(obj)-\>dmark != generator\_mark) {
- rb\_raise(rb\_eTypeError,
- 

```
"wrong argument type %s (expected %s)",

```

- 

```
rb_obj_classname(obj), rb_class2name(rb_cGenerator));

```

- }
- if (!ptr || ptr-\>proc == Qundef) {
- rb\_raise(rb\_eArgError, “uninitialized generator”);
- }
- return ptr;  
+}
- 

+/\* :nodoc: \*/  
+static VALUE  
+generator\_allocate(VALUE klass)  
+{

- struct generator \*ptr;
- VALUE obj;
- 
- obj = Data\_Make\_Struct(klass, struct generator, generator\_mark, -1,  
ptr);
- ptr-\>proc = Qundef;
- 
- return obj;  
+}
- 

+static VALUE  
+generator\_init(VALUE obj, VALUE proc)  
+{

- struct generator \*ptr;
- 
- Data\_Get\_Struct(obj, struct generator, ptr);
- 
- if (!ptr) {
- rb\_raise(rb\_eArgError, “unallocated generator”);
- }
- 
- ptr-\>proc = proc;
- 
- return obj;  
+}
- 

+VALUE rb\_obj\_is\_proc(VALUE proc);  
+  
+/\* :nodoc: \*/  
+static VALUE  
+generator\_initialize(int argc, VALUE \*argv, VALUE obj)  
+{

- VALUE proc;
- 
- if (argc == 0) {
- rb\_need\_block();
- 
- proc = rb\_block\_proc();
- } else {
- rb\_scan\_args(argc, argv, “1”, &proc);
- 
- if (!rb\_obj\_is\_proc(proc))
- 

```
 rb_raise(rb_eTypeError,

```

- 

```
    "wrong argument type %s (expected Proc)",

```

- 

```
    rb_obj_classname(proc));

```

- 
- if (rb\_block\_given\_p()) {
- 

```
 rb_warn("given block not used");

```

- }
- }
- 
- return generator\_init(obj, proc);  
+}
- 

+/\* :nodoc: \*/  
+static VALUE  
+generator\_init\_copy(VALUE obj, VALUE orig)  
+{

- struct generator \*ptr0, \*ptr1;
- 
- ptr0 = generator\_ptr(orig);
- 
- Data\_Get\_Struct(obj, struct generator, ptr1);
- 
- if (!ptr1) {
- rb\_raise(rb\_eArgError, “unallocated generator”);
- }
- 
- ptr1-\>proc = ptr0-\>proc;
- 
- return obj;  
+}
- 

+/\* :nodoc: \*/  
+static VALUE  
+generator\_each(VALUE obj)  
+{

- struct generator \*ptr = generator\_ptr(obj);
- VALUE yielder;
- 
- yielder = yielder\_new();
- 
- rb\_proc\_call(ptr-\>proc, rb\_ary\_new3(1, yielder));
- 
- return obj;  
+}
- 

void  
Init\_Enumerator(void)  
{  
@@ -497,9 +752,24 @@ Init\_Enumerator(void)  
rb\_define\_method(rb\_cEnumerator, “next”, enumerator\_next, 0);  
rb\_define\_method(rb\_cEnumerator, “rewind”, enumerator\_rewind, 0);

- rb\_eStopIteration = rb\_define\_class(“StopIteration”,  
rb\_eIndexError);

- rb\_eStopIteration = rb\_define\_class(“StopIteration”,  
rb\_eIndexError);

- sym\_each = ID2SYM(rb\_intern(“each”));

- /\* Generator \*/

- rb\_cGenerator = rb\_define\_class\_under(rb\_cEnumerator, “Generator”,  
rb\_cObject);

- rb\_include\_module(rb\_cGenerator, rb\_mEnumerable);

- rb\_define\_alloc\_func(rb\_cGenerator, generator\_allocate);

- rb\_define\_method(rb\_cGenerator, “initialize”, generator\_initialize,  
-1);

- rb\_define\_method(rb\_cGenerator, “initialize\_copy”,  
generator\_init\_copy, 1);

- rb\_define\_method(rb\_cGenerator, “each”, generator\_each, 0);

- 
- /\* Yielder \*/

- rb\_cYielder = rb\_define\_class\_under(rb\_cEnumerator, “Yielder”,  
rb\_cObject);

- rb\_define\_alloc\_func(rb\_cYielder, yielder\_allocate);

- rb\_define\_method(rb\_cYielder, “initialize”, yielder\_initialize, 0);

- rb\_define\_method(rb\_cYielder, “yield”, yielder\_yield, -2);

- rb\_define\_method(rb\_cYielder, “\<\<”, yielder\_yield, -2);

- 
- sym\_each = ID2SYM(rb\_intern(“each”));

---

<div class="post-metadata">

**Author:** ![Akinori\_MUSHA](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/b782af/32.png) [@Akinori\_MUSHA](https://www.ruby-forum.com/u/Akinori_MUSHA)\
**Post date:** [August 22, 2008, 1:02am UTC](https://www.ruby-forum.com/t/enumerable-object-from-a-block/146478/2 "2008-08-22T01:02:22Z")

</div>

e$B$^$D$b$He(B e$B$f$-$R$m$G$9e(B

In message “Re: [ruby-dev:35903] Enumerable object from a block”  
on Thu, 21 Aug 2008 22:19:15 +0900, “Akinori MUSHA”  
[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) writes:

|e$B!!%V%m%C%/$G4JC1$Ke(B Enumerable e$B$J%_%V%8%'%/%H$r:n$l$k5!G=$rDI2Ce(B  
|e$B$7$h$&$H;W$$$^$9$,!"$I$&$G$7$g$&$+!#e(B  
|  
|e$B!!$$$A$$$A%/%i%9$r:n$C$?$j!"e(B extend(Enumerable) e$B$7$FFC0[%a%=%C%Ie(B  
|each e$B$rDj5A$7$?$j$7$J$/$F:Q$\_$^$9!#e(B  
|  
| # e$B%U%#%%J%C%A?tNse(B(n\>=1)  
| fib = Enumerator.new { |y|  
| a = b = 1  
| loop {  
| y \<\< a  
| a, b = b, a + b  
| }  
| }  
|  
| p fib.take(10) #=\> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]  
|  
|  
|e$B!!85$Oe(B Ruby 1.8 e$B$Ne(B generator.rb e$B$K$D$$$F$$$?$_$^$15!G=$G$9$,!"e(B  
|e$B\<j7Z$KL58B%j%9%H$d=@Fp$J7+$jJV$7$rDj5A$G$-$k$N$GJXMx$G$9!#e(B

e$B$^$“!”$$$$$s$8$c$J$$$G$7$g$&$+e(B(1.9e$B$J$ie(B)e$B!#$“$H!”%V%m%C%/0z?te(B  
e$B$+$i$NN`?d$G$$$($P!"e(Byieldere$B$Oe(Bcalle$B%a%=%C%I$r;}$C$F$$$?$[$&$,e(B  
e$B$h$$$+$b$7$l$^$;$s!#e(B

---

<div class="post-metadata">

**Author:** ![Akinori\_MUSHA](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/b782af/32.png) [@Akinori\_MUSHA](https://www.ruby-forum.com/u/Akinori_MUSHA)\
**Post date:** [August 26, 2008, 12:56pm UTC](https://www.ruby-forum.com/t/enumerable-object-from-a-block/146478/3 "2008-08-26T12:56:17Z")

</div>

At Fri, 22 Aug 2008 07:54:53 +0900,  
matz wrote:

> | fib = Enumerator.new { |y|  
> |ã€€å…ƒã¯ Ruby 1.8 ã® generator.rb ã«ã¤ã„ã¦ã„ãŸãŠã¾ã‘æ©Ÿèƒ½ã§ã™ãŒã€  
> |æ‰‹è»½ã«ç„¡é™ãƒªã‚¹ãƒˆã‚„æŸ”è»Ÿãªç¹°ã‚Šè¿”ã—ã‚’å®šç¾©ã§ãã‚‹ã®ã§ä¾¿åˆ©ã§ã™ã€‚
> 
> ã¾ã‚ã€ã„ã„ã‚“ã˜ã‚ƒãªã„ã§ã—ã‚‡ã†ã‹(1.9ãªã‚‰)ã€‚ã‚ã¨ã€ãƒ–ãƒ­ãƒƒã‚¯å¼•æ•°

ã€€trunkã«å®Ÿé¨“çš„ã«å…¥ã‚Œã¦ã¿ã¾ã—ãŸã€‚

> ã‹ã‚‰ã®é¡žæŽ¨ã§ã„ãˆã°ã€yielderã¯callãƒ¡ã‚½ãƒƒãƒ‰ã‚’æŒã£ã¦ã„ãŸã»ã†ãŒ  
> ã‚ˆã„ã‹ã‚‚ã—ã‚Œã¾ã›ã‚“ã€‚

ã€€\<\< ã¨åŒç­‰ã® yield ãƒ¡ã‚½ãƒƒãƒ‰ã‚‚ã‚ã‚Šã¾ã™ã€‚ã—ã‹ã—ã€  
yielder.yield(value) ã®é‡è¤‡æ„ŸãŒæ°—æŒã¡æ‚ªã„ã“ã¨ã¯å¦ã‚ã¾ã›ã‚“ã€‚

ã€€ãã£ã¨ Yielder ã¨ã„ã†åå‰ãŒå®‰ç›´ã§è‰¯ããªã„ã‚“ã§ã—ã‚‡ã†ã­ã€‚
