Class: Enumerator (Ruby 2.3.4)

    In Files

    • enumerator.c

    Class/Module Index [+]

    Quicksearch

    Enumerator

    A class which allows both internal and external iteration.

    An Enumerator can be created by the following methods.

    • Kernel#to_enum

    • Kernel#enum_for

    • ::new

    Most methods have two forms: a block form where the contents are evaluated for each item in the enumeration, and a non-block form which returns a new Enumerator wrapping the iteration.

    enumerator = %w(one two three).each
    puts enumerator.class # => Enumerator
    
    enumerator.each_with_object("foo") do |item, obj|
      puts "#{obj}: #{item}"
    end
    
    # foo: one
    # foo: two
    # foo: three
    
    enum_with_obj = enumerator.each_with_object("foo")
    puts enum_with_obj.class # => Enumerator
    
    enum_with_obj.each do |item, obj|
      puts "#{obj}: #{item}"
    end
    
    # foo: one
    # foo: two
    # foo: three
    

    This allows you to chain Enumerators together. For example, you can map a list's elements to strings containing the index and the element as a string via:

    puts %w[foo bar baz].map.with_index { |w, i| "#{i}:#{w}" }
    # => ["0:foo", "1:bar", "2:baz"]
    

    An Enumerator can also be used as an external iterator. For example, #next returns the next value of the iterator or raises StopIteration if the Enumerator is at the end.

    e = [1,2,3].each   # returns an enumerator object.
    puts e.next   # => 1
    puts e.next   # => 2
    puts e.next   # => 3
    puts e.next   # raises StopIteration
    

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

    def ext_each(e)
      while true
        begin
          vs = e.next_values
        rescue StopIteration
          return $!.result
        end
        y = yield(*vs)
        e.feed y
      end
    end
    
    o = Object.new
    
    def o.each
      puts yield
      puts yield(1)
      puts yield(1, 2)
      3
    end
    
    # use o.each as an internal iterator directly.
    puts o.each {|*x| puts x; [:b, *x] }
    # => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
    
    # convert o.each to an external iterator for
    # implementing an internal iterator.
    puts ext_each(o.to_enum) {|*x| puts x; [:b, *x] }
    # => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
    

    Public Class Methods

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

    Creates a new Enumerator object, which can be used as an Enumerable.

    In the first 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 (aliased as +<<+):

    fib = Enumerator.new do |y|
      a = b = 1
      loop do
        y << a
        a, b = b, a + b
      end
    end
    
    p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
    

    The optional parameter can be used to specify how to calculate the size in a lazy fashion (see #size). It can either be a value or a callable object.

    In the second, deprecated, 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 or Kernel#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
    
     
                   static VALUE
    enumerator_initialize(int argc, VALUE *argv, VALUE obj)
    {
        VALUE recv, meth = sym_each;
        VALUE size = Qnil;
    
        if (rb_block_given_p()) {
            rb_check_arity(argc, 0, 1);
            recv = generator_init(generator_allocate(rb_cGenerator), rb_block_proc());
            if (argc) {
                if (NIL_P(argv[0]) || rb_respond_to(argv[0], id_call) ||
                    (RB_TYPE_P(argv[0], T_FLOAT) && RFLOAT_VALUE(argv[0]) == INFINITY)) {
                    size = argv[0];
                }
                else {
                    size = rb_to_int(argv[0]);
                }
                argc = 0;
            }
        }
        else {
            rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
            rb_warn("Enumerator.new without a block is deprecated; use Object#to_enum");
            recv = *argv++;
            if (--argc) {
                meth = *argv++;
                --argc;
            }
        }
    
        return enumerator_init(obj, recv, meth, argc, argv, 0, size);
    }
                

    Public Instance Methods

    each { |elm| block } → obj click to toggle source
    each → enum
    each(*appending_args) { |elm| block } → obj
    each(*appending_args) → an_enumerator

    Iterates over the block according to how this Enumerator 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.new
    
    def obj.each_arg(a, b=:b, *rest)
      yield a
      yield b
      yield rest
      :method_returned
    end
    
    enum = obj.to_enum :each_arg, :a, :x
    
    enum.each.to_a                  #=> [:a, :x, []]
    enum.each.equal?(enum)          #=> true
    enum.each { |elm| elm }         #=> :method_returned
    
    enum.each(:y, :z).to_a          #=> [:a, :x, [:y, :z]]
    enum.each(:y, :z).equal?(enum)  #=> false
    enum.each(:y, :z) { |elm| elm } #=> :method_returned
    
     
                   static VALUE
    enumerator_each(int argc, VALUE *argv, VALUE obj)
    {
        if (argc > 0) {
            struct enumerator *e = enumerator_ptr(obj = rb_obj_dup(obj));
            VALUE args = e->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);
            }
            e->args = args;
        }
        if (!rb_block_given_p()) return obj;
        return enumerator_block_call(obj, 0, obj);
    }
                
    each_with_index {|(*args), idx| ... } click to toggle source
    each_with_index

    Same as #with_index, i.e. there is no starting offset.

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

     
                   static VALUE
    enumerator_each_with_index(VALUE obj)
    {
        return enumerator_with_index(0, NULL, obj);
    }
                
    each_with_object(obj) {|(*args), obj| ... } click to toggle source
    each_with_object(obj)

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

    If no block is given, returns a new Enumerator.

    Example

    to_three = Enumerator.new do |y|
      3.times do |x|
        y << x
      end
    end
    
    to_three_with_string = to_three.with_object("foo")
    to_three_with_string.each do |x,string|
      puts "#{string}: #{x}"
    end
    
    # => foo:0
    # => foo:1
    # => foo:2
    
     
                   static VALUE
    enumerator_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;
    }
                
    feed obj → nil click to toggle source

    Sets the value to be returned by the next yield inside e.

    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].map
    p e.next           #=> 1
    e.feed "a"
    p e.next           #=> 2
    e.feed "b"
    p e.next           #=> 3
    e.feed "c"
    begin
      e.next
    rescue StopIteration
      p $!.result      #=> ["a", "b", "c"]
    end
    
    o = Object.new
    def o.each
      x = yield         # (2) blocks
      p x               # (5) => "foo"
      x = yield         # (6) blocks
      p x               # (8) => nil
      x = yield         # (9) blocks
      p x               # not reached w/o another e.next
    end
    
    e = o.to_enum
    e.next              # (1)
    e.feed "foo"        # (3)
    e.next              # (4)
    e.next              # (7)
                        # (10)
    
     
                   static VALUE
    enumerator_feed(VALUE obj, VALUE v)
    {
        struct enumerator *e = enumerator_ptr(obj);
    
        if (e->feedvalue != Qundef) {
            rb_raise(rb_eTypeError, "feed value already set");
        }
        e->feedvalue = v;
    
        return Qnil;
    }
                
    inspect → string click to toggle source

    Creates a printable version of e.

     
                   static VALUE
    enumerator_inspect(VALUE obj)
    {
        return rb_exec_recursive(inspect_enumerator, obj, 0);
    }
                
    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, StopIteration is raised.

    Example

    a = [1,2,3]
    e = a.to_enum
    p e.next   #=> 1
    p e.next   #=> 2
    p e.next   #=> 3
    p e.next   #raises StopIteration
    

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

     
                   static VALUE
    enumerator_next(VALUE obj)
    {
        VALUE vs = enumerator_next_values(obj);
        return ary2sv(vs, 0);
    }
                
    next_values → array click to toggle source

    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.

    This method can be used to distinguish yield and yield nil.

    Example

    o = Object.new
    def o.each
      yield
      yield 1
      yield 1, 2
      yield nil
      yield [1, 2]
    end
    e = o.to_enum
    p e.next_values
    p e.next_values
    p e.next_values
    p e.next_values
    p e.next_values
    e = o.to_enum
    p e.next
    p e.next
    p e.next
    p e.next
    p e.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]
    

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

     
                   static VALUE
    enumerator_next_values(VALUE obj)
    {
        struct enumerator *e = enumerator_ptr(obj);
        VALUE vs;
    
        if (e->lookahead != Qundef) {
            vs = e->lookahead;
            e->lookahead = Qundef;
            return vs;
        }
    
        return get_next_values(obj, e);
    }
                
    peek → object click to toggle source

    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.

    Example

    a = [1,2,3]
    e = a.to_enum
    p e.next   #=> 1
    p e.peek   #=> 2
    p e.peek   #=> 2
    p e.peek   #=> 2
    p e.next   #=> 2
    p e.next   #=> 3
    p e.peek   #raises StopIteration
    
     
                   static VALUE
    enumerator_peek(VALUE obj)
    {
        VALUE vs = enumerator_peek_values(obj);
        return ary2sv(vs, 1);
    }
                
    peek_values → array click to toggle source

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

    Example

    o = Object.new
    def o.each
      yield
      yield 1
      yield 1, 2
    end
    e = o.to_enum
    p e.peek_values    #=> []
    e.next
    p e.peek_values    #=> [1]
    p e.peek_values    #=> [1]
    e.next
    p e.peek_values    #=> [1, 2]
    e.next
    p e.peek_values    # raises StopIteration
    
     
                   static VALUE
    enumerator_peek_values_m(VALUE obj)
    {
        return rb_ary_dup(enumerator_peek_values(obj));
    }
                
    rewind → e click to toggle source

    Rewinds the enumeration sequence to the beginning.

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

     
                   static VALUE
    enumerator_rewind(VALUE obj)
    {
        struct enumerator *e = enumerator_ptr(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;
    }
                
    size → int, Float::INFINITY or nil click to toggle source

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

    (1..100).to_a.permutation(4).size # => 94109400
    loop.size # => Float::INFINITY
    (1..100).drop_while.size # => nil
    
     
                   static VALUE
    enumerator_size(VALUE obj)
    {
        struct enumerator *e = enumerator_ptr(obj);
        int argc = 0;
        const VALUE *argv = NULL;
        VALUE size;
    
        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(e->size, id_call, argc, argv);
        if (size != Qundef) return size;
        return e->size;
    }
                
    with_index(offset = 0) {|(*args), idx| ... } click to toggle source
    with_index(offset = 0)

    Iterates the given block for each element with an index, which starts from offset. If no block is given, returns a new Enumerator that includes the index, starting from offset

    offset

    the starting index to use

     
                   static VALUE
    enumerator_with_index(int argc, VALUE *argv, VALUE obj)
    {
        VALUE memo;
    
        rb_scan_args(argc, argv, "01", &memo);
        RETURN_SIZED_ENUMERATOR(obj, argc, argv, enumerator_enum_size);
        if (NIL_P(memo))
            memo = INT2FIX(0);
        else
            memo = rb_to_int(memo);
        return enumerator_block_call(obj, enumerator_with_index_i, (VALUE)MEMO_NEW(memo, 0, 0));
    }
                
    with_object(obj) {|(*args), obj| ... } click to toggle source
    with_object(obj)

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

    If no block is given, returns a new Enumerator.

    Example

    to_three = Enumerator.new do |y|
      3.times do |x|
        y << x
      end
    end
    
    to_three_with_string = to_three.with_object("foo")
    to_three_with_string.each do |x,string|
      puts "#{string}: #{x}"
    end
    
    # => foo:0
    # => foo:1
    # => foo:2
    
     
                   static VALUE
    enumerator_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;
    }