[[list_of_tests]]
+Global Functions
+================
+
+Test functions and filter functions live in their own namespace. Global
+functions not. They behave like normal objects in the context. Beside the
+functions added by the application or framewhere there are two functions
+available per default:
+
+`range`
+
+ Works like the python `range function`_ just that it doesn't support
+ ranges greater than ``1000000``.
+
+`debug`
+
+ Function that outputs the contents of the context.
+
Loops
=====
{% endfor %}
</ul>
-*Important difference from Python:* the optional ``else`` block is only
+*Important* Contrary to Python is the optional ``else`` block only
executed if there was no iteration because the sequence was empty.
Inside of a `for` loop block you can access some special variables:
{{ undefined.attribute().attribute_too[42] }}
still returns `undefined`.
+Escaping
+========
+
+Sometimes you might want to add Jinja syntax elements into the template
+without executing them. In that case you have quite a few possibilities.
+
+For small parts this might be a good way:
+
+.. sourcecode:: jinja
+
+ {{ "{{ foo }} is variable syntax and {% foo %} is block syntax" }}
+
+When you have multiple elements you can use the ``raw`` block:
+
+.. sourcecode:: jinja
+
+ {% raw %}
+ Filtering blocks works like this in Jinja:
+ {% filter escape %}
+ <html>
+ <code>goes here</code>
+ </html>
+ {% endfilter %}
+ {% endraw %}
+
Internationalization
====================
don't have the indicator variable on position 1 you have to tell the `pluralize`
tag the correct variable name.
-Inside translatable blocks you cannot use blocks or expressions. The variable
-print syntax (``{{ variablename }}``) can just be used to insert the variables defined
-in the ``trans`` header.
+Inside translatable blocks you cannot use blocks or expressions (however you can
+still use the ``raw`` block which will work as expected). The variable
+print syntax (``{{ variablename }}``) is the only way to insert the variables
+defined in the ``trans`` header. Filters must be applied in the header.
.. admonition:: note
{% endif %}
.. _slicing chapter: http://diveintopython.org/native_data_types/lists.html#odbchelper.list.slice
+.. _range function: http://docs.python.org/tut/node6.html#SECTION006300000000000000000
"""
from jinja import Environment
from jinja.parser import Parser
+from jinja.lexer import Lexer
from jinja.translators.python import PythonTranslator
-__all__ = ['e', 't', 'p']
+__all__ = ['e', 't', 'p', 'l']
e = Environment()
t = e.from_string
def p(x):
print PythonTranslator(e, Parser(e, x).parse()).translate()
+
+def l(x):
+ for item in e.lexer.tokenize(x):
+ print '%5s %-20s %r' % item
# global parsing rules
self.rules = {
'root': [
+ (c('(%s\s*raw\s%s)(.*?)(%s\s*endraw\s*%s)' % (
+ (e(environment.block_start_string),
+ e(environment.block_end_string)) * 2)),
+ (None, 'data', None), None),
(c('(.*?)(?:%s)' % '|'.join([
'(?P<%s_begin>%s)' % (n, e(r)) for n, r in root_tag_rules
])), ('data', '#bygroup'), '#bygroup'),
for idx, token in enumerate(tokens):
# hidden group
if token is None:
- g += m.group(idx)
+ g = m.group(idx)
if g:
lineno += g.count('\n')
continue
# here the only token we should get is "data". all other
# tokens just exist in block or variable sections. (if the
# tokenizer is not brocken)
- elif token == 'data':
+ elif token in 'data':
result.append(nodes.Text(lineno, data))
# so this should be unreachable code
Return a comment that helds the node informations or None
if there is no need to add a debug comment.
"""
+ if node.filename is None:
+ return
rv = '# DEBUG(filename=%s, lineno=%s)' % (
node.filename,
node.lineno
if m is not None:
filename, lineno = m.groups()
if filename == 'None':
- filename = ''
- if lineno == 'None':
- lineno = 0
- else:
+ filename = None
+ if lineno != 'None':
lineno = int(lineno)
break
startpos -= 1
# no traceback information found, reraise unchanged
- if filename is None:
+ if not filename:
return traceback
+
return raise_template_exception(exc_value, filename,
lineno, context)
self._queue = []
pop = self._queue.pop
self._popleft = lambda: pop(0)
+
# alias all queue methods for faster lookup
self._pop = self._queue.pop
-
- # XXX: Is this good? Didn't find another sollution
- def remove_by_value(value):
- for i, v in enumerate(self._queue):
- if v == value:
- self._queue.__delitem__(i)
- break
-
- self._remove = remove_by_value
+ self._remove = self._queue.remove
self._append = self._queue.append
def copy(self):