Skip to content
Enumerator#generate Ruby core proposal demo
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
lib
test
.gitignore
Gemfile
README.md
Rakefile
enumerator_generate.gemspec
examples.rb

README.md

Enumerator#generate

This is an alternative to Object#enumerate Ruby language core proposal. Goal is the same: generating enumerators which can idiomatically replace (most of) while and loop cycles.

After some experiments, it turns out that "start from initial value, and continue with this block" (like Object#enumerate does) is not the only important use case. "Just enumerate with this block" is equally important, and Enumerator#generate supports this case finely. Also, the call sequence seems to be less confusing, it is pretty straight: Enumerator#generate generates an enumerator from block and optional initial value.

Synopsys

Enumerator#generate takes a block and optional initial value, and generates (infinite) enumerator by applying the block to result of previous iteration. If initial value is not passed, first block receives no arguments.

Examples of usage

With initial value

# Infinite sequence
p Enumerator.generate(1, &:succ).take(5)
# => [1, 2, 3, 4, 5]

# Easy Fibonacci
p Enumerator.generate([0, 1]) { |f0, f1| [f1, f0 + f1] }.take(10).map(&:first)
#=> [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

require 'date'

# Find next Tuesday
p Enumerator.generate(Date.today, &:succ).detect { |d| d.wday == 2 }
# => #<Date: 2018-05-22 ((2458261j,0s,0n),+0s,2299161j)>

(Other examples from Object#enumerate are easily translated, too.)

Without initial value

# Random search
target = 7
p Enumerator.generate { rand(10) }.take_while { |i| i != target }.to_a
# => [0, 6, 3, 5,....]

# External while condition
require 'strscan'
scanner = StringScanner.new('7+38/6')
p Enumerator.generate { scanner.scan(%r{\d+|[-+*/]}) }.slice_after { scanner.eos? }.first
# => ["7", "+", "38", "/", "6"]

# Potential message loop system:
Enumerator.generate { Message.receive }.take_while { |msg| msg != :exit }
You can’t perform that action at this time.