If you're new here, you may want to subscribe to my RSS feed. So that you can read the latest updates about Web2.0 tools, Making Money Online, Tips in SEO, Ajax and many more. Thanks for visiting ProgramimiCOM!

Code blocks can be very confusing to newcomers to Ruby, despite the fact that many computer languages have something that functions in a similar manner. This article, the first of three parts, introduces you to code blocks. It is excerpted from chapter eight of the Ruby Cookbook, written by Lucas Carlson and Leonard Richardson (O’Reilly, 2006; ISBN: 0596523696). Copyright © 2006 O’Reilly Media, Inc. All rights reserved. Used with permission from the publisher. Available from booksellers or direct from O’Reilly Media.

In Ruby, a code block (or just “block”) is an object that contains some Ruby code, and the context neccesary to execute it. Code blocks are the most visually distinctive aspect of Ruby, and also one of the most confusing to newcomers from other languages. Essentially, a Ruby code block is a method that has no name.

Most other languages have something like a Ruby code block: C’s function pointers, C++’s function objects, Python’s lambdas and list comprehensions, Perl’s anonymous functions, Java’s anonymous inner classes. These features live mostly in the corners of those languages, shunned by novice programmers. Ruby can’t be written without code blocks. Of the major languages, only Lisp is more block-oriented.

Unlike most other languages, Ruby makes code blocks easy to create and imposes few restrictions on them. In every other chapter of this book, you’ll see blocks passed into methods like it’s no big deal (which it isn’t):

[1,2,3].each { |i| puts i}
# 1
# 2
# 3

In this chapter, we’ll show you how to write that kind of method, the kinds of method that are useful to write that way, and when and how to treat blocks as first-class objects.

Ruby provides two syntaxes for creating code blocks. When the entire block will fit on one line, it’s most readable when enclosed in curly braces:

[1,2,3].each { |i| puts i }
# 1
# 2
# 3

When the block is longer than one line, it’s more readable to begin it with thedokeyword and end it with theendkeyword:

[1,2,3].each do |i|
if i % 2 == 0
puts “#{i} is even.”
else
puts “#{i} is odd.”
end
end
# 1 is odd.
# 2 is even.
# 3 is odd.

Some people use the bracket syntax when they’re interested in the return value of the block, and thedo…endsyntax when they’re interested in the block’s side effects.

Keep in mind that the bracket syntax has a higher precedence than thedo..endsyntax. Consider the following two snippets of code:

1.upto 3 do |x|
putsx
end
# 1
# 2
# 3

1.upto 3 { |x| puts x }
# SyntaxError: compile error

In the second example, the code block binds to the number 3, not to the function call1.upto 3. A standalone variable can’t take a code block, so you get a compile error. When in doubt, use parentheses.

1.upto(3) { |x| puts x }
# 1
# 2
# 3

Usually the code blocks passed into methods are anonymous objects, created on the spot. But you can instantiate a code block as aProcobject by callinglambda. See Recipe 7.1 for more details.

hello = lambda { “Hello”}
hello.call
# => “Hello”

