Browse files

Fix for issue #2

Hooks now intercept callbacks so that post handlers can be run before
the callback.

This is especially useful in Mongoose, where virtual async methods are
not supported.  The only clean way to implement them is via a
post('init') handler.
  • Loading branch information...
1 parent f778859 commit 5c4064f3c5491ebce0b65e826cc32fc870d30aeb @STRML STRML committed Apr 3, 2012
Showing with 44 additions and 4 deletions.
  1. +17 −4 hooks.js
  2. +27 −0 test.js
View
21 hooks.js
@@ -55,10 +55,9 @@ module.exports = {
, _done = function () {
var args_ = Array.prototype.slice.call(arguments)
, ret, total_, current_, next_, done_, postArgs;
+
if (_current === _total) {
- ret = fn.apply(self, args_);
- total_ = posts.length;
- current_ = -1;
+
next_ = function () {
if (arguments[0] instanceof Error) {
return handleError(arguments[0]);
@@ -73,9 +72,23 @@ module.exports = {
throw new Error("Your post must have a next argument -- e.g., function (next, ...)");
postArgs = [once(next_)].concat(hookArgs);
return currPost.apply(self, postArgs);
+ } else if (typeof lastArg === 'function'){
+ // All post handlers are done, call original callback function
+ return lastArg.apply(self);
}
};
- if (total_) return next_();
+
+ // We are assuming that if the last argument provided to the wrapped function is a function, it was expecting
+ // a callback. We trap that callback and wait to call it until all post handlers have finished.
+ if(typeof lastArg === 'function'){
+ args_[args_.length - 1] = once(next_);
+ }
+
+ total_ = posts.length;
+ current_ = -1;
+ ret = fn.apply(self, args_); // Execute wrapped function, post handlers come afterward
+
+ if (total_ && typeof lastArg !== 'function') return next_(); // no callback provided, execute next_() manually
return ret;
}
};
View
27 test.js
@@ -681,5 +681,32 @@ module.exports = {
a.save( function (err) {
err.should.be.an.instanceof(Error);
});
+ },
+
+ 'should intercept method callbacks for post handlers': function () {
+ var A = function () {};
+ _.extend(A, hooks);
+ A.hook('save', function (val, callback) {
+ this.value = val;
+ callback();
+ });
+ A.post('save', function (next) {
+ assert.equal(a.value, 2);
+ this.value += 2;
+ setTimeout(next, 10);
+ }).post('save', function (next) {
+ assert.equal(a.value, 4);
+ this.value += 3;
+ setTimeout(next, 10);
+ }).post('save', function (next) {
+ assert.equal(a.value, 7);
+ this.value2 = 3;
+ setTimeout(next, 10);
+ });
+ var a = new A();
+ a.save(2, function(){
+ assert.equal(a.value, 7);
+ assert.equal(a.value2, 3);
+ });
}
};

0 comments on commit 5c4064f

Please sign in to comment.