--- /dev/null
+# -*- coding: utf-8 -*-
+"""
+ jdebug
+ ~~~~~~
+
+ Helper module to simplify jinja debugging. Use
+
+ :copyright: 2006 by Armin Ronacher.
+ :license: BSD, see LICENSE for more details.
+"""
+from jinja import Environment
+from jinja.parser import Parser
+from jinja.translators.python import PythonTranslator
+
+
+__all__ = ['e', 't', 'p']
+
+e = Environment()
+t = e.from_string
+
+def p(x):
+ print PythonTranslator(e, Parser(e, x).parse()).translate()
"""
jinja_allowed_attributes = ['index', 'index0', 'length', 'parent',
- 'even', 'odd', 'revindex0', 'revindex']
+ 'even', 'odd', 'revindex0', 'revindex',
+ 'first', 'last']
def __init__(self, seq, parent, loop_function):
self.loop_function = loop_function
length = property(lambda s: s._stack[-1]['length'])
even = property(lambda s: s._stack[-1]['index'] % 2 == 0)
odd = property(lambda s: s._stack[-1]['index'] % 2 == 1)
+ first = property(lambda s: s._stack[-1]['index'] == 0)
+ last = property(lambda s: s._stack[-1]['index'] == s._stack[-1]['length'] - 1)
def __iter__(self):
s = self._stack[-1]
)
+class Set(Node):
+ """
+ Allow defining own variables.
+ """
+
+ def __init__(self, lineno, name, expr):
+ self.lineno = lineno
+ self.name = name
+ self.expr = expr
+
+ def get_items(self):
+ return [self.name, self.expr]
+
+ def __repr__(self):
+ return 'Set(%r, %r)' % (
+ self.name,
+ self.expr
+ )
+
+
class Filter(Node):
"""
Node for filter sections.
'for': self.handle_for_directive,
'if': self.handle_if_directive,
'cycle': self.handle_cycle_directive,
+ 'set': self.handle_set_directive,
'filter': self.handle_filter_directive,
'print': self.handle_print_directive,
'macro': self.handle_macro_directive,
# skip that.
return nodes.Cycle(lineno, ast.expr.args[0])
+ def handle_set_directive(self, lineno, gen):
+ """
+ Handle {% set foo = 'value of foo' %}.
+ """
+ try:
+ name = gen.next()
+ if name[1] != 'name' or gen.next()[1:] != ('operator', '='):
+ raise ValueError()
+ except (StopIteration, ValueError):
+ raise TemplateSyntaxError('invalid syntax for set', lineno)
+ ast = self.parse_python(lineno, gen, '(%s)')
+ return nodes.Set(lineno, name[1], ast.expr)
+
def handle_filter_directive(self, lineno, gen):
"""
Handle {% filter foo|bar %} directives.
def handle_macro_directive(self, lineno, gen):
"""
- Handle {% macro foo(bar, baz) %}.
+ Handle {% macro foo bar, baz %}.
"""
try:
macro_name = gen.next()
raise TemplateSyntaxError('include requires a string', lineno)
return nodes.Include(lineno, tokens[0][2][1:-1])
- def parse_python(self, lineno, gen, template='%s'):
+ def parse_python(self, lineno, gen, template):
"""
Convert the passed generator into a flat string representing
python sourcecode and return an ast node or raise a
nodes.Cycle: self.handle_cycle,
nodes.Print: self.handle_print,
nodes.Macro: self.handle_macro,
+ nodes.Set: self.handle_set,
nodes.Filter: self.handle_filter,
nodes.Block: self.handle_block,
nodes.Include: self.handle_include,
compile(translator.translate(), filename, 'exec'))
process = staticmethod(process)
- # -- private methods
+ # -- private helper methods
def indent(self, text):
"""
def filter(self, s, filter_nodes):
"""
- Apply a filter on an object.
+ Apply a filter on an object that already is a python expression.
+ Used to avoid redundant code in bitor and the filter directive.
"""
filters = []
for n in filter_nodes:
node = tmpl
lines = [
+ 'from __future__ import division\n'
'from jinja.datastructure import Undefined, LoopContext, CycleContext\n\n'
'def generate(context, write):\n'
' # BOOTSTRAPPING CODE\n'
return '\n'.join(buf)
+ def handle_set(self, node):
+ """
+ Handle variable assignments.
+ """
+ return self.indent('context[%r] = %s' % (
+ node.name,
+ self.handle_node(node.expr)
+ ))
+
def handle_filter(self, node):
"""
Handle filter sections.