Skip to content

Instantly share code, notes, and snippets.

@voloko
Created May 14, 2009 12:16
Show Gist options
  • Save voloko/111639 to your computer and use it in GitHub Desktop.
Save voloko/111639 to your computer and use it in GitHub Desktop.
/**
* Aspects for js (Function call interception)
* Released under the MIT License
* @copyright 2009 Vladimir Kolesnikov
* @author Vladimir Kolesnikov <voloko@gmail.com>
*/
var Aspect = new function() {
this.add = function(obj, aspectName, aspect) {
for (var selector in aspect) {
if (!aspect.hasOwnProperty(selector)) continue;
wrapMethod(obj, selector, aspect[selector])
}
obj.__aspects = obj.__aspects || {};
obj.__aspects[aspectName] = aspect;
},
this.remove = function(obj, aspectName) {
var aspect = obj.__aspects[aspectName],
selector;
for (selector in aspect) {
if (!aspect.hasOwnProperty(selector)) continue;
unwrapMethod(obj, selector, aspect[selector]);
}
delete obj.__aspects[aspectName];
}
function wrapMethod(obj, selector, wrapper) {
var wrapperDescription = getWrapperDescription(selector),
method, runBefore = false;
method = obj[wrapperDescription.methodName];
if (!method.__wrappers) {
method = obj[wrapperDescription.methodName] = createInterceptor(method);
};
method.__wrappers[wrapperDescription.runBefore ? 'before' : 'after'].push(wrapper);
}
function unwrapMethod(obj, selector, wrapper) {
var wrapperDescription = getWrapperDescription(selector),
method = obj[wrapperDescription.methodName],
wrappers = method.__wrappers;
wrappers.before = without(wrappers.before, wrapper);
wrappers.after = without(wrappers.after, wrapper);
}
function getWrapperDescription(selector) {
var match = selector.match(/^((after|before) )?(.*)$/);
return {
runBefore: !match || match[2] != "after",
methodName: match ? match[3] : selector
}
}
function without(array, item) {
var result = [];
for (var i=0, l = array.length; i < l; i++) {
if (array[i] != item) result[result.length] = array[i];
};
return result;
}
function createInterceptor(method) {
var interceptor = function() {
for (var items = interceptor.__wrappers.before, l = items.length, i = 0; i < l; i++) {
try{
items[i].apply(this, arguments);
} catch (e) {
if (e instanceof AspectReturnException) return e.value;
throw e
}
}
var result = method.apply(this, arguments);
for (items = interceptor.__wrappers.after, l = items.length, i = 0; i < l; i++) {
try {
items[i].apply(this, arguments);
} catch (e) {
throw e;
}
}
return result;
}
interceptor.__wrappers = {
before: [],
after: []
}
return interceptor;
}
};
var AspectReturnException = function(value) { this.value = value }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment