However, as I was using, I discovered a rather annoying feature. If you recall, builders depended on the method_missing feature of Ruby to implement arbitrary XML tags on the fly. But, in order for code like this …
builder.p { em("Hello World") }
to work, the em message must be sent to the builder object. Normally unadorned messages are sent to self. However, the builder object evaluated its block in a special way to hijack the value of self to point to itself.
It is really cool that we just need to mention the tag name and it automatically gets generated. But there is a downside. Suppose we replace the literal "Hello World" with a method called greet that dynamically determines the proper form of greeting. Now the code looks like this…
builder.p { em(greet) } # greet is a method
Now, not only em, but also greet gets sent to the builder. This is wrong, greet is a method defined on the current object, not the builder. To get around this, we must save the value of self outside the block and make it available under a different name. Perhaps like this…
s = self
builder.p { em(s.greet) }
As I was using builder I notice I was doing the s = self step on almost everytime I used a builder. And when I forget to use the s, I would get weird bugs in my HTML output.
Clearly I was being too clever (in my defense, I just copied the Groovy design for their builders). So I fixed the builder to use normal blocks with normal evaluation and the number of accidental bugs went way down. The greet example now reads like this under the new version of builder:
builder.p { builder.em(greet) }
Now, since is it awkward to keep mentioning the builder name over and over, it would be nice to have a shortcut. Hence builders pass themselves as a parameter to the blocks. This gives us the opportunity to use a shorter name, but only with in the block. Again, the greet example is
builder.p { |xml| xml.em(greet) }
(The shorter name isn’t a big advantage here, but is a big convenience when many tags are created.)
So, it gets back to that old adage: KISS — Keep It Simple Stupid!
Builder is availble as a gem. Version 1.0.0 has the new, simpler interface. Because Builder is a gem, you can install both versions and use either, as long as you don’t mix their usage in a single application. To use the new version (after installing), just say
require_gem 'builder', '~> 1.0'
This allows you to use any version greater than 1.0 but less that 2.0. To use the old interface, say …
require_gem 'builder', '~> 0.1'
This allows any version 0.1 or later, but rejects version 1.0 and up. The ~> operator is called the Pessimistic version constraint is is helpful when versions of software have incompatible interfaces. The RubyGems wiki has more information about pessimistic version constraint and about versioning policies.