Ruby blocks from the Outside In w\ yield
Dedé Menezes
Posted on July 18, 2024
Ruby programming language if full of blocks. Most of the time we will use blocks but almost never define methods that uses them. So when I sit down to study with a friend I took some time to explain how does it work in the internals.
What is a block?
It can also be called an anonymous method. A method without a name.
Think about this 🤔
def do_your_thing(variable)
variable.upcase
end
do |variable|
variable.upcase
end
Okay, okay. It's too different. Instead of def
there is a do
and instead of ()
we have ||
's 😅
So, what is the goal with this?
The power on this relies on the fact that block can be passed to methods, including those you define. It is a piece of code, a block of code, bounded to a method. It can also be called in different ways but we won't see any of it in here.
The main point is that we can now pass some extra behaviors to some methods! Cool right?
This is what allows us to have one method called #select
and only specify how we want to filter when we CALL the method.
students = ['Bia', 'Samantha', 'Jackie', 'Billie', 'Johnny']
students_with_j = students.select do |student|
student.start_with?('J')
end
p students_with_j #=> ['Jackie', 'Johnny']
Clever hum? Ruby <3
So, how does it work from Outside In?
Well, let's take a look into a fake #timer example. Here is what we wnat to do ⤵️
# We want to create a method
# to calculate how long
# took to perform a task
def timer
# Obviously we will simulate a very long task ;)
puts 'Starting task now!'
# let's get the start time
start_time = Time.now
# PERFORMING HUGE TASK!
puts 'Doing dishes...'
sleep(3) # proccess sleeps for three seconds
puts 'Done w\ dishes! zo/'
# Let's get the end time and calculate the elapsed time
time_end = Time.now
elapsed_time = time_end - start_time
puts "It took us: #{elapsed_time}s"
end
Now, we want to use this method to calculate how long will take to perform another task. In this case, we would need to change the method definition because this new task would take only 0.5 seconds. If we keep changing the method for different tasks then it's better to rename the method hueheuue! this method shoud be called one_point_two_task s😅 Obviously it's a joke
So, how can we make this method CUSTOMIZABLE?!
You got it right! Using a BLOCK!
Yield without parameters
timer do
# Obviously we will simulate a very long task ;)
puts 'Starting task now!'
# let's get the start time
start_time = Time.now
# Here I will define what should we do in the task!
# in our case that is where our sleep(2), sleep(1.2) should be!
# To run the code inside the block we use the keyword ⤵️
yield
# Let's get the end time and calculate the elapsed time
time_end = Time.now
elapsed_time = time_end - start_time
puts "It took us: #{elapsed_time}s"
end
Now, when calling the method, we can specify different tasks to be measured ;)
timer do
puts 'Cooking lunch...'
sleep(0.2)
puts 'Done!'
end
Yield with parameters
Let's create another example, a method to greet someone.
def greet(name)
"Good morning, #{name}"
end
puts greet('Qin')
puts greet('Pedro')
puts greet('Michael')
What if we want now to be able to greet in different languages? Right now my method can only greet in English. Should we change the method name or make it customizable?
You got it right! We can make it customizable using blocks!
The message now will be defined INSIDE THE BLOCK when calling the method. Like the example below ⤵️
message = greet('Chloe') do |name|
"Bounjour, #{name.upcase}!"
end
puts message
So to access the name passed as an argument, we need to PASS IT to the yield. Doing that will make it available as the PIPE VARIABLE!
def greet(name)
yield(name)
end
message = greet('Chloe') do |name|
"Bounjour, #{name.upcase}!"
end
puts message
Conclusion
Blocks in Ruby are a powerful feature that allow you to add customizable behaviors to your methods. Understanding and utilizing blocks allow you to write more flexible and reusable code. Blocks provide a way to pass additional logic to methods. Keep experimenting with blocks, and you'll discover even more creative ways to enhance your Ruby programs.
That's all folks! I hope you liked it!
Happy coding! :)
Posted on July 18, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.