summaryrefslogtreecommitdiff
path: root/docs/index.txt
blob: f19e8d59deb4665fe3369092f8530575eb687566 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
Tempita
+++++++

.. contents::

:author: Ian Bicking <ianb@colorstudy.com>

Status & License
================

Tempita is available under an `MIT-style license <license.html>`_.

It is actively developed, but not an ambitious project.  It does not
seek to take over the templating world, or adopt many new features.
I just wanted a small templating language for cases when ``%`` and
``string.Template`` weren't enough.

Why Another Templating Language
===============================

Surely the world has enough templating languages?  So why did I write
another.

I initially used `Cheetah <http://cheetahtemplate.org/>`_ as the
templating language for `Paste Script
<http://pythonpaste.org/script/>`_, but this caused quite a few
problems.  People frequently had problems installing Cheetah because
it includes a C extension.  Also, the errors and invocation can be a
little confusing.  This might be okay for something that used
Cheetah's features extensively, except that the templating was a very
minor feature of the system, and many people didn't even understand or
care about where templating came into the system.

At the same time, I was starting to create reusable WSGI components
that had some templating in them.  Not a lot of templating, but enough
that ``string.Template`` had become too complicated -- I need if
statements and loops.

Given this, I started looking around for a very small templating
language, and I didn't like anything I found.  Many of them seemed
awkward or like toys that were more about the novelty of the
implementation than the utility of the language.

So one night when I felt like coding but didn't feel like working on
anything I was already working on, I wrote this.  It was first called
``paste.util.template``, but I decided it deserved a life of its own,
hence Tempita.

The Interface
=============

The interface is intended to look a lot like ``string.Template``.  You
can create a template object like::

    >>> import tempita
    >>> tmpl = tempita.Template("""Hello {{name}}""")
    >>> tmpl.substitute(name='Bob')
    'Hello Bob'

Or if you want to skip the class::

    >>> tempita.sub("Hello {{name}}", name='Alice')
    'Hello Alice'

Note that the language allows arbitrary Python to be executed, so
your templates must be trusted.

You can give a name to your template, which is handy when there is an
error (the name will be displayed)::

    >>> tmpl = tempita.Template('Hi {{name}}', name='tmpl')
    >>> tmpl.substitute()
    Traceback (most recent call last):
        ...
    NameError: name 'name' is not defined at line 1 column 6 in file tmpl

You can also give a namespace to use by default, which
``.substitute(...)`` will augment::

    >>> tmpl = tempita.Template(
    ...     'Hi {{upper(name)}}',
    ...     namespace=dict(upper=lambda s: s.upper()))
    >>> tmpl.substitute(name='Joe')
    'Hi JOE'

Lastly, you can give a dictionary-like object as the argument to
``.substitute``, like::

    >>> name = 'Jane'
    >>> tmpl.substitute(locals())
    'Hi JANE'

There's also an `HTMLTemplate`_ class that is more appropriate for
templates that produce HTML.

Unicode
-------

Tempita tries to handle unicode gracefully, for some value of
"graceful".  ``Template`` objects have a ``default_encoding``
attribute.  It will try to use that encoding whenever ``unicode`` and
``str`` objects are mixed in the template.  E.g.::

    >>> tmpl = tempita.Template(u'Hi {{name}}')
    >>> tmpl.substitute(name='Jos\xc3\xa9')
    u'Hi Jos\xe9'
    >>> tmpl = tempita.Template('Hi {{name}}')
    >>> tmpl.substitute(name=u'Jos\xe9')
    'Hi Jos\xc3\xa9'

The Language
============

The language is fairly simple; all the constructs look like
``{{stuff}}``.  

To insert a variable or expression, use ``{{expression}}``.  You can't
use ``}}`` in your expression, but if it comes up just use ``} }``
(put a space between them).  You can pass your expression through
*filters* with ``{{expression | filter}}``, for instance
``{{expression | repr}}``.  This is entirely equivalent to
``{{repr(expression)}}``.  But it might look nicer to some people; I
took it from Django because I liked it.  There's a shared namespace,
so ``repr`` is just an object in the namespace.

If you want to have ``{{`` or ``}}`` in your template, you must use
the built-in variables like ``{{start_braces}}`` and
``{{end_braces}}``.  There's no escape character.

You can do an if statement with::

    {{if condition}}
      true stuff
    {{elif other_condition}}
      other stuff
    {{else}}
      final stuff
    {{endif}}

Some of the blank lines will be removed when, as in this case, they
only contain a single directive.  A trailing ``:`` is optional.

Loops should be unsurprising::

    {{for a, b in items}}
        {{a}} = {{b | repr}}
    {{endfor}}

For anything more complicated, you can use blocks of Python code,
like::

    {{py:x = 1}}
    
    {{py:
    lots of code
    }}

The first form allows statements, like an assignment or raising an
exception.  The second form is for multiple lines.  If you have
multiple lines, then ``{{py:`` must be on a line of its own and the
code can't be indented (except for normal indenting in ``def x():``
etc).

These can't output any values, but they can calculate values and
define functions.  So you can do something like::

    {{py:
    def pad(s):
        return s + ' '*(20-len(s))
    }}
    {{for name, value in kw.items()}}
    {{s | pad}} {{value | repr}}
    {{endfor}}

The last construct is for setting defaults in your template, like::

    {{default width = 100}}

You can use this so that the ``width`` variable will always have a
value in your template (the number ``100``).  If someone calls
``tmpl.substitute(width=200)`` then this will have no effect; only if
the variable is undefined will this default matter.

As a last detail ``{{# comments...}}`` doesn't do anything at all,
because it is a comment.

Still To Do
===========

Currently nested structures in ``for`` loop assignments don't work,
like ``for (a, b), c in x``.  They should.

There's no way to handle exceptions, except in your ``py:`` code.  I'm
not sure what there should be.

Probably I should try to dedent ``py:`` code.