]> git.ipfire.org Git - thirdparty/jinja.git/commitdiff
Fix and improve do_truncate 610/head
authorjab <jab@users.noreply.github.com>
Sat, 24 Sep 2016 21:25:31 +0000 (21:25 +0000)
committerjab <jab@users.noreply.github.com>
Sat, 24 Sep 2016 21:25:31 +0000 (17:25 -0400)
- Ensure that the requested max length be at least as long as the
  requested `end` value (e.g. 3 in the case of '...'). Fixes #539
- Add `leeway` parameter so that strings that just barely miss the
  requested max length cutoff can still be spared from unwanted truncation.
  Default value is 5.
- No longer append a space before appending `end` under any circumstances.
  Adding whitespace before ellipsis punctuation in English is grammatically
  incorrect.

jinja2/filters.py
tests/test_filters.py

index a450406941bfb55ff00fddd22d0bf90823d6414f..d4ab46b1d137555b0cf0f50176ea9276c31836ba 100644 (file)
@@ -455,31 +455,35 @@ def do_indent(s, width=4, indentfirst=False):
     return rv
 
 
-def do_truncate(s, length=255, killwords=False, end='...'):
+def do_truncate(s, length=255, killwords=False, end='...', leeway=5):
     """Return a truncated copy of the string. The length is specified
     with the first parameter which defaults to ``255``. If the second
     parameter is ``true`` the filter will cut the text at length. Otherwise
     it will discard the last word. If the text was in fact
     truncated it will append an ellipsis sign (``"..."``). If you want a
     different ellipsis sign than ``"..."`` you can specify it using the
-    third parameter.
+    third parameter. Strings that only exceed the length by the tolerance
+    margin given in the fourth parameter will not be truncated.
 
     .. sourcecode:: jinja
 
-        {{ "foo bar baz"|truncate(9) }}
-            -> "foo ..."
-        {{ "foo bar baz"|truncate(9, True) }}
+        {{ "foo bar baz qux"|truncate(9) }}
+            -> "foo..."
+        {{ "foo bar baz qux"|truncate(9, True) }}
             -> "foo ba..."
+        {{ "foo bar baz qux"|truncate(11) }}
+            -> "foo bar baz qux"
+        {{ "foo bar baz qux"|truncate(11, False, '...', 0) }}
+            -> "foo bar..."
 
     """
-    if len(s) <= length:
+    assert length >= len(end), 'expected length >= %s, got %s' % (len(end), length)
+    assert leeway >= 0, 'expected leeway >= 0, got %s' % leeway
+    if len(s) <= length + leeway:
         return s
-    elif killwords:
+    if killwords:
         return s[:length - len(end)] + end
-
     result = s[:length - len(end)].rsplit(' ', 1)[0]
-    if len(result) < length:
-        result += ' '
     return result + end
 
 
index f8fdad8a001fe0ba6d6a63291fc5ed4d5ecdec5c..b68bd22981df0a2ac59dc986c1c597c1503bfddb 100644 (file)
@@ -239,7 +239,7 @@ class TestFilter():
         out = tmpl.render(data='foobar baz bar' * 1000,
                           smalldata='foobar baz bar')
         msg = 'Current output: %s' % out
-        assert out == 'foobar baz b>>>|foobar baz >>>|foobar baz bar', msg
+        assert out == 'foobar baz b>>>|foobar baz>>>|foobar baz bar', msg
 
     def test_truncate_very_short(self, env):
         tmpl = env.from_string(
@@ -247,12 +247,12 @@ class TestFilter():
             '{{ "foo bar baz"|truncate(9, true) }}'
         )
         out = tmpl.render()
-        assert out == 'foo ...|foo ba...', out
+        assert out == 'foo bar baz|foo bar baz', out
 
     def test_truncate_end_length(self, env):
-        tmpl = env.from_string('{{ "Joel is a slug"|truncate(9, true) }}')
+        tmpl = env.from_string('{{ "Joel is a slug"|truncate(7, true) }}')
         out = tmpl.render()
-        assert out == 'Joel i...', 'Current output: %s' % out
+        assert out == 'Joel...', 'Current output: %s' % out
 
     def test_upper(self, env):
         tmpl = env.from_string('{{ "foo"|upper }}')