1. Technology
You can opt-out at any time. Please refer to our privacy policy for contact information.

Block Parameters and Yielding

By

Block parameters allow you to pass small anonymous methods to a method call. It's so common an idiom in Ruby that it's replaced "for" loops as preferred idiom for iteration. When was the last time you saw a for keyword in Ruby? You rarely see it, Rubyists use the each method, possibly on a Range object if a series of numbers is needed.

The Idiom

Just to refresh your memory, here's what this idiom looks like. Here we have an Array of names, and instead of composing a loop using a keyword, we use the Array's each method to iterate over the names.


#!/usr/bin/env ruby

names = [
  "Robert A. Maes",
  "Virginia S. Herren",
  "Edna R. Ross",
  "Gerard C. Austin"
]

names.each do|name|
  puts "Currently processing #{name}"
end

Using The Idiom in Your Code

This is such a common idiom, it's used in just about all Ruby code. But how does it work? How can you leverage this feature for your own use? All methods in Ruby can accept an additional Proc object, usually generated by the method calling syntax above. To call this anonymous Proc object, you use the yield keyword, which works much like a method call itself, allowing you to call the Proc object as a method complete with an argument list.


#!/usr/bin/env ruby

def yield_and_print
  # The yield keyword will call the
  # implicit Proc object
  ret = yield

  puts %Q{The block yielded "#{ret.to_s}"}
end

yield_and_print{ 10 }
yield_and_print{ "Hello" }
yield_and_print do
  (10 + 20) / 3
end

Yielding Arguments

That's not too interesting, but remember that yield can also pass arguments to the Proc. The blocks passed will use the familiar syntax for defining arguments to blocks using the | (pipe, or vertical bar) characters.


#!/usr/bin/env ruby

def yield_arg_to(arg)
  ret = yield(arg)
  puts %Q{The block yielded "#{ret}" when passed "#{arg}"}
end

yield_arg_to(10) {|i| i * 1337 }
yield_arg_to("Hello") {|s| s + " World" }
yield_arg_to(45.2) do|r|
  "The circumference is #{3.14 * 2 * r}"
end

Explicit Proc Names

To avoid any confusion, you can explicitly name this implicit Proc object. If the last argument in your argument list begins in a & (ampersand), it will not act as a normal object, but rather a name for the implicit Proc object.


#!/usr/bin/env ruby

def yield_arg_to(arg, &proc)
  ret = proc.yield(arg)
  puts %Q{The block yielded "#{ret}" when passed "#{arg}"}
end

yield_arg_to(10) {|i| i * 1337 }
yield_arg_to("Hello") {|s| s + " World" }
yield_arg_to(45.2) do|r|
  "The circumference is #{3.14 * 2 * r}"
end

Passing Procs Explicitly

Say you have a Proc stored in a variable, and you wish to call a method that takes a block (an implicit Proc argument). By simply trying to pass this Proc object as an argument, it will pass it as a normal argument, most likely causing the method to raise an ArgumentError. Instead, pass the Proc object as the last argument in the method call and put a & (ampersand) on the beginning of its variable name.


#!/usr/bin/env ruby

# Print anything that is passed to it
printer = Proc.new{|s| puts s }

(0..10).each(&printer)
  1. About.com
  2. Technology
  3. Ruby
  4. Beginning Ruby
  5. Block Parameters and Yielding

©2014 About.com. All rights reserved.