Custom Haml filters in a Sinatra application

04 March 2014

I’ve been working on a little ruby/sinatra application which involves displaying content rendered from quite a complex proprietary XML format. I decided to use Haml as my templating engine for rendering the views, and added a custom filter to turn the proprietary content into XML. Here’s how they work.

Haml uses filters to transform foreign markup in a view. For example:

%p
  :markdown
    Lorem ipsum *dolor* sit amet

renders as

<p>Lorem ipsum <em>dolor</em> sit amet</p>

By default the Haml gem includes filters for dealing with common markup types like markdown or coffee script. But if you’re working with some other type of non-standard markup then you can add your own custom filter to process it.

Imagine that your markup format looks like this - for convenience I’ll call it ‘Pipemark’:

Lorem ipsum |boldface|dolor|end boldface| sit amet,
consectetur |boldface|adipisicing|end boldface| elit

You make a custom filter by building on top of the Haml base filter class. Your filter needs to have a render method for converting the markup into HTML. For ‘Pipemark’ that’s just a simple substitution:

module Haml::Filters::Pipemark
  include Haml::Filters::Base
 
  def render(input)
    output = input.gsub(/\|boldface\|(.*?)\|end boldface\|/,
                       '<strong>\1</strong>')
  end
 
end

Pass a bit of ‘Pipemark’ data to your view, e.g. for my Sinatra app:

get '/example' do
  data = "Lorem ipsum |boldface|dolor|end boldface| sit amet, 
          consectetur |boldface|adipisicing|end boldface| elit"
  haml :example, :locals => {:quote => data}
end

To render it all you have to do is invoke this filter in your Haml template with a colon:

%div
  :pipemark
    #{quote}

which produces

<div>Lorem ipsum <strong>dolor</strong> sit amet, 
	consectetur <strong>adipisicing</strong> elit</div> 

The render method in my actual example used some xslt to transform xml into html, but the principle was the same.