Comparing version 1.1.0 to 1.2.0
@@ -13,2 +13,4 @@ # meld.js API | ||
1. [Removing Method Advice](#removing-method-advice) | ||
1. [Accessing the Joinpoint](#accessing-the-joinpoint) | ||
* [meld.joinpoint](#meldjoinpoint) | ||
1. [Constructor-specific Info](#constructor-specific-info) | ||
@@ -179,4 +181,6 @@ | ||
Meld.js allows you to add any number of advices to a method, function, or constructor. In addition to adding them individually, as [shown here](api.md#advising-methods), using the individual advice methods (e.g. meld.before, meld.after, etc.), you can also add several advices at once using `meld.add()`. | ||
Meld.js allows you to add any number of advices to a method, function, or constructor. In addition to adding them individually, as [shown here](#advising-methods), using the individual advice methods (e.g. meld.before, meld.after, etc.), you can also add several advices at once using `meld.add()`. | ||
For example, the [bundled aspects](aspects.md) are implemented this way, and can be added using `meld.add()`. | ||
## meld.add | ||
@@ -215,2 +219,17 @@ | ||
# Accessing the Joinpoint | ||
[Around advice](#meldaround) receives the current [joinpoint](reference.md#joinpoint) as a parameter. Other advice types can use `meld.joinpoint()` to retrieve the current joinpoint. | ||
## meld.joinpoint | ||
```js | ||
function myBeforeAdvice() { | ||
var joinpoint = meld.joinpoint(); | ||
// Use joinpoint fields as necessary | ||
} | ||
``` | ||
**IMPORTANT:** The returned joinpoint is only valid within the advice function where it was retrieved by calling `meld.joinpoint`. You should not cache the joinpoint returned by `meld.joinpoint()` and attempt to use it outside of an advice function, or in different advice functions from that which it was originally retrieved. | ||
# Constructor-specific Info | ||
@@ -217,0 +236,0 @@ |
@@ -11,3 +11,5 @@ # meld.js Reference | ||
* [Around](#around) | ||
* [Joinpoint](#joinpoint) | ||
1. [Joinpoint](#joinpoint) | ||
1. [Accessing the Joinpoint](#accessing-the-joinpoint) | ||
2. [Around Joinpoint](#around-joinpoint) | ||
1. [Advice Order](#advice-order) | ||
@@ -108,8 +110,34 @@ 1. [Advising Methods](#advising-methods) | ||
Around advice receives a [Joinpoint](#joinpoint) as its only parameter, which it can use to access the original arguments, context, and method name of the original function, as well as allow the original function to continue, with either its original arguments, or a modified list of arguments. | ||
Around advice receives an [Around Joinpoint](#around-joinpoint) as its only parameter, which it can use to access the original arguments, context, and method name of the original function, as well as allow the original function to continue, with either its original arguments, or a modified list of arguments. | ||
### Joinpoint | ||
# Joinpoint | ||
A joinpoint is the point at which a method or function was intercepted. Think of it as a description of the original function invocation. It provides the arguments with which the original method was called, the method name (in the case of an object method), and its own methods for allowing the original method call to continue and getting its result. | ||
A joinpoint is the point at which a method or function was intercepted. Think of it as a description of the original function invocation. It provides the arguments with which the original method was called, the method name (in the case of an object method), and the context with which the method was called. | ||
A joinpoint has the following properties: | ||
* target - context with which the original method was called | ||
* method - String name of the method that was called | ||
* args - Array of arguments that were passed to the method | ||
## Accessing the Joinpoint | ||
Around advice always receives the current [around joinpoint](#around-joinpoint) as its only argument. | ||
From *inside* any other advice type (before, after, etc.) you may access the current joinpoint by calling `meld.joinpoint()`. It will return the joinpoint within which the current advice function is executing. | ||
When called from *outside* an advice function, `meld.joinpoint()` always returns undefined. | ||
**IMPORTANT:** The returned joinpoint is only valid within the advice function where it was retrieved by calling `meld.joinpoint`. You should not cache the joinpoint returned by `meld.joinpoint()` and attempt to use it outside of an advice function, or in different advice functions from that which it was originally retrieved. | ||
## Around Joinpoint | ||
Around advice receives as its only argument, an augmented joinpoint, sometimes called a "proceeding joinpoint". It has the same fields as a regular joinpoint, with the addition of "proceed" methods for allowing the original method call to continue and getting its result. | ||
An around joinpoint has the following additional properties: | ||
* proceed() - function that around advice should call to proceed to the original method invocation. You may pass arguments to `proceed()` and they will be used *instead of* the original arguments. It will return the result of the original method, or throw an exception if the original method throws. | ||
* proceedApply:`Function` - similar to `proceed()` but accepts an Array of new arguments, e.g. `proceedApply([1, 2, 3])` is equivalent to `proceed(1, 2, 3)` | ||
* proceedCount() - function that returns the number of times that `proceed()` and/or `proceedApply()` have been called *within the current around advice*. | ||
# Advice Order | ||
@@ -116,0 +144,0 @@ |
132
meld.js
@@ -12,3 +12,3 @@ /** @license MIT License (c) copyright B Cavalier & J Hann */ | ||
* | ||
* @version 1.1.0 | ||
* @version 1.2.0 | ||
*/ | ||
@@ -18,6 +18,32 @@ (function (define) { | ||
var ap, prepend, append, iterators, slice, isArray, defineProperty, freeze; | ||
freeze = Object.freeze || function (o) { return o; }; | ||
var meld, currentJoinpoint, joinpointStack, | ||
ap, prepend, append, iterators, slice, isArray, defineProperty; | ||
// | ||
// Public API | ||
// | ||
meld = { | ||
// General add aspect | ||
// Returns a function that will remove the newly-added aspect | ||
add: addAspect, | ||
// Add a single, specific type of advice | ||
// returns a function that will remove the newly-added advice | ||
before: adviceApi('before'), | ||
around: adviceApi('around'), | ||
on: adviceApi('on'), | ||
afterReturning: adviceApi('afterReturning'), | ||
afterThrowing: adviceApi('afterThrowing'), | ||
after: adviceApi('after'), | ||
// Access to the current joinpoint in advices | ||
joinpoint: joinpoint | ||
}; | ||
// TOOD: Freeze joinpoints when v8 perf problems are resolved | ||
// freeze = Object.freeze || function (o) { return o; }; | ||
joinpointStack = []; | ||
ap = Array.prototype; | ||
@@ -63,3 +89,3 @@ prepend = ap.unshift; | ||
advised = this.advised = function() { | ||
var context, args, callOrig, result, afterType, exception; | ||
var context, joinpoint, args, callOrig, afterType; | ||
@@ -92,23 +118,36 @@ // If called as a constructor (i.e. using "new"), create a context | ||
advisor._callSimpleAdvice('before', context, args); | ||
// Save the previous joinpoint and set the current joinpoint | ||
joinpoint = pushJoinpoint({ | ||
target: context, | ||
method: func, | ||
args: args | ||
}); | ||
try { | ||
result = advisor._callAroundAdvice(context, func, args, callOrigAndOn); | ||
} catch(e) { | ||
result = exception = e; | ||
// Switch to afterThrowing | ||
afterType = 'afterThrowing'; | ||
} | ||
advisor._callSimpleAdvice('before', context, args); | ||
args = [result]; | ||
try { | ||
joinpoint.result = advisor._callAroundAdvice(context, func, args, callOrigAndOn); | ||
} catch(e) { | ||
joinpoint.result = joinpoint.exception = e; | ||
// Switch to afterThrowing | ||
afterType = 'afterThrowing'; | ||
} | ||
callAfter(afterType, args); | ||
callAfter('after', args); | ||
args = [joinpoint.result]; | ||
if(exception) { | ||
throw exception; | ||
callAfter(afterType, args); | ||
callAfter('after', args); | ||
if(joinpoint.exception) { | ||
throw joinpoint.exception; | ||
} | ||
return joinpoint.result; | ||
} finally { | ||
// Restore the previous joinpoint, if necessary. | ||
popJoinpoint(); | ||
} | ||
return result; | ||
function callOrigAndOn(args) { | ||
@@ -191,3 +230,4 @@ var result = callOrig(args); | ||
// Joinpoint is immutable | ||
joinpoint = freeze({ | ||
// TODO: Use Object.freeze once v8 perf problem is fixed | ||
joinpoint = pushJoinpoint({ | ||
target: context, | ||
@@ -201,4 +241,8 @@ method: method, | ||
// Call supplied around advice function | ||
return around.call(context, joinpoint); | ||
try { | ||
// Call supplied around advice function | ||
return around.call(context, joinpoint); | ||
} finally { | ||
popJoinpoint(); | ||
} | ||
@@ -293,3 +337,3 @@ /** | ||
* @param methodName {String} name of method on target for which to get an advisor | ||
* @return {Object} existing or newly created advisor for the supplied method | ||
* @return {Object|undefined} existing or newly created advisor for the supplied method | ||
*/ | ||
@@ -318,21 +362,2 @@ Advisor.get = function(target, methodName) { | ||
// | ||
// Public API | ||
// | ||
return { | ||
// General add aspect | ||
// Returns a function that will remove the newly-added aspect | ||
add: addAspect, | ||
// Add a single, specific type of advice | ||
// returns a function that will remove the newly-added advice | ||
before: adviceApi('before'), | ||
around: adviceApi('around'), | ||
on: adviceApi('on'), | ||
afterReturning: adviceApi('afterReturning'), | ||
afterThrowing: adviceApi('afterThrowing'), | ||
after: adviceApi('after') | ||
}; | ||
function addAspect(target, pointcut, aspect) { | ||
@@ -510,3 +535,4 @@ // pointcut can be: string, Array of strings, RegExp, Function(targetObject): Array of strings | ||
try { | ||
Object.defineProperty(instance, 'constructor', { | ||
// Try to define a constructor, but don't care if it fails | ||
defineProperty(instance, 'constructor', { | ||
value: C, | ||
@@ -536,7 +562,19 @@ enumerable: false | ||
function joinpoint() { | ||
return currentJoinpoint; | ||
} | ||
function pushJoinpoint(newJoinpoint) { | ||
joinpointStack.push(currentJoinpoint); | ||
return currentJoinpoint = newJoinpoint; | ||
} | ||
function popJoinpoint() { | ||
return currentJoinpoint = joinpointStack.pop(); | ||
} | ||
return meld; | ||
}); | ||
})(typeof define == 'function' && define.amd | ||
? define | ||
: function (factory) { module.exports = factory(); } | ||
// Boilerplate for AMD and CommonJS | ||
})(typeof define == 'function' && define.amd ? define : function (factory) { module.exports = factory(); } | ||
); |
{ | ||
"name": "meld", | ||
"version": "1.1.0", | ||
"version": "1.2.0", | ||
"description": "AOP for JS with before, around, on, afterReturning, afterThrowing, after advice, and pointcut support", | ||
@@ -5,0 +5,0 @@ "keywords": ["aop", "aspect", "cujo"], |
@@ -30,2 +30,3 @@ [![Build Status](https://secure.travis-ci.org/cujojs/meld.png)](http://travis-ci.org/cujojs/meld) | ||
* [Reference](meld/blob/master/docs/reference.md) | ||
* [Aspects](meld/blob/master/docs/aspects.md) | ||
@@ -76,2 +77,10 @@ # Quick Start | ||
### 1.2.0 | ||
* `meld.joinpoint()` - [Access the current joinpoint](meld/blob/master/docs/api.md#meldjoinpoint) from any advice type. | ||
* [Bundled aspects](meld/blob/master/docs/aspects.md): | ||
* trace: trace method call entry/return/throw | ||
* memoize: simple memoization for methods and functions | ||
* cache: configurable caching aspect to do more than simple memoization | ||
### 1.1.0 | ||
@@ -78,0 +87,0 @@ |
@@ -1,3 +0,3 @@ | ||
(function(buster, aop) { | ||
"use strict"; | ||
(function(buster, meld) { | ||
'use strict'; | ||
@@ -35,3 +35,3 @@ var assert, refute; | ||
aop.after(target, 'method', function afterAdvice(a) { | ||
meld.after(target, 'method', function afterAdvice(a) { | ||
// this should be the advised object | ||
@@ -64,3 +64,3 @@ assert.equals(target, this); | ||
aop.after(target, 'method', function afterAdvice(a) { | ||
meld.after(target, 'method', function afterAdvice(a) { | ||
// this should be the advised object | ||
@@ -67,0 +67,0 @@ assert.equals(target, this); |
@@ -1,3 +0,3 @@ | ||
(function(buster, aop) { | ||
"use strict"; | ||
(function(buster, meld) { | ||
'use strict'; | ||
@@ -31,3 +31,3 @@ var assert, refute, fail; | ||
aop.afterReturning(target, 'method', function afterAdvice(a) { | ||
meld.afterReturning(target, 'method', function afterAdvice(a) { | ||
// this should be the advised object | ||
@@ -65,3 +65,3 @@ assert.equals(target, this); | ||
aop.afterReturning(target, 'method', function afterReturning0(a) { | ||
meld.afterReturning(target, 'method', function afterReturning0(a) { | ||
// this should be the advised object | ||
@@ -86,3 +86,3 @@ assert.equals(target, this); | ||
aop.afterReturning(target, 'method', function afterReturning1(a) { | ||
meld.afterReturning(target, 'method', function afterReturning1(a) { | ||
// this should be the advised object | ||
@@ -104,3 +104,3 @@ assert.equals(target, this); | ||
aop.afterReturning(target, 'method', function afterReturning2(a) { | ||
meld.afterReturning(target, 'method', function afterReturning2(a) { | ||
// this should be the advised object | ||
@@ -137,3 +137,3 @@ assert.equals(target, this); | ||
aop.afterReturning(target, 'method', spy); | ||
meld.afterReturning(target, 'method', spy); | ||
@@ -140,0 +140,0 @@ assert.exception(function() { |
@@ -1,3 +0,3 @@ | ||
(function(buster, aop) { | ||
"use strict"; | ||
(function(buster, meld) { | ||
'use strict'; | ||
@@ -31,3 +31,3 @@ var assert, refute, fail; | ||
aop.afterThrowing(target, 'method', function afterReturning1(a) { | ||
meld.afterThrowing(target, 'method', function afterReturning1(a) { | ||
// this should be the advised object | ||
@@ -62,3 +62,3 @@ assert.equals(target, this); | ||
aop.afterThrowing(target, 'method', function afterReturning0(a) { | ||
meld.afterThrowing(target, 'method', function afterReturning0(a) { | ||
// this should be the advised object | ||
@@ -83,3 +83,3 @@ assert.equals(target, this); | ||
aop.afterThrowing(target, 'method', function afterReturning1(a) { | ||
meld.afterThrowing(target, 'method', function afterReturning1(a) { | ||
// this should be the advised object | ||
@@ -101,3 +101,3 @@ assert.equals(target, this); | ||
aop.afterThrowing(target, 'method', function afterReturning2(a) { | ||
meld.afterThrowing(target, 'method', function afterReturning2(a) { | ||
// this should be the advised object | ||
@@ -132,3 +132,3 @@ assert.equals(target, this); | ||
aop.afterThrowing(target, 'method', spy); | ||
meld.afterThrowing(target, 'method', spy); | ||
@@ -135,0 +135,0 @@ refute.exception(function() { |
@@ -1,3 +0,3 @@ | ||
(function(buster, aop) { | ||
"use strict"; | ||
(function(buster, meld) { | ||
'use strict'; | ||
@@ -17,3 +17,3 @@ var assert, refute; | ||
Fixture.prototype = { | ||
method: function(a) { | ||
method: function() { | ||
return (++this.val); | ||
@@ -30,3 +30,3 @@ } | ||
aop.around(target, 'method', function aroundAdvice(joinpoint) { | ||
meld.around(target, 'method', function aroundAdvice(joinpoint) { | ||
// this should be the advised object | ||
@@ -64,3 +64,3 @@ assert.equals(target, this); | ||
aop.around(target, 'method', function aroundAdvice(joinpoint) { | ||
meld.around(target, 'method', function aroundAdvice(joinpoint) { | ||
// Calling joinpoint.proceed() multiple times is allowed | ||
@@ -78,10 +78,9 @@ assert.same(0, joinpoint.proceedCount()); | ||
'should be invoked from most recently added to least recently added': function() { | ||
var inner, outer, target; | ||
var inner, target; | ||
inner = this.spy(); | ||
outer = this.spy(); | ||
target = new Fixture(); | ||
// Inner | ||
aop.around(target, 'method', function aroundAdviceInner(joinpoint) { | ||
meld.around(target, 'method', function aroundAdviceInner(joinpoint) { | ||
inner(); | ||
@@ -93,3 +92,3 @@ // This will proceed to the original method | ||
// Outer | ||
aop.around(target, 'method', function aroundAdviceOuter(joinpoint) { | ||
meld.around(target, 'method', function aroundAdviceOuter(joinpoint) { | ||
refute.calledOnce(inner); | ||
@@ -116,3 +115,3 @@ // This will proceed to the inner around | ||
aop.around(target, 'method', function aroundAdvice(joinpoint) { | ||
meld.around(target, 'method', function aroundAdvice(joinpoint) { | ||
// arg should be the return value from the orig method | ||
@@ -142,3 +141,3 @@ assert.equals(1, joinpoint.args.length); | ||
aop.around(target, 'method', function aroundAdvice(joinpoint) { | ||
meld.around(target, 'method', function aroundAdvice(joinpoint) { | ||
// arg should be the return value from the orig method | ||
@@ -163,3 +162,3 @@ assert.equals(1, joinpoint.args.length); | ||
aop.around(target, 'method', function aroundAdvice(joinpoint) { | ||
meld.around(target, 'method', function aroundAdvice(joinpoint) { | ||
joinpoint.proceed(); | ||
@@ -178,3 +177,3 @@ return 1; | ||
aop.around(target, 'method', function aroundAdvice(joinpoint) { | ||
meld.around(target, 'method', function aroundAdvice(/*joinpoint*/) { | ||
// Don't proceed to original method | ||
@@ -181,0 +180,0 @@ // joinpoint.proceed(); |
@@ -1,3 +0,3 @@ | ||
(function(buster, aop) { | ||
"use strict"; | ||
(function(buster, meld) { | ||
'use strict'; | ||
@@ -26,3 +26,3 @@ var assert, refute; | ||
aop.before(target, 'method', function before1(a) { | ||
meld.before(target, 'method', function before1(a) { | ||
// this should be the advised object | ||
@@ -56,3 +56,3 @@ assert.equals(target, this); | ||
aop.before(target, 'method', function before0(a) { | ||
meld.before(target, 'method', function before0(a) { | ||
assert.equals(target, this); | ||
@@ -71,3 +71,3 @@ assert.equals(arg, a); | ||
aop.before(target, 'method', function before1(a) { | ||
meld.before(target, 'method', function before1(a) { | ||
assert.equals(target, this); | ||
@@ -90,3 +90,3 @@ assert.equals(arg, a); | ||
aop.before(target, 'method', function before2(a) { | ||
meld.before(target, 'method', function before2(a) { | ||
assert.equals(target, this); | ||
@@ -93,0 +93,0 @@ assert.equals(arg, a); |
exports['meld:node'] = { | ||
environment: 'node', | ||
tests: ['*.js'] | ||
tests: ['**/*.js'] | ||
}; |
(function(buster, meld) { | ||
"use strict"; | ||
'use strict'; | ||
@@ -4,0 +4,0 @@ var assert, refute, arg; |
(function(buster, meld) { | ||
"use strict"; | ||
'use strict'; | ||
@@ -4,0 +4,0 @@ var assert, refute; |
@@ -1,3 +0,3 @@ | ||
(function(buster, aop) { | ||
"use strict"; | ||
(function(buster, meld) { | ||
'use strict'; | ||
@@ -32,3 +32,3 @@ var assert, refute; | ||
aop.on(target, 'method', function on(a) { | ||
meld.on(target, 'method', function on(a) { | ||
// this should be the advised object | ||
@@ -61,3 +61,3 @@ assert.equals(target, this); | ||
aop.on(target, 'method', spy); | ||
meld.on(target, 'method', spy); | ||
@@ -64,0 +64,0 @@ assert.exception(function() { |
@@ -1,3 +0,3 @@ | ||
(function(buster, aop) { | ||
"use strict"; | ||
(function(buster, meld) { | ||
'use strict'; | ||
@@ -21,3 +21,3 @@ var assert, refute; | ||
aop.add(target, 'method1', { | ||
meld.add(target, 'method1', { | ||
before: before | ||
@@ -47,3 +47,3 @@ }); | ||
aop.add(target, ['method1', 'method3'], { | ||
meld.add(target, ['method1', 'method3'], { | ||
before: before | ||
@@ -78,3 +78,3 @@ }); | ||
aop.add(target, /method[13]/, { | ||
meld.add(target, /method[13]/, { | ||
before: before | ||
@@ -109,3 +109,3 @@ }); | ||
aop.add(target, | ||
meld.add(target, | ||
function(target) { | ||
@@ -112,0 +112,0 @@ return ['method1', 'method3']; |
@@ -1,3 +0,3 @@ | ||
(function(buster, aop) { | ||
"use strict"; | ||
(function(buster, meld) { | ||
'use strict'; | ||
@@ -19,3 +19,3 @@ var assert, refute; | ||
// Advise the prototype method | ||
aop.before(Fixture.prototype, 'method', before); | ||
meld.before(Fixture.prototype, 'method', before); | ||
@@ -22,0 +22,0 @@ target = new Fixture(); |
@@ -1,3 +0,3 @@ | ||
(function(buster, aop) { | ||
"use strict"; | ||
(function(buster, meld) { | ||
'use strict'; | ||
@@ -22,3 +22,3 @@ var assert, refute; | ||
advice = this.spy(); | ||
ref = aop.before(fixture, 'method', advice); | ||
ref = meld.before(fixture, 'method', advice); | ||
@@ -46,3 +46,3 @@ assert.defined(fixture.method._advisor); | ||
advice = this.spy(); | ||
ref = aop.before(fixture, /method[12]/, advice); | ||
ref = meld.before(fixture, /method[12]/, advice); | ||
@@ -73,3 +73,3 @@ assert.defined(fixture.method1._advisor); | ||
ref = aop.around(fixture, 'method', advice); | ||
ref = meld.around(fixture, 'method', advice); | ||
@@ -102,3 +102,3 @@ fixture.method(); | ||
fixture.method = this.spy(); | ||
ref = aop.add(fixture, 'method', aspect); | ||
ref = meld.add(fixture, 'method', aspect); | ||
@@ -105,0 +105,0 @@ fixture.method(); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
89096
28
1746
148