class Enumerator

Class Enumerator supports:

An Enumerator may be created by the following methods:

In addition, certain Ruby methods return Enumerator objects: a Ruby iterator method that accepts a block may return an Enumerator if no block is given. There are many such methods, for example, in classesArray andHash. (In the documentation for those classes, search fornew_enumerator.)

Internal Iteration

In _internal iteration_, an iterator method drives the iteration and the caller’s block handles the processing; this example uses methodeach_with_index:

words = %w[foo bar baz] # => ["foo", "bar", "baz"]enumerator = words.each # => #<Enumerator: ...>enumerator.each_with_index {|word, i| puts "#{i}: #{word}" }0: foo1: bar2: baz

Iterator methods in class Enumerator include:

Class Enumerator includes moduleEnumerable, which provides many more iterator methods.

External Iteration

In _external iteration_, the user’s program both drives the iteration and handles the processing in stream-like fashion; this example uses methodnext:

words =%w[foo bar baz]enumerator =words.eachenumerator.next# => "foo"enumerator.next# => "bar"enumerator.next# => "baz"enumerator.next# Raises StopIteration: iteration reached an end

External iteration methods in class Enumerator include:

Each of these methods raisesFrozenError if called from a frozen Enumerator.

External Iteration and Fiber

External iteration that usesFiber differssignificantly from internal iteration:

Concretely:

Thread.current[:fiber_local] =1Fiber[:storage_var] =1e =Enumerator.newdo|y|pThread.current[:fiber_local]# for external iteration: nil, for internal iteration: 1pFiber[:storage_var]# => 1, inheritedFiber[:storage_var]+=1y<<42endpe.next# => 42pFiber[:storage_var]# => 1 (it ran in a different Fiber)e.each {p_1 }pFiber[:storage_var]# => 2 (it ran in the same Fiber/"stack" as the current Fiber)

Converting External Iteration to Internal Iteration

You can use an external iterator to implement an internal iterator as follows:

defext_each(e)whiletruebeginvs =e.next_valuesrescueStopIterationreturn$!.resultendy =yield(*vs)e.feedyendendo =Object.newdefo.eachputsyieldputsyield(1)putsyield(1,2)3end# use o.each as an internal iterator directly.putso.each {|*x|putsx; [:b,*x] }# => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3# convert o.each to an external iterator for# implementing an internal iterator.putsext_each(o.to_enum) {|*x|putsx; [:b,*x] }# => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3

Public Class Methods

Source
static VALUEenumerator_initialize(int argc, VALUE *argv, VALUE obj){    VALUE iter = rb_block_proc();    VALUE recv = generator_init(generator_allocate(rb_cGenerator), iter);    VALUE arg0 = rb_check_arity(argc, 0, 1) ? argv[0] : Qnil;    VALUE size = convert_to_feasible_size_value(arg0);    return enumerator_init(obj, recv, sym_each, 0, 0, 0, size, false);}

Returns a new Enumerator object that can be used for iteration.

The given block defines the iteration; it is called with a “yielder” object that can yield an object via a call to methodyielder.yield:

fib =Enumerator.newdo|yielder|n =next_n =1whiletruedoyielder.yield(n)n,next_n =next_n,n+next_nendendfib.take(10)# => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

Parametersize specifies how the size is to be calculated (seesize); it can either be a value or a callable object:

Enumerator.new{}.size# => nilEnumerator.new(42){}.size# => 42Enumerator.new(-> {42}){}.size# => 42
Source
static VALUEenumerator_s_produce(int argc, VALUE *argv, VALUE klass){    VALUE init, producer, opts, size;    ID keyword_ids[1];    if (!rb_block_given_p()) rb_raise(rb_eArgError, "no block given");    keyword_ids[0] = rb_intern("size");    rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, argc, argv, "01:", &init, &opts);    rb_get_kwargs(opts, keyword_ids, 0, 1, &size);    size = UNDEF_P(size) ? DBL2NUM(HUGE_VAL) : convert_to_feasible_size_value(size);    if (argc == 0 || (argc == 1 && !NIL_P(opts))) {        init = Qundef;    }    producer = producer_init(producer_allocate(rb_cEnumProducer), init, rb_block_proc(), size);    return rb_enumeratorize_with_size_kw(producer, sym_each, 0, 0, producer_size, RB_NO_KEYWORDS);}

Creates an infinite enumerator from any block, just called over and over. The result of the previous iteration is passed to the next one. Ifinitial is provided, it is passed to the first iteration, and becomes the first element of the enumerator; if it is not provided, the first iteration receivesnil, and its result becomes the first element of the iterator.

RaisingStopIteration from the block stops an iteration.

Enumerator.produce(1,&:succ)# => enumerator of 1, 2, 3, 4, ....Enumerator.produce {rand(10) }# => infinite random number sequenceancestors =Enumerator.produce(node) {|prev|node =prev.parentorraiseStopIteration }enclosing_section =ancestors.find {|n|n.type==:section }

Using::produce together withEnumerable methods likeEnumerable#detect,Enumerable#slice_after,Enumerable#take_while can provide Enumerator-based alternatives forwhile anduntil cycles:

# Find next Tuesdayrequire"date"Enumerator.produce(Date.today,&:succ).detect(&:tuesday?)# Simple lexer:require"strscan"scanner =StringScanner.new("7+38/6")PATTERN =%r{\d+|[-/+*]}Enumerator.produce {scanner.scan(PATTERN) }.slice_after {scanner.eos? }.first# => ["7", "+", "38", "/", "6"]

The optionalsize keyword argument specifies the size of the enumerator, which can be retrieved byEnumerator#size. It can be an integer,Float::INFINITY, a callable object (such as a lambda), ornil to indicate unknown size. When not specified, the size defaults toFloat::INFINITY.

# Infinite enumeratorenum =Enumerator.produce(1,size:Float::INFINITY,&:succ)enum.size# => Float::INFINITY# Finite enumerator with known/computable sizeabs_dir =File.expand_path("./baz")# => "/foo/bar/baz"traverser =Enumerator.produce(abs_dir,size:-> {abs_dir.count("/")+1 }) {raiseStopIterationifit=="/"File.dirname(it)}traverser.size# => 4# Finite enumerator with unknown sizecalendar =Enumerator.produce(Date.today,size:nil) {it.monday??raise(StopIteration):it+1}calendar.size# => nil
Source
static VALUEenumerator_s_product(int argc, VALUE *argv, VALUE klass){    VALUE enums = Qnil, options = Qnil, block = Qnil;    rb_scan_args(argc, argv, "*:&", &enums, &options, &block);    if (!NIL_P(options) && !RHASH_EMPTY_P(options)) {        rb_exc_raise(rb_keyword_error_new("unknown", rb_hash_keys(options)));    }    VALUE obj = enum_product_initialize(argc, argv, enum_product_allocate(rb_cEnumProduct));    if (!NIL_P(block)) {        enum_product_run(obj, block);        return Qnil;    }    return obj;}

Generates a new enumerator object that generates a Cartesian product of given enumerable objects. This is equivalent toEnumerator::Product.new.

e =Enumerator.product(1..3, [4,5])e.to_a#=> [[1, 4], [1, 5], [2, 4], [2, 5], [3, 4], [3, 5]]e.size#=> 6

When a block is given, calls the block with each N-element array generated and returnsnil.

Public Instance Methods

Source
static VALUEenumerator_plus(VALUE obj, VALUE eobj){    return new_enum_chain(rb_ary_new_from_args(2, obj, eobj));}

Returns an enumerator object generated from this enumerator and a given enumerable.

