New DRYML - Part 1

Posted by Tom on 2007-07-21

As I’ve mentioned a few times, there’s lot of breaking changes in the “new DRYML”. In some ways there’s not a huge amount of new functionality, but we really feel it’s much cleaner and more elegant now. I’ll go over the new features in this and probably one or two further posts.

If you want to try any of this out, Hobo 0.6-pre1 has been tagged in the repository:

  • svn://

It’s just a preview though and you’ll likely encounter bugs. We won’t we updating the website or releasing a gem.

Changes to current features

Let’s start by working through some features from the perspective of changing an app to work with the new DRYML.

A bunch of names changes

The hobolib directory (app/views/hobolib) is now taglibs. We wanted to make Hobo feel less like an add-on and more integrated.

<taglib> is now <include>

The part_id attribute for creating ajax parts is now simply part. Hopefully this will help avoid some confusion about the different roles in the ajax mechanism of part names and DOM IDs.

The xattrs attribute for adding a hash-full of attributes to a tag in one go is now merge_attrs.

Code attributes

Code attributes are now signified with & instead of a #, so for example:

<if q="&logged_in">

Instead of

<if q="#logged_in">

The reason for the change is that you can now use #{...} at the start of an attribute, e.g.:

<button label="#{name} is my name" />

field and with instead of attr and obj

To set the context to some field of the current context you now say field="..." instead of `attr=”…”. You can also use a new shorthand:

<repeat:comments> ... </repeat>

Notice the :comments part is missing from the close tag (that’s optional).

To set the context to any value, use with="&..." instead of obj="#..."

Bye bye parameter tags, hello templates

Parameter tags used to offer an alternate syntax to attributes for passing parameters to tags, so

<page title="My Page"/>

Was the same as

<page><:title>My Page</:title></page>

It looks great in a simple example like that, but in practice this feature was getting messy. Looking at some DRYML code, it was far from obvious why you’d be using a <:parameter_tag> in one place and a <normal_tag> in another. And what happened when you had a tag-body and parameter tags? That was even messier. And what about inner tags? Are they another name for parameter tags or something different? And then there was the mysterious content_option and replace_option. Which one should I use? Why?

So now there are no parameter tags, and instead there are template tags. Templates are a new kind of tag you can define:

  • They are distinguished form normal tags because the name is in <CamelCase>
  • They don’t have a tag-body. You never user <tagbody> in a template definition
  • Templates have attributes like regular defined tags. They also have parameters
  • A parameter is a section of content that the caller of the template can augment or replace
  • You create a parameter by adding the param attribute to any tag inside the template

Here’s an example:

<def tag="Page">
    <head param="head">
      <title param="title" />
    <body param="body">
      <div class="header" param="header" />
      <div class="main" param="main" />
      <div class="footer" param="footer" />

(note: it’s quite common that the parameter name is the same as the tag name, as in <head param="head">, in this case you can omit the parameter name, e.g. <head param>)

When calling this template, you can provide content and attributes for any of thed parameters. You can also append and prepend to parameters, or even replace parameters entirely:

  <title>My Page</title>
    <script src="..."/>
  <body onclick="runMyScript()"/>
  <header> header...
  <main> content...

To explain what’s going on in terms of “old DRYML”, it’s as if every child of <page> is a parameter tag. <title>, <head>, <body> etc. are neither defined tags or plain HTML tags. They are template parameters. The attributes and content of these tags are passed to the template and appear in the appropriate places.

Parameters can be called with various modifiers. In the above example we see <head.append>, which adds a script tag to the head section, and <footer> which replaces the footer entirely – in this case with nothing at all, so the footer is simply removed. The full set of these modifiers is:

  • append: append content to the body of the parameter
  • prepend: prepend content to the body of the parameter
  • before: insert content just before the parameter
  • after: insert content just after the parameter
  • replace: replace the parameter entirely

The power really kicks in with the fact that you can nest parameters, but I think that will have to go in part 2, along with local tags, control attributes and a few other bits and bobs…