From 8da51305eb177d3e11c38280e7bc449d9c896698 Mon Sep 17 00:00:00 2001 From: David Braun Date: Wed, 11 Oct 2017 03:32:47 -0400 Subject: [PATCH] Add functional API. --- README.md | 22 ++++++++++++++++++++++ lib/index.js | 24 ++++++++++++++++++++++++ test/index.js | 47 +++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 91 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c5950c1..2ce2f9e 100644 --- a/README.md +++ b/README.md @@ -228,6 +228,28 @@ Closed channels always return `undefined` immediately. #### slice(start, end) -> Channel +### Functional API + +There is a parallel API to support functional-style programming. Every channel +method is also available as an independent function in the `Channel` namespace +that takes a channel as the final argument. For example, `slice` can be called +in either of the following two ways: + +```JavaScript +// method +channel.slice(10) + +// function +Channel.slice(10, Infinity, channel) +``` + +You can also use partial application to pass the channel in later: + +```JavaScript +const skipTen = Channel.slice(10, Infinity) +skipTen(channel) +``` + # Contributing Please [submit an issue](https://github.com/NodeGuy/channel/issues/new) if you diff --git a/lib/index.js b/lib/index.js index e75f95f..363c8d4 100644 --- a/lib/index.js +++ b/lib/index.js @@ -311,4 +311,28 @@ Channel.select = (...methodPromises) => { return promise } +// functional interface allowing full or partial application +// +// Channel.slice(10, Infinity, channel) +// +// or +// +// const skipTen = Channel.slice(10, Infinity) +// skipTen(channel) + +const channel = Channel() +const methods = Object.keys(channel).concat(Object.keys(channel.readOnly())) + +methods.forEach((method) => { + Channel[method] = (...args) => { + const arity = method === `slice` + ? 3 + : channel[method].length + + return args.length >= arity + ? args[arity - 1][method](...args.slice(0, arity - 1)) + : (channel) => channel[method](...args) + } +}) + module.exports = Object.freeze(Channel) diff --git a/test/index.js b/test/index.js index a4b8184..2022bdf 100644 --- a/test/index.js +++ b/test/index.js @@ -99,6 +99,45 @@ describe(`Channel`, function () { break } }) + + describe(`functional interface`, async function () { + describe(`map`, function () { + it(`full application`, async function () { + assert.deepEqual( + await toArray(Channel.map( + (value) => value.toUpperCase(), + Channel.of(`a`, `b`, `c`) + )), + [`A`, `B`, `C`] + ) + }) + + it(`partial application`, async function () { + assert.deepEqual( + await toArray(Channel.map((value) => + value.toUpperCase())(Channel.of(`a`, `b`, `c`)) + ), + [`A`, `B`, `C`] + ) + }) + }) + + describe(`slice`, function () { + it(`full application`, async function () { + assert.deepEqual( + await toArray(Channel.slice(1, 4, Channel.of(0, 1, 2, 3, 4))), + [1, 2, 3] + ) + }) + + it(`partial application`, async function () { + assert.deepEqual( + await toArray(Channel.slice(1, 4)(Channel.of(0, 1, 2, 3, 4))), + [1, 2, 3] + ) + }) + }) + }) }) describe(`Channel object`, function () { @@ -143,7 +182,9 @@ describe(`Channel object`, function () { it(`filter`, async function () { assert.deepEqual( - await toArray(Channel.of(0, 1, 2, 3, 4, 5).filter(x => x % 2 !== 0)), + await toArray(Channel.of(0, 1, 2, 3, 4, 5) + .filter((value) => value % 2 !== 0) + ), [1, 3, 5] ) }) @@ -165,7 +206,9 @@ describe(`Channel object`, function () { it(`map`, async function () { assert.deepEqual( - await toArray(Channel.of(`a`, `b`, `c`).map(x => x.toUpperCase())), + await toArray(Channel.of(`a`, `b`, `c`) + .map((value) => value.toUpperCase()) + ), [`A`, `B`, `C`] ) })