This is a small challenge to learn more about how blocks work in Ruby. Blocks are actually very similiar to methods.
So let's think about methods for a second... You call a method with data from the outside world — the method's arguments. The code inside the method can see and use this data.
If arguments are how we pass in data into methods, blocks are how we pass in behavior. Think of them as a chunk of logic or a "brain" that your method can run (aka: "call" or "yield").
In Ruby, blocks can be passed into methods as a sort of "invisible argument", like this:
def print_result
result_from_block = yield
puts result_from_block
end
# This will print out the number 9 to the console
print_result { 3 * 3 }
# Blocks can also be written using the do...end format
print_result do
creature = "walrus"
"I am the #{creature}!"
end
# Very cool: blocks have access to variables outside of their definition!
shopping_list = [:milk, :eggs, :cheese]
print_result do
important_item = shopping_list.sample # select one at random
"I hope I don't forget #{important_item}!!!"
end
As you will notice, the call to yield in the method definition is where the block is executed.
Let's write something practical using blocks. A common scenario is wanting to benchmark some code. The "skeleton" involved in benchmarking doesn't need to know what it's benchmarking, but it should be responsible for keeping track of how long it's running and other benchmarking-specific concerns.
That is, it shouldn't care whether we're benchmarking a simple function to add two numbers or something much more complicated.
Without blocks we might write code like this:
start_time = Time.now
# Calculate the 200th Fibonacci number
fibonacci(200)
end_time = Time.now
# This will return the difference in the timestamps in seconds
running_time = end_time - start_time
puts "fibonacci(200) took #{running_time} seconds."
To make our benchmarking logic reusable, let's use blocks to create a benchmark method that can benchmark anything.
The goal of this challenge is to help you get better at understanding and using blocks. Feel free to play around and create toy versions of your code before you dive in.
- Writing methods that take a block parameter
- Returning values from blocks
Implement the benchmark method in the benchmark_with_block.rb file.
# Be careful, pasting this into IRB will take a long time to print.
# It's a loooong string. :)
long_string = "apple"*100000000
running_time = benchmark { long_string.reverse }
puts "string.reverse took #{running_time} seconds to run"