e = (1..3).each+ [4,5]e.to_a#=> [1, 2, 3, 4, 5]
Source
static VALUEenumerator_each(int argc, VALUE *argv, VALUE obj){    struct enumerator *e = enumerator_ptr(obj);    if (argc > 0) {        VALUE args = (e = enumerator_ptr(obj = rb_obj_dup(obj)))->args;        if (args) {#if SIZEOF_INT < SIZEOF_LONG            /* check int range overflow */            rb_long2int(RARRAY_LEN(args) + argc);#endif            args = rb_ary_dup(args);            rb_ary_cat(args, argv, argc);        }        else {            args = rb_ary_new4(argc, argv);        }        RB_OBJ_WRITE(obj, &e->args, args);        e->size = Qnil;        e->size_fn = 0;    }    if (!rb_block_given_p()) return obj;    if (!lazy_precheck(e->procs)) return Qnil;    return enumerator_block_call(obj, 0, obj);}

Iterates over the block according to how thisEnumerator was constructed. If no block and no arguments are given, returns self.

Examples

"Hello, world!".scan(/\w+/)#=> ["Hello", "world"]"Hello, world!".to_enum(:scan,/\w+/).to_a#=> ["Hello", "world"]"Hello, world!".to_enum(:scan).each(/\w+/).to_a#=> ["Hello", "world"]obj =Object.newdefobj.each_arg(a,b=:b,*rest)yieldayieldbyieldrest:method_returnedendenum =obj.to_enum:each_arg,:a,:xenum.each.to_a#=> [:a, :x, []]enum.each.equal?(enum)#=> trueenum.each {|elm|elm }#=> :method_returnedenum.each(:y,:z).to_a#=> [:a, :x, [:y, :z]]enum.each(:y,:z).equal?(enum)#=> falseenum.each(:y,:z) {|elm|elm }#=> :method_returned
Source
static VALUEenumerator_each_with_index(VALUE obj){    return enumerator_with_index(0, NULL, obj);}

Same asEnumerator#with_index(0), i.e. there is no starting offset.

If no block is given, a newEnumerator is returned that includes the index.

Source
static VALUEenumerator_with_object(VALUE obj, VALUE memo){    RETURN_SIZED_ENUMERATOR(obj, 1, &memo, enumerator_enum_size);    enumerator_block_call(obj, enumerator_with_object_i, memo);    return memo;}

Iterates the given block for each element with an arbitrary object,obj, and returnsobj

If no block is given, returns a newEnumerator.

Example

to_three =Enumerator.newdo|y|3.timesdo|x|y<<xendendto_three_with_string =to_three.with_object("foo")to_three_with_string.eachdo|x,string|puts"#{string}: #{x}"end# => foo: 0# => foo: 1# => foo: 2
Also aliased as:with_object
Source
static VALUEenumerator_feed(VALUE obj, VALUE v){    struct enumerator *e = enumerator_ptr(obj);    rb_check_frozen(obj);    if (!UNDEF_P(e->feedvalue)) {        rb_raise(rb_eTypeError, "feed value already set");    }    RB_OBJ_WRITE(obj, &e->feedvalue, v);    return Qnil;}

Sets the value to be returned by the next yield insidee.

If the value is not set, the yield returns nil.

This value is cleared after being yielded.

# Array#map passes the array's elements to "yield" and collects the# results of "yield" as an array.# Following example shows that "next" returns the passed elements and# values passed to "feed" are collected as an array which can be# obtained by StopIteration#result.e = [1,2,3].mappe.next#=> 1e.feed"a"pe.next#=> 2e.feed"b"pe.next#=> 3e.feed"c"begine.nextrescueStopIterationp$!.result#=> ["a", "b", "c"]endo =Object.newdefo.eachx =yield# (2) blockspx# (5) => "foo"x =yield# (6) blockspx# (8) => nilx =yield# (9) blockspx# not reached w/o another e.nextende =o.to_enume.next# (1)e.feed"foo"# (3)e.next# (4)e.next# (7)# (10)
Source
static VALUEenumerator_inspect(VALUE obj){    return rb_exec_recursive(inspect_enumerator, obj, 0);}

Creates a printable version ofe.

Source
static VALUEenumerator_next(VALUE obj){    VALUE vs = enumerator_next_values(obj);    return ary2sv(vs, 0);}

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

Example

a = [1,2,3]e =a.to_enumpe.next#=> 1pe.next#=> 2pe.next#=> 3pe.next#raises StopIteration

See class-level notes about external iterators.

Source
static VALUEenumerator_next_values(VALUE obj){    struct enumerator *e = enumerator_ptr(obj);    VALUE vs;    rb_check_frozen(obj);    if (!UNDEF_P(e->lookahead)) {        vs = e->lookahead;        e->lookahead = Qundef;        return vs;    }    return get_next_values(obj, e);}

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

See class-level notes about external iterators.

This method can be used to distinguishyield andyield nil.

Example

o =Object.newdefo.eachyieldyield1yield1,2yieldnilyield [1,2]ende =o.to_enumpe.next_valuespe.next_valuespe.next_valuespe.next_valuespe.next_valuese =o.to_enumpe.nextpe.nextpe.nextpe.nextpe.next## yield args       next_values      next#  yield            []               nil#  yield 1          [1]              1#  yield 1, 2       [1, 2]           [1, 2]#  yield nil        [nil]            nil#  yield [1, 2]     [[1, 2]]         [1, 2]
Source
static VALUEenumerator_peek(VALUE obj){    VALUE vs = enumerator_peek_values(obj);    return ary2sv(vs, 1);}

Returns the next object in the enumerator, but doesn’t move the internal position forward. If the position is already at the end,StopIteration is raised.

See class-level notes about external iterators.

Example

a = [1,2,3]e =a.to_enumpe.next#=> 1pe.peek#=> 2pe.peek#=> 2pe.peek#=> 2pe.next#=> 2pe.next#=> 3pe.peek#raises StopIteration
Source
static VALUEenumerator_peek_values_m(VALUE obj){    return rb_ary_dup(enumerator_peek_values(obj));}

Returns the next object as an array, similar toEnumerator#next_values, but doesn’t move the internal position forward. If the position is already at the end,StopIteration is raised.

See class-level notes about external iterators.

Example

o =Object.newdefo.eachyieldyield1yield1,2ende =o.to_enumpe.peek_values#=> []e.nextpe.peek_values#=> [1]pe.peek_values#=> [1]e.nextpe.peek_values#=> [1, 2]e.nextpe.peek_values# raises StopIteration
Source
static VALUEenumerator_rewind(VALUE obj){    struct enumerator *e = enumerator_ptr(obj);    rb_check_frozen(obj);    rb_check_funcall(e->obj, id_rewind, 0, 0);    e->fib = 0;    e->dst = Qnil;    e->lookahead = Qundef;    e->feedvalue = Qundef;    e->stop_exc = Qfalse;    return obj;}

Rewinds the enumeration sequence to the beginning.

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

Source
static VALUEenumerator_size(VALUE obj){    struct enumerator *e = enumerator_ptr(obj);    int argc = 0;    const VALUE *argv = NULL;    VALUE size;    if (e->procs) {        struct generator *g = generator_ptr(e->obj);        VALUE receiver = rb_check_funcall(g->obj, id_size, 0, 0);        long i = 0;        for (i = 0; i < RARRAY_LEN(e->procs); i++) {            VALUE proc = RARRAY_AREF(e->procs, i);            struct proc_entry *entry = proc_entry_ptr(proc);            lazyenum_size_func *size_fn = entry->fn->size;            if (!size_fn) {                return Qnil;            }            receiver = (*size_fn)(proc, receiver);        }        return receiver;    }    if (e->size_fn) {        return (*e->size_fn)(e->obj, e->args, obj);    }    if (e->args) {        argc = (int)RARRAY_LEN(e->args);        argv = RARRAY_CONST_PTR(e->args);    }    size = rb_check_funcall_kw(e->size, id_call, argc, argv, e->kw_splat);    if (!UNDEF_P(size)) return size;    return e->size;}

Returns the size of the enumerator, ornil if it can’t be calculated lazily.

(1..100).to_a.permutation(4).size# => 94109400loop.size# => Float::INFINITY(1..100).drop_while.size# => nil

Note that enumerator size might be inaccurate, and should be rather treated as a hint. For example, there is no check that the size provided to::new is accurate:

e =Enumerator.new(5) {|y|2.times {y<<it} }e.size# => 5e.to_a.size# => 2

Another example is an enumerator created by::produce without asize argument. Such enumerators returnInfinity for size, but this is inaccurate if the passed block raises StopIteration:

e =Enumerator.produce(1) {it+1 }e.size# => Infinitye =Enumerator.produce(1) {it>3?raise(StopIteration):it+1 }e.size# => Infinitye.to_a.size# => 4
Source
static VALUEenumerator_with_index(int argc, VALUE *argv, VALUE obj){    VALUE memo;    rb_check_arity(argc, 0, 1);    RETURN_SIZED_ENUMERATOR(obj, argc, argv, enumerator_enum_size);    memo = (!argc || NIL_P(memo = argv[0])) ? INT2FIX(0) : rb_to_int(memo);    return enumerator_block_call(obj, enumerator_with_index_i, (VALUE)rb_imemo_memo_new(memo, 0, 0));}

Iterates the given block for each element with an index, which starts fromoffset. If no block is given, returns a newEnumerator that includes the index, starting fromoffset

offset

the starting index to use

Iterates the given block for each element with an arbitrary object,obj, and returnsobj

If no block is given, returns a newEnumerator.

Example

to_three =Enumerator.newdo|y|3.timesdo|x|y<<xendendto_three_with_string =to_three.with_object("foo")to_three_with_string.eachdo|x,string|puts"#{string}: #{x}"end# => foo: 0# => foo: 1# => foo: 2
Alias for:each_with_object