=======================================
Aspect-oriented Programming for Dummies
=======================================

$Id$

  >>> from cybertools.util.aop import getNotifier

  >>> class Demo(object):
  ...     def foo(self, num):
  ...         return 38 + num

  >>> demo = Demo()
  >>> demo.foo(4)
  42

  >>> wrappedFoo = getNotifier(demo.foo)
  >>> demo.foo is wrappedFoo
  True

Repeated calls of ``getNotifier()`` return the same wrapped object.

  >>> getNotifier(demo.foo) is wrappedFoo
  True

Calling the wrapped method still works.

  >>> demo.foo(8)
  46

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))

  >>> demo.foo.subscribe(log, None, 'before foo')

  >>> demo.foo(4)
  logging: before foo, result=None
  42

  >>> demo.foo.subscribe(log, log, "that's foo")
  >>> demo.foo(4)
  logging: before foo, result=None
  logging: that's foo, result=None
  logging: that's foo, result=42
  42


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

