Evented AOP for NodeJS
Evented Aspect Oriented Programming
npm install rubberduck
or clone the GitHub repository.
var rubberduck = require('rubberduck');
Lets punch the push method of an array instance and log the element that gets pushed before the method executes and the new length of the array (returned by Array.push) and the pushed element when it returns.
var rubberduck = require'rubberduck'myarray =emitter = rubberduckemittermyarraypunch'push';emitteron'beforePush'console.log'About to push ' + args0;;emitteron'afterPush'console.log'Pushed ' + args0 + ', the new length is ' + result;;myarraypush'Test';
Once you picked the methods to be punched the emitter fires the following events:
// Before any punched method executesemitteron'before'// args : Array of function arguments// instance: The function context (this reference)// name : The function name;// After any punched method returnedemitteron'after'// result : The return value or an array of// the callback arguments for asynchronous functions// args : Array of function arguments// instance: The function context (this reference)// name : The function name;
You can also listen to specific events by using camelcased event names. To get evnts only for the test method, attach the following event listener:
The parameters are the same as in the general event listeners.
You can also punch asynchronous methods, that execute a callback instead of returning the value. In this case the after events receives an array of the callback parameters instead of a single return value. Just tell the event emitter the position of the callback in your arguments list when punching a method (use -1 if the callback is at the end of the argument list):
var rubberduck = require'rubberduck'thisname = name;callbacknull thisname + ' quacks!';var donald = 'Donald'emitter = rubberduckemitterdonaldpunch'quack' 0;// Log the callback results for _quack_emitteron'afterQuack'// Results contains the callback argumentsconsole.logresults;;
You can also punch an objects prototype to receive events about all its instances but it is important to be selective about what methods to punch. Firing events on methods that get called many times (e.g. attaching to the Array.prototype) might lead to big performance hits and can quickly exceed the maximum call stack size.
Methods that throw instead of return will still call the after event handlers, with the error
provided as the result instead. This includes asynchronous functions with callbacks both before
and after the callback occurs. These methods fire
errorMethod events in place
afterMethod events. Asynchronous methods that return an
object as the first argument to the callback will also fire error-type events rather than after.
A second optional parameter to
punch (the third argument) is a flag indicating whether or not
rubberduck should be strict with the signature of the resulting function. This means the
property of any punched method will remain the same (rather than revert to zero), at the cost of
a slightly more expensive mechanism to punch the methods, and is off by default.
wrapAsyncshould still return the original value (#5)
Copyright (C) 2014 David Luecke firstname.lastname@example.org
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.