log = lambda { |str| puts “[LOG] #{str}” }
log.call(”A test log message.”)
# [LOG] A test log message.

Like any method, a block can accept arguments. A block’s arguments are defined in a comma-separated list at the beginning of the block, enclosed in pipe characters:

{1=>2, 2=>4}.each { |k,v| puts “Key #{k}, value #{v}” }
# Key 1, value 2
# Key 2, value 4

Arguments to blocks look almost like arguments to methods, but there are a few restrictions: you can’t set default values for block arguments, you can’t expand hashes or arrays inline, and a block cannot itself take a block argument.*

SinceProcobjects are created like other objects, you can create factory methods whose return values are customized pieces of executable Ruby code. Here’s a simple factory method for code blocks that do multiplication:

def times_n(n)
lambda { |x| x * n }
end

The following code uses the factory to create and use two customized methods:

times_ten = times_n(10)
times_ten.call(5) # => 50
times_ten.call(1.25) # => 12.5

circumference = times_n(2*Math::PI)
circumference.call(10) #
=> 62.8318530717959
circumference.call(3) #
=> 18.8495559215388
[1, 2, 3].collect(&circumference)
# => [6.28318530717959, 12.5663706143592, 18.8495559215388]

You may have heard people talking about Ruby’s “closures.” What is a closure, and how is it different from a block? In Ruby, there is no difference between closures and blocks. Every Ruby block is also a closure.†

So what makes a Ruby block a closure? Basically, a Ruby block carries around the context in which it was defined. A block can reference the variables that were in scope when it was defined, even if those variables later go out of scope. Here’s a simple example; see Recipe 7.4 for more.

ceiling = 50
# Which of these numbers are less than the target?
[1, 10, 49, 50.1, 200].select { |x| x < ceiling }
# => [1, 10, 49]

The variableceilingis within scope when the block is defined, but it goes out of scope when the flow of execution enters theselectmethod. Nonetheless, the block can accessceilingfrom withinselect, because it carries its context around with it. That’s what makes it a closure.

We suspect that a lot of people who say “closures” when talking about Ruby blocks just do it to sound smart. Since we’ve already ruined any chance we might have had at sounding smart, we’ve decided refer to Ruby closures as just plain “blocks” throughout this book. The only exceptions are in the rare places where we must discuss the context that makes Ruby’s code blocks real closures, rather than “dumb” blocks.

Creating and Invoking a Block

Problem

You want to put some Ruby code into an object so you can pass it around and call it later.

Solution

By this time, you should familiar with a block as some Ruby code enclosed in curly brackets. You might think it possible to define a block object as follows:

aBlock = { |x| puts x } # WRONG

# SyntaxError: compile error

That doesn’t work because a block is only valid Ruby syntax when it’s an argument to a method call. There are several equivalent methods that take a block and return it as an object. The most favored method isKernel#lambda:*

aBlock = lambda { |x| puts x } # RIGHT

To call the block, use thecallmethod:

aBlock.call “Hello World!”
# Hello World!

Discussion

The ability to assign a bit of Ruby code to a variable is very powerful. It lets you write general frameworks and plug in specific pieces of code at the crucial points.

As you’ll find out in Recipe 7.2, you can accept a block as an argument to a method by prepending&to the argument name. This way, you can write your own trivial version of thelambdamethod:

def my_lambda(&aBlock)
aBlock
end

b = my_lambda { puts “Hello World My Way!” }
b.call
# Hello World My Way!

A newly defined block is actually aProcobject.

b.class # => Proc

You can also initialize blocks with theProcconstructor or the methodKernel#proc. The methodsKernel#lambda,Kernel#proc, andProc.newall do basically the same thing. These three lines of code are nearly equivalent:

aBlock = Proc.new { |x| puts x }
aBlock = proc { |x| puts x }
aBlock = lambda { |x| puts x }

What’s the difference?Kernel#lambdais the preferred way of creating block objects, because it gives you block objects that act more like Ruby methods. Consider what happens when you call a block with the wrong number of arguments:

add_lambda = lambda { |x,y| x + y }

add_lambda.call(4)
# ArgumentError: wrong number of arguments (1 for 2)

add_lambda.call(4,5,6)
# ArgumentError: wrong number of arguments (3 for 2)

A block created withlambdaacts like a Ruby method. If you don’t specify the right number of arguments, you can’t call the block. But a block created withProc.newacts like the anonymous code block you pass into a method likeEnumerable#each:

add_procnew = Proc.new { |x,y| x + y }

add_procnew.call(4)
# TypeError: nil can’t be coerced into Fixnum

add_procnew.call(4,5,6) # => 9

If you don’t specify enough arguments when you call the block, the rest of the arguments are givennil. If you specify too many arguments, the extra arguments are ignored. Unless you want this kind of behavior, uselambda.

In Ruby 1.8,Kernel#procacts likeKernel#lambda. In Ruby 1.9,Kernel#procacts likeProc.new, as better befits its name.

Writing a Method That Accepts a Block

Problem

You want to write a method that can accept and call an attached code block: a method that works like Array#each,Fixnum#upto, and other built-in Ruby methods.

Solution

You don’t need to do anything special to make your method capable of accepting a block. Any method can use a block if the caller passes one in. At any time in your method, you can call the block with yield:

def call_twice
puts “I’m about to call your block.”
yield
puts “I’m about to call your block again.”
yield
end

call_twice { puts “Hi, I’m a talking code block.” }
# I’m about to call your block.
# Hi, I’m a talking code block.
# I’m about to call your block again.
# Hi, I’m a talking code block.

Another example:

def repeat(n)
if block_given?
n.times { yield }
else
raise ArgumentError.new(”I can’t repeat a block you don’t give me!”)
end
end

repeat(4) { puts “Hello.” }
# Hello.
# Hello.
# Hello.
# Hello.

repeat(4) #
ArgumentError: I can’t repeat a block you don’t give me!

Discussion Since Ruby focuses so heavily on iterator methods and other methods that accept code blocks, it’s important to know how to use code blocks in your own methods.

You don’t have to do anything special to make your method capable of taking a code block. A caller can pass a code block into any Ruby method; it’s just that there’s no point in doing that if the method never invokesyield.

puts(”Print this message.”) { puts “And also run this code block!” }
# Print this message.

Theyieldkeyword acts like a special method, a stand-in for whatever code block was passed in. When you call it, it’s exactly as the code block were aProc object and you had invoked itscallmethod.

This may seem mysterious if you’re unfamiliar with the practice of passing blocks around, but it is usually the preferred method of calling blocks in Ruby. If you feel more comfortable receiving a code block as a “real” argument to your method, see Recipe 7.3.

You can pass in arguments toyield(they’ll be passed to the block) and you can do things with the value of theyield statement (this is the value of the last statement in the block).

Here’s a method that passes arguments into its code block, and uses the value of the block:

def call_twice
puts “Calling your block.”
ret1 = yield(”very first”)
puts “The value of your block: #{ret1}”

puts “Calling your block again.”
ret2 = yield(”second”)
puts “The value of your block: #{ret2}”
end

call_twice do |which_time|
puts “I’m a code block, called for the #{which_time} time.”
which_time == “very first” ? 1 : 2
end
# Calling your block.
# I’m a code block, called for the very first time.
# The value of your block: 1
# Calling your block again.
# I’m a code block, called for the second time.
# The value of your block: 2

Here’s a more realistic example. The methodHash#findtakes a code block, passes each of a hash’s key-value pairs into the code block, and returns the first key-value pair for which the code block evaluates to true.

squares = {0=>0, 1=>1, 2=>4, 3=>9}
squares.find { |key, value| key > 1 } # => [2, 4]

Suppose we want a method that works likeHash#find, but returns a new hash containing all the key-value pairs for which the code block evaluates to true. We can do this by passing arguments into theyieldstatement and using its result:

class Hash
def find_all
new_hash = Hash.new
each { |k,v| new_hash[k] = v if yield(k, v) }
new_hash
end
end

squares.find_all { |key, value| key > 1 } # => {2=>4, 3=>9}

As it turns out, the Hash#delete_if method already does the inverse of what we want. By negating the result of our code block, we can makeHash#delete_ifdo the job ofHash#find_all. We just need to work off of a duplicate of our hash, becausedelete_ ifis a destructive method:

squares.dup.delete_if { |key, value| key > 1 } # => {0=>0, 1=>1}
squares.dup.delete_if { |key, value| key <= 1 } # => {2=>4, 3=>9}

Hash#find_allturns out to be unnecessary, but it made for a good example.

You can write a method that takes an optional code block by callingKernel#block_ given?from within your method. That method returns true only if the caller of your method passed in a code block. If it returns false, you can raise an exception, or you can fall back to behavior that doesn’t need a block and never uses theyieldkeyword.

If your method callsyieldand the caller didn’t pass in a code block, Ruby will throw an exception:

[1, 2, 3].each
# LocalJumpError: no block given

Binding a Block Argument to a Variable

Problem

You’ve written a method that takes a code block, but it’s not enough for you to simply call the block with yield. You need to somehow bind the code block to a variable, so you can manipulate the block directly. Most likely, you need to pass it as the code block to another method.

Solution

Put the name of the block variable at the end of the list of your method’s arguments. Prefix it with an ampersand so that Ruby knows it’s a block argument, not a regular argument.

An incoming code block will be converted into aProc object and bound to the block variable. You can pass it around to other methods, call it directly usingcall, oryieldto it as though you’d never bound it to a variable at all. All three of the following methods do exactly the same thing:

def repeat(n)
n.times { yield } if block_given?
end
repeat(2) { puts “Hello.” }
# Hello.
# Hello.

def repeat(n, &block)
n.times { block.call } if block
end
repeat(2) { puts “Hello.” }
# Hello.
# Hello.

def repeat(n, &block)
n.times { yield } if block
end
repeat(2) { puts “Hello.” }
# Hello.
# Hello.

Discussion If &foo is the name of a method’s last argument, it means that the method accepts an optional block namedfoo. If the caller chooses to pass in a block, it will be made available as aProc object bound to the variablefoo. Since it is an optional argument,foowill benilif no block is actually passed in. This frees you from having to callKernel#block_given?to see whether or not you got a block.

When you call a method, you can pass in anyProcobject as the code block by prefixing the appropriate variable name with an ampersand. You can even do this on aProcobject that was originally passed in as a code block to your method.

Many methods for collections, likeeach,select, anddetect, accept code blocks. It’s easy to wrap such methods when your own methods can bind a block to a variable. Here, a method calledbiggestfinds the largest element of a collection that gives a true result for the given block:

def biggest(collection, &block)
block ? collection.select(&block).max : collection.max
end

array = [1, 2, 3, 4, 5]
biggest(array) {|i| i < 3} # => 2
biggest(array) {|i| i != 5 } # => 4
biggest(array) # => 5

This is also very useful when you need to write a frontend to a method that takes a block. Your wrapper method can bind an incoming code block to a variable, then pass it as a code block to the other method.

This code calls a code blocklimittimes, each time passing in a random number betweenminandmax:

def pick_random_numbers(min, max, limit)
limit.times { yield min+rand(max+1) }
end

This code is a wrapper method for pick_random_numbers. It calls a code block 6 times, each time with a random number from 1 to 49:

def lottery_style_numbers(&block)
pick_random_numbers(1, 49, 6, &block)
end

lottery_style_numbers { |n| puts “Lucky number: #{n}” }
# Lucky number: 20
# Lucky number: 39
# Lucky number: 41
# Lucky number: 10
# Lucky number: 41
# Lucky number: 32

The code block argument must always be the very last argument defined for a method. This means that if your method takes a variable number of arguments, the code block argument goes after the container for the variable arguments:

def invoke_on_each(*args, &block)
args.each { |arg| yield arg }
end

invoke_on_each(1, 2, 3, 4) { |x| puts x ** 2 }
# 1
# 4
# 9
# 16

See Also

  1. Recipe 8.11, “Accepting or Passing a Variable Number of Arguments”
  2. Recall from the chapter introduction that in Ruby 1.8, a code block cannot itself take a block argument; this is fixed in Ruby 1.9

Please check back another day for the continuation of this article.

by O’Reilly Media