diff --git a/README.md b/README.md index 82366a1f9..28f13e7cb 100644 --- a/README.md +++ b/README.md @@ -74,12 +74,12 @@ Don’t assign values to the [special variable](http://nodejs.org/api/repl.html# * [_.chunk](http://lodash.com/docs#chunk) for splitting an array into chunks of a given size * [_.clone](http://lodash.com/docs#clone) supports shallow cloning of `Date` & `RegExp` objects * [_.cloneDeep](http://lodash.com/docs#cloneDeep) for deep cloning arrays & objects - * [_.consume](http://lodash.com/docs#consume) to complement [_.consumeRight](http://lodash.com/docs#consumeRight) (a.k.a `_.compose`) * [_.contains](http://lodash.com/docs#contains) accepts a `fromIndex` * [_.create](http://lodash.com/docs#create) for easier object inheritance * [_.curry](http://lodash.com/docs#curry) & [_.curryRight](http://lodash.com/docs#curryRight) for creating [curried](http://hughfdjackson.com/javascript/why-curry-helps/) functions * [_.debounce](http://lodash.com/docs#debounce) & [_.throttle](http://lodash.com/docs#throttle) are cancelable & accept options for more control * [_.findIndex](http://lodash.com/docs#findIndex) & [_.findKey](http://lodash.com/docs#findKey) for finding indexes & keys + * [_.flow](http://lodash.com/docs#flow) to complement [_.flowRight](http://lodash.com/docs#vlowRight) (a.k.a `_.compose`) * [_.forEach](http://lodash.com/docs#forEach) supports exiting early * [_.forIn](http://lodash.com/docs#forIn) for iterating all enumerable properties * [_.forOwn](http://lodash.com/docs#forOwn) for iterating own properties diff --git a/lodash.js b/lodash.js index 17fb90e0f..7491e7818 100644 --- a/lodash.js +++ b/lodash.js @@ -794,10 +794,10 @@ * * The chainable wrapper functions are: * `after`, `assign`, `at`, `before`, `bind`, `bindAll`, `bindKey`, `callback`, - * `chain`, `chunk`, `compact`, `concat`, `constant`, `consume`, `consumeRight`, - * `countBy`, `create`, `curry`, `debounce`, `defaults`, `defer`, `delay`, - * `difference`, `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, - * `flatten`, `flattenDeep`, `forEach`, `forEachRight`, `forIn`, `forInRight`, + * `chain`, `chunk`, `compact`, `concat`, `constant`, `countBy`, `create`, + * `curry`, `debounce`, `defaults`, `defer`, `delay`, `difference`, `drop`, + * `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, `flatten`, `flattenDeep`, + * `flow`, `flowRight`, `forEach`, `forEachRight`, `forIn`, `forInRight`, * `forOwn`, `forOwnRight`, `functions`, `groupBy`, `indexBy`, `initial`, * `intersection`, `invert`, `invoke`, `keys`, `keysIn`, `map`, `mapValues`, * `matches`, `memoize`, `merge`, `mixin`, `negate`, `noop`, `omit`, `once`, @@ -5357,8 +5357,8 @@ /** * Reduces a collection to a value which is the accumulated result of running * each element in the collection through `iteratee`, where each successive - * invocation consumes the return value of the previous. If `accumulator` is - * not provided the first element of the collection is used as the initial + * invocation is supplied the return value of the previous. If `accumulator` + * is not provided the first element of the collection is used as the initial * value. The `iteratee` is bound to `thisArg`and invoked with four arguments; * (accumulator, value, index|key, collection). * @@ -5915,96 +5915,6 @@ : createWrapper(key, bitmask, null, object); } - /** - * Creates a function that invokes the provided functions with the `this` - * binding of the created function, where each successive invocation consumes - * the return value of the previous. - * - * @static - * @memberOf _ - * @category Function - * @param {...Function} [funcs] Functions to invoke. - * @returns {Function} Returns the new function. - * @example - * - * function add(x, y) { - * return x + y; - * } - * - * function square(n) { - * return n * n; - * } - * - * var addSquare = _.consume(add, square); - * addSquare(1, 2); - * // => 9 - */ - function consume() { - var funcs = arguments, - length = funcs.length; - - if (!length) { - return function() {}; - } - if (!arrayEvery(funcs, isFunction)) { - throw new TypeError(FUNC_ERROR_TEXT); - } - return function() { - var index = 0, - result = funcs[index].apply(this, arguments); - - while (++index < length) { - result = funcs[index].call(this, result); - } - return result; - }; - } - - /** - * This method is like `_.consume` except that it creates a function that - * invokes the provided functions from right to left. - * - * @static - * @memberOf _ - * @alias compose - * @category Function - * @param {...Function} [funcs] Functions to invoke. - * @returns {Function} Returns the new function. - * @example - * - * function add(x, y) { - * return x + y; - * } - * - * function square(n) { - * return n * n; - * } - * - * var addSquare = _.consumeRight(square, add); - * addSquare(1, 2); - * // => 9 - */ - function consumeRight() { - var funcs = arguments, - fromIndex = funcs.length - 1; - - if (fromIndex < 0) { - return function() {}; - } - if (!arrayEvery(funcs, isFunction)) { - throw new TypeError(FUNC_ERROR_TEXT); - } - return function() { - var index = fromIndex, - result = funcs[index].apply(this, arguments); - - while (index--) { - result = funcs[index].call(this, result); - } - return result; - }; - } - /** * Creates a function that accepts one or more arguments of `func` that when * called either invokes `func` returning its result if all `func` arguments @@ -6297,6 +6207,96 @@ return setTimeout(function() { func.apply(undefined, args); }, wait); } + /** + * Creates a function that invokes the provided functions with the `this` + * binding of the created function, where each successive invocation is + * supplied the return value of the previous. + * + * @static + * @memberOf _ + * @category Function + * @param {...Function} [funcs] Functions to invoke. + * @returns {Function} Returns the new function. + * @example + * + * function add(x, y) { + * return x + y; + * } + * + * function square(n) { + * return n * n; + * } + * + * var addSquare = _.flow(add, square); + * addSquare(1, 2); + * // => 9 + */ + function flow() { + var funcs = arguments, + length = funcs.length; + + if (!length) { + return function() {}; + } + if (!arrayEvery(funcs, isFunction)) { + throw new TypeError(FUNC_ERROR_TEXT); + } + return function() { + var index = 0, + result = funcs[index].apply(this, arguments); + + while (++index < length) { + result = funcs[index].call(this, result); + } + return result; + }; + } + + /** + * This method is like `_.flow` except that it creates a function that + * invokes the provided functions from right to left. + * + * @static + * @memberOf _ + * @alias backflow, compose + * @category Function + * @param {...Function} [funcs] Functions to invoke. + * @returns {Function} Returns the new function. + * @example + * + * function add(x, y) { + * return x + y; + * } + * + * function square(n) { + * return n * n; + * } + * + * var addSquare = _.flowRight(square, add); + * addSquare(1, 2); + * // => 9 + */ + function flowRight() { + var funcs = arguments, + fromIndex = funcs.length - 1; + + if (fromIndex < 0) { + return function() {}; + } + if (!arrayEvery(funcs, isFunction)) { + throw new TypeError(FUNC_ERROR_TEXT); + } + return function() { + var index = fromIndex, + result = funcs[index].apply(this, arguments); + + while (index--) { + result = funcs[index].call(this, result); + } + return result; + }; + } + /** * Creates a function that memoizes the result of `func`. If `resolver` is * provided it determines the cache key for storing the result based on the @@ -6972,7 +6972,7 @@ * @example * * _.functions(_); - * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...] + * // => ['all', 'any', 'bind', ...] */ function functions(object) { return baseFunctions(object, keysIn(object)); @@ -9339,8 +9339,6 @@ lodash.chain = chain; lodash.chunk = chunk; lodash.compact = compact; - lodash.consume = consume; - lodash.consumeRight = consumeRight; lodash.constant = constant; lodash.countBy = countBy; lodash.create = create; @@ -9358,6 +9356,8 @@ lodash.filter = filter; lodash.flatten = flatten; lodash.flattenDeep = flattenDeep; + lodash.flow = flow; + lodash.flowRight = flowRight; lodash.forEach = forEach; lodash.forEachRight = forEachRight; lodash.forIn = forIn; @@ -9420,8 +9420,9 @@ lodash.zipObject = zipObject; // add aliases + lodash.backflow = flowRight; lodash.collect = map; - lodash.compose = consumeRight; + lodash.compose = flowRight; lodash.each = forEach; lodash.eachRight = forEachRight; lodash.extend = assign; diff --git a/test/test.js b/test/test.js index dfff3f3cb..455c2b40f 100644 --- a/test/test.js +++ b/test/test.js @@ -1722,23 +1722,24 @@ /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.consumeRight'); + QUnit.module('lodash.flowRight'); (function() { - test('should be aliased', 1, function() { - strictEqual(_.compose, _.consumeRight); + test('should be aliased', 2, function() { + strictEqual(_.backflow, _.flowRight); + strictEqual(_.compose, _.flowRight); }); }()); /*--------------------------------------------------------------------------*/ - QUnit.module('consume methods'); + QUnit.module('flow methods'); - _.each(['consume', 'consumeRight'], function(methodName) { + _.each(['flow', 'flowRight'], function(methodName) { var func = _[methodName], - isConsume = methodName == 'consume'; + isFlow = methodName == 'flow'; - test('`_.' + methodName + '` should create a function that consumes the output of the provided functions', 1, function() { + test('`_.' + methodName + '` should supply each function with the return value of the previous', 1, function() { function add(x, y) { return x + y; } @@ -1751,8 +1752,8 @@ return n.toFixed(1); } - var consumer = isConsume ? func(add, square, fixed) : func(fixed, square, add); - strictEqual(consumer(1, 2), '9.0'); + var combined = isFlow ? func(add, square, fixed) : func(fixed, square, add); + strictEqual(combined(1, 2), '9.0'); }); test('`_.' + methodName + '` should return a new function', 1, function() { @@ -1760,14 +1761,14 @@ }); test('`_.' + methodName + '` should return a noop function when no arguments are provided', 2, function() { - var consumer = func(); + var combined = func(); try { - strictEqual(consumer(), undefined); + strictEqual(combined(), undefined); } catch(e) { ok(false); } - notStrictEqual(consumer, _.noop); + notStrictEqual(combined, _.noop); }); test('`_.' + methodName + '` should return a wrapped value when chaining', 1, function() { @@ -12071,16 +12072,17 @@ var rejectFalsey = [ 'after', + 'backflow', 'before', 'bind', 'compose', - 'consume', - 'consumeRight', 'curry', 'curryRight', 'debounce', 'defer', 'delay', + 'flow', + 'flowRight', 'memoize', 'negate', 'once', @@ -12159,13 +12161,13 @@ }); }); - test('should throw a TypeError for falsey arguments', 19, function() { + test('should throw a TypeError for falsey arguments', 20, function() { _.each(rejectFalsey, function(methodName) { var expected = _.map(falsey, _.constant(true)), func = _[methodName]; var actual = _.map(falsey, function(value, index) { - var pass = !index && /^(?:compose|consume(Right)?)$/.test(methodName); + var pass = !index && /^(?:backflow|compose|flow(Right)?)$/.test(methodName); try { index ? func(value) : func(); } catch(e) {