Skip to content

Commit

Permalink
feat: implement compose
Browse files Browse the repository at this point in the history
  • Loading branch information
customcommander committed Feb 27, 2021
1 parent bf1d3da commit 6ca623a
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 0 deletions.
43 changes: 43 additions & 0 deletions src/functions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* @license MIT
* @copyright (c) 2021 Julien Gonzalez <hello@spinjs.com>
*/

const {assert_function} = require('./private/helpers');

/**
* @namespace
* @alias ROOT
*/
module.exports = {

/**
* Performs a right-to-left function composition.
*
* Given a list of functions returns a new function that takes an indefinite number of parameters and applies
* the rightmost function to these, the result of which is fed into the second rightmost function, etc.
* Returns the return value of the leftmost function.
*
* @example
* ```javascript
* const comp = compose(x => x + 2, (x, y) => x + y);
* comp(30, 10);
* //=> 42
* ```
*
* @public
* @param {...function()} fn
* @returns {function()}
* @throws When called with no arguments or with some non-function arguments.
*/
compose: (...fn) => {
if (fn.length === 0) throw new Error('compose: called with no arguments');
fn.forEach((f, i) => assert_function(f, `compose: arg at ${i} is not a function`));
return (...args) => {
let i = fn.length - 1;
let x = fn[i](...args);
while (--i >= 0) x = fn[i](x);
return x;
};
}
};
21 changes: 21 additions & 0 deletions test/compose.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const test = require('tape');
const td = require('testdouble');
const {compose} = require('../dist');

test('compose', t => {
const f = td.func();
const g = td.func();
const h = td.func();

td.when(h(30, 10)).thenReturn(40);
td.when(g(40)).thenReturn(41);
td.when(f(41)).thenReturn(42);

const comp = compose(f, g, h);
t.true(comp(30, 10) === 42, 'compose(f, g, h)(x) === f(g(h(x)))');

t.throws(() => compose(), 'throws when called with no arguments');
t.throws(() => compose(() => 42, [], () => 42), 'throws when called with non-function arguments');

t.end();
});

0 comments on commit 6ca623a

Please sign in to comment.