summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTres Seaver <tseaver@palladion.com>2015-10-17 14:41:01 -0400
committerTres Seaver <tseaver@palladion.com>2015-10-17 14:41:01 -0400
commit57ad3f9ed99243c1f060964289b543ddcebc48e9 (patch)
tree0cea8d607772e913957603c041d390b9310d6a73
parent2d56e36f354fd69b47e90f1b8367d206aba5273e (diff)
parentd1c63c2ae399d3d2be8b6d2f8536129ac5d5d0d8 (diff)
downloadzope-event-57ad3f9ed99243c1f060964289b543ddcebc48e9.tar.gz
Merge pull request #2 from zopefoundation/classhandler
Classhandler
-rw-r--r--CHANGES.rst4
-rw-r--r--docs/classhandler.rst42
-rw-r--r--docs/index.rst1
-rw-r--r--src/zope/event/classhandler.py70
-rw-r--r--src/zope/event/tests.py12
5 files changed, 127 insertions, 2 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index ebb773e..81120c5 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,11 +1,11 @@
``zope.event`` Changelog
========================
-4.0.4 (unreleased)
+4.1.0 (unreleased)
------------------
- Require 100% branch (as well as statement) coverage.
-
+- Added a simple class-based handler implementation.
4.0.3 (2014-03-19)
------------------
diff --git a/docs/classhandler.rst b/docs/classhandler.rst
new file mode 100644
index 0000000..5385b68
--- /dev/null
+++ b/docs/classhandler.rst
@@ -0,0 +1,42 @@
+Class-based event handlers
+==========================
+
+A light-weight event-handler framework based on event classes is
+provided by the ``zope.event.classhandler`` module.
+
+Handlers are registered for event classes:
+
+ >>> import zope.event.classhandler
+
+ >>> class MyEvent(object):
+ ... def __repr__(self):
+ ... return self.class.__name__
+
+ >>> def handler1(event):
+ ... print("handler1 %r" % event)
+
+ >>> zope.event.classhandler.handler(MyEvent, handler1)
+
+Descriptor syntax:
+
+ >>> @zope.event.classhandler.handler(MyEvent)
+ ... def handler2(event):
+ ... print("handler2 %r" % event)
+
+ >>> class MySubEvent(MyEvent):
+ ... pass
+
+ >>> @zope.event.classhandler.handler(MySubEvent)
+ ... def handler3(event):
+ ... print("handler3 %r" % event)
+
+
+Subscribers are called in class method-resolution order, so only
+new-style event classes are supported, and then by order of registry.
+
+ >>> import zope.event
+ >>> zope.event.notify(MySubEvent())
+ handler3 MySubEvent
+ handler1 MySubEvent
+ handler2 MySubEvent
+
diff --git a/docs/index.rst b/docs/index.rst
index 6fd6e4b..0d5be8b 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -19,6 +19,7 @@ Contents:
usage
theory
api
+ classhandler
hacking
Indices and tables
diff --git a/src/zope/event/classhandler.py b/src/zope/event/classhandler.py
new file mode 100644
index 0000000..0a1df59
--- /dev/null
+++ b/src/zope/event/classhandler.py
@@ -0,0 +1,70 @@
+"""Class-based event handlers
+
+
+A light-weight event-handler framework based on event classes.
+
+Handlers are registered for event classes:
+
+ >>> import zope.event.classhandler
+
+ >>> class MyEvent(object):
+ ... def __repr__(self):
+ ... return self.__class__.__name__
+
+ >>> def handler1(event):
+ ... print("handler1 %r" % event)
+
+ >>> zope.event.classhandler.handler(MyEvent, handler1)
+
+Descriptor syntax:
+
+ >>> @zope.event.classhandler.handler(MyEvent)
+ ... def handler2(event):
+ ... print("handler2 %r" % event)
+
+ >>> class MySubEvent(MyEvent):
+ ... pass
+
+ >>> @zope.event.classhandler.handler(MySubEvent)
+ ... def handler3(event):
+ ... print("handler3 %r" % event)
+
+
+Subscribers are called in class method-resolution order, so only
+new-style event classes are supported, and then by order of registry.
+
+ >>> import zope.event
+ >>> zope.event.notify(MySubEvent())
+ handler3 MySubEvent
+ handler1 MySubEvent
+ handler2 MySubEvent
+
+"""
+import zope.event
+
+registry = {}
+
+def handler(event_class, handler_=None, decorator=False):
+ """Define an event handler for a (new-style) class.
+
+ This can be called with a class and a handler, or with just a
+ class and the result used as a handler decorator.
+ """
+ if handler_ is None:
+ return lambda func: handler(event_class, func, True)
+
+ if not registry:
+ zope.event.subscribers.append(dispatch)
+
+ if event_class not in registry:
+ registry[event_class] = [handler_]
+ else:
+ registry[event_class].append(handler_)
+
+ if decorator:
+ return handler
+
+def dispatch(event):
+ for event_class in event.__class__.__mro__:
+ for handler in registry.get(event_class, ()):
+ handler(event)
diff --git a/src/zope/event/tests.py b/src/zope/event/tests.py
index a7b045d..eed5562 100644
--- a/src/zope/event/tests.py
+++ b/src/zope/event/tests.py
@@ -13,6 +13,7 @@
##############################################################################
""" Test the event system
"""
+import doctest
import unittest
class Test_notify(unittest.TestCase):
@@ -42,7 +43,18 @@ class Test_notify(unittest.TestCase):
self._callFUT(event)
self.assertEqual(dummy, [event])
+def setUpClassHandlers(test):
+ import zope.event
+ test.globs['old_subs'] = zope.event.subscribers
+
+def tearDownClassHandlers(test):
+ import zope.event
+ zope.event.subscribers = test.globs['old_subs']
+
def test_suite():
return unittest.TestSuite((
unittest.makeSuite(Test_notify),
+ doctest.DocTestSuite(
+ 'zope.event.classhandler',
+ setUp=setUpClassHandlers, tearDown=tearDownClassHandlers)
))