With the recent announcement of Amrita2, I became interested in Ruby templating engines again.
Since September 2004, I’ve been using my templating engine Tangerine (small example) and have been quite confident with it. Unfortunately, the code became quite a mess and certain things (most notably, accessing the object of a higher block) were simply impossible (without extremely crude hacks using local variables, that need a ugly syntax then). In short, you couldn’t use Tangerine if you didn’t write it. :-)
Therefore, I’ve decided to largely rewrite Tangerine, and the result is now known as Kashmir (following my tradition of naming templating engines after Led Zeppelin songs…).
Kashmir tries to walk on the small path between the mess of raw evaled-ruby like ERB (you wouldn’t believe what kind of problems people have with that) and the clinical sterileness of data-driven templating like Amrita. I think I did that pretty well, though I’m not yet totally finished.
Let’s do a quick comparision:
ERB (+ 0 lines Ruby):
Not done:<br />
<% @not_done.each do |@item| %>
<%= check_box("item", "done", "onclick" =>
"document.location.href='/todo/toggle_check/#{@item.id}'") %>
<%= @item.description %>
<%= link_to("Edit", :action => "edit", :id => @item.id) %>
<%= link_to("Destroy",
{ :action => "destroy", :id => @item.id },
:confirm => "Are you sure you want to delete this entry: " +
"#{@item.description}") %>
<br />
<% end %>
Amrita2 (+ about 30 lines of Ruby):
Not done:<br />
<div id='not_done'>
<input id="item_done" name="item[done]" type="checkbox" value="1" />
<span> </span>
<span id='description' />
<span> </span>
<a id='edit_link' href="/todo/edit/">Edit</a>
<span> </span>
<a id='destroy_link' href="/todo/destroy/">
Destroy</a>
</div>
Kashmir (+ 5 lines of attr_reader
; untested as I don’t do Rails, but
you get the idea):
Not done:<br />
^not_done.each{
^(check_box("item", "done", "onclick" =>
"document.location.href='/todo/toggle_check/#{id}'"))
^description
^(link_to("Edit", :action => "edit", :id => id))
^(link_to("Destroy",
{ :action => "destroy", :id => id },
:confirm => "Are you sure you want to delete this entry: " +
"#{description}"))
<br />
}
That’s it. Fairly readable and still powerful enough not to stray pure ruby all over the place. (And please note that the Rails API was made with ERB in mind.)
Another interesting thing is that, unlike ERB, Kashmir compiles the
templates into Proc
s for faster execution. A small benchmark for
10,000 expansions of a bit bigger template:
Tangerine 9.748724
Kashmir 4.073861
ERB 11.613445
I’ll release this week, hopefully. I especially want to add a “passive API” (weird term, I really think it’s active) as described in the Amrita2 README.
require "amrita2/template"
tmpl = Amrita2::TemplateFile.new("template.html")
tmpl.expand(STDOUT) do |m|
# amrita2 passes a Module compiled from the template
# with methods for dynamic elements.
m.title("hello world")
m.body("Amrita is a html template library for Ruby")
end
NP: Led Zeppelin—Kashmir