eventemitter-ex
Advanced tools
Comparing version 0.0.7 to 0.0.8
@@ -6,3 +6,5 @@ (function () { | ||
util = require('util'), | ||
assert = require('assert'); | ||
assert = require('assert'), | ||
slice = Function.prototype.call.bind(Array.prototype.slice), | ||
concat = Array.prototype.concat; | ||
@@ -20,3 +22,3 @@ module.exports = EventEmitterEx; | ||
var except = Array.prototype.slice.call(arguments, 1); | ||
var except = slice(arguments, 1); | ||
this._onAllListeners.push([f, except]); | ||
@@ -53,3 +55,3 @@ }; | ||
EventEmitterEx.prototype.startPipeline = function startPipeline (/* arguments */) { | ||
var args = Array.prototype.slice.call(arguments); | ||
var args = slice(arguments); | ||
args.unshift('end'); | ||
@@ -62,3 +64,3 @@ | ||
var self = this, | ||
except = Array.prototype.slice.call(arguments, 1); | ||
except = slice(arguments, 1); | ||
@@ -76,3 +78,3 @@ if (typeof ee.onAllExcept === 'function') { | ||
ee.on('error', function (/* arguments */) { | ||
var args = Array.prototype.slice.call(arguments); | ||
var args = slice(arguments); | ||
args.unshift('error'); | ||
@@ -99,3 +101,3 @@ self.emit.apply(self, args); | ||
var eex = new EventEmitterEx(), | ||
mapArgs = Array.prototype.slice.call(arguments); | ||
mapArgs = slice(arguments); | ||
@@ -114,3 +116,3 @@ mapArgs.forEach(assertIsFunction); | ||
// flatten the array | ||
result = [].concat.apply(['end'], result); | ||
result = concat.apply(['end'], result); | ||
} catch (err) { | ||
@@ -131,3 +133,3 @@ eex.emit('error', err); | ||
var eex = new EventEmitterEx(), | ||
funcs = Array.prototype.slice.call(arguments); | ||
funcs = slice(arguments); | ||
@@ -138,18 +140,22 @@ funcs.forEach(assertIsFunction); | ||
this.on('end', function (/* arguments */) { | ||
var result = [], firstError, len = funcs.length; | ||
var endArgs = Array.prototype.slice.call(arguments); | ||
endArgs.push(callback); | ||
var result = [], firstError, len = funcs.length, lenLoop = len; | ||
var endArgs = slice(arguments), | ||
endArgsLen = endArgs.length; | ||
funcs.forEach(function (f) { | ||
f.apply(eex, endArgs); | ||
}); | ||
for (var i = 0; i < lenLoop; i++) { | ||
endArgs[endArgsLen] = callback.bind(null, i); | ||
funcs[i].apply(eex, endArgs); | ||
} | ||
function callback (err/* arguments */) { | ||
function callback (position, err/* arguments */) { | ||
assert(! Array.isArray(result[position]), | ||
'Callback called more than once by function at position ' + position + ' (0-based)'); | ||
if (err) { | ||
firstError = firstError || err; | ||
result[position] = []; | ||
} else { | ||
result.push(Array.prototype.slice.call(arguments, 1)); | ||
result[position] = slice(arguments, 2); | ||
} | ||
len--; | ||
assert(len >= 0, 'Callback called more than once for each mapAsync() function!'); | ||
if (! len) { | ||
@@ -160,3 +166,3 @@ if (firstError) { | ||
// flatten the array | ||
eex.emit.apply(eex, [].concat.apply(['end'], result)); | ||
eex.emit.apply(eex, concat.apply(['end'], result)); | ||
} | ||
@@ -170,10 +176,48 @@ } | ||
EventEmitterEx.prototype.flatMap = function flatMap (f) { | ||
assertIsFunction(f); | ||
EventEmitterEx.prototype.flatMap = function flatMap (/* arguments */) { | ||
var eex = new EventEmitterEx(), | ||
funcs = slice(arguments); | ||
var eex = new EventEmitterEx(); | ||
funcs.forEach(assertIsFunction); | ||
eex.pipeExcept(this, 'end'); | ||
this.on('end', function (/* arguments */) { | ||
eex.pipeExcept(f.apply(eex, arguments)); | ||
var result = [], firstError, len = funcs.length, lenLoop = len; | ||
for (var i = 0; i < lenLoop; i++) { | ||
var e = funcs[i].apply(eex, arguments); | ||
eex.pipeExcept(e, 'end', 'error'); | ||
e.on('end', endListener.bind(null, i)); | ||
e.on('error', errorListener.bind(null, i)); | ||
} | ||
function checkUsage (position) { | ||
assert(! Array.isArray(result[position]), | ||
'end/error (or both) event emitted more than once by emitter at position ' + position + ' (0-based)'); | ||
} | ||
function endListener (position/* arguments */) { | ||
checkUsage(position); | ||
result[position] = slice(arguments, 1); | ||
maybeNext(); | ||
} | ||
function errorListener (position, err) { | ||
checkUsage(position); | ||
firstError = firstError || err; | ||
result[position] = []; | ||
maybeNext(); | ||
} | ||
function maybeNext () { | ||
len--; | ||
if (! len) { | ||
if (firstError) { | ||
eex.emit('error', firstError); | ||
} else { | ||
// flatten the array | ||
eex.emit.apply(eex, concat.apply(['end'], result)); | ||
} | ||
} | ||
} | ||
}); | ||
@@ -180,0 +224,0 @@ |
{ | ||
"name": "eventemitter-ex", | ||
"version": "0.0.7", | ||
"version": "0.0.8", | ||
"description": "EventEmitter extensions", | ||
@@ -5,0 +5,0 @@ "main": "EventEmitterEx.js", |
@@ -357,3 +357,3 @@ (function () { | ||
cb(null); | ||
}).to.throw(Error, 'Callback called more than once for each mapAsync() function!'); | ||
}).to.throw(Error, 'Callback called more than once by function at position 0 (0-based)'); | ||
done(); | ||
@@ -365,2 +365,14 @@ }); | ||
it('should throw if callback called too many times (with misbehaving callback)', function (done) { | ||
var mapped = emitter.mapAsync(function () {/* bad function, does not call cb() */}, function (cb) { | ||
cb(null); | ||
expect(function () { | ||
cb(null); | ||
}).to.throw(Error, 'Callback called more than once by function at position 1 (0-based)'); | ||
done(); | ||
}); | ||
mapped.on('error', done); | ||
emitter.emit('end'); | ||
}); | ||
it('should support synchronous call of callback', function (done) { | ||
@@ -434,3 +446,3 @@ var A = 42; | ||
it('should call each map function and return results in order', function (done) { | ||
it('should call each map function and return results in order (sync)', function (done) { | ||
var f1 = function (a1, a2, cb) { | ||
@@ -452,2 +464,19 @@ cb(null, a1 + a2); | ||
it('should call each map function and return results in order (async)', function (done) { | ||
var f1 = function (a1, a2, cb) { | ||
setImmediate(cb.bind(null, null, a1 + a2)); | ||
}; | ||
var f2 = function (a1, a2, cb) { | ||
cb(null, a1 * a2); | ||
}; | ||
var r = emitter.mapAsync(f1, f2); | ||
r.on('end', function (r1, r2) { | ||
r1.should.be.equal(6); | ||
r2.should.be.equal(8); | ||
done(); | ||
}); | ||
emitter.emit('end', 4, 2); | ||
}); | ||
}); | ||
@@ -473,2 +502,89 @@ | ||
it('should throw if emitter emit end more than once', function () { | ||
var e = new EEX(); | ||
emitter | ||
.flatMap(function () { | ||
return e; | ||
}); | ||
emitter.emit('end'); | ||
e.emit('end'); | ||
expect(function () { | ||
e.emit('end'); | ||
}).to.throw(Error, 'end/error (or both) event emitted more than once by emitter at position 0 (0-based)'); | ||
}); | ||
it('should throw if emitter emit error more than once', function () { | ||
var e = new EEX(); | ||
emitter | ||
.flatMap(function () { | ||
return e; | ||
}) | ||
.on('error', function () { | ||
// ignore | ||
}); | ||
emitter.emit('end'); | ||
e.emit('error', new Error('123')); | ||
expect(function () { | ||
e.emit('error', new Error('234')); | ||
}).to.throw(Error, 'end/error (or both) event emitted more than once by emitter at position 0 (0-based)'); | ||
}); | ||
it('should throw if emitter emit end and error', function () { | ||
var e = new EEX(); | ||
emitter | ||
.flatMap(function () { | ||
return e; | ||
}); | ||
emitter.emit('end'); | ||
e.emit('end'); | ||
expect(function () { | ||
e.emit('error', new Error('234')); | ||
}).to.throw(Error, 'end/error (or both) event emitted more than once by emitter at position 0 (0-based)'); | ||
}); | ||
it('should collect results and emit all together in order', function (done) { | ||
var A = 1, B = 40, C = 2, e = new EEX(); | ||
emitter | ||
.flatMap( | ||
function () { | ||
return e; | ||
}, | ||
function () { | ||
return new EEX() | ||
.startPipeline(C) | ||
.on('end', function () { e.startPipeline(A, B); } ); | ||
}) | ||
.on('end', function (r1, r2, r3, r4) { | ||
r1.should.be.equal(A); | ||
r2.should.be.equal(B); | ||
r3.should.be.equal(C); | ||
expect(r4).to.be.undefined; | ||
done(); | ||
}) | ||
.on('error', done); | ||
emitter.emit('end'); | ||
}); | ||
it('should emit error after all emitters finished', function (done) { | ||
var e = new EEX(), error = new Error('error!'); | ||
emitter | ||
.flatMap( | ||
function () { | ||
return e; | ||
}, | ||
function () { | ||
return new EEX() | ||
.startPipeline() | ||
.on('end', e.emit.bind(e, 'error', error)); | ||
}) | ||
.on('end', function () { | ||
fail('end emitted', 'end emitted'); | ||
}) | ||
.on('error', function (err) { | ||
err.should.be.equal(error); | ||
done(); | ||
}); | ||
emitter.emit('end'); | ||
}); | ||
it('should throw exception on non-function arguments', function () { | ||
@@ -475,0 +591,0 @@ expect(function () { |
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
48940
782