Block Basics
Exercises
Overview
Blocks in Ruby are simply chunks of code between braces (single-line blocks) or between do
and end
(multi-line blocks). You can't execute a block of code directly. Instead, you must associate a block with a call to a method. When the method runs, it turns around and executes the code in the block. Depending on the method, it can also pass parameters to the associated block.
Now that you've seen blocks in action in the video, it's your turn!
1. Play With Blocks
Ruby has a number of built-in methods that take blocks. So let's begin with some basic blocks to warm up the fingers...
-
If you haven't already done so, create a new Ruby program file called
block_basics.rb
where you can play around with blocks. -
Start by using the
times
method with a block to print the following workout steps, 5 times:situp pushup chinup
-
That's a good start, but now suppose you want to prefix each step with the repetition number, like so:
0 situp 0 pushup 0 chinup 1 situp 1 pushup 1 chinup ... and so on 4 situp 4 pushup 4 chinup
To do that, recall that the
times
method will pass the current iteration to the block. You can capture that number in a block parameter. Remember that block parameters sit between vertical bars at the start of the block. Here's the general form for a block that takes one parameter:object.method do |parameter| # block code end # or for a single-line block: object.method { |parameter| ... }
-
You know your fitness instructor is a bit odd when she starts counting with zero. Unfortunately, the
times
method counts like a programmer. Change the code to use theupto
method, which counts more like a fitness pro, to count the repetitions from 1 through 5. Here's the output you're aiming for:1 situp 1 pushup 1 chinup 2 situp 2 pushup 2 chinup ... and so on 5 situp 5 pushup 5 chinup
Warmed up? Perfect! Here's the take-away: Although you attach a block to a method, the block is not a method parameter. The method and its parameters are totally separate from the code block. We'll see how methods actually call a block a bit later.
2. Create Frequent Flyers
Let's apply what we've learned about blocks toward something a bit more realistic. Suppose you're developing a frequent flyer program. To keep it simple for now, each frequent flyer has a name, email, and number of miles flown, which is represented in the following Flyer
class:
class Flyer
attr_reader :name, :email, :miles_flown
def initialize(name, email, miles_flown)
@name = name
@email = email
@miles_flown = miles_flown
end
def to_s
"#{name} (#{email}): #{miles_flown}"
end
end
Notice that the class defines a convenient to_s
method that returns a formatted string representing a specific flyer.
-
Go ahead and copy the code above into a new Ruby program file called
flyer.rb
. We'll build off this class over the next several exercises. -
Then create an array of five flyers, each with unique names, emails, and number of miles flown. Rather than creating them one by one, use your friend the
upto
method with an associated block to create and add each flyer to the array.Once you've filled up the array of flyers, print the array using
puts
. Passing an array toputs
will print each element in the array using the string returned by the object'sto_s
method. Your goal is the following output:Flyer 1 (flyer1@example.com): 1000 Flyer 2 (flyer2@example.com): 2000 Flyer 3 (flyer3@example.com): 3000 Flyer 4 (flyer4@example.com): 4000 Flyer 5 (flyer5@example.com): 5000
-
Once you get that working, feel free to experiment! For example, try changing the name of the block parameter.
Solution
All the exercise solutions, as well as the example code we write in the videos, is available for download in the
code bundle file (right-click to save). No peeking until you
try! When you unzip the file, you'll end up with a directory called
pragstudio-ruby-blocks-code
. Inside that directory, you'll find two sub-directories:
exercise-solutions
and video-code
. And inside each of those directories you'll find code organized into
sub-directories matching the names of the course modules.
The full solution for this exercise is in the
block-basics
directory of the
code bundle.
Pop Quiz
Take a minute to review the main concepts you've learned in this section, and let them sink in before moving on.
-
By convention, multi-line blocks to start with ________ and end with ________.
-
By convention, single-line blocks to start with ________ and end with ________.
-
Block parameters are always placed within ________.
-
Convert the following code from a multi-line block to a single-line block.
1.upto(10) do |count| puts "#{count} alligator" end
-
In the example below, the value of the method parameter is ________.
1.upto(5) do |count| puts "#{count} situps" puts "#{count} pushups" puts "#{count} chinups" end
-
In the example above, the block parameter is ________ and it is a ________ variable.
Bonus Round
Suppose you wanted to continue doing five repetitions of each exercise, but counting by 2, starting with 1 and ending with 9. (It's a new fad in exercise, trust us!) In that new regimen, here's the output you're looking for:
1 situp 1 pushup 1 chinup 3 situp 3 pushup 3 chinup ... and so on 9 situp 9 pushup 9 chinup
To do that, we need to introduce you to a new method. Similar to the upto
method, Ruby also has a step method. It takes two parameters: the upper limit and the step interval.
Give it an honest try before looking at the answer!
Wrap Up
So now that you've been around the ol' block (sorry, that was lame), you now know how to:
-
call methods that take blocks (such as
times
andupto
) - write single and multi-line blocks
- write blocks that take parameters
Here's a visual overview of what we learned in this section (click to enlarge):
For quick and handy reference, download all the cheat-sheet summaries in a single summary PDF.
Everything from here forward builds on this basic foundation! Next up we'll use blocks with another iterator method: each
. It's super powerful and you'll see (and use) it extensively in Ruby and Rails.