From e22cb5f3b32de7df85c413f2eb7c2a9e9d6ea7ef Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Wed, 14 Oct 2015 17:55:01 -0700 Subject: [PATCH] Rename `_.first` to `_.head`, `_.rest` to `_.tail`, & `_.restParam` to `_.rest`. --- lodash.js | 258 ++++----- test/backbone.html | 2 +- test/test.js | 1252 +++++++++++++++++++++--------------------- test/underscore.html | 13 +- 4 files changed, 773 insertions(+), 752 deletions(-) diff --git a/lodash.js b/lodash.js index 92c269c39..a8beebc1e 100644 --- a/lodash.js +++ b/lodash.js @@ -1410,50 +1410,50 @@ * * The wrapper methods that support shortcut fusion are: * `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`, `findLast`, - * `first`, `initial`, `last`, `map`, `reject`, `rest`, `reverse`, `slice`, + * `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`, `tail`, * `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray` * * The chainable wrapper methods are: * `after`, `ary`, `assign`, `assignWith`, `at`, `before`, `bind`, `bindAll`, * `bindKey`, `chain`, `chunk`, `commit`, `compact`, `concat`, `constant`, - * `countBy`, `create`, `curry`, `debounce`, `defaults`, `defaultsDeep`, - * `defer`, `delay`, `difference`, `differenceBy`, `drop`, `dropRight`, - * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`, - * `flatten`, `flattenDeep`, `flip`, `flow`, `flowRight`, `forEach`, - * `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `functions`, - * `groupBy`, `initial`, `intersection`, `intersectionBy`, `invert`, `invoke`, - * `iteratee`, `keyBy`, `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, - * `matches`, `matchesProperty`, `memoize`, `merge`, `mergeWith` `method`, - * `methodOf`, `mixin`, `modArgs`, `modArgsSet', 'negate`, `omit`, `omitBy`, - * `once`, `pairs`, `partial`, `partialRight`, `partition`, `pick`, `pickBy`, - * `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`, `pullAt`, - * `push`, `range`, `rearg`, `reject`, `remove`, `rest`, `restParam`, `reverse`, - * `sampleSize`, `set`, `setWith`, `shuffle`, `slice`, `sort`, `sortBy`, - * `sortByOrder`, `splice`, `spread`, `take`, `takeRight`, `takeRightWhile`, - * `takeWhile`, `tap`, `throttle`, `thru`, `times`, `toArray`, `toPath`, - * `toPlainObject`, `transform`, `union`, `unionBy`, `uniq`, `uniqBy`, `unset`, - * `unshift`, `unzip`, `unzipWith`, `values`, `valuesIn`, `without`, `wrap`, - * `xor`, `xorBy`, `zip`, `zipObject`, and `zipWith` + * `countBy`, `create`, `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, + * `delay`, `difference`, `differenceBy`, `drop`, `dropRight`, `dropRightWhile`, + * `dropWhile`, `extend`, `extendWith`, `fill`, `filter`, `flatten`, `flattenDeep`, + * `flip`, `flow`, `flowRight`, `forEach`, `forEachRight`, `forIn`, `forInRight`, + * `forOwn`, `forOwnRight`, `functions`, `groupBy`, `initial`, `intersection`, + * `intersectionBy`, `invert`, `invoke`, `iteratee`, `keyBy`, `keys`, `keysIn`, + * `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`, `memoize`, + * `merge`, `mergeWith` `method`, `methodOf`, `mixin`, `modArgs`, `modArgsSet', + * 'negate`, `omit`, `omitBy`, `once`, `pairs`, `partial`, `partialRight`, + * `partition`, `pick`, `pickBy`, `plant`, `property`, `propertyOf`, `pull`, + * `pullAll`, `pullAllBy`, `pullAt`, `push`, `range`, `rearg`, `reject`, + * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`, + * `slice`, `sort`, `sortBy`, `sortByOrder`, `splice`, `spread`, `tail`, + * `take`, `takeRight`, `takeRightWhile`, `takeWhile`, `tap`, `throttle`, + * `thru`, `times`, `toArray`, `toPath`, `toPlainObject`, `transform`, `union`, + * `unionBy`, `uniq`, `uniqBy`, `unset`, `unshift`, `unzip`, `unzipWith`, + * `values`, `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `zip`, `zipObject`, + * and `zipWith` * * The wrapper methods that are **not** chainable by default are: * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clone`, `cloneDeep`, * `cloneDeepWith`, `cloneWith`, `deburr`, `endsWith`, `eq`, `escape`, * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`, - * `findLastIndex`, `findLastKey`, `first`, `floor`, `get`, `gt`, `gte`, `has`, - * `hasIn`, `identity`, `includes`, `indexOf`, `inRange`, `isArguments`, - * `isArray`, `isArrayLike`, `isArrayLikeObject`, `isBoolean`, `isDate`, - * `isElement`, `isEmpty`, `isEqual`, `isEqualWith`, `isError`, `isFinite`, - * `isFunction`, `isInteger`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, - * `isNil`, `isNull`, `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, - * `isRegExp`, `isSafeInteger`, `isString`, `isUndefined`, `isTypedArray`, - * `join`, `kebabCase`, `last`, `lastIndexOf`, `lowerCase`, `lt`, `lte`, `max`, - * `min`, `noConflict`, `noop`, `now`, `pad`, `padLeft`, `padRight`, `parseInt`, - * `pop`, `random`, `reduce`, `reduceRight`, `repeat`, `result`, `round`, - * `runInContext`, `sample`, `shift`, `size`, `snakeCase`, `some`, `sortedIndex`, - * `sortedIndexBy`, `sortedLastIndex`, `sortedLastIndexBy`, `startCase`, - * `startsWith`, `sum`, `sumBy`, `template`, `toLower`, `toInteger`, `toString`, - * `toUpper`, `trim`, `trimLeft`, `trimRight`, `trunc`, `unescape`, `uniqueId`, - * `upperCase`, `value`, and `words` + * `findLastIndex`, `findLastKey`, `floor`, `get`, `gt`, `gte`, `has`, `hasIn`, + * `head`, `identity`, `includes`, `indexOf`, `inRange`, `isArguments`, `isArray`, + * `isArrayLike`, `isArrayLikeObject`, `isBoolean`, `isDate`, `isElement`, + * `isEmpty`, `isEqual`, `isEqualWith`, `isError`, `isFinite`, `isFunction`, + * `isInteger`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`, + * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`, + * `isSafeInteger`, `isString`, `isUndefined`, `isTypedArray`, `join`, `kebabCase`, + * `last`, `lastIndexOf`, `lowerCase`, `lt`, `lte`, `max`, `min`, `noConflict`, + * `noop`, `now`, `pad`, `padLeft`, `padRight`, `parseInt`, `pop`, `random`, + * `reduce`, `reduceRight`, `repeat`, `result`, `round`, `runInContext`, + * `sample`, `shift`, `size`, `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, + * `sortedLastIndex`, `sortedLastIndexBy`, `startCase`, `startsWith`, `sum`, + * `sumBy`, `template`, `toLower`, `toInteger`, `toString`, `toUpper`, `trim`, + * `trimLeft`, `trimRight`, `trunc`, `unescape`, `uniqueId`, `upperCase`, + * `value`, and `words` * * @name _ * @constructor @@ -3675,7 +3675,7 @@ * @returns {Function} Returns the new assigner function. */ function createAssigner(assigner) { - return restParam(function(object, sources) { + return rest(function(object, sources) { var index = -1, length = object == null ? 0 : sources.length, customizer = length > 1 ? sources[length - 1] : undefined, @@ -3969,9 +3969,9 @@ * @returns {Function} Returns the new invoker function. */ function createInvoker(arrayFunc) { - return restParam(function(iteratees) { + return rest(function(iteratees) { iteratees = arrayMap(baseFlatten(iteratees), getIteratee()); - return restParam(function(args) { + return rest(function(args) { var thisArg = this; return arrayFunc(iteratees, function(iteratee) { return iteratee.apply(thisArg, args); @@ -3989,11 +3989,11 @@ * @returns {Function} Returns the new arguments modifier function. */ function createModArgs(resolver) { - return restParam(function(func, transforms) { + return rest(function(func, transforms) { transforms = arrayMap(baseFlatten(transforms), getIteratee()); var funcsLength = transforms.length; - return restParam(function(args) { + return rest(function(args) { var index = -1, length = nativeMin(args.length, funcsLength), modded = copyArray(args); @@ -5004,7 +5004,7 @@ * _.difference([3, 2, 1], [4, 2]); * // => [3, 1] */ - var difference = restParam(function(array, values) { + var difference = rest(function(array, values) { return isArrayLikeObject(array) ? baseDifference(array, baseFlatten(values, false, true)) : []; @@ -5031,7 +5031,7 @@ * _.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x'); * // => [{ 'x': 2 }] */ - var differenceBy = restParam(function(array, values) { + var differenceBy = rest(function(array, values) { var iteratee = last(values); if (isArrayLikeObject(iteratee)) { iteratee = undefined; @@ -5309,26 +5309,6 @@ : -1; } - /** - * Gets the first element of `array`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @returns {*} Returns the first element of `array`. - * @example - * - * _.first([1, 2, 3]); - * // => 1 - * - * _.first([]); - * // => undefined - */ - function first(array) { - return array ? array[0] : undefined; - } - /** * Flattens `array` a single level. * @@ -5365,6 +5345,27 @@ return length ? baseFlatten(array, true) : []; } + /** + * Gets the first element of `array`. + * + * @static + * @memberOf _ + * @alias first + * @category Array + * @param {Array} array The array to query. + * @returns {*} Returns the first element of `array`. + * @example + * + * _.head([1, 2, 3]); + * // => 1 + * + * _.head([]); + * // => undefined + */ + function head(array) { + return array ? array[0] : undefined; + } + /** * Gets the index at which the first occurrence of `value` is found in `array` * using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) @@ -5431,7 +5432,7 @@ * _.intersection([2, 1], [4, 2], [1, 2]); * // => [2] */ - var intersection = restParam(function(arrays) { + var intersection = rest(function(arrays) { var mapped = arrayMap(arrays, toArrayLikeObject); return (mapped.length && mapped[0] === arrays[0]) ? baseIntersection(mapped) @@ -5458,7 +5459,7 @@ * _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); * // => [{ 'x': 1 }] */ - var intersectionBy = restParam(function(arrays) { + var intersectionBy = rest(function(arrays) { var iteratee = last(arrays), mapped = arrayMap(arrays, toArrayLikeObject); @@ -5552,7 +5553,7 @@ * console.log(array); * // => [1, 1] */ - var pull = restParam(pullAll); + var pull = rest(pullAll); /** * This method is like `_.pull` except that it accepts an array of values to remove. @@ -5631,7 +5632,7 @@ * console.log(evens); * // => [10, 20] */ - var pullAt = restParam(function(array, indexes) { + var pullAt = rest(function(array, indexes) { indexes = arrayMap(baseFlatten(indexes), String); var result = baseAt(array, indexes); @@ -5686,23 +5687,6 @@ return result; } - /** - * Gets all but the first element of `array`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.rest([1, 2, 3]); - * // => [2, 3] - */ - function rest(array) { - return drop(array, 1); - } - /** * Reverses `array` so that the first element becomes the last, the second * element becomes the second to last, and so on. @@ -5939,6 +5923,23 @@ : []; } + /** + * Gets all but the first element of `array`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to query. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.tail([1, 2, 3]); + * // => [2, 3] + */ + function tail(array) { + return drop(array, 1); + } + /** * Creates a slice of `array` with `n` elements taken from the beginning. * @@ -6104,7 +6105,7 @@ * _.union([2, 1], [4, 2], [1, 2]); * // => [2, 1, 4] */ - var union = restParam(function(arrays) { + var union = rest(function(arrays) { return baseUniq(baseFlatten(arrays, false, true)); }); @@ -6128,7 +6129,7 @@ * _.unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); * // => [{ 'x': 1 }, { 'x': 2 }] */ - var unionBy = restParam(function(arrays) { + var unionBy = rest(function(arrays) { var iteratee = last(arrays); if (isArrayLikeObject(iteratee)) { iteratee = undefined; @@ -6267,7 +6268,7 @@ * _.without([1, 2, 1, 3], 1, 2); * // => [3] */ - var without = restParam(function(array, values) { + var without = rest(function(array, values) { return isArrayLikeObject(array) ? baseDifference(array, values) : []; @@ -6287,7 +6288,7 @@ * _.xor([2, 1], [4, 2]); * // => [1, 4] */ - var xor = restParam(function(arrays) { + var xor = rest(function(arrays) { return baseXor(arrayFilter(arrays, isArrayLikeObject)); }); @@ -6311,7 +6312,7 @@ * _.xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); * // => [{ 'x': 2 }] */ - var xorBy = restParam(function(arrays) { + var xorBy = rest(function(arrays) { var iteratee = last(arrays); if (isArrayLikeObject(iteratee)) { iteratee = undefined; @@ -6334,7 +6335,7 @@ * _.zip(['fred', 'barney'], [30, 40], [true, false]); * // => [['fred', 30, true], ['barney', 40, false]] */ - var zip = restParam(unzip); + var zip = rest(unzip); /** * The inverse of `_.pairs`; this method returns an object composed from arrays @@ -6392,7 +6393,7 @@ * _.zipWith([1, 2], [10, 20], [100, 200], _.add); * // => [111, 222] */ - var zipWith = restParam(function(arrays) { + var zipWith = rest(function(arrays) { var length = arrays.length, iteratee = length > 1 ? arrays[length - 1] : undefined; @@ -6425,7 +6426,7 @@ * .map(function(o) { * return o.user + ' is ' + o.age; * }) - * .first() + * .head() * .value(); * // => 'pebbles is 1' */ @@ -6501,13 +6502,13 @@ * ]; * * // without explicit chaining - * _(users).first(); + * _(users).head(); * // => { 'user': 'barney', 'age': 36 } * * // with explicit chaining * _(users) * .chain() - * .first() + * .head() * .pick('user') * .value(); * // => { 'user': 'barney' } @@ -6565,7 +6566,7 @@ * console.log(array); * // => [1] */ - var wrapperConcat = restParam(function(values) { + var wrapperConcat = rest(function(values) { values = baseFlatten(values); return this.thru(function(array) { return arrayConcat(isArray(array) ? array : [Object(array)], values); @@ -7047,7 +7048,7 @@ * _.invoke([123, 456], String.prototype.split, ''); * // => [['1', '2', '3'], ['4', '5', '6']] */ - var invoke = restParam(function(collection, path, args) { + var invoke = rest(function(collection, path, args) { var index = -1, isFunc = typeof path == 'function', isProp = isKey(path), @@ -7469,7 +7470,7 @@ * }) ); * // => [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]] */ - var sortBy = restParam(function(collection, iteratees) { + var sortBy = rest(function(collection, iteratees) { if (collection == null) { return []; } @@ -7672,7 +7673,7 @@ * bound('hi'); * // => 'hi fred!' */ - var bind = restParam(function(func, thisArg, partials) { + var bind = rest(function(func, thisArg, partials) { var bitmask = BIND_FLAG; if (partials.length) { var holders = replaceHolders(partials, bind.placeholder); @@ -7707,7 +7708,7 @@ * jQuery('#docs').on('click', view.onClick); * // => logs 'clicked docs' when the element is clicked */ - var bindAll = restParam(function(object, methodNames) { + var bindAll = rest(function(object, methodNames) { arrayEach(baseFlatten(methodNames), function(key) { object[key] = bind(object[key], object); }); @@ -7758,7 +7759,7 @@ * bound('hi'); * // => 'hiya fred!' */ - var bindKey = restParam(function(object, key, partials) { + var bindKey = rest(function(object, key, partials) { var bitmask = BIND_FLAG | BIND_KEY_FLAG; if (partials.length) { var holders = replaceHolders(partials, bindKey.placeholder); @@ -8068,7 +8069,7 @@ * }, 'deferred'); * // logs 'deferred' after one or more milliseconds */ - var defer = restParam(function(func, args) { + var defer = rest(function(func, args) { return baseDelay(func, 1, args); }); @@ -8090,7 +8091,7 @@ * }, 1000, 'later'); * // => logs 'later' after one second */ - var delay = restParam(function(func, wait, args) { + var delay = rest(function(func, wait, args) { return baseDelay(func, wait, args); }); @@ -8413,7 +8414,7 @@ * greetFred('hi'); * // => 'hi fred' */ - var partial = restParam(function(func, partials) { + var partial = rest(function(func, partials) { var holders = replaceHolders(partials, partial.placeholder); return createWrapper(func, PARTIAL_FLAG, undefined, partials, holders); }); @@ -8449,7 +8450,7 @@ * sayHelloTo('fred'); * // => 'hello fred' */ - var partialRight = restParam(function(func, partials) { + var partialRight = rest(function(func, partials) { var holders = replaceHolders(partials, partialRight.placeholder); return createWrapper(func, PARTIAL_RIGHT_FLAG, undefined, partials, holders); }); @@ -8476,7 +8477,7 @@ * rearged('b', 'c', 'a') * // => ['a', 'b', 'c'] */ - var rearg = restParam(function(func, indexes) { + var rearg = rest(function(func, indexes) { return createWrapper(func, REARG_FLAG, undefined, undefined, undefined, baseFlatten(indexes)); }); @@ -8494,7 +8495,7 @@ * @returns {Function} Returns the new function. * @example * - * var say = _.restParam(function(what, names) { + * var say = _.rest(function(what, names) { * return what + ' ' + _.initial(names).join(', ') + * (_.size(names) > 1 ? ', & ' : '') + _.last(names); * }); @@ -8502,7 +8503,7 @@ * say('hello', 'fred', 'barney', 'pebbles'); * // => 'hello fred, barney, & pebbles' */ - function restParam(func, start) { + function rest(func, start) { if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } @@ -8511,22 +8512,22 @@ var args = arguments, index = -1, length = nativeMax(args.length - start, 0), - rest = Array(length); + array = Array(length); while (++index < length) { - rest[index] = args[start + index]; + array[index] = args[start + index]; } switch (start) { - case 0: return func.call(this, rest); - case 1: return func.call(this, args[0], rest); - case 2: return func.call(this, args[0], args[1], rest); + case 0: return func.call(this, array); + case 1: return func.call(this, args[0], array); + case 2: return func.call(this, args[0], args[1], array); } var otherArgs = Array(start + 1); index = -1; while (++index < start) { otherArgs[index] = args[index]; } - otherArgs[start] = rest; + otherArgs[start] = array; return func.apply(this, otherArgs); }; } @@ -9832,7 +9833,7 @@ * _.at(['a', 'b', 'c'], 0, 2); * // => ['a', 'c'] */ - var at = restParam(function(object, paths) { + var at = rest(function(object, paths) { return baseAt(object, baseFlatten(paths)); }); @@ -9893,7 +9894,7 @@ * _.defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' }); * // => { 'user': 'barney', 'age': 36 } */ - var defaults = restParam(function(args) { + var defaults = rest(function(args) { args.push(undefined, extendDefaults); return extendWith.apply(undefined, args); }); @@ -9916,7 +9917,7 @@ * // => { 'user': { 'name': 'barney', 'age': 36 } } * */ - var defaultsDeep = restParam(function(args) { + var defaultsDeep = rest(function(args) { args.push(undefined, mergeDefaults); return mergeWith.apply(undefined, args); }); @@ -10538,7 +10539,7 @@ * _.omit(object, 'user'); * // => { 'age': 40 } */ - var omit = restParam(function(object, props) { + var omit = rest(function(object, props) { if (object == null) { return {}; } @@ -10608,7 +10609,7 @@ * _.pick(object, 'user'); * // => { 'user': 'fred' } */ - var pick = restParam(function(object, props) { + var pick = rest(function(object, props) { return object == null ? {} : basePick(object, baseFlatten(props)); }); @@ -11970,7 +11971,7 @@ * elements = []; * } */ - var attempt = restParam(function(func, args) { + var attempt = rest(function(func, args) { try { return func.apply(undefined, args); } catch (e) { @@ -12138,7 +12139,7 @@ * _.invoke(_.sortBy(objects, _.method(['a', 'b', 'c'])), 'a.b.c'); * // => [1, 2] */ - var method = restParam(function(path, args) { + var method = rest(function(path, args) { return function(object) { return invokePath(object, path, args); }; @@ -12166,7 +12167,7 @@ * _.map([['a', '2'], ['c', '0']], _.methodOf(object)); * // => [2, 0] */ - var methodOf = restParam(function(object, args) { + var methodOf = rest(function(object, args) { return function(path) { return invokePath(object, path, args); }; @@ -12839,7 +12840,6 @@ lodash.reject = reject; lodash.remove = remove; lodash.rest = rest; - lodash.restParam = restParam; lodash.reverse = reverse; lodash.sampleSize = sampleSize; lodash.set = set; @@ -12851,6 +12851,7 @@ lodash.sortedUniq = sortedUniq; lodash.sortedUniqBy = sortedUniqBy; lodash.spread = spread; + lodash.tail = tail; lodash.take = take; lodash.takeRight = takeRight; lodash.takeRightWhile = takeRightWhile; @@ -12912,7 +12913,6 @@ lodash.findLast = findLast; lodash.findLastIndex = findLastIndex; lodash.findLastKey = findLastKey; - lodash.first = first; lodash.floor = floor; lodash.forEach = forEach; lodash.forEachRight = forEachRight; @@ -12925,6 +12925,7 @@ lodash.gte = gte; lodash.has = has; lodash.hasIn = hasIn; + lodash.head = head; lodash.identity = identity; lodash.includes = includes; lodash.indexOf = indexOf; @@ -13009,6 +13010,9 @@ lodash.uniqueId = uniqueId; lodash.upperCase = upperCase; + // Add aliases. + lodash.first = head; + mixin(lodash, (function() { var source = {}; baseForOwn(lodash, function(func, methodName) { @@ -13071,8 +13075,8 @@ }; }); - // Add `LazyWrapper` methods for `_.first` and `_.last`. - arrayEach(['first', 'last'], function(methodName, index) { + // Add `LazyWrapper` methods for `_.head` and `_.last`. + arrayEach(['head', 'last'], function(methodName, index) { var takeName = 'take' + (index ? 'Right' : ''); LazyWrapper.prototype[methodName] = function() { @@ -13080,8 +13084,8 @@ }; }); - // Add `LazyWrapper` methods for `_.initial` and `_.rest`. - arrayEach(['initial', 'rest'], function(methodName, index) { + // Add `LazyWrapper` methods for `_.initial` and `_.tail`. + arrayEach(['initial', 'tail'], function(methodName, index) { var dropName = 'drop' + (index ? '' : 'Right'); LazyWrapper.prototype[methodName] = function() { @@ -13094,7 +13098,7 @@ }; LazyWrapper.prototype.find = function(predicate) { - return this.filter(predicate).first(); + return this.filter(predicate).head(); }; LazyWrapper.prototype.findLast = function(predicate) { @@ -13138,7 +13142,7 @@ // Add `LazyWrapper` methods to `lodash.prototype`. baseForOwn(LazyWrapper.prototype, function(func, methodName) { var checkIteratee = /^(?:filter|find|map|reject)|While$/.test(methodName), - isTaker = /^(?:first|last)$/.test(methodName), + isTaker = /^(?:head|last)$/.test(methodName), retUnwrapped = isTaker || /^find/.test(methodName), lodashFunc = lodash[isTaker ? ('take' + (methodName == 'last' ? 'Right' : '')) : methodName]; diff --git a/test/backbone.html b/test/backbone.html index 2775d5bc6..6e5e775f3 100644 --- a/test/backbone.html +++ b/test/backbone.html @@ -32,7 +32,7 @@ return function(_) { lodash.defaultsDeep(_, { 'templateSettings': lodash.templateSettings }); - lodash.mixin(_ , { 'indexBy': lodash.keyBy }); + lodash.mixin(_ , { 'indexBy': lodash.keyBy, 'rest': lodash.tail }); lodash.mixin(_, lodash.pick(lodash, lodash.difference(lodash.functions(lodash), lodash.functions(_)))); }; }()); diff --git a/test/test.js b/test/test.js index d6d1ea59c..c2cc98abf 100644 --- a/test/test.js +++ b/test/test.js @@ -1927,14 +1927,14 @@ if (!isNpm) { var array = ['c', 'b', 'a']; - assert.ok(_.chain(array).first() instanceof _); - assert.ok(_(array).chain().first() instanceof _); + assert.ok(_.chain(array).head() instanceof _); + assert.ok(_(array).chain().head() instanceof _); assert.ok(_.chain(array).isArray() instanceof _); assert.ok(_(array).chain().isArray() instanceof _); - assert.ok(_.chain(array).sortBy().first() instanceof _); - assert.ok(_(array).chain().sortBy().first() instanceof _); + assert.ok(_.chain(array).sortBy().head() instanceof _); + assert.ok(_(array).chain().sortBy().head() instanceof _); } else { skipTest(assert, 6); @@ -2450,14 +2450,14 @@ assert.notStrictEqual(combined, _.identity); }); - QUnit.test('`_.' + methodName + '` should work with a curried function and `_.first`', function(assert) { + QUnit.test('`_.' + methodName + '` should work with a curried function and `_.head`', function(assert) { assert.expect(1); var curried = _.curry(_.identity); var combined = isFlow - ? func(_.first, curried) - : func(curried, _.first); + ? func(_.head, curried) + : func(curried, _.head); assert.strictEqual(combined([1]), 1); }); @@ -4949,91 +4949,6 @@ /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.first'); - - (function() { - var array = [1, 2, 3, 4]; - - QUnit.test('should return the first element', function(assert) { - assert.expect(1); - - assert.strictEqual(_.first(array), 1); - }); - - QUnit.test('should return `undefined` when querying empty arrays', function(assert) { - assert.expect(1); - - var array = []; - array['-1'] = 1; - - assert.strictEqual(_.first(array), undefined); - }); - - QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { - assert.expect(1); - - var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], - actual = _.map(array, _.first); - - assert.deepEqual(actual, [1, 4, 7]); - }); - - QUnit.test('should return an unwrapped value when implicitly chaining', function(assert) { - assert.expect(1); - - if (!isNpm) { - assert.strictEqual(_(array).first(), 1); - } - else { - skipTest(assert); - } - }); - - QUnit.test('should return a wrapped value when explicitly chaining', function(assert) { - assert.expect(1); - - if (!isNpm) { - assert.ok(_(array).chain().first() instanceof _); - } - else { - skipTest(assert); - } - }); - - QUnit.test('should not execute immediately when explicitly chaining', function(assert) { - assert.expect(1); - - if (!isNpm) { - var wrapped = _(array).chain().first(); - assert.strictEqual(wrapped.__wrapped__, array); - } - else { - skipTest(assert); - } - }); - - QUnit.test('should work in a lazy chain sequence', function(assert) { - assert.expect(2); - - if (!isNpm) { - var largeArray = _.range(LARGE_ARRAY_SIZE), - smallArray = array; - - _.times(2, function(index) { - var array = index ? largeArray : smallArray, - wrapped = _(array).filter(isEven); - - assert.strictEqual(wrapped.first(), _.first(_.filter(array, isEven))); - }); - } - else { - skipTest(assert, 2); - } - }); - }()); - - /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.flip'); (function() { @@ -5051,418 +4966,6 @@ /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.take'); - - (function() { - var array = [1, 2, 3]; - - QUnit.test('should take the first two elements', function(assert) { - assert.expect(1); - - assert.deepEqual(_.take(array, 2), [1, 2]); - }); - - QUnit.test('should treat falsey `n` values, except `undefined`, as `0`', function(assert) { - assert.expect(1); - - var expected = _.map(falsey, function(value) { - return value === undefined ? [1] : []; - }); - - var actual = _.map(falsey, function(n) { - return _.take(array, n); - }); - - assert.deepEqual(actual, expected); - }); - - QUnit.test('should return an empty array when `n` < `1`', function(assert) { - assert.expect(3); - - _.each([0, -1, -Infinity], function(n) { - assert.deepEqual(_.take(array, n), []); - }); - }); - - QUnit.test('should return all elements when `n` >= `array.length`', function(assert) { - assert.expect(4); - - _.each([3, 4, Math.pow(2, 32), Infinity], function(n) { - assert.deepEqual(_.take(array, n), array); - }); - }); - - QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { - assert.expect(1); - - var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], - actual = _.map(array, _.take); - - assert.deepEqual(actual, [[1], [4], [7]]); - }); - - QUnit.test('should work in a lazy chain sequence', function(assert) { - assert.expect(6); - - if (!isNpm) { - var array = _.range(1, LARGE_ARRAY_SIZE + 1), - predicate = function(value) { values.push(value); return isEven(value); }, - values = [], - actual = _(array).take(2).take().value(); - - assert.deepEqual(actual, _.take(_.take(array, 2))); - - actual = _(array).filter(predicate).take(2).take().value(); - assert.deepEqual(values, [1, 2]); - assert.deepEqual(actual, _.take(_.take(_.filter(array, predicate), 2))); - - actual = _(array).take(6).takeRight(4).take(2).takeRight().value(); - assert.deepEqual(actual, _.takeRight(_.take(_.takeRight(_.take(array, 6), 4), 2))); - - values = []; - - actual = _(array).take(array.length - 1).filter(predicate).take(6).takeRight(4).take(2).takeRight().value(); - assert.deepEqual(values, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]); - assert.deepEqual(actual, _.takeRight(_.take(_.takeRight(_.take(_.filter(_.take(array, array.length - 1), predicate), 6), 4), 2))); - } - else { - skipTest(assert, 6); - } - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('lodash.takeRight'); - - (function() { - var array = [1, 2, 3]; - - QUnit.test('should take the last two elements', function(assert) { - assert.expect(1); - - assert.deepEqual(_.takeRight(array, 2), [2, 3]); - }); - - QUnit.test('should treat falsey `n` values, except `undefined`, as `0`', function(assert) { - assert.expect(1); - - var expected = _.map(falsey, function(value) { - return value === undefined ? [3] : []; - }); - - var actual = _.map(falsey, function(n) { - return _.takeRight(array, n); - }); - - assert.deepEqual(actual, expected); - }); - - QUnit.test('should return an empty array when `n` < `1`', function(assert) { - assert.expect(3); - - _.each([0, -1, -Infinity], function(n) { - assert.deepEqual(_.takeRight(array, n), []); - }); - }); - - QUnit.test('should return all elements when `n` >= `array.length`', function(assert) { - assert.expect(4); - - _.each([3, 4, Math.pow(2, 32), Infinity], function(n) { - assert.deepEqual(_.takeRight(array, n), array); - }); - }); - - QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { - assert.expect(1); - - var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], - actual = _.map(array, _.takeRight); - - assert.deepEqual(actual, [[3], [6], [9]]); - }); - - QUnit.test('should work in a lazy chain sequence', function(assert) { - assert.expect(6); - - if (!isNpm) { - var array = _.range(LARGE_ARRAY_SIZE), - predicate = function(value) { values.push(value); return isEven(value); }, - values = [], - actual = _(array).takeRight(2).takeRight().value(); - - assert.deepEqual(actual, _.takeRight(_.takeRight(array))); - - actual = _(array).filter(predicate).takeRight(2).takeRight().value(); - assert.deepEqual(values, array); - assert.deepEqual(actual, _.takeRight(_.takeRight(_.filter(array, predicate), 2))); - - actual = _(array).takeRight(6).take(4).takeRight(2).take().value(); - assert.deepEqual(actual, _.take(_.takeRight(_.take(_.takeRight(array, 6), 4), 2))); - - values = []; - - actual = _(array).filter(predicate).takeRight(6).take(4).takeRight(2).take().value(); - assert.deepEqual(values, array); - assert.deepEqual(actual, _.take(_.takeRight(_.take(_.takeRight(_.filter(array, predicate), 6), 4), 2))); - } - else { - skipTest(assert, 6); - } - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('lodash.takeRightWhile'); - - (function() { - var array = [1, 2, 3, 4]; - - var objects = [ - { 'a': 0, 'b': 0 }, - { 'a': 1, 'b': 1 }, - { 'a': 2, 'b': 2 } - ]; - - QUnit.test('should take elements while `predicate` returns truthy', function(assert) { - assert.expect(1); - - var actual = _.takeRightWhile(array, function(num) { - return num > 2; - }); - - assert.deepEqual(actual, [3, 4]); - }); - - QUnit.test('should provide the correct `predicate` arguments', function(assert) { - assert.expect(1); - - var args; - - _.takeRightWhile(array, function() { - args = slice.call(arguments); - }); - - assert.deepEqual(args, [4, 3, array]); - }); - - QUnit.test('should work with a "_.matches" style `predicate`', function(assert) { - assert.expect(1); - - assert.deepEqual(_.takeRightWhile(objects, { 'b': 2 }), objects.slice(2)); - }); - - QUnit.test('should work with a "_.matchesProperty" style `predicate`', function(assert) { - assert.expect(1); - - assert.deepEqual(_.takeRightWhile(objects, ['b', 2]), objects.slice(2)); - }); - - QUnit.test('should work with a "_.property" style `predicate`', function(assert) { - assert.expect(1); - - assert.deepEqual(_.takeRightWhile(objects, 'b'), objects.slice(1)); - }); - - QUnit.test('should work in a lazy chain sequence', function(assert) { - assert.expect(3); - - if (!isNpm) { - var array = _.range(LARGE_ARRAY_SIZE), - predicate = function(num) { return num > 2; }, - expected = _.takeRightWhile(array, predicate), - wrapped = _(array).takeRightWhile(predicate); - - assert.deepEqual(wrapped.value(), expected); - assert.deepEqual(wrapped.reverse().value(), expected.slice().reverse()); - assert.strictEqual(wrapped.last(), _.last(expected)); - } - else { - skipTest(assert, 3); - } - }); - - QUnit.test('should provide the correct `predicate` arguments in a lazy chain sequence', function(assert) { - assert.expect(5); - - if (!isNpm) { - var args, - array = _.range(LARGE_ARRAY_SIZE + 1), - expected = [square(LARGE_ARRAY_SIZE), LARGE_ARRAY_SIZE - 1, _.map(array.slice(1), square)]; - - _(array).slice(1).takeRightWhile(function(value, index, array) { - args = slice.call(arguments); - }).value(); - - assert.deepEqual(args, [LARGE_ARRAY_SIZE, LARGE_ARRAY_SIZE - 1, array.slice(1)]); - - _(array).slice(1).map(square).takeRightWhile(function(value, index, array) { - args = slice.call(arguments); - }).value(); - - assert.deepEqual(args, expected); - - _(array).slice(1).map(square).takeRightWhile(function(value, index) { - args = slice.call(arguments); - }).value(); - - assert.deepEqual(args, expected); - - _(array).slice(1).map(square).takeRightWhile(function(index) { - args = slice.call(arguments); - }).value(); - - assert.deepEqual(args, [square(LARGE_ARRAY_SIZE)]); - - _(array).slice(1).map(square).takeRightWhile(function() { - args = slice.call(arguments); - }).value(); - - assert.deepEqual(args, expected); - } - else { - skipTest(assert, 5); - } - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('lodash.takeWhile'); - - (function() { - var array = [1, 2, 3, 4]; - - var objects = [ - { 'a': 2, 'b': 2 }, - { 'a': 1, 'b': 1 }, - { 'a': 0, 'b': 0 } - ]; - - QUnit.test('should take elements while `predicate` returns truthy', function(assert) { - assert.expect(1); - - var actual = _.takeWhile(array, function(num) { - return num < 3; - }); - - assert.deepEqual(actual, [1, 2]); - }); - - QUnit.test('should provide the correct `predicate` arguments', function(assert) { - assert.expect(1); - - var args; - - _.takeWhile(array, function() { - args = slice.call(arguments); - }); - - assert.deepEqual(args, [1, 0, array]); - }); - - QUnit.test('should work with a "_.matches" style `predicate`', function(assert) { - assert.expect(1); - - assert.deepEqual(_.takeWhile(objects, { 'b': 2 }), objects.slice(0, 1)); - }); - - QUnit.test('should work with a "_.matchesProperty" style `predicate`', function(assert) { - assert.expect(1); - - assert.deepEqual(_.takeWhile(objects, ['b', 2]), objects.slice(0, 1)); - }); - QUnit.test('should work with a "_.property" style `predicate`', function(assert) { - assert.expect(1); - - assert.deepEqual(_.takeWhile(objects, 'b'), objects.slice(0, 2)); - }); - - QUnit.test('should work in a lazy chain sequence', function(assert) { - assert.expect(3); - - if (!isNpm) { - var array = _.range(LARGE_ARRAY_SIZE), - predicate = function(num) { return num < 3; }, - expected = _.takeWhile(array, predicate), - wrapped = _(array).takeWhile(predicate); - - assert.deepEqual(wrapped.value(), expected); - assert.deepEqual(wrapped.reverse().value(), expected.slice().reverse()); - assert.strictEqual(wrapped.last(), _.last(expected)); - } - else { - skipTest(assert, 3); - } - }); - - QUnit.test('should work in a lazy chain sequence with `take`', function(assert) { - assert.expect(1); - - if (!isNpm) { - var array = _.range(LARGE_ARRAY_SIZE); - - var actual = _(array) - .takeWhile(function(num) { return num < 4; }) - .take(2) - .takeWhile(function(num) { return num == 0; }) - .value(); - - assert.deepEqual(actual, [0]); - } - else { - skipTest(assert); - } - }); - - QUnit.test('should provide the correct `predicate` arguments in a lazy chain sequence', function(assert) { - assert.expect(5); - - if (!isNpm) { - var args, - array = _.range(LARGE_ARRAY_SIZE + 1), - expected = [1, 0, _.map(array.slice(1), square)]; - - _(array).slice(1).takeWhile(function(value, index, array) { - args = slice.call(arguments); - }).value(); - - assert.deepEqual(args, [1, 0, array.slice(1)]); - - _(array).slice(1).map(square).takeWhile(function(value, index, array) { - args = slice.call(arguments); - }).value(); - - assert.deepEqual(args, expected); - - _(array).slice(1).map(square).takeWhile(function(value, index) { - args = slice.call(arguments); - }).value(); - - assert.deepEqual(args, expected); - - _(array).slice(1).map(square).takeWhile(function(value) { - args = slice.call(arguments); - }).value(); - - assert.deepEqual(args, [1]); - - _(array).slice(1).map(square).takeWhile(function() { - args = slice.call(arguments); - }).value(); - - assert.deepEqual(args, expected); - } - else { - skipTest(assert, 5); - } - }); - }()); - - /*--------------------------------------------------------------------------*/ - QUnit.module('flatten methods'); (function() { @@ -6592,6 +6095,97 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.head'); + + (function() { + var array = [1, 2, 3, 4]; + + QUnit.test('should return the first element', function(assert) { + assert.expect(1); + + assert.strictEqual(_.head(array), 1); + }); + + QUnit.test('should return `undefined` when querying empty arrays', function(assert) { + assert.expect(1); + + var array = []; + array['-1'] = 1; + + assert.strictEqual(_.head(array), undefined); + }); + + QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { + assert.expect(1); + + var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], + actual = _.map(array, _.head); + + assert.deepEqual(actual, [1, 4, 7]); + }); + + QUnit.test('should return an unwrapped value when implicitly chaining', function(assert) { + assert.expect(1); + + if (!isNpm) { + assert.strictEqual(_(array).head(), 1); + } + else { + skipTest(assert); + } + }); + + QUnit.test('should return a wrapped value when explicitly chaining', function(assert) { + assert.expect(1); + + if (!isNpm) { + assert.ok(_(array).chain().head() instanceof _); + } + else { + skipTest(assert); + } + }); + + QUnit.test('should not execute immediately when explicitly chaining', function(assert) { + assert.expect(1); + + if (!isNpm) { + var wrapped = _(array).chain().head(); + assert.strictEqual(wrapped.__wrapped__, array); + } + else { + skipTest(assert); + } + }); + + QUnit.test('should work in a lazy chain sequence', function(assert) { + assert.expect(2); + + if (!isNpm) { + var largeArray = _.range(LARGE_ARRAY_SIZE), + smallArray = array; + + _.times(2, function(index) { + var array = index ? largeArray : smallArray, + wrapped = _(array).filter(isEven); + + assert.strictEqual(wrapped.head(), _.head(_.filter(array, isEven))); + }); + } + else { + skipTest(assert, 2); + } + }); + + QUnit.test('should be aliased', function(assert) { + assert.expect(1); + + assert.strictEqual(_.first, _.head); + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.identity'); (function() { @@ -15382,7 +14976,7 @@ var args, object = { 'a': 1, 'b': 2 }, - firstKey = _.first(_.keys(object)); + firstKey = _.head(_.keys(object)); var expected = firstKey == 'a' ? [0, 1, 'a', object] @@ -16034,105 +15628,6 @@ QUnit.module('lodash.rest'); - (function() { - var array = [1, 2, 3]; - - QUnit.test('should accept a falsey `array` argument', function(assert) { - assert.expect(1); - - var expected = _.map(falsey, _.constant([])); - - var actual = _.map(falsey, function(array, index) { - try { - return index ? _.rest(array) : _.rest(); - } catch (e) {} - }); - - assert.deepEqual(actual, expected); - }); - - QUnit.test('should exclude the first element', function(assert) { - assert.expect(1); - - assert.deepEqual(_.rest(array), [2, 3]); - }); - - QUnit.test('should return an empty when querying empty arrays', function(assert) { - assert.expect(1); - - assert.deepEqual(_.rest([]), []); - }); - - QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { - assert.expect(1); - - var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], - actual = _.map(array, _.rest); - - assert.deepEqual(actual, [[2, 3], [5, 6], [8, 9]]); - }); - - QUnit.test('should work in a lazy chain sequence', function(assert) { - assert.expect(4); - - if (!isNpm) { - var array = _.range(LARGE_ARRAY_SIZE), - values = []; - - var actual = _(array).rest().filter(function(value) { - values.push(value); - return false; - }) - .value(); - - assert.deepEqual(actual, []); - assert.deepEqual(values, array.slice(1)); - - values = []; - - actual = _(array).filter(function(value) { - values.push(value); - return isEven(value); - }) - .rest() - .value(); - - assert.deepEqual(actual, _.rest(_.filter(array, isEven))); - assert.deepEqual(values, array); - } - else { - skipTest(assert, 4); - } - }); - - QUnit.test('should not execute subsequent iteratees on an empty array in a lazy chain sequence', function(assert) { - assert.expect(4); - - if (!isNpm) { - var array = _.range(LARGE_ARRAY_SIZE), - iteratee = function() { pass = false; }, - pass = true, - actual = _(array).slice(0, 1).rest().map(iteratee).value(); - - assert.ok(pass); - assert.deepEqual(actual, []); - - pass = true; - actual = _(array).filter().slice(0, 1).rest().map(iteratee).value(); - - assert.ok(pass); - assert.deepEqual(actual, []); - } - else { - skipTest(assert, 4); - } - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('lodash.restParam'); - (function() { function fn(a, b, c) { return slice.call(arguments); @@ -16141,14 +15636,14 @@ QUnit.test('should apply a rest parameter to `func`', function(assert) { assert.expect(1); - var rp = _.restParam(fn); + var rp = _.rest(fn); assert.deepEqual(rp(1, 2, 3, 4), [1, 2, [3, 4]]); }); QUnit.test('should work with `start`', function(assert) { assert.expect(1); - var rp = _.restParam(fn, 1); + var rp = _.rest(fn, 1); assert.deepEqual(rp(1, 2, 3, 4), [1, [2, 3, 4]]); }); @@ -16159,7 +15654,7 @@ expected = _.map(values, _.constant([[1, 2, 3, 4]])); var actual = _.map(values, function(value) { - var rp = _.restParam(fn, value); + var rp = _.rest(fn, value); return rp(1, 2, 3, 4); }); @@ -16169,21 +15664,21 @@ QUnit.test('should coerce `start` to an integer', function(assert) { assert.expect(1); - var rp = _.restParam(fn, 1.6); + var rp = _.rest(fn, 1.6); assert.deepEqual(rp(1, 2, 3), [1, [2, 3]]); }); QUnit.test('should use an empty array when `start` is not reached', function(assert) { assert.expect(1); - var rp = _.restParam(fn); + var rp = _.rest(fn); assert.deepEqual(rp(1), [1, undefined, []]); }); QUnit.test('should work on functions with more than three params', function(assert) { assert.expect(1); - var rp = _.restParam(function(a, b, c, d) { + var rp = _.rest(function(a, b, c, d) { return slice.call(arguments); }); @@ -17618,6 +17113,517 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.tail'); + + (function() { + var array = [1, 2, 3]; + + QUnit.test('should accept a falsey `array` argument', function(assert) { + assert.expect(1); + + var expected = _.map(falsey, _.constant([])); + + var actual = _.map(falsey, function(array, index) { + try { + return index ? _.tail(array) : _.tail(); + } catch (e) {} + }); + + assert.deepEqual(actual, expected); + }); + + QUnit.test('should exclude the first element', function(assert) { + assert.expect(1); + + assert.deepEqual(_.tail(array), [2, 3]); + }); + + QUnit.test('should return an empty when querying empty arrays', function(assert) { + assert.expect(1); + + assert.deepEqual(_.tail([]), []); + }); + + QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { + assert.expect(1); + + var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], + actual = _.map(array, _.tail); + + assert.deepEqual(actual, [[2, 3], [5, 6], [8, 9]]); + }); + + QUnit.test('should work in a lazy chain sequence', function(assert) { + assert.expect(4); + + if (!isNpm) { + var array = _.range(LARGE_ARRAY_SIZE), + values = []; + + var actual = _(array).tail().filter(function(value) { + values.push(value); + return false; + }) + .value(); + + assert.deepEqual(actual, []); + assert.deepEqual(values, array.slice(1)); + + values = []; + + actual = _(array).filter(function(value) { + values.push(value); + return isEven(value); + }) + .tail() + .value(); + + assert.deepEqual(actual, _.tail(_.filter(array, isEven))); + assert.deepEqual(values, array); + } + else { + skipTest(assert, 4); + } + }); + + QUnit.test('should not execute subsequent iteratees on an empty array in a lazy chain sequence', function(assert) { + assert.expect(4); + + if (!isNpm) { + var array = _.range(LARGE_ARRAY_SIZE), + iteratee = function() { pass = false; }, + pass = true, + actual = _(array).slice(0, 1).tail().map(iteratee).value(); + + assert.ok(pass); + assert.deepEqual(actual, []); + + pass = true; + actual = _(array).filter().slice(0, 1).tail().map(iteratee).value(); + + assert.ok(pass); + assert.deepEqual(actual, []); + } + else { + skipTest(assert, 4); + } + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('lodash.take'); + + (function() { + var array = [1, 2, 3]; + + QUnit.test('should take the first two elements', function(assert) { + assert.expect(1); + + assert.deepEqual(_.take(array, 2), [1, 2]); + }); + + QUnit.test('should treat falsey `n` values, except `undefined`, as `0`', function(assert) { + assert.expect(1); + + var expected = _.map(falsey, function(value) { + return value === undefined ? [1] : []; + }); + + var actual = _.map(falsey, function(n) { + return _.take(array, n); + }); + + assert.deepEqual(actual, expected); + }); + + QUnit.test('should return an empty array when `n` < `1`', function(assert) { + assert.expect(3); + + _.each([0, -1, -Infinity], function(n) { + assert.deepEqual(_.take(array, n), []); + }); + }); + + QUnit.test('should return all elements when `n` >= `array.length`', function(assert) { + assert.expect(4); + + _.each([3, 4, Math.pow(2, 32), Infinity], function(n) { + assert.deepEqual(_.take(array, n), array); + }); + }); + + QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { + assert.expect(1); + + var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], + actual = _.map(array, _.take); + + assert.deepEqual(actual, [[1], [4], [7]]); + }); + + QUnit.test('should work in a lazy chain sequence', function(assert) { + assert.expect(6); + + if (!isNpm) { + var array = _.range(1, LARGE_ARRAY_SIZE + 1), + predicate = function(value) { values.push(value); return isEven(value); }, + values = [], + actual = _(array).take(2).take().value(); + + assert.deepEqual(actual, _.take(_.take(array, 2))); + + actual = _(array).filter(predicate).take(2).take().value(); + assert.deepEqual(values, [1, 2]); + assert.deepEqual(actual, _.take(_.take(_.filter(array, predicate), 2))); + + actual = _(array).take(6).takeRight(4).take(2).takeRight().value(); + assert.deepEqual(actual, _.takeRight(_.take(_.takeRight(_.take(array, 6), 4), 2))); + + values = []; + + actual = _(array).take(array.length - 1).filter(predicate).take(6).takeRight(4).take(2).takeRight().value(); + assert.deepEqual(values, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]); + assert.deepEqual(actual, _.takeRight(_.take(_.takeRight(_.take(_.filter(_.take(array, array.length - 1), predicate), 6), 4), 2))); + } + else { + skipTest(assert, 6); + } + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('lodash.takeRight'); + + (function() { + var array = [1, 2, 3]; + + QUnit.test('should take the last two elements', function(assert) { + assert.expect(1); + + assert.deepEqual(_.takeRight(array, 2), [2, 3]); + }); + + QUnit.test('should treat falsey `n` values, except `undefined`, as `0`', function(assert) { + assert.expect(1); + + var expected = _.map(falsey, function(value) { + return value === undefined ? [3] : []; + }); + + var actual = _.map(falsey, function(n) { + return _.takeRight(array, n); + }); + + assert.deepEqual(actual, expected); + }); + + QUnit.test('should return an empty array when `n` < `1`', function(assert) { + assert.expect(3); + + _.each([0, -1, -Infinity], function(n) { + assert.deepEqual(_.takeRight(array, n), []); + }); + }); + + QUnit.test('should return all elements when `n` >= `array.length`', function(assert) { + assert.expect(4); + + _.each([3, 4, Math.pow(2, 32), Infinity], function(n) { + assert.deepEqual(_.takeRight(array, n), array); + }); + }); + + QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { + assert.expect(1); + + var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], + actual = _.map(array, _.takeRight); + + assert.deepEqual(actual, [[3], [6], [9]]); + }); + + QUnit.test('should work in a lazy chain sequence', function(assert) { + assert.expect(6); + + if (!isNpm) { + var array = _.range(LARGE_ARRAY_SIZE), + predicate = function(value) { values.push(value); return isEven(value); }, + values = [], + actual = _(array).takeRight(2).takeRight().value(); + + assert.deepEqual(actual, _.takeRight(_.takeRight(array))); + + actual = _(array).filter(predicate).takeRight(2).takeRight().value(); + assert.deepEqual(values, array); + assert.deepEqual(actual, _.takeRight(_.takeRight(_.filter(array, predicate), 2))); + + actual = _(array).takeRight(6).take(4).takeRight(2).take().value(); + assert.deepEqual(actual, _.take(_.takeRight(_.take(_.takeRight(array, 6), 4), 2))); + + values = []; + + actual = _(array).filter(predicate).takeRight(6).take(4).takeRight(2).take().value(); + assert.deepEqual(values, array); + assert.deepEqual(actual, _.take(_.takeRight(_.take(_.takeRight(_.filter(array, predicate), 6), 4), 2))); + } + else { + skipTest(assert, 6); + } + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('lodash.takeRightWhile'); + + (function() { + var array = [1, 2, 3, 4]; + + var objects = [ + { 'a': 0, 'b': 0 }, + { 'a': 1, 'b': 1 }, + { 'a': 2, 'b': 2 } + ]; + + QUnit.test('should take elements while `predicate` returns truthy', function(assert) { + assert.expect(1); + + var actual = _.takeRightWhile(array, function(num) { + return num > 2; + }); + + assert.deepEqual(actual, [3, 4]); + }); + + QUnit.test('should provide the correct `predicate` arguments', function(assert) { + assert.expect(1); + + var args; + + _.takeRightWhile(array, function() { + args = slice.call(arguments); + }); + + assert.deepEqual(args, [4, 3, array]); + }); + + QUnit.test('should work with a "_.matches" style `predicate`', function(assert) { + assert.expect(1); + + assert.deepEqual(_.takeRightWhile(objects, { 'b': 2 }), objects.slice(2)); + }); + + QUnit.test('should work with a "_.matchesProperty" style `predicate`', function(assert) { + assert.expect(1); + + assert.deepEqual(_.takeRightWhile(objects, ['b', 2]), objects.slice(2)); + }); + + QUnit.test('should work with a "_.property" style `predicate`', function(assert) { + assert.expect(1); + + assert.deepEqual(_.takeRightWhile(objects, 'b'), objects.slice(1)); + }); + + QUnit.test('should work in a lazy chain sequence', function(assert) { + assert.expect(3); + + if (!isNpm) { + var array = _.range(LARGE_ARRAY_SIZE), + predicate = function(num) { return num > 2; }, + expected = _.takeRightWhile(array, predicate), + wrapped = _(array).takeRightWhile(predicate); + + assert.deepEqual(wrapped.value(), expected); + assert.deepEqual(wrapped.reverse().value(), expected.slice().reverse()); + assert.strictEqual(wrapped.last(), _.last(expected)); + } + else { + skipTest(assert, 3); + } + }); + + QUnit.test('should provide the correct `predicate` arguments in a lazy chain sequence', function(assert) { + assert.expect(5); + + if (!isNpm) { + var args, + array = _.range(LARGE_ARRAY_SIZE + 1), + expected = [square(LARGE_ARRAY_SIZE), LARGE_ARRAY_SIZE - 1, _.map(array.slice(1), square)]; + + _(array).slice(1).takeRightWhile(function(value, index, array) { + args = slice.call(arguments); + }).value(); + + assert.deepEqual(args, [LARGE_ARRAY_SIZE, LARGE_ARRAY_SIZE - 1, array.slice(1)]); + + _(array).slice(1).map(square).takeRightWhile(function(value, index, array) { + args = slice.call(arguments); + }).value(); + + assert.deepEqual(args, expected); + + _(array).slice(1).map(square).takeRightWhile(function(value, index) { + args = slice.call(arguments); + }).value(); + + assert.deepEqual(args, expected); + + _(array).slice(1).map(square).takeRightWhile(function(index) { + args = slice.call(arguments); + }).value(); + + assert.deepEqual(args, [square(LARGE_ARRAY_SIZE)]); + + _(array).slice(1).map(square).takeRightWhile(function() { + args = slice.call(arguments); + }).value(); + + assert.deepEqual(args, expected); + } + else { + skipTest(assert, 5); + } + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('lodash.takeWhile'); + + (function() { + var array = [1, 2, 3, 4]; + + var objects = [ + { 'a': 2, 'b': 2 }, + { 'a': 1, 'b': 1 }, + { 'a': 0, 'b': 0 } + ]; + + QUnit.test('should take elements while `predicate` returns truthy', function(assert) { + assert.expect(1); + + var actual = _.takeWhile(array, function(num) { + return num < 3; + }); + + assert.deepEqual(actual, [1, 2]); + }); + + QUnit.test('should provide the correct `predicate` arguments', function(assert) { + assert.expect(1); + + var args; + + _.takeWhile(array, function() { + args = slice.call(arguments); + }); + + assert.deepEqual(args, [1, 0, array]); + }); + + QUnit.test('should work with a "_.matches" style `predicate`', function(assert) { + assert.expect(1); + + assert.deepEqual(_.takeWhile(objects, { 'b': 2 }), objects.slice(0, 1)); + }); + + QUnit.test('should work with a "_.matchesProperty" style `predicate`', function(assert) { + assert.expect(1); + + assert.deepEqual(_.takeWhile(objects, ['b', 2]), objects.slice(0, 1)); + }); + QUnit.test('should work with a "_.property" style `predicate`', function(assert) { + assert.expect(1); + + assert.deepEqual(_.takeWhile(objects, 'b'), objects.slice(0, 2)); + }); + + QUnit.test('should work in a lazy chain sequence', function(assert) { + assert.expect(3); + + if (!isNpm) { + var array = _.range(LARGE_ARRAY_SIZE), + predicate = function(num) { return num < 3; }, + expected = _.takeWhile(array, predicate), + wrapped = _(array).takeWhile(predicate); + + assert.deepEqual(wrapped.value(), expected); + assert.deepEqual(wrapped.reverse().value(), expected.slice().reverse()); + assert.strictEqual(wrapped.last(), _.last(expected)); + } + else { + skipTest(assert, 3); + } + }); + + QUnit.test('should work in a lazy chain sequence with `take`', function(assert) { + assert.expect(1); + + if (!isNpm) { + var array = _.range(LARGE_ARRAY_SIZE); + + var actual = _(array) + .takeWhile(function(num) { return num < 4; }) + .take(2) + .takeWhile(function(num) { return num == 0; }) + .value(); + + assert.deepEqual(actual, [0]); + } + else { + skipTest(assert); + } + }); + + QUnit.test('should provide the correct `predicate` arguments in a lazy chain sequence', function(assert) { + assert.expect(5); + + if (!isNpm) { + var args, + array = _.range(LARGE_ARRAY_SIZE + 1), + expected = [1, 0, _.map(array.slice(1), square)]; + + _(array).slice(1).takeWhile(function(value, index, array) { + args = slice.call(arguments); + }).value(); + + assert.deepEqual(args, [1, 0, array.slice(1)]); + + _(array).slice(1).map(square).takeWhile(function(value, index, array) { + args = slice.call(arguments); + }).value(); + + assert.deepEqual(args, expected); + + _(array).slice(1).map(square).takeWhile(function(value, index) { + args = slice.call(arguments); + }).value(); + + assert.deepEqual(args, expected); + + _(array).slice(1).map(square).takeWhile(function(value) { + args = slice.call(arguments); + }).value(); + + assert.deepEqual(args, [1]); + + _(array).slice(1).map(square).takeWhile(function() { + args = slice.call(arguments); + }).value(); + + assert.deepEqual(args, expected); + } + else { + skipTest(assert, 5); + } + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.tap'); (function() { @@ -20170,14 +20176,14 @@ } }); - QUnit.test('`_.' + methodName + '` should work when in a lazy chain sequence before `first` or `last`', function(assert) { + QUnit.test('`_.' + methodName + '` should work when in a lazy chain sequence before `head` or `last`', function(assert) { assert.expect(1); if (!isNpm) { var array = _.range(LARGE_ARRAY_SIZE + 1), wrapped = _(array).slice(1)[methodName]([LARGE_ARRAY_SIZE, LARGE_ARRAY_SIZE + 1]); - var actual = _.map(['first', 'last'], function(methodName) { + var actual = _.map(['head', 'last'], function(methodName) { return wrapped[methodName](); }); @@ -20449,7 +20455,7 @@ assert.expect(2); if (!isNpm) { - var wrapped = _([1]).chain().commit().first(); + var wrapped = _([1]).chain().commit().head(); assert.ok(wrapped instanceof _); assert.strictEqual(wrapped.value(), 1); } @@ -20677,7 +20683,7 @@ wrapped1 = _(array1).chain().map(square), wrapped2 = wrapped1.plant(array2); - assert.deepEqual(wrapped2.first().value(), 36); + assert.deepEqual(wrapped2.head().value(), 36); } else { skipTest(assert); @@ -20888,10 +20894,10 @@ _.times(2, function(index) { var array = (index ? largeArray : smallArray).slice(), expected = array.slice().reverse(), - wrapped = _(array).chain().reverse().first(); + wrapped = _(array).chain().reverse().head(); assert.ok(wrapped instanceof _); - assert.strictEqual(wrapped.value(), _.first(expected)); + assert.strictEqual(wrapped.value(), _.head(expected)); assert.deepEqual(array, expected); }); } @@ -21233,10 +21239,10 @@ 'escapeRegExp', 'every', 'find', - 'first', 'floor', 'has', 'hasIn', + 'head', 'includes', 'isArguments', 'isArray', @@ -21360,18 +21366,18 @@ assert.deepEqual(_.dropWhile(args,_.identity), [ null, [3], null, 5], message('dropWhile')); assert.deepEqual(_.findIndex(args, _.identity), 0, message('findIndex')); assert.deepEqual(_.findLastIndex(args, _.identity), 4, message('findLastIndex')); - assert.deepEqual(_.first(args), 1, message('first')); assert.deepEqual(_.flatten(args), [1, null, 3, null, 5], message('flatten')); + assert.deepEqual(_.head(args), 1, message('head')); assert.deepEqual(_.indexOf(args, 5), 4, message('indexOf')); assert.deepEqual(_.initial(args), [1, null, [3], null], message('initial')); assert.deepEqual(_.intersection(args, [1]), [1], message('intersection')); assert.deepEqual(_.last(args), 5, message('last')); assert.deepEqual(_.lastIndexOf(args, 1), 0, message('lastIndexOf')); - assert.deepEqual(_.rest(args, 4), [null, [3], null, 5], message('rest')); assert.deepEqual(_.sortedIndex(sortedArgs, 6), 3, message('sortedIndex')); assert.deepEqual(_.sortedIndexOf(sortedArgs, 5), 2, message('sortedIndexOf')); assert.deepEqual(_.sortedLastIndex(sortedArgs, 5), 3, message('sortedLastIndex')); assert.deepEqual(_.sortedLastIndexOf(sortedArgs, 1), 0, message('sortedLastIndexOf')); + assert.deepEqual(_.tail(args, 4), [null, [3], null, 5], message('tail')); assert.deepEqual(_.take(args, 2), [1, null], message('take')); assert.deepEqual(_.takeRight(args, 1), [5], message('takeRight')); assert.deepEqual(_.takeRightWhile(args, _.identity), [5], message('takeRightWhile')); @@ -21470,7 +21476,7 @@ 'partial', 'partialRight', 'rearg', - 'restParam', + 'rest', 'spread', 'throttle' ]; @@ -21485,7 +21491,7 @@ 'partial', 'partialRight', 'rearg', - 'restParam', + 'rest', 'spread' ]; @@ -21517,11 +21523,11 @@ 'range', 'reject', 'remove', - 'rest', 'sampleSize', 'shuffle', 'sortBy', 'sortByOrder', + 'tail', 'take', 'times', 'toArray', @@ -21536,7 +21542,7 @@ var acceptFalsey = _.difference(allMethods, rejectFalsey); QUnit.test('should accept falsey arguments', function(assert) { - assert.expect(256); + assert.expect(257); var emptyArrays = _.map(falsey, _.constant([])); diff --git a/test/underscore.html b/test/underscore.html index 91e0383d0..e2e43d291 100644 --- a/test/underscore.html +++ b/test/underscore.html @@ -342,16 +342,27 @@ 'methods': 'functions', 'object': 'zipObject', 'pluck': 'map', - 'restArgs': 'restParam', + 'restParam': 'restArgs', 'select': 'filter', 'where': 'filter' }; + var keyMap = { + 'rest': 'tail', + 'restArgs': 'rest' + }; + var lodash = _.noConflict(); return function(_) { lodash.defaultsDeep(_, { 'templateSettings': lodash.templateSettings }); lodash.mixin(_, lodash.pick(lodash, lodash.difference(lodash.functions(lodash), lodash.functions(_)))); + + lodash.forOwn(keyMap, function(realName, otherName) { + _[otherName] = lodash[realName]; + _.prototype[otherName] = lodash.prototype[realName]; + }); + lodash.forOwn(aliasToReal, function(realName, alias) { _[alias] = _[realName]; _.prototype[alias] = _.prototype[realName];