Ticket #5172: numerical-foo-loop.diff

File numerical-foo-loop.diff, 5.6 KB (added by Vincent Foley, 17 years ago)
  • django/template/defaulttags.py

     
    6969                return smart_unicode(value)
    7070        return u''
    7171
     72class NumForNode(Node):
     73    def __init__(self, loopvar, start, end, step, exclusive, nodelist_loop):
     74        self.loopvar = loopvar
     75        self.start = Variable(start)
     76        self.end = Variable(end)
     77        self.step = Variable(step)
     78        self.exclusive = exclusive
     79        self.nodelist_loop = nodelist_loop
     80
     81    def __repr__(self):
     82        if self.exclusive:
     83            exclusive = ' exclusive'
     84        else:
     85            exclusive = ''
     86
     87        if step != 1:
     88            step_str = ' by %s' % step
     89        else:
     90            step_str = ''
     91
     92        return '<For Node: for %s %s to %s%s%s>' % \
     93                (self.loopvar, self.start, self.end,
     94                 step_str, exclusive)
     95
     96    def __iter__(self):
     97        for node in self.nodelist_loop:
     98            yield node
     99
     100    def make_seq(self, context):
     101        start = int(self.start.resolve(context))
     102        end = int(self.end.resolve(context))
     103        step = int(self.step.resolve(context))
     104   
     105        if step < 0:
     106            end -= int(not self.exclusive)
     107        else:
     108            end += int(not self.exclusive)
     109
     110        return xrange(start, end, step)
     111
     112
     113    def render(self, context):
     114        nodelist = NodeList()
     115        context.push()
     116        seq = self.make_seq(context)
     117        for i in seq:
     118            context[self.loopvar] = i
     119            for node in self.nodelist_loop:
     120                nodelist.append(node.render(context))
     121        context.pop()
     122        return nodelist.render(context)
     123
     124
    72125class ForNode(Node):
    73126    def __init__(self, loopvars, sequence, reversed, nodelist_loop):
    74127        self.loopvars, self.sequence = loopvars, sequence
     
    565618
    566619    """
    567620    bits = token.contents.split()
     621
    568622    if len(bits) < 4:
    569623        raise TemplateSyntaxError, "'for' statements should have at least four words: %s" % token.contents
    570624
     625    if bits[-3] != 'in' and bits[-2] != 'in':
     626        return do_numfor(parser, token)
     627
    571628    reversed = bits[-1] == 'reversed'
    572629    in_index = reversed and -3 or -2
    573630    if bits[in_index] != 'in':
     
    584641    return ForNode(loopvars, sequence, reversed, nodelist_loop)
    585642do_for = register.tag("for", do_for)
    586643
     644def do_numfor(parser, token):
     645    bits = token.split_contents()
     646
     647    if len(bits) < 5:
     648        raise TemplateSyntaxError("num 'for' tag should have at least 5 arguments: %s" % token.contents)
     649    if bits[3] != 'to':
     650        raise TemplateSyntaxError("num 'for' tag should use the format 'for i 1 to 5': %s" % token.contents)
     651    try:
     652        start, end = bits[2], bits[4]
     653    except ValueError:
     654        raise TemplateSyntaxError("num 'for' tag should use the format 'for i 1 to 5': %s" % token.contents)
     655       
     656    step = '1'
     657    try:
     658        if bits[5] == 'by':
     659            try:
     660                step = bits[6]
     661            except IndexError:
     662                raise TemplateSyntaxError("step value required after 'by' keyword: %s" % token.contents)
     663    except IndexError:
     664        pass
     665    exclusive = bits[-1] == 'exclusive'
     666
     667    loopvar = bits[1]
     668
     669    nodelist_loop = parser.parse(('endfor',))
     670    parser.delete_first_token()
     671    return NumForNode(loopvar, start, end, step, exclusive, nodelist_loop)
     672
    587673def do_ifequal(parser, token, negate):
    588674    bits = list(token.split_contents())
    589675    if len(bits) != 3:
  • tests/regressiontests/templates/tests.py

     
    365365            'for-tag-unpack12': ("{% for x,y,z in items %}{{ x }}:{{ y }},{{ z }}/{% endfor %}", {"items": (('one', 1, 'carrot'), ('two', 2))}, ("one:1,carrot/two:2,/", "one:1,carrot/two:2,INVALID/")),
    366366            'for-tag-unpack13': ("{% for x,y,z in items %}{{ x }}:{{ y }},{{ z }}/{% endfor %}", {"items": (('one', 1, 'carrot'), ('two', 2, 'cheese'))}, ("one:1,carrot/two:2,cheese/", "one:1,carrot/two:2,cheese/")),
    367367
     368
     369            ### NUMERICAL FOR TAG #####################################################
     370            'numfor-tag01': ("{% for i 1 to 5 %}{{ i }}{% endfor %}", {}, "12345"),
     371            'numfor-tag02': ("{% for i 1 to 5 exclusive %}{{ i }}{% endfor %}", {}, u"1234"),
     372            'numfor-tag03': ("{% for i 1 to 5 by 2 %}{{ i }}{% endfor %}", {}, "135"),
     373            'numfor-tag04': ("{% for i 1 to 5 by 2 exclusive %}{{ i }}{% endfor %}", {}, "13"),
     374
     375            'numfor-tag05': ("{% for i 5 to 1 by -1 %}{{ i }}{% endfor %}", {}, "54321"),
     376            'numfor-tag06': ("{% for i 5 to 1 by -1 exclusive %}{{ i }}{% endfor %}", {}, "5432"),
     377            'numfor-tag07': ("{% for i 5 to 1 by -2 %}{{ i }}{% endfor %}", {}, "531"),
     378            'numfor-tag08': ("{% for i 5 to 1 by -2 exclusive %}{{ i }}{% endfor %}", {}, "53"),
     379
     380            'numfor-tag09': ("{% for i 1 to 5 by -1 %}{{ i }}{% endfor %}", {}, ""),
     381            'numfor-tag10': ("{% for i 5 to 1 by 1 %}{{ i }}{% endfor %}", {}, ""),
     382
     383            'numfor-tag11': ("{% for i x to y by z %}{{ i }}{% endfor %}", {'x': 1, 'y': 5, 'z': 1}, "12345"),
     384
    368385            ### IF TAG ################################################################
    369386            'if-tag01': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": True}, "yes"),
    370387            'if-tag02': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": False}, "no"),
Back to Top