From 550480d76ba9a5632e39461cfa81dfd92473d77f Mon Sep 17 00:00:00 2001 From: ianb Date: Tue, 24 Jul 2007 01:03:50 +0000 Subject: more docs --- docs/index.txt | 200 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 187 insertions(+), 13 deletions(-) diff --git a/docs/index.txt b/docs/index.txt index f19e8d5..50d05f5 100644 --- a/docs/index.txt +++ b/docs/index.txt @@ -93,6 +93,13 @@ Lastly, you can give a dictionary-like object as the argument to There's also an `HTMLTemplate`_ class that is more appropriate for templates that produce HTML. +You can also instantiate a template from a filename with +``Template.from_filename(filename, namespace={}, encoding=None)``. +This is like calling:: + + Template(open(filename, 'rb').read().decode(encoding), + name=filename, namespace=namespace) + Unicode ------- @@ -108,12 +115,17 @@ attribute. It will try to use that encoding whenever ``unicode`` and >>> tmpl.substitute(name=u'Jos\xe9') 'Hi Jos\xc3\xa9' +The default encoding is UTF8. + The Language ============ The language is fairly simple; all the constructs look like ``{{stuff}}``. +Substitution +------------ + 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 @@ -127,6 +139,21 @@ 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. +None, as a special case, is substituted as the empty string. + +Also there is a command for setting default values in your template:: + + {{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. You can use any +expression to the right of the ``=``. + +if +-- + You can do an if statement with:: {{if condition}} @@ -140,12 +167,20 @@ You can do an if statement with:: Some of the blank lines will be removed when, as in this case, they only contain a single directive. A trailing ``:`` is optional. +for +--- + Loops should be unsurprising:: {{for a, b in items}} {{a}} = {{b | repr}} {{endfor}} +See? Unsurprising. + +Python blocks +------------- + For anything more complicated, you can use blocks of Python code, like:: @@ -172,26 +207,165 @@ define functions. So you can do something like:: {{s | pad}} {{value | repr}} {{endfor}} -The last construct is for setting defaults in your template, like:: +As a last detail ``{{# comments...}}`` doesn't do anything at all, +because it is a comment. - {{default width = 100}} +bunch and looper +---------------- -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. +There's two kinds of objects provided to help you in your templates. +The first is ``tempita.bunch``, which is just a dictionary that also +lets you use attributes:: -As a last detail ``{{# comments...}}`` doesn't do anything at all, -because it is a comment. + >>> bunch = tempita.bunch(a=1) + >>> bunch.a + 1 + >>> bunch.items() + [('a', 1)] + >>> bunch.default = None + >>> print bunch.b + None + +This can be nice for passing options into a template. + +The other object is for use inside the template, and is part of the +default namespace, ``looper``. This can be used in ``for`` loops in +some convenient ways. You basically use it like:: + + {{for loop, item in looper(seq)}} + ... + {{endfor}} + +The ``loop`` object has a bunch of useful methods and attributes:: + + ``.index`` + The index of the current item (like you'd get with + ``enumerate()``) + ``.number`` + The number: ``.index + 1`` + ``.item`` + The item you are looking at. Which you probably already have, + but it's there if you want it. + ``.next`` + The next item in the sequence, or None if it's the last item. + ``.previous`` + The previous item in the sequence, or None if it's the first + item. + ``.odd`` + True if this is an odd item. The first item is even. + ``.even`` + True if it's even. + ``.first`` + True if this is the first item. + ``.last`` + True if this is the last item. + ``.length`` + The total length of the sequence. + ``.first_group(getter=None)`` + Returns true if this item is the first in the group, where the + group is either of equal objects (probably boring), or when you + give a getter. getter can be ``'.attribute'``, like + ``'.last_name'`` -- this lets you group people by their last + name. Or a method, like ``'.birth_year()'`` -- which calls the + method. If it's just a string, it is expected to be a key in a + dictionary, like ``'name'`` which groups on ``item['name']``. + Or you can give a function which returns the value to group on. + This always returns true when ``.first`` returns true. + ``.last_group(getter=None)`` + Like ``first_group``, only returns True when it's the last of + the group. This always returns true when ``.last`` returns true. + +Note that there's currently a limitation in the templating language, +so you can't do ``{{for loop, (key, value) in looper(d.items())}}``. +You'll have to do:: + + {{for loop, key_value in looper(d.items())}} + {{py:key, value = key_value}} + ... + {{endfor}} + +HTMLTemplate +============ + +In addition to ``Template`` there is a template specialized for HTML, +``HTMLTemplate`` (and the substitution function ``sub_html``). + +The basic thing that it adds is automatic HTML quoting. All values +substituted into your template will be quoted unless they are +specially marked. + +You mark objects as instances of ``tempita.html``. The easiest way is +``{{some_string | html}}``, though you can also use +``tempita.html(string)`` in your functions. + +An example:: + + >>> tmpl = tempita.HTMLTemplate('''\ + ... Hi {{name}}! + ... {{title|html}}''') + >>> name = tempita.html('') + >>> href = 'Attack!">' + >>> title = 'Homepage' + >>> tmpl.substitute(locals()) + 'Hi !\nHomepage' + +It also adds a couple handy builtins:: + + ``html_quote(value)``: + HTML quotes the value. Turns all unicode values into + character references, so it always returns ASCII text. Also + it calls ``str(value)`` or ``unicode(value)``, so you can do + things like ``html_quote(1)``. + + ``url(value)``: + Does URL quoting, similar to ``html_quote()``. + + ``attr(**kw)``: + Inserts attributes. Use like:: + +
+ + Then it'll put in something like ``width="{{width}}" + class={{div_class}}``. But any attribute that is None is left + out entirely. + +Extending Tempita +================= + +It's not really meant for extension. Instead you should just write +Python functions and classes that do what you want, and use them in +the template. You can either add the namespace to the constructor, or +extend ``default_namespace`` in your own subclass. + +The extension that ``HTMLTemplate`` uses is to subclass and override +the ``_repr(value, pos)`` function. This is called on each object +just before inserting it in the template. + +Two other methods you might want to look at are ``_eval(code, ns, +pos)`` and ``_exec(code, ns, pos)``, which evaluate and execute +expressions and statements. You could probably make this language +safe with appropriate implementations of those methods. Still To Do =========== -Currently nested structures in ``for`` loop assignments don't work, -like ``for (a, b), c in x``. They should. +* 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. + +* There should be some way of calling a function with a chunk of the + template. Maybe like:: -There's no way to handle exceptions, except in your ``py:`` code. I'm -not sure what there should be. + {{call expr}} + template code... + {{endcall}} -Probably I should try to dedent ``py:`` code. + That means ``{{expr(result_of_template_code)}}``. But maybe there + should be another assignment form too, if you don't want to + immediately put the output in the code. And then you get methods. + Is this going too far? -- cgit v1.2.1