[svn] added fist code for cycle and a few more filters in jinja
authorArmin Ronacher <armin.ronacher@active-4.com>
Tue, 27 Feb 2007 09:31:14 +0000 (10:31 +0100)
committerArmin Ronacher <armin.ronacher@active-4.com>
Tue, 27 Feb 2007 09:31:14 +0000 (10:31 +0100)
--HG--
branch : trunk

jinja/filters.py
jinja/nodes.py
jinja/parser.py
jinja/translators/python.py

index c495d32500052bf53acc0ed33acc2c47fea2c026..083f90aaa3e4e489517fd01cec36b3e7c3b09d8c 100644 (file)
@@ -8,6 +8,23 @@
     :copyright: 2006 by Armin Ronacher.
     :license: BSD, see LICENSE for more details.
 """
+from random import choice
+from urllib import urlencode, quote
+
+
+try:
+    _reversed = reversed
+except NameError:
+    # python2.3 compatibility hack for the do_reverse function
+    def _reversed(seq):
+        try:
+            return seq[::-1]
+        except:
+            try:
+                return list(seq)[::-1]
+            except:
+                raise TypeError('argument to _reversed must '
+                                'be a sequence')
 
 
 def stringfilter(f):
@@ -178,6 +195,111 @@ def do_reversed():
     return wrapped
 
 
+def do_center(value, width=80):
+    """
+    {{ var|center(80) }}
+
+    Centers the value in a field of a given width.
+    """
+    return value.center(width)
+do_center = stringfilter(do_center)
+
+
+def do_title(value):
+    """
+    {{ var|title }}
+
+    Capitalize the first character of all words.
+    """
+    return value.title()
+do_title = stringfilter(do_title)
+
+
+def do_capitalize(value):
+    """
+    {{ var|capitalize }}
+
+    Capitalize the first character of the string.
+    """
+    return value.capitalize()
+do_capitalize = stringfilter(do_capitalize)
+
+
+def do_first():
+    """
+    {{ var|first }}
+
+    Return the frist item of a sequence or None.
+    """
+    def wrapped(env, context, seq):
+        try:
+            return iter(seq).next()
+        except StopIteration:
+            return
+    return wrapped
+
+
+def do_last():
+    """
+    {{ var|last }}
+
+    Return the last item of a sequence.
+    """
+    def wrapped(env, context, seq):
+        try:
+            return iter(_reversed(seq)).next()
+        except (TypeError, StopIteration):
+            return
+    return wrapped
+
+
+def do_random():
+    """
+    {{ var|random }}
+
+    Return a random item from the sequence.
+    """
+    def wrapped(env, context, seq):
+        try:
+            return choice(seq)
+        except:
+            return
+    return wrapped
+
+
+def do_urlencode():
+    """
+    {{ var|urlencode }}
+
+    {{ {'foo': 'bar'}|urlencode }}
+
+    urlencode a string or directory.
+    """
+    def wrapped(env, context, value):
+        if isinstance(value, dict):
+            tmp = {}
+            for key, value in value.iteritems():
+                tmp[env.to_unicode(key)] = env.to_unicode(value)
+            return urlencode(tmp)
+        else:
+            return quote(env.to_unicode(value))
+    return wrapped
+
+
+def do_jsonencode():
+    """
+    {{ var|jsonencode }}
+
+    JSON dump a variable. just works if simplejson is installed.
+    """
+    global simplejson
+    try:
+        simplejson
+    except NameError:
+        import simplejson
+    return lambda e, c, v: simplejson.dumps(v)
+
+
 FILTERS = {
     'replace':              do_replace,
     'upper':                do_upper,
@@ -192,5 +314,13 @@ FILTERS = {
     'count':                do_count,
     'odd':                  do_odd,
     'even':                 do_even,
-    'reversed':             do_reversed
+    'reversed':             do_reversed,
+    'center':               do_center,
+    'title':                do_title,
+    'capitalize':           do_capitalize,
+    'first':                do_first,
+    'last':                 do_last,
+    'random':               do_random,
+    'urlencode':            do_urlencode,
+    'jsonencode':           do_jsonencode
 }
index 580310a2874e4b8ff3a51c282ef112280dc4cb49..c10479bde2c7796f197341dd8313aa2628732d08 100644 (file)
@@ -77,6 +77,19 @@ class IfCondition(Node):
         )
 
 
+class Cycle(Node):
+    """
+    A node that represents the cycle statement.
+    """
+
+    def __init__(self, pos, seq):
+        self.pos = pos
+        self.seq = seq
+
+    def __repr__(self):
+        return 'Cycle(%r)' % (self.seq,)
+
+
 class Print(Node):
     """
     A node that represents variable tags and print calls
index 7ab0fe85ea8e6eeb16eb9d153c8f889145cffa23..e2455542f0cb5e6e6cc1132621a1fceb1dd5f474 100644 (file)
@@ -53,6 +53,7 @@ class Parser(object):
         self.directives = {
             'for':          self.handle_for_directive,
             'if':           self.handle_if_directive,
+            'cycle':        self.handle_cycle_directive,
             'print':        self.handle_print_directive
         }
 
@@ -90,6 +91,15 @@ class Parser(object):
 
         return nodes.IfCondition(pos, ast.tests[0][0], body, else_)
 
+    def handle_cycle_directive(self, pos, gen):
+        """
+        Handle {% cycle foo, bar, baz %}.
+        """
+        ast = self.parse_python(pos, gen, '_cycle((%s))')
+        # ast is something like Discard(CallFunc(Name('_cycle'), ...))
+        # skip that.
+        return nodes.Cycle(pos, ast.expr.args[0])
+
     def handle_print_directive(self, pos, gen):
         """
         Handle {{ foo }} and {% print foo %}.
index 175dbd35596db03da5d2ceb1f32e9f890adcc28b..127a7835fd9f810dc319f04e3dc1c43887852d24 100644 (file)
@@ -37,6 +37,7 @@ class PythonTranslator(object):
             nodes.NodeList:         self.handle_node_list,
             nodes.ForLoop:          self.handle_for_loop,
             nodes.IfCondition:      self.handle_if_condition,
+            nodes.Cycle:            self.handle_cycle,
             nodes.Print:            self.handle_print,
             # used python nodes
             ast.Name:               self.handle_name,
@@ -155,6 +156,16 @@ class PythonTranslator(object):
             self.indention -= 1
         return '\n'.join(buf)
 
+    def handle_cycle(self, node):
+        """
+        Handle the cycle tag.
+        """
+        buf = []
+        write = lambda x: buf.append(self.indent(x))
+        write('# XXX: add some code here')
+        self.last_pos = node.pos
+        return '\n'.join(buf)
+
     def handle_print(self, node):
         """
         Handle a print statement.