small refactoring
--HG--
branch : trunk
diff --git a/jinja2/runtime.py b/jinja2/runtime.py
index 17a5996..9a61040 100644
--- a/jinja2/runtime.py
+++ b/jinja2/runtime.py
@@ -185,7 +185,7 @@
len(self)
def cycle(self, *args):
- """A replacement for the old ``{% cycle %}`` tag."""
+ """Cycles among the arguments with the current loop index."""
if not args:
raise TypeError('no items for cycling given')
return args[self.index0 % len(args)]
@@ -200,7 +200,7 @@
return self.length
def __iter__(self):
- return self
+ return LoopContextIterator(self)
def loop(self, iterable):
if self._recurse is None:
@@ -212,16 +212,17 @@
# the the loop without or with too many arguments.
__call__ = loop; del loop
- def next(self):
- self.index0 += 1
- return self._next(), self
-
@property
def length(self):
if self._length is None:
try:
+ # first try to get the length from the iterable (if the
+ # iterable is a sequence)
length = len(self._iterable)
except TypeError:
+ # if that's not possible (ie: iterating over a generator)
+ # we have to convert the iterable into a sequence and
+ # use the length of that.
self._iterable = tuple(self._iterable)
self._next = iter(self._iterable).next
length = len(tuple(self._iterable)) + self.index0 + 1
@@ -236,6 +237,22 @@
)
+class LoopContextIterator(object):
+ """The iterator for a loop context."""
+ __slots__ = ('context',)
+
+ def __init__(self, context):
+ self.context = context
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ ctx = self.context
+ ctx.index0 += 1
+ return ctx._next(), ctx
+
+
class Macro(object):
"""Wraps a macro."""