[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