join now also accepts parameters
authorArmin Ronacher <armin.ronacher@active-4.com>
Mon, 24 Jan 2011 00:13:51 +0000 (01:13 +0100)
committerArmin Ronacher <armin.ronacher@active-4.com>
Mon, 24 Jan 2011 00:13:51 +0000 (01:13 +0100)
CHANGES
jinja2/filters.py
jinja2/nodes.py
jinja2/runtime.py
jinja2/testsuite/filters.py

diff --git a/CHANGES b/CHANGES
index 7cda7b22a7b879424860403c7b5864e7c4568e8a..2cdedf426e61997fdce33bef1c5ae00e257a4ef1 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -29,6 +29,9 @@ Version 2.6
   optional starting index which defaultes to zero.  This now became the
   second argument to the function because it's rarely used.
 - like sum, sort now also makes it possible to order items by attribute.
+- like sum and sort, join now also is able to join attributes of objects
+  as string.
+- the internal eval context now has a reference to the environment.
 
 Version 2.5.5
 -------------
index 8cd83875331537c562b13e5161313ffe26526799..fe33eb004f31e9338638466149dacc30d30f3ca1 100644 (file)
@@ -256,7 +256,7 @@ def do_default(value, default_value=u'', boolean=False):
 
 
 @evalcontextfilter
-def do_join(eval_ctx, value, d=u''):
+def do_join(eval_ctx, value, d=u'', attribute=None):
     """Return a string which is the concatenation of the strings in the
     sequence. The separator between elements is an empty string per
     default, you can define it with the optional parameter:
@@ -268,7 +268,19 @@ def do_join(eval_ctx, value, d=u''):
 
         {{ [1, 2, 3]|join }}
             -> 123
+
+    It is also possible to join certain attributes of an object:
+
+    .. sourcecode:: jinja
+
+        {{ users|join(', ', attribute='username') }}
+
+    .. versionadded:: 2.6
+       The `attribute` parameter was added.
     """
+    if attribute is not None:
+        value = imap(make_attrgetter(eval_ctx.environment, attribute), value)
+
     # no automatic escaping?  joining is a lot eaiser then
     if not eval_ctx.autoescape:
         return unicode(d).join(imap(unicode, value))
index c18d299c83817c6911c024addbcd8a3aa29fc284..f9da1da5a295f364635ece012a746d3e3afc8814 100644 (file)
@@ -77,6 +77,7 @@ class EvalContext(object):
     """
 
     def __init__(self, environment, template_name=None):
+        self.environment = environment
         if callable(environment.autoescape):
             self.autoescape = environment.autoescape(template_name)
         else:
index 72ab93e3b2d77b64d7f9bddeb621506825a65075..d73483de30a53bb4c748640845cff57cb4aad7eb 100644 (file)
@@ -8,7 +8,6 @@
     :copyright: (c) 2010 by the Jinja Team.
     :license: BSD.
 """
-import sys
 from itertools import chain, imap
 from jinja2.nodes import EvalContext, _context_function_types
 from jinja2.utils import Markup, partial, soft_unicode, escape, missing, \
index 64cd0a902ad92696388e4cecfa858ba37994d9d1..ff04c9ff79c1f425ce0a48bd3f4c092e3a920133 100644 (file)
@@ -128,6 +128,13 @@ class FilterTestCase(JinjaTestCase):
         tmpl = env2.from_string('{{ ["<foo>", "<span>foo</span>"|safe]|join }}')
         assert tmpl.render() == '&lt;foo&gt;<span>foo</span>'
 
+    def test_join_attribute(self):
+        class User(object):
+            def __init__(self, username):
+                self.username = username
+        tmpl = env.from_string('''{{ users|join(', ', 'username') }}''')
+        assert tmpl.render(users=map(User, ['foo', 'bar'])) == 'foo, bar'
+
     def test_last(self):
         tmpl = env.from_string('''{{ foo|last }}''')
         out = tmpl.render(foo=range(10))