[Zope-Checkins] SVN: Zope/branches/ajung-zpt-end-game/lib/python/Products/PageTemplates/ Bring back the ability to say some_iterator/first/bar and some_iterator/last/foo

Philipp von Weitershausen philikon at philikon.de
Tue May 23 04:40:06 EDT 2006


Log message for revision 68249:
  Bring back the ability to say some_iterator/first/bar and some_iterator/last/foo
  by providing PathIterator which (every much like the old PathIterator.Iterator
  class) handles its own traversal (only now we use the Zope 3 traversal hooks).
  

Changed:
  U   Zope/branches/ajung-zpt-end-game/lib/python/Products/PageTemplates/Expressions.py
  U   Zope/branches/ajung-zpt-end-game/lib/python/Products/PageTemplates/PathIterator.py
  U   Zope/branches/ajung-zpt-end-game/lib/python/Products/PageTemplates/tests/testHTMLTests.py

-=-
Modified: Zope/branches/ajung-zpt-end-game/lib/python/Products/PageTemplates/Expressions.py
===================================================================
--- Zope/branches/ajung-zpt-end-game/lib/python/Products/PageTemplates/Expressions.py	2006-05-22 23:59:14 UTC (rev 68248)
+++ Zope/branches/ajung-zpt-end-game/lib/python/Products/PageTemplates/Expressions.py	2006-05-23 08:40:04 UTC (rev 68249)
@@ -17,16 +17,18 @@
 
 $Id$
 """
+from zope.interface import implements
 from zope.tales.tales import ExpressionEngine, Context, Iterator
 from zope.tales.expressions import PathExpr, StringExpr, NotExpr
 from zope.tales.expressions import DeferExpr, SubPathExpr
 from zope.tales.expressions import SimpleModuleImporter
 from zope.tales.pythonexpr import PythonExpr
+from zope.traversing.interfaces import ITraversable
 from zope.traversing.adapters import traversePathElement
 from zope.contentprovider.tales import TALESProviderExpression
 
+import OFS.interfaces
 from zExceptions import NotFound, Unauthorized
-from OFS.interfaces import ITraversable
 from Products.PageTemplates import ZRPythonExpr
 from Products.PageTemplates.DeferExpr import LazyExpr
 from Products.PageTemplates.GlobalTranslationService import getGlobalTranslationService
@@ -52,7 +54,7 @@
 
     while path_items:
         name = path_items.pop()
-        if ITraversable.providedBy(object):
+        if OFS.interfaces.ITraversable.providedBy(object):
             try:
                 object = object.restrictedTraverse(name)
             except (NotFound, Unauthorized), e:
@@ -82,8 +84,7 @@
         context = self.contexts.get('context')
         return getGlobalTranslationService().translate(
             domain, msgid, mapping=mapping,
-            context=context,
-            default=default)
+            context=context, default=default)
 
 class ZopeEngine(ExpressionEngine):
     
@@ -97,8 +98,6 @@
 
 class ZopeIterator(Iterator):
 
-    __allow_access_to_unprotected_subobjects__ = True
-
     # The things below used to be attributes in
     # ZTUtils.Iterator.Iterator, however in zope.tales.tales.Iterator
     # they're methods.  We need BBB on the Python level so we redefine
@@ -122,27 +121,23 @@
     def item(self):
         return super(ZopeIterator, self).item()
 
-    # The following things were in ZTUtils.Iterator.Iterator but
-    # aren't anymore in zope.tales.tales.Iterator.  For a good reason.
-    # They're just insane.
-
+    # This method was on the old ZTUtils.Iterator.Iterator class but
+    # isn't part of the spec.  We'll support it for a short
+    # deprecation period.
     # BBB 2005/05/01 -- to be removed after 12 months
-
     @property
     @deprecate("The 'nextIndex' method has been deprecated and will disappear "
                "in Zope 2.12.  Use 'iterator.index+1' instead.")
     def nextIndex(self):
         return self.index + 1
 
-    @deprecate("The 'first' method has been deprecated and will disappear "
-               "in Zope 2.12.  Use the 'start' property instead.")
+    # 'first' and 'last' are Zope 2 enhancements to the TALES iterator
+    # spec.  See help/tal-repeat.stx for more info
     def first(self, name=None):
         if self.start:
             return True
-        return not self.same_part(name, self._last, self.item)
+        return not self.same_part(name, self._last_item, self.item)
 
-    @deprecate("The 'last' method has been deprecated and will disappear "
-               "in Zope 2.12.  Use the 'end' property instead.")
     def last(self, name=None):
         if self.end:
             return True
@@ -154,9 +149,47 @@
         no = object()
         return getattr(ob1, name, no) == getattr(ob2, name, no) is not no
 
+    # 'first' needs to have access to the last item in the loop
+    def next(self):
+        if self._nextIndex > 0:
+            self._last_item = self.item
+        return super(ZopeIterator, self).next()
+
+class PathIterator(ZopeIterator):
+    """A TALES Iterator with the ability to use first() and last() on
+    subpaths of elements."""
+    # we want to control our own traversal so that we can deal with
+    # 'first' and 'last' when they appear in path expressions
+    implements(ITraversable)
+
+    def traverse(self, name, furtherPath):
+        if name in ('first', 'last'):
+            method = getattr(self, name)
+            # it's important that 'name' becomes a copy because we'll
+            # clear out 'furtherPath'
+            name = furtherPath[:]
+            if not name:
+                name = None
+            # make sure that traversal ends here with us
+            furtherPath[:] = []
+            return method(name)
+        return getattr(self, name)
+
+    def same_part(self, name, ob1, ob2):
+        if name is None:
+            return ob1 == ob2
+        if isinstance(name, basestring):
+            name = name.split('/')
+        try:
+            ob1 = boboTraverseAwareSimpleTraverse(ob1, name, None)
+            ob2 = boboTraverseAwareSimpleTraverse(ob2, name, None)
+        except LookupError:
+            return False
+        return ob1 == ob2
+
 def createZopeEngine():
     e = ZopeEngine()
-    e.iteratorFactory = ZopeIterator
+    e.iteratorFactory = PathIterator
     for pt in ZopePathExpr._default_type_names:
         e.registerType(pt, ZopePathExpr)
     e.registerType('string', StringExpr)

Modified: Zope/branches/ajung-zpt-end-game/lib/python/Products/PageTemplates/PathIterator.py
===================================================================
--- Zope/branches/ajung-zpt-end-game/lib/python/Products/PageTemplates/PathIterator.py	2006-05-22 23:59:14 UTC (rev 68248)
+++ Zope/branches/ajung-zpt-end-game/lib/python/Products/PageTemplates/PathIterator.py	2006-05-23 08:40:04 UTC (rev 68249)
@@ -18,8 +18,8 @@
 """
 import zope.deferredimport
 zope.deferredimport.deprecated(
-    "It has been renamed to ZopeIterator and moved to the "
+    "It has been renamed to PathIterator and moved to the "
     "Products.PageTemplates.Expressions module.  This reference will be "
     "gone in Zope 2.12.",
-    PathIterator = "Products.PageTemplates.Expressions:ZopeIterator"
+    PathIterator = "Products.PageTemplates.Expressions:PathIterator"
     )

