# HG changeset patch # User cmlenz # Date 1156866294 0 # Node ID 835203f3b8fd08d12a59fdc12622bea8abfa3b4a # Parent 0619a27f5e673ec84d55520fc4745cb0c51ce56e Cleanup the application of template processing steps (flatten, eval, match) so that they are only performed when necessary. Results in a small performance boost, and also fixes #35. diff --git a/markup/template.py b/markup/template.py --- a/markup/template.py +++ b/markup/template.py @@ -915,7 +915,7 @@ ctxt = Context(**kwargs) stream = self.stream - for filter_ in [self._eval, self._match, self._flatten] + self.filters: + for filter_ in [self._flatten, self._eval, self._match] + self.filters: stream = filter_(iter(stream), ctxt) return Stream(stream) @@ -923,7 +923,7 @@ """Internal stream filter that evaluates any expressions in `START` and `TEXT` events. """ - filters = (self._eval, self._match, self._flatten) + filters = (self._flatten, self._eval) for kind, data, pos in stream: @@ -983,9 +983,7 @@ # events to which those directives should be applied directives, substream = data substream = _apply_directives(substream, ctxt, directives) - for filter_ in (self._eval, self._match, self._flatten): - substream = filter_(substream, ctxt) - for event in substream: + for event in self._flatten(substream, ctxt): yield event else: yield kind, data, pos @@ -1009,10 +1007,17 @@ enumerate(match_templates): if test(kind, data, pos, ctxt) is True: + + # Let the remaining match templates know about the event so + # they get a chance to update their internal state + for test in [mt[0] for mt in match_templates[idx + 1:]]: + test(kind, data, pos, ctxt) + # Consume and store all events until an end event # corresponding to this start event is encountered content = [(kind, data, pos)] depth = 1 + stream = self._match(stream, ctxt) while depth > 0: kind, data, pos = stream.next() if kind is START: @@ -1020,12 +1025,14 @@ elif kind is END: depth -= 1 content.append((kind, data, pos)) - test(kind, data, pos, ctxt) - content = list(self._flatten(content, ctxt)) - select = lambda path: Stream(content).select(path) + # Make the select() function available in the body of the + # match template + def select(path): + return Stream(content).select(path) ctxt.push(dict(select=select)) + # Recursively process the output template = _apply_directives(template, ctxt, directives) for event in self._match(self._eval(template, ctxt), ctxt, match_templates[:idx] + diff --git a/markup/tests/template.py b/markup/tests/template.py --- a/markup/tests/template.py +++ b/markup/tests/template.py @@ -330,6 +330,18 @@ """) self.assertRaises(TypeError, list, tmpl.generate(badfunc=badfunc)) + def test_def_in_matched(self): + tmpl = Template(""" + ${select('*')} + + + ${maketitle(True)} + + """) + self.assertEqual(""" + True + """, str(tmpl.generate())) + class ForDirectiveTestCase(unittest.TestCase): """Tests for the `py:for` template directive."""