Ruby 2.7 adds Enumerator#produce


Ruby 2.7 has added Enumerator#produce to generate Enumerator from any custom data-transformation.

Before

Let’s say we want to print the first 10 numbers of fibonacci series.

The code to achieve this would look like:

result = Enumerator.new do |yielder|
  base_1 = 0
  base_2 = 1
  loop do
    yielder.yield base_1
    base_1, base_2 = base_2, base_1 + base_2
  end
end

result.take(10)
=> [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

As shown above, we need to use loop and yield in order to achieve the required results.

Enumerator#produce

We can now use Enumerator#produce in Ruby 2.7 to achieve this in a simpler way:

Enumerator.produce([0, 1]) { |base_1, base_2| [base_2, base_1 + base_2] }.take(10).map(&:first)
=> [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

Enumerator.produce(initial, &block), will produce an infinite sequence where each next element is calculated by applying block to previous.

initial is the first sequence element. We can use produce without initial value as well.

Enumerator.produce(&block), will produce an infinite sequence. The first element of the sequence will be the result of calling the block with no args.

Example of produce without args:

# Get random date within a month which falls on weekday
Enumerator.produce { Date.today+rand(30) }.detect{ |date| !date.sunday? || !date.saturday? }
=> #<Date: 2019-11-15 ((2458803j,0s,0n),+0s,2299161j)>

As illustrated above, produce helps to produce enumerators with a much cleaner and simpler code.

More information about this feature along with few other examples can be found on Feature #14781.