Skip to content

Instantly share code, notes, and snippets.

@fundon
Created July 8, 2011 09:00
Show Gist options
  • Save fundon/1071396 to your computer and use it in GitHub Desktop.
Save fundon/1071396 to your computer and use it in GitHub Desktop.
JavaScript, Aspect Oriented Programming(AOP)
function AOP(obj, advice) {
this._instance = obj;
this._advice = advice;
}
AOP.prototype = {
_method: null,
_params: null,
result: null,
setAdviceResult: function(result) {
this.result = result;
},
getAdviceResult: function() {
return this.result;
},
proceed: function() {
if (this._instance instanceof AOP) {
this._instance.setAdviceResult(this.getAdviceResult());
}
//console.log(this._params);
return this._instance[this._method].apply(this._instance, this._params);
}
};
AOP.getInstance = function(target, advice) {
var _class = target['class'], _method = target['method'];
var obj = new _class();
var method = obj[_method];
var depth = 0;
do {
obj = new AOP(obj, advice);
obj[_method] = function() {
return function() {
this._params = arguments;
try {
try {
var ret = this._advice.aroundAdvice(this);
return ret;
} catch (e) {
this._advice.beforeAdvice();
var ret = this.proceed();
this._advice.afterAdvice();
return ret;
}
} catch (e) {
return this._advice.throwsAdvice(e);
}
}
}();
obj._method = _method;
obj.depth = depth++;
//console.log(obj.depth + '-' + advice.name);
} while (advice = advice.getPreAdvice());
return obj;
}
function Advice(advice) {
if (advice) {
this._pre_advice = advice;
}
}
Advice.prototype = {
_pre_advice: null,
getPreAdvice: function() {
return this._pre_advice;
},
beforeAdvice: function() {},
afterAdvice: function() {},
aroundAdvice: function(aop) {
throw new Error();
},
throwsAdvice: function(error) {
return error;
}
};
function LogAdvice() {
Advice.call(this, arguments[0]);
this.name = 'Log Advice';
//console.log(this.name);
}
LogAdvice.prototype.__proto__ = Advice.prototype;
LogAdvice.prototype.aroundAdvice = function(aop) {
console.log('Log Around Advice before');
var ret = aop.proceed();
console.log('Log Around Advice after');
return ret;
}
function CacheAdvice() {
Advice.call(this, arguments[0]);
this.name = 'Cache Advice';
//console.log(this.name);
}
CacheAdvice.prototype.__proto__ = Advice.prototype;
CacheAdvice.prototype.aroundAdvice = function(aop) {
console.log('Cache Around Advice before');
var ret = aop.proceed();
console.log('Cache Around Advice after');
return ret;
}
function PermissionAdvice() {
Advice.call(this, arguments[0]);
this.name = 'Permission Advice';
//console.log(this.name);
}
PermissionAdvice.prototype.__proto__ = Advice.prototype;
PermissionAdvice.prototype.aroundAdvice = function(aop) {
//console.log('Permission Around Advice before');
//var ret = aop.proceed();
//console.log('Permission Around Advice after');
//return ret;
throw new Error('Permission fail');
}
PermissionAdvice.prototype.beforeAdvice = function() {
console.log('Permission Before Advice');
}
function User() {
this.name = 'User Class';
}
User.prototype.foobar = function() {
console.log('Hello foobar');
return 'User.foobar';
}
User.prototype.login = function() {
console.log('I did it');
}
var user = AOP.getInstance({'class': User, 'method': 'foobar'}, new CacheAdvice(new LogAdvice(new PermissionAdvice())));
user.foobar(1,2,34);
//var user = AOP.getInstance({'class': User, 'method': 'login'}, new CacheAdvice(new PermissionAdvice()));
//user.login();
//console.dir(user);
//console.log(user instanceof AOP);
function AOP(obj, advice) {
this._instance = obj;
this._advice = advice;
}
AOP.prototype = {
_method: null,
_params: null,
result: null,
setAdviceResult: function(result) {
this.result = result;
},
getAdviceResult: function() {
return this.result;
},
proceed: function() {
if (this._instance instanceof AOP) {
this._instance.setAdviceResult(this.getAdviceResult());
}
//console.log(this._params);
return this._instance[this._method].apply(this._instance, this._params);
}
};
AOP.getInstance = function(target, advice) {
var _class = target['class'], _method = target['method'];
var obj = new _class();
var method = obj[_method];
var __method = _method.toLowerCase();
var depth = 0;
do {
obj = new AOP(obj, advice);
obj[_method] = function() {
return function() {
this._params = arguments;
try {
try {
//var ret = this._advice.aroundAdvice(this);
var ret = (this._advice['around_' + __method] || function(aop){return aop.proceed();})(this);
return ret;
} catch (e) {
//this._advice.beforeAdvice();
//var ret = this.proceed();
//this._advice.afterAdvice();
(this._advice['before_' + __method] || function(){})();
var ret = this.proceed();
(this._advice['after_' + __method] || function(){})();
return ret;
}
} catch (e) {
return this._advice.throwsAdvice(e);
}
}
}();
obj._method = _method;
obj.depth = depth++;
//console.log(obj.depth + '-' + advice.name);
} while (advice = advice.getPreAdvice());
return obj;
}
function Advice(advice) {
if (advice) {
this._pre_advice = advice;
}
}
Advice.prototype = {
_pre_advice: null,
getPreAdvice: function() {
return this._pre_advice;
},
beforeAdvice: function() {},
afterAdvice: function() {},
aroundAdvice: function(aop) {
throw new Error();
},
throwsAdvice: function(error) {
return error;
}
};
function LogAdvice() {
Advice.call(this, arguments[0]);
this.name = 'Log Advice';
//console.log(this.name);
}
LogAdvice.prototype.__proto__ = Advice.prototype;
LogAdvice.prototype.aroundAdvice = function(aop) {
console.log('Log Around Advice before');
var ret = aop.proceed();
console.log('Log Around Advice after');
return ret;
}
function CacheAdvice() {
Advice.call(this, arguments[0]);
this.name = 'Cache Advice';
//console.log(this.name);
}
CacheAdvice.prototype.__proto__ = Advice.prototype;
CacheAdvice.prototype.aroundAdvice = function(aop) {
console.log('Cache Around Advice before');
var ret = aop.proceed();
console.log('Cache Around Advice after');
return ret;
}
function PermissionAdvice() {
Advice.call(this, arguments[0]);
this.name = 'Permission Advice';
//console.log(this.name);
}
PermissionAdvice.prototype.__proto__ = Advice.prototype;
PermissionAdvice.prototype.aroundAdvice = function(aop) {
//console.log('Permission Around Advice before');
//var ret = aop.proceed();
//console.log('Permission Around Advice after');
//return ret;
throw new Error('Permission fail');
}
PermissionAdvice.prototype.beforeAdvice = function() {
console.log('Permission Before Advice');
}
PermissionAdvice.prototype.around_foobar = function() {
console.log('Permission around, foobar');
throw new Error('Permission around fail');
}
PermissionAdvice.prototype.before_foobar = function() {
console.log('Permission before, foobar');
}
function User() {
this.name = 'User Class';
}
User.prototype.foobar = function() {
console.log('Hello foobar');
return 'User.foobar';
}
User.prototype.login = function() {
console.log('I did it');
}
var user = AOP.getInstance({'class': User, 'method': 'foobar'}, new CacheAdvice(new LogAdvice(new PermissionAdvice())));
user.foobar(1,2,34);
var user = AOP.getInstance({'class': User, 'method': 'login'}, new CacheAdvice(new PermissionAdvice()));
user.login();
//console.dir(user);
//console.log(user instanceof AOP);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment