This is an implementation of HAML for Python (2.5 through 2.7).
I have kept as much of the same syntax as I could, but there are some Rubyisms built into HAML that I simply cannot replicate. I have tried to stay true to the original features while adapting them to be Pythonic.
This package essentially cross-compiles PyHAML code into a Mako template. Ergo, all of your standard Mako syntax also applies to content which does not match any of the HAML syntax.
A simple PyHAML template:
#profile
.left.column
#date= print_date
#address= current_user.address
.right.column
#email= current_user.email
#bio= current_user.bio
A Mako template to do the same thing:
<div id="profile">
<div class="left column">
<div id="date">${print_date}</div>
<div id="address">${current_user.address}</div>
</div>
<div class="right column">
<div id="email">${current_user.email}</div>
<div id="bio">${current_user.bio}</div>
</div>
</div>
import haml
import mako.template
if your_templates_are_in_a_directory:
# Build the template lookup.
lookup = mako.lookup.TemplateLookup(["various", "template", "paths"],
preprocessor=haml.preprocessor
)
# Retrieve a template.
template = lookup.get_template('example_template.haml')
else: # You have some strings...
# Write your HAML.
haml_source = '.content Hello, World!'
# Build your template.
template = mako.template.Template(haml_source,
preprocessor=haml.preprocessor
)
# Render!
print template.render()
Herein lies our differences to the HAML reference.
Python syntax must be used as if calling a function that takes keyword arguments. Eg.:
%ul
- for i in range(5):
%li(id=['item', str(i)]) ITEM ${i}
renders to:
<ul>
<li id="item_0">ITEM 0</li>
<li id="item_1">ITEM 1</li>
<li id="item_2">ITEM 2</li>
<li id="item_3">ITEM 3</li>
<li id="item_4">ITEM 4</li>
</ul>
If you want to pass in a class, use the keyword "class_". If you want to use attribute names with dashes, use camel case instead and it will be converted for you:
%meta(httpEquiv="Content-Type", content="text/html;charset=UTF-8")
renders to:
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
If you want to pass in any other non-identifier attribute names, you can expand a mapping in place. Eg.:
%div(class_='content', **{'not-valid-python': 'value'}) content
renders to:
<div class='content', not-valid-python="value">content</div>
You can also pass in mapping objects as positional objects. Eg.:
- attrs = dict(a='one', b='two')
%a(attrs)/
renders to:
<a a="one" b="two" />
We only output the XHTML style attribute. Eg.:
%input(type='checkbox', checked=True)
to
<input type="checkbox" checked="checked" />
Clearly this is now evaluating Python. It is evaluated in the Mako runtime context.
We are using Mako to do the heavy lifting here.
We have function delaration/calling syntax similar to SASS-style mixins. E.g.:
@make_ol(*args)
%ol - for arg in args:
%li ${arg}
+make_ol(1, 2, 3)
renders to:
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
We don't supply any filters, but the mechanism is there to take callables from the runtime globals to use as a filter. You can also use Mako expression interpolation. Eg.:
-! def to_upper(x):
return x.upper()
- value = 123
:to_upper
%p The syntaxes, they do nothing!
#id x
.class x
- statement
/ comment
${value}
Haven't gotten around to these yet...