[RAD stands for Ruby Ape Diaries, of which this is part X.] If you’re writing Web apps, and even if you’re one of the few who isn’t, you’re probably going to have write code to generate markup, HTML or XML. Historically, programmers have found this difficult, and thus there are lots of libraries that try to abstract markup away behind code (for example, my own Genx). There are tricky issues and trade-offs here, and Ruby throws them into pretty sharp focus.

The Simple Way · Generating XML isn’t that tough, you just use print statements and make sure to escape any magic syntax characters, and make really sure you’re handling the Unicode issues. Alternatively, you can use a library like Genx with primitives like startElement and addAttribute and so on.

But this is pretty low-level, and it there’s an obvious tension between the (hierarchical) structure of XML and the (linear) structure of your program.

Templating · Near as I can tell, most of the XML that’s programmatically generated out there in the real world is template-driven. PHP is probably the leader in terms of volume, if only because there are just way too many Java templating systems.

In Ruby-land, Rails’ RHTML seems to be the winner.

Content Blocks · Of course, it takes about ten seconds for an XML-savvy programmer to look at Ruby’s block structure and have the little light go on over her head saying “Hey, I’ll have a method that takes care of the start tags and end tags, and the block fills in the content.” For the Ape, I accidentally invented one of these myself for doing HTML <li> structures, the first cut looked like

  def lip
    print "<li><p>"
    yield
    puts "</p></li>"
  end

But then I realized you might want to have multiple paragraphs in your list item, and I needed a hook to put in the links to the client/server dialogs, and it grew.

If you read the Pickaxe book, they point out that the CGI module does this; check the first-edition text here and search for “Creating Forms”.

The Second Edition Pickaxe goes on to say “Although quite interesting, this method of generating HTML is fairly laborious and probably isn’t used much in practice. Most people seem to write the HTML directly, use a templating system, or use an application framework...”

I don’t know, I thought the example code looked OK. For the ultimate expression of this kind of thinking, check out _why’s Markaby; here’s an example:

 html do
   head do
     title action_name
     stylesheet_link_tag 'scaffold'
   end

   body do
     p flash[:notice], :style => "color: green" 
     self << @content_for_layout
   end
 end

Hmm... there are a couple of non-obvious things going on. The text explains:

As you can see all the normal helpers and variables are present. There is one caveat: in default Markaby, helper methods are automatically output when called. So, in the above, the stylesheet_link_tag gets output. (To turn that off, use @output_helpers = false.)

Do you understand that? I don’t. A few more months of Rubying, though, and I probably would.

Markaby is clever; some of those methods like html and body and p are defined, but some aren’t; they’re caught by missing_method, which generates tags based on the method name.

It bothers me though; some of the element methods have built-in semantics and some don’t. And you can give XML elements names that will cause you headaches in Ruby, like <first-step> (yes, you can in fact have methods with names like that using define_method and send voodoo, but you’d rather not).

RGenx? · So it occurs that it wouldn’t be that hard to do a completely generalized and kind of elegant XML generator in Ruby. Off the top of my head, I’m thinking of something like this:

  • A per-doc Namespaces thingie that you (optionally) use to declare namespace prefixes.

  • An AttList class that builds a hash of attributes you want on some element; you add attributes to it by providing their namespace URI, local-part, and value; it takes care of escaping the value.

  • An element method that takes a namespace URI, a local-part, an AttList; and a body that fills in the content.

  • A text method that takes care of escaping and output.

  • Like Genx, you’d want to set a target for the output so that the magic of << would let you build things in memory or send ’em down a pipe.

I think that’s all you’d need. In Genx I added all sorts of black magic to allow changing namespace prefixes mid-stream and so on, but that seems very un-Rubyish.

But, does the world need such a thing? Probably not.


author · Dad · software · colophon · rights
picture of the day
September 01, 2006
· Technology (87 fragments)
· · Dynamic Languages (45 more)
· · Java (123 more)
· · Ruby (93 more)

By .

The opinions expressed here
are my own, and no other party
necessarily agrees with them.

A full disclosure of my
professional interests is
on the author page.