[Checkins] SVN: z3c.caching/trunk/src/z3c/caching/ Update API so that RulesetRegistries are just a convenience layer on top of the ZCA rather than a special global object

Matthew Wilkes matthew at matthewwilkes.co.uk
Mon Dec 28 12:44:31 EST 2009


Log message for revision 107222:
  Update API so that RulesetRegistries are just a convenience layer on top of the ZCA rather than a special global object

Changed:
  A   z3c.caching/trunk/src/z3c/caching/interfaces.py
  D   z3c.caching/trunk/src/z3c/caching/modified.py
  U   z3c.caching/trunk/src/z3c/caching/registry.py
  U   z3c.caching/trunk/src/z3c/caching/tests/test_registry.py

-=-
Added: z3c.caching/trunk/src/z3c/caching/interfaces.py
===================================================================
--- z3c.caching/trunk/src/z3c/caching/interfaces.py	                        (rev 0)
+++ z3c.caching/trunk/src/z3c/caching/interfaces.py	2009-12-28 17:44:31 UTC (rev 107222)
@@ -0,0 +1,27 @@
+from zope.interface import Interface, Attribute
+
+class ICacheRule(Interface):
+    """Represents the cache rule applied to an object."""
+    
+    id = Attribute("The identifier of this cache rule")
+    
+
+class IRulesetRegistry(Interface):
+    
+    def register(obj, rule):
+        """Mark objects that are implementers of `obj` to use the caching 
+        rule `rule`.  The value for `rule` MUST be a valid python identifier.
+        """
+    
+    def unregister(obj):
+        """Remove any prior rule registration attached to obj in this 
+        registry. N.B. registries are hierarchical, a parent may still 
+        provide rules."""
+    
+    def clear():
+        """Remove all rule registrations in this registry."""
+    
+    def lookup(obj):
+        """Return the id of the rule associated with `obj`.  If no rule has 
+        been registered `None` is returned.
+        """
\ No newline at end of file

Deleted: z3c.caching/trunk/src/z3c/caching/modified.py
===================================================================
--- z3c.caching/trunk/src/z3c/caching/modified.py	2009-12-28 16:43:17 UTC (rev 107221)
+++ z3c.caching/trunk/src/z3c/caching/modified.py	2009-12-28 17:44:31 UTC (rev 107222)
@@ -1,34 +0,0 @@
-from zope.dublincore.interfaces import IDCTimes
-from Products.CMFCore.interfaces import ICatalogableDublinCore
-
-
-class ILastModified(Interface):
-    def __call__(context):
-        """Return the last modification date for an object.""" 
-
-
- at adapter(ICatalogableDublinCore)
- at implementer(ILastModified)
-def CatalogableDublinCoreLastModified(obj):
-    return obj.modified()
-
-
- at adapter(IDCTimes)
- at implementer(ILastModified)
-def DCTimesLastModified(obj):
-    return obj.modified()
-
-
- at adapter(IBrowserView)
- at implementer(ILastModified)
-def BrowserViewLastModified(obj):
-    if not has_attr(aq_base(self.context, "context")):
-        return None
-
-    context=aq_base(self.context.context)
-    lm=ILastModified(context, None)
-    if lm is not None:
-        return lm(context)
-
-    return None
-

Modified: z3c.caching/trunk/src/z3c/caching/registry.py
===================================================================
--- z3c.caching/trunk/src/z3c/caching/registry.py	2009-12-28 16:43:17 UTC (rev 107221)
+++ z3c.caching/trunk/src/z3c/caching/registry.py	2009-12-28 17:44:31 UTC (rev 107222)
@@ -1,55 +1,59 @@
-# Rulesets are registered for entities, which can be a type, an interface or even
-# even a specific interface. This means the lookup mechanism needs to be aware
-# of all of those and deal with things like derived classes as well. Luckily
-# we have a framework which already implements that: zope.component.
-#
-# We will (ab)use the zope.component registries by registering a dummy adapter
-# for the entity to a special ICacheRule interface and which will always
-# return the ruleset id.
+""" Rulesets are registered for entities, which can be a type, an interface or
+even even a specific interface. This means the lookup mechanism needs to be
+aware of all of those and deal with things like derived classes as well.
+Luckily we have a framework which already implements that: zope.component.
 
-from zope.interface import Interface
-from zope.component import getGlobalSiteManager
+We will (ab)use the zope.component registries by registering a dummy adapter
+for the entity to a special ICacheRule interface and which will always return
+the ruleset id. """
 
+from zope.interface import implements
+from zope.component import adapts, getGlobalSiteManager
+from zope.component.interfaces import IComponents
 
-class _ICacheRule(Interface):
-    pass
+from interfaces import ICacheRule, IRulesetRegistry
 
+class CacheRule(object):
+    __slots__ = ("id")
+    implements(ICacheRule)
+    
+    def __init__(self, identifier):
+        self.id = identifier
 
 class RulesetRegistry(object):
-    def __init__(self):
-        self._rules=set()
 
+    implements(IRulesetRegistry)
+    adapts(IComponents)
 
-    def register(self, obj, rule):
-        if obj in self._rules:
-            return
+    def __init__(self, registry):
+        self.registry = registry
 
-        gsm=getGlobalSiteManager()
+    def register(self, obj, rule):
         def r(context):
             return lambda r=rule:r
