My excursions into the dark recess of my
/js directory continue.
This was originally something I wrote a while back when I was learning
about Aspect-oriented programming in Java and wanted see how
it turned out, writing the core functions wasn’t that complicated at
This is basically all there is to it. The
Aop.around() method takes
a pointcut (a regexp pattern), a reference to the advice
(function reference) to be applied and an optional list of namespaces
then loops through all slots in each namespace (defaulting to the
global object if no namespaces were specified) and replaces any
functions whose name matches the pointcut pattern with a wrapper
Aop.next() method is just a convenience: it is used to pass
control over to the original function.
All right, time for an example. Everyone loves examples, right? Right. Here’s me defining a trivial function in the global namespace:
REPL i can run directly from the command line. You should be
able to embed the script in a web page and run it from the
Firebug console as well, but you’ll have to change
Now, let’s apply some around advice to my greeter function:
So, what’s happening here? We’re telling Aop.js that we want to add a
wrapper around all functions starting with the name ‘hello’ in the
global namespace. Upon function invocation, this wrapper function
calls the advice function with a map of named parameters such as the
orignal name of the function being called, a reference to the original
function and a list of function arguments. What happens then is up to
the advice function; in this case it just calls the original method
Aop.next()), printing out a message before and after the
call. Not very exciting perhaps, but certainly proof of concept.
But wait, did I just say that the function arguments is passed on to the advice function? I sure did. Does that mean that I can manipulate them before the original function is called? You bet:
Naturally, the same goes for return values, only in reverse. The advice function is free to pass on whatever the original function returns, or return something different if it wants to:
Before() and after() advice
It is quite easy adding support for before and after advice if we
define them using
These are simpler convenience methods that adds an advice function
that will be called before and after function invocation,
respectively. In order to make them easy to use, I’ve chosen to
simplify the advice functions a bit. Unlike
Aop.around() they get
called with the same arguments as the original function (and not with
a parameter map).
Unfortunatly, stripping down the API like this makes certain things
Aop.after(). You can’t inspect
the name of the current function for example, or manipulate it’s
arguments or return values. But hey, in that case just use
Aop.around() instead. It’s simple enough.
When I rediscovered this script it looked quite different, and as I started hacking more on it to write this post I found myself refactoring, adding code, and removing. And removing. And removing. Now only the really necessary parts remain, and there’s a certain beauty in that.