# HG changeset patch
# User mgood
# Date 1151970903 0
# Node ID 436e30c8420b27f4703e245464923c1de57c18f7
# Parent e03b77726756cf41fcfa03a2800c70bf6b4a8f54
implement `py:choose/when/otherwise` directives for conditionally selecting one of several blocks
diff --git a/markup/template.py b/markup/template.py
--- a/markup/template.py
+++ b/markup/template.py
@@ -503,6 +503,123 @@
yield event
+class ChooseDirective(Directive):
+ """Implementation of the `py:choose` directive for conditionally selecting
+ one of several body elements to display.
+
+ If the `py:choose` expression is empty the expressions of nested `py:when`
+ directives are tested for truth. The first true `py:when` body is output.
+
+ >>> ctxt = Context()
+ >>> tmpl = Template('''
+ ... 0
+ ... 1
+ ...
''')
+ >>> print tmpl.generate(ctxt)
+
+ 1
+
+
+ If multiple `py:when` bodies match only the first is output.
+ >>> tmpl = Template('''
+ ... 1
+ ... 2
+ ...
''')
+ >>> print tmpl.generate(ctxt)
+
+ 1
+
+
+ If the `py:choose` directive contains an expression, the nested `py:when`
+ directives are tested for equality to the `py:choose` expression.
+ >>> tmpl = Template('''
+ ... 1
+ ... 2
+ ...
''')
+ >>> print tmpl.generate(ctxt)
+
+ 2
+
+
+ If no `py:when` directive is matched then the fallback directive
+ `py:otherwise` will be used.
+ >>> tmpl = Template('''
+ ... hidden
+ ... hello
+ ...
''')
+ >>> print tmpl.generate(ctxt)
+
+ hello
+
+
+ `py:choose` blocks can be nested:
+ >>> tmpl = Template('''
+ ...
+ ... 2
+ ... 3
+ ...
+ ...
''')
+ >>> print tmpl.generate(ctxt)
+
+
+ Behavior is undefined if a `py:choose` block contains content outside a
+ `py:when` or `py:otherwise` block. Behavior is also undefined if a
+ `py:otherwise` occurs before `py:when` blocks.
+ """
+
+ def __call__(self, stream, ctxt):
+ if self.expr:
+ self.value = self.expr.evaluate(ctxt)
+ self.matched = False
+ ctxt.push(__choose=self)
+ for event in stream:
+ yield event
+ ctxt.pop()
+
+
+class WhenDirective(Directive):
+ """Implementation of the `py:when` directive for nesting in a parent with
+ the `py:choose` directive. See the documentation of `py:choose` for
+ usage.
+ """
+ def __call__(self, stream, ctxt):
+ choose = ctxt['__choose']
+ if choose.matched:
+ return []
+ value = self.expr.evaluate(ctxt)
+ try:
+ if value == choose.value:
+ choose.matched = True
+ return stream
+ except AttributeError:
+ if value:
+ choose.matched = True
+ return stream
+ return []
+
+
+class OtherwiseDirective(Directive):
+ """Implementation of the `py:otherwise` directive for nesting in a parent
+ with the `py:choose` directive. See the documentation of `py:choose` for
+ usage.
+ """
+ def __call__(self, stream, ctxt):
+ choose = ctxt['__choose']
+ if choose.matched:
+ return []
+ choose.matched = True
+ return stream
+
+
class Template(object):
"""Can parse a template and transform it into the corresponding output
based on context data.
@@ -519,7 +636,10 @@
('replace', ReplaceDirective),
('content', ContentDirective),
('attrs', AttrsDirective),
- ('strip', StripDirective)]
+ ('strip', StripDirective),
+ ('choose', ChooseDirective),
+ ('when', WhenDirective),
+ ('otherwise', OtherwiseDirective)]
_dir_by_name = dict(directives)
_dir_order = [directive[1] for directive in directives]