Understanding Blocks (and Yield) in Ruby

David Maksimov
2 min readAug 29, 2020

--

One of the unique features of the Ruby programming languages is blocks. I’ve never heard of blocks before I started learning Ruby and it took me a little while to understand their use and purpose. They’re a powerful feature that’s used widely.

Here’s the simplest example of using a block in Ruby. The code below iterates through each item in an array of book titles and prints it.

books = ['To Kill a Mockingbird', '1984', 'The Catcher in the Rye']books.each do |book|
puts book
end
# Outputs:
# To Kill a Mockingbird
# 1984
# The Catcher in the Rye

Essentially a block passes a parameter (or parameters) and lets you do something with it.

Blocks
- Start with do
- Accept one or more parameters
- Do something with the parameters
- End with end

Parameters

The parameters are just arguments that you accept. You can name them whatever you like.

In the example above we named our parameter book but we could have easily named it anything.

books = ['To Kill a Mockingbird', '1984', 'The Catcher in the Rye']books.each do |book_title|
puts book_title
end
# Outputs:
# To Kill a Mockingbird
# 1984
# The Catcher in the Rye

Whatever name you accept for you parameter is the variable name you use within your block.

Shorthand Syntax

Ruby also provides a shorthand syntax for blocks which allows you to write simple one-liners.

The same block from above can be written in the following way.

books = ['To Kill a Mockingbird', '1984', 'The Catcher in the Rye']books.each { |book| puts book }# Outputs:
# To Kill a Mockingbird
# 1984
# The Catcher in the Rye

Writing Your Own Blocks

You’re not limited to using the blocks that already exist. You can write your own.

Say you have an initializer method for an ApiClient class. It’ll set the conventional configuration by default but you want to provide a way to customize the configuration if needed. For example, someone might want to add an additional header that should be present when the ApiClient makes requests.

If you wanted to use the default you would do the following without passing a block.

client = ApiClient.new

However, what if you wanted to start with the defaults but then additionally customize the configuration? Maybe something like:

api_key = 'neXYWWxojNJxckDJxSLKjW2EurdI84R8ZZucMW89wHXmFOF13udOz'client = ApiClient.new do |config|
config.add_header('X-API-Key', api_key)
end

What would our initialize method look like?

class ApiClient
# ...
def initialize
@config = ApiConfig.new
yield @config if block_given?
self
end
#...
end

Notice the yield part. This is what lets you attach a block to your method. You may pass any number of arguments to the yield method. These arguments will be the parameters given to the block.

Use the block_given? to check if a block was given if you want it to be optional.

--

--