codahale.com٭blog

This is my old blog. My current writing is here: codahale.com

A Ruby HOWTO: Writing A Method That Uses Code Blocks

One of the first things about Ruby which absolutely delighted me was its implementation of code blocks. They take a potentially ugly construct–anonymous delegates–and turn them into a readable, time-saving structure:


chunky_bacon = %w(moo hoo ha ha)
chunky_bacon.each { |cb|
	puts "--> #{cb}"
}

So how can we use this wonderful little bit of functionality in our own code? Well, break out a text editor and a terminal window, because it’s time to write some Ruby! Until the Tryptophan kicks in and we lurch around, belly exposed and bulging, wondering how long it’ll take until we’ve digested enough food to go back for another slice of pie. Happy Thanksgiving!

Wait… why are code blocks cool?

Okay, maybe there’re a few skeptics out there who are thinking to themselves “Gosh, Coda… this all sounds super-swell, but I’m not just not convinced that the classes I write could use code blocks.” Fine, Diogenes, here’s a short list of areas in which code blocks are totally wicked:

  • Transactions: Do you have something which needs to be done atomically? All-or-nothing commit? Rollback-if-accidentally-set-on-fire? Code blocks are, like, made for you.
  • Iterators: Got a bunch of stuff? Want to go through it, one at a time? Yeah… code blocks.
  • Wrappers & Templates: Oh, you’re still using string substitution? How cute… code blocks!

Got it? Good. Code blocks!

Yay! Code blocks! Err… crap.

If you’re anything like me, you immediately jumped to the RDoc info for the Ruby Core, and took a gander at the listing for Array#each:

array.each {|item| block } → array

That’s not helpful. Luckily, I am.

Example One: A Basic Code Block

Here is an insanely simple method which will execute any code block passed to it:


def simple
	puts 'Here comes the code block!'
	yield
	puts 'There was the code block!'
end
simple { puts 'Hooray! The code block is here!' } »
Here comes the code block!
Hooray! The code block is here!
There was the code block!

Just that simple. The important bit is the yield statement, which actually executes the code block. If no code block is passed, Ruby raises an exception:


simple » LocalJumpError: no block given in 'simple'

Example Two: An Optional Code Block

Making a code block optional is simple as hell, too. Dig it:


def optional
	puts 'A code block isn\'t required, but it\'s nice.'
	yield if block_given?
	puts 'I\'m happy either way, really.'
end

Kernel#block_given? is a method which returns true if yield actually has something to do. Neat, huh?

Example Three: A Code Block With Parameters

Code blocks by themselves are fun, sure, but we need to beef this up if we’re going to get anything done. Let’s write a method that passes a few parameters to a code block:


def parameters
	puts 'Here, have two random numbers.'
	yield rand(10), rand(50) if block_given?
	puts 'Now say thank you!'
end
parameters { |x,y| puts "#{x}, #{y}" } »
Here, have two random numbers.
8, 21
Now say thank you!

As you can see, the code block acts as a method with two parameters. yield is passed the two parameters, which are in turn sent to the code block. This, of course, raises the question: what the hell happens when you pass it a code block with the wrong number of parameters?
First, let’s try it using a code block with no parameters:


parameters { puts 'No variable!' } »
Here, have two random numbers.
No variable!
Now say thank you!

Now let’s try it using a code block with just one parameter:


parameters { |x| puts x } »
Here, have two random numbers.
warning: multiple values for a block parameter (2 for 1)
1
17
Now say thank you!

Didn’t expect that, did you? Two important things happened:

  1. A warning was raised over the number of parameters.
  2. The code block was called twice: once for each object passed to yield. Jacob Fugal points out that the code block isn’t called twice, but rather Ruby passes the two values as an array, which when fed through puts, is printed on multiple lines.

It’d be nice to be able to write a more flexible method, one which could tell how many parameters a code block will accept and then act accordingly. Hmm…

Example Four: A Code Block With A Variable Number of Parameters

For this next trick, we’ll be taking advantage of a not-widely-publicized feature of Ruby–the ampersand. This little tidbit of information is found nestled in the back of the Pickaxe book:

If the last parameter in a method definition is prefixed with an ampersand [...], Ruby looks for a code block whenever that method is called. That code block is converted to an object of class Proc and assigned to the parameter. You can then treat the parameter as any other variable.

Since it’s a Proc object, we can use Proc#arity to figure out how many parameters the code block has. So let’s try this:


def variable(&block)
	puts 'Here goes:'
	case block.arity
		when 0
			yield
		when 1
			yield 'one'
		when 2
			yield 'one', 'two'
		when 3
			yield 'one', 'two', 'three'
	end
	puts 'Done!'
end

