I’d like to take a tour of Mako, Mike Bayer’s excellent Python template engine. First, a few comments on my column on adding event behaviours to Elixir:
1. The pastebin code has a few mistakes (I’m sure those interested will have spotted them); I noticed them of course just after I posted the code, but haven’t found any way to correct it (unlike in djangosnippets, for example, there does not seem any way to edit your pasted code).
Updated: here is the improved code.
2. Comments on the Elixir google group have been quite positive. As pointed out, the code could be definitely improved, it’s a bit repetitive for starters.
3. In the same vein, someone has provided an excellent example of adding validation DSLs to Elixir.
Now, on to Mako. Mako is loosely based on Myghty, which itself is based on Mason, a Perl template engine of some vintage that has been used for example by Amazon. Myghty was pretty cool, I had only used it in “hello world” stuff but it seemed a lot easier than for example Cheetah. Cheetah had a lot of hassles such as having to precompile master templates which made it a bit of a PITA at times (that might have been fixed by now; it’s been a while since I have used it).
Mako is a text-based template engine, unlike Kid or Genshi; you can therefore use it in producing non-SGML output such as email contents or JavaScript and CSS. It has a number of tags for doing stuff like inheritance, control flow syntax (same as Python, but with closing tags like endif for getting round the significant whitespace issue) and variable inclusion. The syntax and tags are very simple and a Python coder (or even web designer) should get up to speed with Mako very quickly.
The really nifty thing about Mako, however, is that it combines a lot of the best ideas from other template engines into one package. For example, inheritance is borrowed from Myghty, and also Django/Jinja.
Some template designers don’t like too much logic in their code – Django for example. In Django, using their standard template engine makes it hard to do anything more than if/else conditionals and for loops. This is by intention; templates are for designers only, and it enforces MVC – you have to move code into the controller (or Django “view”) or special tags.
The way I see it, there is no problem with logic in the view / template layer – as long as that code concerns itself only with presentation logic. Often however that logic can get convoluted and repetitive, and you want to cordon it off into a function. With Mako you can do this with namespaces. A namespace is essentially just a library of template code.
For example, say you have a Mako file, formutils.mako, which looks something like this:
<%def name="label(field, content)">
<label for="${field}">${content}</label>
</%def>
Now in another file, you include the code in formutils.mako like so:
<%namespace name="form" file="/formutils.mako" />
Now you can call the functions defined in formutils.mako just like any other Python function:
${form.label('name', 'Your name:')}
For people who know Rails, this kind of like partials, but with simpler syntax. If you are using Pylons you can use helpers, but Mako namespaces are better if the code is more HTML than Python.
Another neat idea is template inheritance. In large web apps this is important because your site is often broken down into different modules or sections, each with 90% the same layout but maybe an extra stylesheet, menu, title etc. Some template engines don’t support inheritance or do it badly: Rails for example has layouts, but layouts cannot be (as far as I know) chained in any way, so you end up cutting and pasting code or putting in lots of conditionals; you can only replace the main body of the template, not selected pieces. They are also dependent on the controller layer, which kind of breaks MVC. In Mako you have a similar directive to namespaces:
<%inherit file='/base.mako' />
Now you can define functions in the same way in your base.mako file, for example:
<%def name='title()'>Hi de ho!</%def>
and call them in your template HTML code:
<title>${self.title()}</title>
(note the use of self, which is important if you want inheritance to work).
Any template which inherits base.mako should output:
<title>Hi de ho!</title>
However, if you want to change the title you just need to override the title() function in your template:
<%def name='title()'>Ho de hi!</%def>
Then you get:
<title>Ho de hi!</title>
When you are building a large, complex web site this is really, really useful. I’m working on a large Rails project right now and this simple feature would be so handy.
One final word : Mako performance rocks, see the Mako home page for a comparative study. Mako out-performs even Cheetah and Django.