Comparing version 0.0.10 to 0.0.11
@@ -66,6 +66,6 @@ var async = require('async'), | ||
if (callback) { | ||
asyncApply(emitter, listeners[0], args, callback); | ||
asyncApply(emitter, handleOnce(emitter, name, listeners[0]), args, callback); | ||
} | ||
else { | ||
return listeners[0].apply(emitter, args); | ||
return handleOnce(emitter, name, listeners[0]).apply(emitter, args); | ||
} | ||
@@ -79,2 +79,5 @@ } | ||
function asyncApply (thisArg, fn, args, done) { | ||
if ('function' === typeof fn.removeWrapper) { | ||
fn.removeWrapper(); // remove the wrapper, as it would have removed itself | ||
} | ||
if (!Array.isArray(args)) args = [args]; | ||
@@ -99,6 +102,22 @@ if (fn.length <= args.length) { | ||
// For waterfall, args only need to be bound to the first task. | ||
return asyncApply.bind(emitter, emitter, listener); | ||
return asyncApply.bind(emitter, emitter, handleOnce(emitter, name, listener)); | ||
} | ||
return asyncApply.bind(emitter, emitter, listener, args); | ||
return asyncApply.bind(emitter, emitter, handleOnce(emitter, name, listener), args); | ||
}); | ||
} | ||
/** | ||
* Allow (and honor) emitter.once('foo', ...) | ||
* See: | ||
* EventEmitter.prototype.once | ||
* https://github.com/joyent/node/blob/master/lib/events.js#L184-L199 | ||
*/ | ||
function handleOnce (emitter, name, listener) { | ||
// A .once listener is actually a wrapper that has the original listener attached | ||
// If there is no such property, it's a normal .on listener -- proceed as normal | ||
if (typeof listener.listener !== 'function') return listener; | ||
var origlistener = listener.listener; | ||
origlistener.removeWrapper = emitter.removeListener.bind(emitter, name, listener); // save this removal function for execution time | ||
return origlistener; // apply to the original listener; note that since the .once wrapper | ||
// was removed, it won't get invoked again | ||
} |
{ | ||
"name": "eventflow", | ||
"version": "0.0.10", | ||
"version": "0.0.11", | ||
"description": "Flow control for your event emitters", | ||
@@ -5,0 +5,0 @@ "main": "eventflow.js", |
@@ -30,7 +30,29 @@ var eventflow = require('../') | ||
emitter.once('foo', function () { | ||
result.push('d'); | ||
}); | ||
emitter.once('foo', function (cb) { | ||
result.push('e'); | ||
cb(); | ||
}); | ||
assert.equal(emitter.listeners('foo').length, 5); | ||
emitter.series('foo', function () { | ||
assert.equal(emitter.listeners('foo').length, 3); | ||
assert.equal(result[0], 'a'); | ||
assert.equal(result[1], 'b'); | ||
assert.equal(result[2], 'c'); | ||
done(); | ||
assert.equal(result[3], 'd'); | ||
assert.equal(result[4], 'e'); | ||
result = []; | ||
emitter.series('foo', function () { | ||
assert.equal(emitter.listeners('foo').length, 3); | ||
assert.equal(result[0], 'a'); | ||
assert.equal(result[1], 'b'); | ||
assert.equal(result[2], 'c'); | ||
assert.equal(result.length, 3); | ||
done(); | ||
}); | ||
}); | ||
@@ -51,3 +73,17 @@ }); | ||
emitter.once('bar', function (a, b) { | ||
result.push(a); | ||
result.push(b); | ||
}); | ||
emitter.once('bar', function (a, b, cb) { | ||
result.push(a); | ||
result.push(b); | ||
cb(); | ||
}); | ||
assert.equal(emitter.listeners('bar').length, 4); | ||
emitter.series('bar', 'foo', 'baz', function () { | ||
assert.equal(emitter.listeners('bar').length, 2); | ||
assert.equal(result[0], 'foo'); | ||
@@ -57,3 +93,16 @@ assert.equal(result[1], 'baz'); | ||
assert.equal(result[3], 'baz'); | ||
done(); | ||
assert.equal(result[4], 'foo'); | ||
assert.equal(result[5], 'baz'); | ||
assert.equal(result[6], 'foo'); | ||
assert.equal(result[7], 'baz'); | ||
result = []; | ||
emitter.series('bar', 'foo', 'baz', function () { | ||
assert.equal(emitter.listeners('bar').length, 2); | ||
assert.equal(result[0], 'foo'); | ||
assert.equal(result[1], 'baz'); | ||
assert.equal(result[2], 'foo'); | ||
assert.equal(result[3], 'baz'); | ||
assert.equal(result.length, 4); | ||
done(); | ||
}); | ||
}); | ||
@@ -69,2 +118,8 @@ }); | ||
}); | ||
emitter.once('fruit', function (cb) { | ||
cb(null, 'grape'); | ||
}); | ||
emitter.once('fruit', function () { | ||
return 'lime'; | ||
}); | ||
emitter.series('fruit', function (err, results) { | ||
@@ -74,2 +129,4 @@ assert.ifError(err); | ||
assert.equal(results[1], 'orange'); | ||
assert.equal(results[2], 'grape'); | ||
assert.equal(results[3], 'lime'); | ||
done(); | ||
@@ -83,2 +140,5 @@ }); | ||
}); | ||
emitter.once('drink', function (cb) { | ||
cb('oh no! first'); | ||
}); | ||
emitter.on('drink', function (cb) { | ||
@@ -93,4 +153,10 @@ cb('oh no!'); | ||
assert.equal(result.length, 1); | ||
assert.equal(err, 'oh no!'); | ||
done(); | ||
assert.equal(err, 'oh no! first'); | ||
result = []; | ||
emitter.series('drink', function (err) { | ||
assert.equal(result[0], 'coke'); | ||
assert.equal(result.length, 1); | ||
assert.equal(err, 'oh no!'); | ||
done(); | ||
}); | ||
}); | ||
@@ -100,2 +166,5 @@ }); | ||
it('should support sync listeners returning errors', function (done) { | ||
emitter.once('eat', function () { | ||
return new Error('I am not really hungry...'); | ||
}); | ||
emitter.on('eat', function () { | ||
@@ -105,4 +174,7 @@ return new Error('I am full'); | ||
emitter.series('eat', function (err, results) { | ||
assert.equal(err.message, 'I am full'); | ||
done(); | ||
assert.equal(err.message, 'I am not really hungry...'); | ||
emitter.series('eat', function (err, results) { | ||
assert.equal(err.message, 'I am full'); | ||
done(); | ||
}); | ||
}); | ||
@@ -128,5 +200,14 @@ }); | ||
}); | ||
emitter.on('candy', function () { | ||
result.boring = 'Hershey Bar'; | ||
}); | ||
emitter.on('candy', function (cb) { | ||
result.perfect = 'Peanut Butter Cup'; | ||
cb(); | ||
}); | ||
emitter.parallel('candy', function () { | ||
assert.equal(result.sour, 'Sour Patch'); | ||
assert.equal(result.hard, 'Jolly Rancher'); | ||
assert.equal(result.boring, 'Hershey Bar'); | ||
assert.equal(result.perfect, 'Peanut Butter Cup'); | ||
done(); | ||
@@ -143,8 +224,17 @@ }); | ||
}); | ||
emitter.once('numbers', function() { | ||
return 3; | ||
}); | ||
emitter.once('numbers', function() { | ||
return 4; | ||
}); | ||
emitter.parallel('numbers', function (err, results) { | ||
assert.ifError(err); | ||
assert.equal(results[1], 2); | ||
assert.equal(results[3], 4); | ||
assert.equal(results.length, 4); | ||
emitter.parallel('numbers', function (err, results) { | ||
assert.ifError(err); | ||
assert.equal(results[0], 1); | ||
assert.equal(results.length, 2); | ||
done(); | ||
@@ -177,3 +267,3 @@ }); | ||
it('should work when there is exactly one synchronous listner', function (done) { | ||
it('should work when there is exactly one synchronous listener', function (done) { | ||
var timestamp = new Date().getTime(); | ||
@@ -190,4 +280,19 @@ emitter.on('timestamp', function () { | ||
it('should work when there is exactly one asynchronous listener', function (done) { | ||
it('should respect exactly one synchronous .once listener', function (done) { | ||
var timestamp = new Date().getTime(); | ||
emitter.once('timestamp', function () { | ||
return timestamp; | ||
}); | ||
emitter.invoke('timestamp', function (err, value) { | ||
assert.ifError(err); | ||
assert.equal(value, timestamp); | ||
emitter.invoke('timestamp', function (err, value) { | ||
assert(err); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
it('should respect exactly one asynchronous listener', function (done) { | ||
var timestamp = new Date().getTime(); | ||
emitter.on('timestamp', function (callback) { | ||
@@ -203,2 +308,17 @@ callback(null, timestamp); | ||
it('should respect exactly one asynchronous .once listener', function (done) { | ||
var timestamp = new Date().getTime(); | ||
emitter.once('timestamp', function (callback) { | ||
callback(null, timestamp); | ||
}); | ||
emitter.invoke('timestamp', function (err, value) { | ||
assert.ifError(err); | ||
assert.equal(value, timestamp); | ||
emitter.invoke('timestamp', function (err, value) { | ||
assert(err); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
it('should work with arguments', function (done) { | ||
@@ -226,2 +346,25 @@ emitter.on('add', function (a, b) { | ||
it('should work with arguments using .once listener', function (done) { | ||
emitter.once('multiply', function (a, b) { | ||
return a * b; | ||
}); | ||
emitter.invoke('multiply', 2, 3, function (err, value) { | ||
assert.ifError(err); | ||
assert.equal(value, 6); | ||
done(); | ||
}); | ||
}); | ||
it('should work with arguments, asynchronously, using .once listener', function (done) { | ||
emitter.once('modulus', function (a, b, callback) { | ||
// You thought I was going to divide, didn't you? | ||
callback(null, a % b); | ||
}); | ||
emitter.invoke('modulus', 3, 2, function (err, value) { | ||
assert.ifError(err); | ||
assert.equal(value, 1); | ||
done(); | ||
}); | ||
}); | ||
it('should be able to be called multiple times', function (done) { | ||
@@ -247,2 +390,6 @@ emitter.on('echo', function (msg) { | ||
assert.equal(emitter.invoke('sync'), 'isSync'); | ||
emitter.once('resync', function () { | ||
return 'isSync'; | ||
}); | ||
assert.equal(emitter.invoke('resync'), 'isSync'); | ||
}); | ||
@@ -271,2 +418,21 @@ }); | ||
it('should work with one or more .once handlers', function (done) { | ||
emitter.once('foo', function (n) { | ||
return n + 1; | ||
}); | ||
emitter.once('foo', function (n, cb) { | ||
cb(null, n * 5); | ||
}); | ||
emitter.on('foo', function (n) { | ||
return n - 3; | ||
}); | ||
emitter.waterfall('foo', 0, function (err, n) { | ||
assert.equal(n, 2); | ||
done(); | ||
}); | ||
}); | ||
it('should support optional use of `error`', function (done) { | ||
@@ -273,0 +439,0 @@ emitter.on('drink', function (n) { |
25615
542