Skip to content

Instantly share code, notes, and snippets.

@SebastianHGonzalez
Last active January 21, 2019 13:54
Show Gist options
  • Select an option

  • Save SebastianHGonzalez/baf4c9a1facfb9ce5b163fb9e4612531 to your computer and use it in GitHub Desktop.

Select an option

Save SebastianHGonzalez/baf4c9a1facfb9ce5b163fb9e4612531 to your computer and use it in GitHub Desktop.
AOP example code
class PointCut {
aspects = [];
constructor(definition) {
this.inject(definition);
}
addAspect(aspect) {
this.aspects = [...this.aspects, aspect];
}
inject(definition) {
definition.decoreateTargets(joinPoint => this.decorate(joinPoint));
}
decorate(joinPoint) {
const pointCut = this;
return function (...args) {
const context = this;
pointCut.before(context, joinPoint.name, ...args);
const result = pointCut.around(context, joinPoint, ...args);
pointCut.after(context, joinPoint.name, result, ...args);
return result;
}
}
before(context, joinPointName, ...args) {
this.aspects.reduce(
(_, aspect) => aspect.before(context, joinPointName, ...args)
);
}
after(context, joinPointName, result, ...args) {
return this.aspects.reduce(
(prevResult, aspect) => aspect.after(context, joinPointName, prevResult, ...args),
result
);
}
around(context, joinPoint, ...args) {
return this.aspects.reduce(
function aroundReducer(next, aspect) {
return function joinPointify(...newArgs) {
const newContext = this;
aspect.around(newContext, next, ...newArgs)
}
},
joinPoint
).apply(context, args);
}
}
class PointCutDefinition {
/**
* TODO
*/
decorateTargets(decorator) {
this.decorateMethods(decorator);
}
decorateMethods(decorator) {
this.targetClasses
.map(targetClass => targetClass.prototype)
.forEach(prototype => {
const targetMethods = this.getTargetMethods(targetClass);
targetMethods.forEach(targetMethod => {
prototype[targetMethod.name] = decorator(targetMethod)
})
});
}
}
class LoggerAspect {
constructor(logger) {
this.logger = logger;
}
before(context, joinPointName, ...args) {
this.logger.log("logging");
}
}
class Foo {
bar() {
return 'baz';
}
}
const foo = new Foo();
const definition = new PointCutDefinition();
definition.add({ class: Foo, methodName: "bar" })
const barPointCut = new PointCut(definition);
foo.bar();
// <- "baz"
barPointCut.addAspect(new LoggerAspect(console));
foo.bar();
// "logging"
// <- "baz"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment