Skip to content

Commit

Permalink
stream: simpler stream constructon
Browse files Browse the repository at this point in the history
Via revealing constructor pattern. Referenced to discussion in issue nodejs/readable-stream#102 of iojs/readable-stream
  • Loading branch information
sonewman committed Feb 3, 2015
1 parent 3e67d7e commit 5edbe1a
Show file tree
Hide file tree
Showing 7 changed files with 245 additions and 2 deletions.
133 changes: 131 additions & 2 deletions doc/api/stream.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,7 @@ of stream class you are writing:
<p>[Writable](#stream_class_stream_writable_1)</p>
</td>
<td>
<p><code>[_write][]</code></p>
<p><code>[_write][]</code>, <code>_writev</code></p>
</td>
</tr>
<tr>
Expand All @@ -729,7 +729,7 @@ of stream class you are writing:
<p>[Duplex](#stream_class_stream_duplex_1)</p>
</td>
<td>
<p><code>[_read][]</code>, <code>[_write][]</code></p>
<p><code>[_read][]</code>, <code>[_write][]</code>, <code>_writev</code></p>
</td>
</tr>
<tr>
Expand Down Expand Up @@ -1315,6 +1315,135 @@ 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 API Via Revealing Constructor Pattern

<!--type=misc-->

To implement any sort of stream you can now pass that streams specific methods as parameters to the constructors options:

<table>
<thead>
<tr>
<th>
<p>Use-case</p>
</th>
<th>
<p>Class</p>
</th>
<th>
<p>Method(s) to implement</p>
</th>
</tr>
</thead>
<tr>
<td>
<p>Reading only</p>
</td>
<td>
<p>[Readable](#stream_class_stream_readable_1)</p>
</td>
<td>
<p><code>[read][_read]</code></p>
</td>
</tr>
<tr>
<td>
<p>Writing only</p>
</td>
<td>
<p>[Writable](#stream_class_stream_writable_1)</p>
</td>
<td>
<p><code>[write][_write]</code></p>
</td>
</tr>
<tr>
<td>
<p>Reading and writing</p>
</td>
<td>
<p>[Duplex](#stream_class_stream_duplex_1)</p>
</td>
<td>
<p><code>[read][_read]</code>, <code>[write][_write]</code>, <code>writev</code></p>
</td>
</tr>
<tr>
<td>
<p>Operate on written data, then read the result</p>
</td>
<td>
<p>[Transform](#stream_class_stream_transform_1)</p>
</td>
<td>
<p><code>transform</code>, <code>flush</code></p>
</td>
</tr>
</table>

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

<!--type=misc-->
Expand Down
3 changes: 3 additions & 0 deletions lib/_stream_readable.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ function Readable(options) {
// legacy
this.readable = true;

if (options && typeof options.read === 'function')
this._read = options.read;

Stream.call(this);
}

Expand Down
8 changes: 8 additions & 0 deletions lib/_stream_transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
8 changes: 8 additions & 0 deletions lib/_stream_writable.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
19 changes: 19 additions & 0 deletions test/parallel/test-stream-readable-revealing-constructor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
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);
console.log('ok');
});
32 changes: 32 additions & 0 deletions test/parallel/test-stream-transform-revealing-constructor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
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);
console.log('ok');
});
44 changes: 44 additions & 0 deletions test/parallel/test-stream-writable-revealing-constructor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
var common = require('../common');
var assert = require('assert');

var Writable = require('stream').Writable;

(function one() {
var _writeCalled = false;
function _write(d, e, n) {
_writeCalled = true;
}

var w = new Writable({ write: _write });
w.end(new Buffer('blerg'));

process.on('exit', function () {
assert.equal(w._write, _write);
assert(_writeCalled);
console.log('ok 1');
});
}());

(function two() {
var _writevCalled = false;
var dLength = 0;

function _writev(d, n) {
dLength = d.length;
_writevCalled = true;
}

var w = new Writable({ writev: _writev });
w.cork();

w.write(new Buffer('blerg'));
w.write(new Buffer('blerg'));
w.end();

process.on('exit', function () {
assert.equal(w._writev, _writev);
assert.equal(dLength, 2);
assert(_writevCalled);
console.log('ok 2');
});
}());

0 comments on commit 5edbe1a

Please sign in to comment.