In Progress
Unit 1, Lesson 1
In Progress

# Yield or Enumerate

Video transcript & code

I hope you're not tired of hearing about Enumerators, because I'm not quite done talking about them.

Many of Ruby's collection iteration methods have an interesting trick: if we call them without a block, they return an `Enumerator`. For instance, take the `#each_slice` method. If we call it with a block, it iterates through the collection, yielding slices of the collection until it reaches the end.

``````require 'pp'
[0,1,2,3,4,5,6,7,8,9].each_slice(2) do |slice|
pp slice
end
# >> [0, 1]
# >> [2, 3]
# >> [4, 5]
# >> [6, 7]
# >> [8, 9]
``````

But if we call it without a block, it returns an `Enumerator`:

``````require 'pp'
[1,2,3,4,5,6,7,8,9].each_slice(2) # => #<Enumerator: [1, 2, 3, 4, 5, 6, 7, 8, 9]:each_slice(2)>
``````

This is convenient for chaining enumerable operations.

``````require 'pp'
sums = [0,1,2,3,4,5,6,7,8,9].each_slice(2).map do |slice|
slice.reduce(:+)
end
sums # => [1, 5, 9, 13, 17]
``````

Any method that yields a series of values could potentially be a lot more flexible if it behaved like this, returning an `Enumerator` in the absence of a block. So we might reasonably want to know how to duplicate this behavior in our own methods.

As it happens, it's not hard at all. In fact, it's a one-liner.

``````def names
yield "Ylva"
yield "Brighid"
yield "Shifra"
yield "Yesamin"
end
``````

This line checks to see if a block has been provided. If so, it allows the method to continue normally. Otherwise, it constructs an `Enumerator` for the current method and immediately returns it. When we try it out, we can see that calling the method without a block returns a fully-functional `Enumerator`.

``````names                           # => #<Enumerator: main:names>
names.to_a                      # => ["Ylva", "Brighid", "Shifra", "Yesamin"]
``````

One potential improvement we can make to this line is to replace the name of the method with the `__callee__` special variable. This variable always contains the name of the current method. By making this change, we eliminate the duplication of the method name, and ensure that if we ever change the name of the method the call to `#to_enum` will continue to work.

``````def names