If you have been following along with this series, you might be confused by the use of blocks.

So far we’ve seen blocks being passed to iterator methods such as each, map and select whilst looking at Arrays, and Hashes.

A block is simply a chunk of code that can be passed as an argument to a function. You can think of it as a list of instructions that can be passed around and acted upon.

In today’s tutorial we will be looking at understanding and using blocks in Ruby.

What is a Block?

If you are already familiar with other programming languages, you might already be familiar with the concept of passing a chunk of code to a function.

In Ruby, a block is a chunk of code that sits between curly braces or a do..end statement.

For example, imagine we have the following Array:

colours = [‘red’, ‘blue’, ‘green’];  

We could print each colour to the screen by passing a block wrapped in curly braces like this:

colours.each {|colour| puts colour }  

Or alternatively we could pass a block wrapped in do..end like this:

colours.each do |colour|  
puts colour  
end  

Usually you will see curly braces used if the block fits on one line, and do..end when it spans multiple lines.

So a block is a chunk of code that you pass as an argument to a method.

In both cases above, each element of the Array will be passed to the block. The block accepts each element and then puts it to the screen.

This makes methods like each very flexible because we can pass a list of actions that should be executed upon for each item as a block of instructions.

Using a Block in a method

So hopefully the last section makes sense. A block is simply a chunk of code that can be passed to a method.

To better understand what’s going on under the hood, we’ll now look at implementing a method that excepts a block:

def do_something

end

do_something { puts "hello world" }  

Here we have a simple method called do_something. After we have declared the method we call it and pass it a block that will print "hello world" to the screen.

Notice how we don’t have to tell the method that it should be expecting a block.

However, if you save this as a Ruby file and run it from Terminal you will notice that nothing is printed to the screen!

In order for the block to be executed we need to yield the control flow. We do that by using the yield key word:

def do_something  
yield  
end

do_something { puts "hello world" }  

When the yield key word is encountered we jump into the block and run the chunk of code and then jump back out and continue with the rest of the method.

You can see this in action with the following code:

def do_something  
puts "before the block"  
yield  
puts "after the block"  
end

do_something { puts "Inside the block" }  

If a method is expecting a block but you don’t pass one an Exception will be thrown:

def do_something  
yield  
end

do_something

=> no block given (yield) (LocalJumpError)  

You can conditionally yield to a block if a block is passed by calling block_given?:

def do_something  
yield if block_given?  
end

do_something  

Finally, you can also pass arguments to a block. This is what is happening when you pass a block to the each method of an Array.

To understand this better we can implement our own iterator method on the Array Class:

class Array  
def reverse_each  
reverse.each do |item|  
yield item  
end  
end  
end

[1,2,3].reverse_each { |number| puts number }  

In the example above we’ve added a new method to the Array class called reverse_each.

This method will reverse the Array of items and then call the each method and pass the block. Each item of the Array will be passed to the block.

If you run this code in Terminal you will see that the numbers are printed to the screen in reverse order.

Why would you use a block?

So why would you want to use a block and why are they so important to Ruby? Well blocks are useful for a number of different reasons.

Firstly, using blocks makes it possible to implement generic methods like each or map that can be used in all sorts of different ways.

For example, the each method will call a block for each element, whereas the map method will return a new Array containing the values returned by the block.

By providing the raw tools of the each and map methods and the ability to write blocks, Ruby is giving us with what we need to define the behaviour we need to implement. This means we can reuse these methods with any kind of behaviour without having to duplicate the logic of iterating over the Array.

Secondly, blocks allow you to DRY up your code to prevent repetition. For example, take a look at this:

class SnapChat

def take_picture  
puts "You have authenticated!"  
puts "Take a picture"  
end

def record_video  
puts "You have authenticated!"  
puts "Record a video"  
end

end

client = SnapChat.new  
client.take_picture  
client.record_video  

In both of these methods we first need to authenticate before we can take the action. We can DRY this code up by using a block:

class SnapChat

def authenticate  
puts "You have authenticated!"  
yield  
end

def take_picture  
authenticate { puts "Take a picture" }  
end

def record_video  
authenticate { puts puts "Record a video" }  
end

end

client = SnapChat.new  
client.take_picture  
client.record_video  

So once again we are using the flexibility of blocks to reduce repetition.

And finally, blocks make it really easy to encapsulate a series of tasks using the Ruby classes like File:

File.open("shopping_list.txt","w") do |f|  
f << "eggs"  
end  

In this example we open up a new file called shopping_list.txt and then pass the file to a block where we can work with it, in this case simply adding a new item to the list.

Ruby will automatically deal with closing the file at the end of the block.

Using a block in this example is also much better than writing the following series of statements:

f = File.open("shopping_list.txt","w")  
f << "eggs"  
f.close  

Conclusion

Blocks are a very important and very useful part of the Ruby language. You will see heavy use of blocks in almost all Ruby code you encounter, so it’s important to understand what they are for and what is exactly going on under the hood.

Block are useful for all sorts of reasons really and you will see them used in all sorts of different scenarios.

If you’re new to programming in general, blocks can seem a bit daunting or confusing. However once you get into the swing of writing Ruby, you will see that blocks are really an invaluable component of your Ruby tool belt.