eventemitter-ex
Advanced tools
Comparing version 0.0.8 to 1.0.0
@@ -18,7 +18,10 @@ (function () { | ||
EventEmitterEx.prototype.onAllExcept = function onAllExcept (f /* arguments */) { | ||
EventEmitterEx.prototype.onAllExcept = function onAllExcept (/* arguments */) { | ||
var f = arguments[arguments.length - 1]; | ||
assertIsFunction(f); | ||
var except = slice(arguments, 1); | ||
var except = slice(arguments, 0, -1); | ||
this._onAllListeners.push([f, except]); | ||
return this; | ||
}; | ||
@@ -60,13 +63,18 @@ | ||
EventEmitterEx.prototype.pipeExcept = function pipeExcept (ee) { | ||
EventEmitterEx.prototype.pipeExcept = function pipeExcept (/* arguments */) { | ||
var ee = arguments[arguments.length - 1]; | ||
if (! (ee instanceof EE)) { | ||
throw new TypeError('Expecting EventEmitter or EventEmitterEx. Given: ' + typeof ee); | ||
} | ||
var self = this, | ||
except = slice(arguments, 1); | ||
except = slice(arguments, 0, -1); | ||
if (typeof ee.onAllExcept === 'function') { | ||
// This is an EventEmitterEx | ||
except.unshift(function (/* arguments */) { | ||
except.push(function (/* arguments */) { | ||
self.emit.apply(self, arguments); | ||
}); | ||
ee.onAllExcept.apply(ee, except); | ||
} else if (typeof ee.emit === 'function') { | ||
} else { | ||
// This is a usual EventEmitter | ||
@@ -90,4 +98,2 @@ var emit = ee.emit; | ||
}; | ||
} else { | ||
throw new TypeError('Expecting EventEmitter or EventEmitterEx. Given: ' + typeof ee); | ||
} | ||
@@ -103,3 +109,3 @@ return this; | ||
eex.pipeExcept(this, 'end'); | ||
eex.pipeExcept('end', this); | ||
this.on('end', function (/* arguments */) { | ||
@@ -134,3 +140,3 @@ var result; | ||
eex.pipeExcept(this, 'end'); | ||
eex.pipeExcept('end', this); | ||
this.on('end', function (/* arguments */) { | ||
@@ -150,7 +156,7 @@ var result = [], firstError, len = funcs.length, lenLoop = len; | ||
if (err) { | ||
firstError = firstError || err; | ||
if (err === null) { | ||
result[position] = slice(arguments, 2); | ||
} else { | ||
if (! firstError) firstError = slice(arguments, 1); | ||
result[position] = []; | ||
} else { | ||
result[position] = slice(arguments, 2); | ||
} | ||
@@ -160,3 +166,4 @@ len--; | ||
if (firstError) { | ||
eex.emit('error', firstError); | ||
firstError.unshift('error'); | ||
eex.emit.apply(eex, firstError); | ||
} else { | ||
@@ -179,3 +186,3 @@ // flatten the array | ||
eex.pipeExcept(this, 'end'); | ||
eex.pipeExcept('end', this); | ||
this.on('end', function (/* arguments */) { | ||
@@ -186,3 +193,3 @@ var result = [], firstError, len = funcs.length, lenLoop = len; | ||
var e = funcs[i].apply(eex, arguments); | ||
eex.pipeExcept(e, 'end', 'error'); | ||
eex.pipeExcept('end', 'error', e); | ||
e.on('end', endListener.bind(null, i)); | ||
@@ -189,0 +196,0 @@ e.on('error', errorListener.bind(null, i)); |
{ | ||
"name": "eventemitter-ex", | ||
"version": "0.0.8", | ||
"version": "1.0.0", | ||
"description": "EventEmitter extensions", | ||
@@ -5,0 +5,0 @@ "main": "EventEmitterEx.js", |
246
README.md
# eventemitter-ex | ||
Node.js EventEmitter Extensions | ||
[![NPM](https://nodei.co/npm/eventemitter-ex.png)](https://npmjs.org/package/eventemitter-ex) | ||
[![NPM](https://nodei.co/npm-dl/eventemitter-ex.png)](https://nodei.co/npm-dl/eventemitter-ex/) | ||
[![Build Status](https://travis-ci.org/ash2k/eventemitter-ex.svg?branch=master)](https://travis-ci.org/ash2k/eventemitter-ex) | ||
[![npm version](https://badge.fury.io/js/eventemitter-ex.svg)](https://badge.fury.io/js/eventemitter-ex) | ||
[![Coverage Status](https://coveralls.io/repos/ash2k/eventemitter-ex/badge.svg?branch=master)](https://coveralls.io/r/ash2k/eventemitter-ex?branch=master) | ||
## What is it? | ||
It is a library for [Node.js](https://nodejs.org/) / [io.js](https://iojs.org) to compose [EventEmitters](https://nodejs.org/api/events.html#events_class_events_eventemitter). | ||
## Documentation and usage examples | ||
We will use the following functions in the examples below: | ||
```javascript | ||
var EE = require('events').EventEmitter; | ||
var EEX = require('eventemitter-ex'); | ||
function numbers () { | ||
var ee = new EE(); | ||
setImmediate(function () { | ||
ee.emit('data', 1); | ||
ee.emit('data', 2); | ||
ee.emit('data', 3); | ||
ee.emit('end', 10); | ||
}); | ||
return ee; | ||
} | ||
function doubleUp (x) { | ||
return x * 2; | ||
} | ||
function asyncDoubleUp (x, cb) { | ||
setImmediate(function () { | ||
cb(null, doubleUp(x)); | ||
}); | ||
// can be implemented synchronously too | ||
// cb(null, doubleUp(x)); | ||
} | ||
``` | ||
For more advanced examples please take a look at the [tests](test/EventEmitterEx.test.js). | ||
### Basic functionality | ||
#### onAllExcept([event, ..., ]function) | ||
Attaches the provided listener to all events except the specified ones. Listeners will be called with the type of the event fired along with its actual payload. | ||
```javascript | ||
var eex = new EEX() | ||
.onAllExcept('end', console.log); | ||
eex.emit('data', 42); | ||
eex.emit('end'); | ||
// will print | ||
data 42 | ||
``` | ||
#### emitAsync(event[, payload, ...]) | ||
Asynchronously emits an event with specified payload. | ||
```javascript | ||
var eex = new EEX() | ||
.emitAsync('end', 42) | ||
.on('end', console.log); | ||
// will print | ||
42 | ||
``` | ||
#### startPipeline([payload, ...]) | ||
Asynchronously emits `end` event with the provided payload. Useful to triger pipelines where next steps are `map()`/`mapAsync()`/`flatMap()` operations. | ||
```javascript | ||
var eex = new EEX() | ||
.startPipeline(42) // same as .emitAsync('end', 42) | ||
.map(doubleUp) | ||
.on('end', console.log); | ||
// will print | ||
84 | ||
``` | ||
#### pipeExcept([event, ..., ]emitter) | ||
You can pipe one or more emitters into `EEX` emitter. Events from source(s) will be fired on the target emitter. | ||
```javascript | ||
var eex = new EEX() | ||
.pipeExcept(numbers()) | ||
.on('data', console.log) | ||
.on('end', console.log); | ||
// will print | ||
1 | ||
2 | ||
3 | ||
10 | ||
``` | ||
It is possible to specify exceptions - events that will not be piped: | ||
```javascript | ||
var eex = new EEX() | ||
.pipeExcept('data', numbers()) | ||
.on('data', console.log) | ||
.on('end', console.log); | ||
// will print | ||
10 | ||
``` | ||
#### listenersOnAll(event) | ||
Returns an array of listeners attached via `onAllExcept()` that will be triggered for the specified type of event. | ||
```javascript | ||
var eex = new EEX() | ||
.onAllExcept('end', console.log); | ||
console.log(eex.listenersOnAll('data').length); | ||
console.log(eex.listenersOnAll('end').length); | ||
// will print | ||
1 | ||
0 | ||
``` | ||
#### listenerCountOnAll(event) | ||
Returns number of listeners attached via `onAllExcept()` that will be triggered for the specified type of event. | ||
```javascript | ||
var eex = new EEX() | ||
.onAllExcept('end', console.log); | ||
console.log(eex.listenerCountOnAll('data')); | ||
console.log(eex.listenerCountOnAll('end')); | ||
// will print | ||
1 | ||
0 | ||
``` | ||
#### EEX.listenerCount(emitter, event) | ||
Returns the number of listeners for a given event for the given emitter. Same as | ||
[EventEmitter.listenerCount()](https://nodejs.org/api/events.html#events_class_method_eventemitter_listenercount_emitter_event) | ||
but also understands objects of `EEX` type and takes into account listeners, attached via `onAllExcept()`. | ||
```javascript | ||
var eex = new EEX() | ||
.onAllExcept('data', console.log) | ||
.onAllExcept('end', console.log) | ||
.on('end', function () {}); | ||
console.log(EEX.listenerCount(eex, 'end')); | ||
// will print | ||
2 | ||
``` | ||
#### EEX.startAsync(function) | ||
Returns new `EEX` which will be provided to the function asynchronously. | ||
```javascript | ||
var eex = EEX | ||
.startAsync(function (e) { | ||
e.emit('end', 42); | ||
}) | ||
.on('end', console.log); | ||
// will print | ||
42 | ||
``` | ||
### Chaining emitters | ||
`end` event from emitter is triggering next stage of execution, defined by `map()`/`mapAsync()`/`flatMap()` operation. Payload of `end` event is passed as argument(s) to the next stage. `error` event terminates the pipeline by bubbling up through the chain of emitters, triggering `error` listeners. | ||
#### map(function[, function, ...]) | ||
Returns new `EEX` that will emit all events from the source emitter except `end`. It will handle `end` event using the provided function by passing the payload to it. Result of that function will be emitted as `end` event on the returned emitter. Exception thrown from the function will be emitted as an `error` event on the returned emitter. | ||
```javascript | ||
var eex = new EEX() | ||
.pipeExcept(numbers()) | ||
.map(doubleUp) // pass function, no invocation here | ||
.on('data', console.log) | ||
.on('end', console.log); | ||
// will print | ||
1 | ||
2 | ||
3 | ||
20 | ||
``` | ||
#### mapAsync(function[, function, ...]) | ||
Returns new `EEX` that will emit all events from the source emitter except `end`. It will handle `end` event using the provided function by passing the payload to it along with a callback to be called with the result of the computation or error. Callback is passed as the last argument and it follows the standard node convention `function (err, res1, res2, ...)`. When callback is called its arguments will be emitted on the returned emitter as `end` event payload or as `error` event payload if `err !== null`. | ||
```javascript | ||
var eex = new EEX() | ||
.pipeExcept(numbers()) | ||
.mapAsync(asyncDoubleUp) // pass function, no invocation here | ||
.on('data', console.log) | ||
.on('end', console.log); | ||
// will print | ||
1 | ||
2 | ||
3 | ||
20 | ||
``` | ||
#### flatMap(function[, function, ...]) | ||
Returns new `EEX` that will emit all events from the source emitter except `end`. It will handle `end` event using the provided function by passing `end` payload to it. The function should return an `EventEmitter`, events from which will be piped into the returned emitter. | ||
```javascript | ||
var eex = new EEX() | ||
.pipeExcept(numbers()) | ||
.flatMap(function (x) { | ||
return new EEX() | ||
.emitAsync('data', 3 * x) | ||
.pipeExcept(numbers()); | ||
}) | ||
.on('data', console.log) | ||
.on('end', console.log); | ||
// will print | ||
1 | ||
2 | ||
3 | ||
30 | ||
1 | ||
2 | ||
3 | ||
10 | ||
``` |
@@ -15,2 +15,10 @@ (function () { | ||
describe('#onAllExcept()', function () { | ||
it('should return self', function () { | ||
emitter.onAllExcept('data', function () {}).should.be.equal(emitter); | ||
}); | ||
}); | ||
describe('#startAsync()', function () { | ||
@@ -119,3 +127,3 @@ | ||
emitter.pipeExcept(source, 'end'); | ||
emitter.pipeExcept('end', source); | ||
@@ -147,3 +155,3 @@ emitter.on('error', spyError2); | ||
emitter.pipeExcept(source, 'end', 'x'); | ||
emitter.pipeExcept('end', 'x', source); | ||
@@ -200,3 +208,3 @@ emitter.on('a', spyA); | ||
emitter.pipeExcept(source, 'error'); | ||
emitter.pipeExcept('error', source); | ||
@@ -216,3 +224,3 @@ source.on('error', spyError1); | ||
emitter.pipeExcept(source, 'error'); | ||
emitter.pipeExcept('error', source); | ||
@@ -357,2 +365,63 @@ source.on('error', spyError); | ||
it('should emit error if no arguments passed to callback', function (done) { | ||
var mapped = emitter.mapAsync(function (cb) { | ||
cb(); | ||
}); | ||
mapped.on('error', function () { | ||
done(); | ||
}); | ||
mapped.on('end', function () { throw new Error('Should not emit end'); }); | ||
emitter.emit('end'); | ||
}); | ||
// this is to check type strictness of the err check | ||
it('should emit error on false as first argument to callback', function (done) { | ||
var A = 1, B = 40, C = 2; | ||
var mapped = emitter.mapAsync(function (cb) { | ||
cb(false, A, B, C); | ||
}); | ||
mapped.on('error', function (err, a, b, c) { | ||
err.should.be.false; | ||
a.should.be.equal(A); | ||
b.should.be.equal(B); | ||
c.should.be.equal(C); | ||
done(); | ||
}); | ||
mapped.on('end', function () { throw new Error('Should not emit end'); }); | ||
emitter.emit('end'); | ||
}); | ||
// this is to check type strictness of the err check | ||
it('should emit error on true as first argument to callback', function (done) { | ||
var A = 1, B = 40, C = 2; | ||
var mapped = emitter.mapAsync(function (cb) { | ||
cb(true, A, B, C); | ||
}); | ||
mapped.on('error', function (err, a, b, c) { | ||
err.should.be.true; | ||
a.should.be.equal(A); | ||
b.should.be.equal(B); | ||
c.should.be.equal(C); | ||
done(); | ||
}); | ||
mapped.on('end', function () { throw new Error('Should not emit end'); }); | ||
emitter.emit('end'); | ||
}); | ||
// this is to check type strictness of the err check | ||
it('should emit end on null as first argument to callback', function (done) { | ||
var A = 1, B = 40, C = 2; | ||
var mapped = emitter.mapAsync(function (cb) { | ||
cb(null, A, B, C); | ||
}); | ||
mapped.on('error', function () { throw new Error('Should not emit error'); }); | ||
mapped.on('end', function (a, b, c) { | ||
a.should.be.equal(A); | ||
b.should.be.equal(B); | ||
c.should.be.equal(C); | ||
done(); | ||
}); | ||
emitter.emit('end'); | ||
}); | ||
it('should throw if callback called too many times', function (done) { | ||
@@ -359,0 +428,0 @@ var mapped = emitter.mapAsync(function (cb) { |
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
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
58132
849
1
250