# HG changeset patch
# User cmlenz
# Date 1153992137 0
# Node ID f12e7987d7f45302eaabc2a796f5a7a1347fd87b
# Parent 0f246a30d3a7767baee6167b31242ed184bfa140
Added `py:with` directive based on Jonas' patch in #17.
diff --git a/markup/template.py b/markup/template.py
--- a/markup/template.py
+++ b/markup/template.py
@@ -619,6 +619,47 @@
return _apply_directives(stream, ctxt, directives)
+class WithDirective(Directive):
+ """Implementation of the `py:with` template directive, which allows
+ shorthand access to variables and expressions.
+
+ >>> tmpl = Template('''
+ ... $x $y $z
+ ...
''')
+ >>> print tmpl.generate(Context(x=42))
+
+ 42 7 52
+
+ """
+ __slots__ = ['vars']
+
+ ATTRIBUTE = 'vars'
+
+ def __init__(self, value, filename=None, lineno=-1, offset=-1):
+ Directive.__init__(self, None, filename, lineno, offset)
+ self.vars = []
+ try:
+ for stmt in value.split(';'):
+ name, value = stmt.split('=', 1)
+ self.vars.append((name.strip(),
+ Expression(value.strip(), filename, lineno)))
+ except SyntaxError, err:
+ raise TemplateSyntaxError(err, filename, lineno,
+ offset + (err.offset or 0))
+
+ def __call__(self, stream, ctxt, directives):
+ ctxt.push(dict([(name, expr.evaluate(ctxt))
+ for name, expr in self.vars]))
+ for event in _apply_directives(stream, ctxt, directives):
+ yield event
+ ctxt.pop()
+
+ def __repr__(self):
+ return '<%s "%s">' % (self.__class__.__name__,
+ '; '.join(['%s = %s' % (name, expr.source)
+ for name, expr in self.vars]))
+
+
class Template(object):
"""Can parse a template and transform it into the corresponding output
based on context data.
@@ -635,6 +676,7 @@
('when', WhenDirective),
('otherwise', OtherwiseDirective),
('choose', ChooseDirective),
+ ('with', WithDirective),
('replace', ReplaceDirective),
('content', ContentDirective),
('attrs', AttrsDirective),
diff --git a/markup/tests/template.py b/markup/tests/template.py
--- a/markup/tests/template.py
+++ b/markup/tests/template.py
@@ -414,6 +414,30 @@
""", str(tmpl.generate()))
+class WithDirectiveTestCase(unittest.TestCase):
+ """Tests for the `py:with` template directive."""
+
+ def test_shadowing(self):
+ tmpl = Template("""
+ ${x}
+
+ ${x}
+
""")
+ self.assertEqual("""
+ 42
+ 84
+ 42
+
""", str(tmpl.generate(Context(x=42))))
+
+ def test_as_element(self):
+ tmpl = Template("""""")
+ self.assertEqual("""
+ 84
+
""", str(tmpl.generate(Context(x=42))))
+
+
class TemplateTestCase(unittest.TestCase):
"""Tests for basic template processing, expression evaluation and error
reporting.
@@ -578,6 +602,7 @@
suite.addTest(unittest.makeSuite(IfDirectiveTestCase, 'test'))
suite.addTest(unittest.makeSuite(MatchDirectiveTestCase, 'test'))
suite.addTest(unittest.makeSuite(StripDirectiveTestCase, 'test'))
+ suite.addTest(unittest.makeSuite(WithDirectiveTestCase, 'test'))
return suite
if __name__ == '__main__':