]> git.ipfire.org Git - thirdparty/jinja.git/commitdiff
Add changed() to loop context 676/head
authorAdrian Moennich <adrian@planetcoding.net>
Wed, 1 Feb 2017 20:47:17 +0000 (21:47 +0100)
committerAdrian Moennich <adrian@planetcoding.net>
Sat, 24 Jun 2017 08:52:06 +0000 (10:52 +0200)
CHANGES
docs/templates.rst
jinja2/runtime.py
tests/test_async.py
tests/test_core_tags.py

diff --git a/CHANGES b/CHANGES
index afb26c18c3f232c44ab489b5b3dbce9432ba4ddc..a684130b8bb5438732999d76d021d734ffe09907 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -13,6 +13,9 @@ Version 2.10
 - Added `previtem` and `nextitem` to loop contexts, providing access to the
   previous/next item in the loop. If such an item does not exist, the value is
   undefined.
+- Added `changed(*values)` to loop contexts, providing an easy way of checking
+  whether a value has changed since the last iteration (or rather since the
+  last call of the method)
 
 Version 2.9.6
 -------------
index f259f83943d356d5e996a01a5cd8b8e562c7421b..5defc8bb6f36e4214c1d8db1e08e79d0fef9862a 100644 (file)
@@ -618,6 +618,9 @@ Inside of a for-loop block, you can access some special variables:
 | `loop.nextitem`       | The item from the following iteration of the loop.|
 |                       | Undefined during the last iteration.              |
 +-----------------------+---------------------------------------------------+
+| `loop.changed(*val)`  | True if previously called with a different value  |
+|                       | (or not called at all).                           |
++-----------------------+---------------------------------------------------+
 
 Within a for-loop, it's possible to cycle among a list of strings/variables
 each time through the loop by using the special `loop.cycle` helper::
@@ -700,6 +703,16 @@ and `nextitem`::
         {% endif %}
     {% endfor %}
 
+If you only care whether the value changed at all, using `changed` is even
+easier::
+
+    {% for entry in entries %}
+        {% if loop.changed(entry.category) %}
+            <h2>{{ entry.category }}</h2>
+        {% endif %}
+        <p>{{ entry.message }}</p>
+    {% endfor %}
+
 .. _if:
 
 If
index 2f91a8c8d877caacd3724a4bd6f3e7de37eedcc5..a75ae6ef15c860adf643768756b0fd12c791d9ce 100644 (file)
@@ -360,6 +360,7 @@ class LoopContextBase(object):
         self._recurse = recurse
         self.index0 = -1
         self.depth0 = depth0
+        self._last_checked_value = missing
 
     def cycle(self, *args):
         """Cycles among the arguments with the current loop index."""
@@ -367,6 +368,13 @@ class LoopContextBase(object):
             raise TypeError('no items for cycling given')
         return args[self.index0 % len(args)]
 
+    def changed(self, *value):
+        """Checks whether the value has changed since the last call."""
+        if self._last_checked_value != value:
+            self._last_checked_value = value
+            return True
+        return False
+
     first = property(lambda x: x.index0 == 0)
     last = property(lambda x: x._after is _last_iteration)
     index = property(lambda x: x.index0 + 1)
index 83eb93765c3ba0422ab3e6513a482745e3f8f3f8..2f177473d2d04e836e0802fd19c28477376aa900 100644 (file)
@@ -312,6 +312,13 @@ class TestAsyncForLoop(object):
         output = tmpl.render(seq=list(range(4)))
         assert output == 'x-0-1|0-1-2|1-2-3|2-3-x|'
 
+    def test_changed(self, test_env_async):
+        tmpl = test_env_async.from_string('''{% for item in seq -%}
+            {{ loop.changed(item) }},
+        {%- endfor %}''')
+        output = tmpl.render(seq=[None, None, 1, 2, 2, 3, 4, 4, 4])
+        assert output == 'True,False,True,True,False,True,True,False,False,'
+
     def test_scope(self, test_env_async):
         tmpl = test_env_async.from_string('{% for item in seq %}{% endfor %}{{ item }}')
         output = tmpl.render(seq=list(range(10)))
index 0fb4be8fb5059ea590102b0b6579633cd6dce5ca..4f56db78db7363f7c8aabc3d979d0d2d43f265bc 100644 (file)
@@ -76,6 +76,13 @@ class TestForLoop(object):
         output = tmpl.render(seq=list(range(4)))
         assert output == 'x-0-1|0-1-2|1-2-3|2-3-x|'
 
+    def test_changed(self, env):
+        tmpl = env.from_string('''{% for item in seq -%}
+            {{ loop.changed(item) }},
+        {%- endfor %}''')
+        output = tmpl.render(seq=[None, None, 1, 2, 2, 3, 4, 4, 4])
+        assert output == 'True,False,True,True,False,True,True,False,False,'
+
     def test_scope(self, env):
         tmpl = env.from_string('{% for item in seq %}{% endfor %}{{ item }}')
         output = tmpl.render(seq=list(range(10)))