We’re declaring block as a method parameter here so we’ll have more access to it. The ampersand in front indicates that it’s going to be take the code block and put it into the Proc object block. Once we’ve got block we can see how many parameters it takes (Proc#arity) and deal with it accordingly. So how does that work?


variable {} »
Here goes:
Done!


variable { |x| puts x } »
Here goes:
one
Done!


variable { |x,y| puts x, y } »
Here goes:
one
two
Done!


variable { |x,y,z| puts x, y, z } »
Here goes:
one
two
three
Done!

Works like a charm.

Example Five: A Useless Transaction

Now let’s try to do something useful. Let’s say we’re writing something which needs to happen in an all-or-nothing, atomic fashion. Either the whole thing works, or none of it does. Just for kicks, let’s imagine we’re in charge of naming someone who’s super-angsty about particular names. If they don’t like that name, they won’t change it, but they’ll get super-angsty. We’d like to come up with a way for us to give them a name, and if they don’t like it, go back to their old one. But we want this to be Ruby-tastic, so check it out:


class AngstyNamedPerson
	attr_reader :name

	@@hated_names = %w(Leroy Sparkles Thaddius)

	def name=(new_name)
		@name = new_name
		raise "I have probems with being named #{@name}." if @@hated_names.include? new_name
	end

	def initialize(name)
		@name = name
	end

	def transactionally(&block)
		old_name = @name
		begin
			yield self if block_given?
		rescue
			@name = old_name
		end
	end
end

mr_pibbles = AngstyNamedPerson.new('Mr. Pibbles')

We’re putting a lot of tricks into this one, but AngstyNamedPerson#transactionally is the important bit. It backs up the existing name, and then provides the code block access to the AngstyNamedPerson object being referenced. If that doesn’t work, it reverts back to the old name. Just for kicks, I’ve created an instance with the name “Mr. Pibbles,” because I’m mean like that. What happens when we try to name him Sparkles?


mr_pibbles.name = 'Sparkles' »
in `name=': I have probems with being named Sparkles. (RuntimeError)
puts mr_pibbles.name » Sparkles

Hmm. No good. Raised an error and the bad name has already been saved. Thanks to code blocks, there’s a better way of doing this:


mr_pibbles.transactionally do |anp|
	anp.name = 'Leroy'
end
puts mr_pibbles.name » Mr. Pibbles

Booyeah!

Example Six: A Useless Iterator

Okay, now let’s imagine that we want to make a type of Array which has a special method which allows us to iterate through a subset of its elements. Why? Boy, this is Thanksgiving, and I’ll be goddamned if we’re not gonna act like a family on a day of thanks! We’re a family and we’re gonna act like one! *takes another gulp of whisky* Now pass the gravy:


class StupidArray < Array
	def for_each_but_not_all(range, &block)
		range.each do |i|
			yield self[i]
		end
	end
end

sa = StupidArray.new
sa << 'yay' << 'moo' << 'whee' << 'eek' << 'shaz' << 'ding'
sa.for_each_but_not_all(1..3) { |x|
	puts x
}

Neat, huh?

Example Seven: A Useless Template

And finally, you can make templating systems using code blocks:


class SimpleTemplate < Array
	def display_as_html
		puts '<html>'
		puts '<head><title>Yay For Arrays</title></head>'
		puts '<body>'
		self.each { |x|
			puts(yield(x))
		}
		puts '</body>'
		puts ''
	end
end

And it does this:


st = SimpleTemplate.new
st << "yay" << "moo" << "whee" << "eek" << "shaz" << "ding"
st.display_as_html { |x|
	"<span class=\"number\">#{x}"
} »
<html>
<head><title>Yay For Arrays</title></head>
<body>
<span class="number">yay</span>
<span class="number">moo</span>
<span class="number">whee</span>
<span class="number">eek</span>
<span class="number">shaz</span>
<span class="number">ding</span>
</body>
</html>

Go Forth And Multiply

Alrighty, fools. Now you know, and now you can use code blocks in your own code. Yay!

6 Responses to “A Ruby HOWTO: Writing A Method That Uses Code Blocks”

  1. Jacob Fugal Says:

    I know this post is old, but it just got posted on dzone (which is sucked into the Artima Ruby Buzz feed). You’ve got an important mistake in section 3 when you create the +simple+ method which yields two values, but then call the method with a block that only takes one parameter. In your explanation you state that:

    The code block was called twice: once for each object passed to yield.

    This isn’t correct. Instead, what happened was that the multiple values were squeezed into the one parameter the code block expected. As an example, try changing the body of your block to use +p+ instead of +puts+, ie:

    
      def parameters
        puts 'Here, have two random numbers.'
        yield rand(10), rand(50) if block_given?
        puts 'Now say thank you!'
      end
      parameters { |a| p a } »
      Here, have two random numbers.
      [6, 34]
      Now say thank you!
    

    The behavior you saw before where it looked like it was printing each number separately was just due to the default stringification of Arrays!

  2. Jacob Fugal Says:

    Apparently my guess at acceptable HTML for comments was wrong. Just imagine that code up above is in a <pre> tag. :)

  3. Coda Says:

    Thanks for the save, Jacob!

    I wrote this as much as an exercise in learning as an example, and I was kind of surprised to see this get picked up by dzone. Needless to say, my level of knowledge regarding Ruby has picked up quite a bit in the past 6 months. ;-)

  4. datsoc.com » Blocks are cool Says:

    [...] Info on blocks Participate! Leave your [...]

  5. Sean’s Mental Walkabout » Blog Archive » Pidgin, Network Manager, Dbus, Ruby, oh my! Says:

    [...] proxy interface object sets up a signal using 2 parameters and a code block. Every time there is a DeviceNowActive signal on the system bus, I recycle pidgin. Pretty straight [...]

  6. Dynamic programming using closures in Ruby « Blah Blah Blah Says:

    [...] http://blog.codahale.com/2005/11/24/a-ruby-howto-writing-a-method-that-uses-code-blocks/ [...]