A few weeks ago I heard about Merb on the RailsEnvy podcast and sat down to give it a try. I have some limited Ruby on Rails experience, mostly little things, and just wanted to play with the new Ruby web-framework. If you’re not familiar with Merb, it provides a lot of the same niceties as Rails, but while remaining completely agnostic about choosing things like JavaScript frameworks, Object-relational models, and template engines. This is how I discovered HAML (XHTML Abstraction Mark-up Language) or Markup Haiku, as the developer puts it. I’ll probably write about my experience with Merb in a future post, today I’m going to write about HAML.
So what’s HAML?
HAML’s designer calls it markup haiku. It’s a templating language that stresses structure and readability. HAML is a shorthand mark-up for defining the structure of a web page. It is a drop-in replacement for RHTML templates in Rails, although it also works in Merb and there is currently a PHP library in development.
What’s it look like?
Here’s a very basic page written in HAML. It’s important to note that HAML is space-sensitive, meaning that each nested element is indented with 2 spaces from the previous line. Likewise the resulting HTML will be well-formed and indented with 2 spaces. This may not be obvious in the output below.
!!!XML
!!!
%html{html_attrs}
%head
%title HAML Page
%link{ :rel => "stylesheet", :type => "text/css", :href => "example.css"}
%body
%h1 HAML Example
Notice that html elements are marked with the % character. This is not just limited to valid HTML elements, any XML element can be noted this way. Notice that there’s no ending tags, HAML handles this automatically for you…very nice. If you’re a ruby developer, the stylesheet link line will look familiar to you. If you’re a python, perl, or PHP developer, this may look a little unfriendly, but should be understandable. The first two lines of the markup are my favorite part of writing HAML. As you will see below, those lines translate into the XML and DOCTYPE lines of the resulting XHTML document. Since I have to look-up these lines every time I write a new page, I love this markup. That’s enough suspense, here’s what it looks like in HTML:
<?xml version='1.0' encoding='utf-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>HAML Page</title>
<link href='example.css' rel='stylesheet' type='text/css' />
</head>
<body>
<h1>HAML Example</h1>
</body>
</html>
What I Like About HAML
I am a stickler for readable code, so I really like both the HAML and resulting HTML. By forcing designers to indent each block of code HAML ensures that the code is readable and maintainable and also makes finding structural bugs easy. HAML also provides a nice shorthand for styled divs, rather than <div class=”foo”>, you can simply type .foo. This notation ought to look familiar to anyone who has ever programmed CSS. As long as the elements do not contain a lot of attributes, HAML’s shorthands are very convenient. Everything about HAML makes defining the structure simpler than RHTML (or PHP, for that matter).
What I Dislike About HAML
I have to stress the fact that HAML is for defining page structure. There’s no notion of inline elements (think <em>, <strong>, <a>) in HAML, only blocks. You can put standard HTML tags in the mark-up, and I’ve found it necessary to do this many times. For the sake of completeness, I’ve tried using HAML to maintain a static HTML page (admittedly, outside of HAML’s primary mission) and found mixing inline HTML and HAML structure a bit tedious. Problems don’t stop at inline elements, any element that require a lot of attributes, like an <a>, <img>, or <script> tag, are far more complex in HAML than in HTML. If you’re using CSS+HTML, this probably doesn’t affect your code too much, but it’s important to mention. In addition to these limitations, I find the choice to require exactly 2 spaces a bit arbitrary. It was probably a decision to make the parser simple and quick, but python, which also uses space-delimited blocks, is not so strict and has a very fast parser. This isn’t a big issue to me, since I generally use two spaces anyway, but if you’re used to 4 spaces or tabs, you may need to adjust. Finally, on several occasions the HAML parser on my machine would not parse the code, but the online parser would. The error messages from the local parser weren’t always helpful, but it tried its best to guide me to my error. It was frustrating, however, that the online and offline parsers had different behaviors.
Final Verdict
I must admit, when I first saw HAML, I thought to myself “What’s the point?” I was quickly won over. For what it is, a simple template language and RHTML replacement, HAML is very good. I love the quick shorthands and neat code. Its limitations are few and easy to overcome. It’s now my template language of choice for Rails and Merb. I’m reserving judgment about using it in PHP applications, but as the PHP library matures, I’d like to give this a shot. I’d really love to see a tool that will let me use HAML templates to easily maintain static HTML pages. If you’ve not tried HAML, I really do suggest it.