From 9c18fc705515d8eac6ff288b491f54318e313b50 Mon Sep 17 00:00:00 2001 From: David Braun Date: Sun, 22 Oct 2017 12:39:02 -0400 Subject: [PATCH] `from` and `of`: Return read-only channels. --- doc/API.md | 34 +++++++++++++++++++++++++++++----- lib/index.js | 2 +- test/index.js | 40 ++++++++++++++++++++++++---------------- 3 files changed, 54 insertions(+), 22 deletions(-) diff --git a/doc/API.md b/doc/API.md index dd99f40..cf31601 100644 --- a/doc/API.md +++ b/doc/API.md @@ -9,10 +9,11 @@ - [value()](#value) - [Array-like Properties](#array-like-properties) - [Channel](#channel) - - [Channel([bufferLength = 0]) -> Channel](#channelbufferlength--0---channel) + - [Channel([bufferLength]) -> Channel](#channelbufferlength---channel) - [Channel.isChannel(value) -> Boolean](#channelischannelvalue---boolean) - - [Channel.of(...values) -> Channel](#channelofvalues---channel) - - [Channel.from(callback | iterable | stream.Readable[, mapfn [, thisArg]]) -> Channel](#channelfromcallback--iterable--streamreadable-mapfn--thisarg---channel) + - [Channel.of(...values) -> read-only Channel](#channelofvalues---read-only-channel) + - [Channel.from(callback | iterable | stream.Readable[, mapfn [, thisArg]]) -> read-only Channel](#channelfromcallback--iterable--streamreadable-mapfn--thisarg---read-only-channel) + - [Examples](#examples-1) - [Channel Object](#channel-object) - [every(callbackfn[, thisArg]) -> async Boolean](#everycallbackfn-thisarg---async-boolean) - [filter(callbackfn[, thisArg]) -> Channel](#filtercallbackfn-thisarg---channel) @@ -160,11 +161,11 @@ to push up to `bufferLength` values before blocking. Return `true` if `value` is a channel, `false` otherwise. -### Channel.of(...values) -> Channel +### Channel.of(...values) -> read-only Channel Push `values` into a new channel and then close it. -### Channel.from(callback | iterable | stream.Readable[, mapfn [, thisArg]]) -> Channel +### Channel.from(callback | iterable | stream.Readable[, mapfn [, thisArg]]) -> read-only Channel Create a new `Channel` from a callback function, an iterable, or a [Node.js readable stream](https://nodejs.org/api/stream.html#stream_readable_streams). @@ -176,6 +177,29 @@ pushing into the channel. Close the channel when the function returns If the optional `mapfn` argument is provided, call it (using the also optional `thisArg`) on each value before pushing it into the channel. +#### Examples + +```JavaScript +const randomValues = Channel.from(Math.random); + +const fromArray = Channel.from([0, 1, 2]); + +const generator = function*() { + let counter = 0; + + for (;;) { + yield counter; + counter++; + } +}; + +const fromGenerator = Channel.from(generator()); + +const fromStream = Channel.from( + fs.createReadStream(`Communicating Sequential Processes.pdf`) +); +``` + ## Channel Object ### every(callbackfn[, thisArg]) -> async Boolean diff --git a/lib/index.js b/lib/index.js index 72a8b38..d068406 100644 --- a/lib/index.js +++ b/lib/index.js @@ -349,7 +349,7 @@ Channel.from = (values, mapfn, thisArg) => { } })(); - return mapfn ? channel.map(mapfn, thisArg) : channel; + return (mapfn ? channel.map(mapfn, thisArg) : channel).readOnly(); }; Channel.of = (...values) => Channel.from(values); diff --git a/test/index.js b/test/index.js index c9d74e0..8c1e7c5 100644 --- a/test/index.js +++ b/test/index.js @@ -45,17 +45,27 @@ describe(`Channel`, function() { }); describe(`from`, function() { - it(`callback`, async function() { - let counter = 0; - const callback = () => (counter < 3 ? counter++ : undefined); - assert.deepEqual(await Channel.from(callback).values(), [0, 1, 2]); + describe(`types`, function() { + it(`callback`, async function() { + let counter = 0; + const callback = () => (counter < 3 ? counter++ : undefined); + assert.deepEqual(await Channel.from(callback).values(), [0, 1, 2]); + }); + + it(`iterable`, async function() { + assert.deepEqual(await Channel.from([0, 1, 2]).values(), [0, 1, 2]); + }); + + it(`Node.js's stream.Readable`, async function() { + const readable = stream.PassThrough({ objectMode: true }); + readable.write(0); + readable.write(1); + readable.end(2); + assert.deepEqual(await Channel.from(readable).values(), [0, 1, 2]); + }); }); - it(`iterable`, async function() { - assert.deepEqual(await Channel.from([0, 1, 2]).values(), [0, 1, 2]); - }); - - it(`mapfn`, async function() { + it(`with mapfn`, async function() { assert.deepEqual( await Channel.from([`a`, `b`, `c`], value => value.toUpperCase() @@ -64,12 +74,8 @@ describe(`Channel`, function() { ); }); - it(`Node.js's stream.readOnly`, async function() { - const readOnly = stream.PassThrough({ objectMode: true }); - readOnly.write(0); - readOnly.write(1); - readOnly.end(2); - assert.deepEqual(await Channel.from(readOnly).values(), [0, 1, 2]); + it(`returns a readOnly channel`, function() { + assert(!(`push` in Channel.from([0, 1, 2]))); }); }); @@ -81,7 +87,9 @@ describe(`Channel`, function() { }); it(`of`, async function() { - assert.deepEqual(await Channel.of(0, 1, 2).values(), [0, 1, 2]); + const channel = Channel.of(0, 1, 2); + assert(!(`push` in channel)); + assert.deepEqual(await channel.values(), [0, 1, 2]); }); describe(`select`, function() {