From fed86c1a36050290549b1b8177978324ae3bc8e4 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Tue, 27 Feb 2007 10:31:14 +0100 Subject: [PATCH] [svn] added fist code for cycle and a few more filters in jinja --HG-- branch : trunk --- jinja/filters.py | 132 +++++++++++++++++++++++++++++++++++- jinja/nodes.py | 13 ++++ jinja/parser.py | 10 +++ jinja/translators/python.py | 11 +++ 4 files changed, 165 insertions(+), 1 deletion(-) diff --git a/jinja/filters.py b/jinja/filters.py index c495d32..083f90a 100644 --- a/jinja/filters.py +++ b/jinja/filters.py @@ -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 } diff --git a/jinja/nodes.py b/jinja/nodes.py index 580310a..c10479b 100644 --- a/jinja/nodes.py +++ b/jinja/nodes.py @@ -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 diff --git a/jinja/parser.py b/jinja/parser.py index 7ab0fe8..e245554 100644 --- a/jinja/parser.py +++ b/jinja/parser.py @@ -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 %}. diff --git a/jinja/translators/python.py b/jinja/translators/python.py index 175dbd3..127a783 100644 --- a/jinja/translators/python.py +++ b/jinja/translators/python.py @@ -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. -- 2.26.2