Showing posts with label hook. Show all posts
Showing posts with label hook. Show all posts

Tuesday, January 20, 2009

Understanding hooks in ECP.

Hooks in ECP are Python decorators that allow developers to replace existing methods by hooking into them. In fact, there is enough flexibility to decide at run time if the original invocation should be replaced by something new. Possibly depending on the state of some other object in the system.

The hook() decorator accepts two parameters: object, and method. The object parameter specifies the object in which defines the method to be hooked. The method parameter specifies the method to be hooked. The decorated function, the actual hook, must specify the same operation signature as the original method invocation.

For instance, lets say we want to hook the Package.get_name() method. We would define the hook as follows.
#ECP hook demonstration

from enomalism2.model import Package, hook

@hook(Package, Package.get_name)
def hook_get_name(fn, self):
"""Hook into the Package.get_name() method."""
return 'My Package'
Obviously not the most useful hook in the world, we replace the package name that would have been retrieved with a static string. In fact, the original Package.get_name() call is never actually invoked. It is replaced entirely.

Hooks can also be modeled as event subscriptions, where in the system, each method invocation can be considered a published event. Each defined hook can be considered an event subscription. For example, lets modify the previous example to simulate a pre and post event situation.
#ECP hook pre/post event demonstration 

import logging
from enomalism2.model import Package, hook

@hook(Package, Package.get_name)
def hook_get_name(fn, self):
"""Hook into the Package.get_name() method."""
logging.info("Attempting to get the package name...")
result=fn(self)
logging.info("Success.")
return result
Here, our pre-event functionality logs the fact that we are attempting to retrieve the package name. Our post-event functionality logs the fact that the package name retrieval was successful. To contract the first example, the original method is invoked here. We are simply extending the functionality. What is interesting is the fact that we can do so in any direction. We can add pre-invocation functionality, post-invocation functionality; we can replace the invocation entirely if need be.

Wednesday, December 3, 2008

New tools in the TG controllers module

After taking a look at some changes made to the TurboGears controller module in trunk, I must say I'm impressed with the improvements over the current 1.0.x branch.

The first change I noticed was that all classes are now derived from the WSGIController class from the Pylons Python web framework. Also new, and the most interesting in my view, are the hook processing mechanism implemented by the DecoratedController class. What this means is that developers writing TurboGears applications can define hooks that are processed in any of these controller states:
  • before validation
  • before the controller method is called
  • before the rendering takes place
  • after the rendering has happened
If nothing else, I think this will add great value in monitoring the state transitions in larger TurboGears applications. Some requests can be quite large; especially during development time and it is handy to know where this requests are failing. You can now easily log attribute values of your controller instance before validation takes place. This could give some insight as to why the validation is failing with valid values. These hook processors also allow for pre and post processing for every state transition within the controller life-cycle.

It looks like using a controller is not all that different from the current TurboGears. Simply extend the TGController class and expose your methods as needed.