In my Ruby web projects I like to use Haml as a templating language.

Sometimes I’m using some CSS/JS framework (such as Bootstrap or Foundation). When this is the case, I normally go to it’s documentation, copy a snippet of code and paste into my templates. Then I need to convert it into Haml and here’s where Emacs+Ruby come in.

The gem

Before copying any code in this article, you’ll need to install the html2haml gem.

$ gem install html2haml

This gem will do the conversion for us.

This is how it works: we can pass a filename as an argument and it’ll give us the Haml code

$ cat example.html
<h1 class="title">hello</h1>
<div id="some_id">
  <p>some string</p>
  <p>some other string</p>
</div>

$ html2haml example.html
%h1.title hello
#some_id
  %p some string
  %p some other string

Or we can simply pass the HTML string though standard input

$ cat example.html | html2haml -s --html-attributes --erb
%h1.title hello
#some_id
  %p some string
  %p some other string

Here we need to pass the -s option to tell the gem to use standard input.

We’re also telling it to use HTML attributes syntax, which is the way I like it and to parse ERB tags.

Converting the whole buffer

Given a buffer written entirely in HTML, we can convert it to Haml by calling the following command I wrote

(defun fdx/erb-to-haml-current-buffer ()
  "run html2haml on current buffer"
  (interactive)
  (save-excursion
    (save-buffer)
    (shell-command (concat "html2haml --html-attributes --erb " (buffer-file-name)) ; " 2> /dev/null")
                   (current-buffer)
                   )))

This uses the name of the buffer to make the conversion. The shell-command command will replace the entire buffer contents with the output of the command we pass as a paramater.

Converting just a segment

But sometimes we only need a small portion of the buffer to be converted (for example when we come to an existing template and paste a small snippet).

For this purpose I wrote the following command, which is a bit more elaborate.

Notice that we need to redirect standard error to /dev/null to avoid cluttering our Haml code with errors and warnings.

(defun fdx/erb-to-haml-on-region (start end)
  "run html2haml on current region"
  (interactive "r")
  (save-excursion
    (let ((erb-string (concat
                       "\n<!-- FROM HERE -->\n"
                       (buffer-substring start end)
                       "\n<!-- UPTO HERE -->\n")))
      (let (
            (haml-string (shell-command-to-string (concat "echo \"" erb-string"\" |" "html2haml -s --html-attributes --erb"); " 2> /dev/null")
                                                  )))
        (delete-region start end)
        (insert haml-string)
        ) ; let 2
      ) ; let 1
    )
  )

For this one we use the actual region we selected and pass it the -s option.

We also insert markers telling us where the new code starts and where it ends. This is because we’re not actually dealing with indentation and, if the result is too long, we could get lost in the code.

Hope you liked today’s trick. See you later.

Saluti.