[svn] added a sanity check for block tags outside the root level
authorArmin Ronacher <armin.ronacher@active-4.com>
Sat, 28 Apr 2007 21:23:44 +0000 (23:23 +0200)
committerArmin Ronacher <armin.ronacher@active-4.com>
Sat, 28 Apr 2007 21:23:44 +0000 (23:23 +0200)
--HG--
branch : trunk

CHANGES
docs/src/designerdoc.txt
docs/src/i18n.txt
jinja/parser.py

diff --git a/CHANGES b/CHANGES
index be0276269706f69f1707a047565abdf8a3397520..8dcac277f4d2b49281bf90f8c0dca8f1d81c6d1a 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -81,6 +81,8 @@ Version 1.1
 
 - it's not possible to stream templates.
 
+- fixed a corner case when defining a block inside of a condition
+
 
 Version 1.0
 -----------
index 71792924f01fb0be77320e5c540d54d36ea9cd49..6c6dbabf7f739528b355f069335e3b7aab62e87b 100644 (file)
@@ -611,6 +611,50 @@ value from the parent template is used instead.
     two similarly-named ``{% block %}`` tags in a template, that template's
     parent wouldn't know which one of the blocks' content to use.
 
+How Inheritance Works Internally
+--------------------------------
+
+Inheritance in Jinja is straighforward. If a template contains a
+``{% extends %}`` tag it's considered being a child template, otherwise it's
+a layout template. In a layout template you can place blocks basically
+everywhere. In a child template blocks can only be located either top level
+or inside of another block.
+
+Data outside of a block in a child template is executed before the layout
+template is rendered, thus you can use it to propagate data to the whole
+inheritance chain. Having a block in an invalid position you will receive
+an syntax error. Here some examples:
+
+**impossible**:
+
+    .. sourcecode:: jinja
+
+        {% extends 'master.html' %}
+        {% if some_condition %}
+          {% block body %}
+            ...
+          {% endblock %}
+        {% endif %}
+
+    This can't work because template inheritance works at translation /
+    compilation time not at template executation.
+
+**possible**:
+
+    .. sourcecode:: jinja
+
+        {% extends 'master.html' %}
+        {% block body %}
+          {% if some_condition %}
+            {% block myblock %}
+              ...
+            {% endblock %}
+          {% endblock %}
+        {% endblock %}
+
+    This can work although it probably makes no sense in this specific case.
+    However the condition is handled at runtime because it's in a valid block
+    and defines a new block subtemplates can override.
 
 Super Blocks
 ============
index 621cc91acab3bd115a6a9f454a1dfe3ecd89b022..cfad370312caa7dcf2d4a24f5e0a4c46abd5e5c6 100644 (file)
@@ -50,6 +50,10 @@ However. For many web applications this might be a way:
     tmpl = env.get_template('index.html')
     tmpl.render(LANGUAGE='de_DE')
 
+This example assumes that you use gettext and have a gettext
+`Translations` object which is returned by the `get_translator`
+function.
+
 
 Collecting Translations
 =======================
index a7e2e05345a55776700befa513fc6829915eaeaf..207dd54f9a1ca60668e5f81732cf2392959d095a 100644 (file)
@@ -574,40 +574,62 @@ class Parser(object):
         filename attributes for all nodes in the tree.
         """
         body = self.subparse(None)
-        todo = [body]
-        while todo:
-            node = todo.pop()
-            # all names excluding keywords have an trailing underline.
-            # if we find a name without trailing underline that's a keyword
-            # and this code raises an error. else strip the underline again
-            if node.__class__ in (ast.AssName, ast.Name, ast.Keyword):
-                if not node.name.endswith('_'):
-                    raise TemplateSyntaxError('illegal use of keyword %r '
-                                              'as identifier.' % node.name,
-                                              node.lineno, self.filename)
-                node.name = node.name[:-1]
-            # same for attributes
-            elif node.__class__ is ast.Getattr:
-                if not node.attrname.endswith('_'):
-                    raise TemplateSyntaxError('illegal use of keyword %r '
-                                              'as attribute name.' %
-                                              node.name, node.lineno,
-                                              self.filename)
-                node.attrname = node.attrname[:-1]
-            # if we have a ForLoop we ensure that nobody patches existing
-            # object using "for foo.bar in seq"
-            elif node.__class__ is nodes.ForLoop:
-                def check(node):
-                    if node.__class__ not in (ast.AssName, ast.AssTuple):
-                        raise TemplateSyntaxError('can\'t assign to '
-                                                  'expression.', node.lineno,
+        def walk(nodes_, stack):
+            for node in nodes_:
+                # all names excluding keywords have an trailing underline.
+                # if we find a name without trailing underline that's a
+                # keyword and this code raises an error. else strip the
+                # underline again
+                if node.__class__ in (ast.AssName, ast.Name, ast.Keyword):
+                    if not node.name.endswith('_'):
+                        raise TemplateSyntaxError('illegal use of keyword %r '
+                                                  'as identifier.' %
+                                                  node.name, node.lineno,
+                                                  self.filename)
+                    node.name = node.name[:-1]
+                # same for attributes
+                elif node.__class__ is ast.Getattr:
+                    if not node.attrname.endswith('_'):
+                        raise TemplateSyntaxError('illegal use of keyword %r '
+                                                  'as attribute name.' %
+                                                  node.name, node.lineno,
                                                   self.filename)
-                    for n in node.getChildNodes():
-                        check(n)
-                check(node.item)
-            # now set the filename and continue working on the childnodes
-            node.filename = self.filename
-            todo.extend(node.getChildNodes())
+                    node.attrname = node.attrname[:-1]
+                # if we have a ForLoop we ensure that nobody patches existing
+                # object using "for foo.bar in seq"
+                elif node.__class__ is nodes.ForLoop:
+                    def check(node):
+                        if node.__class__ not in (ast.AssName, ast.AssTuple):
+                            raise TemplateSyntaxError('can\'t assign to '
+                                                      'expression.',
+                                                      node.lineno,
+                                                      self.filename)
+                        for n in node.getChildNodes():
+                            check(n)
+                    check(node.item)
+                # ensure that in child templates block are either top level
+                # or located inside of another block tag.
+                elif self.extends is not None and \
+                     node.__class__ is nodes.Block:
+                    if stack[-1] is not body:
+                        for n in stack:
+                            if n.__class__ is nodes.Block:
+                                break
+                        else:
+                            raise TemplateSyntaxError('misplaced block %r, '
+                                                      'blocks in child '
+                                                      'templates must be '
+                                                      'either top level or '
+                                                      'located in a block '
+                                                      'tag.' % node.name,
+                                                      node.lineno,
+                                                      self.filename)
+                # now set the filename and continue working on the childnodes
+                node.filename = self.filename
+                stack.append(node)
+                walk(node.getChildNodes(), stack)
+                stack.pop()
+        walk([body], [body])
         return nodes.Template(self.filename, body, self.extends)
 
     def subparse(self, test, drop_needle=False):