From 50daee7243a3f987e1a28d93c43f913471d6885a Mon Sep 17 00:00:00 2001 From: Sam Newman Date: Tue, 3 Feb 2015 01:12:41 +0000 Subject: [PATCH] stream: simpler stream constructon Adds simplified constructor pattern, allowing users to provide "read", "write", "transform", "flush", and "writev" functions as stream options in lieu of subclassing. Semver: minor PR-URL: https://github.com/iojs/io.js/pull/697 Fixes: https://github.com/iojs/readable-stream/issues/102 Reviewed-By: Chris Dickinson --- doc/api/stream.markdown | 75 ++++++++++++++++++- lib/_stream_readable.js | 3 + lib/_stream_transform.js | 8 ++ lib/_stream_writable.js | 8 ++ ...stream-readable-constructor-set-methods.js | 18 +++++ ...tream-transform-constructor-set-methods.js | 31 ++++++++ ...stream-writable-constructor-set-methods.js | 34 +++++++++ 7 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 test/parallel/test-stream-readable-constructor-set-methods.js create mode 100644 test/parallel/test-stream-transform-constructor-set-methods.js create mode 100644 test/parallel/test-stream-writable-constructor-set-methods.js diff --git a/doc/api/stream.markdown b/doc/api/stream.markdown index 943718660c..bbd2af0d7a 100644 --- a/doc/api/stream.markdown +++ b/doc/api/stream.markdown @@ -718,7 +718,7 @@ of stream class you are writing:

[Writable](#stream_class_stream_writable_1)

-

[_write][]

+

[_write][], _writev

@@ -729,7 +729,7 @@ of stream class you are writing:

[Duplex](#stream_class_stream_duplex_1)

-

[_read][], [_write][]

+

[_read][], [_write][], _writev

@@ -1315,6 +1315,77 @@ for examples and testing, but there are occasionally use cases where it can come in handy as a building block for novel sorts of streams. +## Simplified Constructor API + + + +In simple cases there is now the added benefit of being able to construct a stream without inheritance. + +This can be done by passing the appropriate methods as constructor options: + +Examples: + +### Readable +```javascript +var readable = new stream.Readable({ + read: function(n) { + // sets this._read under the hood + } +}); +``` + +### Writable +```javascript +var writable = new stream.Writable({ + write: function(chunk, encoding, next) { + // sets this._write under the hood + } +}); + +// or + +var writable = new stream.Writable({ + writev: function(chunks, next) { + // sets this._writev under the hood + } +}); +``` + +### Duplex +```javascript +var duplex = new stream.Duplex({ + read: function(n) { + // sets this._read under the hood + }, + write: function(chunk, encoding, next) { + // sets this._write under the hood + } +}); + +// or + +var duplex = new stream.Duplex({ + read: function(n) { + // sets this._read under the hood + }, + writev: function(chunks, next) { + // sets this._writev under the hood + } +}); +``` + +### Transform +```javascript +var transform = new stream.Transform({ + transform: function(chunk, encoding, next) { + // sets this._transform under the hood + }, + flush: function(done) { + // sets this._flush under the hood + } +}); +``` + ## Streams: Under the Hood diff --git a/lib/_stream_readable.js b/lib/_stream_readable.js index 2418648b69..bf736477e8 100644 --- a/lib/_stream_readable.js +++ b/lib/_stream_readable.js @@ -85,6 +85,9 @@ function Readable(options) { // legacy this.readable = true; + if (options && typeof options.read === 'function') + this._read = options.read; + Stream.call(this); } diff --git a/lib/_stream_transform.js b/lib/_stream_transform.js index d3e7a13486..8ff428e11f 100644 --- a/lib/_stream_transform.js +++ b/lib/_stream_transform.js @@ -105,6 +105,14 @@ function Transform(options) { // sync guard flag. this._readableState.sync = false; + if (options) { + if (typeof options.transform === 'function') + this._transform = options.transform; + + if (typeof options.flush === 'function') + this._flush = options.flush; + } + this.once('prefinish', function() { if (typeof this._flush === 'function') this._flush(function(er) { diff --git a/lib/_stream_writable.js b/lib/_stream_writable.js index 0176f4095f..6a008fe76d 100644 --- a/lib/_stream_writable.js +++ b/lib/_stream_writable.js @@ -137,6 +137,14 @@ function Writable(options) { // legacy. this.writable = true; + if (options) { + if (typeof options.write === 'function') + this._write = options.write; + + if (typeof options.writev === 'function') + this._writev = options.writev; + } + Stream.call(this); } diff --git a/test/parallel/test-stream-readable-constructor-set-methods.js b/test/parallel/test-stream-readable-constructor-set-methods.js new file mode 100644 index 0000000000..a88ffcd67a --- /dev/null +++ b/test/parallel/test-stream-readable-constructor-set-methods.js @@ -0,0 +1,18 @@ +var common = require('../common'); +var assert = require('assert'); + +var Readable = require('stream').Readable; + +var _readCalled = false; +function _read(n) { + _readCalled = true; + this.push(null); +} + +var r = new Readable({ read: _read }); +r.resume(); + +process.on('exit', function () { + assert.equal(r._read, _read); + assert(_readCalled); +}); diff --git a/test/parallel/test-stream-transform-constructor-set-methods.js b/test/parallel/test-stream-transform-constructor-set-methods.js new file mode 100644 index 0000000000..55e64ed9b2 --- /dev/null +++ b/test/parallel/test-stream-transform-constructor-set-methods.js @@ -0,0 +1,31 @@ +var common = require('../common'); +var assert = require('assert'); + +var Transform = require('stream').Transform; + +var _transformCalled = false; +function _transform(d, e, n) { + _transformCalled = true; + n(); +} + +var _flushCalled = false; +function _flush(n) { + _flushCalled = true; + n(); +} + +var t = new Transform({ + transform: _transform, + flush: _flush +}); + +t.end(new Buffer('blerg')); +t.resume(); + +process.on('exit', function () { + assert.equal(t._transform, _transform); + assert.equal(t._flush, _flush); + assert(_transformCalled); + assert(_flushCalled); +}); diff --git a/test/parallel/test-stream-writable-constructor-set-methods.js b/test/parallel/test-stream-writable-constructor-set-methods.js new file mode 100644 index 0000000000..496ce66975 --- /dev/null +++ b/test/parallel/test-stream-writable-constructor-set-methods.js @@ -0,0 +1,34 @@ +var common = require('../common'); +var assert = require('assert'); + +var Writable = require('stream').Writable; + +var _writeCalled = false; +function _write(d, e, n) { + _writeCalled = true; +} + +var w = new Writable({ write: _write }); +w.end(new Buffer('blerg')); + +var _writevCalled = false; +var dLength = 0; +function _writev(d, n) { + dLength = d.length; + _writevCalled = true; +} + +var w2 = new Writable({ writev: _writev }); +w2.cork(); + +w2.write(new Buffer('blerg')); +w2.write(new Buffer('blerg')); +w2.end(); + +process.on('exit', function () { + assert.equal(w._write, _write); + assert(_writeCalled); + assert.equal(w2._writev, _writev); + assert.equal(dLength, 2); + assert(_writevCalled); +});