Modified: Zope/branches/ajung-zpt-end-game/lib/python/Products/PageTemplates/tests/testHTMLTests.py
===================================================================
--- Zope/branches/ajung-zpt-end-game/lib/python/Products/PageTemplates/tests/testHTMLTests.py	2006-05-22 23:59:14 UTC (rev 68248)
+++ Zope/branches/ajung-zpt-end-game/lib/python/Products/PageTemplates/tests/testHTMLTests.py	2006-05-23 08:40:04 UTC (rev 68249)
@@ -125,15 +125,6 @@
         self.assert_expected(self.folder.t, 'Loop1.html')
 
     def checkFancyLoop(self):
-        # XXX This checks among others for a feature of the
-        # PathIterator which lets you do something like this in a path
-        # expr: iterator/last/bla.  This would check whether the
-        # current item in the iteration was the last one with a
-        # particular 'bla' attribute value.  I wonder whether anyone
-        # actually needs this? I vote for ripping it out.  We can
-        # provide BBB for a certain deprecation period by enabling a
-        # specialized ITraversable adapter for ZopeIterator that works
-        # similar to the old PathIterator.
         self.assert_expected(self.folder.t, 'Loop2.html')
 
     def checkGlobalsShadowLocals(self):



More information about the Zope-Checkins mailing list