]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Tests and docs for break/continue in templates
authorBen Darnell <ben@bendarnell.com>
Mon, 25 Jun 2012 02:52:53 +0000 (19:52 -0700)
committerBen Darnell <ben@bendarnell.com>
Mon, 25 Jun 2012 02:52:53 +0000 (19:52 -0700)
tornado/template.py
tornado/test/template_test.py

index 64d8391eaabc6452173c42712f95e00dcb0fd5c6..13eb7808131fc7e7ec465dd31e74118861d34c12 100644 (file)
@@ -101,6 +101,11 @@ with ``{# ... #}``.
 
         {% apply linkify %}{{name}} said: {{message}}{% end %}
 
+    Note that as an implementation detail apply blocks are implemented
+    as nested functions and thus may interact strangely with variables
+    set via ``{% set %}``, or the use of ``{% break %}`` or ``{% continue %}``
+    within loops.
+
 ``{% autoescape *function* %}``
     Sets the autoescape mode for the current file.  This does not affect
     other files, even those referenced by ``{% include %}``.  Note that
@@ -134,7 +139,8 @@ with ``{# ... #}``.
     tag will be ignored.  For an example, see the ``{% block %}`` tag.
 
 ``{% for *var* in *expr* %}...{% end %}``
-    Same as the python ``for`` statement.
+    Same as the python ``for`` statement.  ``{% break %}`` and
+    ``{% continue %}`` may be used inside the loop.
 
 ``{% from *x* import *y* %}``
     Same as the python ``import`` statement.
@@ -169,7 +175,8 @@ with ``{# ... #}``.
     Same as the python ``try`` statement.
 
 ``{% while *condition* %}... {% end %}``
-    Same as the python ``while`` statement.
+    Same as the python ``while`` statement.  ``{% break %}`` and
+    ``{% continue %}`` may be used inside the loop.
 """
 
 from __future__ import absolute_import, division, with_statement
@@ -817,6 +824,10 @@ def _parse(reader, template, in_block=None, in_loop=None):
             # parse inner body recursively
             if operator in ("for", "while"):
                 block_body = _parse(reader, template, operator, operator)
+            elif operator == "apply":
+                # apply creates a nested function so syntactically it's not
+                # in the loop.
+                block_body = _parse(reader, template, operator, None)
             else:
                 block_body = _parse(reader, template, operator, in_loop)
 
index d70e4875c4b42e8980868131aa01519e28324a65..a4b9453b7a2da8c6b6c25758d966ce64c5f3ee08 100644 (file)
@@ -115,6 +115,38 @@ try{% set y = 1/x %}
         template = Template(utf8("{% comment blah blah %}foo"))
         self.assertEqual(template.generate(), b("foo"))
 
+    def test_break_continue(self):
+        template = Template(utf8("""\
+{% for i in range(10) %}
+    {% if i == 2 %}
+        {% continue %}
+    {% end %}
+    {{ i }}
+    {% if i == 6 %}
+        {% break %}
+    {% end %}
+{% end %}"""))
+        result = template.generate()
+        # remove extraneous whitespace
+        result = b('').join(result.split())
+        self.assertEqual(result, b("013456"))
+
+    def test_break_outside_loop(self):
+        try:
+            Template(utf8("{% break %}"))
+            raise Exception("Did not get expected exception")
+        except ParseError:
+            pass
+
+    def test_break_in_apply(self):
+        # This test verifies current behavior, although of course it would
+        # be nice if apply didn't cause seemingly unrelated breakage
+        try:
+            Template(utf8("{% for i in [] %}{% apply foo %}{% break %}{% end %}{% end %}"))
+            raise Exception("Did not get expected exception")
+        except ParseError:
+            pass
+
 
 class StackTraceTest(LogTrapTestCase):
     def test_error_line_number_expression(self):