Re-Introducing Herml
Posted: March 13th, 2009 | Author: kevin | Filed under: Erlang | View CommentsMonths ago I blogged a bit about herml, a port of Haml to Erlang. I’ve gotten quite busy at work and haven’t had much time for adding features onto herml. Fortunately for me, my co-conspirator Sean has taken up my slack and added some kick-ass features like iteration and sub-template rendering with just a teensy-weensy bit o’ help yours truly.
Where possible Sean and I have tried to err on the side of choosing an Erlang-like syntax where Haml opts for Ruby-like constructs. This is easily seen in herml’s iteration syntax:
!!!
%html
%body
%table
%tr
- [{@Message}] <- @Messages
%td
@Message
We've taken Erlang's list comprehension syntax and bent it a bit. I'm pretty satisfied with the syntax since it strikes a good balance between "Erlanginess" and readability.
This template would be rendered by calling herml_manager:execute_template/3:
herml_manager:start_link(default, "/tmp").
herml_manager:render_template(default, "looping.herml", [{"Messages, ["Message1", "Message2"]}]).
herml_manager is the integration point you should use to embed herml rendering in your code. Depending on how the manager is started it will cache templates for faster execution and monitor templates for changes and automatically reload them.
The resulting output looks like this:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<body>
<table>
<tr>
<td>Message1</td>
<td>Message2</td>
</tr>
</table>
</body>
</html>
herml can also render nested templates via herml:render/2:
%html
%body
@@herml:render('sub_main.herml')
"Normal" function calls and variables are prefixed with a single at (@) sign in herml. Prefixing a function call with two at signs (@@), as in the example above, causes herml to use the current environment when rendering the nested template. Practically this means functions which are called via @@ should, in addition to their regular argument list, take one additional argument to hold the environment. herml guarantees this will always be the last argument in the list.
I'm pretty proud of the progress we've made but there's still much more to do:
- Use a more efficient representation for compiled templates. Erlang modules, maybe?
- Add more helper functions
- Streamline
herml_manager's interface - Write more docs and examples
- And on and on and on. . .
herml is certainly not for everyone in the same way that Haml isn't universally liked. If you do like the ideas behind Haml I hope you'll give herml a look. And, if you decide to check out herml, please take a look at herml's unit tests. herml's docs are woefully lacking but the unit tests contain many template examples.
To tempt you a bit more, I'll close with a few more examples of herml's current rendering capabilities:
!!!
%html
%body
%strong
Hello world!
renders as:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<body>
<strong>
Hello, world!
</strong>
</body>
</html>
!!!
%html
%body
#message
%strong
Hello world!
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<body>
<div id="message">
<strong>
Hello world!
</strong>
</div>
</body>
</html>
!!!
%html
%body
%strong
@Message
is rendered using:
herml_manager:execute_template(herml, "msg.herml", [{"Message", "Goodbye"}])
and looks like this:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<body>
<strong>
Goodbye
</strong>
</body>
</html>