Permalink
Browse files

[api test doc] Allow for user-created EventEmitter instances to be op…

…tionally passed to `errs.handle`.
  • Loading branch information...
1 parent bbc7f29 commit 2f4ce18705c5d0e2eec84041b59cda164b92ae83 @indexzero committed Mar 3, 2012
Showing with 118 additions and 12 deletions.
  1. +70 −2 README.md
  2. +14 −9 lib/errs.js
  3. +34 −1 test/errs-test.js
View
@@ -6,6 +6,7 @@ Simple error creation and passing utilities focused on:
* [Reusing Error Types](#reusing-types)
* [Merging with Existing Errors](#merging-errors)
* [Optional Callback Invocation](#optional-invocation)
+* [Piping Error Events](#piping-errors)
<a name="creating-errors" />
## Creating Errors
@@ -134,7 +135,7 @@ Node.js handles asynchronous IO through the elegant `EventEmitter` API. In many
}
```
-`errs` it presents a common API for both emitting `error` events and invoking continuations (i.e. callbacks) with errors;
+`errs` it presents a common API for both emitting `error` events and invoking continuations (i.e. callbacks) with errors. If a `callback` is supplied to `errs.handle()` it will be invoked with the error. It no `callback` is provided then an `EventEmitter` is returned which emits an `error` event on the next tick:
``` js
function importantFeature(callback) {
@@ -146,7 +147,74 @@ Node.js handles asynchronous IO through the elegant `EventEmitter` API. In many
}
```
-If a `callback` is supplied to `errs.handle()` it will be invoked with the error. It no `callback` is provided then an `EventEmitter` is returned which emits an `error` event on the next tick.
+<a name="piping-errors" />
+## Piping Errors
+
+Often when working with streams (especially when buffering for whatever reason), you may have already returned an `EventEmitter` or `Stream` instance by the time an error is handled.
+
+``` js
+ function pipeSomething(callback) {
+ //
+ // You have a stream (e.g. http.ResponseStream) and you
+ // have an optional `callback`.
+ //
+ var stream = new require('stream').Stream;
+
+ //
+ // You need to do something async which may respond with an
+ // error
+ //
+ getAnotherStream(function (err, source) {
+ if (err) {
+ if (callback)
+ callback(err);
+ }
+
+ stream.emit('error', err);
+ return;
+ }
+
+ source.pipe(stream);
+ })
+
+ return stream;
+ }
+```
+
+You may pass either a `function` or `EventEmitter` instance to `errs.handle`.
+
+``` js
+ function pipeSomething(callback) {
+ //
+ // You have a stream (e.g. http.ResponseStream) and you
+ // have an optional `callback`.
+ //
+ var stream = new require('stream').Stream;
+
+ //
+ // You need to do something async which may respond with an
+ // error
+ //
+ getAnotherStream(function (err, source) {
+ if (err) {
+ //
+ // Invoke the callback if it exists otherwise the stream.
+ //
+ return errs.handle(err, callback || stream);
+ }
+
+ source.pipe(stream);
+ })
+
+ return stream;
+ }
+```
+
+If you wish to invoke both a `callback` function and an `error` event simply pass both:
+
+``` js
+ errs.handle(err, callback, stream);
+```
## Methods
The `errs` modules exposes some simple utility methods:
View
@@ -146,25 +146,30 @@ exports.merge = function (err, type, opts) {
//
// ### function handle (error, callback)
// #### @error {string|function|Array|object} Error to handle
-// #### @callback {function} **Optional** Continuation to pass the error to.
+// #### @callback {function|EventEmitter} **Optional** Continuation or stream to pass the error to.
+// #### @stream {EventEmitter} **Optional** Explicit EventEmitter to use.
//
// Attempts to instantiate the given `error`. If the `error` is already a properly
// formed `error` object (with a `stack` property) it will not be modified.
//
-// * If a `callback` is supplied, it is invoked with the `error`.
+// * If `callback` is a function, it is invoked with the `error`.
+// * If `callback` is an `EventEmitter`, it emits the `error` event on
+// that emitter and returns it.
// * If no `callback`, return a new `EventEmitter` which emits `error`
// on `process.nextTick()`.
//
-exports.handle = function (error, callback) {
+exports.handle = function (error, callback, stream) {
error = exports.create(error);
- if (callback) {
- return callback(error);
+ if (typeof callback === 'function') {
+ callback(error);
+ }
+
+ if (typeof callback !== 'function' || stream) {
+ var emitter = stream || callback || new events.EventEmitter();
+ process.nextTick(function () { emitter.emit('error', error); });
+ return emitter;
}
-
- var emitter = new events.EventEmitter();
- process.nextTick(function () { emitter.emit('error', error); });
- return emitter;
};
//
View
@@ -7,6 +7,7 @@
*/
var assert = require('assert'),
+ events = require('events'),
vows = require('vows'),
errs = require('../lib/errs'),
fixtures = require('./fixtures'),
@@ -65,14 +66,46 @@ vows.describe('errs').addBatch({
assert.equal(err, this.err);
}
},
+ "with an EventEmitter (i.e. stream)": {
+ topic: function () {
+ var err = this.err = errs.create('Some emitted error'),
+ stream = new events.EventEmitter();
+
+ stream.once('error', this.callback.bind(this, null));
+ errs.handle(err, stream);
+ },
+ "should emit the `error` event": function (_, err) {
+ assert.equal(err, this.err);
+ }
+ },
+ "with a callback and an EventEmitter": {
+ topic: function () {
+ var err = this.err = errs.create('Some emitted error'),
+ stream = new events.EventEmitter(),
+ invoked = 0,
+ that = this;
+
+ function onError(err) {
+ if (++invoked === 2) {
+ that.callback.call(that, null, err);
+ }
+ }
+
+ stream.once('error', onError);
+ errs.handle(err, onError, stream);
+ },
+ "should emit the `error` event": function (_, err) {
+ assert.equal(err, this.err);
+ }
+ },
"with no callback": {
topic: function () {
var err = this.err = errs.create('Some emitted error'),
emitter = errs.handle(err);
emitter.once('error', this.callback.bind(this, null));
},
- "should invoke the callback with the error": function (_, err) {
+ "should emit the `error` event": function (_, err) {
assert.equal(err, this.err);
}
}

0 comments on commit 2f4ce18

Please sign in to comment.