proof-of-concept for a simple AOP implementation
git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@1966 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
c978861b04
commit
171b3c76bc
2 changed files with 45 additions and 8 deletions
27
util/aop.py
27
util/aop.py
|
@ -34,13 +34,22 @@ class Notifier(object):
|
|||
def __init__(self, method):
|
||||
self.method = method
|
||||
obj = method.im_self or method.im_class
|
||||
name = method.im_func.func_name
|
||||
name = self.name = method.im_func.func_name
|
||||
setattr(obj, name, self)
|
||||
self.beforeSubs = []
|
||||
self.afterSubs = []
|
||||
|
||||
def __get__(self, instance, cls=None):
|
||||
return BoundNotifier(self, instance)
|
||||
if instance is None:
|
||||
# class-level access
|
||||
return self
|
||||
existing = instance.__dict__.get(self.name)
|
||||
if isinstance(existing, BoundNotifier):
|
||||
# the instance's method is already wrapped
|
||||
return existing
|
||||
notifier = BoundNotifier(self, instance)
|
||||
setattr(instance, self.name, notifier)
|
||||
return notifier
|
||||
|
||||
def __call__(self, *args, **kw):
|
||||
for sub, sargs, skw in self.beforeSubs:
|
||||
|
@ -62,15 +71,21 @@ class BoundNotifier(object):
|
|||
def __init__(self, context, instance):
|
||||
self.context = context
|
||||
self.instance = instance
|
||||
self.beforeSubs = []
|
||||
self.afterSubs = []
|
||||
|
||||
def __call__(self, *args, **kw):
|
||||
for sub, sargs, skw in self.context.beforeSubs:
|
||||
context = self.context
|
||||
for sub, sargs, skw in self.beforeSubs + context.beforeSubs:
|
||||
sub(None, *sargs, **skw)
|
||||
result = self.context.method(self.instance, *args, **kw)
|
||||
for sub, aargs, akw in self.context.afterSubs:
|
||||
result = context.method(self.instance, *args, **kw)
|
||||
for sub, aargs, akw in self.afterSubs + context.afterSubs:
|
||||
sub(result, *aargs, **akw)
|
||||
return result
|
||||
|
||||
def subscribe(self, before, after, *args, **kw):
|
||||
self.context.subscribe(before, after, *args, **kw)
|
||||
if before is not None:
|
||||
self.beforeSubs.append((before, args, kw))
|
||||
if after is not None:
|
||||
self.afterSubs.append((after, args, kw))
|
||||
|
||||
|
|
26
util/aop.txt
26
util/aop.txt
|
@ -28,8 +28,8 @@ Calling the wrapped method still works.
|
|||
>>> demo.foo(8)
|
||||
46
|
||||
|
||||
We can now get information about the returning of the method by
|
||||
subscribing to it using some log function.
|
||||
We can now get information about the start and end of the method call by
|
||||
subscribing to it using a logging routine.
|
||||
|
||||
>>> def log(result, msg):
|
||||
... print 'logging: %s, result=%s' % (msg, str(result))
|
||||
|
@ -51,14 +51,36 @@ subscribing to it using some log function.
|
|||
Wrapping methods on class level
|
||||
===============================
|
||||
|
||||
The above code did only wrap the bound method ``foo()`` of a certain
|
||||
instance of the ``Demo`` class. Other instances of this class are not
|
||||
affected.
|
||||
|
||||
>>> demo = Demo()
|
||||
>>> demo.foo(4)
|
||||
42
|
||||
|
||||
But we may also wrap the class itself and subscribe to the method on
|
||||
the class level.
|
||||
|
||||
>>> getNotifier(Demo.foo)
|
||||
<...Notifier object ...>
|
||||
>>> Demo.foo.subscribe(None, log, 'after foo')
|
||||
|
||||
This now affects all instances of the class.
|
||||
|
||||
>>> demo.foo(4)
|
||||
logging: after foo, result=42
|
||||
42
|
||||
>>> demo.foo(8)
|
||||
logging: after foo, result=46
|
||||
46
|
||||
|
||||
Combining class and instance level wrapping
|
||||
-------------------------------------------
|
||||
|
||||
>>> demo.foo.subscribe(None, log, 'after demo.foo')
|
||||
>>> demo.foo(10)
|
||||
logging: after demo.foo, result=48
|
||||
logging: after foo, result=48
|
||||
48
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue