const test = require('tape');
// The '_composer' wrapper fn supports reversing execution order, literally only changes the inner fn '_partial'
const compose = _composer(); // note: '_composer' defined at the end, read tests first
const composeRight = _composer(true);
// Define a Pure-at-heart function (https://en.wikipedia.org/wiki/Pure_function)
const add5 = n => {
n = parseInt(n) + 5
return n; // required
}
test('sequence of 3 functions', t => {
const add15 = compose(add5, add5, add5);
t.equals(add15(0), 15)
t.equals(add15(5), 20)
t.equals(add15('5'), 20)
t.end();
})
// Define some Pure-at-heart functions (https://en.wikipedia.org/wiki/Pure_function)
const half = n => {
n = (parseInt(n) * 0.5).toFixed(2)
return n; // required
}
const square = n => {
n = (parseInt(n * n)).toFixed(2)
return n; // required
}
test('sequence of different functions', t => {
const add5HalfSquare = compose(add5, half, square);
t.equals(add5HalfSquare(5), '25.00', 'I can caz maths?');
// 5+5==10, half(10)==5, 5*5==25
t.end();
})
// Plz ignore 'es6-ishness' - the point is the pattern above:
// Forward/reverse function chain helper - See examples, way simpler in code - tldr: this glues other functions toghether
function _composer(reverse = false) {
// @uglytruth
// Returns higher-order-function, executes using Array.reduce syntax (link mdn article).
// Starting with the initial arguments, each function is sequentially executed, passing arguments from one function to the next - functions MUST RETURN THE VALUE TO HAND-OFF.
// Only supports single param functions - **this is a feature**
return function _directionalFunChain() {
const fns = Array.from(arguments);
return function _partial() {
return Array.from(fns)
[reverse ? 'reduceRight' : 'reduce']((last, fn) => fn && fn(last) || last, [...arguments]);
}.bind(this);
}
}