-        gsm.registerAdapter(r, provided=_ICacheRule, required=(obj,))
+        self.registry.registerAdapter(r, provided=ICacheRule, required=(obj,))
+        return None
 
-        self._rules.add(obj)
 
+    def unregister(self, obj):
+        self.registry.unregisterAdapter(provided=ICacheRule, required=(obj,))
+        return None
 
-    def unregister(self, obj, rule):
-        if obj not in self._rules:
-            return
 
-        gsm=getGlobalSiteManager()
-        gsm.unregisterAdapter(provided=_ICacheRule, required=(obj,))
-        self._rules.remove(obj)
-
-
     def clear(self):
-        gsm=getGlobalSiteManager()
-        for obj in self._rules:
-            gsm.unregisterAdapter(provided=_ICacheRule, required=(obj,))
-        self._rules.clear()
+        # We force the iterator to be evaluated to start with as the backing
+        # storage will be changing size
+        for rule in list(self.registry.registeredAdapters()):
+            if rule.provided != ICacheRule:
+                continue # Not our responsibility
+            else:
+                self.registry.unregisterAdapter(factory=rule.factory,
+                                                provided=rule.provided, 
+                                                required=rule.required)
+        return None
 
-
     def lookup(self, obj):
-        ruler=_ICacheRule(obj, None)
+        ruler=ICacheRule(obj, None)
         if ruler is not None:
             return ruler()
         return None
@@ -57,28 +61,8 @@
 
     __getitem__ = lookup
 
+# Set up RulesetRegistry as an adapter for component roots
+getGlobalSiteManager().registerAdapter(RulesetRegistry)
 
-_registry = RulesetRegistry()
-
-unregister = _registry.unregister
-register = _registry.register
-lookup = _registry.lookup
-
-
-def cleanupCacheRulesets():
-    global _registry
-
-    _registry.clear()
-
-try:
-    from zope.testing.cleanup import addCleanUp
-except ImportError:
-    # don't have that part of Zope
-    pass
-else:
-    addCleanUp(cleanupCacheRulesets)
-    del addCleanUp
-
-
-__all__ = [ "register", "unregister", "lookup" ]
-
+def getGlobalRulesetRegistry():
+    return IRulesetRegistry(getGlobalSiteManager())

Modified: z3c.caching/trunk/src/z3c/caching/tests/test_registry.py
===================================================================
--- z3c.caching/trunk/src/z3c/caching/tests/test_registry.py	2009-12-28 16:43:17 UTC (rev 107221)
+++ z3c.caching/trunk/src/z3c/caching/tests/test_registry.py	2009-12-28 17:44:31 UTC (rev 107222)
@@ -1,42 +1,58 @@
 from zope.interface import Interface
 from zope.interface import implements
 from unittest import TestCase
-from z3c.caching.registry import cleanupCacheRulesets
-from z3c.caching.registry import _registry
 
+from z3c.caching.registry import getGlobalRulesetRegistry
+
 class ITestView(Interface):
     pass
 
+class IMoreSpecificTestView(ITestView):
+    pass
 
 class TestView(object):
     implements(ITestView)
 
+class OtherTestView(object):
+    implements(IMoreSpecificTestView)
 
 
 class TestRulesetRegistry(TestCase):
-    def tearDown(self):
-        cleanupCacheRulesets()
 
+    def setUp(self):
+        self.registry = getGlobalRulesetRegistry()
 
-    def testRulesetForInstance(self):
-        _registry.register(TestView, "frop")
+    def test_no_ruleset_returned_if_unregistered(self):
+        self.failUnless(self.registry[None] is None)
+
+    def test_ruleset_for_class(self):
+        self.registry.register(TestView, "frop")
         i=TestView()
-        self.assertEqual(_registry[i], "frop")
+        self.assertEqual(self.registry[i], "frop")
 
+    def test_ruleset_for_interface(self):
+        self.registry.register(ITestView, "frop")
+        i=TestView()
+        self.assertEqual(self.registry[i], "frop")
 
-    def testRulesetViaInterface(self):
-        _registry.register(ITestView, "frop")
+    def test_ruleset_registered_twice(self):
+        self.registry.register(ITestView, "frop")
+        self.registry.register(ITestView, "fribble")
         i=TestView()
-        self.assertEqual(_registry[i], "frop")
+        self.assertEqual(self.registry[i], "frop")
 
+    def test_unregistering_ruleset_removes_ruleset(self):
+        self.registry.register(TestView, "frop")
+        self.registry.unregister(TestView)
+        self.failUnless(self.registry[TestView] is None)
 
-    def testUnknownRulesetReturnsNone(self):
-        self.failUnless(_registry[None] is None)
+    def test_unregistering_nonexistant_ruleset_doesnt_error(self):
+        self.failUnless(self.registry[TestView] is None)
+        self.registry.unregister(TestView)
+        self.failUnless(self.registry[TestView] is None)
 
-
-    def testUnregister(self):
-        _registry.register(TestView, "frop")
-        _registry.unregister(TestView, "frop")
-        self.failUnless(_registry[TestView] is None)
-
-
+    def test_clearing_registry_removes_rulesets(self):
+        self.registry.register(ITestView, "frop")
+        i = TestView()
+        self.registry.clear()
+        self.failUnless(self.registry[i] is None)



More information about the checkins mailing list