The yield Keyword in Ruby
In this article, we’re going to explore the following topics:
- the
yield
keyword - blocks &
yield
arguments - return values
- the
Enumerable#map
method
The yield
keyword — in association with a block — allows to pass a set of additional instructions during a method invocation.
This mechanism allows you to customise a method depending on your needs.
What’s a block ?
A block is part of the Ruby method syntax.
This means that when a block is recognised by the Ruby parser then it’ll be associated to the invoked method and literally replaces yield
s in the method
produces
one yield
multiple yields
multiple yields
The code inside the block will “replace” yield
keyword in the method definition.
Now, what happens if we don’t pass a block during method invocation for a method that includes yield
?
block_given?
When yield
is called in a method, the method requires a block. Otherwise, a LocalJumpError
is raised
So, how to make the block optional ? By using Kernel#block_given?
Here, yield
is only processed if a block is passed during a method call.
Arguments
yield
can take a list of arguments that will be available for the block
Here, the block takes |hello, world|
as arguments. Those arguments are provided by yield
inside yield_with_arguments
.
Return value
It’s possible to get the return value of a block by simply assigning the return value of a yield
to a variable
hello_world
contains "Hello World!"
returned by the block.
Array#my_map
Now that we’ve made an overview of yield
, let’s try to recap the important notions by implementing an example.
Enumerable#map
allows you to iterate over a list of objects and manipulate each of them. Then it returns a new list that contains all the manipulated objects.
$> array = [1, 2, 3]
=> [1, 2, 3]
$> array.map { |n| n + 2 }
=> [3, 4, 5]
$> array
=> [1, 2, 3]
In the above example, we assign [1, 2, 3]
to array
.
Then we call array.map { |n| n + 2 }
that adds 2
to each element of array
. A new array that contains [3, 4, 5]
is returned by array.map
.
Finally, we see that the initial array
didn’t change.
Now, let’s try to implement our own version of Enumerable#map
directly on the Array
class
$> array = [1, 2, 3]
=> [1, 2, 3]
$> array.my_map {|n| n + 2}
=> [3, 4, 5]
$> array
=> [1, 2, 3]
Our custom method has the same behavior as the Enumerable#map
method.
That’s great! Now let’s dive into the code.
1- we create a temporary array named ary
. This variable will contain the return value of our method.
2- we iterate over the calling array by using self.each
.
3- for each element, we call yield(elem)
— where elem
is the current element of the iteration. Then, we store the return value of yield(elem)
in ary
variable.
4- we return ary
.
Now, what happens if we forget to pass a block to our Array#my_map
method?
$> array.my_map
LocalJumpError (no block given (yield))
As you probably expected, an error is raised.
Fortunately, we’ve already fixed this issue in the previous sections.
So let’s reuse the Kernel#block_given?
method to enhance our Array#my_map
method
$> array.my_map
=> [1, 2, 3]
If there is no block passed to the method then we force the method to return a copy of the calling array.
Ruby Mastery
We’re currently finalizing our first online course: Ruby Mastery.
Join the list for an exclusive release alert! 🔔
Also, you can follow us on x.com as we’re very active on this platform. Indeed, we post elaborate code examples every day.
💚