changeset 208:bc146e63c159 trunk

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.
author cmlenz
date Tue, 29 Aug 2006 15:44:54 +0000
parents 28bfc6aafab7
children fc6b2fb66518
files markup/template.py markup/tests/template.py
diffstat 2 files changed, 27 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- 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] +
--- a/markup/tests/template.py
+++ b/markup/tests/template.py
@@ -330,6 +330,18 @@
         </html>""")
         self.assertRaises(TypeError, list, tmpl.generate(badfunc=badfunc))
 
+    def test_def_in_matched(self):
+        tmpl = Template("""<doc xmlns:py="http://markup.edgewall.org/">
+          <head py:match="head">${select('*')}</head>
+          <head>
+            <py:def function="maketitle(test)"><b py:replace="test" /></py:def>
+            <title>${maketitle(True)}</title>
+          </head>
+        </doc>""")
+        self.assertEqual("""<doc>
+          <head><title>True</title></head>
+        </doc>""", str(tmpl.generate()))
+
 
 class ForDirectiveTestCase(unittest.TestCase):
     """Tests for the `py:for` template directive."""
Copyright (C) 2012-2017 Edgewall Software