Eric Radman : a Journal

Programming Documents with Haml

Haml is an templating language for writing HTML. Over the past decade the capabilities of HTML+CSS have become good enough for nearly everything: letters, my resume, pages on this site, even forms.

Haml 6 uses a completely incompatible library and command line. To work around this set the gem install to version 5.2.2.

Haml combines a set of valuable features:

  1. A notation that mirrors HTML
  2. Blocks of text can be interpreted using custom filters
  3. Ad-hoc scripting

Mirroring HTML

Notwithstanding the name, Haml is not very abstract. It is mostly a 1:1 representation of the HTML it generates

    %title A Letter
    %link{:href=>"main.css", :rel=>"stylesheet", :type=>"text/css"}/
      - require 'date'
      = "Last updated on " +"%B %d, %Y")

Setting a class and id properties have their own syntax

/ class="first"

/ id="content"

Ruby code can be run directly, and Haml::Engine can be used directly to process another template.


In Haml, Ruby itself is also not abstracted, which gives us the ability to invent new mechanisms. One simple scheme I have used is to read extra arguments on the command line


This means Makefile can easily communicate a source file to read

.SUFFIXES: .haml .html

SOURCES != ls posts/*.haml | awk 'sub("\.haml$$", ".html")'

    haml template.haml $@ $<


Perhaps the most important feature of template language is the ability to process and transform blocks of text

# link.rb
module Haml::Filters::Link
  include Haml::Filters::Base

  def render(text)
    %q|<a href="#{text}">#{text}</a>|

This function processes a block of text as the input

  Visit my home page at

And to compile add an include path and a reference to the library

haml -I . -r link my.haml

Built-in Tests

Builtin self tests are an excellent means of writing filters. Haml filters are simple Ruby modules, so we can build simple self-tests without having to instantiate an object

require 'haml'

module Haml::Filters::Link
    def render(text)
        # ...

if __FILE__ == $0
    include Haml::Filters::Link

    out = render("")
    expected = %q|<a href=""></a>|

    if expected == out
        puts "PASS"
        puts <<~MESSAGE
          expected: #{expected}
          got     : #{out}


Nearly every other templating system seems to have difficulty controlling whitespace, and Haml is no exception.

The normal way to add a comma or a period after another tag is to use the and succeed method. (See also surround). In this example I want a period immediately following the hyperlink

Send comments to
= succeed '.' do

Another technique for controlling whitespace is to append > to trim whitespace and then add non-breaking spaces where needed

  %span.Prompt> $&nbsp;
  ls *.css *.html | entr reload-browser Firefox

Note that Haml allows HTML to be mixed in directly. This is a wonderful option whenever raw HTML provides a readable or correct solution to formatting.