Project

General

Profile

Feature #15144

Enumerator#chain

Added by zverok (Victor Shepelev) almost 2 years ago. Updated almost 2 years ago.

Status:
Closed
Priority:
Normal
Target version:
-
[ruby-core:89121]

Description

I am not sure I am not missing something, but...

[1, 2, 3].each.chain([3, 4, 5].each) # => Enumerator

...seem to be a useful pattern.

It especially shows itself in case of lazy enumerators, representing several long-calculated sequences, like something...

# just data from several sources, abstracted into enumerator, fetching it on demand
process = URLS.lazy.map(&Faraday.method(:get)))
  .chain(LOCAL_FILES.lazy.map(&File.method(:read)))
  .chain(FALLBACK_FILE.then.lazy.map(&File.method(:read))) # with yield_self aka then we can even chain ONE value

process.detect { |val| found?(val) } # uniformely search several sources (lazy-loading them) for some value

# tty-progressbar is able to work with enumerables:
bar = TTY::ProgressBar.new("[:bar]", total: URLS.count + LOCAL_FILES.count + 1)
bar.iterate(process).detect { |val| found?(val) } # shows progress-bar for uniform process of detection

Prototype impl. is dead simple, of course:

class Enumerator
  def chain(*others)
    Enumerator.new { |y|
      [self, *others].each { |e| e.each { |v| y << v } }
    }
  end
end

Obviously, the effect could be reached with flat_map, but it seems "chaining" of iterations is pretty common and clear concept (and Google search for "ruby enumerator chain" shows people constantly ask about the way).


Files


Related issues

Related to Ruby master - Feature #709: Enumerator#+Rejectedknu (Akinori MUSHA)Actions

Also available in: Atom PDF