TL;DR
Use Proc.new
Calling Enumerators - normal use
You’re writing some code which calls an Enumerator - a function that makes repeated calls to the block of code that you provide.
1 2 3 4 5 6 |
|
This will print:
1 2 |
|
The values are supplied by yield_me_2_things
and the printing is done in
the block, { |x| puts }
, that is passed to that method.
Generalize
I can now make a generalized method, to handle any number of things:
1 2 3 4 5 6 7 8 |
|
…the output is the same.
An alternative: use a block
I could equally have implemented the method using a &block
parameter -
for the caller, it makes no difference:
1 2 3 4 5 6 7 8 |
|
…the output is the same.
The problem
What if I want one Enumerator to call another?
What if I want to keep the specific version (yield_me_2_things
)
but just make it call the generalized method?
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
How should I write the two methods, while keeping both usable indipendently?
Attempt 1: Forward using yield
With yield
, you don’t explicitly receive the block, you just call it.
Does that work across two levels? I.e., does the block get passed to method I call?
1 2 3 4 5 6 7 8 9 10 11 12 |
|
No, doesn’t work, enumerate_n_things
doesn’t receive a block.
I get this error:
1
|
|
Attempt 2: Forward using a block
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Prints:
1 2 |
|
But we can no longer pass a block to the generalized method:
1
|
|
enumerate_n_things
now expects the block as a normal parameter.
I get this error:
1
|
|
Solution: Proc.new
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Both calls now work!
Proc.new
transforms any block passed to a method into a Proc.
If we use that as the default value for a block parameter we can
call methods directly with blocks, or forward blocks between
enumerators.