changeset 202:92353f28ae54 trunk

Remove the (hopefully) last instance where directives store state in instance variables, allowing templates to be cached and reused in a threadsafe manner. Closes #39. Many thanks to Christian Boos for the patch!
author cmlenz
date Fri, 25 Aug 2006 12:43:01 +0000
parents c5e0a1c86173
children 48fab34e5e4d
files markup/template.py markup/tests/template.py
diffstat 2 files changed, 70 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/markup/template.py
+++ b/markup/template.py
@@ -111,6 +111,16 @@
         """Set a variable in the current scope."""
         self.frames[0][key] = value
 
+    def _find(self, key, default=None):
+        """Retrieve a given variable's value and frame it was found in.
+
+        Intented for internal use by directives.
+        """
+        for frame in self.frames:
+            if key in frame:
+                return frame[key], frame
+        return default, None
+
     def get(self, key, default=None):
         """Get a variable's value, starting at the current scope and going
         upward.
@@ -586,10 +596,10 @@
     ATTRIBUTE = 'test'
 
     def __call__(self, stream, ctxt, directives):
+        frame = dict({'_choose.matched': False})
         if self.expr:
-            self.value = self.expr.evaluate(ctxt)
-        self.matched = False
-        ctxt.push(dict(_choose=self))
+            frame['_choose.value'] = self.expr.evaluate(ctxt)
+        ctxt.push(frame)
         for event in _apply_directives(stream, ctxt, directives):
             yield event
         ctxt.pop()
@@ -605,26 +615,26 @@
     ATTRIBUTE = 'test'
 
     def __call__(self, stream, ctxt, directives):
-        choose = ctxt['_choose']
-        if not choose:
+        matched, frame = ctxt._find('_choose.matched')
+        if not frame:
             raise TemplateSyntaxError('"when" directives can only be used '
                                       'inside a "choose" directive',
                                       *stream.next()[2])
-        if choose.matched:
+        if matched:
             return []
         if not self.expr:
             raise TemplateSyntaxError('"when" directive has no test condition',
                                       *stream.next()[2])
         value = self.expr.evaluate(ctxt)
-        try:
-            if value == choose.value:
-                choose.matched = True
-                return _apply_directives(stream, ctxt, directives)
-        except AttributeError:
-            if value:
-                choose.matched = True
-                return _apply_directives(stream, ctxt, directives)
-        return []
+        if '_choose.value' in frame:
+            matched = (value == frame['_choose.value'])
+        else:
+            matched = bool(value)
+        frame['_choose.matched'] = matched
+        if not matched:
+            return []
+
+        return _apply_directives(stream, ctxt, directives)
 
 
 class OtherwiseDirective(Directive):
@@ -634,14 +644,15 @@
     See the documentation of `py:choose` for usage.
     """
     def __call__(self, stream, ctxt, directives):
-        choose = ctxt['_choose']
-        if not choose:
+        matched, frame = ctxt._find('_choose.matched')
+        if not frame:
             raise TemplateSyntaxError('an "otherwise" directive can only be '
                                       'used inside a "choose" directive',
                                       *stream.next()[2])
-        if choose.matched:
+        if matched:
             return []
-        choose.matched = True
+        frame['_choose.matched'] = True
+
         return _apply_directives(stream, ctxt, directives)
 
 
--- a/markup/tests/template.py
+++ b/markup/tests/template.py
@@ -110,6 +110,46 @@
           </div>
         </doc>""", str(tmpl.generate()))
 
+    def test_complex_nesting(self):
+        """
+        Verify more complex nesting.
+        """
+        tmpl = Template("""<doc xmlns:py="http://markup.edgewall.org/">
+          <div py:choose="1">
+            <div py:when="1" py:choose="">
+              <span py:when="2">OK</span>
+              <span py:when="1">FAIL</span>
+            </div>
+          </div>
+        </doc>""")
+        self.assertEqual("""<doc>
+          <div>
+            <div>
+              <span>OK</span>
+            </div>
+          </div>
+        </doc>""", str(tmpl.generate()))
+
+    def test_complex_nesting_otherwise(self):
+        """
+        Verify more complex nesting using otherwise.
+        """
+        tmpl = Template("""<doc xmlns:py="http://markup.edgewall.org/">
+          <div py:choose="1">
+            <div py:when="1" py:choose="2">
+              <span py:when="1">FAIL</span>
+              <span py:otherwise="">OK</span>
+            </div>
+          </div>
+        </doc>""")
+        self.assertEqual("""<doc>
+          <div>
+            <div>
+              <span>OK</span>
+            </div>
+          </div>
+        </doc>""", str(tmpl.generate()))
+
     def test_when_with_strip(self):
         """
         Verify that a when directive with a strip directive actually strips of
Copyright (C) 2012-2017 Edgewall Software