In Files

  • enumerator.c

Enumerator

A class which provides a method `each' to be used as an Enumerable object.

Public Class Methods

new(obj, method = :each, *args) click to toggle source
new { |y| ... }

Creates a new Enumerator object, which is to be used as an Enumerable object iterating in a given way.

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) {
        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);
}
            

Public Instance Methods

each {...} click to toggle source

Iterates the given block using the object and the method specified in the first place. If no block is given, returns self.

 
               static VALUE
enumerator_each(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->obj, e->meth, argc, argv,
                         enumerator_each_i, (VALUE)e);
}
            
with_index {|(*args), idx| ... } click to toggle source
with_index

Iterates the given block for each element with an index, which start from 0. If no block is given, returns an enumerator.

 
               static VALUE
enumerator_with_index(VALUE obj)
{
    struct enumerator *e;
    VALUE memo = 0;
    int argc = 0;
    VALUE *argv = 0;

    RETURN_ENUMERATOR(obj, 0, 0);
    e = enumerator_ptr(obj);
    if (e->args) {
        argc = RARRAY_LEN(e->args);
        argv = RARRAY_PTR(e->args);
    }
    return rb_block_call(e->obj, e->meth, argc, argv,
                         enumerator_with_index_i, (VALUE)&memo);
}
            
with_object(obj) {|(*args), memo_obj| ... } click to toggle source
with_object(obj)

Iterates the given block for each element with an arbitrary object given, and returns the initially given object.

If no block is given, returns an enumerator.

 
               static VALUE
enumerator_with_object(VALUE obj, VALUE memo)
{
    struct enumerator *e;
    int argc = 0;
    VALUE *argv = 0;

    RETURN_ENUMERATOR(obj, 1, &memo);
    e = enumerator_ptr(obj);
    if (e->args) {
        argc = RARRAY_LEN(e->args);
        argv = RARRAY_PTR(e->args);
    }
    rb_block_call(e->obj, e->meth, argc, argv,
                  enumerator_with_object_i, memo);

    return memo;
}
            
next => object click to toggle source

Returns the next object in the enumerator, and move the internal position forward. When the position reached at the end, internal position is rewound then StopIteration is raised.

Note that enumeration sequence by next method does not affect other non-external enumeration methods, unless underlying iteration methods itself has side-effect, e.g. IO#each_line.

 
               static VALUE
enumerator_next(VALUE obj)
{
    struct enumerator *e = enumerator_ptr(obj);
    VALUE curr, v;
    curr = rb_fiber_current();

    if (!e->fib || !rb_fiber_alive_p(e->fib)) {
        next_init(obj, e);
    }

    v = rb_fiber_resume(e->fib, 1, &curr);
    if (e->no_next) {
        e->fib = 0;
        e->dst = Qnil;
        e->no_next = Qfalse;
        rb_raise(rb_eStopIteration, "iteration reached at end");
    }
    return v;
}
            
rewind => e click to toggle source

Rewinds the enumeration sequence by the next method.

If the enclosed object responds to a “rewind” method, it is called.

 
               static VALUE
enumerator_rewind(VALUE obj)
{
    struct enumerator *e = enumerator_ptr(obj);

    if (rb_respond_to(e->obj, id_rewind))
        rb_funcall(e->obj, id_rewind, 0);

    e->fib = 0;
    e->dst = Qnil;
    e->no_next = Qfalse;
    return obj;
}
            
with_index {|(*args), idx| ... } click to toggle source
with_index

Iterates the given block for each element with an index, which start from 0. If no block is given, returns an enumerator.

 
               static VALUE
enumerator_with_index(VALUE obj)
{
    struct enumerator *e;
    VALUE memo = 0;
    int argc = 0;
    VALUE *argv = 0;

    RETURN_ENUMERATOR(obj, 0, 0);
    e = enumerator_ptr(obj);
    if (e->args) {
        argc = RARRAY_LEN(e->args);
        argv = RARRAY_PTR(e->args);
    }
    return rb_block_call(e->obj, e->meth, argc, argv,
                         enumerator_with_index_i, (VALUE)&memo);
}
            
with_object(obj) {|(*args), memo_obj| ... } click to toggle source
with_object(obj)

Iterates the given block for each element with an arbitrary object given, and returns the initially given object.

If no block is given, returns an enumerator.

 
               static VALUE
enumerator_with_object(VALUE obj, VALUE memo)
{
    struct enumerator *e;
    int argc = 0;
    VALUE *argv = 0;

    RETURN_ENUMERATOR(obj, 1, &memo);
    e = enumerator_ptr(obj);
    if (e->args) {
        argc = RARRAY_LEN(e->args);
        argv = RARRAY_PTR(e->args);
    }
    rb_block_call(e->obj, e->meth, argc, argv,
                  enumerator_with_object_i, memo);

    return memo;
}