From 7862ae6d3625436ced505b3db507743e46c30432 Mon Sep 17 00:00:00 2001 From: jdalton Date: Wed, 1 Jul 2015 00:50:17 -0700 Subject: [PATCH 001/935] Adjust UMD to export to `window` or `self` when available regardless of other exports. --- lodash.src.js | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 1855c28906..37c52b2061 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -253,22 +253,25 @@ }; /** Detect free variable `exports`. */ - var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports; + var freeExports = (objectTypes[typeof exports] && exports && !exports.nodeType) ? exports : null; /** Detect free variable `module`. */ - var freeModule = objectTypes[typeof module] && module && !module.nodeType && module; + var freeModule = (objectTypes[typeof module] && module && !module.nodeType) ? module : null; /** Detect free variable `global` from Node.js. */ - var freeGlobal = freeExports && freeModule && typeof global == 'object' && global && global.Object && global; + var freeGlobal = checkGlobal(freeExports && freeModule && typeof global == 'object' && global); /** Detect free variable `self`. */ - var freeSelf = objectTypes[typeof self] && self && self.Object && self; + var freeSelf = checkGlobal(objectTypes[typeof self] && self); /** Detect free variable `window`. */ - var freeWindow = objectTypes[typeof window] && window && window.Object && window; + var freeWindow = checkGlobal(objectTypes[typeof window] && window); /** Detect the popular CommonJS extension `module.exports`. */ - var moduleExports = freeModule && freeModule.exports === freeExports && freeExports; + var moduleExports = (freeModule && freeModule.exports === freeExports) ? freeExports : null; + + /** Detect `this` as the global object. */ + var thisGlobal = checkGlobal(objectTypes[typeof this] && this); /** * Used as a reference to the global object. @@ -276,7 +279,7 @@ * The `this` value is used if it's the global object to avoid Greasemonkey's * restricted `window` object, otherwise the `window` object is used. */ - var root = freeGlobal || ((freeWindow !== (this && this.window)) && freeWindow) || freeSelf || this; + var root = freeGlobal || ((freeWindow !== (thisGlobal && thisGlobal.window)) && freeWindow) || freeSelf || thisGlobal; /*--------------------------------------------------------------------------*/ @@ -418,6 +421,17 @@ return index; } + /** + * Checks if `value` is a global object. + * + * @private + * @param {*} value The value to check. + * @returns {null|Object} Returns `value` if it's a global object, else `null`. + */ + function checkGlobal(value) { + return (objectTypes[typeof value] && value && value.Object) ? value : null; + } + /** * Used by `_.sortBy` to compare transformed elements of a collection and stable * sort them in ascending order. @@ -12524,14 +12538,13 @@ // Export lodash. var _ = runInContext(); + // Expose lodash on the free variable `window` or `self` when available. This + // prevents errors in cases where lodash is loaded by a script tag in the presence + // of an AMD loader. See http://requirejs.org/docs/errors.html#mismatch for more details. + (freeWindow || freeSelf || {})._ = _; + // Some AMD build optimizers like r.js check for condition patterns like the following: if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) { - // Expose lodash to the global object when an AMD loader is present to avoid - // errors in cases where lodash is loaded by a script tag and not intended - // as an AMD module. See http://requirejs.org/docs/errors.html#mismatch for - // more details. - root._ = _; - // Define as an anonymous module so, through path mapping, it can be // referenced as the "underscore" module. define(function() { From bd98779b3c0ae5c48f5949c50173df6bb12f654c Mon Sep 17 00:00:00 2001 From: jdalton Date: Wed, 1 Jul 2015 21:17:28 -0700 Subject: [PATCH 002/935] Fix test fails related to `root._`. --- test/test.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/test.js b/test/test.js index 4230d55171..defbdb2131 100644 --- a/test/test.js +++ b/test/test.js @@ -236,6 +236,9 @@ (_.runInContext ? _.runInContext(root) : _) )); + /** Used to restore the `_` reference. */ + var oldDash = root._; + /** List of latin-1 supplementary letters to basic latin letters. */ var burredLetters = [ '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7', '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', @@ -457,6 +460,7 @@ // Load lodash and expose it to the bad extensions/shims. lodashBizarro = (lodashBizarro = require(filePath))._ || lodashBizarro['default'] || lodashBizarro; + root._ = oldDash; // Restore built-in methods. setProperty(Array, 'isArray', _isArray); @@ -11545,7 +11549,6 @@ (function() { test('should return the `lodash` function', 2, function() { if (!isModularize) { - var oldDash = root._; strictEqual(_.noConflict(), oldDash); if (!(isRhino && typeof require == 'function')) { @@ -18141,8 +18144,7 @@ var acceptFalsey = _.difference(allMethods, rejectFalsey); test('should accept falsey arguments', 229, function() { - var emptyArrays = _.map(falsey, _.constant([])), - oldDash = root._; + var emptyArrays = _.map(falsey, _.constant([])); _.each(acceptFalsey, function(methodName) { var expected = emptyArrays, From 1bfe25f1a5e1441995922d24d7b290fd6243c8dd Mon Sep 17 00:00:00 2001 From: jdalton Date: Mon, 6 Jul 2015 10:05:56 -0700 Subject: [PATCH 003/935] Remove aliases and rename `_.callback` to `_.iteratee`. --- lodash.src.js | 259 ++- test/test.js | 4830 ++++++++++++++++++++++++------------------------- 2 files changed, 2494 insertions(+), 2595 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 37c52b2061..3662e75c80 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -1786,34 +1786,6 @@ return object; } - /** - * The base implementation of `_.callback` which supports specifying the - * number of arguments to provide to `func`. - * - * @private - * @param {*} [func=_.identity] The value to convert to a callback. - * @param {*} [thisArg] The `this` binding of `func`. - * @param {number} [argCount] The number of arguments to provide to `func`. - * @returns {Function} Returns the callback. - */ - function baseCallback(func, thisArg, argCount) { - var type = typeof func; - if (type == 'function') { - return thisArg === undefined - ? func - : bindCallback(func, thisArg, argCount); - } - if (func == null) { - return identity; - } - if (type == 'object') { - return baseMatches(func); - } - return thisArg === undefined - ? property(func) - : baseMatchesProperty(func, thisArg); - } - /** * The base implementation of `_.clone` without support for argument juggling * and `this` binding `customizer` functions. @@ -2142,6 +2114,34 @@ return result; } + /** + * The base implementation of `_.iteratee` which supports specifying the + * number of arguments to provide to `func`. + * + * @private + * @param {*} [func=_.identity] The value to convert to an iteratee. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {number} [argCount] The number of arguments to provide to `func`. + * @returns {Function} Returns the iteratee. + */ + function baseIteratee(func, thisArg, argCount) { + var type = typeof func; + if (type == 'function') { + return thisArg === undefined + ? func + : bindCallback(func, thisArg, argCount); + } + if (func == null) { + return identity; + } + if (type == 'object') { + return baseMatches(func); + } + return thisArg === undefined + ? property(func) + : baseMatchesProperty(func, thisArg); + } + /** * The base implementation of `baseForIn` and `baseForOwn` which iterates * over `object` properties returned by `keysFunc` invoking `iteratee` for @@ -2769,7 +2769,7 @@ * @returns {Array} Returns the new sorted array. */ function baseSortByOrder(collection, iteratees, orders) { - var callback = getCallback(), + var callback = getIteratee(), index = -1; iteratees = arrayMap(iteratees, function(iteratee) { return callback(iteratee); }); @@ -3000,7 +3000,7 @@ } /** - * A specialized version of `baseCallback` which only supports `this` binding + * A specialized version of `baseIteratee` which only supports `this` binding * and specifying the number of arguments to provide to `func`. * * @private @@ -3123,7 +3123,7 @@ function createAggregator(setter, initializer) { return function(collection, iteratee, thisArg) { var result = initializer ? initializer() : {}; - iteratee = getCallback(iteratee, thisArg, 3); + iteratee = getIteratee(iteratee, thisArg, 3); if (isArray(collection)) { var index = -1, @@ -3364,7 +3364,7 @@ if (thisArg && isIterateeCall(collection, iteratee, thisArg)) { iteratee = undefined; } - iteratee = getCallback(iteratee, thisArg, 3); + iteratee = getIteratee(iteratee, thisArg, 3); if (iteratee.length == 1) { collection = isArray(collection) ? collection : toIterable(collection); var result = arrayExtremum(collection, iteratee, comparator, exValue); @@ -3386,7 +3386,7 @@ */ function createFind(eachFunc, fromRight) { return function(collection, predicate, thisArg) { - predicate = getCallback(predicate, thisArg, 3); + predicate = getIteratee(predicate, thisArg, 3); if (isArray(collection)) { var index = baseFindIndex(collection, predicate, fromRight); return index > -1 ? collection[index] : undefined; @@ -3407,7 +3407,7 @@ if (!(array && array.length)) { return -1; } - predicate = getCallback(predicate, thisArg, 3); + predicate = getIteratee(predicate, thisArg, 3); return baseFindIndex(array, predicate, fromRight); }; } @@ -3421,7 +3421,7 @@ */ function createFindKey(objectFunc) { return function(object, predicate, thisArg) { - predicate = getCallback(predicate, thisArg, 3); + predicate = getIteratee(predicate, thisArg, 3); return baseFind(object, predicate, objectFunc, true); }; } @@ -3539,7 +3539,7 @@ function createObjectMapper(isMapKeys) { return function(object, iteratee, thisArg) { var result = {}; - iteratee = getCallback(iteratee, thisArg, 3); + iteratee = getIteratee(iteratee, thisArg, 3); baseForOwn(object, function(value, key, object) { var mapped = iteratee(value, key, object); @@ -3593,7 +3593,7 @@ var initFromArray = arguments.length < 3; return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection)) ? arrayFunc(collection, iteratee, accumulator, initFromArray) - : baseReduce(collection, getCallback(iteratee, thisArg, 4), accumulator, initFromArray, eachFunc); + : baseReduce(collection, getIteratee(iteratee, thisArg, 4), accumulator, initFromArray, eachFunc); }; } @@ -3772,8 +3772,8 @@ */ function createSortedIndex(retHighest) { return function(array, value, iteratee, thisArg) { - var callback = getCallback(iteratee); - return (iteratee == null && callback === baseCallback) + var callback = getIteratee(iteratee); + return (iteratee == null && callback === baseIteratee) ? binaryIndex(array, value, retHighest) : binaryIndexBy(array, value, callback(iteratee, thisArg, 1), retHighest); }; @@ -3989,21 +3989,6 @@ return true; } - /** - * Gets the appropriate "callback" function. If the `_.callback` method is - * customized this function returns the custom method, otherwise it returns - * the `baseCallback` function. If arguments are provided the chosen function - * is invoked with them and its result is returned. - * - * @private - * @returns {Function} Returns the chosen function or its result. - */ - function getCallback(func, thisArg, argCount) { - var result = lodash.callback || callback; - result = result === callback ? baseCallback : result; - return argCount ? result(func, thisArg, argCount) : result; - } - /** * Gets metadata for `func`. * @@ -4052,6 +4037,21 @@ return collection ? result(collection, target, fromIndex) : result; } + /** + * Gets the appropriate "iteratee" function. If the `_.iteratee` method is + * customized this function returns the custom method, otherwise it returns + * the `baseIteratee` function. If arguments are provided the chosen function + * is invoked with them and its result is returned. + * + * @private + * @returns {Function} Returns the chosen function or its result. + */ + function getIteratee(func, thisArg, argCount) { + var result = lodash.iteratee || iteratee; + result = result === iteratee ? baseIteratee : result; + return argCount ? result(func, thisArg, argCount) : result; + } + /** * Gets the "length" property value of `object`. * @@ -4825,7 +4825,7 @@ */ function dropRightWhile(array, predicate, thisArg) { return (array && array.length) - ? baseWhile(array, getCallback(predicate, thisArg, 3), true, true) + ? baseWhile(array, getIteratee(predicate, thisArg, 3), true, true) : []; } @@ -4880,7 +4880,7 @@ */ function dropWhile(array, predicate, thisArg) { return (array && array.length) - ? baseWhile(array, getCallback(predicate, thisArg, 3), true) + ? baseWhile(array, getIteratee(predicate, thisArg, 3), true) : []; } @@ -5399,7 +5399,7 @@ indexes = [], length = array.length; - predicate = getCallback(predicate, thisArg, 3); + predicate = getIteratee(predicate, thisArg, 3); while (++index < length) { var value = array[index]; if (predicate(value, index, array)) { @@ -5649,7 +5649,7 @@ */ function takeRightWhile(array, predicate, thisArg) { return (array && array.length) - ? baseWhile(array, getCallback(predicate, thisArg, 3), false, true) + ? baseWhile(array, getIteratee(predicate, thisArg, 3), false, true) : []; } @@ -5704,7 +5704,7 @@ */ function takeWhile(array, predicate, thisArg) { return (array && array.length) - ? baseWhile(array, getCallback(predicate, thisArg, 3)) + ? baseWhile(array, getIteratee(predicate, thisArg, 3)) : []; } @@ -5786,8 +5786,8 @@ iteratee = isIterateeCall(array, isSorted, thisArg) ? undefined : isSorted; isSorted = false; } - var callback = getCallback(); - if (!(iteratee == null && callback === baseCallback)) { + var callback = getIteratee(); + if (!(iteratee == null && callback === baseIteratee)) { iteratee = callback(iteratee, thisArg, 3); } return (isSorted && getIndexOf() === baseIndexOf) @@ -6420,7 +6420,7 @@ predicate = undefined; } if (typeof predicate != 'function' || thisArg !== undefined) { - predicate = getCallback(predicate, thisArg, 3); + predicate = getIteratee(predicate, thisArg, 3); } return func(collection, predicate); } @@ -6476,7 +6476,7 @@ */ function filter(collection, predicate, thisArg) { var func = isArray(collection) ? arrayFilter : baseFilter; - predicate = getCallback(predicate, thisArg, 3); + predicate = getIteratee(predicate, thisArg, 3); return func(collection, predicate); } @@ -6877,7 +6877,7 @@ */ function map(collection, iteratee, thisArg) { var func = isArray(collection) ? arrayMap : baseMap; - iteratee = getCallback(iteratee, thisArg, 3); + iteratee = getIteratee(iteratee, thisArg, 3); return func(collection, iteratee); } @@ -7072,7 +7072,7 @@ */ function reject(collection, predicate, thisArg) { var func = isArray(collection) ? arrayFilter : baseFilter; - predicate = getCallback(predicate, thisArg, 3); + predicate = getIteratee(predicate, thisArg, 3); return func(collection, function(value, index, collection) { return !predicate(value, index, collection); }); @@ -7217,7 +7217,7 @@ predicate = undefined; } if (typeof predicate != 'function' || thisArg !== undefined) { - predicate = getCallback(predicate, thisArg, 3); + predicate = getIteratee(predicate, thisArg, 3); } return func(collection, predicate); } @@ -7278,7 +7278,7 @@ iteratee = undefined; } var index = -1; - iteratee = getCallback(iteratee, thisArg, 3); + iteratee = getIteratee(iteratee, thisArg, 3); var result = baseMap(collection, function(value, key, collection) { return { 'criteria': iteratee(value, key, collection), 'index': ++index, 'value': value }; @@ -10223,7 +10223,7 @@ */ function transform(object, iteratee, accumulator, thisArg) { var isArr = isArray(object) || isTypedArray(object); - iteratee = getCallback(iteratee, thisArg, 4); + iteratee = getIteratee(iteratee, thisArg, 4); if (accumulator == null) { if (isArr || isObject(object)) { @@ -11293,6 +11293,47 @@ } }); + /** + * Creates a function that returns `value`. + * + * @static + * @memberOf _ + * @category Utility + * @param {*} value The value to return from the new function. + * @returns {Function} Returns the new function. + * @example + * + * var object = { 'user': 'fred' }; + * var getter = _.constant(object); + * + * getter() === object; + * // => true + */ + function constant(value) { + return function() { + return value; + }; + } + + /** + * This method returns the first argument provided to it. + * + * @static + * @memberOf _ + * @category Utility + * @param {*} value Any value. + * @returns {*} Returns `value`. + * @example + * + * var object = { 'user': 'fred' }; + * + * _.identity(object) === object; + * // => true + */ + function identity(value) { + return value; + } + /** * Creates a function that invokes `func` with the `this` binding of `thisArg` * and arguments of the created function. If `func` is a property name the @@ -11316,7 +11357,7 @@ * ]; * * // wrap to create custom callback shorthands - * _.callback = _.wrap(_.callback, function(callback, func, thisArg) { + * _.iteratee = _.wrap(_.iteratee, function(callback, func, thisArg) { * var match = /^(.+?)__([gl]t)(.+)$/.exec(func); * if (!match) { * return callback(func, thisArg); @@ -11331,54 +11372,13 @@ * _.filter(users, 'age__gt36'); * // => [{ 'user': 'fred', 'age': 40 }] */ - function callback(func, thisArg, guard) { + function iteratee(func, thisArg, guard) { if (guard && isIterateeCall(func, thisArg, guard)) { thisArg = undefined; } return isObjectLike(func) ? matches(func) - : baseCallback(func, thisArg); - } - - /** - * Creates a function that returns `value`. - * - * @static - * @memberOf _ - * @category Utility - * @param {*} value The value to return from the new function. - * @returns {Function} Returns the new function. - * @example - * - * var object = { 'user': 'fred' }; - * var getter = _.constant(object); - * - * getter() === object; - * // => true - */ - function constant(value) { - return function() { - return value; - }; - } - - /** - * This method returns the first argument provided to it. - * - * @static - * @memberOf _ - * @category Utility - * @param {*} value Any value. - * @returns {*} Returns `value`. - * @example - * - * var object = { 'user': 'fred' }; - * - * _.identity(object) === object; - * // => true - */ - function identity(value) { - return value; + : baseIteratee(func, thisArg); } /** @@ -12018,7 +12018,7 @@ if (thisArg && isIterateeCall(collection, iteratee, thisArg)) { iteratee = undefined; } - iteratee = getCallback(iteratee, thisArg, 3); + iteratee = getIteratee(iteratee, thisArg, 3); return iteratee.length == 1 ? arraySum(isArray(collection) ? collection : toIterable(collection), iteratee) : baseSum(collection, iteratee); @@ -12056,7 +12056,6 @@ lodash.bind = bind; lodash.bindAll = bindAll; lodash.bindKey = bindKey; - lodash.callback = callback; lodash.chain = chain; lodash.chunk = chunk; lodash.compact = compact; @@ -12094,6 +12093,7 @@ lodash.intersection = intersection; lodash.invert = invert; lodash.invoke = invoke; + lodash.iteratee = iteratee; lodash.keys = keys; lodash.keysIn = keysIn; lodash.map = map; @@ -12159,18 +12159,8 @@ lodash.zipWith = zipWith; // Add aliases. - lodash.backflow = flowRight; - lodash.collect = map; - lodash.compose = flowRight; lodash.each = forEach; lodash.eachRight = forEachRight; - lodash.extend = assign; - lodash.iteratee = callback; - lodash.methods = functions; - lodash.object = zipObject; - lodash.select = filter; - lodash.tail = rest; - lodash.unique = uniq; // Add functions to `lodash.prototype`. mixin(lodash, lodash); @@ -12266,17 +12256,8 @@ lodash.uniqueId = uniqueId; lodash.words = words; - // Add aliases. - lodash.all = every; - lodash.any = some; - lodash.contains = includes; + // Add aliases lodash.eq = isEqual; - lodash.detect = find; - lodash.foldl = reduce; - lodash.foldr = reduceRight; - lodash.head = first; - lodash.include = includes; - lodash.inject = reduce; mixin(lodash, (function() { var source = {}; @@ -12348,7 +12329,7 @@ LazyWrapper.prototype[methodName] = function(iteratee, thisArg) { var result = this.clone(); - result.__iteratees__.push({ 'iteratee': getCallback(iteratee, thisArg, 1), 'type': type }); + result.__iteratees__.push({ 'iteratee': getIteratee(iteratee, thisArg, 1), 'type': type }); result.__filtered__ = result.__filtered__ || isFilter; return result; }; @@ -12387,7 +12368,7 @@ }; LazyWrapper.prototype.reject = function(predicate, thisArg) { - predicate = getCallback(predicate, thisArg, 1); + predicate = getIteratee(predicate, thisArg, 1); return this.filter(function(value) { return !predicate(value); }); @@ -12524,12 +12505,6 @@ lodash.prototype.toString = wrapperToString; lodash.prototype.run = lodash.prototype.toJSON = lodash.prototype.valueOf = lodash.prototype.value = wrapperValue; - // Add function aliases to the `lodash` wrapper. - lodash.prototype.collect = lodash.prototype.map; - lodash.prototype.head = lodash.prototype.first; - lodash.prototype.select = lodash.prototype.filter; - lodash.prototype.tail = lodash.prototype.rest; - return lodash; } diff --git a/test/test.js b/test/test.js index defbdb2131..2f10be14b9 100644 --- a/test/test.js +++ b/test/test.js @@ -1068,10 +1068,6 @@ var expected = { 'a': undefined }; deepEqual(_.assign({}, expected, _.identity), expected); }); - - test('should be aliased', 1, function() { - strictEqual(_.extend, _.assign); - }); }()); /*--------------------------------------------------------------------------*/ @@ -2212,17 +2208,6 @@ /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.flowRight'); - - (function() { - test('should be aliased', 2, function() { - strictEqual(_.backflow, _.flowRight); - strictEqual(_.compose, _.flowRight); - }); - }()); - - /*--------------------------------------------------------------------------*/ - QUnit.module('flow methods'); _.each(['flow', 'flowRight'], function(methodName) { @@ -2567,910 +2552,682 @@ /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.callback'); + QUnit.module('lodash.curry'); (function() { - test('should provide arguments to `func`', 3, function() { - var fn = function() { - var result = [this]; - push.apply(result, arguments); - return result; - }; + function fn(a, b, c, d) { + return slice.call(arguments); + } - var callback = _.callback(fn), - actual = callback('a', 'b', 'c', 'd', 'e', 'f'); + test('should curry based on the number of arguments provided', 3, function() { + var curried = _.curry(fn), + expected = [1, 2, 3, 4]; - ok(actual[0] === null || actual[0] && actual[0].Array); - deepEqual(actual.slice(1), ['a', 'b', 'c', 'd', 'e', 'f']); + deepEqual(curried(1)(2)(3)(4), expected); + deepEqual(curried(1, 2)(3, 4), expected); + deepEqual(curried(1, 2, 3, 4), expected); + }); - var object = {}; - callback = _.callback(fn, object); - actual = callback('a', 'b'); + test('should allow specifying `arity`', 3, function() { + var curried = _.curry(fn, 3), + expected = [1, 2, 3]; - deepEqual(actual, [object, 'a', 'b']); + deepEqual(curried(1)(2, 3), expected); + deepEqual(curried(1, 2)(3), expected); + deepEqual(curried(1, 2, 3), expected); }); - test('should return `_.identity` when `func` is nullish', 1, function() { - var object = {}, - values = [, null, undefined], - expected = _.map(values, _.constant([!isNpm && _.identity, object])); + test('should coerce `arity` to a number', 2, function() { + var values = ['0', 'xyz'], + expected = _.map(values, _.constant([])); - var actual = _.map(values, function(value, index) { - var identity = index ? _.callback(value) : _.callback(); - return [!isNpm && identity, identity(object)]; + var actual = _.map(values, function(arity) { + return _.curry(fn, arity)(); }); deepEqual(actual, expected); + deepEqual(_.curry(fn, '2')(1)(2), [1, 2]); }); - test('should not error when `func` is nullish and a `thisArg` is provided', 2, function() { - var object = {}; + test('should support placeholders', 4, function() { + var curried = _.curry(fn), + ph = curried.placeholder; - _.each([null, undefined], function(value) { - try { - var callback = _.callback(value, {}); - strictEqual(callback(object), object); - } catch(e) { - ok(false, e.message); - } - }); + deepEqual(curried(1)(ph, 3)(ph, 4)(2), [1, 2, 3, 4]); + deepEqual(curried(ph, 2)(1)(ph, 4)(3), [1, 2, 3, 4]); + deepEqual(curried(ph, ph, 3)(ph, 2)(ph, 4)(1), [1, 2, 3, 4]); + deepEqual(curried(ph, ph, ph, 4)(ph, ph, 3)(ph, 2)(1), [1, 2, 3, 4]); }); - test('should create a callback with a falsey `thisArg`', 1, function() { - var fn = function() { return this; }, - object = {}; - - var expected = _.map(falsey, function(value) { - var result = fn.call(value); - return (result && result.Array) ? object : result; - }); - - var actual = _.map(falsey, function(value) { - var callback = _.callback(fn, value), - result = callback(); + test('should work with partialed methods', 2, function() { + var curried = _.curry(fn), + expected = [1, 2, 3, 4]; - return (result && result.Array) ? object : result; - }); + var a = _.partial(curried, 1), + b = _.bind(a, null, 2), + c = _.partialRight(b, 4), + d = _.partialRight(b(3), 4); - ok(_.isEqual(actual, expected)); + deepEqual(c(3), expected); + deepEqual(d(), expected); }); - test('should return a callback created by `_.matches` when `func` is an object', 2, function() { - var matches = _.callback({ 'a': 1, 'b': 2 }); - strictEqual(matches({ 'a': 1, 'b': 2, 'c': 3 }), true); - strictEqual(matches({ 'b': 2 }), false); + test('should provide additional arguments after reaching the target arity', 3, function() { + var curried = _.curry(fn, 3); + deepEqual(curried(1)(2, 3, 4), [1, 2, 3, 4]); + deepEqual(curried(1, 2)(3, 4, 5), [1, 2, 3, 4, 5]); + deepEqual(curried(1, 2, 3, 4, 5, 6), [1, 2, 3, 4, 5, 6]); }); - test('should return a callback created by `_.matches` when `func` is an array', 2, function() { - var matches = _.callback(['a', 'b']); - strictEqual(matches({ '0': 'a', '1': 'b', '2': 'c' }), true); - strictEqual(matches({ '1': 'b' }), false); + test('should return a function with a `length` of `0`', 6, function() { + _.times(2, function(index) { + var curried = index ? _.curry(fn, 4) : _.curry(fn); + strictEqual(curried.length, 0); + strictEqual(curried(1).length, 0); + strictEqual(curried(1, 2).length, 0); + }); }); - test('should not change match behavior if `source` is augmented', 9, function() { - var sources = [ - { 'a': { 'b': 2, 'c': 3 } }, - { 'a': 1, 'b': 2 }, - { 'a': 1 } - ]; - - _.each(sources, function(source, index) { - var object = _.cloneDeep(source), - matches = _.callback(source); + test('should ensure `new curried` is an instance of `func`', 2, function() { + var Foo = function(value) { + return value && object; + }; - strictEqual(matches(object), true); + var curried = _.curry(Foo), + object = {}; - if (index) { - source.a = 2; - source.b = 1; - source.c = 3; - } else { - source.a.b = 1; - source.a.c = 2; - source.a.d = 3; - } - strictEqual(matches(object), true); - strictEqual(matches(source), false); - }); + ok(new curried(false) instanceof Foo); + strictEqual(new curried(true), object); }); - test('should return a callback created by `_.matchesProperty` when `func` is a number or string and `thisArg` is not `undefined`', 3, function() { - var array = ['a'], - matches = _.callback(0, 'a'); + test('should not set a `this` binding', 9, function() { + var fn = function(a, b, c) { + var value = this || {}; + return [value[a], value[b], value[c]]; + }; - strictEqual(matches(array), true); + var object = { 'a': 1, 'b': 2, 'c': 3 }, + expected = [1, 2, 3]; - matches = _.callback('0', 'a'); - strictEqual(matches(array), true); + deepEqual(_.curry(_.bind(fn, object), 3)('a')('b')('c'), expected); + deepEqual(_.curry(_.bind(fn, object), 3)('a', 'b')('c'), expected); + deepEqual(_.curry(_.bind(fn, object), 3)('a', 'b', 'c'), expected); - matches = _.callback(1, undefined); - strictEqual(matches(array), undefined); + deepEqual(_.bind(_.curry(fn), object)('a')('b')('c'), Array(3)); + deepEqual(_.bind(_.curry(fn), object)('a', 'b')('c'), Array(3)); + deepEqual(_.bind(_.curry(fn), object)('a', 'b', 'c'), expected); + + object.curried = _.curry(fn); + deepEqual(object.curried('a')('b')('c'), Array(3)); + deepEqual(object.curried('a', 'b')('c'), Array(3)); + deepEqual(object.curried('a', 'b', 'c'), expected); }); + }()); - test('should support deep paths for `_.matchesProperty` shorthands', 1, function() { - var object = { 'a': { 'b': { 'c': { 'd': 1, 'e': 2 } } } }, - matches = _.callback('a.b.c', { 'e': 2 }); + /*--------------------------------------------------------------------------*/ - strictEqual(matches(object), true); - }); + QUnit.module('lodash.curryRight'); - test('should return a callback created by `_.property` when `func` is a number or string', 2, function() { - var array = ['a'], - prop = _.callback(0); + (function() { + function fn(a, b, c, d) { + return slice.call(arguments); + } - strictEqual(prop(array), 'a'); + test('should curry based on the number of arguments provided', 3, function() { + var curried = _.curryRight(fn), + expected = [1, 2, 3, 4]; - prop = _.callback('0'); - strictEqual(prop(array), 'a'); + deepEqual(curried(4)(3)(2)(1), expected); + deepEqual(curried(3, 4)(1, 2), expected); + deepEqual(curried(1, 2, 3, 4), expected); }); - test('should support deep paths for `_.property` shorthands', 1, function() { - var object = { 'a': { 'b': { 'c': 3 } } }, - prop = _.callback('a.b.c'); + test('should allow specifying `arity`', 3, function() { + var curried = _.curryRight(fn, 3), + expected = [1, 2, 3]; - strictEqual(prop(object), 3); + deepEqual(curried(3)(1, 2), expected); + deepEqual(curried(2, 3)(1), expected); + deepEqual(curried(1, 2, 3), expected); }); - test('should work with functions created by `_.partial` and `_.partialRight`', 2, function() { - var fn = function() { - var result = [this.a]; - push.apply(result, arguments); - return result; - }; - - var expected = [1, 2, 3], - object = { 'a': 1 }, - callback = _.callback(_.partial(fn, 2), object); + test('should work with partialed methods', 2, function() { + var curried = _.curryRight(fn), + expected = [1, 2, 3, 4]; - deepEqual(callback(3), expected); + var a = _.partialRight(curried, 4), + b = _.partialRight(a, 3), + c = _.bind(b, null, 1), + d = _.partial(b(2), 1); - callback = _.callback(_.partialRight(fn, 3), object); - deepEqual(callback(2), expected); + deepEqual(c(2), expected); + deepEqual(d(), expected); }); - test('should support binding built-in methods', 2, function() { - var fn = function() {}, - object = { 'a': 1 }, - bound = fn.bind && fn.bind(object), - callback = _.callback(hasOwnProperty, object); - - strictEqual(callback('a'), true); + test('should support placeholders', 4, function() { + var curried = _.curryRight(fn), + expected = [1, 2, 3, 4], + ph = curried.placeholder; - if (bound) { - callback = _.callback(bound, object); - notStrictEqual(callback, bound); - } - else { - skipTest(); - } + deepEqual(curried(4)(2, ph)(1, ph)(3), expected); + deepEqual(curried(3, ph)(4)(1, ph)(2), expected); + deepEqual(curried(ph, ph, 4)(ph, 3)(ph, 2)(1), expected); + deepEqual(curried(ph, ph, ph, 4)(ph, ph, 3)(ph, 2)(1), expected); }); - test('should work as an iteratee for methods like `_.map`', 1, function() { - var fn = function() { return this instanceof Number; }, - array = [fn, fn, fn], - callbacks = _.map(array, _.callback), - expected = _.map(array, _.constant(false)); + test('should provide additional arguments after reaching the target arity', 3, function() { + var curried = _.curryRight(fn, 3); + deepEqual(curried(4)(1, 2, 3), [1, 2, 3, 4]); + deepEqual(curried(4, 5)(1, 2, 3), [1, 2, 3, 4, 5]); + deepEqual(curried(1, 2, 3, 4, 5, 6), [1, 2, 3, 4, 5, 6]); + }); - var actual = _.map(callbacks, function(callback) { - return callback(); + test('should return a function with a `length` of `0`', 6, function() { + _.times(2, function(index) { + var curried = index ? _.curryRight(fn, 4) : _.curryRight(fn); + strictEqual(curried.length, 0); + strictEqual(curried(4).length, 0); + strictEqual(curried(3, 4).length, 0); }); - - deepEqual(actual, expected); }); - test('should be aliased', 1, function() { - strictEqual(_.iteratee, _.callback); + test('should ensure `new curried` is an instance of `func`', 2, function() { + var Foo = function(value) { + return value && object; + }; + + var curried = _.curryRight(Foo), + object = {}; + + ok(new curried(false) instanceof Foo); + strictEqual(new curried(true), object); }); - }()); - /*--------------------------------------------------------------------------*/ + test('should not set a `this` binding', 9, function() { + var fn = function(a, b, c) { + var value = this || {}; + return [value[a], value[b], value[c]]; + }; - QUnit.module('custom `_.callback` methods'); + var object = { 'a': 1, 'b': 2, 'c': 3 }, + expected = [1, 2, 3]; - (function() { - var array = ['one', 'two', 'three'], - callback = _.callback, - getPropA = _.partial(_.property, 'a'), - getPropB = _.partial(_.property, 'b'), - getLength = _.partial(_.property, 'length'); - - var getSum = function() { - return function(result, object) { - return result + object.a; - }; - }; + deepEqual(_.curryRight(_.bind(fn, object), 3)('c')('b')('a'), expected); + deepEqual(_.curryRight(_.bind(fn, object), 3)('b', 'c')('a'), expected); + deepEqual(_.curryRight(_.bind(fn, object), 3)('a', 'b', 'c'), expected); - var objects = [ - { 'a': 0, 'b': 0 }, - { 'a': 1, 'b': 0 }, - { 'a': 1, 'b': 1 } - ]; + deepEqual(_.bind(_.curryRight(fn), object)('c')('b')('a'), Array(3)); + deepEqual(_.bind(_.curryRight(fn), object)('b', 'c')('a'), Array(3)); + deepEqual(_.bind(_.curryRight(fn), object)('a', 'b', 'c'), expected); - test('`_.countBy` should use `_.callback` internally', 1, function() { - if (!isModularize) { - _.callback = getLength; - deepEqual(_.countBy(array), { '3': 2, '5': 1 }); - _.callback = callback; - } - else { - skipTest(); - } + object.curried = _.curryRight(fn); + deepEqual(object.curried('c')('b')('a'), Array(3)); + deepEqual(object.curried('b', 'c')('a'), Array(3)); + deepEqual(object.curried('a', 'b', 'c'), expected); }); + }()); - test('`_.dropRightWhile` should use `_.callback` internally', 1, function() { - if (!isModularize) { - _.callback = getPropB; - deepEqual(_.dropRightWhile(objects), objects.slice(0, 2)); - _.callback = callback; - } - else { - skipTest(); - } - }); + /*--------------------------------------------------------------------------*/ - test('`_.dropWhile` should use `_.callback` internally', 1, function() { - if (!isModularize) { - _.callback = getPropB; - deepEqual(_.dropWhile(objects.reverse()).reverse(), objects.reverse().slice(0, 2)); - _.callback = callback; - } - else { - skipTest(); - } - }); + QUnit.module('curry methods'); - test('`_.every` should use `_.callback` internally', 1, function() { - if (!isModularize) { - _.callback = getPropA; - strictEqual(_.every(objects.slice(1)), true); - _.callback = callback; - } - else { - skipTest(); + _.each(['curry', 'curryRight'], function(methodName) { + var func = _[methodName], + fn = function(a, b) { return slice.call(arguments); }, + isCurry = methodName == 'curry'; + + test('`_.' + methodName + '` should not error on functions with the same name as lodash methods', 1, function() { + function run(a, b) { + return a + b; } - }); - test('`_.filter` should use `_.callback` internally', 1, function() { - if (!isModularize) { - var objects = [{ 'a': 0 }, { 'a': 1 }]; + var curried = func(run); - _.callback = getPropA; - deepEqual(_.filter(objects), [objects[1]]); - _.callback = callback; - } - else { - skipTest(); - } - }); + try { + var actual = curried(1)(2); + } catch(e) {} - test('`_.find` should use `_.callback` internally', 1, function() { - if (!isModularize) { - _.callback = getPropA; - strictEqual(_.find(objects), objects[1]); - _.callback = callback; - } - else { - skipTest(); - } + strictEqual(actual, 3); }); - test('`_.findIndex` should use `_.callback` internally', 1, function() { - if (!isModularize) { - _.callback = getPropA; - strictEqual(_.findIndex(objects), 1); - _.callback = callback; - } - else { - skipTest(); - } - }); + test('`_.' + methodName + '` should work as an iteratee for methods like `_.map`', 2, function() { + var array = [fn, fn, fn], + object = { 'a': fn, 'b': fn, 'c': fn }; - test('`_.findLast` should use `_.callback` internally', 1, function() { - if (!isModularize) { - _.callback = getPropA; - strictEqual(_.findLast(objects), objects[2]); - _.callback = callback; - } - else { - skipTest(); - } - }); + _.each([array, object], function(collection) { + var curries = _.map(collection, func), + expected = _.map(collection, _.constant(isCurry ? ['a', 'b'] : ['b', 'a'])); - test('`_.findLastIndex` should use `_.callback` internally', 1, function() { - if (!isModularize) { - _.callback = getPropA; - strictEqual(_.findLastIndex(objects), 2); - _.callback = callback; - } - else { - skipTest(); - } - }); + var actual = _.map(curries, function(curried) { + return curried('a')('b'); + }); - test('`_.findLastKey` should use `_.callback` internally', 1, function() { - if (!isModularize) { - _.callback = getPropB; - strictEqual(_.findKey(objects), '2'); - _.callback = callback; - } - else { - skipTest(); - } + deepEqual(actual, expected); + }); }); + }); - test('`_.findKey` should use `_.callback` internally', 1, function() { - if (!isModularize) { - _.callback = getPropB; - strictEqual(_.findLastKey(objects), '2'); - _.callback = callback; - } - else { - skipTest(); - } - }); + /*--------------------------------------------------------------------------*/ - test('`_.groupBy` should use `_.callback` internally', 1, function() { - if (!isModularize) { - _.callback = getLength; - deepEqual(_.groupBy(array), { '3': ['one', 'two'], '5': ['three'] }); - _.callback = callback; - } - else { - skipTest(); - } - }); + QUnit.module('lodash.debounce'); - test('`_.indexBy` should use `_.callback` internally', 1, function() { - if (!isModularize) { - _.callback = getLength; - deepEqual(_.indexBy(array), { '3': 'two', '5': 'three' }); - _.callback = callback; - } - else { - skipTest(); - } - }); + (function() { + asyncTest('should debounce a function', 2, function() { + if (!(isRhino && isModularize)) { + var callCount = 0, + debounced = _.debounce(function() { callCount++; }, 32); - test('`_.map` should use `_.callback` internally', 1, function() { - if (!isModularize) { - _.callback = getPropA; - deepEqual(_.map(objects), [0, 1, 1]); - _.callback = callback; - } - else { - skipTest(); - } - }); + debounced(); + debounced(); + debounced(); - test('`_.mapKeys` should use `_.callback` internally', 1, function() { - if (!isModularize) { - _.callback = getPropB; - deepEqual(_.mapKeys({ 'a': { 'b': 1 } }), { '1': { 'b': 1 } }); - _.callback = callback; - } - else { - skipTest(); - } - }); + strictEqual(callCount, 0); - test('`_.mapValues` should use `_.callback` internally', 1, function() { - if (!isModularize) { - _.callback = getPropB; - deepEqual(_.mapValues({ 'a': { 'b': 1 } }), { 'a': 1 }); - _.callback = callback; + setTimeout(function() { + strictEqual(callCount, 1); + QUnit.start(); + }, 96); } else { - skipTest(); + skipTest(2); + QUnit.start(); } }); - test('`_.max` should use `_.callback` internally', 1, function() { - if (!isModularize) { - _.callback = getPropB; - deepEqual(_.max(objects), objects[2]); - _.callback = callback; - } - else { - skipTest(); - } - }); + asyncTest('subsequent debounced calls return the last `func` result', 2, function() { + if (!(isRhino && isModularize)) { + var debounced = _.debounce(_.identity, 32); + debounced('x'); - test('`_.min` should use `_.callback` internally', 1, function() { - if (!isModularize) { - _.callback = getPropB; - deepEqual(_.min(objects), objects[0]); - _.callback = callback; + setTimeout(function() { + notEqual(debounced('y'), 'y'); + }, 64); + + setTimeout(function() { + notEqual(debounced('z'), 'z'); + QUnit.start(); + }, 128); } else { - skipTest(); + skipTest(2); + QUnit.start(); } }); - test('`_.partition` should use `_.callback` internally', 1, function() { - if (!isModularize) { - var objects = [{ 'a': 1 }, { 'a': 1 }, { 'b': 2 }]; + asyncTest('subsequent "immediate" debounced calls return the last `func` result', 2, function() { + if (!(isRhino && isModularize)) { + var debounced = _.debounce(_.identity, 32, true), + result = [debounced('x'), debounced('y')]; - _.callback = getPropA; - deepEqual(_.partition(objects), [objects.slice(0, 2), objects.slice(2)]); - _.callback = callback; - } - else { - skipTest(); - } - }); + deepEqual(result, ['x', 'x']); - test('`_.reduce` should use `_.callback` internally', 1, function() { - if (!isModularize) { - _.callback = getSum; - strictEqual(_.reduce(objects, undefined, 0), 2); - _.callback = callback; + setTimeout(function() { + var result = [debounced('a'), debounced('b')]; + deepEqual(result, ['a', 'a']); + QUnit.start(); + }, 64); } else { - skipTest(); + skipTest(2); + QUnit.start(); } }); - test('`_.reduceRight` should use `_.callback` internally', 1, function() { - if (!isModularize) { - _.callback = getSum; - strictEqual(_.reduceRight(objects, undefined, 0), 2); - _.callback = callback; - } - else { - skipTest(); - } - }); + asyncTest('should apply default options', 2, function() { + if (!(isRhino && isModularize)) { + var callCount = 0; - test('`_.reject` should use `_.callback` internally', 1, function() { - if (!isModularize) { - var objects = [{ 'a': 0 }, { 'a': 1 }]; + var debounced = _.debounce(function(value) { + callCount++; + return value; + }, 32, {}); - _.callback = getPropA; - deepEqual(_.reject(objects), [objects[0]]); - _.callback = callback; + strictEqual(debounced('x'), undefined); + + setTimeout(function() { + strictEqual(callCount, 1); + QUnit.start(); + }, 64); } else { - skipTest(); + skipTest(2); + QUnit.start(); } }); - test('`_.remove` should use `_.callback` internally', 1, function() { - if (!isModularize) { - var objects = [{ 'a': 0 }, { 'a': 1 }]; + asyncTest('should support a `leading` option', 7, function() { + if (!(isRhino && isModularize)) { + var withLeading, + callCounts = [0, 0, 0]; - _.callback = getPropA; - _.remove(objects); - deepEqual(objects, [{ 'a': 0 }]); - _.callback = callback; - } - else { - skipTest(); - } - }); + _.each([true, { 'leading': true }], function(options, index) { + var debounced = _.debounce(function(value) { + callCounts[index]++; + return value; + }, 32, options); - test('`_.some` should use `_.callback` internally', 1, function() { - if (!isModularize) { - _.callback = getPropB; - strictEqual(_.some(objects), true); - _.callback = callback; - } - else { - skipTest(); - } - }); + if (index == 1) { + withLeading = debounced; + } + strictEqual(debounced('x'), 'x'); + }); - test('`_.sortBy` should use `_.callback` internally', 1, function() { - if (!isModularize) { - _.callback = getPropA; - deepEqual(_.sortBy(objects.slice().reverse()), [objects[0], objects[2], objects[1]]); - _.callback = callback; - } - else { - skipTest(); - } - }); + _.each([false, { 'leading': false }], function(options) { + var withoutLeading = _.debounce(_.identity, 32, options); + strictEqual(withoutLeading('x'), undefined); + }); - test('`_.sortedIndex` should use `_.callback` internally', 1, function() { - if (!isModularize) { - var objects = [{ 'a': 30 }, { 'a': 50 }]; + var withLeadingAndTrailing = _.debounce(function() { + callCounts[2]++; + }, 32, { 'leading': true }); - _.callback = getPropA; - strictEqual(_.sortedIndex(objects, { 'a': 40 }), 1); - _.callback = callback; - } - else { - skipTest(); - } - }); + withLeadingAndTrailing(); + withLeadingAndTrailing(); - test('`_.sortedLastIndex` should use `_.callback` internally', 1, function() { - if (!isModularize) { - var objects = [{ 'a': 30 }, { 'a': 50 }]; + strictEqual(callCounts[2], 1); - _.callback = getPropA; - strictEqual(_.sortedLastIndex(objects, { 'a': 40 }), 1); - _.callback = callback; - } - else { - skipTest(); - } - }); + setTimeout(function() { + deepEqual(callCounts, [1, 1, 2]); - test('`_.sum` should use `_.callback` internally', 1, function() { - if (!isModularize) { - _.callback = getPropB; - strictEqual(_.sum(objects), 1); - _.callback = callback; + withLeading('x'); + strictEqual(callCounts[1], 2); + + QUnit.start(); + }, 64); } else { - skipTest(); + skipTest(7); + QUnit.start(); } }); - test('`_.takeRightWhile` should use `_.callback` internally', 1, function() { - if (!isModularize) { - _.callback = getPropB; - deepEqual(_.takeRightWhile(objects), objects.slice(2)); - _.callback = callback; + asyncTest('should support a `trailing` option', 4, function() { + if (!(isRhino && isModularize)) { + var withCount = 0, + withoutCount = 0; + + var withTrailing = _.debounce(function(value) { + withCount++; + return value; + }, 32, { 'trailing': true }); + + var withoutTrailing = _.debounce(function(value) { + withoutCount++; + return value; + }, 32, { 'trailing': false }); + + strictEqual(withTrailing('x'), undefined); + strictEqual(withoutTrailing('x'), undefined); + + setTimeout(function() { + strictEqual(withCount, 1); + strictEqual(withoutCount, 0); + QUnit.start(); + }, 64); } else { - skipTest(); + skipTest(4); + QUnit.start(); } }); - test('`_.takeWhile` should use `_.callback` internally', 1, function() { - if (!isModularize) { - _.callback = getPropB; - deepEqual(_.takeWhile(objects.reverse()), objects.reverse().slice(2)); - _.callback = callback; + asyncTest('should support a `maxWait` option', 1, function() { + if (!(isRhino && isModularize)) { + var limit = (argv || isPhantom) ? 1000 : 320, + withCount = 0, + withoutCount = 0; + + var withMaxWait = _.debounce(function() { + withCount++; + }, 64, { 'maxWait': 128 }); + + var withoutMaxWait = _.debounce(function() { + withoutCount++; + }, 96); + + var start = +new Date; + while ((new Date - start) < limit) { + withMaxWait(); + withoutMaxWait(); + } + var actual = [Boolean(withCount), Boolean(withoutCount)]; + + setTimeout(function() { + deepEqual(actual, [true, false]); + QUnit.start(); + }, 1); } else { skipTest(); + QUnit.start(); } }); - test('`_.transform` should use `_.callback` internally', 1, function() { - if (!isModularize) { - _.callback = function() { - return function(result, object) { - result.sum += object.a; - }; - }; + asyncTest('should cancel `maxDelayed` when `delayed` is invoked', 1, function() { + if (!(isRhino && isModularize)) { + var callCount = 0; - deepEqual(_.transform(objects, undefined, { 'sum': 0 }), { 'sum': 2 }); - _.callback = callback; + var debounced = _.debounce(function() { + callCount++; + }, 32, { 'maxWait': 64 }); + + debounced(); + + setTimeout(function() { + strictEqual(callCount, 1); + QUnit.start(); + }, 128); } else { skipTest(); + QUnit.start(); } }); - test('`_.uniq` should use `_.callback` internally', 1, function() { - if (!isModularize) { - _.callback = getPropB; - deepEqual(_.uniq(objects), [objects[0], objects[2]]); - _.callback = callback; + asyncTest('should invoke the `trailing` call with the correct arguments and `this` binding', 2, function() { + if (!(isRhino && isModularize)) { + var actual, + callCount = 0, + object = {}; + + var debounced = _.debounce(function(value) { + actual = [this]; + push.apply(actual, arguments); + return ++callCount != 2; + }, 32, { 'leading': true, 'maxWait': 64 }); + + while (true) { + if (!debounced.call(object, 'a')) { + break; + } + } + setTimeout(function() { + strictEqual(callCount, 2); + deepEqual(actual, [object, 'a']); + QUnit.start(); + }, 64); } else { - skipTest(); + skipTest(2); + QUnit.start(); } }); }()); /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.curry'); + QUnit.module('lodash.deburr'); (function() { - function fn(a, b, c, d) { - return slice.call(arguments); - } - - test('should curry based on the number of arguments provided', 3, function() { - var curried = _.curry(fn), - expected = [1, 2, 3, 4]; - - deepEqual(curried(1)(2)(3)(4), expected); - deepEqual(curried(1, 2)(3, 4), expected); - deepEqual(curried(1, 2, 3, 4), expected); + test('should convert latin-1 supplementary letters to basic latin', 1, function() { + var actual = _.map(burredLetters, _.deburr); + deepEqual(actual, deburredLetters); }); - test('should allow specifying `arity`', 3, function() { - var curried = _.curry(fn, 3), - expected = [1, 2, 3]; + test('should not deburr latin-1 mathematical operators', 1, function() { + var operators = ['\xd7', '\xf7'], + actual = _.map(operators, _.deburr); - deepEqual(curried(1)(2, 3), expected); - deepEqual(curried(1, 2)(3), expected); - deepEqual(curried(1, 2, 3), expected); + deepEqual(actual, operators); }); - test('should coerce `arity` to a number', 2, function() { - var values = ['0', 'xyz'], - expected = _.map(values, _.constant([])); + test('should deburr combining diacritical marks', 1, function() { + var values = comboMarks.concat(comboHalfs), + expected = _.map(values, _.constant('ei')); - var actual = _.map(values, function(arity) { - return _.curry(fn, arity)(); + var actual = _.map(values, function(chr) { + return _.deburr('e' + chr + 'i'); }); deepEqual(actual, expected); - deepEqual(_.curry(fn, '2')(1)(2), [1, 2]); }); + }()); - test('should support placeholders', 4, function() { - var curried = _.curry(fn), - ph = curried.placeholder; - - deepEqual(curried(1)(ph, 3)(ph, 4)(2), [1, 2, 3, 4]); - deepEqual(curried(ph, 2)(1)(ph, 4)(3), [1, 2, 3, 4]); - deepEqual(curried(ph, ph, 3)(ph, 2)(ph, 4)(1), [1, 2, 3, 4]); - deepEqual(curried(ph, ph, ph, 4)(ph, ph, 3)(ph, 2)(1), [1, 2, 3, 4]); - }); + /*--------------------------------------------------------------------------*/ - test('should work with partialed methods', 2, function() { - var curried = _.curry(fn), - expected = [1, 2, 3, 4]; + QUnit.module('lodash.defaults'); - var a = _.partial(curried, 1), - b = _.bind(a, null, 2), - c = _.partialRight(b, 4), - d = _.partialRight(b(3), 4); + (function() { + test('should assign properties of a source object if missing on the destination object', 1, function() { + deepEqual(_.defaults({ 'a': 1 }, { 'a': 2, 'b': 2 }), { 'a': 1, 'b': 2 }); + }); - deepEqual(c(3), expected); - deepEqual(d(), expected); + test('should accept multiple source objects', 2, function() { + var expected = { 'a': 1, 'b': 2, 'c': 3 }; + deepEqual(_.defaults({ 'a': 1, 'b': 2 }, { 'b': 3 }, { 'c': 3 }), expected); + deepEqual(_.defaults({ 'a': 1, 'b': 2 }, { 'b': 3, 'c': 3 }, { 'c': 2 }), expected); }); - test('should provide additional arguments after reaching the target arity', 3, function() { - var curried = _.curry(fn, 3); - deepEqual(curried(1)(2, 3, 4), [1, 2, 3, 4]); - deepEqual(curried(1, 2)(3, 4, 5), [1, 2, 3, 4, 5]); - deepEqual(curried(1, 2, 3, 4, 5, 6), [1, 2, 3, 4, 5, 6]); + test('should not overwrite `null` values', 1, function() { + var actual = _.defaults({ 'a': null }, { 'a': 1 }); + strictEqual(actual.a, null); }); - test('should return a function with a `length` of `0`', 6, function() { - _.times(2, function(index) { - var curried = index ? _.curry(fn, 4) : _.curry(fn); - strictEqual(curried.length, 0); - strictEqual(curried(1).length, 0); - strictEqual(curried(1, 2).length, 0); - }); + test('should overwrite `undefined` values', 1, function() { + var actual = _.defaults({ 'a': undefined }, { 'a': 1 }); + strictEqual(actual.a, 1); }); - - test('should ensure `new curried` is an instance of `func`', 2, function() { - var Foo = function(value) { - return value && object; - }; - - var curried = _.curry(Foo), - object = {}; - - ok(new curried(false) instanceof Foo); - strictEqual(new curried(true), object); - }); - - test('should not set a `this` binding', 9, function() { - var fn = function(a, b, c) { - var value = this || {}; - return [value[a], value[b], value[c]]; - }; - - var object = { 'a': 1, 'b': 2, 'c': 3 }, - expected = [1, 2, 3]; - - deepEqual(_.curry(_.bind(fn, object), 3)('a')('b')('c'), expected); - deepEqual(_.curry(_.bind(fn, object), 3)('a', 'b')('c'), expected); - deepEqual(_.curry(_.bind(fn, object), 3)('a', 'b', 'c'), expected); - - deepEqual(_.bind(_.curry(fn), object)('a')('b')('c'), Array(3)); - deepEqual(_.bind(_.curry(fn), object)('a', 'b')('c'), Array(3)); - deepEqual(_.bind(_.curry(fn), object)('a', 'b', 'c'), expected); - - object.curried = _.curry(fn); - deepEqual(object.curried('a')('b')('c'), Array(3)); - deepEqual(object.curried('a', 'b')('c'), Array(3)); - deepEqual(object.curried('a', 'b', 'c'), expected); - }); - }()); + }()); /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.curryRight'); + QUnit.module('lodash.defaultsDeep'); (function() { - function fn(a, b, c, d) { - return slice.call(arguments); - } - - test('should curry based on the number of arguments provided', 3, function() { - var curried = _.curryRight(fn), - expected = [1, 2, 3, 4]; - - deepEqual(curried(4)(3)(2)(1), expected); - deepEqual(curried(3, 4)(1, 2), expected); - deepEqual(curried(1, 2, 3, 4), expected); - }); - - test('should allow specifying `arity`', 3, function() { - var curried = _.curryRight(fn, 3), - expected = [1, 2, 3]; - - deepEqual(curried(3)(1, 2), expected); - deepEqual(curried(2, 3)(1), expected); - deepEqual(curried(1, 2, 3), expected); - }); - - test('should work with partialed methods', 2, function() { - var curried = _.curryRight(fn), - expected = [1, 2, 3, 4]; - - var a = _.partialRight(curried, 4), - b = _.partialRight(a, 3), - c = _.bind(b, null, 1), - d = _.partial(b(2), 1); - - deepEqual(c(2), expected); - deepEqual(d(), expected); - }); - - test('should support placeholders', 4, function() { - var curried = _.curryRight(fn), - expected = [1, 2, 3, 4], - ph = curried.placeholder; + test('should deep assign properties of a source object if missing on the destination object', 1, function() { + var object = { 'a': { 'b': 2 }, 'd': 4 }, + source = { 'a': { 'b': 1, 'c': 3 }, 'e': 5 }, + expected = { 'a': { 'b': 2, 'c': 3 }, 'd': 4, 'e': 5 }; - deepEqual(curried(4)(2, ph)(1, ph)(3), expected); - deepEqual(curried(3, ph)(4)(1, ph)(2), expected); - deepEqual(curried(ph, ph, 4)(ph, 3)(ph, 2)(1), expected); - deepEqual(curried(ph, ph, ph, 4)(ph, ph, 3)(ph, 2)(1), expected); + deepEqual(_.defaultsDeep(object, source), expected); }); - test('should provide additional arguments after reaching the target arity', 3, function() { - var curried = _.curryRight(fn, 3); - deepEqual(curried(4)(1, 2, 3), [1, 2, 3, 4]); - deepEqual(curried(4, 5)(1, 2, 3), [1, 2, 3, 4, 5]); - deepEqual(curried(1, 2, 3, 4, 5, 6), [1, 2, 3, 4, 5, 6]); - }); + test('should accept multiple source objects', 2, function() { + var source1 = { 'a': { 'b': 3 } }, + source2 = { 'a': { 'c': 3 } }, + source3 = { 'a': { 'b': 3, 'c': 3 } }, + source4 = { 'a': { 'c': 4 } }, + expected = { 'a': { 'b': 2, 'c': 3 } }; - test('should return a function with a `length` of `0`', 6, function() { - _.times(2, function(index) { - var curried = index ? _.curryRight(fn, 4) : _.curryRight(fn); - strictEqual(curried.length, 0); - strictEqual(curried(4).length, 0); - strictEqual(curried(3, 4).length, 0); - }); + deepEqual(_.defaultsDeep({ 'a': { 'b': 2 } }, source1, source2), expected); + deepEqual(_.defaultsDeep({ 'a': { 'b': 2 } }, source3, source4), expected); }); - test('should ensure `new curried` is an instance of `func`', 2, function() { - var Foo = function(value) { - return value && object; - }; - - var curried = _.curryRight(Foo), - object = {}; + test('should not overwrite `null` values', 1, function() { + var object = { 'a': { 'b': null } }, + source = { 'a': { 'b': 2 } }, + actual = _.defaultsDeep(object, source); - ok(new curried(false) instanceof Foo); - strictEqual(new curried(true), object); + strictEqual(actual.a.b, null); }); - test('should not set a `this` binding', 9, function() { - var fn = function(a, b, c) { - var value = this || {}; - return [value[a], value[b], value[c]]; - }; - - var object = { 'a': 1, 'b': 2, 'c': 3 }, - expected = [1, 2, 3]; - - deepEqual(_.curryRight(_.bind(fn, object), 3)('c')('b')('a'), expected); - deepEqual(_.curryRight(_.bind(fn, object), 3)('b', 'c')('a'), expected); - deepEqual(_.curryRight(_.bind(fn, object), 3)('a', 'b', 'c'), expected); - - deepEqual(_.bind(_.curryRight(fn), object)('c')('b')('a'), Array(3)); - deepEqual(_.bind(_.curryRight(fn), object)('b', 'c')('a'), Array(3)); - deepEqual(_.bind(_.curryRight(fn), object)('a', 'b', 'c'), expected); + test('should overwrite `undefined` values', 1, function() { + var object = { 'a': { 'b': undefined } }, + source = { 'a': { 'b': 2 } }, + actual = _.defaultsDeep(object, source); - object.curried = _.curryRight(fn); - deepEqual(object.curried('c')('b')('a'), Array(3)); - deepEqual(object.curried('b', 'c')('a'), Array(3)); - deepEqual(object.curried('a', 'b', 'c'), expected); + strictEqual(actual.a.b, 2); }); }()); /*--------------------------------------------------------------------------*/ - QUnit.module('curry methods'); + QUnit.module('lodash.defer'); - _.each(['curry', 'curryRight'], function(methodName) { - var func = _[methodName], - fn = function(a, b) { return slice.call(arguments); }, - isCurry = methodName == 'curry'; + (function() { + asyncTest('should defer `func` execution', 1, function() { + if (!(isRhino && isModularize)) { + var pass = false; + _.defer(function() { pass = true; }); - test('`_.' + methodName + '` should not error on functions with the same name as lodash methods', 1, function() { - function run(a, b) { - return a + b; + setTimeout(function() { + ok(pass); + QUnit.start(); + }, 32); + } + else { + skipTest(); + QUnit.start(); } - - var curried = func(run); - - try { - var actual = curried(1)(2); - } catch(e) {} - - strictEqual(actual, 3); - }); - - test('`_.' + methodName + '` should work as an iteratee for methods like `_.map`', 2, function() { - var array = [fn, fn, fn], - object = { 'a': fn, 'b': fn, 'c': fn }; - - _.each([array, object], function(collection) { - var curries = _.map(collection, func), - expected = _.map(collection, _.constant(isCurry ? ['a', 'b'] : ['b', 'a'])); - - var actual = _.map(curries, function(curried) { - return curried('a')('b'); - }); - - deepEqual(actual, expected); - }); }); - }); - /*--------------------------------------------------------------------------*/ - - QUnit.module('lodash.debounce'); - - (function() { - asyncTest('should debounce a function', 2, function() { + asyncTest('should provide additional arguments to `func`', 1, function() { if (!(isRhino && isModularize)) { - var callCount = 0, - debounced = _.debounce(function() { callCount++; }, 32); - - debounced(); - debounced(); - debounced(); + var args; - strictEqual(callCount, 0); + _.defer(function() { + args = slice.call(arguments); + }, 1, 2); setTimeout(function() { - strictEqual(callCount, 1); + deepEqual(args, [1, 2]); QUnit.start(); - }, 96); + }, 32); } else { - skipTest(2); + skipTest(); QUnit.start(); } }); - asyncTest('subsequent debounced calls return the last `func` result', 2, function() { + asyncTest('should be cancelable', 1, function() { if (!(isRhino && isModularize)) { - var debounced = _.debounce(_.identity, 32); - debounced('x'); + var pass = true; - setTimeout(function() { - notEqual(debounced('y'), 'y'); - }, 64); + var timerId = _.defer(function() { + pass = false; + }); + + clearTimeout(timerId); setTimeout(function() { - notEqual(debounced('z'), 'z'); + ok(pass); QUnit.start(); - }, 128); + }, 32); } else { - skipTest(2); + skipTest(); QUnit.start(); } }); + }()); - asyncTest('subsequent "immediate" debounced calls return the last `func` result', 2, function() { + /*--------------------------------------------------------------------------*/ + + QUnit.module('lodash.delay'); + + (function() { + asyncTest('should delay `func` execution', 2, function() { if (!(isRhino && isModularize)) { - var debounced = _.debounce(_.identity, 32, true), - result = [debounced('x'), debounced('y')]; + var pass = false; + _.delay(function() { pass = true; }, 32); - deepEqual(result, ['x', 'x']); + setTimeout(function() { + ok(!pass); + }, 1); setTimeout(function() { - var result = [debounced('a'), debounced('b')]; - deepEqual(result, ['a', 'a']); + ok(pass); QUnit.start(); }, 64); } @@ -3480,482 +3237,188 @@ } }); - asyncTest('should apply default options', 2, function() { + asyncTest('should provide additional arguments to `func`', 1, function() { if (!(isRhino && isModularize)) { - var callCount = 0; - - var debounced = _.debounce(function(value) { - callCount++; - return value; - }, 32, {}); + var args; - strictEqual(debounced('x'), undefined); + _.delay(function() { + args = slice.call(arguments); + }, 32, 1, 2); setTimeout(function() { - strictEqual(callCount, 1); + deepEqual(args, [1, 2]); QUnit.start(); }, 64); } else { - skipTest(2); + skipTest(); QUnit.start(); } }); - asyncTest('should support a `leading` option', 7, function() { + asyncTest('should be cancelable', 1, function() { if (!(isRhino && isModularize)) { - var withLeading, - callCounts = [0, 0, 0]; - - _.each([true, { 'leading': true }], function(options, index) { - var debounced = _.debounce(function(value) { - callCounts[index]++; - return value; - }, 32, options); - - if (index == 1) { - withLeading = debounced; - } - strictEqual(debounced('x'), 'x'); - }); - - _.each([false, { 'leading': false }], function(options) { - var withoutLeading = _.debounce(_.identity, 32, options); - strictEqual(withoutLeading('x'), undefined); - }); - - var withLeadingAndTrailing = _.debounce(function() { - callCounts[2]++; - }, 32, { 'leading': true }); + var pass = true; - withLeadingAndTrailing(); - withLeadingAndTrailing(); + var timerId = _.delay(function() { + pass = false; + }, 32); - strictEqual(callCounts[2], 1); + clearTimeout(timerId); setTimeout(function() { - deepEqual(callCounts, [1, 1, 2]); - - withLeading('x'); - strictEqual(callCounts[1], 2); - + ok(pass); QUnit.start(); }, 64); } else { - skipTest(7); + skipTest(); QUnit.start(); } }); + }()); - asyncTest('should support a `trailing` option', 4, function() { - if (!(isRhino && isModularize)) { - var withCount = 0, - withoutCount = 0; + /*--------------------------------------------------------------------------*/ - var withTrailing = _.debounce(function(value) { - withCount++; - return value; - }, 32, { 'trailing': true }); + QUnit.module('lodash.difference'); - var withoutTrailing = _.debounce(function(value) { - withoutCount++; - return value; - }, 32, { 'trailing': false }); + (function() { + var args = arguments; - strictEqual(withTrailing('x'), undefined); - strictEqual(withoutTrailing('x'), undefined); + test('should return the difference of the given arrays', 2, function() { + var actual = _.difference([1, 2, 3, 4, 5], [5, 2, 10]); + deepEqual(actual, [1, 3, 4]); - setTimeout(function() { - strictEqual(withCount, 1); - strictEqual(withoutCount, 0); - QUnit.start(); - }, 64); - } - else { - skipTest(4); - QUnit.start(); - } + actual = _.difference([1, 2, 3, 4, 5], [5, 2, 10], [8, 4]); + deepEqual(actual, [1, 3]); }); - asyncTest('should support a `maxWait` option', 1, function() { - if (!(isRhino && isModularize)) { - var limit = (argv || isPhantom) ? 1000 : 320, - withCount = 0, - withoutCount = 0; - - var withMaxWait = _.debounce(function() { - withCount++; - }, 64, { 'maxWait': 128 }); + test('should match `NaN`', 1, function() { + deepEqual(_.difference([1, NaN, 3], [NaN, 5, NaN]), [1, 3]); + }); - var withoutMaxWait = _.debounce(function() { - withoutCount++; - }, 96); + test('should work with large arrays', 1, function() { + var array1 = _.range(LARGE_ARRAY_SIZE + 1), + array2 = _.range(LARGE_ARRAY_SIZE), + a = {}, + b = {}, + c = {}; - var start = +new Date; - while ((new Date - start) < limit) { - withMaxWait(); - withoutMaxWait(); - } - var actual = [Boolean(withCount), Boolean(withoutCount)]; + array1.push(a, b, c); + array2.push(b, c, a); - setTimeout(function() { - deepEqual(actual, [true, false]); - QUnit.start(); - }, 1); - } - else { - skipTest(); - QUnit.start(); - } + deepEqual(_.difference(array1, array2), [LARGE_ARRAY_SIZE]); }); - asyncTest('should cancel `maxDelayed` when `delayed` is invoked', 1, function() { - if (!(isRhino && isModularize)) { - var callCount = 0; - - var debounced = _.debounce(function() { - callCount++; - }, 32, { 'maxWait': 64 }); - - debounced(); + test('should work with large arrays of objects', 1, function() { + var object1 = {}, + object2 = {}, + largeArray = _.times(LARGE_ARRAY_SIZE, _.constant(object1)); - setTimeout(function() { - strictEqual(callCount, 1); - QUnit.start(); - }, 128); - } - else { - skipTest(); - QUnit.start(); - } + deepEqual(_.difference([object1, object2], largeArray), [object2]); }); - asyncTest('should invoke the `trailing` call with the correct arguments and `this` binding', 2, function() { - if (!(isRhino && isModularize)) { - var actual, - callCount = 0, - object = {}; - - var debounced = _.debounce(function(value) { - actual = [this]; - push.apply(actual, arguments); - return ++callCount != 2; - }, 32, { 'leading': true, 'maxWait': 64 }); + test('should work with large arrays of `NaN`', 1, function() { + var largeArray = _.times(LARGE_ARRAY_SIZE, _.constant(NaN)); + deepEqual(_.difference([1, NaN, 3], largeArray), [1, 3]); + }); - while (true) { - if (!debounced.call(object, 'a')) { - break; - } - } - setTimeout(function() { - strictEqual(callCount, 2); - deepEqual(actual, [object, 'a']); - QUnit.start(); - }, 64); - } - else { - skipTest(2); - QUnit.start(); - } + test('should ignore values that are not array-like', 3, function() { + var array = [1, null, 3]; + deepEqual(_.difference(args, 3, { '0': 1 }), [1, 2, 3]); + deepEqual(_.difference(null, array, 1), []); + deepEqual(_.difference(array, args, null), [null]); }); - }()); + }(1, 2, 3)); /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.deburr'); + QUnit.module('lodash.drop'); (function() { - test('should convert latin-1 supplementary letters to basic latin', 1, function() { - var actual = _.map(burredLetters, _.deburr); - deepEqual(actual, deburredLetters); - }); - - test('should not deburr latin-1 mathematical operators', 1, function() { - var operators = ['\xd7', '\xf7'], - actual = _.map(operators, _.deburr); + var array = [1, 2, 3]; - deepEqual(actual, operators); + test('should drop the first two elements', 1, function() { + deepEqual(_.drop(array, 2), [3]); }); - test('should deburr combining diacritical marks', 1, function() { - var values = comboMarks.concat(comboHalfs), - expected = _.map(values, _.constant('ei')); + test('should treat falsey `n` values, except nullish, as `0`', 1, function() { + var expected = _.map(falsey, function(value) { + return value == null ? [2, 3] : array; + }); - var actual = _.map(values, function(chr) { - return _.deburr('e' + chr + 'i'); + var actual = _.map(falsey, function(n) { + return _.drop(array, n); }); deepEqual(actual, expected); }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('lodash.defaults'); - (function() { - test('should assign properties of a source object if missing on the destination object', 1, function() { - deepEqual(_.defaults({ 'a': 1 }, { 'a': 2, 'b': 2 }), { 'a': 1, 'b': 2 }); + test('should return all elements when `n` < `1`', 3, function() { + _.each([0, -1, -Infinity], function(n) { + deepEqual(_.drop(array, n), array); + }); }); - test('should accept multiple source objects', 2, function() { - var expected = { 'a': 1, 'b': 2, 'c': 3 }; - deepEqual(_.defaults({ 'a': 1, 'b': 2 }, { 'b': 3 }, { 'c': 3 }), expected); - deepEqual(_.defaults({ 'a': 1, 'b': 2 }, { 'b': 3, 'c': 3 }, { 'c': 2 }), expected); + test('should return an empty array when `n` >= `array.length`', 4, function() { + _.each([3, 4, Math.pow(2, 32), Infinity], function(n) { + deepEqual(_.drop(array, n), []); + }); }); - test('should not overwrite `null` values', 1, function() { - var actual = _.defaults({ 'a': null }, { 'a': 1 }); - strictEqual(actual.a, null); - }); + test('should work as an iteratee for methods like `_.map`', 1, function() { + var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], + actual = _.map(array, _.drop); - test('should overwrite `undefined` values', 1, function() { - var actual = _.defaults({ 'a': undefined }, { 'a': 1 }); - strictEqual(actual.a, 1); + deepEqual(actual, [[2, 3], [5, 6], [8, 9]]); }); - }()); - /*--------------------------------------------------------------------------*/ + test('should work in a lazy chain sequence', 6, function() { + if (!isNpm) { + var array = _.range(1, LARGE_ARRAY_SIZE + 1), + values = [], + predicate = function(value) { values.push(value); return value > 2; }, + actual = _(array).drop(2).drop().value(); - QUnit.module('lodash.defaultsDeep'); + deepEqual(actual, array.slice(3)); - (function() { - test('should deep assign properties of a source object if missing on the destination object', 1, function() { - var object = { 'a': { 'b': 2 }, 'd': 4 }, - source = { 'a': { 'b': 1, 'c': 3 }, 'e': 5 }, - expected = { 'a': { 'b': 2, 'c': 3 }, 'd': 4, 'e': 5 }; - - deepEqual(_.defaultsDeep(object, source), expected); - }); - - test('should accept multiple source objects', 2, function() { - var source1 = { 'a': { 'b': 3 } }, - source2 = { 'a': { 'c': 3 } }, - source3 = { 'a': { 'b': 3, 'c': 3 } }, - source4 = { 'a': { 'c': 4 } }, - expected = { 'a': { 'b': 2, 'c': 3 } }; - - deepEqual(_.defaultsDeep({ 'a': { 'b': 2 } }, source1, source2), expected); - deepEqual(_.defaultsDeep({ 'a': { 'b': 2 } }, source3, source4), expected); - }); - - test('should not overwrite `null` values', 1, function() { - var object = { 'a': { 'b': null } }, - source = { 'a': { 'b': 2 } }, - actual = _.defaultsDeep(object, source); - - strictEqual(actual.a.b, null); - }); - - test('should overwrite `undefined` values', 1, function() { - var object = { 'a': { 'b': undefined } }, - source = { 'a': { 'b': 2 } }, - actual = _.defaultsDeep(object, source); - - strictEqual(actual.a.b, 2); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('lodash.defer'); - - (function() { - asyncTest('should defer `func` execution', 1, function() { - if (!(isRhino && isModularize)) { - var pass = false; - _.defer(function() { pass = true; }); - - setTimeout(function() { - ok(pass); - QUnit.start(); - }, 32); - } - else { - skipTest(); - QUnit.start(); - } - }); - - asyncTest('should provide additional arguments to `func`', 1, function() { - if (!(isRhino && isModularize)) { - var args; - - _.defer(function() { - args = slice.call(arguments); - }, 1, 2); - - setTimeout(function() { - deepEqual(args, [1, 2]); - QUnit.start(); - }, 32); - } - else { - skipTest(); - QUnit.start(); - } - }); - - asyncTest('should be cancelable', 1, function() { - if (!(isRhino && isModularize)) { - var pass = true; - - var timerId = _.defer(function() { - pass = false; - }); - - clearTimeout(timerId); - - setTimeout(function() { - ok(pass); - QUnit.start(); - }, 32); - } - else { - skipTest(); - QUnit.start(); - } - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('lodash.delay'); - - (function() { - asyncTest('should delay `func` execution', 2, function() { - if (!(isRhino && isModularize)) { - var pass = false; - _.delay(function() { pass = true; }, 32); - - setTimeout(function() { - ok(!pass); - }, 1); - - setTimeout(function() { - ok(pass); - QUnit.start(); - }, 64); - } - else { - skipTest(2); - QUnit.start(); - } - }); - - asyncTest('should provide additional arguments to `func`', 1, function() { - if (!(isRhino && isModularize)) { - var args; - - _.delay(function() { - args = slice.call(arguments); - }, 32, 1, 2); - - setTimeout(function() { - deepEqual(args, [1, 2]); - QUnit.start(); - }, 64); - } - else { - skipTest(); - QUnit.start(); - } - }); - - asyncTest('should be cancelable', 1, function() { - if (!(isRhino && isModularize)) { - var pass = true; + actual = _(array).filter(predicate).drop(2).drop().value(); + deepEqual(values, array); + deepEqual(actual, _.drop(_.drop(_.filter(array, predicate), 2))); - var timerId = _.delay(function() { - pass = false; - }, 32); + actual = _(array).drop(2).dropRight().drop().dropRight(2).value(); + deepEqual(actual, _.dropRight(_.drop(_.dropRight(_.drop(array, 2))), 2)); - clearTimeout(timerId); + values = []; - setTimeout(function() { - ok(pass); - QUnit.start(); - }, 64); + actual = _(array).drop().filter(predicate).drop(2).dropRight().drop().dropRight(2).value(); + deepEqual(values, array.slice(1)); + deepEqual(actual, _.dropRight(_.drop(_.dropRight(_.drop(_.filter(_.drop(array), predicate), 2))), 2)); } else { - skipTest(); - QUnit.start(); + skipTest(6); } }); }()); /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.difference'); - - (function() { - var args = arguments; - - test('should return the difference of the given arrays', 2, function() { - var actual = _.difference([1, 2, 3, 4, 5], [5, 2, 10]); - deepEqual(actual, [1, 3, 4]); - - actual = _.difference([1, 2, 3, 4, 5], [5, 2, 10], [8, 4]); - deepEqual(actual, [1, 3]); - }); - - test('should match `NaN`', 1, function() { - deepEqual(_.difference([1, NaN, 3], [NaN, 5, NaN]), [1, 3]); - }); - - test('should work with large arrays', 1, function() { - var array1 = _.range(LARGE_ARRAY_SIZE + 1), - array2 = _.range(LARGE_ARRAY_SIZE), - a = {}, - b = {}, - c = {}; - - array1.push(a, b, c); - array2.push(b, c, a); - - deepEqual(_.difference(array1, array2), [LARGE_ARRAY_SIZE]); - }); - - test('should work with large arrays of objects', 1, function() { - var object1 = {}, - object2 = {}, - largeArray = _.times(LARGE_ARRAY_SIZE, _.constant(object1)); - - deepEqual(_.difference([object1, object2], largeArray), [object2]); - }); - - test('should work with large arrays of `NaN`', 1, function() { - var largeArray = _.times(LARGE_ARRAY_SIZE, _.constant(NaN)); - deepEqual(_.difference([1, NaN, 3], largeArray), [1, 3]); - }); - - test('should ignore values that are not array-like', 3, function() { - var array = [1, null, 3]; - deepEqual(_.difference(args, 3, { '0': 1 }), [1, 2, 3]); - deepEqual(_.difference(null, array, 1), []); - deepEqual(_.difference(array, args, null), [null]); - }); - }(1, 2, 3)); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('lodash.drop'); + QUnit.module('lodash.dropRight'); (function() { var array = [1, 2, 3]; - test('should drop the first two elements', 1, function() { - deepEqual(_.drop(array, 2), [3]); + test('should drop the last two elements', 1, function() { + deepEqual(_.dropRight(array, 2), [1]); }); test('should treat falsey `n` values, except nullish, as `0`', 1, function() { var expected = _.map(falsey, function(value) { - return value == null ? [2, 3] : array; + return value == null ? [1, 2] : array; }); var actual = _.map(falsey, function(n) { - return _.drop(array, n); + return _.dropRight(array, n); }); deepEqual(actual, expected); @@ -3963,114 +3426,44 @@ test('should return all elements when `n` < `1`', 3, function() { _.each([0, -1, -Infinity], function(n) { - deepEqual(_.drop(array, n), array); + deepEqual(_.dropRight(array, n), array); }); }); test('should return an empty array when `n` >= `array.length`', 4, function() { _.each([3, 4, Math.pow(2, 32), Infinity], function(n) { - deepEqual(_.drop(array, n), []); + deepEqual(_.dropRight(array, n), []); }); }); test('should work as an iteratee for methods like `_.map`', 1, function() { var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], - actual = _.map(array, _.drop); + actual = _.map(array, _.dropRight); - deepEqual(actual, [[2, 3], [5, 6], [8, 9]]); + deepEqual(actual, [[1, 2], [4, 5], [7, 8]]); }); test('should work in a lazy chain sequence', 6, function() { if (!isNpm) { var array = _.range(1, LARGE_ARRAY_SIZE + 1), values = [], - predicate = function(value) { values.push(value); return value > 2; }, - actual = _(array).drop(2).drop().value(); + predicate = function(value) { values.push(value); return value < 9; }, + actual = _(array).dropRight(2).dropRight().value(); - deepEqual(actual, array.slice(3)); + deepEqual(actual, array.slice(0, -3)); - actual = _(array).filter(predicate).drop(2).drop().value(); + actual = _(array).filter(predicate).dropRight(2).dropRight().value(); deepEqual(values, array); - deepEqual(actual, _.drop(_.drop(_.filter(array, predicate), 2))); + deepEqual(actual, _.dropRight(_.dropRight(_.filter(array, predicate), 2))); - actual = _(array).drop(2).dropRight().drop().dropRight(2).value(); - deepEqual(actual, _.dropRight(_.drop(_.dropRight(_.drop(array, 2))), 2)); + actual = _(array).dropRight(2).drop().dropRight().drop(2).value(); + deepEqual(actual, _.drop(_.dropRight(_.drop(_.dropRight(array, 2))), 2)); values = []; - actual = _(array).drop().filter(predicate).drop(2).dropRight().drop().dropRight(2).value(); - deepEqual(values, array.slice(1)); - deepEqual(actual, _.dropRight(_.drop(_.dropRight(_.drop(_.filter(_.drop(array), predicate), 2))), 2)); - } - else { - skipTest(6); - } - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('lodash.dropRight'); - - (function() { - var array = [1, 2, 3]; - - test('should drop the last two elements', 1, function() { - deepEqual(_.dropRight(array, 2), [1]); - }); - - test('should treat falsey `n` values, except nullish, as `0`', 1, function() { - var expected = _.map(falsey, function(value) { - return value == null ? [1, 2] : array; - }); - - var actual = _.map(falsey, function(n) { - return _.dropRight(array, n); - }); - - deepEqual(actual, expected); - }); - - test('should return all elements when `n` < `1`', 3, function() { - _.each([0, -1, -Infinity], function(n) { - deepEqual(_.dropRight(array, n), array); - }); - }); - - test('should return an empty array when `n` >= `array.length`', 4, function() { - _.each([3, 4, Math.pow(2, 32), Infinity], function(n) { - deepEqual(_.dropRight(array, n), []); - }); - }); - - test('should work as an iteratee for methods like `_.map`', 1, function() { - var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], - actual = _.map(array, _.dropRight); - - deepEqual(actual, [[1, 2], [4, 5], [7, 8]]); - }); - - test('should work in a lazy chain sequence', 6, function() { - if (!isNpm) { - var array = _.range(1, LARGE_ARRAY_SIZE + 1), - values = [], - predicate = function(value) { values.push(value); return value < 9; }, - actual = _(array).dropRight(2).dropRight().value(); - - deepEqual(actual, array.slice(0, -3)); - - actual = _(array).filter(predicate).dropRight(2).dropRight().value(); - deepEqual(values, array); - deepEqual(actual, _.dropRight(_.dropRight(_.filter(array, predicate), 2))); - - actual = _(array).dropRight(2).drop().dropRight().drop(2).value(); - deepEqual(actual, _.drop(_.dropRight(_.drop(_.dropRight(array, 2))), 2)); - - values = []; - - actual = _(array).dropRight().filter(predicate).dropRight(2).drop().dropRight().drop(2).value(); - deepEqual(values, array.slice(0, -1)); - deepEqual(actual, _.drop(_.dropRight(_.drop(_.dropRight(_.filter(_.dropRight(array), predicate), 2))), 2)); + actual = _(array).dropRight().filter(predicate).dropRight(2).drop().dropRight().drop(2).value(); + deepEqual(values, array.slice(0, -1)); + deepEqual(actual, _.drop(_.dropRight(_.drop(_.dropRight(_.filter(_.dropRight(array), predicate), 2))), 2)); } else { skipTest(6); @@ -4431,10 +3824,6 @@ var actual = _.map([[1]], _.every); deepEqual(actual, [true]); }); - - test('should be aliased', 1, function() { - strictEqual(_.all, _.every); - }); }()); /*--------------------------------------------------------------------------*/ @@ -4630,10 +4019,6 @@ strictEqual(counter, 3); }); - - test('should be aliased', 1, function() { - strictEqual(_.select, _.filter); - }); }()); /*--------------------------------------------------------------------------*/ @@ -4733,11 +4118,6 @@ strictEqual(actual, expected); }); } - if (methodName == 'find') { - test('should be aliased', 1, function() { - strictEqual(_.detect, func); - }); - } }()); }); @@ -4851,10 +4231,6 @@ skipTest(2); } }); - - test('should be aliased', 1, function() { - strictEqual(_.head, _.first); - }); }()); /*--------------------------------------------------------------------------*/ @@ -6125,10 +5501,6 @@ Foo.prototype.c = _.noop; deepEqual(_.functions(new Foo).sort(), ['a', 'c']); }); - - test('should be aliased', 1, function() { - strictEqual(_.methods, _.functions); - }); }()); /*--------------------------------------------------------------------------*/ @@ -6511,11 +5883,6 @@ ok(_.every(array1, _.partial(_.includes, array2))); }); - - test('should be aliased', 2, function() { - strictEqual(_.contains, _.includes); - strictEqual(_.include, _.includes); - }); }(1, 2, 3, 4)); /*--------------------------------------------------------------------------*/ @@ -7345,23 +6712,639 @@ strictEqual(_.isEmpty({ 'length': '0' }), false); }); - test('should fix the JScript `[[DontEnum]]` bug (test in IE < 9)', 1, function() { - strictEqual(_.isEmpty(shadowObject), false); + test('should fix the JScript `[[DontEnum]]` bug (test in IE < 9)', 1, function() { + strictEqual(_.isEmpty(shadowObject), false); + }); + + test('should skip the prototype property of functions (test in Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1)', 2, function() { + function Foo() {} + Foo.prototype.a = 1; + + strictEqual(_.isEmpty(Foo), true); + + Foo.prototype = { 'a': 1 }; + strictEqual(_.isEmpty(Foo), true); + }); + + test('should return an unwrapped value when implicitly chaining', 1, function() { + if (!isNpm) { + strictEqual(_({}).isEmpty(), true); + } + else { + skipTest(); + } + }); + + test('should return a wrapped value when explicitly chaining', 1, function() { + if (!isNpm) { + ok(_({}).chain().isEmpty() instanceof _); + } + else { + skipTest(); + } + }); + }(1, 2, 3)); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('lodash.isEqual'); + + (function() { + test('should perform comparisons between primitive values', 1, function() { + var pairs = [ + [1, 1, true], [1, Object(1), true], [1, '1', false], [1, 2, false], + [-0, -0, true], [0, 0, true], [0, Object(0), true], [Object(0), Object(0), true], [-0, 0, true], [0, '0', false], [0, null, false], + [NaN, NaN, true], [NaN, Object(NaN), true], [Object(NaN), Object(NaN), true], [NaN, 'a', false], [NaN, Infinity, false], + ['a', 'a', true], ['a', Object('a'), true], [Object('a'), Object('a'), true], ['a', 'b', false], ['a', ['a'], false], + [true, true, true], [true, Object(true), true], [Object(true), Object(true), true], [true, 1, false], [true, 'a', false], + [false, false, true], [false, Object(false), true], [Object(false), Object(false), true], [false, 0, false], [false, '', false], + [null, null, true], [null, undefined, false], [null, {}, false], [null, '', false], + [undefined, undefined, true], [undefined, null, false], [undefined, '', false] + ]; + + var expected = _.map(pairs, function(pair) { + return pair[2]; + }); + + var actual = _.map(pairs, function(pair) { + return _.isEqual(pair[0], pair[1]); + }); + + deepEqual(actual, expected); + }); + + test('should perform comparisons between arrays', 6, function() { + var array1 = [true, null, 1, 'a', undefined], + array2 = [true, null, 1, 'a', undefined]; + + strictEqual(_.isEqual(array1, array2), true); + + array1 = [[1, 2, 3], new Date(2012, 4, 23), /x/, { 'e': 1 }]; + array2 = [[1, 2, 3], new Date(2012, 4, 23), /x/, { 'e': 1 }]; + + strictEqual(_.isEqual(array1, array2), true); + + array1 = [1]; + array1[2] = 3; + + array2 = [1]; + array2[1] = undefined; + array2[2] = 3; + + strictEqual(_.isEqual(array1, array2), true); + + array1 = [Object(1), false, Object('a'), /x/, new Date(2012, 4, 23), ['a', 'b', [Object('c')]], { 'a': 1 }]; + array2 = [1, Object(false), 'a', /x/, new Date(2012, 4, 23), ['a', Object('b'), ['c']], { 'a': 1 }]; + + strictEqual(_.isEqual(array1, array2), true); + + array1 = [1, 2, 3]; + array2 = [3, 2, 1]; + + strictEqual(_.isEqual(array1, array2), false); + + array1 = [1, 2]; + array2 = [1, 2, 3]; + + strictEqual(_.isEqual(array1, array2), false); + }); + + test('should treat arrays with identical values but different non-numeric properties as equal', 3, function() { + var array1 = [1, 2, 3], + array2 = [1, 2, 3]; + + array1.every = array1.filter = array1.forEach = array1.indexOf = array1.lastIndexOf = array1.map = array1.some = array1.reduce = array1.reduceRight = null; + array2.concat = array2.join = array2.pop = array2.reverse = array2.shift = array2.slice = array2.sort = array2.splice = array2.unshift = null; + + strictEqual(_.isEqual(array1, array2), true); + + array1 = [1, 2, 3]; + array1.a = 1; + + array2 = [1, 2, 3]; + array2.b = 1; + + strictEqual(_.isEqual(array1, array2), true); + + array1 = /x/.exec('vwxyz'); + array2 = ['x']; + + strictEqual(_.isEqual(array1, array2), true); + }); + + test('should work with sparse arrays', 3, function() { + var array = Array(1); + + strictEqual(_.isEqual(array, Array(1)), true); + strictEqual(_.isEqual(array, [undefined]), true); + strictEqual(_.isEqual(array, Array(2)), false); + }); + + test('should perform comparisons between plain objects', 5, function() { + var object1 = { 'a': true, 'b': null, 'c': 1, 'd': 'a', 'e': undefined }, + object2 = { 'a': true, 'b': null, 'c': 1, 'd': 'a', 'e': undefined }; + + strictEqual(_.isEqual(object1, object2), true); + + object1 = { 'a': [1, 2, 3], 'b': new Date(2012, 4, 23), 'c': /x/, 'd': { 'e': 1 } }; + object2 = { 'a': [1, 2, 3], 'b': new Date(2012, 4, 23), 'c': /x/, 'd': { 'e': 1 } }; + + strictEqual(_.isEqual(object1, object2), true); + + object1 = { 'a': 1, 'b': 2, 'c': 3 }; + object2 = { 'a': 3, 'b': 2, 'c': 1 }; + + strictEqual(_.isEqual(object1, object2), false); + + object1 = { 'a': 1, 'b': 2, 'c': 3 }; + object2 = { 'd': 1, 'e': 2, 'f': 3 }; + + strictEqual(_.isEqual(object1, object2), false); + + object1 = { 'a': 1, 'b': 2 }; + object2 = { 'a': 1, 'b': 2, 'c': 3 }; + + strictEqual(_.isEqual(object1, object2), false); + }); + + test('should perform comparisons of nested objects', 1, function() { + var object1 = { + 'a': [1, 2, 3], + 'b': true, + 'c': Object(1), + 'd': 'a', + 'e': { + 'f': ['a', Object('b'), 'c'], + 'g': Object(false), + 'h': new Date(2012, 4, 23), + 'i': _.noop, + 'j': 'a' + } + }; + + var object2 = { + 'a': [1, Object(2), 3], + 'b': Object(true), + 'c': 1, + 'd': Object('a'), + 'e': { + 'f': ['a', 'b', 'c'], + 'g': false, + 'h': new Date(2012, 4, 23), + 'i': _.noop, + 'j': 'a' + } + }; + + strictEqual(_.isEqual(object1, object2), true); + }); + + test('should perform comparisons between object instances', 4, function() { + function Foo() { this.value = 1; } + Foo.prototype.value = 1; + + function Bar() { + this.value = 1; + } + Bar.prototype.value = 2; + + strictEqual(_.isEqual(new Foo, new Foo), true); + strictEqual(_.isEqual(new Foo, new Bar), false); + strictEqual(_.isEqual({ 'value': 1 }, new Foo), false); + strictEqual(_.isEqual({ 'value': 2 }, new Bar), false); + }); + + test('should perform comparisons between objects with constructor properties', 5, function() { + strictEqual(_.isEqual({ 'constructor': 1 }, { 'constructor': 1 }), true); + strictEqual(_.isEqual({ 'constructor': 1 }, { 'constructor': '1' }), false); + strictEqual(_.isEqual({ 'constructor': [1] }, { 'constructor': [1] }), true); + strictEqual(_.isEqual({ 'constructor': [1] }, { 'constructor': ['1'] }), false); + strictEqual(_.isEqual({ 'constructor': Object }, {}), false); + }); + + test('should perform comparisons between arrays with circular references', 4, function() { + var array1 = [], + array2 = []; + + array1.push(array1); + array2.push(array2); + + strictEqual(_.isEqual(array1, array2), true); + + array1.push('b'); + array2.push('b'); + + strictEqual(_.isEqual(array1, array2), true); + + array1.push('c'); + array2.push('d'); + + strictEqual(_.isEqual(array1, array2), false); + + array1 = ['a', 'b', 'c']; + array1[1] = array1; + array2 = ['a', ['a', 'b', 'c'], 'c']; + + strictEqual(_.isEqual(array1, array2), false); + }); + + test('should perform comparisons between objects with circular references', 4, function() { + var object1 = {}, + object2 = {}; + + object1.a = object1; + object2.a = object2; + + strictEqual(_.isEqual(object1, object2), true); + + object1.b = 0; + object2.b = Object(0); + + strictEqual(_.isEqual(object1, object2), true); + + object1.c = Object(1); + object2.c = Object(2); + + strictEqual(_.isEqual(object1, object2), false); + + object1 = { 'a': 1, 'b': 2, 'c': 3 }; + object1.b = object1; + object2 = { 'a': 1, 'b': { 'a': 1, 'b': 2, 'c': 3 }, 'c': 3 }; + + strictEqual(_.isEqual(object1, object2), false); + }); + + test('should perform comparisons between objects with multiple circular references', 3, function() { + var array1 = [{}], + array2 = [{}]; + + (array1[0].a = array1).push(array1); + (array2[0].a = array2).push(array2); + + strictEqual(_.isEqual(array1, array2), true); + + array1[0].b = 0; + array2[0].b = Object(0); + + strictEqual(_.isEqual(array1, array2), true); + + array1[0].c = Object(1); + array2[0].c = Object(2); + + strictEqual(_.isEqual(array1, array2), false); + }); + + test('should perform comparisons between objects with complex circular references', 1, function() { + var object1 = { + 'foo': { 'b': { 'c': { 'd': {} } } }, + 'bar': { 'a': 2 } + }; + + var object2 = { + 'foo': { 'b': { 'c': { 'd': {} } } }, + 'bar': { 'a': 2 } + }; + + object1.foo.b.c.d = object1; + object1.bar.b = object1.foo.b; + + object2.foo.b.c.d = object2; + object2.bar.b = object2.foo.b; + + strictEqual(_.isEqual(object1, object2), true); + }); + + test('should perform comparisons between objects with shared property values', 1, function() { + var object1 = { + 'a': [1, 2] + }; + + var object2 = { + 'a': [1, 2], + 'b': [1, 2] + }; + + object1.b = object1.a; + + strictEqual(_.isEqual(object1, object2), true); + }); + + test('should work with `arguments` objects (test in IE < 9)', 2, function() { + var args1 = (function() { return arguments; }(1, 2, 3)), + args2 = (function() { return arguments; }(1, 2, 3)), + args3 = (function() { return arguments; }(1, 2)); + + strictEqual(_.isEqual(args1, args2), true); + strictEqual(_.isEqual(args1, args3), false); + }); + + test('should treat `arguments` objects like `Object` objects', 4, function() { + var args = (function() { return arguments; }(1, 2, 3)), + object = { '0': 1, '1': 2, '2': 3 }; + + function Foo() {} + Foo.prototype = object; + + strictEqual(_.isEqual(args, object), true); + strictEqual(_.isEqual(object, args), true); + + strictEqual(_.isEqual(args, new Foo), false); + strictEqual(_.isEqual(new Foo, args), false); + }); + + test('should perform comparisons between date objects', 4, function() { + strictEqual(_.isEqual(new Date(2012, 4, 23), new Date(2012, 4, 23)), true); + strictEqual(_.isEqual(new Date(2012, 4, 23), new Date(2013, 3, 25)), false); + strictEqual(_.isEqual(new Date(2012, 4, 23), { 'getTime': _.constant(1337756400000) }), false); + strictEqual(_.isEqual(new Date('a'), new Date('a')), false); + }); + + test('should perform comparisons between error objects', 1, function() { + var pairs = _.map([ + 'Error', + 'EvalError', + 'RangeError', + 'ReferenceError', + 'SyntaxError', + 'TypeError', + 'URIError' + ], function(type, index, errorTypes) { + var otherType = errorTypes[++index % errorTypes.length], + CtorA = root[type], + CtorB = root[otherType]; + + return [new CtorA('a'), new CtorA('a'), new CtorB('a'), new CtorB('b')]; + }); + + var expected = _.times(pairs.length, _.constant([true, false, false])); + + var actual = _.map(pairs, function(pair) { + return [_.isEqual(pair[0], pair[1]), _.isEqual(pair[0], pair[2]), _.isEqual(pair[2], pair[3])]; + }); + + deepEqual(actual, expected); + }); + + test('should perform comparisons between functions', 2, function() { + function a() { return 1 + 2; } + function b() { return 1 + 2; } + + strictEqual(_.isEqual(a, a), true); + strictEqual(_.isEqual(a, b), false); + }); + + test('should perform comparisons between regexes', 5, function() { + strictEqual(_.isEqual(/x/gim, /x/gim), true); + strictEqual(_.isEqual(/x/gim, /x/mgi), true); + strictEqual(_.isEqual(/x/gi, /x/g), false); + strictEqual(_.isEqual(/x/, /y/), false); + strictEqual(_.isEqual(/x/g, { 'global': true, 'ignoreCase': false, 'multiline': false, 'source': 'x' }), false); + }); + + test('should perform comparisons between typed arrays', 1, function() { + var pairs = _.map(typedArrays, function(type, index) { + var otherType = typedArrays[(index + 1) % typedArrays.length], + CtorA = root[type] || function(n) { this.n = n; }, + CtorB = root[otherType] || function(n) { this.n = n; }, + bufferA = root[type] ? new ArrayBuffer(8) : 8, + bufferB = root[otherType] ? new ArrayBuffer(8) : 8, + bufferC = root[otherType] ? new ArrayBuffer(16) : 16; + + return [new CtorA(bufferA), new CtorA(bufferA), new CtorB(bufferB), new CtorB(bufferC)]; + }); + + var expected = _.times(pairs.length, _.constant([true, false, false])); + + var actual = _.map(pairs, function(pair) { + return [_.isEqual(pair[0], pair[1]), _.isEqual(pair[0], pair[2]), _.isEqual(pair[2], pair[3])]; + }); + + deepEqual(actual, expected); + }); + + test('should avoid common type coercions', 9, function() { + strictEqual(_.isEqual(true, Object(false)), false); + strictEqual(_.isEqual(Object(false), Object(0)), false); + strictEqual(_.isEqual(false, Object('')), false); + strictEqual(_.isEqual(Object(36), Object('36')), false); + strictEqual(_.isEqual(0, ''), false); + strictEqual(_.isEqual(1, true), false); + strictEqual(_.isEqual(1337756400000, new Date(2012, 4, 23)), false); + strictEqual(_.isEqual('36', 36), false); + strictEqual(_.isEqual(36, '36'), false); + }); + + test('should fix the JScript `[[DontEnum]]` bug (test in IE < 9)', 1, function() { + strictEqual(_.isEqual(shadowObject, {}), false); + }); + + test('should return `false` for objects with custom `toString` methods', 1, function() { + var primitive, + object = { 'toString': function() { return primitive; } }, + values = [true, null, 1, 'a', undefined], + expected = _.map(values, _.constant(false)); + + var actual = _.map(values, function(value) { + primitive = value; + return _.isEqual(object, value); + }); + + deepEqual(actual, expected); + }); + + test('should provide the correct `customizer` arguments', 1, function() { + var argsList = [], + object1 = { 'a': [1, 2], 'b': null }, + object2 = { 'a': [1, 2], 'b': null }; + + object1.b = object2; + object2.b = object1; + + var expected = [ + [object1, object2], + [object1.a, object2.a, 'a'], + [object1.a[0], object2.a[0], 0], + [object1.a[1], object2.a[1], 1], + [object1.b, object2.b, 'b'], + [object1.b.a, object2.b.a, 'a'], + [object1.b.a[0], object2.b.a[0], 0], + [object1.b.a[1], object2.b.a[1], 1], + [object1.b.b, object2.b.b, 'b'] + ]; + + _.isEqual(object1, object2, function() { + argsList.push(slice.call(arguments)); + }); + + deepEqual(argsList, expected); + }); + + test('should set the `this` binding', 1, function() { + var actual = _.isEqual('a', 'b', function(a, b) { + return this[a] == this[b]; + }, { 'a': 1, 'b': 1 }); + + strictEqual(actual, true); + }); + + test('should handle comparisons if `customizer` returns `undefined`', 3, function() { + strictEqual(_.isEqual('a', 'a', _.noop), true); + strictEqual(_.isEqual(['a'], ['a'], _.noop), true); + strictEqual(_.isEqual({ '0': 'a' }, { '0': 'a' }, _.noop), true); + }); + + test('should not handle comparisons if `customizer` returns `true`', 3, function() { + var customizer = function(value) { + return _.isString(value) || undefined; + }; + + strictEqual(_.isEqual('a', 'b', customizer), true); + strictEqual(_.isEqual(['a'], ['b'], customizer), true); + strictEqual(_.isEqual({ '0': 'a' }, { '0': 'b' }, customizer), true); + }); + + test('should not handle comparisons if `customizer` returns `false`', 3, function() { + var customizer = function(value) { + return _.isString(value) ? false : undefined; + }; + + strictEqual(_.isEqual('a', 'a', customizer), false); + strictEqual(_.isEqual(['a'], ['a'], customizer), false); + strictEqual(_.isEqual({ '0': 'a' }, { '0': 'a' }, customizer), false); + }); + + test('should return a boolean value even if `customizer` does not', 2, function() { + var actual = _.isEqual('a', 'b', _.constant('c')); + strictEqual(actual, true); + + var values = _.without(falsey, undefined), + expected = _.map(values, _.constant(false)); + + actual = []; + _.each(values, function(value) { + actual.push(_.isEqual('a', 'a', _.constant(value))); + }); + + deepEqual(actual, expected); + }); + + test('should ensure `customizer` is a function', 1, function() { + var array = [1, 2, 3], + eq = _.partial(_.isEqual, array), + actual = _.map([array, [1, 0, 3]], eq); + + deepEqual(actual, [true, false]); + }); + + test('should work as an iteratee for `_.every`', 1, function() { + var actual = _.every([1, 1, 1], _.partial(_.isEqual, 1)); + ok(actual); + }); + + test('should treat objects created by `Object.create(null)` like any other plain object', 2, function() { + function Foo() { this.a = 1; } + Foo.prototype.constructor = null; + + var object2 = { 'a': 1 }; + strictEqual(_.isEqual(new Foo, object2), false); + + if (create) { + var object1 = create(null); + object1.a = 1; + strictEqual(_.isEqual(object1, object2), true); + } + else { + skipTest(); + } + }); + + test('should return `true` for like-objects from different documents', 4, function() { + // Ensure `_._object` is assigned (unassigned in Opera 10.00). + if (_._object) { + strictEqual(_.isEqual({ 'a': 1, 'b': 2, 'c': 3 }, _._object), true); + strictEqual(_.isEqual({ 'a': 1, 'b': 2, 'c': 2 }, _._object), false); + strictEqual(_.isEqual([1, 2, 3], _._array), true); + strictEqual(_.isEqual([1, 2, 2], _._array), false); + } + else { + skipTest(4); + } + }); + + test('should not error on DOM elements', 1, function() { + if (document) { + var element1 = document.createElement('div'), + element2 = element1.cloneNode(true); + + try { + strictEqual(_.isEqual(element1, element2), false); + } catch(e) { + ok(false, e.message); + } + } + else { + skipTest(); + } + }); + + test('should perform comparisons between wrapped values', 32, function() { + var stamp = +new Date; + + var values = [ + [[1, 2], [1, 2], [1, 2, 3]], + [true, true, false], + [new Date(stamp), new Date(stamp), new Date(stamp - 100)], + [{ 'a': 1, 'b': 2 }, { 'a': 1, 'b': 2 }, { 'a': 1, 'b': 1 }], + [1, 1, 2], + [NaN, NaN, Infinity], + [/x/, /x/, /x/i], + ['a', 'a', 'A'] + ]; + + _.each(values, function(vals) { + if (!isNpm) { + var wrapped1 = _(vals[0]), + wrapped2 = _(vals[1]), + actual = wrapped1.isEqual(wrapped2); + + strictEqual(actual, true); + strictEqual(_.isEqual(_(actual), _(true)), true); + + wrapped1 = _(vals[0]); + wrapped2 = _(vals[2]); + + actual = wrapped1.isEqual(wrapped2); + strictEqual(actual, false); + strictEqual(_.isEqual(_(actual), _(false)), true); + } + else { + skipTest(4); + } + }); }); - test('should skip the prototype property of functions (test in Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1)', 2, function() { - function Foo() {} - Foo.prototype.a = 1; + test('should perform comparisons between wrapped and non-wrapped values', 4, function() { + if (!isNpm) { + var object1 = _({ 'a': 1, 'b': 2 }), + object2 = { 'a': 1, 'b': 2 }; - strictEqual(_.isEmpty(Foo), true); + strictEqual(object1.isEqual(object2), true); + strictEqual(_.isEqual(object1, object2), true); - Foo.prototype = { 'a': 1 }; - strictEqual(_.isEmpty(Foo), true); + object1 = _({ 'a': 1, 'b': 2 }); + object2 = { 'a': 1, 'b': 1 }; + + strictEqual(object1.isEqual(object2), false); + strictEqual(_.isEqual(object1, object2), false); + } + else { + skipTest(4); + } }); test('should return an unwrapped value when implicitly chaining', 1, function() { if (!isNpm) { - strictEqual(_({}).isEmpty(), true); + strictEqual(_('a').isEqual('a'), true); } else { skipTest(); @@ -7370,682 +7353,517 @@ test('should return a wrapped value when explicitly chaining', 1, function() { if (!isNpm) { - ok(_({}).chain().isEmpty() instanceof _); + ok(_('a').chain().isEqual('a') instanceof _); } else { skipTest(); } }); - }(1, 2, 3)); + + test('should be aliased', 1, function() { + strictEqual(_.eq, _.isEqual); + }); + }()); /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.isEqual'); + QUnit.module('lodash.isError'); (function() { - test('should perform comparisons between primitive values', 1, function() { - var pairs = [ - [1, 1, true], [1, Object(1), true], [1, '1', false], [1, 2, false], - [-0, -0, true], [0, 0, true], [0, Object(0), true], [Object(0), Object(0), true], [-0, 0, true], [0, '0', false], [0, null, false], - [NaN, NaN, true], [NaN, Object(NaN), true], [Object(NaN), Object(NaN), true], [NaN, 'a', false], [NaN, Infinity, false], - ['a', 'a', true], ['a', Object('a'), true], [Object('a'), Object('a'), true], ['a', 'b', false], ['a', ['a'], false], - [true, true, true], [true, Object(true), true], [Object(true), Object(true), true], [true, 1, false], [true, 'a', false], - [false, false, true], [false, Object(false), true], [Object(false), Object(false), true], [false, 0, false], [false, '', false], - [null, null, true], [null, undefined, false], [null, {}, false], [null, '', false], - [undefined, undefined, true], [undefined, null, false], [undefined, '', false] - ]; + var args = arguments; - var expected = _.map(pairs, function(pair) { - return pair[2]; - }); + test('should return `true` for error objects', 1, function() { + var expected = _.map(errors, _.constant(true)); - var actual = _.map(pairs, function(pair) { - return _.isEqual(pair[0], pair[1]); + var actual = _.map(errors, function(error) { + return _.isError(error) === true; }); deepEqual(actual, expected); }); - test('should perform comparisons between arrays', 6, function() { - var array1 = [true, null, 1, 'a', undefined], - array2 = [true, null, 1, 'a', undefined]; - - strictEqual(_.isEqual(array1, array2), true); - - array1 = [[1, 2, 3], new Date(2012, 4, 23), /x/, { 'e': 1 }]; - array2 = [[1, 2, 3], new Date(2012, 4, 23), /x/, { 'e': 1 }]; - - strictEqual(_.isEqual(array1, array2), true); - - array1 = [1]; - array1[2] = 3; - - array2 = [1]; - array2[1] = undefined; - array2[2] = 3; - - strictEqual(_.isEqual(array1, array2), true); - - array1 = [Object(1), false, Object('a'), /x/, new Date(2012, 4, 23), ['a', 'b', [Object('c')]], { 'a': 1 }]; - array2 = [1, Object(false), 'a', /x/, new Date(2012, 4, 23), ['a', Object('b'), ['c']], { 'a': 1 }]; - - strictEqual(_.isEqual(array1, array2), true); - - array1 = [1, 2, 3]; - array2 = [3, 2, 1]; - - strictEqual(_.isEqual(array1, array2), false); - - array1 = [1, 2]; - array2 = [1, 2, 3]; - - strictEqual(_.isEqual(array1, array2), false); - }); - - test('should treat arrays with identical values but different non-numeric properties as equal', 3, function() { - var array1 = [1, 2, 3], - array2 = [1, 2, 3]; - - array1.every = array1.filter = array1.forEach = array1.indexOf = array1.lastIndexOf = array1.map = array1.some = array1.reduce = array1.reduceRight = null; - array2.concat = array2.join = array2.pop = array2.reverse = array2.shift = array2.slice = array2.sort = array2.splice = array2.unshift = null; - - strictEqual(_.isEqual(array1, array2), true); - - array1 = [1, 2, 3]; - array1.a = 1; - - array2 = [1, 2, 3]; - array2.b = 1; - - strictEqual(_.isEqual(array1, array2), true); - - array1 = /x/.exec('vwxyz'); - array2 = ['x']; - - strictEqual(_.isEqual(array1, array2), true); - }); - - test('should work with sparse arrays', 3, function() { - var array = Array(1); - - strictEqual(_.isEqual(array, Array(1)), true); - strictEqual(_.isEqual(array, [undefined]), true); - strictEqual(_.isEqual(array, Array(2)), false); - }); - - test('should perform comparisons between plain objects', 5, function() { - var object1 = { 'a': true, 'b': null, 'c': 1, 'd': 'a', 'e': undefined }, - object2 = { 'a': true, 'b': null, 'c': 1, 'd': 'a', 'e': undefined }; - - strictEqual(_.isEqual(object1, object2), true); - - object1 = { 'a': [1, 2, 3], 'b': new Date(2012, 4, 23), 'c': /x/, 'd': { 'e': 1 } }; - object2 = { 'a': [1, 2, 3], 'b': new Date(2012, 4, 23), 'c': /x/, 'd': { 'e': 1 } }; - - strictEqual(_.isEqual(object1, object2), true); - - object1 = { 'a': 1, 'b': 2, 'c': 3 }; - object2 = { 'a': 3, 'b': 2, 'c': 1 }; - - strictEqual(_.isEqual(object1, object2), false); - - object1 = { 'a': 1, 'b': 2, 'c': 3 }; - object2 = { 'd': 1, 'e': 2, 'f': 3 }; + test('should return `false` for non error objects', 12, function() { + var expected = _.map(falsey, _.constant(false)); - strictEqual(_.isEqual(object1, object2), false); + var actual = _.map(falsey, function(value, index) { + return index ? _.isError(value) : _.isError(); + }); - object1 = { 'a': 1, 'b': 2 }; - object2 = { 'a': 1, 'b': 2, 'c': 3 }; + deepEqual(actual, expected); - strictEqual(_.isEqual(object1, object2), false); + strictEqual(_.isError(args), false); + strictEqual(_.isError([1, 2, 3]), false); + strictEqual(_.isError(true), false); + strictEqual(_.isError(new Date), false); + strictEqual(_.isError(_), false); + strictEqual(_.isError(slice), false); + strictEqual(_.isError({ 'a': 1 }), false); + strictEqual(_.isError(1), false); + strictEqual(_.isError(NaN), false); + strictEqual(_.isError(/x/), false); + strictEqual(_.isError('a'), false); }); - test('should perform comparisons of nested objects', 1, function() { - var object1 = { - 'a': [1, 2, 3], - 'b': true, - 'c': Object(1), - 'd': 'a', - 'e': { - 'f': ['a', Object('b'), 'c'], - 'g': Object(false), - 'h': new Date(2012, 4, 23), - 'i': _.noop, - 'j': 'a' - } - }; - - var object2 = { - 'a': [1, Object(2), 3], - 'b': Object(true), - 'c': 1, - 'd': Object('a'), - 'e': { - 'f': ['a', 'b', 'c'], - 'g': false, - 'h': new Date(2012, 4, 23), - 'i': _.noop, - 'j': 'a' - } - }; - - strictEqual(_.isEqual(object1, object2), true); - }); + test('should work with an error object from another realm', 1, function() { + if (_._object) { + var expected = _.map(_._errors, _.constant(true)); - test('should perform comparisons between object instances', 4, function() { - function Foo() { this.value = 1; } - Foo.prototype.value = 1; + var actual = _.map(_._errors, function(error) { + return _.isError(error) === true; + }); - function Bar() { - this.value = 1; + deepEqual(actual, expected); + } + else { + skipTest(); } - Bar.prototype.value = 2; - - strictEqual(_.isEqual(new Foo, new Foo), true); - strictEqual(_.isEqual(new Foo, new Bar), false); - strictEqual(_.isEqual({ 'value': 1 }, new Foo), false); - strictEqual(_.isEqual({ 'value': 2 }, new Bar), false); - }); - - test('should perform comparisons between objects with constructor properties', 5, function() { - strictEqual(_.isEqual({ 'constructor': 1 }, { 'constructor': 1 }), true); - strictEqual(_.isEqual({ 'constructor': 1 }, { 'constructor': '1' }), false); - strictEqual(_.isEqual({ 'constructor': [1] }, { 'constructor': [1] }), true); - strictEqual(_.isEqual({ 'constructor': [1] }, { 'constructor': ['1'] }), false); - strictEqual(_.isEqual({ 'constructor': Object }, {}), false); }); + }(1, 2, 3)); - test('should perform comparisons between arrays with circular references', 4, function() { - var array1 = [], - array2 = []; - - array1.push(array1); - array2.push(array2); - - strictEqual(_.isEqual(array1, array2), true); - - array1.push('b'); - array2.push('b'); + /*--------------------------------------------------------------------------*/ - strictEqual(_.isEqual(array1, array2), true); + QUnit.module('lodash.isFinite'); - array1.push('c'); - array2.push('d'); + (function() { + var args = arguments; - strictEqual(_.isEqual(array1, array2), false); + test('should return `true` for finite values', 1, function() { + var values = [0, 1, 3.14, -1], + expected = _.map(values, _.constant(true)); - array1 = ['a', 'b', 'c']; - array1[1] = array1; - array2 = ['a', ['a', 'b', 'c'], 'c']; + var actual = _.map(values, function(value) { + return _.isFinite(value); + }); - strictEqual(_.isEqual(array1, array2), false); + deepEqual(actual, expected); }); - test('should perform comparisons between objects with circular references', 4, function() { - var object1 = {}, - object2 = {}; + test('should return `false` for non-finite values', 9, function() { + var values = [NaN, Infinity, -Infinity, Object(1)], + expected = _.map(values, _.constant(false)); - object1.a = object1; - object2.a = object2; + var actual = _.map(values, function(value) { + return _.isFinite(value); + }); - strictEqual(_.isEqual(object1, object2), true); + deepEqual(actual, expected); - object1.b = 0; - object2.b = Object(0); + strictEqual(_.isFinite(args), false); + strictEqual(_.isFinite([1, 2, 3]), false); + strictEqual(_.isFinite(true), false); + strictEqual(_.isFinite(new Date), false); + strictEqual(_.isFinite(new Error), false); + strictEqual(_.isFinite({ 'a': 1 }), false); + strictEqual(_.isFinite(/x/), false); + strictEqual(_.isFinite('a'), false); + }); - strictEqual(_.isEqual(object1, object2), true); + test('should return `false` for non-numeric values', 1, function() { + var values = [undefined, [], true, new Date, new Error, '', ' ', '2px'], + expected = _.map(values, _.constant(false)); - object1.c = Object(1); - object2.c = Object(2); + var actual = _.map(values, function(value) { + return _.isFinite(value); + }); - strictEqual(_.isEqual(object1, object2), false); + deepEqual(actual, expected); + }); - object1 = { 'a': 1, 'b': 2, 'c': 3 }; - object1.b = object1; - object2 = { 'a': 1, 'b': { 'a': 1, 'b': 2, 'c': 3 }, 'c': 3 }; + test('should return `false` for numeric string values', 1, function() { + var values = ['2', '0', '08'], + expected = _.map(values, _.constant(false)); - strictEqual(_.isEqual(object1, object2), false); + var actual = _.map(values, function(value) { + return _.isFinite(value); + }); + + deepEqual(actual, expected); }); + }(1, 2, 3)); - test('should perform comparisons between objects with multiple circular references', 3, function() { - var array1 = [{}], - array2 = [{}]; + /*--------------------------------------------------------------------------*/ - (array1[0].a = array1).push(array1); - (array2[0].a = array2).push(array2); + QUnit.module('lodash.isFunction'); - strictEqual(_.isEqual(array1, array2), true); + (function() { + var args = arguments; - array1[0].b = 0; - array2[0].b = Object(0); + test('should return `true` for functions', 2, function() { + strictEqual(_.isFunction(_), true); + strictEqual(_.isFunction(slice), true); + }); - strictEqual(_.isEqual(array1, array2), true); + test('should return `true` for typed array constructors', 1, function() { + var expected = _.map(typedArrays, function(type) { + return objToString.call(root[type]) == funcTag; + }); - array1[0].c = Object(1); - array2[0].c = Object(2); + var actual = _.map(typedArrays, function(type) { + return _.isFunction(root[type]); + }); - strictEqual(_.isEqual(array1, array2), false); + deepEqual(actual, expected); }); - test('should perform comparisons between objects with complex circular references', 1, function() { - var object1 = { - 'foo': { 'b': { 'c': { 'd': {} } } }, - 'bar': { 'a': 2 } - }; - - var object2 = { - 'foo': { 'b': { 'c': { 'd': {} } } }, - 'bar': { 'a': 2 } - }; + test('should return `false` for non-functions', 11, function() { + var expected = _.map(falsey, _.constant(false)); - object1.foo.b.c.d = object1; - object1.bar.b = object1.foo.b; + var actual = _.map(falsey, function(value, index) { + return index ? _.isFunction(value) : _.isFunction(); + }); - object2.foo.b.c.d = object2; - object2.bar.b = object2.foo.b; + deepEqual(actual, expected); - strictEqual(_.isEqual(object1, object2), true); + strictEqual(_.isFunction(args), false); + strictEqual(_.isFunction([1, 2, 3]), false); + strictEqual(_.isFunction(true), false); + strictEqual(_.isFunction(new Date), false); + strictEqual(_.isFunction(new Error), false); + strictEqual(_.isFunction({ 'a': 1 }), false); + strictEqual(_.isFunction(1), false); + strictEqual(_.isFunction(NaN), false); + strictEqual(_.isFunction(/x/), false); + strictEqual(_.isFunction('a'), false); }); - test('should perform comparisons between objects with shared property values', 1, function() { - var object1 = { - 'a': [1, 2] - }; + test('should work with host objects in IE 8 document mode (test in IE 11)', 2, function() { + // Trigger a Chakra JIT bug. + // See https://github.com/jashkenas/underscore/issues/1621. + _.each([body, xml], function(object) { + if (object) { + _.times(100, _.isFunction); + strictEqual(_.isFunction(object), false); + } + else { + skipTest(); + } + }); + }); - var object2 = { - 'a': [1, 2], - 'b': [1, 2] - }; + test('should work with a function from another realm', 1, function() { + if (_._object) { + strictEqual(_.isFunction(_._function), true); + } + else { + skipTest(); + } + }); + }(1, 2, 3)); - object1.b = object1.a; + /*--------------------------------------------------------------------------*/ - strictEqual(_.isEqual(object1, object2), true); - }); + QUnit.module('lodash.isMatch'); - test('should work with `arguments` objects (test in IE < 9)', 2, function() { - var args1 = (function() { return arguments; }(1, 2, 3)), - args2 = (function() { return arguments; }(1, 2, 3)), - args3 = (function() { return arguments; }(1, 2)); + (function() { + test('should perform a deep comparison between `object` and `source`', 5, function() { + var object = { 'a': 1, 'b': 2, 'c': 3 }; + strictEqual(_.isMatch(object, { 'a': 1 }), true); + strictEqual(_.isMatch(object, { 'b': 1 }), false); + strictEqual(_.isMatch(object, { 'a': 1, 'c': 3 }), true); + strictEqual(_.isMatch(object, { 'c': 3, 'd': 4 }), false); - strictEqual(_.isEqual(args1, args2), true); - strictEqual(_.isEqual(args1, args3), false); + object = { 'a': { 'b': { 'c': 1, 'd': 2 }, 'e': 3 }, 'f': 4 }; + strictEqual(_.isMatch(object, { 'a': { 'b': { 'c': 1 } } }), true); }); - test('should treat `arguments` objects like `Object` objects', 4, function() { - var args = (function() { return arguments; }(1, 2, 3)), - object = { '0': 1, '1': 2, '2': 3 }; + test('should match inherited `object` properties', 1, function() { + function Foo() { this.a = 1; } + Foo.prototype.b = 2; - function Foo() {} - Foo.prototype = object; + strictEqual(_.isMatch({ 'a': new Foo }, { 'a': { 'b': 2 } }), true); + }); - strictEqual(_.isEqual(args, object), true); - strictEqual(_.isEqual(object, args), true); + test('should match `-0` as `0`', 2, function() { + var object1 = { 'a': -0 }, + object2 = { 'a': 0 }; - strictEqual(_.isEqual(args, new Foo), false); - strictEqual(_.isEqual(new Foo, args), false); + strictEqual(_.isMatch(object1, object2), true); + strictEqual(_.isMatch(object2, object1), true); }); - test('should perform comparisons between date objects', 4, function() { - strictEqual(_.isEqual(new Date(2012, 4, 23), new Date(2012, 4, 23)), true); - strictEqual(_.isEqual(new Date(2012, 4, 23), new Date(2013, 3, 25)), false); - strictEqual(_.isEqual(new Date(2012, 4, 23), { 'getTime': _.constant(1337756400000) }), false); - strictEqual(_.isEqual(new Date('a'), new Date('a')), false); - }); + test('should not match by inherited `source` properties', 1, function() { + function Foo() { this.a = 1; } + Foo.prototype.b = 2; - test('should perform comparisons between error objects', 1, function() { - var pairs = _.map([ - 'Error', - 'EvalError', - 'RangeError', - 'ReferenceError', - 'SyntaxError', - 'TypeError', - 'URIError' - ], function(type, index, errorTypes) { - var otherType = errorTypes[++index % errorTypes.length], - CtorA = root[type], - CtorB = root[otherType]; + var objects = [{ 'a': 1 }, { 'a': 1, 'b': 2 }], + source = new Foo, + expected = _.map(objects, _.constant(true)); - return [new CtorA('a'), new CtorA('a'), new CtorB('a'), new CtorB('b')]; + var actual = _.map(objects, function(object) { + return _.isMatch(object, source); }); - var expected = _.times(pairs.length, _.constant([true, false, false])); + deepEqual(actual, expected); + }); - var actual = _.map(pairs, function(pair) { - return [_.isEqual(pair[0], pair[1]), _.isEqual(pair[0], pair[2]), _.isEqual(pair[2], pair[3])]; + test('should return `false` when `object` is nullish', 1, function() { + var values = [null, undefined], + expected = _.map(values, _.constant(false)), + source = { 'a': 1 }; + + var actual = _.map(values, function(value) { + try { + return _.isMatch(value, source); + } catch(e) {} }); deepEqual(actual, expected); }); - test('should perform comparisons between functions', 2, function() { - function a() { return 1 + 2; } - function b() { return 1 + 2; } + test('should return `true` when comparing an empty `source`', 1, function() { + var object = { 'a': 1 }, + expected = _.map(empties, _.constant(true)); - strictEqual(_.isEqual(a, a), true); - strictEqual(_.isEqual(a, b), false); - }); + var actual = _.map(empties, function(value) { + return _.isMatch(object, value); + }); - test('should perform comparisons between regexes', 5, function() { - strictEqual(_.isEqual(/x/gim, /x/gim), true); - strictEqual(_.isEqual(/x/gim, /x/mgi), true); - strictEqual(_.isEqual(/x/gi, /x/g), false); - strictEqual(_.isEqual(/x/, /y/), false); - strictEqual(_.isEqual(/x/g, { 'global': true, 'ignoreCase': false, 'multiline': false, 'source': 'x' }), false); + deepEqual(actual, expected); }); - test('should perform comparisons between typed arrays', 1, function() { - var pairs = _.map(typedArrays, function(type, index) { - var otherType = typedArrays[(index + 1) % typedArrays.length], - CtorA = root[type] || function(n) { this.n = n; }, - CtorB = root[otherType] || function(n) { this.n = n; }, - bufferA = root[type] ? new ArrayBuffer(8) : 8, - bufferB = root[otherType] ? new ArrayBuffer(8) : 8, - bufferC = root[otherType] ? new ArrayBuffer(16) : 16; + test('should compare a variety of `source` property values', 2, function() { + var object1 = { 'a': false, 'b': true, 'c': '3', 'd': 4, 'e': [5], 'f': { 'g': 6 } }, + object2 = { 'a': 0, 'b': 1, 'c': 3, 'd': '4', 'e': ['5'], 'f': { 'g': '6' } }; + + strictEqual(_.isMatch(object1, object1), true); + strictEqual(_.isMatch(object1, object2), false); + }); - return [new CtorA(bufferA), new CtorA(bufferA), new CtorB(bufferB), new CtorB(bufferC)]; - }); + test('should work with a function for `source`', 1, function() { + function source() {} - var expected = _.times(pairs.length, _.constant([true, false, false])); + source.a = 1; + source.b = function() {}; + source.c = 3; - var actual = _.map(pairs, function(pair) { - return [_.isEqual(pair[0], pair[1]), _.isEqual(pair[0], pair[2]), _.isEqual(pair[2], pair[3])]; + var objects = [{ 'a': 1 }, { 'a': 1, 'b': source.b, 'c': 3 }]; + + var actual = _.map(objects, function(object) { + return _.isMatch(object, source); }); - deepEqual(actual, expected); + deepEqual(actual, [false, true]); }); - test('should avoid common type coercions', 9, function() { - strictEqual(_.isEqual(true, Object(false)), false); - strictEqual(_.isEqual(Object(false), Object(0)), false); - strictEqual(_.isEqual(false, Object('')), false); - strictEqual(_.isEqual(Object(36), Object('36')), false); - strictEqual(_.isEqual(0, ''), false); - strictEqual(_.isEqual(1, true), false); - strictEqual(_.isEqual(1337756400000, new Date(2012, 4, 23)), false); - strictEqual(_.isEqual('36', 36), false); - strictEqual(_.isEqual(36, '36'), false); + test('should work with strings', 4, function() { + var pairs = [['xo', Object('x')], [Object('xo'), 'x']]; + + _.each(pairs, function(pair) { + strictEqual(_.isMatch(pair[0], pair[1]), true); + strictEqual(_.isMatch(pair[1], pair[0]), false); + }); }); - test('should fix the JScript `[[DontEnum]]` bug (test in IE < 9)', 1, function() { - strictEqual(_.isEqual(shadowObject, {}), false); + test('should return `true` when comparing a `source` of empty arrays and objects', 1, function() { + var objects = [{ 'a': [1], 'b': { 'c': 1 } }, { 'a': [2, 3], 'b': { 'd': 2 } }], + source = { 'a': [], 'b': {} }; + + var actual = _.filter(objects, function(object) { + return _.isMatch(object, source); + }); + + deepEqual(actual, objects); }); - test('should return `false` for objects with custom `toString` methods', 1, function() { - var primitive, - object = { 'toString': function() { return primitive; } }, - values = [true, null, 1, 'a', undefined], - expected = _.map(values, _.constant(false)); + test('should return `true` when comparing an empty `source` to a nullish `object`', 1, function() { + var values = [null, undefined], + expected = _.map(values, _.constant(true)), + source = {}; var actual = _.map(values, function(value) { - primitive = value; - return _.isEqual(object, value); + try { + return _.isMatch(value, source); + } catch(e) {} }); deepEqual(actual, expected); }); - test('should provide the correct `customizer` arguments', 1, function() { - var argsList = [], - object1 = { 'a': [1, 2], 'b': null }, - object2 = { 'a': [1, 2], 'b': null }; + test('should search arrays of `source` for values', 3, function() { + var objects = [{ 'a': ['b'] }, { 'a': ['c', 'd'] }], + source = { 'a': ['d'] }, + predicate = function(object) { return _.isMatch(object, source); }, + actual = _.filter(objects, predicate); - object1.b = object2; - object2.b = object1; + deepEqual(actual, [objects[1]]); - var expected = [ - [object1, object2], - [object1.a, object2.a, 'a'], - [object1.a[0], object2.a[0], 0], - [object1.a[1], object2.a[1], 1], - [object1.b, object2.b, 'b'], - [object1.b.a, object2.b.a, 'a'], - [object1.b.a[0], object2.b.a[0], 0], - [object1.b.a[1], object2.b.a[1], 1], - [object1.b.b, object2.b.b, 'b'] - ]; + source = { 'a': ['b', 'd'] }; + actual = _.filter(objects, predicate); - _.isEqual(object1, object2, function() { - argsList.push(slice.call(arguments)); - }); + deepEqual(actual, []); - deepEqual(argsList, expected); + source = { 'a': ['d', 'b'] }; + actual = _.filter(objects, predicate); + deepEqual(actual, []); }); - test('should set the `this` binding', 1, function() { - var actual = _.isEqual('a', 'b', function(a, b) { - return this[a] == this[b]; - }, { 'a': 1, 'b': 1 }); - - strictEqual(actual, true); - }); + test('should perform a partial comparison of all objects within arrays of `source`', 1, function() { + var source = { 'a': [{ 'b': 1 }, { 'b': 4, 'c': 5 }] }; - test('should handle comparisons if `customizer` returns `undefined`', 3, function() { - strictEqual(_.isEqual('a', 'a', _.noop), true); - strictEqual(_.isEqual(['a'], ['a'], _.noop), true); - strictEqual(_.isEqual({ '0': 'a' }, { '0': 'a' }, _.noop), true); - }); + var objects = [ + { 'a': [{ 'b': 1, 'c': 2 }, { 'b': 4, 'c': 5, 'd': 6 }] }, + { 'a': [{ 'b': 1, 'c': 2 }, { 'b': 4, 'c': 6, 'd': 7 }] } + ]; - test('should not handle comparisons if `customizer` returns `true`', 3, function() { - var customizer = function(value) { - return _.isString(value) || undefined; - }; + var actual = _.filter(objects, function(object) { + return _.isMatch(object, source); + }); - strictEqual(_.isEqual('a', 'b', customizer), true); - strictEqual(_.isEqual(['a'], ['b'], customizer), true); - strictEqual(_.isEqual({ '0': 'a' }, { '0': 'b' }, customizer), true); + deepEqual(actual, [objects[0]]); }); - test('should not handle comparisons if `customizer` returns `false`', 3, function() { - var customizer = function(value) { - return _.isString(value) ? false : undefined; - }; + test('should handle a `source` with `undefined` values', 3, function() { + var objects = [{ 'a': 1 }, { 'a': 1, 'b': 1 }, { 'a': 1, 'b': undefined }], + source = { 'b': undefined }, + predicate = function(object) { return _.isMatch(object, source); }, + actual = _.map(objects, predicate), + expected = [false, false, true]; - strictEqual(_.isEqual('a', 'a', customizer), false); - strictEqual(_.isEqual(['a'], ['a'], customizer), false); - strictEqual(_.isEqual({ '0': 'a' }, { '0': 'a' }, customizer), false); - }); + deepEqual(actual, expected); - test('should return a boolean value even if `customizer` does not', 2, function() { - var actual = _.isEqual('a', 'b', _.constant('c')); - strictEqual(actual, true); + source = { 'a': 1, 'b': undefined }; + actual = _.map(objects, predicate); - var values = _.without(falsey, undefined), - expected = _.map(values, _.constant(false)); + deepEqual(actual, expected); - actual = []; - _.each(values, function(value) { - actual.push(_.isEqual('a', 'a', _.constant(value))); - }); + objects = [{ 'a': { 'b': 1 } }, { 'a':{ 'b':1, 'c': 1 } }, { 'a': { 'b': 1, 'c': undefined } }]; + source = { 'a': { 'c': undefined } }; + actual = _.map(objects, predicate); deepEqual(actual, expected); }); - test('should ensure `customizer` is a function', 1, function() { - var array = [1, 2, 3], - eq = _.partial(_.isEqual, array), - actual = _.map([array, [1, 0, 3]], eq); - - deepEqual(actual, [true, false]); - }); + test('should match properties when `value` is a function', 1, function() { + function Foo() {} + Foo.a = { 'b': 1, 'c': 2 }; - test('should work as an iteratee for `_.every`', 1, function() { - var actual = _.every([1, 1, 1], _.partial(_.isEqual, 1)); - ok(actual); + var matches = _.matches({ 'a': { 'b': 1 } }); + strictEqual(matches(Foo), true); }); - test('should treat objects created by `Object.create(null)` like any other plain object', 2, function() { - function Foo() { this.a = 1; } - Foo.prototype.constructor = null; + test('should match properties when `value` is not a plain object', 1, function() { + function Foo(object) { _.assign(this, object); } - var object2 = { 'a': 1 }; - strictEqual(_.isEqual(new Foo, object2), false); + var object = new Foo({ 'a': new Foo({ 'b': 1, 'c': 2 }) }), + matches = _.matches({ 'a': { 'b': 1 } }); - if (create) { - var object1 = create(null); - object1.a = 1; - strictEqual(_.isEqual(object1, object2), true); - } - else { - skipTest(); - } + strictEqual(matches(object), true); }); - test('should return `true` for like-objects from different documents', 4, function() { - // Ensure `_._object` is assigned (unassigned in Opera 10.00). - if (_._object) { - strictEqual(_.isEqual({ 'a': 1, 'b': 2, 'c': 3 }, _._object), true); - strictEqual(_.isEqual({ 'a': 1, 'b': 2, 'c': 2 }, _._object), false); - strictEqual(_.isEqual([1, 2, 3], _._array), true); - strictEqual(_.isEqual([1, 2, 2], _._array), false); - } - else { - skipTest(4); - } - }); + test('should match problem JScript properties (test in IE < 9)', 1, function() { + var objects = [{}, shadowObject]; - test('should not error on DOM elements', 1, function() { - if (document) { - var element1 = document.createElement('div'), - element2 = element1.cloneNode(true); + var actual = _.map(objects, function(object) { + return _.isMatch(object, shadowObject); + }); - try { - strictEqual(_.isEqual(element1, element2), false); - } catch(e) { - ok(false, e.message); - } - } - else { - skipTest(); - } + deepEqual(actual, [false, true]); }); - test('should perform comparisons between wrapped values', 32, function() { - var stamp = +new Date; + test('should provide the correct `customizer` arguments', 1, function() { + var argsList = [], + object1 = { 'a': [1, 2], 'b': null }, + object2 = { 'a': [1, 2], 'b': null }; - var values = [ - [[1, 2], [1, 2], [1, 2, 3]], - [true, true, false], - [new Date(stamp), new Date(stamp), new Date(stamp - 100)], - [{ 'a': 1, 'b': 2 }, { 'a': 1, 'b': 2 }, { 'a': 1, 'b': 1 }], - [1, 1, 2], - [NaN, NaN, Infinity], - [/x/, /x/, /x/i], - ['a', 'a', 'A'] + object1.b = object2; + object2.b = object1; + + var expected = [ + [object1.a, object2.a, 'a'], + [object1.a[0], object2.a[0], 0], + [object1.a[1], object2.a[1], 1], + [object1.b, object2.b, 'b'], + [object1.b.a, object2.b.a, 'a'], + [object1.b.a[0], object2.b.a[0], 0], + [object1.b.a[1], object2.b.a[1], 1], + [object1.b.b, object2.b.b, 'b'], + [object1.b.b.a, object2.b.b.a, 'a'], + [object1.b.b.a[0], object2.b.b.a[0], 0], + [object1.b.b.a[1], object2.b.b.a[1], 1], + [object1.b.b.b, object2.b.b.b, 'b'] ]; - _.each(values, function(vals) { - if (!isNpm) { - var wrapped1 = _(vals[0]), - wrapped2 = _(vals[1]), - actual = wrapped1.isEqual(wrapped2); + _.isMatch(object1, object2, function() { + argsList.push(slice.call(arguments)); + }); + + deepEqual(argsList, expected); + }); - strictEqual(actual, true); - strictEqual(_.isEqual(_(actual), _(true)), true); + test('should set the `this` binding', 1, function() { + var actual = _.isMatch({ 'a': 1 }, { 'a': 2 }, function(a, b) { + return this[a] == this[b]; + }, { 'a': 1, 'b': 1 }); - wrapped1 = _(vals[0]); - wrapped2 = _(vals[2]); + strictEqual(actual, true); + }); - actual = wrapped1.isEqual(wrapped2); - strictEqual(actual, false); - strictEqual(_.isEqual(_(actual), _(false)), true); - } - else { - skipTest(4); - } - }); + test('should handle comparisons if `customizer` returns `undefined`', 1, function() { + strictEqual(_.isMatch({ 'a': 1 }, { 'a': 1 }, _.noop), true); }); - test('should perform comparisons between wrapped and non-wrapped values', 4, function() { - if (!isNpm) { - var object1 = _({ 'a': 1, 'b': 2 }), - object2 = { 'a': 1, 'b': 2 }; + test('should return a boolean value even if `customizer` does not', 2, function() { + var object = { 'a': 1 }, + actual = _.isMatch(object, { 'a': 1 }, _.constant('a')); - strictEqual(object1.isEqual(object2), true); - strictEqual(_.isEqual(object1, object2), true); + strictEqual(actual, true); - object1 = _({ 'a': 1, 'b': 2 }); - object2 = { 'a': 1, 'b': 1 }; + var expected = _.map(falsey, _.constant(false)); - strictEqual(object1.isEqual(object2), false); - strictEqual(_.isEqual(object1, object2), false); - } - else { - skipTest(4); - } - }); + actual = []; + _.each(falsey, function(value) { + actual.push(_.isMatch(object, { 'a': 2 }, _.constant(value))); + }); - test('should return an unwrapped value when implicitly chaining', 1, function() { - if (!isNpm) { - strictEqual(_('a').isEqual('a'), true); - } - else { - skipTest(); - } + deepEqual(actual, expected); }); - test('should return a wrapped value when explicitly chaining', 1, function() { - if (!isNpm) { - ok(_('a').chain().isEqual('a') instanceof _); - } - else { - skipTest(); - } - }); + test('should ensure `customizer` is a function', 1, function() { + var object = { 'a': 1 }, + matches = _.partial(_.isMatch, object), + actual = _.map([object, { 'a': 2 }], matches); - test('should be aliased', 1, function() { - strictEqual(_.eq, _.isEqual); + deepEqual(actual, [true, false]); }); }()); /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.isError'); + QUnit.module('lodash.isNaN'); (function() { var args = arguments; - test('should return `true` for error objects', 1, function() { - var expected = _.map(errors, _.constant(true)); - - var actual = _.map(errors, function(error) { - return _.isError(error) === true; - }); - - deepEqual(actual, expected); + test('should return `true` for NaNs', 2, function() { + strictEqual(_.isNaN(NaN), true); + strictEqual(_.isNaN(Object(NaN)), true); }); - test('should return `false` for non error objects', 12, function() { - var expected = _.map(falsey, _.constant(false)); + test('should return `false` for non-NaNs', 12, function() { + var expected = _.map(falsey, function(value) { return value !== value; }); var actual = _.map(falsey, function(value, index) { - return index ? _.isError(value) : _.isError(); + return index ? _.isNaN(value) : _.isNaN(); }); deepEqual(actual, expected); - strictEqual(_.isError(args), false); - strictEqual(_.isError([1, 2, 3]), false); - strictEqual(_.isError(true), false); - strictEqual(_.isError(new Date), false); - strictEqual(_.isError(_), false); - strictEqual(_.isError(slice), false); - strictEqual(_.isError({ 'a': 1 }), false); - strictEqual(_.isError(1), false); - strictEqual(_.isError(NaN), false); - strictEqual(_.isError(/x/), false); - strictEqual(_.isError('a'), false); + strictEqual(_.isNaN(args), false); + strictEqual(_.isNaN([1, 2, 3]), false); + strictEqual(_.isNaN(true), false); + strictEqual(_.isNaN(new Date), false); + strictEqual(_.isNaN(new Error), false); + strictEqual(_.isNaN(_), false); + strictEqual(_.isNaN(slice), false); + strictEqual(_.isNaN({ 'a': 1 }), false); + strictEqual(_.isNaN(1), false); + strictEqual(_.isNaN(/x/), false); + strictEqual(_.isNaN('a'), false); }); - test('should work with an error object from another realm', 1, function() { + test('should work with `NaN` from another realm', 1, function() { if (_._object) { - var expected = _.map(_._errors, _.constant(true)); - - var actual = _.map(_._errors, function(error) { - return _.isError(error) === true; - }); - - deepEqual(actual, expected); + strictEqual(_.isNaN(_._nan), true); } else { skipTest(); @@ -8055,127 +7873,104 @@ /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.isFinite'); + QUnit.module('lodash.isNative'); (function() { var args = arguments; - test('should return `true` for finite values', 1, function() { - var values = [0, 1, 3.14, -1], - expected = _.map(values, _.constant(true)); - - var actual = _.map(values, function(value) { - return _.isFinite(value); + test('should return `true` for native methods', 6, function() { + _.each([Array, create, root.encodeURI, slice, Uint8Array], function(func) { + if (func) { + strictEqual(_.isNative(func), true); + } + else { + skipTest(); + } }); - deepEqual(actual, expected); + if (body) { + strictEqual(_.isNative(body.cloneNode), true); + } + else { + skipTest(); + } }); - test('should return `false` for non-finite values', 9, function() { - var values = [NaN, Infinity, -Infinity, Object(1)], - expected = _.map(values, _.constant(false)); + test('should return `false` for non-native methods', 12, function() { + var expected = _.map(falsey, _.constant(false)); - var actual = _.map(values, function(value) { - return _.isFinite(value); + var actual = _.map(falsey, function(value, index) { + return index ? _.isNative(value) : _.isNative(); }); deepEqual(actual, expected); - strictEqual(_.isFinite(args), false); - strictEqual(_.isFinite([1, 2, 3]), false); - strictEqual(_.isFinite(true), false); - strictEqual(_.isFinite(new Date), false); - strictEqual(_.isFinite(new Error), false); - strictEqual(_.isFinite({ 'a': 1 }), false); - strictEqual(_.isFinite(/x/), false); - strictEqual(_.isFinite('a'), false); - }); - - test('should return `false` for non-numeric values', 1, function() { - var values = [undefined, [], true, new Date, new Error, '', ' ', '2px'], - expected = _.map(values, _.constant(false)); - - var actual = _.map(values, function(value) { - return _.isFinite(value); - }); - - deepEqual(actual, expected); + strictEqual(_.isNative(args), false); + strictEqual(_.isNative([1, 2, 3]), false); + strictEqual(_.isNative(true), false); + strictEqual(_.isNative(new Date), false); + strictEqual(_.isNative(new Error), false); + strictEqual(_.isNative(_), false); + strictEqual(_.isNative({ 'a': 1 }), false); + strictEqual(_.isNative(1), false); + strictEqual(_.isNative(NaN), false); + strictEqual(_.isNative(/x/), false); + strictEqual(_.isNative('a'), false); }); - test('should return `false` for numeric string values', 1, function() { - var values = ['2', '0', '08'], - expected = _.map(values, _.constant(false)); - - var actual = _.map(values, function(value) { - return _.isFinite(value); - }); - - deepEqual(actual, expected); + test('should work with native functions from another realm', 2, function() { + if (_._element) { + strictEqual(_.isNative(_._element.cloneNode), true); + } + else { + skipTest(); + } + if (_._object) { + strictEqual(_.isNative(_._object.valueOf), true); + } + else { + skipTest(); + } }); }(1, 2, 3)); /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.isFunction'); + QUnit.module('lodash.isNull'); (function() { var args = arguments; - - test('should return `true` for functions', 2, function() { - strictEqual(_.isFunction(_), true); - strictEqual(_.isFunction(slice), true); - }); - - test('should return `true` for typed array constructors', 1, function() { - var expected = _.map(typedArrays, function(type) { - return objToString.call(root[type]) == funcTag; - }); - - var actual = _.map(typedArrays, function(type) { - return _.isFunction(root[type]); - }); - - deepEqual(actual, expected); - }); - - test('should return `false` for non-functions', 11, function() { - var expected = _.map(falsey, _.constant(false)); - - var actual = _.map(falsey, function(value, index) { - return index ? _.isFunction(value) : _.isFunction(); - }); - - deepEqual(actual, expected); - - strictEqual(_.isFunction(args), false); - strictEqual(_.isFunction([1, 2, 3]), false); - strictEqual(_.isFunction(true), false); - strictEqual(_.isFunction(new Date), false); - strictEqual(_.isFunction(new Error), false); - strictEqual(_.isFunction({ 'a': 1 }), false); - strictEqual(_.isFunction(1), false); - strictEqual(_.isFunction(NaN), false); - strictEqual(_.isFunction(/x/), false); - strictEqual(_.isFunction('a'), false); - }); - - test('should work with host objects in IE 8 document mode (test in IE 11)', 2, function() { - // Trigger a Chakra JIT bug. - // See https://github.com/jashkenas/underscore/issues/1621. - _.each([body, xml], function(object) { - if (object) { - _.times(100, _.isFunction); - strictEqual(_.isFunction(object), false); - } - else { - skipTest(); - } + + test('should return `true` for nulls', 1, function() { + strictEqual(_.isNull(null), true); + }); + + test('should return `false` for non-nulls', 13, function() { + var expected = _.map(falsey, function(value) { return value === null; }); + + var actual = _.map(falsey, function(value, index) { + return index ? _.isNull(value) : _.isNull(); }); + + deepEqual(actual, expected); + + strictEqual(_.isNull(args), false); + strictEqual(_.isNull([1, 2, 3]), false); + strictEqual(_.isNull(true), false); + strictEqual(_.isNull(new Date), false); + strictEqual(_.isNull(new Error), false); + strictEqual(_.isNull(_), false); + strictEqual(_.isNull(slice), false); + strictEqual(_.isNull({ 'a': 1 }), false); + strictEqual(_.isNull(1), false); + strictEqual(_.isNull(NaN), false); + strictEqual(_.isNull(/x/), false); + strictEqual(_.isNull('a'), false); }); - test('should work with a function from another realm', 1, function() { + test('should work with nulls from another realm', 1, function() { if (_._object) { - strictEqual(_.isFunction(_._function), true); + strictEqual(_.isNull(_._null), true); } else { skipTest(); @@ -8185,318 +7980,397 @@ /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.isMatch'); + QUnit.module('lodash.isNumber'); (function() { - test('should perform a deep comparison between `object` and `source`', 5, function() { - var object = { 'a': 1, 'b': 2, 'c': 3 }; - strictEqual(_.isMatch(object, { 'a': 1 }), true); - strictEqual(_.isMatch(object, { 'b': 1 }), false); - strictEqual(_.isMatch(object, { 'a': 1, 'c': 3 }), true); - strictEqual(_.isMatch(object, { 'c': 3, 'd': 4 }), false); + var args = arguments; - object = { 'a': { 'b': { 'c': 1, 'd': 2 }, 'e': 3 }, 'f': 4 }; - strictEqual(_.isMatch(object, { 'a': { 'b': { 'c': 1 } } }), true); + test('should return `true` for numbers', 3, function() { + strictEqual(_.isNumber(0), true); + strictEqual(_.isNumber(Object(0)), true); + strictEqual(_.isNumber(NaN), true); }); - test('should match inherited `object` properties', 1, function() { - function Foo() { this.a = 1; } - Foo.prototype.b = 2; + test('should return `false` for non-numbers', 11, function() { + var expected = _.map(falsey, function(value) { return typeof value == 'number'; }); - strictEqual(_.isMatch({ 'a': new Foo }, { 'a': { 'b': 2 } }), true); + var actual = _.map(falsey, function(value, index) { + return index ? _.isNumber(value) : _.isNumber(); + }); + + deepEqual(actual, expected); + + strictEqual(_.isNumber(args), false); + strictEqual(_.isNumber([1, 2, 3]), false); + strictEqual(_.isNumber(true), false); + strictEqual(_.isNumber(new Date), false); + strictEqual(_.isNumber(new Error), false); + strictEqual(_.isNumber(_), false); + strictEqual(_.isNumber(slice), false); + strictEqual(_.isNumber({ 'a': 1 }), false); + strictEqual(_.isNumber(/x/), false); + strictEqual(_.isNumber('a'), false); }); - test('should match `-0` as `0`', 2, function() { - var object1 = { 'a': -0 }, - object2 = { 'a': 0 }; + test('should work with numbers from another realm', 1, function() { + if (_._object) { + strictEqual(_.isNumber(_._number), true); + } + else { + skipTest(); + } + }); - strictEqual(_.isMatch(object1, object2), true); - strictEqual(_.isMatch(object2, object1), true); + test('should avoid `[xpconnect wrapped native prototype]` in Firefox', 1, function() { + strictEqual(_.isNumber(+"2"), true); }); + }(1, 2, 3)); - test('should not match by inherited `source` properties', 1, function() { - function Foo() { this.a = 1; } - Foo.prototype.b = 2; + /*--------------------------------------------------------------------------*/ - var objects = [{ 'a': 1 }, { 'a': 1, 'b': 2 }], - source = new Foo, - expected = _.map(objects, _.constant(true)); + QUnit.module('lodash.isObject'); - var actual = _.map(objects, function(object) { - return _.isMatch(object, source); - }); + (function() { + var args = arguments; - deepEqual(actual, expected); + test('should return `true` for objects', 12, function() { + strictEqual(_.isObject(args), true); + strictEqual(_.isObject([1, 2, 3]), true); + strictEqual(_.isObject(Object(false)), true); + strictEqual(_.isObject(new Date), true); + strictEqual(_.isObject(new Error), true); + strictEqual(_.isObject(_), true); + strictEqual(_.isObject(slice), true); + strictEqual(_.isObject({ 'a': 1 }), true); + strictEqual(_.isObject(Object(0)), true); + strictEqual(_.isObject(/x/), true); + strictEqual(_.isObject(Object('a')), true); + + if (document) { + strictEqual(_.isObject(body), true); + } else { + skipTest(); + } }); - test('should return `false` when `object` is nullish', 1, function() { - var values = [null, undefined], - expected = _.map(values, _.constant(false)), - source = { 'a': 1 }; + test('should return `false` for non-objects', 1, function() { + var symbol = (Symbol || noop)(), + values = falsey.concat(true, 1, 'a', symbol), + expected = _.map(values, _.constant(false)); - var actual = _.map(values, function(value) { - try { - return _.isMatch(value, source); - } catch(e) {} + var actual = _.map(values, function(value, index) { + return index ? _.isObject(value) : _.isObject(); }); deepEqual(actual, expected); }); - test('should return `true` when comparing an empty `source`', 1, function() { - var object = { 'a': 1 }, - expected = _.map(empties, _.constant(true)); + test('should work with objects from another realm', 8, function() { + if (_._element) { + strictEqual(_.isObject(_._element), true); + } + else { + skipTest(); + } + if (_._object) { + strictEqual(_.isObject(_._object), true); + strictEqual(_.isObject(_._boolean), true); + strictEqual(_.isObject(_._date), true); + strictEqual(_.isObject(_._function), true); + strictEqual(_.isObject(_._number), true); + strictEqual(_.isObject(_._regexp), true); + strictEqual(_.isObject(_._string), true); + } + else { + skipTest(7); + } + }); - var actual = _.map(empties, function(value) { - return _.isMatch(object, value); - }); + test('should avoid V8 bug #2291 (test in Chrome 19-20)', 1, function() { + // Trigger a V8 JIT bug. + // See https://code.google.com/p/v8/issues/detail?id=2291. + var object = {}; - deepEqual(actual, expected); - }); + // 1: Useless comparison statement, this is half the trigger. + object == object; - test('should compare a variety of `source` property values', 2, function() { - var object1 = { 'a': false, 'b': true, 'c': '3', 'd': 4, 'e': [5], 'f': { 'g': 6 } }, - object2 = { 'a': 0, 'b': 1, 'c': 3, 'd': '4', 'e': ['5'], 'f': { 'g': '6' } }; + // 2: Initial check with object, this is the other half of the trigger. + _.isObject(object); - strictEqual(_.isMatch(object1, object1), true); - strictEqual(_.isMatch(object1, object2), false); + strictEqual(_.isObject('x'), false); }); + }(1, 2, 3)); - test('should work with a function for `source`', 1, function() { - function source() {} - - source.a = 1; - source.b = function() {}; - source.c = 3; + /*--------------------------------------------------------------------------*/ - var objects = [{ 'a': 1 }, { 'a': 1, 'b': source.b, 'c': 3 }]; + QUnit.module('lodash.isPlainObject'); - var actual = _.map(objects, function(object) { - return _.isMatch(object, source); - }); + (function() { + var element = document && document.createElement('div'); - deepEqual(actual, [false, true]); + test('should detect plain objects', 5, function() { + function Foo(a) { + this.a = 1; + } + strictEqual(_.isPlainObject({}), true); + strictEqual(_.isPlainObject({ 'a': 1 }), true); + strictEqual(_.isPlainObject({ 'constructor': Foo }), true); + strictEqual(_.isPlainObject([1, 2, 3]), false); + strictEqual(_.isPlainObject(new Foo(1)), false); }); - test('should work with strings', 4, function() { - var pairs = [['xo', Object('x')], [Object('xo'), 'x']]; - - _.each(pairs, function(pair) { - strictEqual(_.isMatch(pair[0], pair[1]), true); - strictEqual(_.isMatch(pair[1], pair[0]), false); - }); + test('should return `true` for objects with a `[[Prototype]]` of `null`', 1, function() { + if (create) { + strictEqual(_.isPlainObject(create(null)), true); + } else { + skipTest(); + } }); - test('should return `true` when comparing a `source` of empty arrays and objects', 1, function() { - var objects = [{ 'a': [1], 'b': { 'c': 1 } }, { 'a': [2, 3], 'b': { 'd': 2 } }], - source = { 'a': [], 'b': {} }; + test('should return `true` for plain objects with a custom `valueOf` property', 2, function() { + strictEqual(_.isPlainObject({ 'valueOf': 0 }), true); - var actual = _.filter(objects, function(object) { - return _.isMatch(object, source); - }); + if (element) { + var valueOf = element.valueOf; + element.valueOf = 0; - deepEqual(actual, objects); + strictEqual(_.isPlainObject(element), false); + element.valueOf = valueOf; + } + else { + skipTest(); + } }); - test('should return `true` when comparing an empty `source` to a nullish `object`', 1, function() { - var values = [null, undefined], - expected = _.map(values, _.constant(true)), - source = {}; - - var actual = _.map(values, function(value) { - try { - return _.isMatch(value, source); - } catch(e) {} - }); + test('should return `false` for DOM elements', 1, function() { + if (element) { + strictEqual(_.isPlainObject(element), false); + } else { + skipTest(); + } + }); - deepEqual(actual, expected); + test('should return `false` for Object objects without a `toStringTag` of "Object"', 3, function() { + strictEqual(_.isPlainObject(arguments), false); + strictEqual(_.isPlainObject(Error), false); + strictEqual(_.isPlainObject(Math), false); }); - test('should search arrays of `source` for values', 3, function() { - var objects = [{ 'a': ['b'] }, { 'a': ['c', 'd'] }], - source = { 'a': ['d'] }, - predicate = function(object) { return _.isMatch(object, source); }, - actual = _.filter(objects, predicate); + test('should return `false` for non-objects', 3, function() { + var expected = _.map(falsey, _.constant(false)); - deepEqual(actual, [objects[1]]); + var actual = _.map(falsey, function(value, index) { + return index ? _.isPlainObject(value) : _.isPlainObject(); + }); - source = { 'a': ['b', 'd'] }; - actual = _.filter(objects, predicate); + deepEqual(actual, expected); - deepEqual(actual, []); + strictEqual(_.isPlainObject(true), false); + strictEqual(_.isPlainObject('a'), false); + }); - source = { 'a': ['d', 'b'] }; - actual = _.filter(objects, predicate); - deepEqual(actual, []); + test('should work with objects from another realm', 1, function() { + if (_._object) { + strictEqual(_.isPlainObject(_._object), true); + } + else { + skipTest(); + } }); + }()); - test('should perform a partial comparison of all objects within arrays of `source`', 1, function() { - var source = { 'a': [{ 'b': 1 }, { 'b': 4, 'c': 5 }] }; + /*--------------------------------------------------------------------------*/ - var objects = [ - { 'a': [{ 'b': 1, 'c': 2 }, { 'b': 4, 'c': 5, 'd': 6 }] }, - { 'a': [{ 'b': 1, 'c': 2 }, { 'b': 4, 'c': 6, 'd': 7 }] } - ]; + QUnit.module('lodash.isRegExp'); - var actual = _.filter(objects, function(object) { - return _.isMatch(object, source); - }); + (function() { + var args = arguments; - deepEqual(actual, [objects[0]]); + test('should return `true` for regexes', 2, function() { + strictEqual(_.isRegExp(/x/), true); + strictEqual(_.isRegExp(RegExp('x')), true); }); - test('should handle a `source` with `undefined` values', 3, function() { - var objects = [{ 'a': 1 }, { 'a': 1, 'b': 1 }, { 'a': 1, 'b': undefined }], - source = { 'b': undefined }, - predicate = function(object) { return _.isMatch(object, source); }, - actual = _.map(objects, predicate), - expected = [false, false, true]; - - deepEqual(actual, expected); + test('should return `false` for non-regexes', 12, function() { + var expected = _.map(falsey, _.constant(false)); - source = { 'a': 1, 'b': undefined }; - actual = _.map(objects, predicate); + var actual = _.map(falsey, function(value, index) { + return index ? _.isRegExp(value) : _.isRegExp(); + }); deepEqual(actual, expected); - objects = [{ 'a': { 'b': 1 } }, { 'a':{ 'b':1, 'c': 1 } }, { 'a': { 'b': 1, 'c': undefined } }]; - source = { 'a': { 'c': undefined } }; - actual = _.map(objects, predicate); - - deepEqual(actual, expected); + strictEqual(_.isRegExp(args), false); + strictEqual(_.isRegExp([1, 2, 3]), false); + strictEqual(_.isRegExp(true), false); + strictEqual(_.isRegExp(new Date), false); + strictEqual(_.isRegExp(new Error), false); + strictEqual(_.isRegExp(_), false); + strictEqual(_.isRegExp(slice), false); + strictEqual(_.isRegExp({ 'a': 1 }), false); + strictEqual(_.isRegExp(1), false); + strictEqual(_.isRegExp(NaN), false); + strictEqual(_.isRegExp('a'), false); }); - test('should match properties when `value` is a function', 1, function() { - function Foo() {} - Foo.a = { 'b': 1, 'c': 2 }; - - var matches = _.matches({ 'a': { 'b': 1 } }); - strictEqual(matches(Foo), true); + test('should work with regexes from another realm', 1, function() { + if (_._object) { + strictEqual(_.isRegExp(_._regexp), true); + } + else { + skipTest(); + } }); + }(1, 2, 3)); - test('should match properties when `value` is not a plain object', 1, function() { - function Foo(object) { _.assign(this, object); } + /*--------------------------------------------------------------------------*/ - var object = new Foo({ 'a': new Foo({ 'b': 1, 'c': 2 }) }), - matches = _.matches({ 'a': { 'b': 1 } }); + QUnit.module('lodash.isString'); - strictEqual(matches(object), true); + (function() { + var args = arguments; + + test('should return `true` for strings', 2, function() { + strictEqual(_.isString('a'), true); + strictEqual(_.isString(Object('a')), true); }); - test('should match problem JScript properties (test in IE < 9)', 1, function() { - var objects = [{}, shadowObject]; + test('should return `false` for non-strings', 12, function() { + var expected = _.map(falsey, function(value) { return value === ''; }); - var actual = _.map(objects, function(object) { - return _.isMatch(object, shadowObject); + var actual = _.map(falsey, function(value, index) { + return index ? _.isString(value) : _.isString(); }); - deepEqual(actual, [false, true]); - }); + deepEqual(actual, expected); - test('should provide the correct `customizer` arguments', 1, function() { - var argsList = [], - object1 = { 'a': [1, 2], 'b': null }, - object2 = { 'a': [1, 2], 'b': null }; + strictEqual(_.isString(args), false); + strictEqual(_.isString([1, 2, 3]), false); + strictEqual(_.isString(true), false); + strictEqual(_.isString(new Date), false); + strictEqual(_.isString(new Error), false); + strictEqual(_.isString(_), false); + strictEqual(_.isString(slice), false); + strictEqual(_.isString({ '0': 1, 'length': 1 }), false); + strictEqual(_.isString(1), false); + strictEqual(_.isString(NaN), false); + strictEqual(_.isString(/x/), false); + }); - object1.b = object2; - object2.b = object1; + test('should work with strings from another realm', 1, function() { + if (_._object) { + strictEqual(_.isString(_._string), true); + } + else { + skipTest(); + } + }); + }(1, 2, 3)); - var expected = [ - [object1.a, object2.a, 'a'], - [object1.a[0], object2.a[0], 0], - [object1.a[1], object2.a[1], 1], - [object1.b, object2.b, 'b'], - [object1.b.a, object2.b.a, 'a'], - [object1.b.a[0], object2.b.a[0], 0], - [object1.b.a[1], object2.b.a[1], 1], - [object1.b.b, object2.b.b, 'b'], - [object1.b.b.a, object2.b.b.a, 'a'], - [object1.b.b.a[0], object2.b.b.a[0], 0], - [object1.b.b.a[1], object2.b.b.a[1], 1], - [object1.b.b.b, object2.b.b.b, 'b'] - ]; + /*--------------------------------------------------------------------------*/ - _.isMatch(object1, object2, function() { - argsList.push(slice.call(arguments)); - }); + QUnit.module('lodash.isTypedArray'); - deepEqual(argsList, expected); - }); + (function() { + var args = arguments; - test('should set the `this` binding', 1, function() { - var actual = _.isMatch({ 'a': 1 }, { 'a': 2 }, function(a, b) { - return this[a] == this[b]; - }, { 'a': 1, 'b': 1 }); + test('should return `true` for typed arrays', 1, function() { + var expected = _.map(typedArrays, function(type) { + return type in root; + }); - strictEqual(actual, true); - }); + var actual = _.map(typedArrays, function(type) { + var Ctor = root[type]; + return Ctor ? _.isTypedArray(new Ctor(new ArrayBuffer(8))) : false; + }); - test('should handle comparisons if `customizer` returns `undefined`', 1, function() { - strictEqual(_.isMatch({ 'a': 1 }, { 'a': 1 }, _.noop), true); + deepEqual(actual, expected); }); - test('should return a boolean value even if `customizer` does not', 2, function() { - var object = { 'a': 1 }, - actual = _.isMatch(object, { 'a': 1 }, _.constant('a')); - - strictEqual(actual, true); - + test('should return `false` for non typed arrays', 13, function() { var expected = _.map(falsey, _.constant(false)); - actual = []; - _.each(falsey, function(value) { - actual.push(_.isMatch(object, { 'a': 2 }, _.constant(value))); + var actual = _.map(falsey, function(value, index) { + return index ? _.isTypedArray(value) : _.isTypedArray(); }); deepEqual(actual, expected); + + strictEqual(_.isTypedArray(args), false); + strictEqual(_.isTypedArray([1, 2, 3]), false); + strictEqual(_.isTypedArray(true), false); + strictEqual(_.isTypedArray(new Date), false); + strictEqual(_.isTypedArray(new Error), false); + strictEqual(_.isTypedArray(_), false); + strictEqual(_.isTypedArray(slice), false); + strictEqual(_.isTypedArray({ 'a': 1 }), false); + strictEqual(_.isTypedArray(1), false); + strictEqual(_.isTypedArray(NaN), false); + strictEqual(_.isTypedArray(/x/), false); + strictEqual(_.isTypedArray('a'), false); }); - test('should ensure `customizer` is a function', 1, function() { - var object = { 'a': 1 }, - matches = _.partial(_.isMatch, object), - actual = _.map([object, { 'a': 2 }], matches); + test('should work with typed arrays from another realm', 1, function() { + if (_._object) { + var props = _.map(typedArrays, function(type) { + return '_' + type.toLowerCase(); + }); - deepEqual(actual, [true, false]); + var expected = _.map(props, function(key) { + return key in _; + }); + + var actual = _.map(props, function(key) { + var value = _[key]; + return value ? _.isTypedArray(value) : false; + }); + + deepEqual(actual, expected); + } + else { + skipTest(); + } }); - }()); + }(1, 2, 3)); /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.isNaN'); + QUnit.module('lodash.isUndefined'); (function() { var args = arguments; - test('should return `true` for NaNs', 2, function() { - strictEqual(_.isNaN(NaN), true); - strictEqual(_.isNaN(Object(NaN)), true); + test('should return `true` for `undefined` values', 2, function() { + strictEqual(_.isUndefined(), true); + strictEqual(_.isUndefined(undefined), true); }); - test('should return `false` for non-NaNs', 12, function() { - var expected = _.map(falsey, function(value) { return value !== value; }); + test('should return `false` for non `undefined` values', 13, function() { + var expected = _.map(falsey, function(value) { return value === undefined; }); var actual = _.map(falsey, function(value, index) { - return index ? _.isNaN(value) : _.isNaN(); + return index ? _.isUndefined(value) : _.isUndefined(); }); deepEqual(actual, expected); - strictEqual(_.isNaN(args), false); - strictEqual(_.isNaN([1, 2, 3]), false); - strictEqual(_.isNaN(true), false); - strictEqual(_.isNaN(new Date), false); - strictEqual(_.isNaN(new Error), false); - strictEqual(_.isNaN(_), false); - strictEqual(_.isNaN(slice), false); - strictEqual(_.isNaN({ 'a': 1 }), false); - strictEqual(_.isNaN(1), false); - strictEqual(_.isNaN(/x/), false); - strictEqual(_.isNaN('a'), false); + strictEqual(_.isUndefined(args), false); + strictEqual(_.isUndefined([1, 2, 3]), false); + strictEqual(_.isUndefined(true), false); + strictEqual(_.isUndefined(new Date), false); + strictEqual(_.isUndefined(new Error), false); + strictEqual(_.isUndefined(_), false); + strictEqual(_.isUndefined(slice), false); + strictEqual(_.isUndefined({ 'a': 1 }), false); + strictEqual(_.isUndefined(1), false); + strictEqual(_.isUndefined(NaN), false); + strictEqual(_.isUndefined(/x/), false); + strictEqual(_.isUndefined('a'), false); }); - test('should work with `NaN` from another realm', 1, function() { + test('should work with `undefined` from another realm', 1, function() { if (_._object) { - strictEqual(_.isNaN(_._nan), true); + strictEqual(_.isUndefined(_._undefined), true); } else { skipTest(); @@ -8506,557 +8380,638 @@ /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.isNative'); + QUnit.module('isType checks'); (function() { - var args = arguments; + test('should return `false` for subclassed values', 8, function() { + var funcs = [ + 'isArray', 'isBoolean', 'isDate', 'isError', + 'isFunction', 'isNumber', 'isRegExp', 'isString' + ]; - test('should return `true` for native methods', 6, function() { - _.each([Array, create, root.encodeURI, slice, Uint8Array], function(func) { - if (func) { - strictEqual(_.isNative(func), true); + _.each(funcs, function(methodName) { + function Foo() {} + Foo.prototype = root[methodName.slice(2)].prototype; + + var object = new Foo; + if (objToString.call(object) == objectTag) { + strictEqual(_[methodName](object), false, '`_.' + methodName + '` returns `false`'); + } else { + skipTest(); + } + }); + }); + + test('should not error on host objects (test in IE)', 15, function() { + var funcs = [ + 'isArguments', 'isArray', 'isBoolean', 'isDate', 'isElement', + 'isError', 'isFinite', 'isFunction', 'isNaN', 'isNull', 'isNumber', + 'isObject', 'isRegExp', 'isString', 'isUndefined' + ]; + + _.each(funcs, function(methodName) { + if (xml) { + var pass = true; + + try { + _[methodName](xml); + } catch(e) { + pass = false; + } + ok(pass, '`_.' + methodName + '` should not error'); } else { skipTest(); } }); + }); + }()); - if (body) { - strictEqual(_.isNative(body.cloneNode), true); - } - else { - skipTest(); - } + /*--------------------------------------------------------------------------*/ + + QUnit.module('lodash.iteratee'); + + (function() { + test('should provide arguments to `func`', 3, function() { + var fn = function() { + var result = [this]; + push.apply(result, arguments); + return result; + }; + + var iteratee = _.iteratee(fn), + actual = iteratee('a', 'b', 'c', 'd', 'e', 'f'); + + ok(actual[0] === null || actual[0] && actual[0].Array); + deepEqual(actual.slice(1), ['a', 'b', 'c', 'd', 'e', 'f']); + + var object = {}; + iteratee = _.iteratee(fn, object); + actual = iteratee('a', 'b'); + + deepEqual(actual, [object, 'a', 'b']); }); - test('should return `false` for non-native methods', 12, function() { - var expected = _.map(falsey, _.constant(false)); + test('should return `_.identity` when `func` is nullish', 1, function() { + var object = {}, + values = [, null, undefined], + expected = _.map(values, _.constant([!isNpm && _.identity, object])); - var actual = _.map(falsey, function(value, index) { - return index ? _.isNative(value) : _.isNative(); + var actual = _.map(values, function(value, index) { + var identity = index ? _.iteratee(value) : _.iteratee(); + return [!isNpm && identity, identity(object)]; }); deepEqual(actual, expected); - - strictEqual(_.isNative(args), false); - strictEqual(_.isNative([1, 2, 3]), false); - strictEqual(_.isNative(true), false); - strictEqual(_.isNative(new Date), false); - strictEqual(_.isNative(new Error), false); - strictEqual(_.isNative(_), false); - strictEqual(_.isNative({ 'a': 1 }), false); - strictEqual(_.isNative(1), false); - strictEqual(_.isNative(NaN), false); - strictEqual(_.isNative(/x/), false); - strictEqual(_.isNative('a'), false); }); - test('should work with native functions from another realm', 2, function() { - if (_._element) { - strictEqual(_.isNative(_._element.cloneNode), true); - } - else { - skipTest(); - } - if (_._object) { - strictEqual(_.isNative(_._object.valueOf), true); - } - else { - skipTest(); - } + test('should not error when `func` is nullish and a `thisArg` is provided', 2, function() { + var object = {}; + + _.each([null, undefined], function(value) { + try { + var iteratee = _.iteratee(value, {}); + strictEqual(iteratee(object), object); + } catch(e) { + ok(false, e.message); + } + }); }); - }(1, 2, 3)); - /*--------------------------------------------------------------------------*/ + test('should create an iteratee with a falsey `thisArg`', 1, function() { + var fn = function() { return this; }, + object = {}; - QUnit.module('lodash.isNull'); + var expected = _.map(falsey, function(value) { + var result = fn.call(value); + return (result && result.Array) ? object : result; + }); - (function() { - var args = arguments; + var actual = _.map(falsey, function(value) { + var iteratee = _.iteratee(fn, value), + result = iteratee(); - test('should return `true` for nulls', 1, function() { - strictEqual(_.isNull(null), true); + return (result && result.Array) ? object : result; + }); + + ok(_.isEqual(actual, expected)); }); - test('should return `false` for non-nulls', 13, function() { - var expected = _.map(falsey, function(value) { return value === null; }); + test('should return an iteratee created by `_.matches` when `func` is an object', 2, function() { + var matches = _.iteratee({ 'a': 1, 'b': 2 }); + strictEqual(matches({ 'a': 1, 'b': 2, 'c': 3 }), true); + strictEqual(matches({ 'b': 2 }), false); + }); - var actual = _.map(falsey, function(value, index) { - return index ? _.isNull(value) : _.isNull(); + test('should return an iteratee created by `_.matches` when `func` is an array', 2, function() { + var matches = _.iteratee(['a', 'b']); + strictEqual(matches({ '0': 'a', '1': 'b', '2': 'c' }), true); + strictEqual(matches({ '1': 'b' }), false); + }); + + test('should not change match behavior if `source` is augmented', 9, function() { + var sources = [ + { 'a': { 'b': 2, 'c': 3 } }, + { 'a': 1, 'b': 2 }, + { 'a': 1 } + ]; + + _.each(sources, function(source, index) { + var object = _.cloneDeep(source), + matches = _.iteratee(source); + + strictEqual(matches(object), true); + + if (index) { + source.a = 2; + source.b = 1; + source.c = 3; + } else { + source.a.b = 1; + source.a.c = 2; + source.a.d = 3; + } + strictEqual(matches(object), true); + strictEqual(matches(source), false); }); + }); - deepEqual(actual, expected); + test('should return an iteratee created by `_.matchesProperty` when `func` is a number or string and `thisArg` is not `undefined`', 3, function() { + var array = ['a'], + matches = _.iteratee(0, 'a'); - strictEqual(_.isNull(args), false); - strictEqual(_.isNull([1, 2, 3]), false); - strictEqual(_.isNull(true), false); - strictEqual(_.isNull(new Date), false); - strictEqual(_.isNull(new Error), false); - strictEqual(_.isNull(_), false); - strictEqual(_.isNull(slice), false); - strictEqual(_.isNull({ 'a': 1 }), false); - strictEqual(_.isNull(1), false); - strictEqual(_.isNull(NaN), false); - strictEqual(_.isNull(/x/), false); - strictEqual(_.isNull('a'), false); + strictEqual(matches(array), true); + + matches = _.iteratee('0', 'a'); + strictEqual(matches(array), true); + + matches = _.iteratee(1, undefined); + strictEqual(matches(array), undefined); }); - test('should work with nulls from another realm', 1, function() { - if (_._object) { - strictEqual(_.isNull(_._null), true); - } - else { - skipTest(); - } + test('should support deep paths for `_.matchesProperty` shorthands', 1, function() { + var object = { 'a': { 'b': { 'c': { 'd': 1, 'e': 2 } } } }, + matches = _.iteratee('a.b.c', { 'e': 2 }); + + strictEqual(matches(object), true); }); - }(1, 2, 3)); - /*--------------------------------------------------------------------------*/ + test('should return an iteratee created by `_.property` when `func` is a number or string', 2, function() { + var array = ['a'], + prop = _.iteratee(0); - QUnit.module('lodash.isNumber'); + strictEqual(prop(array), 'a'); - (function() { - var args = arguments; + prop = _.iteratee('0'); + strictEqual(prop(array), 'a'); + }); - test('should return `true` for numbers', 3, function() { - strictEqual(_.isNumber(0), true); - strictEqual(_.isNumber(Object(0)), true); - strictEqual(_.isNumber(NaN), true); + test('should support deep paths for `_.property` shorthands', 1, function() { + var object = { 'a': { 'b': { 'c': 3 } } }, + prop = _.iteratee('a.b.c'); + + strictEqual(prop(object), 3); }); - test('should return `false` for non-numbers', 11, function() { - var expected = _.map(falsey, function(value) { return typeof value == 'number'; }); + test('should work with functions created by `_.partial` and `_.partialRight`', 2, function() { + var fn = function() { + var result = [this.a]; + push.apply(result, arguments); + return result; + }; - var actual = _.map(falsey, function(value, index) { - return index ? _.isNumber(value) : _.isNumber(); - }); + var expected = [1, 2, 3], + object = { 'a': 1 }, + iteratee = _.iteratee(_.partial(fn, 2), object); - deepEqual(actual, expected); + deepEqual(iteratee(3), expected); - strictEqual(_.isNumber(args), false); - strictEqual(_.isNumber([1, 2, 3]), false); - strictEqual(_.isNumber(true), false); - strictEqual(_.isNumber(new Date), false); - strictEqual(_.isNumber(new Error), false); - strictEqual(_.isNumber(_), false); - strictEqual(_.isNumber(slice), false); - strictEqual(_.isNumber({ 'a': 1 }), false); - strictEqual(_.isNumber(/x/), false); - strictEqual(_.isNumber('a'), false); + iteratee = _.iteratee(_.partialRight(fn, 3), object); + deepEqual(iteratee(2), expected); }); - test('should work with numbers from another realm', 1, function() { - if (_._object) { - strictEqual(_.isNumber(_._number), true); + test('should support binding built-in methods', 2, function() { + var fn = function() {}, + object = { 'a': 1 }, + bound = fn.bind && fn.bind(object), + iteratee = _.iteratee(hasOwnProperty, object); + + strictEqual(iteratee('a'), true); + + if (bound) { + iteratee = _.iteratee(bound, object); + notStrictEqual(iteratee, bound); } else { skipTest(); } }); - test('should avoid `[xpconnect wrapped native prototype]` in Firefox', 1, function() { - strictEqual(_.isNumber(+"2"), true); + test('should work as an iteratee for methods like `_.map`', 1, function() { + var fn = function() { return this instanceof Number; }, + array = [fn, fn, fn], + iteratees = _.map(array, _.iteratee), + expected = _.map(array, _.constant(false)); + + var actual = _.map(iteratees, function(iteratee) { + return iteratee(); + }); + + deepEqual(actual, expected); }); - }(1, 2, 3)); + }()); /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.isObject'); + QUnit.module('custom `_.iteratee` methods'); (function() { - var args = arguments; + var array = ['one', 'two', 'three'], + getPropA = _.partial(_.property, 'a'), + getPropB = _.partial(_.property, 'b'), + getLength = _.partial(_.property, 'length'), + iteratee = _.iteratee; - test('should return `true` for objects', 12, function() { - strictEqual(_.isObject(args), true); - strictEqual(_.isObject([1, 2, 3]), true); - strictEqual(_.isObject(Object(false)), true); - strictEqual(_.isObject(new Date), true); - strictEqual(_.isObject(new Error), true); - strictEqual(_.isObject(_), true); - strictEqual(_.isObject(slice), true); - strictEqual(_.isObject({ 'a': 1 }), true); - strictEqual(_.isObject(Object(0)), true); - strictEqual(_.isObject(/x/), true); - strictEqual(_.isObject(Object('a')), true); + var getSum = function() { + return function(result, object) { + return result + object.a; + }; + }; - if (document) { - strictEqual(_.isObject(body), true); - } else { + var objects = [ + { 'a': 0, 'b': 0 }, + { 'a': 1, 'b': 0 }, + { 'a': 1, 'b': 1 } + ]; + + test('`_.countBy` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + _.iteratee = getLength; + deepEqual(_.countBy(array), { '3': 2, '5': 1 }); + _.iteratee = iteratee; + } + else { skipTest(); } }); - test('should return `false` for non-objects', 1, function() { - var symbol = (Symbol || noop)(), - values = falsey.concat(true, 1, 'a', symbol), - expected = _.map(values, _.constant(false)); - - var actual = _.map(values, function(value, index) { - return index ? _.isObject(value) : _.isObject(); - }); - - deepEqual(actual, expected); + test('`_.dropRightWhile` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + _.iteratee = getPropB; + deepEqual(_.dropRightWhile(objects), objects.slice(0, 2)); + _.iteratee = iteratee; + } + else { + skipTest(); + } }); - test('should work with objects from another realm', 8, function() { - if (_._element) { - strictEqual(_.isObject(_._element), true); + test('`_.dropWhile` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + _.iteratee = getPropB; + deepEqual(_.dropWhile(objects.reverse()).reverse(), objects.reverse().slice(0, 2)); + _.iteratee = iteratee; } else { skipTest(); } - if (_._object) { - strictEqual(_.isObject(_._object), true); - strictEqual(_.isObject(_._boolean), true); - strictEqual(_.isObject(_._date), true); - strictEqual(_.isObject(_._function), true); - strictEqual(_.isObject(_._number), true); - strictEqual(_.isObject(_._regexp), true); - strictEqual(_.isObject(_._string), true); + }); + + test('`_.every` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + _.iteratee = getPropA; + strictEqual(_.every(objects.slice(1)), true); + _.iteratee = iteratee; } else { - skipTest(7); + skipTest(); } }); - test('should avoid V8 bug #2291 (test in Chrome 19-20)', 1, function() { - // Trigger a V8 JIT bug. - // See https://code.google.com/p/v8/issues/detail?id=2291. - var object = {}; - - // 1: Useless comparison statement, this is half the trigger. - object == object; - - // 2: Initial check with object, this is the other half of the trigger. - _.isObject(object); + test('`_.filter` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + var objects = [{ 'a': 0 }, { 'a': 1 }]; - strictEqual(_.isObject('x'), false); + _.iteratee = getPropA; + deepEqual(_.filter(objects), [objects[1]]); + _.iteratee = iteratee; + } + else { + skipTest(); + } }); - }(1, 2, 3)); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('lodash.isPlainObject'); - - (function() { - var element = document && document.createElement('div'); - test('should detect plain objects', 5, function() { - function Foo(a) { - this.a = 1; + test('`_.find` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + _.iteratee = getPropA; + strictEqual(_.find(objects), objects[1]); + _.iteratee = iteratee; + } + else { + skipTest(); } - strictEqual(_.isPlainObject({}), true); - strictEqual(_.isPlainObject({ 'a': 1 }), true); - strictEqual(_.isPlainObject({ 'constructor': Foo }), true); - strictEqual(_.isPlainObject([1, 2, 3]), false); - strictEqual(_.isPlainObject(new Foo(1)), false); }); - test('should return `true` for objects with a `[[Prototype]]` of `null`', 1, function() { - if (create) { - strictEqual(_.isPlainObject(create(null)), true); - } else { + test('`_.findIndex` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + _.iteratee = getPropA; + strictEqual(_.findIndex(objects), 1); + _.iteratee = iteratee; + } + else { skipTest(); } }); - test('should return `true` for plain objects with a custom `valueOf` property', 2, function() { - strictEqual(_.isPlainObject({ 'valueOf': 0 }), true); - - if (element) { - var valueOf = element.valueOf; - element.valueOf = 0; - - strictEqual(_.isPlainObject(element), false); - element.valueOf = valueOf; + test('`_.findLast` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + _.iteratee = getPropA; + strictEqual(_.findLast(objects), objects[2]); + _.iteratee = iteratee; } else { skipTest(); } }); - test('should return `false` for DOM elements', 1, function() { - if (element) { - strictEqual(_.isPlainObject(element), false); - } else { + test('`_.findLastIndex` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + _.iteratee = getPropA; + strictEqual(_.findLastIndex(objects), 2); + _.iteratee = iteratee; + } + else { skipTest(); } }); - test('should return `false` for Object objects without a `toStringTag` of "Object"', 3, function() { - strictEqual(_.isPlainObject(arguments), false); - strictEqual(_.isPlainObject(Error), false); - strictEqual(_.isPlainObject(Math), false); + test('`_.findLastKey` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + _.iteratee = getPropB; + strictEqual(_.findKey(objects), '2'); + _.iteratee = iteratee; + } + else { + skipTest(); + } }); - test('should return `false` for non-objects', 3, function() { - var expected = _.map(falsey, _.constant(false)); - - var actual = _.map(falsey, function(value, index) { - return index ? _.isPlainObject(value) : _.isPlainObject(); - }); - - deepEqual(actual, expected); + test('`_.findKey` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + _.iteratee = getPropB; + strictEqual(_.findLastKey(objects), '2'); + _.iteratee = iteratee; + } + else { + skipTest(); + } + }); - strictEqual(_.isPlainObject(true), false); - strictEqual(_.isPlainObject('a'), false); + test('`_.groupBy` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + _.iteratee = getLength; + deepEqual(_.groupBy(array), { '3': ['one', 'two'], '5': ['three'] }); + _.iteratee = iteratee; + } + else { + skipTest(); + } }); - test('should work with objects from another realm', 1, function() { - if (_._object) { - strictEqual(_.isPlainObject(_._object), true); + test('`_.indexBy` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + _.iteratee = getLength; + deepEqual(_.indexBy(array), { '3': 'two', '5': 'three' }); + _.iteratee = iteratee; } else { skipTest(); } }); - }()); - /*--------------------------------------------------------------------------*/ + test('`_.map` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + _.iteratee = getPropA; + deepEqual(_.map(objects), [0, 1, 1]); + _.iteratee = iteratee; + } + else { + skipTest(); + } + }); - QUnit.module('lodash.isRegExp'); + test('`_.mapKeys` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + _.iteratee = getPropB; + deepEqual(_.mapKeys({ 'a': { 'b': 1 } }), { '1': { 'b': 1 } }); + _.iteratee = iteratee; + } + else { + skipTest(); + } + }); - (function() { - var args = arguments; + test('`_.mapValues` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + _.iteratee = getPropB; + deepEqual(_.mapValues({ 'a': { 'b': 1 } }), { 'a': 1 }); + _.iteratee = iteratee; + } + else { + skipTest(); + } + }); - test('should return `true` for regexes', 2, function() { - strictEqual(_.isRegExp(/x/), true); - strictEqual(_.isRegExp(RegExp('x')), true); + test('`_.max` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + _.iteratee = getPropB; + deepEqual(_.max(objects), objects[2]); + _.iteratee = iteratee; + } + else { + skipTest(); + } }); - test('should return `false` for non-regexes', 12, function() { - var expected = _.map(falsey, _.constant(false)); + test('`_.min` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + _.iteratee = getPropB; + deepEqual(_.min(objects), objects[0]); + _.iteratee = iteratee; + } + else { + skipTest(); + } + }); - var actual = _.map(falsey, function(value, index) { - return index ? _.isRegExp(value) : _.isRegExp(); - }); + test('`_.partition` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + var objects = [{ 'a': 1 }, { 'a': 1 }, { 'b': 2 }]; - deepEqual(actual, expected); + _.iteratee = getPropA; + deepEqual(_.partition(objects), [objects.slice(0, 2), objects.slice(2)]); + _.iteratee = iteratee; + } + else { + skipTest(); + } + }); - strictEqual(_.isRegExp(args), false); - strictEqual(_.isRegExp([1, 2, 3]), false); - strictEqual(_.isRegExp(true), false); - strictEqual(_.isRegExp(new Date), false); - strictEqual(_.isRegExp(new Error), false); - strictEqual(_.isRegExp(_), false); - strictEqual(_.isRegExp(slice), false); - strictEqual(_.isRegExp({ 'a': 1 }), false); - strictEqual(_.isRegExp(1), false); - strictEqual(_.isRegExp(NaN), false); - strictEqual(_.isRegExp('a'), false); + test('`_.reduce` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + _.iteratee = getSum; + strictEqual(_.reduce(objects, undefined, 0), 2); + _.iteratee = iteratee; + } + else { + skipTest(); + } }); - test('should work with regexes from another realm', 1, function() { - if (_._object) { - strictEqual(_.isRegExp(_._regexp), true); + test('`_.reduceRight` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + _.iteratee = getSum; + strictEqual(_.reduceRight(objects, undefined, 0), 2); + _.iteratee = iteratee; } else { skipTest(); } }); - }(1, 2, 3)); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('lodash.isString'); - (function() { - var args = arguments; + test('`_.reject` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + var objects = [{ 'a': 0 }, { 'a': 1 }]; - test('should return `true` for strings', 2, function() { - strictEqual(_.isString('a'), true); - strictEqual(_.isString(Object('a')), true); + _.iteratee = getPropA; + deepEqual(_.reject(objects), [objects[0]]); + _.iteratee = iteratee; + } + else { + skipTest(); + } }); - test('should return `false` for non-strings', 12, function() { - var expected = _.map(falsey, function(value) { return value === ''; }); - - var actual = _.map(falsey, function(value, index) { - return index ? _.isString(value) : _.isString(); - }); - - deepEqual(actual, expected); + test('`_.remove` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + var objects = [{ 'a': 0 }, { 'a': 1 }]; - strictEqual(_.isString(args), false); - strictEqual(_.isString([1, 2, 3]), false); - strictEqual(_.isString(true), false); - strictEqual(_.isString(new Date), false); - strictEqual(_.isString(new Error), false); - strictEqual(_.isString(_), false); - strictEqual(_.isString(slice), false); - strictEqual(_.isString({ '0': 1, 'length': 1 }), false); - strictEqual(_.isString(1), false); - strictEqual(_.isString(NaN), false); - strictEqual(_.isString(/x/), false); + _.iteratee = getPropA; + _.remove(objects); + deepEqual(objects, [{ 'a': 0 }]); + _.iteratee = iteratee; + } + else { + skipTest(); + } }); - test('should work with strings from another realm', 1, function() { - if (_._object) { - strictEqual(_.isString(_._string), true); + test('`_.some` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + _.iteratee = getPropB; + strictEqual(_.some(objects), true); + _.iteratee = iteratee; } else { skipTest(); } }); - }(1, 2, 3)); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('lodash.isTypedArray'); - - (function() { - var args = arguments; - - test('should return `true` for typed arrays', 1, function() { - var expected = _.map(typedArrays, function(type) { - return type in root; - }); - - var actual = _.map(typedArrays, function(type) { - var Ctor = root[type]; - return Ctor ? _.isTypedArray(new Ctor(new ArrayBuffer(8))) : false; - }); - deepEqual(actual, expected); + test('`_.sortBy` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + _.iteratee = getPropA; + deepEqual(_.sortBy(objects.slice().reverse()), [objects[0], objects[2], objects[1]]); + _.iteratee = iteratee; + } + else { + skipTest(); + } }); - test('should return `false` for non typed arrays', 13, function() { - var expected = _.map(falsey, _.constant(false)); - - var actual = _.map(falsey, function(value, index) { - return index ? _.isTypedArray(value) : _.isTypedArray(); - }); - - deepEqual(actual, expected); + test('`_.sortedIndex` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + var objects = [{ 'a': 30 }, { 'a': 50 }]; - strictEqual(_.isTypedArray(args), false); - strictEqual(_.isTypedArray([1, 2, 3]), false); - strictEqual(_.isTypedArray(true), false); - strictEqual(_.isTypedArray(new Date), false); - strictEqual(_.isTypedArray(new Error), false); - strictEqual(_.isTypedArray(_), false); - strictEqual(_.isTypedArray(slice), false); - strictEqual(_.isTypedArray({ 'a': 1 }), false); - strictEqual(_.isTypedArray(1), false); - strictEqual(_.isTypedArray(NaN), false); - strictEqual(_.isTypedArray(/x/), false); - strictEqual(_.isTypedArray('a'), false); + _.iteratee = getPropA; + strictEqual(_.sortedIndex(objects, { 'a': 40 }), 1); + _.iteratee = iteratee; + } + else { + skipTest(); + } }); - test('should work with typed arrays from another realm', 1, function() { - if (_._object) { - var props = _.map(typedArrays, function(type) { - return '_' + type.toLowerCase(); - }); - - var expected = _.map(props, function(key) { - return key in _; - }); - - var actual = _.map(props, function(key) { - var value = _[key]; - return value ? _.isTypedArray(value) : false; - }); + test('`_.sortedLastIndex` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + var objects = [{ 'a': 30 }, { 'a': 50 }]; - deepEqual(actual, expected); + _.iteratee = getPropA; + strictEqual(_.sortedLastIndex(objects, { 'a': 40 }), 1); + _.iteratee = iteratee; } else { skipTest(); } }); - }(1, 2, 3)); - /*--------------------------------------------------------------------------*/ - - QUnit.module('lodash.isUndefined'); - - (function() { - var args = arguments; - - test('should return `true` for `undefined` values', 2, function() { - strictEqual(_.isUndefined(), true); - strictEqual(_.isUndefined(undefined), true); + test('`_.sum` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + _.iteratee = getPropB; + strictEqual(_.sum(objects), 1); + _.iteratee = iteratee; + } + else { + skipTest(); + } }); - test('should return `false` for non `undefined` values', 13, function() { - var expected = _.map(falsey, function(value) { return value === undefined; }); - - var actual = _.map(falsey, function(value, index) { - return index ? _.isUndefined(value) : _.isUndefined(); - }); - - deepEqual(actual, expected); - - strictEqual(_.isUndefined(args), false); - strictEqual(_.isUndefined([1, 2, 3]), false); - strictEqual(_.isUndefined(true), false); - strictEqual(_.isUndefined(new Date), false); - strictEqual(_.isUndefined(new Error), false); - strictEqual(_.isUndefined(_), false); - strictEqual(_.isUndefined(slice), false); - strictEqual(_.isUndefined({ 'a': 1 }), false); - strictEqual(_.isUndefined(1), false); - strictEqual(_.isUndefined(NaN), false); - strictEqual(_.isUndefined(/x/), false); - strictEqual(_.isUndefined('a'), false); + test('`_.takeRightWhile` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + _.iteratee = getPropB; + deepEqual(_.takeRightWhile(objects), objects.slice(2)); + _.iteratee = iteratee; + } + else { + skipTest(); + } }); - test('should work with `undefined` from another realm', 1, function() { - if (_._object) { - strictEqual(_.isUndefined(_._undefined), true); + test('`_.takeWhile` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + _.iteratee = getPropB; + deepEqual(_.takeWhile(objects.reverse()), objects.reverse().slice(2)); + _.iteratee = iteratee; } else { skipTest(); } }); - }(1, 2, 3)); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('isType checks'); - - (function() { - test('should return `false` for subclassed values', 8, function() { - var funcs = [ - 'isArray', 'isBoolean', 'isDate', 'isError', - 'isFunction', 'isNumber', 'isRegExp', 'isString' - ]; - _.each(funcs, function(methodName) { - function Foo() {} - Foo.prototype = root[methodName.slice(2)].prototype; + test('`_.transform` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + _.iteratee = function() { + return function(result, object) { + result.sum += object.a; + }; + }; - var object = new Foo; - if (objToString.call(object) == objectTag) { - strictEqual(_[methodName](object), false, '`_.' + methodName + '` returns `false`'); - } else { - skipTest(); - } - }); + deepEqual(_.transform(objects, undefined, { 'sum': 0 }), { 'sum': 2 }); + _.iteratee = iteratee; + } + else { + skipTest(); + } }); - test('should not error on host objects (test in IE)', 15, function() { - var funcs = [ - 'isArguments', 'isArray', 'isBoolean', 'isDate', 'isElement', - 'isError', 'isFinite', 'isFunction', 'isNaN', 'isNull', 'isNumber', - 'isObject', 'isRegExp', 'isString', 'isUndefined' - ]; - - _.each(funcs, function(methodName) { - if (xml) { - var pass = true; - - try { - _[methodName](xml); - } catch(e) { - pass = false; - } - ok(pass, '`_.' + methodName + '` should not error'); - } - else { - skipTest(); - } - }); + test('`_.uniq` should use `_.iteratee` internally', 1, function() { + if (!isModularize) { + _.iteratee = getPropB; + deepEqual(_.uniq(objects), [objects[0], objects[2]]); + _.iteratee = iteratee; + } + else { + skipTest(); + } }); }()); @@ -9633,10 +9588,6 @@ skipTest(5); } }); - - test('should be aliased', 1, function() { - strictEqual(_.collect, _.map); - }); }()); /*--------------------------------------------------------------------------*/ @@ -13140,11 +13091,6 @@ strictEqual(actual, 'abc'); }); }); - - test('should be aliased', 2, function() { - strictEqual(_.foldl, _.reduce); - strictEqual(_.inject, _.reduce); - }); }()); /*--------------------------------------------------------------------------*/ @@ -13219,10 +13165,6 @@ strictEqual(actual, 'cba'); }); }); - - test('should be aliased', 1, function() { - strictEqual(_.foldr, _.reduceRight); - }); }()); /*--------------------------------------------------------------------------*/ @@ -13819,10 +13761,6 @@ skipTest(4); } }); - - test('should be aliased', 1, function() { - strictEqual(_.tail, _.rest); - }); }()); /*--------------------------------------------------------------------------*/ @@ -14566,10 +14504,6 @@ var actual = _.map([[1]], _.some); deepEqual(actual, [true]); }); - - test('should be aliased', 1, function() { - strictEqual(_.any, _.some); - }); }()); /*--------------------------------------------------------------------------*/ @@ -16789,10 +16723,6 @@ deepEqual(actual, [['a'], ['b']]); }); }); - - test('should be aliased', 1, function() { - strictEqual(_.unique, _.uniq); - }); }()); /*--------------------------------------------------------------------------*/ @@ -17173,10 +17103,6 @@ skipTest(); } }); - - test('should be aliased', 1, function() { - strictEqual(_.object, _.zipObject); - }); }()); /*--------------------------------------------------------------------------*/ @@ -17899,11 +17825,11 @@ (function() { var funcs = [ 'clone', - 'contains', 'every', 'find', 'first', 'has', + 'includes', 'isArguments', 'isArray', 'isBoolean', @@ -18094,8 +18020,6 @@ ]; var rejectFalsey = [ - 'backflow', - 'compose', 'flow', 'flowRight', 'tap', @@ -18143,7 +18067,7 @@ var acceptFalsey = _.difference(allMethods, rejectFalsey); - test('should accept falsey arguments', 229, function() { + test('should accept falsey arguments', 212, function() { var emptyArrays = _.map(falsey, _.constant([])); _.each(acceptFalsey, function(methodName) { @@ -18203,7 +18127,7 @@ }); }); - test('should throw an error for falsey arguments', 25, function() { + test('should throw an error for falsey arguments', 23, function() { _.each(rejectFalsey, function(methodName) { var expected = _.map(falsey, _.constant(true)), func = _[methodName]; From b5dd2e605ddf10101a6f07e2814f0cdd5a57a641 Mon Sep 17 00:00:00 2001 From: jdalton Date: Fri, 3 Jul 2015 10:24:23 -0700 Subject: [PATCH 004/935] Make `_.forEach` and friends implicitly end a chain sequence. --- lodash.src.js | 12 ++++++------ test/test.js | 37 +++++++++++++++++++------------------ 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 3662e75c80..fd00d8c057 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -12080,12 +12080,6 @@ lodash.flattenDeep = flattenDeep; lodash.flow = flow; lodash.flowRight = flowRight; - lodash.forEach = forEach; - lodash.forEachRight = forEachRight; - lodash.forIn = forIn; - lodash.forInRight = forInRight; - lodash.forOwn = forOwn; - lodash.forOwnRight = forOwnRight; lodash.functions = functions; lodash.groupBy = groupBy; lodash.indexBy = indexBy; @@ -12189,6 +12183,12 @@ lodash.findWhere = findWhere; lodash.first = first; lodash.floor = floor; + lodash.forEach = forEach; + lodash.forEachRight = forEachRight; + lodash.forIn = forIn; + lodash.forInRight = forInRight; + lodash.forOwn = forOwn; + lodash.forOwnRight = forOwnRight; lodash.get = get; lodash.gt = gt; lodash.gte = gte; diff --git a/test/test.js b/test/test.js index 2f10be14b9..729d1ad28d 100644 --- a/test/test.js +++ b/test/test.js @@ -4898,6 +4898,12 @@ 'findLast', 'findLastIndex', 'findLastKey', + 'forEach', + 'forEachRight', + 'forIn', + 'forInRight', + 'forOwn', + 'forOwnRight', 'max', 'min', 'some' @@ -5022,21 +5028,24 @@ test('`_.' + methodName + '` should return an unwrapped value when implicitly chaining', 1, function() { if (!isNpm) { - var wrapped = _(array)[methodName](_.noop); - ok(!(wrapped instanceof _)); + var actual = _(array)[methodName](_.noop); + ok(!(actual instanceof _)); } else { skipTest(); } }); - test('`_.' + methodName + '` should return a wrapped value when implicitly chaining', 1, function() { + test('`_.' + methodName + '` should return a wrapped value when explicitly chaining', 2, function() { if (!isNpm) { - var wrapped = _(array).chain()[methodName](_.noop); - ok(wrapped instanceof _); + var wrapped = _(array).chain(), + actual = wrapped[methodName](_.noop); + + ok(actual instanceof _); + notStrictEqual(actual, wrapped); } else { - skipTest(); + skipTest(2); } }); }); @@ -5076,16 +5085,6 @@ } }); - test('`_.' + methodName + '` should not return the existing wrapped value when chaining', 1, function() { - if (!(isBaseEach || isNpm)) { - var wrapped = _(array); - notStrictEqual(wrapped[methodName](_.noop), wrapped); - } - else { - skipTest(); - } - }); - _.each({ 'literal': 'abc', 'object': Object('abc') @@ -5320,8 +5319,10 @@ test('`_.' + methodName + '` should not return the existing wrapped value when chaining', 1, function() { if (!isNpm) { - var wrapped = _({ 'a': 1 }); - notStrictEqual(wrapped[methodName]({ 'b': 2 }), wrapped); + var wrapped = _({ 'a': 1 }), + actual = wrapped[methodName]({ 'b': 2 }); + + notStrictEqual(actual, wrapped); } else { skipTest(); From 5ff9f01abab994a00001c82ee87a6b07d8f889e4 Mon Sep 17 00:00:00 2001 From: jdalton Date: Fri, 3 Jul 2015 10:48:52 -0700 Subject: [PATCH 005/935] Remove `_.findWhere`, `_.pluck`, & `_.where`. --- lodash.src.js | 191 +++++++++++--------------------------------------- test/test.js | 174 ++------------------------------------------- 2 files changed, 47 insertions(+), 318 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index fd00d8c057..ca3a922c4f 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -887,9 +887,8 @@ * * The wrapper methods that support shortcut fusion are: * `compact`, `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, - * `first`, `initial`, `last`, `map`, `pluck`, `reject`, `rest`, `reverse`, - * `slice`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, `toArray`, - * and `where` + * `first`, `initial`, `last`, `map`, `reject`, `rest`, `reverse`, `slice`, + * `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray` * * The chainable wrapper methods are: * `after`, `ary`, `assign`, `at`, `before`, `bind`, `bindAll`, `bindKey`, @@ -902,29 +901,29 @@ * `invoke`, `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, * `matchesProperty`, `memoize`, `merge`, `method`, `methodOf`, `mixin`, * `modArgs`, `negate`, `omit`, `once`, `pairs`, `partial`, `partialRight`, - * `partition`, `pick`, `plant`, `pluck`, `property`, `propertyOf`, `pull`, - * `pullAt`, `push`, `range`, `rearg`, `reject`, `remove`, `rest`, `restParam`, - * `reverse`, `set`, `shuffle`, `slice`, `sort`, `sortBy`, `sortByAll`, - * `sortByOrder`, `splice`, `spread`, `take`, `takeRight`, `takeRightWhile`, - * `takeWhile`, `tap`, `throttle`, `thru`, `times`, `toArray`, `toPlainObject`, - * `transform`, `union`, `uniq`, `unshift`, `unzip`, `unzipWith`, `values`, - * `valuesIn`, `where`, `without`, `wrap`, `xor`, `zip`, `zipObject`, `zipWith` + * `partition`, `pick`, `plant`, `property`, `propertyOf`, `pull`, `pullAt`, + * `push`, `range`, `rearg`, `reject`, `remove`, `rest`, `restParam`, `reverse`, + * `set`, `shuffle`, `slice`, `sort`, `sortBy`, `sortByAll`, `sortByOrder`, + * `splice`, `spread`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, + * `tap`, `throttle`, `thru`, `times`, `toArray`, `toPlainObject`, `transform`, + * `union`, `uniq`, `unshift`, `unzip`, `unzipWith`, `values`, `valuesIn`, + * `without`, `wrap`, `xor`, `zip`, `zipObject`, `zipWith` * * The wrapper methods that are **not** chainable by default are: * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clone`, `cloneDeep`, * `deburr`, `endsWith`, `escape`, `escapeRegExp`, `every`, `find`, `findIndex`, - * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `findWhere`, `first`, - * `floor`, `get`, `gt`, `gte`, `has`, `identity`, `includes`, `indexOf`, - * `inRange`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`, - * `isEmpty`, `isEqual`, `isError`, `isFinite` `isFunction`, `isMatch`, - * `isNative`, `isNaN`, `isNull`, `isNumber`, `isObject`, `isPlainObject`, - * `isRegExp`, `isString`, `isUndefined`, `isTypedArray`, `join`, `kebabCase`, - * `last`, `lastIndexOf`, `lt`, `lte`, `max`, `min`, `noConflict`, `noop`, - * `now`, `pad`, `padLeft`, `padRight`, `parseInt`, `pop`, `random`, `reduce`, - * `reduceRight`, `repeat`, `result`, `round`, `runInContext`, `shift`, `size`, - * `snakeCase`, `some`, `sortedIndex`, `sortedLastIndex`, `startCase`, - * `startsWith`, `sum`, `template`, `trim`, `trimLeft`, `trimRight`, `trunc`, - * `unescape`, `uniqueId`, `value`, and `words` + * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `first`, `floor`, + * `get`, `gt`, `gte`, `has`, `identity`, `includes`, `indexOf`, `inRange`, + * `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`, `isEmpty`, + * `isEqual`, `isError`, `isFinite` `isFunction`, `isMatch`, `isNative`, + * `isNaN`, `isNull`, `isNumber`, `isObject`, `isPlainObject`, `isRegExp`, + * `isString`, `isUndefined`, `isTypedArray`, `join`, `kebabCase`, `last`, + * `lastIndexOf`, `lt`, `lte`, `max`, `min`, `noConflict`, `noop`, `now`, `pad`, + * `padLeft`, `padRight`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`, + * `repeat`, `result`, `round`, `runInContext`, `shift`, `size`,`snakeCase`, + * `some`, `sortedIndex`, `sortedLastIndex`, `startCase`, `startsWith`, `sum`, + * `template`, `trim`, `trimLeft`, `trimRight`, `trunc`, `unescape`, `uniqueId`, + * `value`, and `words` * * The wrapper method `sample` will return a wrapped value when `n` is provided, * otherwise an unwrapped value is returned. @@ -4812,15 +4811,15 @@ * ]; * * // using the `_.matches` callback shorthand - * _.pluck(_.dropRightWhile(users, { 'user': 'pebbles', 'active': false }), 'user'); + * _.map(_.dropRightWhile(users, { 'user': 'pebbles', 'active': false }), 'user'); * // => ['barney', 'fred'] * * // using the `_.matchesProperty` callback shorthand - * _.pluck(_.dropRightWhile(users, 'active', false), 'user'); + * _.map(_.dropRightWhile(users, 'active', false), 'user'); * // => ['barney'] * * // using the `_.property` callback shorthand - * _.pluck(_.dropRightWhile(users, 'active'), 'user'); + * _.map(_.dropRightWhile(users, 'active'), 'user'); * // => ['barney', 'fred', 'pebbles'] */ function dropRightWhile(array, predicate, thisArg) { @@ -4867,15 +4866,15 @@ * ]; * * // using the `_.matches` callback shorthand - * _.pluck(_.dropWhile(users, { 'user': 'barney', 'active': false }), 'user'); + * _.map(_.dropWhile(users, { 'user': 'barney', 'active': false }), 'user'); * // => ['fred', 'pebbles'] * * // using the `_.matchesProperty` callback shorthand - * _.pluck(_.dropWhile(users, 'active', false), 'user'); + * _.map(_.dropWhile(users, 'active', false), 'user'); * // => ['pebbles'] * * // using the `_.property` callback shorthand - * _.pluck(_.dropWhile(users, 'active'), 'user'); + * _.map(_.dropWhile(users, 'active'), 'user'); * // => ['barney', 'fred', 'pebbles'] */ function dropWhile(array, predicate, thisArg) { @@ -5636,15 +5635,15 @@ * ]; * * // using the `_.matches` callback shorthand - * _.pluck(_.takeRightWhile(users, { 'user': 'pebbles', 'active': false }), 'user'); + * _.map(_.takeRightWhile(users, { 'user': 'pebbles', 'active': false }), 'user'); * // => ['pebbles'] * * // using the `_.matchesProperty` callback shorthand - * _.pluck(_.takeRightWhile(users, 'active', false), 'user'); + * _.map(_.takeRightWhile(users, 'active', false), 'user'); * // => ['fred', 'pebbles'] * * // using the `_.property` callback shorthand - * _.pluck(_.takeRightWhile(users, 'active'), 'user'); + * _.map(_.takeRightWhile(users, 'active'), 'user'); * // => [] */ function takeRightWhile(array, predicate, thisArg) { @@ -5691,15 +5690,15 @@ * ]; * * // using the `_.matches` callback shorthand - * _.pluck(_.takeWhile(users, { 'user': 'barney', 'active': false }), 'user'); + * _.map(_.takeWhile(users, { 'user': 'barney', 'active': false }), 'user'); * // => ['barney'] * * // using the `_.matchesProperty` callback shorthand - * _.pluck(_.takeWhile(users, 'active', false), 'user'); + * _.map(_.takeWhile(users, 'active', false), 'user'); * // => ['barney', 'fred'] * * // using the `_.property` callback shorthand - * _.pluck(_.takeWhile(users, 'active'), 'user'); + * _.map(_.takeWhile(users, 'active'), 'user'); * // => [] */ function takeWhile(array, predicate, thisArg) { @@ -6463,15 +6462,15 @@ * ]; * * // using the `_.matches` callback shorthand - * _.pluck(_.filter(users, { 'age': 36, 'active': true }), 'user'); + * _.map(_.filter(users, { 'age': 36, 'active': true }), 'user'); * // => ['barney'] * * // using the `_.matchesProperty` callback shorthand - * _.pluck(_.filter(users, 'active', false), 'user'); + * _.map(_.filter(users, 'active', false), 'user'); * // => ['fred'] * * // using the `_.property` callback shorthand - * _.pluck(_.filter(users, 'active'), 'user'); + * _.map(_.filter(users, 'active'), 'user'); * // => ['barney'] */ function filter(collection, predicate, thisArg) { @@ -6553,39 +6552,6 @@ */ var findLast = createFind(baseEachRight, true); - /** - * Performs a deep comparison between each element in `collection` and the - * source object, returning the first element that has equivalent property - * values. - * - * **Note:** This method supports comparing arrays, booleans, `Date` objects, - * numbers, `Object` objects, regexes, and strings. Objects are compared by - * their own, not inherited, enumerable properties. For comparing a single - * own or inherited property value see `_.matchesProperty`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to search. - * @param {Object} source The object of property values to match. - * @returns {*} Returns the matched element, else `undefined`. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': true }, - * { 'user': 'fred', 'age': 40, 'active': false } - * ]; - * - * _.result(_.findWhere(users, { 'age': 36, 'active': true }), 'user'); - * // => 'barney' - * - * _.result(_.findWhere(users, { 'age': 40, 'active': false }), 'user'); - * // => 'fred' - */ - function findWhere(collection, source) { - return find(collection, baseMatches(source)); - } - /** * Iterates over elements of `collection` invoking `iteratee` for each element. * The `iteratee` is bound to `thisArg` and invoked with three arguments: @@ -6925,7 +6891,7 @@ * ]; * * var mapper = function(array) { - * return _.pluck(array, 'user'); + * return _.map(array, 'user'); * }; * * // using the `_.matches` callback shorthand @@ -6944,33 +6910,6 @@ result[key ? 0 : 1].push(value); }, function() { return [[], []]; }); - /** - * Gets the property value of `path` from all elements in `collection`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Array|string} path The path of the property to pluck. - * @returns {Array} Returns the property values. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 } - * ]; - * - * _.pluck(users, 'user'); - * // => ['barney', 'fred'] - * - * var userIndex = _.indexBy(users, 'user'); - * _.pluck(userIndex, 'age'); - * // => [36, 40] (iteration order is not guaranteed) - */ - function pluck(collection, path) { - return map(collection, property(path)); - } - /** * Reduces `collection` to a value which is the accumulated result of running * each element in `collection` through `iteratee`, where each successive @@ -7059,15 +6998,15 @@ * ]; * * // using the `_.matches` callback shorthand - * _.pluck(_.reject(users, { 'age': 40, 'active': true }), 'user'); + * _.map(_.reject(users, { 'age': 40, 'active': true }), 'user'); * // => ['barney'] * * // using the `_.matchesProperty` callback shorthand - * _.pluck(_.reject(users, 'active', false), 'user'); + * _.map(_.reject(users, 'active', false), 'user'); * // => ['fred'] * * // using the `_.property` callback shorthand - * _.pluck(_.reject(users, 'active'), 'user'); + * _.map(_.reject(users, 'active'), 'user'); * // => ['barney'] */ function reject(collection, predicate, thisArg) { @@ -7267,7 +7206,7 @@ * ]; * * // using the `_.property` callback shorthand - * _.pluck(_.sortBy(users, 'user'), 'user'); + * _.map(_.sortBy(users, 'user'), 'user'); * // => ['barney', 'fred', 'pebbles'] */ function sortBy(collection, iteratee, thisArg) { @@ -7382,39 +7321,6 @@ return baseSortByOrder(collection, iteratees, orders); } - /** - * Performs a deep comparison between each element in `collection` and the - * source object, returning an array of all elements that have equivalent - * property values. - * - * **Note:** This method supports comparing arrays, booleans, `Date` objects, - * numbers, `Object` objects, regexes, and strings. Objects are compared by - * their own, not inherited, enumerable properties. For comparing a single - * own or inherited property value see `_.matchesProperty`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to search. - * @param {Object} source The object of property values to match. - * @returns {Array} Returns the new filtered array. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': false, 'pets': ['hoppy'] }, - * { 'user': 'fred', 'age': 40, 'active': true, 'pets': ['baby puss', 'dino'] } - * ]; - * - * _.pluck(_.where(users, { 'age': 36, 'active': false }), 'user'); - * // => ['barney'] - * - * _.pluck(_.where(users, { 'pets': ['dino'] }), 'user'); - * // => ['fred'] - */ - function where(collection, source) { - return filter(collection, baseMatches(source)); - } - /*------------------------------------------------------------------------*/ /** @@ -11636,7 +11542,7 @@ * _.map(objects, _.property('a.b.c')); * // => [2, 1] * - * _.pluck(_.sortBy(objects, _.property(['a', 'b', 'c'])), 'a.b.c'); + * _.map(_.sortBy(objects, _.property(['a', 'b', 'c'])), 'a.b.c'); * // => [1, 2] */ function property(path) { @@ -12109,7 +12015,6 @@ lodash.partialRight = partialRight; lodash.partition = partition; lodash.pick = pick; - lodash.pluck = pluck; lodash.property = property; lodash.propertyOf = propertyOf; lodash.pull = pull; @@ -12144,7 +12049,6 @@ lodash.unzipWith = unzipWith; lodash.values = values; lodash.valuesIn = valuesIn; - lodash.where = where; lodash.without = without; lodash.wrap = wrap; lodash.xor = xor; @@ -12180,7 +12084,6 @@ lodash.findLast = findLast; lodash.findLastIndex = findLastIndex; lodash.findLastKey = findLastKey; - lodash.findWhere = findWhere; lodash.first = first; lodash.floor = floor; lodash.forEach = forEach; @@ -12353,16 +12256,6 @@ }; }); - // Add `LazyWrapper` methods for `_.pluck` and `_.where`. - arrayEach(['pluck', 'where'], function(methodName, index) { - var operationName = index ? 'filter' : 'map', - createCallback = index ? baseMatches : property; - - LazyWrapper.prototype[methodName] = function(value) { - return this[operationName](createCallback(value)); - }; - }); - LazyWrapper.prototype.compact = function() { return this.filter(identity); }; diff --git a/test/test.js b/test/test.js index 729d1ad28d..1965d82eb8 100644 --- a/test/test.js +++ b/test/test.js @@ -2303,7 +2303,7 @@ }); test('`_.' + methodName + '` should work with curried functions with placeholders', 1, function() { - var curried = _.curry(_.pluck), + var curried = _.curry(_.ary(_.map, 2), 2), getProp = curried(curried.placeholder, 'a'), objects = [{ 'a': 1 }, { 'a': 2 }, { 'a': 1 }]; @@ -4123,46 +4123,6 @@ /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.findWhere'); - - (function() { - var objects = [ - { 'a': 1 }, - { 'a': 1 }, - { 'a': 1, 'b': 2 }, - { 'a': 2, 'b': 2 }, - { 'a': 3 } - ]; - - test('should filter by `source` properties', 6, function() { - strictEqual(_.findWhere(objects, { 'a': 1 }), objects[0]); - strictEqual(_.findWhere(objects, { 'a': 2 }), objects[3]); - strictEqual(_.findWhere(objects, { 'a': 3 }), objects[4]); - strictEqual(_.findWhere(objects, { 'b': 1 }), undefined); - strictEqual(_.findWhere(objects, { 'b': 2 }), objects[2]); - strictEqual(_.findWhere(objects, { 'a': 1, 'b': 2 }), objects[2]); - }); - - test('should work with a function for `source`', 1, function() { - function source() {} - source.a = 2; - - strictEqual(_.findWhere(objects, source), objects[3]); - }); - - test('should match all elements when provided an empty `source`', 1, function() { - var expected = _.map(empties, _.constant(true)); - - var actual = _.map(empties, function(value) { - return _.findWhere(objects, value) === objects[0]; - }); - - deepEqual(actual, expected); - }); - }()); - - /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.first'); (function() { @@ -12372,72 +12332,6 @@ /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.pluck'); - - (function() { - test('should return an array of property values from each element of a collection', 1, function() { - var objects = [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }]; - deepEqual(_.pluck(objects, 'name'), ['barney', 'fred']); - }); - - test('should pluck inherited property values', 1, function() { - function Foo() { this.a = 1; } - Foo.prototype.b = 2; - - deepEqual(_.pluck([new Foo], 'b'), [2]); - }); - - test('should work with an object for `collection`', 1, function() { - var object = { 'a': [1], 'b': [1, 2], 'c': [1, 2, 3] }; - deepEqual(_.pluck(object, 'length'), [1, 2, 3]); - }); - - test('should return `undefined` for undefined properties', 1, function() { - var array = [{ 'a': 1 }], - actual = [_.pluck(array, 'b'), _.pluck(array, 'c')]; - - deepEqual(actual, [[undefined], [undefined]]); - }); - - test('should work with nullish elements', 1, function() { - var objects = [{ 'a': 1 }, null, undefined, { 'a': 4 }]; - deepEqual(_.pluck(objects, 'a'), [1, undefined, undefined, 4]); - }); - - test('should coerce `key` to a string', 1, function() { - function fn() {} - fn.toString = _.constant('fn'); - - var objects = [{ 'null': 1 }, { 'undefined': 2 }, { 'fn': 3 }, { '[object Object]': 4 }], - values = [null, undefined, fn, {}] - - var actual = _.map(objects, function(object, index) { - return _.pluck([object], values[index]); - }); - - deepEqual(actual, [[1], [2], [3], [4]]); - }); - - test('should work in a lazy chain sequence', 2, function() { - if (!isNpm) { - var array = _.times(LARGE_ARRAY_SIZE + 1, function(index) { - return index ? { 'a': index } : null; - }); - - var actual = _(array).slice(1).pluck('a').value(); - deepEqual(actual, _.pluck(array.slice(1), 'a')); - - actual = _(array).slice(1).filter().pluck('a').value(); - deepEqual(actual, _.pluck(_.filter(array.slice(1)), 'a')); - } - else { - skipTest(2); - } - }); - }()); - - /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.property'); (function() { @@ -14541,7 +14435,7 @@ var stableObject = _.zipObject('abcdefghijklmnopqrst'.split(''), stableArray); test('should sort in ascending order', 1, function() { - var actual = _.pluck(_.sortBy(objects, function(object) { + var actual = _.map(_.sortBy(objects, function(object) { return object.b; }), 'b'); @@ -14589,7 +14483,7 @@ }); test('should work with a "_.property" style `iteratee`', 1, function() { - var actual = _.pluck(_.sortBy(objects.concat(undefined), 'b'), 'b'); + var actual = _.map(_.sortBy(objects.concat(undefined), 'b'), 'b'); deepEqual(actual, [1, 2, 3, 4, undefined]); }); @@ -16808,62 +16702,6 @@ /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.where'); - - (function() { - test('should filter by `source` properties', 12, function() { - var objects = [ - { 'a': 1 }, - { 'a': 1 }, - { 'a': 1, 'b': 2 }, - { 'a': 2, 'b': 2 }, - { 'a': 3 } - ]; - - var pairs = [ - [{ 'a': 1 }, [{ 'a': 1 }, { 'a': 1 }, { 'a': 1, 'b': 2 }]], - [{ 'a': 2 }, [{ 'a': 2, 'b': 2 }]], - [{ 'a': 3 }, [{ 'a': 3 }]], - [{ 'b': 1 }, []], - [{ 'b': 2 }, [{ 'a': 1, 'b': 2 }, { 'a': 2, 'b': 2 }]], - [{ 'a': 1, 'b': 2 }, [{ 'a': 1, 'b': 2 }]] - ]; - - _.each(pairs, function(pair) { - var actual = _.where(objects, pair[0]); - deepEqual(actual, pair[1]); - ok(_.isEmpty(_.difference(actual, objects))); - }); - }); - - test('should work with an object for `collection`', 1, function() { - var object = { - 'x': { 'a': 1 }, - 'y': { 'a': 3 }, - 'z': { 'a': 1, 'b': 2 } - }; - - var actual = _.where(object, { 'a': 1 }); - deepEqual(actual, [object.x, object.z]); - }); - - test('should work in a lazy chain sequence', 1, function() { - if (!isNpm) { - var array = _.times(LARGE_ARRAY_SIZE + 1, function(index) { - return index ? { 'a': 1, 'b': index } : { 'a': 3 }; - }); - - var actual = _(array).slice(1).where({ 'a': 1 }).value(); - deepEqual(actual, _.where(array.slice(1), { 'a': 1 })); - } - else { - skipTest(); - } - }); - }()); - - /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.without'); (function() { @@ -18042,7 +17880,6 @@ 'keys', 'map', 'pairs', - 'pluck', 'pull', 'pullAt', 'range', @@ -18060,7 +17897,6 @@ 'union', 'uniq', 'values', - 'where', 'without', 'xor', 'zip' @@ -18068,7 +17904,7 @@ var acceptFalsey = _.difference(allMethods, rejectFalsey); - test('should accept falsey arguments', 212, function() { + test('should accept falsey arguments', 207, function() { var emptyArrays = _.map(falsey, _.constant([])); _.each(acceptFalsey, function(methodName) { @@ -18104,7 +17940,7 @@ }); }); - test('should return an array', 72, function() { + test('should return an array', 68, function() { var array = [1, 2, 3]; _.each(returnArrays, function(methodName) { From 454aca7003e14994e7b9f6ebc5ab436142690eda Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Mon, 20 Jul 2015 09:58:10 -0700 Subject: [PATCH 006/935] Remove `thisArg` params from most methods. --- lodash.src.js | 931 +++++++++++++------------------------------------- test/test.js | 468 ++----------------------- 2 files changed, 265 insertions(+), 1134 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index ca3a922c4f..9481cf5bd2 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -903,9 +903,9 @@ * `modArgs`, `negate`, `omit`, `once`, `pairs`, `partial`, `partialRight`, * `partition`, `pick`, `plant`, `property`, `propertyOf`, `pull`, `pullAt`, * `push`, `range`, `rearg`, `reject`, `remove`, `rest`, `restParam`, `reverse`, - * `set`, `shuffle`, `slice`, `sort`, `sortBy`, `sortByAll`, `sortByOrder`, - * `splice`, `spread`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, - * `tap`, `throttle`, `thru`, `times`, `toArray`, `toPlainObject`, `transform`, + * `set`, `shuffle`, `slice`, `sort`, `sortBy`, `sortByOrder`, `splice`, + * `spread`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, `tap`, + * `throttle`, `thru`, `times`, `toArray`, `toPlainObject`, `transform`, * `union`, `uniq`, `unshift`, `unzip`, `unzipWith`, `values`, `valuesIn`, * `without`, `wrap`, `xor`, `zip`, `zipObject`, `zipWith` * @@ -1464,8 +1464,7 @@ * @private * @param {Array} array The array to iterate over. * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if all elements pass the predicate check, - * else `false`. + * @returns {boolean} Returns `true` if all elements pass the predicate check, else `false`. */ function arrayEvery(array, predicate) { var index = -1, @@ -1579,8 +1578,7 @@ * @param {Array} array The array to iterate over. * @param {Function} iteratee The function invoked per iteration. * @param {*} [accumulator] The initial value. - * @param {boolean} [initFromArray] Specify using the first element of `array` - * as the initial value. + * @param {boolean} [initFromArray] Specify using the first element of `array` as the initial value. * @returns {*} Returns the accumulated value. */ function arrayReduce(array, iteratee, accumulator, initFromArray) { @@ -1604,8 +1602,7 @@ * @param {Array} array The array to iterate over. * @param {Function} iteratee The function invoked per iteration. * @param {*} [accumulator] The initial value. - * @param {boolean} [initFromArray] Specify using the last element of `array` - * as the initial value. + * @param {boolean} [initFromArray] Specify using the last element of `array` as the initial value. * @returns {*} Returns the accumulated value. */ function arrayReduceRight(array, iteratee, accumulator, initFromArray) { @@ -1626,8 +1623,7 @@ * @private * @param {Array} array The array to iterate over. * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. + * @returns {boolean} Returns `true` if any element passes the predicate check, else `false`. */ function arraySome(array, predicate) { var index = -1, @@ -1968,8 +1964,7 @@ * @private * @param {Array|Object|string} collection The collection to iterate over. * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if all elements pass the predicate check, - * else `false` + * @returns {boolean} Returns `true` if all elements pass the predicate check, else `false` */ function baseEvery(collection, predicate) { var result = true; @@ -1983,7 +1978,7 @@ /** * Gets the extremum value of `collection` invoking `iteratee` for each value * in `collection` to generate the criterion by which the value is ranked. - * The `iteratee` is invoked with three arguments: (value, index|key, collection). + * The iteratee is invoked with three arguments: (value, index|key, collection). * * @private * @param {Array|Object|string} collection The collection to iterate over. @@ -2064,8 +2059,7 @@ * @param {Array|Object|string} collection The collection to search. * @param {Function} predicate The function invoked per iteration. * @param {Function} eachFunc The function to iterate over `collection`. - * @param {boolean} [retKey] Specify returning the key of the found element - * instead of the element itself. + * @param {boolean} [retKey] Specify returning the key of the found element instead of the element itself. * @returns {*} Returns the found element or its key, else `undefined`. */ function baseFind(collection, predicate, eachFunc, retKey) { @@ -2119,26 +2113,22 @@ * * @private * @param {*} [func=_.identity] The value to convert to an iteratee. - * @param {*} [thisArg] The `this` binding of `func`. - * @param {number} [argCount] The number of arguments to provide to `func`. * @returns {Function} Returns the iteratee. */ - function baseIteratee(func, thisArg, argCount) { + function baseIteratee(func) { var type = typeof func; if (type == 'function') { - return thisArg === undefined - ? func - : bindCallback(func, thisArg, argCount); + return func; } if (func == null) { return identity; } if (type == 'object') { - return baseMatches(func); + return isArray(func) + ? baseMatchesProperty(func[0], func[1]) + : baseMatches(func); } - return thisArg === undefined - ? property(func) - : baseMatchesProperty(func, thisArg); + return property(func); } /** @@ -2660,8 +2650,7 @@ * @param {Array|Object|string} collection The collection to iterate over. * @param {Function} iteratee The function invoked per iteration. * @param {*} accumulator The initial value. - * @param {boolean} initFromCollection Specify using the first or last element - * of `collection` as the initial value. + * @param {boolean} initFromCollection Specify using the first or last element of `collection` as the initial value. * @param {Function} eachFunc The function to iterate over `collection`. * @returns {*} Returns the accumulated value. */ @@ -2725,8 +2714,7 @@ * @private * @param {Array|Object|string} collection The collection to iterate over. * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. + * @returns {boolean} Returns `true` if any element passes the predicate check, else `false`. */ function baseSome(collection, predicate) { var result; @@ -2960,8 +2948,7 @@ * @param {*} value The value to evaluate. * @param {Function} iteratee The function invoked per iteration. * @param {boolean} [retHighest] Specify returning the highest qualified index. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. + * @returns {number} Returns the index at which `value` should be inserted into `array`. */ function binaryIndexBy(array, value, iteratee, retHighest) { value = iteratee(value); @@ -3004,34 +2991,10 @@ * * @private * @param {Function} func The function to bind. - * @param {*} thisArg The `this` binding of `func`. - * @param {number} [argCount] The number of arguments to provide to `func`. * @returns {Function} Returns the callback. */ - function bindCallback(func, thisArg, argCount) { - if (typeof func != 'function') { - return identity; - } - if (thisArg === undefined) { - return func; - } - switch (argCount) { - case 1: return function(value) { - return func.call(thisArg, value); - }; - case 3: return function(value, index, collection) { - return func.call(thisArg, value, index, collection); - }; - case 4: return function(accumulator, value, index, collection) { - return func.call(thisArg, accumulator, value, index, collection); - }; - case 5: return function(value, other, key, object, source) { - return func.call(thisArg, value, other, key, object, source); - }; - } - return function() { - return func.apply(thisArg, arguments); - }; + function bindCallback(func) { + return typeof func == 'function' ? func : identity; } /** @@ -3120,9 +3083,9 @@ * @returns {Function} Returns the new aggregator function. */ function createAggregator(setter, initializer) { - return function(collection, iteratee, thisArg) { + return function(collection, iteratee) { var result = initializer ? initializer() : {}; - iteratee = getIteratee(iteratee, thisArg, 3); + iteratee = getIteratee(iteratee); if (isArray(collection)) { var index = -1, @@ -3152,17 +3115,10 @@ return restParam(function(object, sources) { var index = -1, length = object == null ? 0 : sources.length, - customizer = length > 2 ? sources[length - 2] : undefined, - guard = length > 2 ? sources[2] : undefined, - thisArg = length > 1 ? sources[length - 1] : undefined; + customizer = length > 1 ? sources[length - 1] : undefined, + guard = length > 2 ? sources[2] : undefined; - if (typeof customizer == 'function') { - customizer = bindCallback(customizer, thisArg, 5); - length -= 2; - } else { - customizer = typeof thisArg == 'function' ? thisArg : undefined; - length -= (customizer ? 1 : 0); - } + customizer = typeof customizer == 'function' ? (length--, customizer) : undefined; if (guard && isIterateeCall(sources[0], sources[1], guard)) { customizer = length < 3 ? undefined : customizer; length = 1; @@ -3359,11 +3315,11 @@ * @returns {Function} Returns the new extremum function. */ function createExtremum(comparator, exValue) { - return function(collection, iteratee, thisArg) { - if (thisArg && isIterateeCall(collection, iteratee, thisArg)) { + return function(collection, iteratee, guard) { + if (guard && isIterateeCall(collection, iteratee, guard)) { iteratee = undefined; } - iteratee = getIteratee(iteratee, thisArg, 3); + iteratee = getIteratee(iteratee); if (iteratee.length == 1) { collection = isArray(collection) ? collection : toIterable(collection); var result = arrayExtremum(collection, iteratee, comparator, exValue); @@ -3384,8 +3340,8 @@ * @returns {Function} Returns the new find function. */ function createFind(eachFunc, fromRight) { - return function(collection, predicate, thisArg) { - predicate = getIteratee(predicate, thisArg, 3); + return function(collection, predicate) { + predicate = getIteratee(predicate); if (isArray(collection)) { var index = baseFindIndex(collection, predicate, fromRight); return index > -1 ? collection[index] : undefined; @@ -3402,11 +3358,11 @@ * @returns {Function} Returns the new find function. */ function createFindIndex(fromRight) { - return function(array, predicate, thisArg) { + return function(array, predicate) { if (!(array && array.length)) { return -1; } - predicate = getIteratee(predicate, thisArg, 3); + predicate = getIteratee(predicate); return baseFindIndex(array, predicate, fromRight); }; } @@ -3419,8 +3375,8 @@ * @returns {Function} Returns the new find function. */ function createFindKey(objectFunc) { - return function(object, predicate, thisArg) { - predicate = getIteratee(predicate, thisArg, 3); + return function(object, predicate) { + predicate = getIteratee(predicate); return baseFind(object, predicate, objectFunc, true); }; } @@ -3489,10 +3445,10 @@ * @returns {Function} Returns the new each function. */ function createForEach(arrayFunc, eachFunc) { - return function(collection, iteratee, thisArg) { - return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection)) + return function(collection, iteratee) { + return (typeof iteratee == 'function' && isArray(collection)) ? arrayFunc(collection, iteratee) - : eachFunc(collection, bindCallback(iteratee, thisArg, 3)); + : eachFunc(collection, bindCallback(iteratee)); }; } @@ -3504,9 +3460,9 @@ * @returns {Function} Returns the new each function. */ function createForIn(objectFunc) { - return function(object, iteratee, thisArg) { - if (typeof iteratee != 'function' || thisArg !== undefined) { - iteratee = bindCallback(iteratee, thisArg, 3); + return function(object, iteratee) { + if (typeof iteratee != 'function') { + iteratee = bindCallback(iteratee); } return objectFunc(object, iteratee, keysIn); }; @@ -3520,9 +3476,9 @@ * @returns {Function} Returns the new each function. */ function createForOwn(objectFunc) { - return function(object, iteratee, thisArg) { - if (typeof iteratee != 'function' || thisArg !== undefined) { - iteratee = bindCallback(iteratee, thisArg, 3); + return function(object, iteratee) { + if (typeof iteratee != 'function') { + iteratee = bindCallback(iteratee); } return objectFunc(object, iteratee); }; @@ -3536,9 +3492,9 @@ * @returns {Function} Returns the new map function. */ function createObjectMapper(isMapKeys) { - return function(object, iteratee, thisArg) { + return function(object, iteratee) { var result = {}; - iteratee = getIteratee(iteratee, thisArg, 3); + iteratee = getIteratee(iteratee); baseForOwn(object, function(value, key, object) { var mapped = iteratee(value, key, object); @@ -3588,11 +3544,11 @@ * @returns {Function} Returns the new each function. */ function createReduce(arrayFunc, eachFunc) { - return function(collection, iteratee, accumulator, thisArg) { + return function(collection, iteratee, accumulator) { var initFromArray = arguments.length < 3; - return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection)) + return (typeof iteratee == 'function' && isArray(collection)) ? arrayFunc(collection, iteratee, accumulator, initFromArray) - : baseReduce(collection, getIteratee(iteratee, thisArg, 4), accumulator, initFromArray, eachFunc); + : baseReduce(collection, getIteratee(iteratee), accumulator, initFromArray, eachFunc); }; } @@ -3770,11 +3726,11 @@ * @returns {Function} Returns the new index function. */ function createSortedIndex(retHighest) { - return function(array, value, iteratee, thisArg) { - var callback = getIteratee(iteratee); + return function(array, value, iteratee) { + var callback = getIteratee(); return (iteratee == null && callback === baseIteratee) ? binaryIndex(array, value, retHighest) - : binaryIndexBy(array, value, callback(iteratee, thisArg, 1), retHighest); + : binaryIndexBy(array, value, callback(iteratee), retHighest); }; } @@ -4045,10 +4001,10 @@ * @private * @returns {Function} Returns the chosen function or its result. */ - function getIteratee(func, thisArg, argCount) { + function getIteratee() { var result = lodash.iteratee || iteratee; result = result === iteratee ? baseIteratee : result; - return argCount ? result(func, thisArg, argCount) : result; + return arguments.length ? result(arguments[0]) : result; } /** @@ -4776,26 +4732,13 @@ /** * Creates a slice of `array` excluding elements dropped from the end. * Elements are dropped until `predicate` returns falsey. The predicate is - * bound to `thisArg` and invoked with three arguments: (value, index, array). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that match the properties of the given - * object, else `false`. + * invoked with three arguments: (value, index, array). * * @static * @memberOf _ * @category Array * @param {Array} array The array to query. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. + * @param {Function|Object|string} [predicate=_.identity] The function invoked per iteration. * @returns {Array} Returns the slice of `array`. * @example * @@ -4815,42 +4758,29 @@ * // => ['barney', 'fred'] * * // using the `_.matchesProperty` callback shorthand - * _.map(_.dropRightWhile(users, 'active', false), 'user'); + * _.map(_.dropRightWhile(users, ['active', false]), 'user'); * // => ['barney'] * * // using the `_.property` callback shorthand * _.map(_.dropRightWhile(users, 'active'), 'user'); * // => ['barney', 'fred', 'pebbles'] */ - function dropRightWhile(array, predicate, thisArg) { + function dropRightWhile(array, predicate) { return (array && array.length) - ? baseWhile(array, getIteratee(predicate, thisArg, 3), true, true) + ? baseWhile(array, getIteratee(predicate), true, true) : []; } /** * Creates a slice of `array` excluding elements dropped from the beginning. * Elements are dropped until `predicate` returns falsey. The predicate is - * bound to `thisArg` and invoked with three arguments: (value, index, array). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. + * invoked with three arguments: (value, index, array). * * @static * @memberOf _ * @category Array * @param {Array} array The array to query. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. + * @param {Function|Object|string} [predicate=_.identity] The function invoked per iteration. * @returns {Array} Returns the slice of `array`. * @example * @@ -4870,16 +4800,16 @@ * // => ['fred', 'pebbles'] * * // using the `_.matchesProperty` callback shorthand - * _.map(_.dropWhile(users, 'active', false), 'user'); + * _.map(_.dropWhile(users, ['active', false]), 'user'); * // => ['pebbles'] * * // using the `_.property` callback shorthand * _.map(_.dropWhile(users, 'active'), 'user'); * // => ['barney', 'fred', 'pebbles'] */ - function dropWhile(array, predicate, thisArg) { + function dropWhile(array, predicate) { return (array && array.length) - ? baseWhile(array, getIteratee(predicate, thisArg, 3), true) + ? baseWhile(array, getIteratee(predicate), true) : []; } @@ -4927,24 +4857,11 @@ * This method is like `_.find` except that it returns the index of the first * element `predicate` returns truthy for instead of the element itself. * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * * @static * @memberOf _ * @category Array * @param {Array} array The array to search. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. + * @param {Function|Object|string} [predicate=_.identity] The function invoked per iteration. * @returns {number} Returns the index of the found element, else `-1`. * @example * @@ -4964,7 +4881,7 @@ * // => 1 * * // using the `_.matchesProperty` callback shorthand - * _.findIndex(users, 'active', false); + * _.findIndex(users, ['active', false]); * // => 0 * * // using the `_.property` callback shorthand @@ -4977,24 +4894,11 @@ * This method is like `_.findIndex` except that it iterates over elements * of `collection` from right to left. * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * * @static * @memberOf _ * @category Array * @param {Array} array The array to search. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. + * @param {Function|Object|string} [predicate=_.identity] The function invoked per iteration. * @returns {number} Returns the index of the found element, else `-1`. * @example * @@ -5014,7 +4918,7 @@ * // => 0 * * // using the `_.matchesProperty` callback shorthand - * _.findLastIndex(users, 'active', false); + * _.findLastIndex(users, ['active', false]); * // => 2 * * // using the `_.property` callback shorthand @@ -5352,19 +5256,8 @@ /** * Removes all elements from `array` that `predicate` returns truthy for - * and returns an array of the removed elements. The predicate is bound to - * `thisArg` and invoked with three arguments: (value, index, array). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. + * and returns an array of the removed elements. The predicate is invoked with + * three arguments: (value, index, array). * * **Note:** Unlike `_.filter`, this method mutates `array`. * @@ -5372,9 +5265,7 @@ * @memberOf _ * @category Array * @param {Array} array The array to modify. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. + * @param {Function|Object|string} [predicate=_.identity] The function invoked per iteration. * @returns {Array} Returns the new array of removed elements. * @example * @@ -5389,7 +5280,7 @@ * console.log(evens); * // => [2, 4] */ - function remove(array, predicate, thisArg) { + function remove(array, predicate) { var result = []; if (!(array && array.length)) { return result; @@ -5398,7 +5289,7 @@ indexes = [], length = array.length; - predicate = getIteratee(predicate, thisArg, 3); + predicate = getIteratee(predicate); while (++index < length) { var value = array[index]; if (predicate(value, index, array)) { @@ -5458,30 +5349,16 @@ * Uses a binary search to determine the lowest index at which `value` should * be inserted into `array` in order to maintain its sort order. If an iteratee * function is provided it's invoked for `value` and each element of `array` - * to compute their sort ranking. The iteratee is bound to `thisArg` and - * invoked with one argument; (value). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. + * to compute their sort ranking. The iteratee is invoked with one argument: + * (value). * * @static * @memberOf _ * @category Array * @param {Array} array The sorted array to inspect. * @param {*} value The value to evaluate. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. + * @returns {number} Returns the index at which `value` should be inserted into `array`. * @example * * _.sortedIndex([30, 50], 40); @@ -5490,12 +5367,12 @@ * _.sortedIndex([4, 4, 5, 5], 5); * // => 2 * - * var dict = { 'data': { 'thirty': 30, 'forty': 40, 'fifty': 50 } }; + * var dict = { 'thirty': 30, 'forty': 40, 'fifty': 50 }; * * // using an iteratee function * _.sortedIndex(['thirty', 'fifty'], 'forty', function(word) { - * return this.data[word]; - * }, dict); + * return dict[word]; + * }); * // => 1 * * // using the `_.property` callback shorthand @@ -5514,11 +5391,8 @@ * @category Array * @param {Array} array The sorted array to inspect. * @param {*} value The value to evaluate. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. + * @returns {number} Returns the index at which `value` should be inserted into `array`. * @example * * _.sortedLastIndex([4, 4, 5, 5], 5); @@ -5599,27 +5473,14 @@ /** * Creates a slice of `array` with elements taken from the end. Elements are - * taken until `predicate` returns falsey. The predicate is bound to `thisArg` - * and invoked with three arguments: (value, index, array). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. + * taken until `predicate` returns falsey. The predicate is invoked with three + * arguments: (value, index, array). * * @static * @memberOf _ * @category Array * @param {Array} array The array to query. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. + * @param {Function|Object|string} [predicate=_.identity] The function invoked per iteration. * @returns {Array} Returns the slice of `array`. * @example * @@ -5639,42 +5500,29 @@ * // => ['pebbles'] * * // using the `_.matchesProperty` callback shorthand - * _.map(_.takeRightWhile(users, 'active', false), 'user'); + * _.map(_.takeRightWhile(users, ['active', false]), 'user'); * // => ['fred', 'pebbles'] * * // using the `_.property` callback shorthand * _.map(_.takeRightWhile(users, 'active'), 'user'); * // => [] */ - function takeRightWhile(array, predicate, thisArg) { + function takeRightWhile(array, predicate) { return (array && array.length) - ? baseWhile(array, getIteratee(predicate, thisArg, 3), false, true) + ? baseWhile(array, getIteratee(predicate), false, true) : []; } /** * Creates a slice of `array` with elements taken from the beginning. Elements - * are taken until `predicate` returns falsey. The predicate is bound to - * `thisArg` and invoked with three arguments: (value, index, array). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. + * are taken until `predicate` returns falsey. The predicate is invoked with + * three arguments: (value, index, array). * * @static * @memberOf _ * @category Array * @param {Array} array The array to query. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. + * @param {Function|Object|string} [predicate=_.identity] The function invoked per iteration. * @returns {Array} Returns the slice of `array`. * @example * @@ -5694,16 +5542,16 @@ * // => ['barney'] * * // using the `_.matchesProperty` callback shorthand - * _.map(_.takeWhile(users, 'active', false), 'user'); + * _.map(_.takeWhile(users, ['active', false]), 'user'); * // => ['barney', 'fred'] * * // using the `_.property` callback shorthand * _.map(_.takeWhile(users, 'active'), 'user'); * // => [] */ - function takeWhile(array, predicate, thisArg) { + function takeWhile(array, predicate) { return (array && array.length) - ? baseWhile(array, getIteratee(predicate, thisArg, 3)) + ? baseWhile(array, getIteratee(predicate)) : []; } @@ -5733,19 +5581,7 @@ * is kept. Providing `true` for `isSorted` performs a faster search algorithm * for sorted arrays. If an iteratee function is provided it's invoked for * each element in the array to generate the criterion by which uniqueness - * is computed. The `iteratee` is bound to `thisArg` and invoked with three - * arguments: (value, index, array). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. + * is computed. The iteratee is invoked with three arguments: (value, index, array). * * @static * @memberOf _ @@ -5754,7 +5590,6 @@ * @param {Array} array The array to inspect. * @param {boolean} [isSorted] Specify the array is sorted. * @param {Function|Object|string} [iteratee] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {Array} Returns the new duplicate-value-free array. * @example * @@ -5767,27 +5602,26 @@ * * // using an iteratee function * _.uniq([1, 2.5, 1.5, 2], function(n) { - * return this.floor(n); - * }, Math); + * return Math.floor(n); + * }); * // => [1, 2.5] * * // using the `_.property` callback shorthand * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); * // => [{ 'x': 1 }, { 'x': 2 }] */ - function uniq(array, isSorted, iteratee, thisArg) { + function uniq(array, isSorted, iteratee) { var length = array ? array.length : 0; if (!length) { return []; } if (isSorted != null && typeof isSorted != 'boolean') { - thisArg = iteratee; - iteratee = isIterateeCall(array, isSorted, thisArg) ? undefined : isSorted; + iteratee = isIterateeCall(array, isSorted, iteratee) ? undefined : isSorted; isSorted = false; } var callback = getIteratee(); if (!(iteratee == null && callback === baseIteratee)) { - iteratee = callback(iteratee, thisArg, 3); + iteratee = callback(iteratee); } return (isSorted && getIndexOf() === baseIndexOf) ? sortedUniq(array, iteratee) @@ -5834,15 +5668,14 @@ /** * This method is like `_.unzip` except that it accepts an iteratee to specify - * how regrouped values should be combined. The `iteratee` is bound to `thisArg` - * and invoked with four arguments: (accumulator, value, index, group). + * how regrouped values should be combined. The iteratee is invoked with four + * arguments: (accumulator, value, index, group). * * @static * @memberOf _ * @category Array * @param {Array} array The array of grouped elements to process. - * @param {Function} [iteratee] The function to combine regrouped values. - * @param {*} [thisArg] The `this` binding of `iteratee`. + * @param {Function} [iteratee=_.identity] The function to combine regrouped values. * @returns {Array} Returns the new array of regrouped elements. * @example * @@ -5852,7 +5685,7 @@ * _.unzipWith(zipped, _.add); * // => [3, 30, 300] */ - function unzipWith(array, iteratee, thisArg) { + function unzipWith(array, iteratee) { var length = array ? array.length : 0; if (!length) { return []; @@ -5861,7 +5694,7 @@ if (iteratee == null) { return result; } - iteratee = bindCallback(iteratee, thisArg, 4); + iteratee = bindCallback(iteratee); return arrayMap(result, function(group) { return arrayReduce(group, iteratee, undefined, true); }); @@ -5977,15 +5810,14 @@ /** * This method is like `_.zip` except that it accepts an iteratee to specify - * how grouped values should be combined. The `iteratee` is bound to `thisArg` - * and invoked with four arguments: (accumulator, value, index, group). + * how grouped values should be combined. The iteratee is invoked with four + * arguments: (accumulator, value, index, group). * * @static * @memberOf _ * @category Array * @param {...Array} [arrays] The arrays to process. * @param {Function} [iteratee] The function to combine grouped values. - * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {Array} Returns the new array of grouped elements. * @example * @@ -5994,17 +5826,10 @@ */ var zipWith = restParam(function(arrays) { var length = arrays.length, - iteratee = length > 2 ? arrays[length - 2] : undefined, - thisArg = length > 1 ? arrays[length - 1] : undefined; + iteratee = length > 1 ? arrays[length - 1] : undefined; - if (length > 2 && typeof iteratee == 'function') { - length -= 2; - } else { - iteratee = (length > 1 && typeof thisArg == 'function') ? (--length, thisArg) : undefined; - thisArg = undefined; - } - arrays.length = length; - return unzipWith(arrays, iteratee, thisArg); + iteratee = typeof iteratee == 'function' ? (arrays.length--, iteratee) : undefined; + return unzipWith(arrays, iteratee); }); /*------------------------------------------------------------------------*/ @@ -6043,16 +5868,15 @@ /** * This method invokes `interceptor` and returns `value`. The interceptor is - * bound to `thisArg` and invoked with one argument; (value). The purpose of - * this method is to "tap into" a method chain in order to perform operations - * on intermediate results within the chain. + * invoked with one argument; (value). The purpose of this method is to "tap into" + * a method chain in order to perform operations on intermediate results within + * the chain. * * @static * @memberOf _ * @category Chain * @param {*} value The value to provide to `interceptor`. * @param {Function} interceptor The function to invoke. - * @param {*} [thisArg] The `this` binding of `interceptor`. * @returns {*} Returns `value`. * @example * @@ -6064,8 +5888,8 @@ * .value(); * // => [2, 1] */ - function tap(value, interceptor, thisArg) { - interceptor.call(thisArg, value); + function tap(value, interceptor) { + interceptor(value); return value; } @@ -6077,7 +5901,6 @@ * @category Chain * @param {*} value The value to provide to `interceptor`. * @param {Function} interceptor The function to invoke. - * @param {*} [thisArg] The `this` binding of `interceptor`. * @returns {*} Returns the result of `interceptor`. * @example * @@ -6090,8 +5913,8 @@ * .value(); * // => ['abc'] */ - function thru(value, interceptor, thisArg) { - return interceptor.call(thisArg, value); + function thru(value, interceptor) { + return interceptor(value); } /** @@ -6324,27 +6147,13 @@ * Creates an object composed of keys generated from the results of running * each element of `collection` through `iteratee`. The corresponding value * of each key is the number of times the key was returned by `iteratee`. - * The `iteratee` is bound to `thisArg` and invoked with three arguments: - * (value, index|key, collection). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. + * The iteratee is invoked with three arguments: (value, index|key, collection). * * @static * @memberOf _ * @category Collection * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. * @returns {Object} Returns the composed aggregate object. * @example * @@ -6353,11 +6162,6 @@ * }); * // => { '4': 1, '6': 2 } * - * _.countBy([4.3, 6.1, 6.4], function(n) { - * return this.floor(n); - * }, Math); - * // => { '4': 1, '6': 2 } - * * _.countBy(['one', 'two', 'three'], 'length'); * // => { '3': 2, '5': 1 } */ @@ -6367,30 +6171,16 @@ /** * Checks if `predicate` returns truthy for **all** elements of `collection`. - * The predicate is bound to `thisArg` and invoked with three arguments: - * (value, index|key, collection). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. + * The predicate is invoked with three arguments: (value, index|key, collection). * * @static * @memberOf _ * @alias all * @category Collection * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {boolean} Returns `true` if all elements pass the predicate check, - * else `false`. + * @param {Function|Object|string} [predicate=_.identity] The function invoked per iteration. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {boolean} Returns `true` if all elements pass the predicate check, else `false`. * @example * * _.every([true, 1, null, 'yes'], Boolean); @@ -6406,48 +6196,35 @@ * // => false * * // using the `_.matchesProperty` callback shorthand - * _.every(users, 'active', false); + * _.every(users, ['active', false]); * // => true * * // using the `_.property` callback shorthand * _.every(users, 'active'); * // => false */ - function every(collection, predicate, thisArg) { + function every(collection, predicate, guard) { var func = isArray(collection) ? arrayEvery : baseEvery; - if (thisArg && isIterateeCall(collection, predicate, thisArg)) { + if (guard && isIterateeCall(collection, predicate, guard)) { predicate = undefined; } - if (typeof predicate != 'function' || thisArg !== undefined) { - predicate = getIteratee(predicate, thisArg, 3); + if (typeof predicate != 'function') { + predicate = getIteratee(predicate); } return func(collection, predicate); } /** * Iterates over elements of `collection`, returning an array of all elements - * `predicate` returns truthy for. The predicate is bound to `thisArg` and - * invoked with three arguments: (value, index|key, collection). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. + * `predicate` returns truthy for. The predicate is invoked with three arguments: + * (value, index|key, collection). * * @static * @memberOf _ * @alias select * @category Collection * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. + * @param {Function|Object|string} [predicate=_.identity] The function invoked per iteration. * @returns {Array} Returns the new filtered array. * @example * @@ -6466,43 +6243,30 @@ * // => ['barney'] * * // using the `_.matchesProperty` callback shorthand - * _.map(_.filter(users, 'active', false), 'user'); + * _.map(_.filter(users, ['active', false]), 'user'); * // => ['fred'] * * // using the `_.property` callback shorthand * _.map(_.filter(users, 'active'), 'user'); * // => ['barney'] */ - function filter(collection, predicate, thisArg) { + function filter(collection, predicate) { var func = isArray(collection) ? arrayFilter : baseFilter; - predicate = getIteratee(predicate, thisArg, 3); + predicate = getIteratee(predicate); return func(collection, predicate); } /** * Iterates over elements of `collection`, returning the first element - * `predicate` returns truthy for. The predicate is bound to `thisArg` and - * invoked with three arguments: (value, index|key, collection). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. + * `predicate` returns truthy for. The predicate is invoked with three arguments: + * (value, index|key, collection). * * @static * @memberOf _ * @alias detect * @category Collection * @param {Array|Object|string} collection The collection to search. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. + * @param {Function|Object|string} [predicate=_.identity] The function invoked per iteration. * @returns {*} Returns the matched element, else `undefined`. * @example * @@ -6522,7 +6286,7 @@ * // => 'pebbles' * * // using the `_.matchesProperty` callback shorthand - * _.result(_.find(users, 'active', false), 'user'); + * _.result(_.find(users, ['active', false]), 'user'); * // => 'fred' * * // using the `_.property` callback shorthand @@ -6539,9 +6303,7 @@ * @memberOf _ * @category Collection * @param {Array|Object|string} collection The collection to search. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. + * @param {Function|Object|string} [predicate=_.identity] The function invoked per iteration. * @returns {*} Returns the matched element, else `undefined`. * @example * @@ -6554,9 +6316,8 @@ /** * Iterates over elements of `collection` invoking `iteratee` for each element. - * The `iteratee` is bound to `thisArg` and invoked with three arguments: - * (value, index|key, collection). Iteratee functions may exit iteration early - * by explicitly returning `false`. + * The iteratee is invoked with three arguments: (value, index|key, collection). + * Iteratee functions may exit iteration early by explicitly returning `false`. * * **Note:** As with other "Collections" methods, objects with a "length" property * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn` @@ -6568,13 +6329,12 @@ * @category Collection * @param {Array|Object|string} collection The collection to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {Array|Object|string} Returns `collection`. * @example * * _([1, 2]).forEach(function(n) { * console.log(n); - * }).value(); + * }); * // => logs each value from left to right and returns the array * * _.forEach({ 'a': 1, 'b': 2 }, function(n, key) { @@ -6594,13 +6354,12 @@ * @category Collection * @param {Array|Object|string} collection The collection to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {Array|Object|string} Returns `collection`. * @example * - * _([1, 2]).forEachRight(function(n) { + * _.forEachRight([1, 2], function(n) { * console.log(n); - * }).value(); + * }); * // => logs each value from right to left and returns the array */ var forEachRight = createForEach(arrayEachRight, baseEachRight); @@ -6609,27 +6368,13 @@ * Creates an object composed of keys generated from the results of running * each element of `collection` through `iteratee`. The corresponding value * of each key is an array of the elements responsible for generating the key. - * The `iteratee` is bound to `thisArg` and invoked with three arguments: - * (value, index|key, collection). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. + * The iteratee is invoked with three arguments: (value, index|key, collection). * * @static * @memberOf _ * @category Collection * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. * @returns {Object} Returns the composed aggregate object. * @example * @@ -6638,11 +6383,6 @@ * }); * // => { '4': [4.2], '6': [6.1, 6.4] } * - * _.groupBy([4.2, 6.1, 6.4], function(n) { - * return this.floor(n); - * }, Math); - * // => { '4': [4.2], '6': [6.1, 6.4] } - * * // using the `_.property` callback shorthand * _.groupBy(['one', 'two', 'three'], 'length'); * // => { '3': ['one', 'two'], '5': ['three'] } @@ -6704,27 +6444,13 @@ * Creates an object composed of keys generated from the results of running * each element of `collection` through `iteratee`. The corresponding value * of each key is the last element responsible for generating the key. The - * iteratee function is bound to `thisArg` and invoked with three arguments: - * (value, index|key, collection). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. + * iteratee is invoked with three arguments: (value, index|key, collection). * * @static * @memberOf _ * @category Collection * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. * @returns {Object} Returns the composed aggregate object. * @example * @@ -6740,11 +6466,6 @@ * return String.fromCharCode(object.code); * }); * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } - * - * _.indexBy(keyData, function(object) { - * return this.fromCharCode(object.code); - * }, String); - * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } */ var indexBy = createAggregator(function(result, value, key) { result[key] = value; @@ -6760,8 +6481,7 @@ * @memberOf _ * @category Collection * @param {Array|Object|string} collection The collection to iterate over. - * @param {Array|Function|string} path The path of the method to invoke or - * the function invoked per iteration. + * @param {Array|Function|string} path The path of the method to invoke or the function invoked per iteration. * @param {...*} [args] The arguments to invoke the method with. * @returns {Array} Returns the array of results. * @example @@ -6787,19 +6507,8 @@ /** * Creates an array of values by running each element in `collection` through - * `iteratee`. The `iteratee` is bound to `thisArg` and invoked with three - * arguments: (value, index|key, collection). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. + * `iteratee`. The iteratee is invoked with three arguments: + * (value, index|key, collection). * * Many lodash methods are guarded to work as iteratees for methods like * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`. @@ -6816,9 +6525,7 @@ * @alias collect * @category Collection * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. * @returns {Array} Returns the new mapped array. * @example * @@ -6841,36 +6548,23 @@ * _.map(users, 'user'); * // => ['barney', 'fred'] */ - function map(collection, iteratee, thisArg) { + function map(collection, iteratee) { var func = isArray(collection) ? arrayMap : baseMap; - iteratee = getIteratee(iteratee, thisArg, 3); + iteratee = getIteratee(iteratee); return func(collection, iteratee); } /** * Creates an array of elements split into two groups, the first of which * contains elements `predicate` returns truthy for, while the second of which - * contains elements `predicate` returns falsey for. The predicate is bound - * to `thisArg` and invoked with three arguments: (value, index|key, collection). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. + * contains elements `predicate` returns falsey for. The predicate is invoked + * with three arguments: (value, index|key, collection). * * @static * @memberOf _ * @category Collection * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. + * @param {Function|Object|string} [predicate=_.identity] The function invoked per iteration. * @returns {Array} Returns the array of grouped elements. * @example * @@ -6879,11 +6573,6 @@ * }); * // => [[1, 3], [2]] * - * _.partition([1.2, 2.3, 3.4], function(n) { - * return this.floor(n) % 2; - * }, Math); - * // => [[1.2, 3.4], [2.3]] - * * var users = [ * { 'user': 'barney', 'age': 36, 'active': false }, * { 'user': 'fred', 'age': 40, 'active': true }, @@ -6899,7 +6588,7 @@ * // => [['pebbles'], ['barney', 'fred']] * * // using the `_.matchesProperty` callback shorthand - * _.map(_.partition(users, 'active', false), mapper); + * _.map(_.partition(users, ['active', false]), mapper); * // => [['barney', 'pebbles'], ['fred']] * * // using the `_.property` callback shorthand @@ -6915,14 +6604,14 @@ * each element in `collection` through `iteratee`, where each successive * invocation is supplied the return value of the previous. If `accumulator` * is not provided the first element of `collection` is used as the initial - * value. The `iteratee` is bound to `thisArg` and invoked with four arguments: + * value. The iteratee is invoked with four arguments: * (accumulator, value, index|key, collection). * * Many lodash methods are guarded to work as iteratees for methods like * `_.reduce`, `_.reduceRight`, and `_.transform`. * * The guarded methods are: - * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `sortByAll`, + * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `sortBy`, * and `sortByOrder` * * @static @@ -6932,7 +6621,6 @@ * @param {Array|Object|string} collection The collection to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. * @param {*} [accumulator] The initial value. - * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {*} Returns the accumulated value. * @example * @@ -6960,7 +6648,6 @@ * @param {Array|Object|string} collection The collection to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. * @param {*} [accumulator] The initial value. - * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {*} Returns the accumulated value. * @example * @@ -6981,9 +6668,7 @@ * @memberOf _ * @category Collection * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. + * @param {Function|Object|string} [predicate=_.identity] The function invoked per iteration. * @returns {Array} Returns the new filtered array. * @example * @@ -7002,16 +6687,16 @@ * // => ['barney'] * * // using the `_.matchesProperty` callback shorthand - * _.map(_.reject(users, 'active', false), 'user'); + * _.map(_.reject(users, ['active', false]), 'user'); * // => ['fred'] * * // using the `_.property` callback shorthand * _.map(_.reject(users, 'active'), 'user'); * // => ['barney'] */ - function reject(collection, predicate, thisArg) { + function reject(collection, predicate) { var func = isArray(collection) ? arrayFilter : baseFilter; - predicate = getIteratee(predicate, thisArg, 3); + predicate = getIteratee(predicate); return func(collection, function(value, index, collection) { return !predicate(value, index, collection); }); @@ -7104,30 +6789,17 @@ /** * Checks if `predicate` returns truthy for **any** element of `collection`. * The function returns as soon as it finds a passing value and does not iterate - * over the entire collection. The predicate is bound to `thisArg` and invoked - * with three arguments: (value, index|key, collection). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. + * over the entire collection. The predicate is invoked with three arguments: + * (value, index|key, collection). * * @static * @memberOf _ * @alias any * @category Collection * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. + * @param {Function|Object|string} [predicate=_.identity] The function invoked per iteration. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {boolean} Returns `true` if any element passes the predicate check, else `false`. * @example * * _.some([null, 0, 'yes', false], Boolean); @@ -7143,20 +6815,20 @@ * // => false * * // using the `_.matchesProperty` callback shorthand - * _.some(users, 'active', false); + * _.some(users, ['active', false]); * // => true * * // using the `_.property` callback shorthand * _.some(users, 'active'); * // => true */ - function some(collection, predicate, thisArg) { + function some(collection, predicate, guard) { var func = isArray(collection) ? arraySome : baseSome; - if (thisArg && isIterateeCall(collection, predicate, thisArg)) { + if (guard && isIterateeCall(collection, predicate, guard)) { predicate = undefined; } - if (typeof predicate != 'function' || thisArg !== undefined) { - predicate = getIteratee(predicate, thisArg, 3); + if (typeof predicate != 'function') { + predicate = getIteratee(predicate); } return func(collection, predicate); } @@ -7165,27 +6837,13 @@ * Creates an array of elements, sorted in ascending order by the results of * running each element in a collection through `iteratee`. This method performs * a stable sort, that is, it preserves the original sort order of equal elements. - * The `iteratee` is bound to `thisArg` and invoked with three arguments: - * (value, index|key, collection). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. + * The iteratee is invoked with three arguments: (value, index|key, collection). * * @static * @memberOf _ * @category Collection * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. * @returns {Array} Returns the new sorted array. * @example * @@ -7229,13 +6887,6 @@ * This method is like `_.sortBy` except that it can sort by multiple iteratees * or property names. * - * If a property name is provided for an iteratee the created `_.property` - * style callback returns the property value of the given element. - * - * If an object is provided for an iteratee the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * * @static * @memberOf _ * @category Collection @@ -7277,13 +6928,6 @@ * values are sorted in ascending order. Otherwise, a value is sorted in * ascending order if its corresponding order is "asc", and descending if "desc". * - * If a property name is provided for an iteratee the created `_.property` - * style callback returns the property value of the given element. - * - * If an object is provided for an iteratee the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * * @static * @memberOf _ * @category Collection @@ -8366,8 +8010,8 @@ * Creates a clone of `value`. If `isDeep` is `true` nested objects are cloned, * otherwise they are assigned by reference. If `customizer` is provided it's * invoked to produce the cloned values. If `customizer` returns `undefined` - * cloning is handled by the method instead. The `customizer` is bound to - * `thisArg` and invoked with up to three argument; (value [, index|key, object]). + * cloning is handled by the method instead. The `customizer` is invoked with + * up to three argument; (value [, index|key, object]). * * **Note:** This method is loosely based on the * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm). @@ -8382,7 +8026,6 @@ * @param {*} value The value to clone. * @param {boolean} [isDeep] Specify a deep clone. * @param {Function} [customizer] The function to customize cloning values. - * @param {*} [thisArg] The `this` binding of `customizer`. * @returns {*} Returns the cloned value. * @example * @@ -8413,25 +8056,24 @@ * el.childNodes.length; * // => 0 */ - function clone(value, isDeep, customizer, thisArg) { + function clone(value, isDeep, customizer) { if (isDeep && typeof isDeep != 'boolean' && isIterateeCall(value, isDeep, customizer)) { isDeep = false; } else if (typeof isDeep == 'function') { - thisArg = customizer; customizer = isDeep; isDeep = false; } return typeof customizer == 'function' - ? baseClone(value, isDeep, bindCallback(customizer, thisArg, 3)) + ? baseClone(value, isDeep, customizer) : baseClone(value, isDeep); } /** * Creates a deep clone of `value`. If `customizer` is provided it's invoked * to produce the cloned values. If `customizer` returns `undefined` cloning - * is handled by the method instead. The `customizer` is bound to `thisArg` - * and invoked with up to three argument; (value [, index|key, object]). + * is handled by the method instead. The `customizer` is invoked with up to + * three argument; (value [, index|key, object]). * * **Note:** This method is loosely based on the * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm). @@ -8445,7 +8087,6 @@ * @category Lang * @param {*} value The value to deep clone. * @param {Function} [customizer] The function to customize cloning values. - * @param {*} [thisArg] The `this` binding of `customizer`. * @returns {*} Returns the deep cloned value. * @example * @@ -8472,9 +8113,9 @@ * el.childNodes.length; * // => 20 */ - function cloneDeep(value, customizer, thisArg) { + function cloneDeep(value, customizer) { return typeof customizer == 'function' - ? baseClone(value, true, bindCallback(customizer, thisArg, 3)) + ? baseClone(value, true, customizer) : baseClone(value, true); } @@ -8669,8 +8310,8 @@ * Performs a deep comparison between two values to determine if they are * equivalent. If `customizer` is provided it's invoked to compare values. * If `customizer` returns `undefined` comparisons are handled by the method - * instead. The `customizer` is bound to `thisArg` and invoked with up to - * three arguments: (value, other [, index|key]). + * instead. The `customizer` is invoked with up to three arguments: + * (value, other [, index|key]). * * **Note:** This method supports comparing arrays, booleans, `Date` objects, * numbers, `Object` objects, regexes, and strings. Objects are compared by @@ -8685,7 +8326,6 @@ * @param {*} value The value to compare. * @param {*} other The other value to compare. * @param {Function} [customizer] The function to customize value comparisons. - * @param {*} [thisArg] The `this` binding of `customizer`. * @returns {boolean} Returns `true` if the values are equivalent, else `false`. * @example * @@ -8709,10 +8349,10 @@ * }); * // => true */ - function isEqual(value, other, customizer, thisArg) { - customizer = typeof customizer == 'function' ? bindCallback(customizer, thisArg, 3) : undefined; + function isEqual(value, other, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; var result = customizer ? customizer(value, other) : undefined; - return result === undefined ? baseIsEqual(value, other, customizer) : !!result; + return result === undefined ? baseIsEqual(value, other, customizer) : !!result; } /** @@ -8821,8 +8461,8 @@ * Performs a deep comparison between `object` and `source` to determine if * `object` contains equivalent property values. If `customizer` is provided * it's invoked to compare values. If `customizer` returns `undefined` - * comparisons are handled by the method instead. The `customizer` is bound - * to `thisArg` and invoked with three arguments: (value, other, index|key). + * comparisons are handled by the method instead. The `customizer` is invoked + * with three arguments: (value, other, index|key). * * **Note:** This method supports comparing properties of arrays, booleans, * `Date` objects, numbers, `Object` objects, regexes, and strings. Functions @@ -8835,7 +8475,6 @@ * @param {Object} object The object to inspect. * @param {Object} source The object of property values to match. * @param {Function} [customizer] The function to customize value comparisons. - * @param {*} [thisArg] The `this` binding of `customizer`. * @returns {boolean} Returns `true` if `object` is a match, else `false`. * @example * @@ -8856,8 +8495,8 @@ * }); * // => true */ - function isMatch(object, source, customizer, thisArg) { - customizer = typeof customizer == 'function' ? bindCallback(customizer, thisArg, 3) : undefined; + function isMatch(object, source, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; return baseIsMatch(object, getMatchData(source), customizer); } @@ -9213,8 +8852,8 @@ * overwrite property assignments of previous sources. If `customizer` is * provided it's invoked to produce the merged values of the destination and * source properties. If `customizer` returns `undefined` merging is handled - * by the method instead. The `customizer` is bound to `thisArg` and invoked - * with five arguments: (objectValue, sourceValue, key, object, source). + * by the method instead. The `customizer` is invoked with five arguments: + * (objectValue, sourceValue, key, object, source). * * @static * @memberOf _ @@ -9222,7 +8861,6 @@ * @param {Object} object The destination object. * @param {...Object} [sources] The source objects. * @param {Function} [customizer] The function to customize assigned values. - * @param {*} [thisArg] The `this` binding of `customizer`. * @returns {Object} Returns `object`. * @example * @@ -9261,7 +8899,7 @@ * Assigns own enumerable properties of source object(s) to the destination * object. Subsequent sources overwrite property assignments of previous sources. * If `customizer` is provided it's invoked to produce the assigned values. - * The `customizer` is bound to `thisArg` and invoked with five arguments: + * The `customizer` is invoked with five arguments: * (objectValue, sourceValue, key, object, source). * * **Note:** This method mutates `object` and is based on @@ -9274,7 +8912,6 @@ * @param {Object} object The destination object. * @param {...Object} [sources] The source objects. * @param {Function} [customizer] The function to customize assigned values. - * @param {*} [thisArg] The `this` binding of `customizer`. * @returns {Object} Returns `object`. * @example * @@ -9381,24 +9018,11 @@ * This method is like `_.find` except that it returns the key of the first * element `predicate` returns truthy for instead of the element itself. * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * * @static * @memberOf _ * @category Object * @param {Object} object The object to search. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. + * @param {Function|Object|string} [predicate=_.identity] The function invoked per iteration. * @returns {string|undefined} Returns the key of the matched element, else `undefined`. * @example * @@ -9418,7 +9042,7 @@ * // => 'pebbles' * * // using the `_.matchesProperty` callback shorthand - * _.findKey(users, 'active', false); + * _.findKey(users, ['active', false]); * // => 'fred' * * // using the `_.property` callback shorthand @@ -9431,24 +9055,11 @@ * This method is like `_.findKey` except that it iterates over elements of * a collection in the opposite order. * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * * @static * @memberOf _ * @category Object * @param {Object} object The object to search. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. + * @param {Function|Object|string} [predicate=_.identity] The function invoked per iteration. * @returns {string|undefined} Returns the key of the matched element, else `undefined`. * @example * @@ -9468,7 +9079,7 @@ * // => 'barney' * * // using the `_.matchesProperty` callback shorthand - * _.findLastKey(users, 'active', false); + * _.findLastKey(users, ['active', false]); * // => 'fred' * * // using the `_.property` callback shorthand @@ -9479,16 +9090,15 @@ /** * Iterates over own and inherited enumerable properties of an object invoking - * `iteratee` for each property. The `iteratee` is bound to `thisArg` and invoked - * with three arguments: (value, key, object). Iteratee functions may exit - * iteration early by explicitly returning `false`. + * `iteratee` for each property. The iteratee is invoked with three arguments: + * (value, key, object). Iteratee functions may exit iteration early by explicitly + * returning `false`. * * @static * @memberOf _ * @category Object * @param {Object} object The object to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {Object} Returns `object`. * @example * @@ -9515,7 +9125,6 @@ * @category Object * @param {Object} object The object to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {Object} Returns `object`. * @example * @@ -9535,16 +9144,15 @@ /** * Iterates over own enumerable properties of an object invoking `iteratee` - * for each property. The `iteratee` is bound to `thisArg` and invoked with - * three arguments: (value, key, object). Iteratee functions may exit iteration - * early by explicitly returning `false`. + * for each property. The iteratee is invoked with three arguments: + * (value, key, object). Iteratee functions may exit iteration early by + * explicitly returning `false`. * * @static * @memberOf _ * @category Object * @param {Object} object The object to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {Object} Returns `object`. * @example * @@ -9571,7 +9179,6 @@ * @category Object * @param {Object} object The object to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {Object} Returns `object`. * @example * @@ -9851,9 +9458,7 @@ * @memberOf _ * @category Object * @param {Object} object The object to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. * @returns {Object} Returns the new mapped object. * @example * @@ -9867,27 +9472,13 @@ /** * Creates an object with the same keys as `object` and values generated by * running each own enumerable property of `object` through `iteratee`. The - * iteratee function is bound to `thisArg` and invoked with three arguments: - * (value, key, object). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. + * iteratee function is invoked with three arguments: (value, key, object). * * @static * @memberOf _ * @category Object * @param {Object} object The object to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. * @returns {Object} Returns the new mapped object. * @example * @@ -9918,7 +9509,6 @@ * @param {Function|...(string|string[])} [predicate] The function invoked per * iteration or property names to omit, specified as individual property * names or arrays of property names. - * @param {*} [thisArg] The `this` binding of `predicate`. * @returns {Object} Returns the new object. * @example * @@ -9938,7 +9528,7 @@ var props = arrayMap(baseFlatten(props), String); return pickByArray(object, baseDifference(keysIn(object), props)); } - var predicate = bindCallback(props[0], props[1], 3); + var predicate = props[0]; return pickByCallback(object, function(value, key, object) { return !predicate(value, key, object); }); @@ -9978,7 +9568,7 @@ * names may be specified as individual arguments or as arrays of property * names. If `predicate` is provided it's invoked for each property of `object` * picking the properties `predicate` returns truthy for. The predicate is - * bound to `thisArg` and invoked with three arguments: (value, key, object). + * invoked with three arguments: (value, key, object). * * @static * @memberOf _ @@ -9987,7 +9577,6 @@ * @param {Function|...(string|string[])} [predicate] The function invoked per * iteration or property names to pick, specified as individual property * names or arrays of property names. - * @param {*} [thisArg] The `this` binding of `predicate`. * @returns {Object} Returns the new object. * @example * @@ -10004,7 +9593,7 @@ return {}; } return typeof props[0] == 'function' - ? pickByCallback(object, bindCallback(props[0], props[1], 3)) + ? pickByCallback(object, props[0]) : pickByArray(object, baseFlatten(props)); }); @@ -10102,9 +9691,9 @@ * An alternative to `_.reduce`; this method transforms `object` to a new * `accumulator` object which is the result of running each of its own enumerable * properties through `iteratee`, with each invocation potentially mutating - * the `accumulator` object. The `iteratee` is bound to `thisArg` and invoked - * with four arguments: (accumulator, value, key, object). Iteratee functions - * may exit iteration early by explicitly returning `false`. + * the `accumulator` object. The iteratee is invoked with four arguments: + * (accumulator, value, key, object). Iteratee functions may exit iteration + * early by explicitly returning `false`. * * @static * @memberOf _ @@ -10112,7 +9701,6 @@ * @param {Array|Object} object The object to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. * @param {*} [accumulator] The custom accumulator value. - * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {*} Returns the accumulated value. * @example * @@ -10127,9 +9715,9 @@ * }); * // => { 'a': 3, 'b': 6 } */ - function transform(object, iteratee, accumulator, thisArg) { + function transform(object, iteratee, accumulator) { var isArr = isArray(object) || isTypedArray(object); - iteratee = getIteratee(iteratee, thisArg, 4); + iteratee = getIteratee(iteratee); if (accumulator == null) { if (isArr || isObject(object)) { @@ -11241,19 +10829,16 @@ } /** - * Creates a function that invokes `func` with the `this` binding of `thisArg` - * and arguments of the created function. If `func` is a property name the - * created callback returns the property value for a given element. If `func` - * is an object the created callback returns `true` for elements that contain - * the equivalent object properties, otherwise it returns `false`. + * Creates a function that invokes `func` with the arguments of the created + * function. If `func` is a property name the created callback returns the + * property value for a given element. If `func` is an object the created + * callback returns `true` for elements that contain the equivalent object properties, otherwise it returns `false`. * * @static * @memberOf _ * @alias iteratee * @category Utility * @param {*} [func=_.identity] The value to convert to a callback. - * @param {*} [thisArg] The `this` binding of `func`. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. * @returns {Function} Returns the callback. * @example * @@ -11278,13 +10863,10 @@ * _.filter(users, 'age__gt36'); * // => [{ 'user': 'fred', 'age': 40 }] */ - function iteratee(func, thisArg, guard) { - if (guard && isIterateeCall(func, thisArg, guard)) { - thisArg = undefined; - } - return isObjectLike(func) + function iteratee(func) { + return (isObjectLike(func) && !isArray(func)) ? matches(func) - : baseIteratee(func, thisArg); + : baseIteratee(func); } /** @@ -11636,15 +11218,13 @@ /** * Invokes the iteratee function `n` times, returning an array of the results - * of each invocation. The `iteratee` is bound to `thisArg` and invoked with - * one argument; (index). + * of each invocation. The iteratee is invoked with one argument; (index). * * @static * @memberOf _ * @category Utility * @param {number} n The number of times to invoke `iteratee`. * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {Array} Returns the array of results. * @example * @@ -11654,14 +11234,9 @@ * _.times(3, function(n) { * mage.castSpell(n); * }); - * // => invokes `mage.castSpell(n)` three times with `n` of `0`, `1`, and `2` - * - * _.times(3, function(n) { - * this.cast(n); - * }, mage); - * // => also invokes `mage.castSpell(n)` three times + * // => invokes `mage.castSpell` three times with `n` of `0`, `1`, and `2` */ - function times(n, iteratee, thisArg) { + function times(n, iteratee) { n = nativeFloor(n); // Exit early to avoid a JSC JIT bug in Safari 8 @@ -11672,7 +11247,7 @@ var index = -1, result = Array(nativeMin(n, MAX_ARRAY_LENGTH)); - iteratee = bindCallback(iteratee, thisArg, 1); + iteratee = bindCallback(iteratee); while (++index < n) { if (index < MAX_ARRAY_LENGTH) { result[index] = iteratee(index); @@ -11772,26 +11347,13 @@ * Gets the maximum value of `collection`. If `collection` is empty or falsey * `-Infinity` is returned. If an iteratee function is provided it's invoked * for each value in `collection` to generate the criterion by which the value - * is ranked. The `iteratee` is bound to `thisArg` and invoked with three - * arguments: (value, index, collection). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. + * is ranked. The iteratee is invoked with three arguments: (value, index, collection). * * @static * @memberOf _ * @category Math * @param {Array|Object|string} collection The collection to iterate over. * @param {Function|Object|string} [iteratee] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {*} Returns the maximum value. * @example * @@ -11821,26 +11383,13 @@ * Gets the minimum value of `collection`. If `collection` is empty or falsey * `Infinity` is returned. If an iteratee function is provided it's invoked * for each value in `collection` to generate the criterion by which the value - * is ranked. The `iteratee` is bound to `thisArg` and invoked with three - * arguments: (value, index, collection). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. + * is ranked. The iteratee is invoked with three arguments: (value, index, collection). * * @static * @memberOf _ * @category Math * @param {Array|Object|string} collection The collection to iterate over. * @param {Function|Object|string} [iteratee] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {*} Returns the minimum value. * @example * @@ -11896,7 +11445,7 @@ * @category Math * @param {Array|Object|string} collection The collection to iterate over. * @param {Function|Object|string} [iteratee] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. * @returns {number} Returns the sum. * @example * @@ -11920,11 +11469,11 @@ * _.sum(objects, 'n'); * // => 10 */ - function sum(collection, iteratee, thisArg) { - if (thisArg && isIterateeCall(collection, iteratee, thisArg)) { + function sum(collection, iteratee, guard) { + if (guard && isIterateeCall(collection, iteratee, guard)) { iteratee = undefined; } - iteratee = getIteratee(iteratee, thisArg, 3); + iteratee = getIteratee(iteratee); return iteratee.length == 1 ? arraySum(isArray(collection) ? collection : toIterable(collection), iteratee) : baseSum(collection, iteratee); @@ -12230,9 +11779,9 @@ var type = index + 1, isFilter = type != LAZY_MAP_FLAG; - LazyWrapper.prototype[methodName] = function(iteratee, thisArg) { + LazyWrapper.prototype[methodName] = function(iteratee) { var result = this.clone(); - result.__iteratees__.push({ 'iteratee': getIteratee(iteratee, thisArg, 1), 'type': type }); + result.__iteratees__.push({ 'iteratee': getIteratee(iteratee), 'type': type }); result.__filtered__ = result.__filtered__ || isFilter; return result; }; @@ -12260,8 +11809,8 @@ return this.filter(identity); }; - LazyWrapper.prototype.reject = function(predicate, thisArg) { - predicate = getIteratee(predicate, thisArg, 1); + LazyWrapper.prototype.reject = function(predicate) { + predicate = getIteratee(predicate); return this.filter(function(value) { return !predicate(value); }); @@ -12286,8 +11835,8 @@ return result; }; - LazyWrapper.prototype.takeRightWhile = function(predicate, thisArg) { - return this.reverse().takeWhile(predicate, thisArg).reverse(); + LazyWrapper.prototype.takeRightWhile = function(predicate) { + return this.reverse().takeWhile(predicate).reverse(); }; LazyWrapper.prototype.toArray = function() { diff --git a/test/test.js b/test/test.js index 1965d82eb8..9872c99393 100644 --- a/test/test.js +++ b/test/test.js @@ -2073,14 +2073,6 @@ deepEqual(argsList, isDeep ? [[foo], [1, 'a', foo]] : [[foo]]); }); - test('`_.' + methodName + '` should support the `thisArg` argument', 1, function() { - var actual = func('a', function(value) { - return this[value]; - }, { 'a': 'A' }); - - strictEqual(actual, 'A'); - }); - test('`_.' + methodName + '` should handle cloning if `customizer` returns `undefined`', 1, function() { var actual = func({ 'a': { 'b': 'c' } }, _.noop); deepEqual(actual, { 'a': { 'b': 'c' } }); @@ -2411,14 +2403,6 @@ deepEqual(args, [4.2, 0, array]); }); - test('should support the `thisArg` argument', 1, function() { - var actual = _.countBy(array, function(num) { - return this.floor(num); - }, Math); - - deepEqual(actual, { '4': 1, '6': 2 }); - }); - test('should work with a "_.property" style `iteratee`', 1, function() { var actual = _.countBy(['one', 'two', 'three'], 'length'); deepEqual(actual, { '3': 2, '5': 1 }); @@ -3502,20 +3486,12 @@ deepEqual(args, [4, 3, array]); }); - test('should support the `thisArg` argument', 1, function() { - var actual = _.dropRightWhile(array, function(num, index) { - return this[index] > 2; - }, array); - - deepEqual(actual, [1, 2]); - }); - test('should work with a "_.matches" style `predicate`', 1, function() { deepEqual(_.dropRightWhile(objects, { 'b': 2 }), objects.slice(0, 2)); }); test('should work with a "_.matchesProperty" style `predicate`', 1, function() { - deepEqual(_.dropRightWhile(objects, 'b', 2), objects.slice(0, 2)); + deepEqual(_.dropRightWhile(objects, ['b', 2]), objects.slice(0, 2)); }); test('should work with a "_.property" style `predicate`', 1, function() { @@ -3568,20 +3544,12 @@ deepEqual(args, [1, 0, array]); }); - test('should support the `thisArg` argument', 1, function() { - var actual = _.dropWhile(array, function(num, index) { - return this[index] < 3; - }, array); - - deepEqual(actual, [3, 4]); - }); - test('should work with a "_.matches" style `predicate`', 1, function() { deepEqual(_.dropWhile(objects, { 'b': 2 }), objects.slice(1)); }); test('should work with a "_.matchesProperty" style `predicate`', 1, function() { - deepEqual(_.dropWhile(objects, 'b', 2), objects.slice(1)); + deepEqual(_.dropWhile(objects, ['b', 2]), objects.slice(1)); }); test('should work with a "_.property" style `predicate`', 1, function() { @@ -4048,10 +4016,6 @@ strictEqual(func(objects, function(object) { return object.a; }), expected[0]); }); - test('should work with a `thisArg`', 1, function() { - strictEqual(func(objects, function(object, index) { return this[index].a; }, objects), expected[0]); - }); - test('should return `' + expected[1] + '` if value is not found', 1, function() { strictEqual(func(objects, function(object) { return object.a === 3; }), expected[1]); }); @@ -4061,7 +4025,7 @@ }); test('should work with a "_.matchesProperty" style `predicate`', 1, function() { - strictEqual(func(objects, 'b', 2), expected[2]); + strictEqual(func(objects, ['b', 2]), expected[2]); }); test('should work with a "_.property" style `predicate`', 1, function() { @@ -4364,20 +4328,12 @@ deepEqual(args, [4, 3, array]); }); - test('should support the `thisArg` argument', 1, function() { - var actual = _.takeRightWhile(array, function(num, index) { - return this[index] > 2; - }, array); - - deepEqual(actual, [3, 4]); - }); - test('should work with a "_.matches" style `predicate`', 1, function() { deepEqual(_.takeRightWhile(objects, { 'b': 2 }), objects.slice(2)); }); test('should work with a "_.matchesProperty" style `predicate`', 1, function() { - deepEqual(_.takeRightWhile(objects, 'b', 2), objects.slice(2)); + deepEqual(_.takeRightWhile(objects, ['b', 2]), objects.slice(2)); }); test('should work with a "_.property" style `predicate`', 1, function() { @@ -4473,20 +4429,12 @@ deepEqual(args, [1, 0, array]); }); - test('should support the `thisArg` argument', 1, function() { - var actual = _.takeWhile(array, function(num, index) { - return this[index] < 3; - }, array); - - deepEqual(actual, [1, 2]); - }); - test('should work with a "_.matches" style `predicate`', 1, function() { deepEqual(_.takeWhile(objects, { 'b': 2 }), objects.slice(0, 1)); }); test('should work with a "_.matchesProperty" style `predicate`', 1, function() { - deepEqual(_.takeWhile(objects, 'b', 2), objects.slice(0, 1)); + deepEqual(_.takeWhile(objects, ['b', 2]), objects.slice(0, 1)); }); test('should work with a "_.property" style `predicate`', 1, function() { deepEqual(_.takeWhile(objects, 'b'), objects.slice(0, 2)); @@ -4898,22 +4846,6 @@ } }); - test('`_.' + methodName + '` should support the `thisArg` argument', 2, function() { - if (methodName != '_baseEach') { - var actual, - callback = function(num, index) { actual = this[index]; }; - - func([1], callback, [2]); - strictEqual(actual, 2); - - func({ 'a': 1 }, callback, { 'a': 2 }); - strictEqual(actual, 2); - } - else { - skipTest(2); - } - }); - test('`_.' + methodName + '` should treat sparse arrays as dense', 1, function() { if (func) { var array = [1]; @@ -5333,14 +5265,6 @@ deepEqual(argsList, expected, 'object property values'); }); - test('`_.' + methodName + '` should support the `thisArg` argument', 1, function() { - var actual = func({}, { 'a': 0 }, function(a, b) { - return this[b]; - }, [2]); - - deepEqual(actual, { 'a': 2 }); - }); - test('`_.' + methodName + '` should not treat `object` as `source`', 1, function() { function Foo() {} Foo.prototype.a = 1; @@ -5493,14 +5417,6 @@ deepEqual(args, [4.2, 0, array]); }); - test('should support the `thisArg` argument', 1, function() { - var actual = _.groupBy(array, function(num) { - return this.floor(num); - }, Math); - - deepEqual(actual, { '4': [4.2], '6': [6.1, 6.4] }); - }); - test('should work with a "_.property" style `iteratee`', 1, function() { var actual = _.groupBy(['one', 'two', 'three'], 'length'); deepEqual(actual, { '3': ['one', 'two'], '5': ['three'] }); @@ -5863,14 +5779,6 @@ deepEqual(actual, expected); }); - test('should support the `thisArg` argument', 1, function() { - var actual = _.indexBy([4.2, 6.1, 6.4], function(num) { - return this.floor(num); - }, Math); - - deepEqual(actual, { '4': 4.2, '6': 6.4 }); - }); - test('should work with a "_.property" style `iteratee`', 1, function() { var actual = _.indexBy(['one', 'two', 'three'], 'length'); deepEqual(actual, { '3': 'two', '5': 'three' }); @@ -7140,14 +7048,6 @@ deepEqual(argsList, expected); }); - test('should set the `this` binding', 1, function() { - var actual = _.isEqual('a', 'b', function(a, b) { - return this[a] == this[b]; - }, { 'a': 1, 'b': 1 }); - - strictEqual(actual, true); - }); - test('should handle comparisons if `customizer` returns `undefined`', 3, function() { strictEqual(_.isEqual('a', 'a', _.noop), true); strictEqual(_.isEqual(['a'], ['a'], _.noop), true); @@ -7751,14 +7651,6 @@ deepEqual(argsList, expected); }); - test('should set the `this` binding', 1, function() { - var actual = _.isMatch({ 'a': 1 }, { 'a': 2 }, function(a, b) { - return this[a] == this[b]; - }, { 'a': 1, 'b': 1 }); - - strictEqual(actual, true); - }); - test('should handle comparisons if `customizer` returns `undefined`', 1, function() { strictEqual(_.isMatch({ 'a': 1 }, { 'a': 1 }, _.noop), true); }); @@ -8393,24 +8285,12 @@ QUnit.module('lodash.iteratee'); (function() { - test('should provide arguments to `func`', 3, function() { - var fn = function() { - var result = [this]; - push.apply(result, arguments); - return result; - }; - - var iteratee = _.iteratee(fn), + test('should provide arguments to `func`', 1, function() { + var fn = function() { return slice.call(arguments); }, + iteratee = _.iteratee(fn), actual = iteratee('a', 'b', 'c', 'd', 'e', 'f'); - ok(actual[0] === null || actual[0] && actual[0].Array); - deepEqual(actual.slice(1), ['a', 'b', 'c', 'd', 'e', 'f']); - - var object = {}; - iteratee = _.iteratee(fn, object); - actual = iteratee('a', 'b'); - - deepEqual(actual, [object, 'a', 'b']); + deepEqual(actual, ['a', 'b', 'c', 'd', 'e', 'f']); }); test('should return `_.identity` when `func` is nullish', 1, function() { @@ -8426,50 +8306,12 @@ deepEqual(actual, expected); }); - test('should not error when `func` is nullish and a `thisArg` is provided', 2, function() { - var object = {}; - - _.each([null, undefined], function(value) { - try { - var iteratee = _.iteratee(value, {}); - strictEqual(iteratee(object), object); - } catch(e) { - ok(false, e.message); - } - }); - }); - - test('should create an iteratee with a falsey `thisArg`', 1, function() { - var fn = function() { return this; }, - object = {}; - - var expected = _.map(falsey, function(value) { - var result = fn.call(value); - return (result && result.Array) ? object : result; - }); - - var actual = _.map(falsey, function(value) { - var iteratee = _.iteratee(fn, value), - result = iteratee(); - - return (result && result.Array) ? object : result; - }); - - ok(_.isEqual(actual, expected)); - }); - test('should return an iteratee created by `_.matches` when `func` is an object', 2, function() { var matches = _.iteratee({ 'a': 1, 'b': 2 }); strictEqual(matches({ 'a': 1, 'b': 2, 'c': 3 }), true); strictEqual(matches({ 'b': 2 }), false); }); - test('should return an iteratee created by `_.matches` when `func` is an array', 2, function() { - var matches = _.iteratee(['a', 'b']); - strictEqual(matches({ '0': 'a', '1': 'b', '2': 'c' }), true); - strictEqual(matches({ '1': 'b' }), false); - }); - test('should not change match behavior if `source` is augmented', 9, function() { var sources = [ { 'a': { 'b': 2, 'c': 3 } }, @@ -8497,22 +8339,22 @@ }); }); - test('should return an iteratee created by `_.matchesProperty` when `func` is a number or string and `thisArg` is not `undefined`', 3, function() { - var array = ['a'], - matches = _.iteratee(0, 'a'); + test('should return an iteratee created by `_.matchesProperty` when `func` is a number or string and a value is provided', 3, function() { + var array = ['a', undefined], + matches = _.iteratee([0, 'a']); strictEqual(matches(array), true); - matches = _.iteratee('0', 'a'); + matches = _.iteratee(['0', 'a']); strictEqual(matches(array), true); - matches = _.iteratee(1, undefined); - strictEqual(matches(array), undefined); + matches = _.iteratee([1, undefined]); + strictEqual(matches(array), true); }); - test('should support deep paths for `_.matchesProperty` shorthands', 1, function() { + test('should support deep paths for "_.matchesProperty" shorthands', 1, function() { var object = { 'a': { 'b': { 'c': { 'd': 1, 'e': 2 } } } }, - matches = _.iteratee('a.b.c', { 'e': 2 }); + matches = _.iteratee(['a.b.c', { 'e': 2 }]); strictEqual(matches(object), true); }); @@ -8527,7 +8369,7 @@ strictEqual(prop(array), 'a'); }); - test('should support deep paths for `_.property` shorthands', 1, function() { + test('should support deep paths for "_.property" shorthands', 1, function() { var object = { 'a': { 'b': { 'c': 3 } } }, prop = _.iteratee('a.b.c'); @@ -8542,30 +8384,12 @@ }; var expected = [1, 2, 3], - object = { 'a': 1 }, - iteratee = _.iteratee(_.partial(fn, 2), object); - - deepEqual(iteratee(3), expected); - - iteratee = _.iteratee(_.partialRight(fn, 3), object); - deepEqual(iteratee(2), expected); - }); - - test('should support binding built-in methods', 2, function() { - var fn = function() {}, - object = { 'a': 1 }, - bound = fn.bind && fn.bind(object), - iteratee = _.iteratee(hasOwnProperty, object); + object = { 'a': 1 , 'iteratee': _.iteratee(_.partial(fn, 2)) }; - strictEqual(iteratee('a'), true); + deepEqual(object.iteratee(3), expected); - if (bound) { - iteratee = _.iteratee(bound, object); - notStrictEqual(iteratee, bound); - } - else { - skipTest(); - } + object.iteratee = _.iteratee(_.partialRight(fn, 3)); + deepEqual(object.iteratee(2), expected); }); test('should work as an iteratee for methods like `_.map`', 1, function() { @@ -9432,16 +9256,6 @@ deepEqual(args, [1, 0, array]); }); - test('should support the `thisArg` argument', 2, function() { - var callback = function(num, index) { return this[index] + num; }, - actual = _.map([1], callback, [2]); - - deepEqual(actual, [3]); - - actual = _.map({ 'a': 1 }, callback, { 'a': 2 }); - deepEqual(actual, [3]); - }); - test('should work with a "_.property" style `iteratee`', 1, function() { var objects = [{ 'a': 'x' }, { 'a': 'y' }]; deepEqual(_.map(objects, 'a'), ['x', 'y']); @@ -9568,18 +9382,6 @@ deepEqual(actual, { '1': 1, '2': 2 }); }); - test('should support the `thisArg` argument', 2, function() { - function callback(num, key) { - return this[key] + num - } - - var actual = _.mapKeys({ 'a': 1 }, callback, { 'a': 2 }); - deepEqual(actual, { '3': 1 }); - - actual = _.mapKeys([2], callback, [1]); - deepEqual(actual, { '3': 2 }); - }); - test('should work with a "_.property" style `iteratee`', 1, function() { var actual = _.mapKeys({ 'a': { 'b': 'c' } }, 'b'); deepEqual(actual, { 'c': { 'b': 'c' } }); @@ -9609,18 +9411,6 @@ deepEqual(actual, { '0': '1', '1': '2' }); }); - test('should support the `thisArg` argument', 2, function() { - function callback(num, key) { - return this[key] + num; - } - - var actual = _.mapValues({ 'a': 1 }, callback, { 'a': 2 }); - deepEqual(actual, { 'a': 3 }); - - actual = _.mapValues([2], callback, [1]); - deepEqual(actual, { '0': 3 }); - }); - test('should work with a "_.property" style `iteratee`', 1, function() { var actual = _.mapValues({ 'a': { 'b': 1 } }, 'b'); deepEqual(actual, { 'a': 1 }); @@ -11089,14 +10879,6 @@ deepEqual(args, expected); }); - test('`_.' + methodName + '` should support the `thisArg` argument', 1, function() { - var actual = func(array, function(num, index) { - return -this[index]; - }, array); - - strictEqual(actual, isMax ? 1 : 3); - }); - test('should work with a "_.property" style `iteratee`', 2, function() { var objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }], actual = func(objects, 'a'); @@ -11594,14 +11376,6 @@ deepEqual(args, expected); }); - test('should set the `this` binding', 1, function() { - var actual = _.omit(object, function(num) { - return num != this.b && num != this.d; - }, { 'b': 2, 'd': 4 }); - - deepEqual(actual, expected); - }); - test('should coerce property names to strings', 1, function() { deepEqual(_.omit({ '0': 'a' }, 0), {}); }); @@ -12215,14 +11989,6 @@ deepEqual(args, [1, 0, array]); }); - test('should support the `thisArg` argument', 1, function() { - var actual = _.partition([1.1, 0.2, 1.3], function(num) { - return this.floor(num); - }, Math); - - deepEqual(actual, [[1.1, 1.3], [0.2]]); - }); - test('should work with a "_.property" style `predicate`', 1, function() { var objects = [{ 'a': 1 }, { 'a': 1 }, { 'b': 2 }], actual = _.partition(objects, 'a'); @@ -12317,14 +12083,6 @@ deepEqual(args, expected); }); - test('should set the `this` binding', 1, function() { - var actual = _.pick(object, function(num) { - return num == this.a || num == this.c; - }, { 'a': 1, 'c': 3 }); - - deepEqual(actual, expected); - }); - test('should coerce property names to strings', 1, function() { deepEqual(_.pick({ '0': 'a', '1': 'b' }, 0), { '0': 'a' }); }); @@ -13079,14 +12837,6 @@ strictEqual(actual, isReduce ? 'abc' : 'cba'); }); - test('`_.' + methodName + '` should support the `thisArg` argument', 1, function() { - var actual = func(array, function(sum, num, index) { - return sum + this[index]; - }, 0, array); - - deepEqual(actual, 6); - }); - test('`_.' + methodName + '` should support empty collections without an initial `accumulator` value', 1, function() { var actual = [], expected = _.map(empties, _.constant()); @@ -13311,16 +13061,6 @@ deepEqual(argsList, [[1, 0, clone], [2, 1, clone], [3, 2, clone]]); }); - test('should support the `thisArg` argument', 1, function() { - var array = [1, 2, 3]; - - var actual = _.remove(array, function(num, index) { - return this[index] < 3; - }, array); - - deepEqual(actual, [1, 2]); - }); - test('should work with a "_.matches" style `predicate`', 1, function() { var objects = [{ 'a': 0, 'b': 1 }, { 'a': 1, 'b': 2 }]; _.remove(objects, { 'a': 1 }); @@ -13329,7 +13069,7 @@ test('should work with a "_.matchesProperty" style `predicate`', 1, function() { var objects = [{ 'a': 0, 'b': 1 }, { 'a': 1, 'b': 2 }]; - _.remove(objects, 'a', 1); + _.remove(objects, ['a', 1]); deepEqual(objects, [{ 'a': 0, 'b': 1 }]); }); @@ -14462,14 +14202,6 @@ deepEqual(args, [objects[0], 0, objects]); }); - test('should support the `thisArg` argument', 1, function() { - var actual = _.sortBy([1, 2, 3], function(num) { - return this.sin(num); - }, Math); - - deepEqual(actual, [3, 1, 2]); - }); - test('should use `_.identity` when `iteratee` is nullish', 1, function() { var array = [3, 2, 1], values = [, null, undefined], @@ -14688,14 +14420,6 @@ deepEqual(args, [40]); }); - test('`_.' + methodName + '` should support the `thisArg` argument', 1, function() { - var actual = func(array, 40, function(num) { - return this[num]; - }, { '30': 30, '40': 40, '50': 50 }); - - strictEqual(actual, 1); - }); - test('`_.' + methodName + '` should work with a "_.property" style `iteratee`', 1, function() { var actual = func(objects, { 'x': 40 }, 'x'); strictEqual(actual, 1); @@ -14918,14 +14642,6 @@ deepEqual(args, [2, 'a', object]); }); - test('should support the `thisArg` argument', 1, function() { - var actual = _.sum([6.8, 4.5, 2.6], function(num) { - return this.floor(num); - }, Math); - - strictEqual(actual, 12); - }); - test('should work with a "_.property" style `iteratee`', 2, function() { var arrays = [[2], [3], [1]]; strictEqual(_.sum(arrays, 0), 6); @@ -15004,21 +14720,6 @@ skipTest(2); } }); - - test('should support the `thisArg` argument', 1, function() { - if (!isNpm) { - var array = [1, 2]; - - var wrapped = _(array.slice()).tap(function(value) { - value.push(this[0]); - }, array); - - deepEqual(wrapped.value(), [1, 2, 1]); - } - else { - skipTest(); - } - }); }()); /*--------------------------------------------------------------------------*/ @@ -15937,16 +15638,6 @@ deepEqual(args, [0]); }); - test('should support the `thisArg` argument', 1, function() { - var expect = [1, 2, 3]; - - var actual = _.times(3, function(num) { - return this[num]; - }, expect); - - deepEqual(actual, expect); - }); - test('should use `_.identity` when `iteratee` is nullish', 1, function() { var values = [, null, undefined], expected = _.map(values, _.constant([0, 1, 2])); @@ -16247,15 +15938,6 @@ deepEqual(args, [first, 1, 'a', object]); } }); - - test('should support the `thisArg` argument when transforming an ' + key, 2, function() { - var actual = _.transform(object, function(result, value, key) { - result[key] = this[key]; - }, null, object); - - deepEqual(actual, object); - notStrictEqual(actual, object); - }); }); test('should create an object from the same realm as `object`', 1, function() { @@ -16505,14 +16187,6 @@ deepEqual(actual, objects.slice(0, 3)); }); - test('should support the `thisArg` argument', 1, function() { - var actual = _.uniq([1, 2, 1.5, 3, 2.5], function(num) { - return this.floor(num); - }, Math); - - deepEqual(actual, [1, 2, 3]); - }); - test('should work with a "_.property" style `iteratee`', 2, function() { var actual = _.uniq(objects, 'a'); @@ -16608,7 +16282,8 @@ }); _.each({ - 'an object': ['a'], + 'an array': [0, 'a'], + 'an object': { '0': 'a' }, 'a number': 0, 'a string': '0' }, @@ -16663,14 +16338,6 @@ deepEqual(args, [1, 2, 1, [1, 2]]); }); - test('should support the `thisArg` argument', 1, function() { - var actual = _.unzipWith([[1.2, 3.4], [2.3, 4.5]], function(a, b) { - return this.floor(a) + this.floor(b); - }, Math); - - deepEqual(actual, [3, 7]); - }); - test('should perform a basic unzip when `iteratee` is nullish', 1, function() { var array = [[1, 3], [2, 4]], values = [, null, undefined], @@ -16967,14 +16634,6 @@ deepEqual(args, [1, 3, 1, [1, 3, 5]]); }); - test('should support the `thisArg` argument', 1, function() { - var actual = _.zipWith([1.2, 2.3], [3.4, 4.5], function(a, b) { - return this.floor(a) + this.floor(b); - }, Math); - - deepEqual(actual, [4, 6]); - }); - test('should perform a basic zip when `iteratee` is nullish', 1, function() { var array1 = [1, 2], array2 = [3, 4], @@ -17986,83 +17645,6 @@ }); }); - test('should handle `null` `thisArg` arguments', 44, function() { - var expected = (function() { return this; }).call(null); - - var funcs = [ - 'assign', - 'clone', - 'cloneDeep', - 'countBy', - 'dropWhile', - 'dropRightWhile', - 'every', - 'filter', - 'find', - 'findIndex', - 'findKey', - 'findLast', - 'findLastIndex', - 'findLastKey', - 'forEach', - 'forEachRight', - 'forIn', - 'forInRight', - 'forOwn', - 'forOwnRight', - 'groupBy', - 'isEqual', - 'map', - 'mapValues', - 'max', - 'merge', - 'min', - 'omit', - 'partition', - 'pick', - 'reduce', - 'reduceRight', - 'reject', - 'remove', - 'some', - 'sortBy', - 'sortedIndex', - 'takeWhile', - 'takeRightWhile', - 'tap', - 'times', - 'transform', - 'thru', - 'uniq' - ]; - - _.each(funcs, function(methodName) { - var actual, - array = ['a'], - callback = function() { actual = this; }, - func = _[methodName], - message = '`_.' + methodName + '` handles `null` `thisArg` arguments'; - - if (func) { - if (_.startsWith(methodName, 'reduce') || methodName == 'transform') { - func(array, callback, 0, null); - } else if (_.includes(['assign', 'merge'], methodName)) { - func(array, array, callback, null); - } else if (_.includes(['isEqual', 'sortedIndex'], methodName)) { - func(array, 'a', callback, null); - } else if (methodName == 'times') { - func(1, callback, null); - } else { - func(array, callback, null); - } - strictEqual(actual, expected, message); - } - else { - skipTest(); - } - }); - }); - test('should not contain minified method names (test production builds)', 1, function() { var shortNames = ['at', 'eq', 'gt', 'lt']; ok(_.every(_.functions(_), function(methodName) { From c51466935c38c56d6c477822cae69e8b36422ad0 Mon Sep 17 00:00:00 2001 From: jdalton Date: Sat, 4 Jul 2015 11:19:23 -0700 Subject: [PATCH 007/935] Rename `bindCallback` to `toFunction`. --- lodash.src.js | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 9481cf5bd2..3f32523cbf 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -2985,18 +2985,6 @@ return nativeMin(high, MAX_ARRAY_INDEX); } - /** - * A specialized version of `baseIteratee` which only supports `this` binding - * and specifying the number of arguments to provide to `func`. - * - * @private - * @param {Function} func The function to bind. - * @returns {Function} Returns the callback. - */ - function bindCallback(func) { - return typeof func == 'function' ? func : identity; - } - /** * Creates a clone of the given array buffer. * @@ -3448,7 +3436,7 @@ return function(collection, iteratee) { return (typeof iteratee == 'function' && isArray(collection)) ? arrayFunc(collection, iteratee) - : eachFunc(collection, bindCallback(iteratee)); + : eachFunc(collection, toFunction(iteratee)); }; } @@ -3461,10 +3449,7 @@ */ function createForIn(objectFunc) { return function(object, iteratee) { - if (typeof iteratee != 'function') { - iteratee = bindCallback(iteratee); - } - return objectFunc(object, iteratee, keysIn); + return objectFunc(object, toFunction(iteratee), keysIn); }; } @@ -3477,10 +3462,7 @@ */ function createForOwn(objectFunc) { return function(object, iteratee) { - if (typeof iteratee != 'function') { - iteratee = bindCallback(iteratee); - } - return objectFunc(object, iteratee); + return objectFunc(object, toFunction(iteratee)); }; } @@ -4496,6 +4478,17 @@ return result; } + /** + * Converts `value` to a function if it's not one. + * + * @private + * @param {*} value The value to process. + * @returns {Function} Returns the function. + */ + function toFunction(func) { + return typeof func == 'function' ? func : identity; + } + /** * Converts `value` to an array-like object if it's not one. * @@ -5694,7 +5687,7 @@ if (iteratee == null) { return result; } - iteratee = bindCallback(iteratee); + iteratee = toFunction(iteratee); return arrayMap(result, function(group) { return arrayReduce(group, iteratee, undefined, true); }); @@ -11247,7 +11240,7 @@ var index = -1, result = Array(nativeMin(n, MAX_ARRAY_LENGTH)); - iteratee = bindCallback(iteratee); + iteratee = toFunction(iteratee); while (++index < n) { if (index < MAX_ARRAY_LENGTH) { result[index] = iteratee(index); From 5651993d93fe26e3ea993f62a3505c8526d85e33 Mon Sep 17 00:00:00 2001 From: jdalton Date: Sat, 4 Jul 2015 11:21:04 -0700 Subject: [PATCH 008/935] Use var `toIteratee` instead of `callback`. --- lodash.src.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 3f32523cbf..1ee09de89e 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -3709,10 +3709,10 @@ */ function createSortedIndex(retHighest) { return function(array, value, iteratee) { - var callback = getIteratee(); - return (iteratee == null && callback === baseIteratee) + var toIteratee = getIteratee(); + return (iteratee == null && toIteratee === baseIteratee) ? binaryIndex(array, value, retHighest) - : binaryIndexBy(array, value, callback(iteratee), retHighest); + : binaryIndexBy(array, value, toIteratee(iteratee), retHighest); }; } @@ -5612,9 +5612,9 @@ iteratee = isIterateeCall(array, isSorted, iteratee) ? undefined : isSorted; isSorted = false; } - var callback = getIteratee(); - if (!(iteratee == null && callback === baseIteratee)) { - iteratee = callback(iteratee); + var toIteratee = getIteratee(); + if (!(iteratee == null && toIteratee === baseIteratee)) { + iteratee = toIteratee(iteratee); } return (isSorted && getIndexOf() === baseIndexOf) ? sortedUniq(array, iteratee) From 1011353729a2614b100ad40a7bbc7a4a1a3137e5 Mon Sep 17 00:00:00 2001 From: jdalton Date: Sat, 4 Jul 2015 11:22:39 -0700 Subject: [PATCH 009/935] Adjust `guard` doc notes. [ci skip] --- lodash.src.js | 48 +++++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 1ee09de89e..14c55be84a 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -4573,7 +4573,7 @@ * @category Array * @param {Array} array The array to process. * @param {number} [size=1] The length of each chunk. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @param- {Object} [guard] Enables use as an iteratee for functions like `_.map`. * @returns {Array} Returns the new array containing chunks. * @example * @@ -4659,7 +4659,7 @@ * @category Array * @param {Array} array The array to query. * @param {number} [n=1] The number of elements to drop. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @param- {Object} [guard] Enables use as an iteratee for functions like `_.map`. * @returns {Array} Returns the slice of `array`. * @example * @@ -4694,7 +4694,7 @@ * @category Array * @param {Array} array The array to query. * @param {number} [n=1] The number of elements to drop. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @param- {Object} [guard] Enables use as an iteratee for functions like `_.map`. * @returns {Array} Returns the slice of `array`. * @example * @@ -4950,7 +4950,7 @@ * @category Array * @param {Array} array The array to flatten. * @param {boolean} [isDeep] Specify a deep flatten. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @param- {Object} [guard] Enables use as an iteratee for functions like `_.map`. * @returns {Array} Returns the new flattened array. * @example * @@ -5401,7 +5401,7 @@ * @category Array * @param {Array} array The array to query. * @param {number} [n=1] The number of elements to take. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @param- {Object} [guard] Enables use as an iteratee for functions like `_.map`. * @returns {Array} Returns the slice of `array`. * @example * @@ -5436,7 +5436,7 @@ * @category Array * @param {Array} array The array to query. * @param {number} [n=1] The number of elements to take. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @param- {Object} [guard] Enables use as an iteratee for functions like `_.map`. * @returns {Array} Returns the slice of `array`. * @example * @@ -6172,7 +6172,7 @@ * @category Collection * @param {Array|Object|string} collection The collection to iterate over. * @param {Function|Object|string} [predicate=_.identity] The function invoked per iteration. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @param- {Object} [guard] Enables use as an iteratee for functions like `_.map`. * @returns {boolean} Returns `true` if all elements pass the predicate check, else `false`. * @example * @@ -6401,7 +6401,7 @@ * @param {Array|Object|string} collection The collection to search. * @param {*} target The value to search for. * @param {number} [fromIndex=0] The index to search from. - * @param- {Object} [guard] Enables use as a callback for functions like `_.reduce`. + * @param- {Object} [guard] Enables use as an iteratee for functions like `_.reduce`. * @returns {boolean} Returns `true` if a matching element is found, else `false`. * @example * @@ -6703,7 +6703,7 @@ * @category Collection * @param {Array|Object|string} collection The collection to sample. * @param {number} [n] The number of elements to sample. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @param- {Object} [guard] Enables use as an iteratee for functions like `_.map`. * @returns {*} Returns the random sample(s). * @example * @@ -6791,7 +6791,7 @@ * @category Collection * @param {Array|Object|string} collection The collection to iterate over. * @param {Function|Object|string} [predicate=_.identity] The function invoked per iteration. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @param- {Object} [guard] Enables use as an iteratee for functions like `_.map`. * @returns {boolean} Returns `true` if any element passes the predicate check, else `false`. * @example * @@ -7030,7 +7030,7 @@ * @category Function * @param {Function} func The function to cap arguments for. * @param {number} [n=func.length] The arity cap. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @param- {Object} [guard] Enables use as an iteratee for functions like `_.map`. * @returns {Function} Returns the new function. * @example * @@ -7238,7 +7238,7 @@ * @category Function * @param {Function} func The function to curry. * @param {number} [arity=func.length] The arity of `func`. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @param- {Object} [guard] Enables use as an iteratee for functions like `_.map`. * @returns {Function} Returns the new curried function. * @example * @@ -7277,7 +7277,7 @@ * @category Function * @param {Function} func The function to curry. * @param {number} [arity=func.length] The arity of `func`. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @param- {Object} [guard] Enables use as an iteratee for functions like `_.map`. * @returns {Function} Returns the new curried function. * @example * @@ -8935,7 +8935,7 @@ * @category Object * @param {Object} prototype The object to inherit from. * @param {Object} [properties] The properties to assign to the object. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @param- {Object} [guard] Enables use as an iteratee for functions like `_.map`. * @returns {Object} Returns the new object. * @example * @@ -9287,7 +9287,7 @@ * @category Object * @param {Object} object The object to invert. * @param {boolean} [multiValue] Allow multiple values per key. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @param- {Object} [guard] Enables use as an iteratee for functions like `_.map`. * @returns {Object} Returns the new inverted object. * @example * @@ -10172,7 +10172,7 @@ * @category String * @param {string} string The string to convert. * @param {number} [radix] The radix to interpret `value` by. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @param- {Object} [guard] Enables use as an iteratee for functions like `_.map`. * @returns {number} Returns the converted integer. * @example * @@ -10521,7 +10521,7 @@ * @category String * @param {string} [string=''] The string to trim. * @param {string} [chars=whitespace] The characters to trim. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @param- {Object} [guard] Enables use as an iteratee for functions like `_.map`. * @returns {string} Returns the trimmed string. * @example * @@ -10555,7 +10555,7 @@ * @category String * @param {string} [string=''] The string to trim. * @param {string} [chars=whitespace] The characters to trim. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @param- {Object} [guard] Enables use as an iteratee for functions like `_.map`. * @returns {string} Returns the trimmed string. * @example * @@ -10585,7 +10585,7 @@ * @category String * @param {string} [string=''] The string to trim. * @param {string} [chars=whitespace] The characters to trim. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @param- {Object} [guard] Enables use as an iteratee for functions like `_.map`. * @returns {string} Returns the trimmed string. * @example * @@ -10620,7 +10620,7 @@ * @param {number} [options.length=30] The maximum string length. * @param {string} [options.omission='...'] The string to indicate text is omitted. * @param {RegExp|string} [options.separator] The separator pattern to truncate to. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @param- {Object} [guard] Enables use as an iteratee for functions like `_.map`. * @returns {string} Returns the truncated string. * @example * @@ -10732,7 +10732,7 @@ * @category String * @param {string} [string=''] The string to inspect. * @param {RegExp|string} [pattern] The pattern to match words. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @param- {Object} [guard] Enables use as an iteratee for functions like `_.map`. * @returns {Array} Returns the words of `string`. * @example * @@ -11438,7 +11438,7 @@ * @category Math * @param {Array|Object|string} collection The collection to iterate over. * @param {Function|Object|string} [iteratee] The function invoked per iteration. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @param- {Object} [guard] Enables use as an iteratee for functions like `_.map`. * @returns {number} Returns the sum. * @example * @@ -11453,9 +11453,7 @@ * { 'n': 6 } * ]; * - * _.sum(objects, function(object) { - * return object.n; - * }); + * _.sum(objects, function(o) { return o.n; }); * // => 10 * * // using the `_.property` callback shorthand From 04bac321d12995af36f3095eb1c20347722d683b Mon Sep 17 00:00:00 2001 From: jdalton Date: Sat, 4 Jul 2015 11:25:19 -0700 Subject: [PATCH 010/935] Cleanup doc examples. [ci skip] --- lodash.src.js | 207 ++++++++++++++++++++++++-------------------------- 1 file changed, 99 insertions(+), 108 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 14c55be84a..00b15afe0c 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -938,8 +938,8 @@ * var wrapped = _([1, 2, 3]); * * // returns an unwrapped value - * wrapped.reduce(function(total, n) { - * return total + n; + * wrapped.reduce(function(sum, n) { + * return sum + n; * }); * // => 6 * @@ -4735,27 +4735,27 @@ * @returns {Array} Returns the slice of `array`. * @example * - * _.dropRightWhile([1, 2, 3], function(n) { - * return n > 1; - * }); - * // => [1] - * * var users = [ * { 'user': 'barney', 'active': true }, * { 'user': 'fred', 'active': false }, * { 'user': 'pebbles', 'active': false } * ]; * + * var resolve = _.partial(_.map, _, 'user'); + * + * resolve( _.dropRightWhile(users, function(o) { return !o.active; }) ); + * // => ['barney'] + * * // using the `_.matches` callback shorthand - * _.map(_.dropRightWhile(users, { 'user': 'pebbles', 'active': false }), 'user'); + * resolve( _.dropRightWhile(users, { 'user': 'pebbles', 'active': false }) ); * // => ['barney', 'fred'] * * // using the `_.matchesProperty` callback shorthand - * _.map(_.dropRightWhile(users, ['active', false]), 'user'); + * resolve( _.dropRightWhile(users, ['active', false]) ); * // => ['barney'] * * // using the `_.property` callback shorthand - * _.map(_.dropRightWhile(users, 'active'), 'user'); + * resolve( _.dropRightWhile(users, 'active') ); * // => ['barney', 'fred', 'pebbles'] */ function dropRightWhile(array, predicate) { @@ -4777,27 +4777,27 @@ * @returns {Array} Returns the slice of `array`. * @example * - * _.dropWhile([1, 2, 3], function(n) { - * return n < 3; - * }); - * // => [3] - * * var users = [ * { 'user': 'barney', 'active': false }, * { 'user': 'fred', 'active': false }, * { 'user': 'pebbles', 'active': true } * ]; * + * var resolve = _.partial(_.map, _, 'user'); + * + * resolve( _.dropWhile(users, function(o) { return !o.active; }) ); + * // => ['pebbles'] + * * // using the `_.matches` callback shorthand - * _.map(_.dropWhile(users, { 'user': 'barney', 'active': false }), 'user'); + * resolve( _.dropWhile(users, { 'user': 'barney', 'active': false }) ); * // => ['fred', 'pebbles'] * * // using the `_.matchesProperty` callback shorthand - * _.map(_.dropWhile(users, ['active', false]), 'user'); + * resolve( _.dropWhile(users, ['active', false]) ); * // => ['pebbles'] * * // using the `_.property` callback shorthand - * _.map(_.dropWhile(users, 'active'), 'user'); + * resolve( _.dropWhile(users, 'active') ); * // => ['barney', 'fred', 'pebbles'] */ function dropWhile(array, predicate) { @@ -4864,9 +4864,7 @@ * { 'user': 'pebbles', 'active': true } * ]; * - * _.findIndex(users, function(chr) { - * return chr.user == 'barney'; - * }); + * _.findIndex(users, function(o) { return o.user == 'barney'; }); * // => 0 * * // using the `_.matches` callback shorthand @@ -4901,9 +4899,7 @@ * { 'user': 'pebbles', 'active': false } * ]; * - * _.findLastIndex(users, function(chr) { - * return chr.user == 'pebbles'; - * }); + * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; }); * // => 2 * * // using the `_.matches` callback shorthand @@ -5363,9 +5359,7 @@ * var dict = { 'thirty': 30, 'forty': 40, 'fifty': 50 }; * * // using an iteratee function - * _.sortedIndex(['thirty', 'fifty'], 'forty', function(word) { - * return dict[word]; - * }); + * _.sortedIndex(['thirty', 'fifty'], 'forty', _.propertyOf(dict)); * // => 1 * * // using the `_.property` callback shorthand @@ -5477,27 +5471,27 @@ * @returns {Array} Returns the slice of `array`. * @example * - * _.takeRightWhile([1, 2, 3], function(n) { - * return n > 1; - * }); - * // => [2, 3] - * * var users = [ * { 'user': 'barney', 'active': true }, * { 'user': 'fred', 'active': false }, * { 'user': 'pebbles', 'active': false } * ]; * + * var resolve = _.partial(_.map, _, 'user'); + * + * resolve( _.takeRightWhile(users, function(o) { return !o.active; }) ); + * // => ['fred', 'pebbles'] + * * // using the `_.matches` callback shorthand - * _.map(_.takeRightWhile(users, { 'user': 'pebbles', 'active': false }), 'user'); + * resolve( _.takeRightWhile(users, { 'user': 'pebbles', 'active': false }) ); * // => ['pebbles'] * * // using the `_.matchesProperty` callback shorthand - * _.map(_.takeRightWhile(users, ['active', false]), 'user'); + * resolve( _.takeRightWhile(users, ['active', false]) ); * // => ['fred', 'pebbles'] * * // using the `_.property` callback shorthand - * _.map(_.takeRightWhile(users, 'active'), 'user'); + * resolve( _.takeRightWhile(users, 'active') ); * // => [] */ function takeRightWhile(array, predicate) { @@ -5519,27 +5513,27 @@ * @returns {Array} Returns the slice of `array`. * @example * - * _.takeWhile([1, 2, 3], function(n) { - * return n < 3; - * }); - * // => [1, 2] - * * var users = [ * { 'user': 'barney', 'active': false }, * { 'user': 'fred', 'active': false}, * { 'user': 'pebbles', 'active': true } * ]; * + * var resolve = _.partial(_.map, _, 'user'); + * + * resolve( _.takeWhile(users, function(o) { return !o.active; }) ); + * // => ['barney', 'fred'] + * * // using the `_.matches` callback shorthand - * _.map(_.takeWhile(users, { 'user': 'barney', 'active': false }), 'user'); + * resolve( _.takeWhile(users, { 'user': 'barney', 'active': false }) ); * // => ['barney'] * * // using the `_.matchesProperty` callback shorthand - * _.map(_.takeWhile(users, ['active', false]), 'user'); + * resolve( _.takeWhile(users, ['active', false]) ); * // => ['barney', 'fred'] * * // using the `_.property` callback shorthand - * _.map(_.takeWhile(users, 'active'), 'user'); + * resolve( _.takeWhile(users, 'active') ); * // => [] */ function takeWhile(array, predicate) { @@ -5844,10 +5838,11 @@ * { 'user': 'pebbles', 'age': 1 } * ]; * - * var youngest = _.chain(users) + * var youngest = _ + * .chain(users) * .sortBy('age') - * .map(function(chr) { - * return chr.user + ' is ' + chr.age; + * .map(function(o) { + * return o.user + ' is ' + o.age; * }) * .first() * .value(); @@ -5929,7 +5924,8 @@ * // => { 'user': 'barney', 'age': 36 } * * // with explicit chaining - * _(users).chain() + * _(users) + * .chain() * .first() * .pick('user') * .value(); @@ -6221,26 +6217,26 @@ * @returns {Array} Returns the new filtered array. * @example * - * _.filter([4, 5, 6], function(n) { - * return n % 2 == 0; - * }); - * // => [4, 6] - * * var users = [ * { 'user': 'barney', 'age': 36, 'active': true }, * { 'user': 'fred', 'age': 40, 'active': false } * ]; * + * var resolve = _.partial(_.map, _, 'user'); + * + * resolve( _.filter(users, function(o) { return !o.active; }) ); + * // => ['fred'] + * * // using the `_.matches` callback shorthand - * _.map(_.filter(users, { 'age': 36, 'active': true }), 'user'); + * resolve( _.filter(users, { 'age': 36, 'active': true }) ); * // => ['barney'] * * // using the `_.matchesProperty` callback shorthand - * _.map(_.filter(users, ['active', false]), 'user'); + * resolve( _.filter(users, ['active', false]) ); * // => ['fred'] * * // using the `_.property` callback shorthand - * _.map(_.filter(users, 'active'), 'user'); + * resolve( _.filter(users, 'active') ); * // => ['barney'] */ function filter(collection, predicate) { @@ -6269,21 +6265,21 @@ * { 'user': 'pebbles', 'age': 1, 'active': true } * ]; * - * _.result(_.find(users, function(chr) { - * return chr.age < 40; - * }), 'user'); + * var resolve = _.partial(_.result, _, 'user'); + * + * resolve( _.find(users, function(o) { return o.age < 40; }) ); * // => 'barney' * * // using the `_.matches` callback shorthand - * _.result(_.find(users, { 'age': 1, 'active': true }), 'user'); + * resolve( _.find(users, { 'age': 1, 'active': true }) ); * // => 'pebbles' * * // using the `_.matchesProperty` callback shorthand - * _.result(_.find(users, ['active', false]), 'user'); + * resolve( _.find(users, ['active', false]) ); * // => 'fred' * * // using the `_.property` callback shorthand - * _.result(_.find(users, 'active'), 'user'); + * resolve( _.find(users, 'active') ); * // => 'barney' */ var find = createFind(baseEach); @@ -6455,8 +6451,8 @@ * _.indexBy(keyData, 'dir'); * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } } * - * _.indexBy(keyData, function(object) { - * return String.fromCharCode(object.code); + * _.indexBy(keyData, function(o) { + * return String.fromCharCode(o.code); * }); * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } */ @@ -6561,31 +6557,29 @@ * @returns {Array} Returns the array of grouped elements. * @example * - * _.partition([1, 2, 3], function(n) { - * return n % 2; - * }); - * // => [[1, 3], [2]] - * * var users = [ * { 'user': 'barney', 'age': 36, 'active': false }, * { 'user': 'fred', 'age': 40, 'active': true }, * { 'user': 'pebbles', 'age': 1, 'active': false } * ]; * - * var mapper = function(array) { - * return _.map(array, 'user'); + * var resolve = function(result) { + * return _.map(result, function(array) { return _.map(array, 'user'); }); * }; * + * resolve( _.partition(users, function(o) { return o.active; }) ); + * // => [['fred'], ['barney', 'pebbles']] + * * // using the `_.matches` callback shorthand - * _.map(_.partition(users, { 'age': 1, 'active': false }), mapper); + * resolve( _.partition(users, { 'age': 1, 'active': false }) ); * // => [['pebbles'], ['barney', 'fred']] * * // using the `_.matchesProperty` callback shorthand - * _.map(_.partition(users, ['active', false]), mapper); + * resolve( _.partition(users, ['active', false]) ); * // => [['barney', 'pebbles'], ['fred']] * * // using the `_.property` callback shorthand - * _.map(_.partition(users, 'active'), mapper); + * resolve( _.partition(users, 'active') ); * // => [['fred'], ['barney', 'pebbles']] */ var partition = createAggregator(function(result, value, key) { @@ -6617,8 +6611,8 @@ * @returns {*} Returns the accumulated value. * @example * - * _.reduce([1, 2], function(total, n) { - * return total + n; + * _.reduce([1, 2], function(sum, n) { + * return sum + n; * }); * // => 3 * @@ -6665,26 +6659,26 @@ * @returns {Array} Returns the new filtered array. * @example * - * _.reject([1, 2, 3, 4], function(n) { - * return n % 2 == 0; - * }); - * // => [1, 3] - * * var users = [ * { 'user': 'barney', 'age': 36, 'active': false }, * { 'user': 'fred', 'age': 40, 'active': true } * ]; * + * var resolve = _.partial(_.map, _, 'user'); + * + * resolve( _.reject(users, function(o) { return !o.active; }) ); + * // => ['fred'] + * * // using the `_.matches` callback shorthand - * _.map(_.reject(users, { 'age': 40, 'active': true }), 'user'); + * resolve( _.reject(users, { 'age': 40, 'active': true }) ); * // => ['barney'] * * // using the `_.matchesProperty` callback shorthand - * _.map(_.reject(users, ['active', false]), 'user'); + * resolve( _.reject(users, ['active', false]) ); * // => ['fred'] * * // using the `_.property` callback shorthand - * _.map(_.reject(users, 'active'), 'user'); + * resolve( _.reject(users, 'active') ); * // => ['barney'] */ function reject(collection, predicate) { @@ -6896,15 +6890,20 @@ * { 'user': 'barney', 'age': 34 } * ]; * - * _.map(_.sortByAll(users, ['user', 'age']), _.values); + * var resolve = _.partial(_.map, _, _.values); + * + * resolve( _.sortBy(users, function(o) { return o.user; }) ); + * // => // => [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]] + * + * resolve( _.sortBy(users, ['user', 'age']) ); * // => [['barney', 34], ['barney', 36], ['fred', 42], ['fred', 48]] * - * _.map(_.sortByAll(users, 'user', function(chr) { - * return Math.floor(chr.age / 10); - * }), _.values); + * resolve( _.sortBy(users, 'user', function(o) { + * return Math.floor(o.age / 10); + * }) ); * // => [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]] */ - var sortByAll = restParam(function(collection, iteratees) { + var sortBy = restParam(function(collection, iteratees) { if (collection == null) { return []; } @@ -6916,7 +6915,7 @@ }); /** - * This method is like `_.sortByAll` except that it allows specifying the + * This method is like `_.sortBy` except that it allows specifying the * sort orders of the iteratees to sort by. If `orders` is unspecified, all * values are sorted in ascending order. Otherwise, a value is sorted in * ascending order if its corresponding order is "asc", and descending if "desc". @@ -6927,7 +6926,7 @@ * @param {Array|Object|string} collection The collection to iterate over. * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. * @param {boolean[]} [orders] The sort orders of `iteratees`. - * @param- {Object} [guard] Enables use as a callback for functions like `_.reduce`. + * @param- {Object} [guard] Enables use as an iteratee for functions like `_.reduce`. * @returns {Array} Returns the new sorted array. * @example * @@ -6938,8 +6937,10 @@ * { 'user': 'barney', 'age': 36 } * ]; * + * var resolve = _.partial(_.map, _, _.values); + * * // sort by `user` in ascending order and by `age` in descending order - * _.map(_.sortByOrder(users, ['user', 'age'], ['asc', 'desc']), _.values); + * resolve( _.sortByOrder(users, ['user', 'age'], ['asc', 'desc']) ); * // => [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]] */ function sortByOrder(collection, iteratees, orders, guard) { @@ -9025,9 +9026,7 @@ * 'pebbles': { 'age': 1, 'active': true } * }; * - * _.findKey(users, function(chr) { - * return chr.age < 40; - * }); + * _.findKey(users, function(o) { return o.age < 40; }); * // => 'barney' (iteration order is not guaranteed) * * // using the `_.matches` callback shorthand @@ -9062,9 +9061,7 @@ * 'pebbles': { 'age': 1, 'active': true } * }; * - * _.findLastKey(users, function(chr) { - * return chr.age < 40; - * }); + * _.findLastKey(users, function(o) { return o.age < 40; }); * // => returns `pebbles` assuming `_.findKey` returns `barney` * * // using the `_.matches` callback shorthand @@ -9475,16 +9472,14 @@ * @returns {Object} Returns the new mapped object. * @example * - * _.mapValues({ 'a': 1, 'b': 2 }, function(n) { - * return n * 3; - * }); - * // => { 'a': 3, 'b': 6 } - * * var users = { * 'fred': { 'user': 'fred', 'age': 40 }, * 'pebbles': { 'user': 'pebbles', 'age': 1 } * }; * + * _.mapValues(users, function(o) { return o.age; }); + * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) + * * // using the `_.property` callback shorthand * _.mapValues(users, 'age'); * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) @@ -11361,9 +11356,7 @@ * { 'user': 'fred', 'age': 40 } * ]; * - * _.max(users, function(chr) { - * return chr.age; - * }); + * _.max(users, function(o) { return o.age; }); * // => { 'user': 'fred', 'age': 40 } * * // using the `_.property` callback shorthand @@ -11397,9 +11390,7 @@ * { 'user': 'fred', 'age': 40 } * ]; * - * _.min(users, function(chr) { - * return chr.age; - * }); + * _.min(users, function(o) { return o.age; }); * // => { 'user': 'barney', 'age': 36 } * * // using the `_.property` callback shorthand From d3d4de12be604b2f9df2132d9066a7ab9c96f3e0 Mon Sep 17 00:00:00 2001 From: jdalton Date: Sat, 4 Jul 2015 11:26:22 -0700 Subject: [PATCH 011/935] Rename `pickByCallback` to `pickByPredicate`. --- lodash.src.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 00b15afe0c..26fdee45af 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -4385,7 +4385,7 @@ * @param {Function} predicate The function invoked per iteration. * @returns {Object} Returns the new object. */ - function pickByCallback(object, predicate) { + function pickByPredicate(object, predicate) { var result = {}; baseForIn(object, function(value, key, object) { if (predicate(value, key, object)) { @@ -9517,7 +9517,7 @@ return pickByArray(object, baseDifference(keysIn(object), props)); } var predicate = props[0]; - return pickByCallback(object, function(value, key, object) { + return pickByPredicate(object, function(value, key, object) { return !predicate(value, key, object); }); }); @@ -9581,7 +9581,7 @@ return {}; } return typeof props[0] == 'function' - ? pickByCallback(object, props[0]) + ? pickByPredicate(object, props[0]) : pickByArray(object, baseFlatten(props)); }); From 86be6d7897eb7e77f8e3a2777e2aab43225223ad Mon Sep 17 00:00:00 2001 From: jdalton Date: Sat, 4 Jul 2015 11:31:29 -0700 Subject: [PATCH 012/935] Move `resolve` doc helpers higher in their example blocks. [ci skip] --- lodash.src.js | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 26fdee45af..ea87276901 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -4735,14 +4735,14 @@ * @returns {Array} Returns the slice of `array`. * @example * + * var resolve = _.partial(_.map, _, 'user'); + * * var users = [ * { 'user': 'barney', 'active': true }, * { 'user': 'fred', 'active': false }, * { 'user': 'pebbles', 'active': false } * ]; * - * var resolve = _.partial(_.map, _, 'user'); - * * resolve( _.dropRightWhile(users, function(o) { return !o.active; }) ); * // => ['barney'] * @@ -4777,14 +4777,14 @@ * @returns {Array} Returns the slice of `array`. * @example * + * var resolve = _.partial(_.map, _, 'user'); + * * var users = [ * { 'user': 'barney', 'active': false }, * { 'user': 'fred', 'active': false }, * { 'user': 'pebbles', 'active': true } * ]; * - * var resolve = _.partial(_.map, _, 'user'); - * * resolve( _.dropWhile(users, function(o) { return !o.active; }) ); * // => ['pebbles'] * @@ -5471,14 +5471,14 @@ * @returns {Array} Returns the slice of `array`. * @example * + * var resolve = _.partial(_.map, _, 'user'); + * * var users = [ * { 'user': 'barney', 'active': true }, * { 'user': 'fred', 'active': false }, * { 'user': 'pebbles', 'active': false } * ]; * - * var resolve = _.partial(_.map, _, 'user'); - * * resolve( _.takeRightWhile(users, function(o) { return !o.active; }) ); * // => ['fred', 'pebbles'] * @@ -5513,14 +5513,14 @@ * @returns {Array} Returns the slice of `array`. * @example * + * var resolve = _.partial(_.map, _, 'user'); + * * var users = [ * { 'user': 'barney', 'active': false }, * { 'user': 'fred', 'active': false}, * { 'user': 'pebbles', 'active': true } * ]; * - * var resolve = _.partial(_.map, _, 'user'); - * * resolve( _.takeWhile(users, function(o) { return !o.active; }) ); * // => ['barney', 'fred'] * @@ -6217,13 +6217,13 @@ * @returns {Array} Returns the new filtered array. * @example * + * var resolve = _.partial(_.map, _, 'user'); + * * var users = [ * { 'user': 'barney', 'age': 36, 'active': true }, * { 'user': 'fred', 'age': 40, 'active': false } * ]; * - * var resolve = _.partial(_.map, _, 'user'); - * * resolve( _.filter(users, function(o) { return !o.active; }) ); * // => ['fred'] * @@ -6259,14 +6259,14 @@ * @returns {*} Returns the matched element, else `undefined`. * @example * + * var resolve = _.partial(_.result, _, 'user'); + * * var users = [ * { 'user': 'barney', 'age': 36, 'active': true }, * { 'user': 'fred', 'age': 40, 'active': false }, * { 'user': 'pebbles', 'age': 1, 'active': true } * ]; * - * var resolve = _.partial(_.result, _, 'user'); - * * resolve( _.find(users, function(o) { return o.age < 40; }) ); * // => 'barney' * @@ -6557,16 +6557,16 @@ * @returns {Array} Returns the array of grouped elements. * @example * + * var resolve = function(result) { + * return _.map(result, function(array) { return _.map(array, 'user'); }); + * }; + * * var users = [ * { 'user': 'barney', 'age': 36, 'active': false }, * { 'user': 'fred', 'age': 40, 'active': true }, * { 'user': 'pebbles', 'age': 1, 'active': false } * ]; * - * var resolve = function(result) { - * return _.map(result, function(array) { return _.map(array, 'user'); }); - * }; - * * resolve( _.partition(users, function(o) { return o.active; }) ); * // => [['fred'], ['barney', 'pebbles']] * @@ -6659,13 +6659,13 @@ * @returns {Array} Returns the new filtered array. * @example * + * var resolve = _.partial(_.map, _, 'user'); + * * var users = [ * { 'user': 'barney', 'age': 36, 'active': false }, * { 'user': 'fred', 'age': 40, 'active': true } * ]; * - * var resolve = _.partial(_.map, _, 'user'); - * * resolve( _.reject(users, function(o) { return !o.active; }) ); * // => ['fred'] * @@ -6930,6 +6930,8 @@ * @returns {Array} Returns the new sorted array. * @example * + * var resolve = _.partial(_.map, _, _.values); + * * var users = [ * { 'user': 'fred', 'age': 48 }, * { 'user': 'barney', 'age': 34 }, @@ -6937,8 +6939,6 @@ * { 'user': 'barney', 'age': 36 } * ]; * - * var resolve = _.partial(_.map, _, _.values); - * * // sort by `user` in ascending order and by `age` in descending order * resolve( _.sortByOrder(users, ['user', 'age'], ['asc', 'desc']) ); * // => [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]] From a898c3d7bcde2d0bfbacbff6de8173fb80cb18b3 Mon Sep 17 00:00:00 2001 From: jdalton Date: Sat, 4 Jul 2015 14:52:21 -0700 Subject: [PATCH 013/935] Absorb `_.sortByAll` into `_.sortBy`. --- lodash.src.js | 82 +++++++++++++-------------------------------------- test/test.js | 38 ++---------------------- 2 files changed, 23 insertions(+), 97 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index ea87276901..057792706a 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -2752,17 +2752,21 @@ * @private * @param {Array|Object|string} collection The collection to iterate over. * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. - * @param {boolean[]} orders The sort orders of `iteratees`. + * @param {boolean[]|string[]} orders The sort orders of `iteratees`. * @returns {Array} Returns the new sorted array. */ function baseSortByOrder(collection, iteratees, orders) { - var callback = getIteratee(), + var toIteratee = getIteratee(), index = -1; - iteratees = arrayMap(iteratees, function(iteratee) { return callback(iteratee); }); + iteratees = arrayMap(iteratees.length ? iteratees : Array(1), function(iteratee) { + return toIteratee(iteratee); + }); - var result = baseMap(collection, function(value) { - var criteria = arrayMap(iteratees, function(iteratee) { return iteratee(value); }); + var result = baseMap(collection, function(value, key, collection) { + var criteria = arrayMap(iteratees, function(iteratee) { + return iteratee(value, key, collection); + }); return { 'criteria': criteria, 'index': ++index, 'value': value }; }); @@ -6822,67 +6826,22 @@ /** * Creates an array of elements, sorted in ascending order by the results of - * running each element in a collection through `iteratee`. This method performs - * a stable sort, that is, it preserves the original sort order of equal elements. - * The iteratee is invoked with three arguments: (value, index|key, collection). - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. - * @returns {Array} Returns the new sorted array. - * @example - * - * _.sortBy([1, 2, 3], function(n) { - * return Math.sin(n); - * }); - * // => [3, 1, 2] - * - * _.sortBy([1, 2, 3], function(n) { - * return this.sin(n); - * }, Math); - * // => [3, 1, 2] - * - * var users = [ - * { 'user': 'fred' }, - * { 'user': 'pebbles' }, - * { 'user': 'barney' } - * ]; - * - * // using the `_.property` callback shorthand - * _.map(_.sortBy(users, 'user'), 'user'); - * // => ['barney', 'fred', 'pebbles'] - */ - function sortBy(collection, iteratee, thisArg) { - if (collection == null) { - return []; - } - if (thisArg && isIterateeCall(collection, iteratee, thisArg)) { - iteratee = undefined; - } - var index = -1; - iteratee = getIteratee(iteratee, thisArg, 3); - - var result = baseMap(collection, function(value, key, collection) { - return { 'criteria': iteratee(value, key, collection), 'index': ++index, 'value': value }; - }); - return baseSortBy(result, compareAscending); - } - - /** - * This method is like `_.sortBy` except that it can sort by multiple iteratees - * or property names. + * running each element in a collection through each iteratee. This method + * performs a stable sort, that is, it preserves the original sort order of + * equal elements. The iteratee is invoked with three arguments: + * (value, index|key, collection). * * @static * @memberOf _ * @category Collection * @param {Array|Object|string} collection The collection to iterate over. - * @param {...(Function|Function[]|Object|Object[]|string|string[])} iteratees + * @param {...(Function|Function[]|Object|Object[]|string|string[])} [iteratees=[_.identity]] * The iteratees to sort by, specified as individual values or arrays of values. * @returns {Array} Returns the new sorted array. * @example * + * var resolve = _.partial(_.map, _, _.values); + * * var users = [ * { 'user': 'fred', 'age': 48 }, * { 'user': 'barney', 'age': 36 }, @@ -6890,8 +6849,6 @@ * { 'user': 'barney', 'age': 34 } * ]; * - * var resolve = _.partial(_.map, _, _.values); - * * resolve( _.sortBy(users, function(o) { return o.user; }) ); * // => // => [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]] * @@ -6907,8 +6864,10 @@ if (collection == null) { return []; } - var guard = iteratees[2]; - if (guard && isIterateeCall(iteratees[0], iteratees[1], guard)) { + var length = iteratees.length; + if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) { + iteratees = []; + } else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) { iteratees.length = 1; } return baseSortByOrder(collection, baseFlatten(iteratees), []); @@ -11560,7 +11519,6 @@ lodash.shuffle = shuffle; lodash.slice = slice; lodash.sortBy = sortBy; - lodash.sortByAll = sortByAll; lodash.sortByOrder = sortByOrder; lodash.spread = spread; lodash.take = take; diff --git a/test/test.js b/test/test.js index 9872c99393..075178d783 100644 --- a/test/test.js +++ b/test/test.js @@ -14146,12 +14146,6 @@ QUnit.module('lodash.sortBy'); (function() { - function Pair(a, b, c) { - this.a = a; - this.b = b; - this.c = c; - } - var objects = [ { 'a': 'x', 'b': 3 }, { 'a': 'y', 'b': 4 }, @@ -14159,21 +14153,6 @@ { 'a': 'y', 'b': 2 } ]; - var stableArray = [ - new Pair(1, 1, 1), new Pair(1, 2, 1), - new Pair(1, 1, 1), new Pair(1, 2, 1), - new Pair(1, 3, 1), new Pair(1, 4, 1), - new Pair(1, 5, 1), new Pair(1, 6, 1), - new Pair(2, 1, 2), new Pair(2, 2, 2), - new Pair(2, 3, 2), new Pair(2, 4, 2), - new Pair(2, 5, 2), new Pair(2, 6, 2), - new Pair(undefined, 1, 1), new Pair(undefined, 2, 1), - new Pair(undefined, 3, 1), new Pair(undefined, 4, 1), - new Pair(undefined, 5, 1), new Pair(undefined, 6, 1) - ]; - - var stableObject = _.zipObject('abcdefghijklmnopqrst'.split(''), stableArray); - test('should sort in ascending order', 1, function() { var actual = _.map(_.sortBy(objects, function(object) { return object.b; @@ -14182,16 +14161,6 @@ deepEqual(actual, [1, 2, 3, 4]); }); - test('should perform a stable sort (test in V8)', 2, function() { - _.each([stableArray, stableObject], function(value, index) { - var actual = _.sortBy(value, function(pair) { - return pair.a; - }); - - deepEqual(actual, stableArray, index ? 'object' : 'array'); - }); - }); - test('should provide the correct `iteratee` arguments', 1, function() { var args; @@ -14286,7 +14255,7 @@ QUnit.module('sortBy methods'); - _.each(['sortByAll', 'sortByOrder'], function(methodName) { + _.each(['sortBy', 'sortByOrder'], function(methodName) { var func = _[methodName]; function Pair(a, b, c) { @@ -17548,7 +17517,6 @@ 'sample', 'shuffle', 'sortBy', - 'sortByAll', 'sortByOrder', 'take', 'times', @@ -17563,7 +17531,7 @@ var acceptFalsey = _.difference(allMethods, rejectFalsey); - test('should accept falsey arguments', 207, function() { + test('should accept falsey arguments', 205, function() { var emptyArrays = _.map(falsey, _.constant([])); _.each(acceptFalsey, function(methodName) { @@ -17599,7 +17567,7 @@ }); }); - test('should return an array', 68, function() { + test('should return an array', 66, function() { var array = [1, 2, 3]; _.each(returnArrays, function(methodName) { From cb94b03e3efdf33d9295de87520755f04234a416 Mon Sep 17 00:00:00 2001 From: jdalton Date: Sat, 4 Jul 2015 14:56:49 -0700 Subject: [PATCH 014/935] Document more default params. [ci skip] --- lodash.src.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 057792706a..aef4caa9d9 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -456,7 +456,7 @@ * @private * @param {Object} object The object to compare. * @param {Object} other The other object to compare. - * @param {boolean[]} orders The order to sort by for each property. + * @param {boolean[]|string[]} orders The order to sort by for each property. * @returns {number} Returns the sort order indicator for `object`. */ function compareMultiple(object, other, orders) { @@ -5580,7 +5580,7 @@ * @category Array * @param {Array} array The array to inspect. * @param {boolean} [isSorted] Specify the array is sorted. - * @param {Function|Object|string} [iteratee] The function invoked per iteration. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. * @returns {Array} Returns the new duplicate-value-free array. * @example * @@ -5808,7 +5808,7 @@ * @memberOf _ * @category Array * @param {...Array} [arrays] The arrays to process. - * @param {Function} [iteratee] The function to combine grouped values. + * @param {Function} [iteratee=_.identity] The function to combine grouped values. * @returns {Array} Returns the new array of grouped elements. * @example * @@ -6883,8 +6883,8 @@ * @memberOf _ * @category Collection * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. - * @param {boolean[]} [orders] The sort orders of `iteratees`. + * @param {Function[]|Object[]|string[]} [iteratees=[_.identity]] The iteratees to sort by. + * @param {boolean[]|string[]} [orders] The sort orders of `iteratees`. * @param- {Object} [guard] Enables use as an iteratee for functions like `_.reduce`. * @returns {Array} Returns the new sorted array. * @example @@ -11300,7 +11300,7 @@ * @memberOf _ * @category Math * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [iteratee] The function invoked per iteration. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. * @returns {*} Returns the maximum value. * @example * @@ -11334,7 +11334,7 @@ * @memberOf _ * @category Math * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [iteratee] The function invoked per iteration. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. * @returns {*} Returns the minimum value. * @example * @@ -11387,7 +11387,7 @@ * @memberOf _ * @category Math * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [iteratee] The function invoked per iteration. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. * @param- {Object} [guard] Enables use as an iteratee for functions like `_.map`. * @returns {number} Returns the sum. * @example From 86b19f742cacbc5f9da394e3a0eda0e4b36f9d7a Mon Sep 17 00:00:00 2001 From: jdalton Date: Sun, 5 Jul 2015 10:19:52 -0700 Subject: [PATCH 015/935] Split `_.max` and `_.min` out into `_.maxBy` and `_.minBy`. --- lodash.src.js | 104 +++++++++++++++++++++++++++++++++-------------- test/test.js | 110 +++++++++++++++++++++----------------------------- 2 files changed, 121 insertions(+), 93 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index aef4caa9d9..980f21ff76 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -1987,7 +1987,7 @@ * @param {*} exValue The initial extremum value. * @returns {*} Returns the extremum value. */ - function baseExtremum(collection, iteratee, comparator, exValue) { + function baseExtremumBy(collection, iteratee, comparator, exValue) { var computed = exValue, result = computed; @@ -3302,11 +3302,24 @@ * Creates a `_.max` or `_.min` function. * * @private + * @param {Function} extremumBy The function used to get the extremum value. + * @returns {Function} Returns the new extremum function. + */ + function createExtremum(extremumBy) { + return function(collection) { + return extremumBy(collection, identity); + }; + } + + /** + * Creates a `_.maxBy` or `_.minBy` function. + * + * @private * @param {Function} comparator The function used to compare values. * @param {*} exValue The initial extremum value. * @returns {Function} Returns the new extremum function. */ - function createExtremum(comparator, exValue) { + function createExtremumBy(comparator, exValue) { return function(collection, iteratee, guard) { if (guard && isIterateeCall(collection, iteratee, guard)) { iteratee = undefined; @@ -3314,12 +3327,15 @@ iteratee = getIteratee(iteratee); if (iteratee.length == 1) { collection = isArray(collection) ? collection : toIterable(collection); + if (!collection.length) { + return exValue; + } var result = arrayExtremum(collection, iteratee, comparator, exValue); - if (!(collection.length && result === exValue)) { + if (result !== exValue) { return result; } } - return baseExtremum(collection, iteratee, comparator, exValue); + return baseExtremumBy(collection, iteratee, comparator, exValue); }; } @@ -11291,10 +11307,10 @@ var floor = createRound('floor'); /** - * Gets the maximum value of `collection`. If `collection` is empty or falsey - * `-Infinity` is returned. If an iteratee function is provided it's invoked - * for each value in `collection` to generate the criterion by which the value - * is ranked. The iteratee is invoked with three arguments: (value, index, collection). + * This method is like `_.max` except that it accepts an iteratee which is + * invoked for each value in `collection` to generate the criterion by which + * the value is ranked. The iteratee is invoked with three arguments: + * (value, index, collection). * * @static * @memberOf _ @@ -11304,59 +11320,85 @@ * @returns {*} Returns the maximum value. * @example * - * _.max([4, 2, 8, 6]); - * // => 8 - * - * _.max([]); - * // => -Infinity - * * var users = [ * { 'user': 'barney', 'age': 36 }, * { 'user': 'fred', 'age': 40 } * ]; * - * _.max(users, function(o) { return o.age; }); + * _.maxBy(users, function(o) { return o.age; }); * // => { 'user': 'fred', 'age': 40 } * * // using the `_.property` callback shorthand - * _.max(users, 'age'); + * _.maxBy(users, 'age'); * // => { 'user': 'fred', 'age': 40 } */ - var max = createExtremum(gt, NEGATIVE_INFINITY); + var maxBy = createExtremumBy(gt, NEGATIVE_INFINITY); /** - * Gets the minimum value of `collection`. If `collection` is empty or falsey - * `Infinity` is returned. If an iteratee function is provided it's invoked - * for each value in `collection` to generate the criterion by which the value - * is ranked. The iteratee is invoked with three arguments: (value, index, collection). + * Gets the maximum value of `collection`. If `collection` is empty or falsey + * `-Infinity` is returned. * * @static * @memberOf _ * @category Math * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. - * @returns {*} Returns the minimum value. + * @returns {*} Returns the maximum value. * @example * - * _.min([4, 2, 8, 6]); - * // => 2 + * _.max([4, 2, 8, 6]); + * // => 8 * - * _.min([]); - * // => Infinity + * _.max([]); + * // => -Infinity + */ + var max = createExtremum(maxBy); + + /** + * This method is like `_.min` except that it accepts an iteratee which is + * invoked for each value in `collection` to generate the criterion by which + * the value is ranked. The iteratee is invoked with three arguments: + * (value, index, collection). + * + * @static + * @memberOf _ + * @category Math + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. + * @returns {*} Returns the minimum value. + * @example * * var users = [ * { 'user': 'barney', 'age': 36 }, * { 'user': 'fred', 'age': 40 } * ]; * - * _.min(users, function(o) { return o.age; }); + * _.minBy(users, function(o) { return o.age; }); * // => { 'user': 'barney', 'age': 36 } * * // using the `_.property` callback shorthand - * _.min(users, 'age'); + * _.minBy(users, 'age'); * // => { 'user': 'barney', 'age': 36 } */ - var min = createExtremum(lt, POSITIVE_INFINITY); + var minBy = createExtremumBy(lt, POSITIVE_INFINITY); + + /** + * Gets the minimum value of `collection`. If `collection` is empty or falsey + * `Infinity` is returned. + * + * @static + * @memberOf _ + * @category Math + * @param {Array|Object|string} collection The collection to iterate over. + * @returns {*} Returns the minimum value. + * @example + * + * _.min([4, 2, 8, 6]); + * // => 2 + * + * _.min([]); + * // => Infinity + */ + var min = createExtremum(minBy); /** * Calculates `n` rounded to `precision`. @@ -11616,7 +11658,9 @@ lodash.lt = lt; lodash.lte = lte; lodash.max = max; + lodash.maxBy = maxBy; lodash.min = min; + lodash.minBy = minBy; lodash.noConflict = noConflict; lodash.noop = noop; lodash.now = now; diff --git a/test/test.js b/test/test.js index 075178d783..be4d9ec30e 100644 --- a/test/test.js +++ b/test/test.js @@ -4724,8 +4724,8 @@ 'map', 'mapKeys', 'mapValues', - 'max', - 'min', + 'maxBy', + 'minBy', 'omit', 'partition', 'pick', @@ -4750,8 +4750,8 @@ 'groupBy', 'indexBy', 'map', - 'max', - 'min', + 'maxBy', + 'minBy', 'partition', 'reduce', 'reduceRight', @@ -4813,7 +4813,9 @@ 'forOwn', 'forOwnRight', 'max', + 'maxBy', 'min', + 'minBy', 'some' ]; @@ -8607,10 +8609,10 @@ } }); - test('`_.max` should use `_.iteratee` internally', 1, function() { + test('`_.maxBy` should use `_.iteratee` internally', 1, function() { if (!isModularize) { _.iteratee = getPropB; - deepEqual(_.max(objects), objects[2]); + deepEqual(_.maxBy(objects), objects[2]); _.iteratee = iteratee; } else { @@ -8618,10 +8620,10 @@ } }); - test('`_.min` should use `_.iteratee` internally', 1, function() { + test('`_.minBy` should use `_.iteratee` internally', 1, function() { if (!isModularize) { _.iteratee = getPropB; - deepEqual(_.min(objects), objects[0]); + deepEqual(_.minBy(objects), objects[0]); _.iteratee = iteratee; } else { @@ -10833,10 +10835,10 @@ QUnit.module('extremum methods'); - _.each(['max', 'min'], function(methodName) { + _.each(['max', 'maxBy', 'min', 'minBy'], function(methodName) { var array = [1, 2, 3], func = _[methodName], - isMax = methodName == 'max'; + isMax = /^max/.test(methodName); test('`_.' + methodName + '` should work with Date objects', 1, function() { var curr = new Date, @@ -10845,38 +10847,48 @@ strictEqual(func([curr, past]), isMax ? curr : past); }); - test('`_.' + methodName + '` should work with an `iteratee` argument', 1, function() { - var actual = func(array, function(num) { - return -num; - }); + test('`_.' + methodName + '` should iterate an object', 1, function() { + var actual = func({ 'a': 1, 'b': 2, 'c': 3 }); + strictEqual(actual, isMax ? 3 : 1); + }); - strictEqual(actual, isMax ? 1 : 3); + test('`_.' + methodName + '` should work with extremely large arrays', 1, function() { + var array = _.range(0, 5e5); + strictEqual(func(array), isMax ? 499999 : 0); }); - test('`_.' + methodName + '` should provide the correct `iteratee` arguments when iterating an array', 1, function() { - var args; + test('`_.' + methodName + '` should work as an iteratee for methods like `_.map`', 2, function() { + var arrays = [[2, 1], [5, 4], [7, 8]], + objects = [{ 'a': 2, 'b': 1 }, { 'a': 5, 'b': 4 }, { 'a': 7, 'b': 8 }], + expected = isMax ? [2, 5, 8] : [1, 4, 7]; - func(array, function() { - args || (args = slice.call(arguments)); + _.each([arrays, objects], function(values) { + deepEqual(_.map(values, func), expected); }); - - deepEqual(args, [1, 0, array]); }); - test('`_.' + methodName + '` should provide the correct `iteratee` arguments when iterating an object', 1, function() { - var args, - object = { 'a': 1, 'b': 2 }, - firstKey = _.first(_.keys(object)); + test('`_.' + methodName + '` should work when chaining on an array with only one value', 1, function() { + if (!isNpm) { + var actual = _([40])[methodName](); + strictEqual(actual, 40); + } + else { + skipTest(); + } + }); + }); - var expected = firstKey == 'a' - ? [1, 'a', object] - : [2, 'b', object]; + _.each(['maxBy', 'minBy'], function(methodName) { + var array = [1, 2, 3], + func = _[methodName], + isMax = methodName == 'maxBy'; - func(object, function() { - args || (args = slice.call(arguments)); - }, 0); + test('`_.' + methodName + '` should work with an `iteratee` argument', 1, function() { + var actual = func(array, function(num) { + return -num; + }); - deepEqual(args, expected); + strictEqual(actual, isMax ? 1 : 3); }); test('should work with a "_.property" style `iteratee`', 2, function() { @@ -10901,36 +10913,6 @@ strictEqual(actual, object); }); - - test('`_.' + methodName + '` should iterate an object', 1, function() { - var actual = func({ 'a': 1, 'b': 2, 'c': 3 }); - strictEqual(actual, isMax ? 3 : 1); - }); - - test('`_.' + methodName + '` should work with extremely large arrays', 1, function() { - var array = _.range(0, 5e5); - strictEqual(func(array), isMax ? 499999 : 0); - }); - - test('`_.' + methodName + '` should work as an iteratee for methods like `_.map`', 2, function() { - var arrays = [[2, 1], [5, 4], [7, 8]], - objects = [{ 'a': 2, 'b': 1 }, { 'a': 5, 'b': 4 }, { 'a': 7, 'b': 8 }], - expected = isMax ? [2, 5, 8] : [1, 4, 7]; - - _.each([arrays, objects], function(values) { - deepEqual(_.map(values, func), expected); - }); - }); - - test('`_.' + methodName + '` should work when chaining on an array with only one value', 1, function() { - if (!isNpm) { - var actual = _([40])[methodName](); - strictEqual(actual, 40); - } - else { - skipTest(); - } - }); }); /*--------------------------------------------------------------------------*/ @@ -17318,7 +17300,9 @@ 'join', 'last', 'max', + 'maxBy', 'min', + 'minBy', 'parseInt', 'pop', 'shift', @@ -17531,7 +17515,7 @@ var acceptFalsey = _.difference(allMethods, rejectFalsey); - test('should accept falsey arguments', 205, function() { + test('should accept falsey arguments', 207, function() { var emptyArrays = _.map(falsey, _.constant([])); _.each(acceptFalsey, function(methodName) { From 10c44b08c93c886c942f1aa7b1e677cb9eb5fe18 Mon Sep 17 00:00:00 2001 From: jdalton Date: Sun, 5 Jul 2015 11:22:47 -0700 Subject: [PATCH 016/935] Reduce the number of function creator helpers to improve readabilty. --- lodash.src.js | 543 ++++++++++++++++++++------------------------------ 1 file changed, 213 insertions(+), 330 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 980f21ff76..da6cd435f6 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -2475,52 +2475,6 @@ }; } - /** - * The base implementation of `_.merge` without support for argument juggling, - * multiple sources, and `this` binding `customizer` functions. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @param {Function} [customizer] The function to customize merged values. - * @param {Array} [stackA=[]] Tracks traversed source objects. - * @param {Array} [stackB=[]] Associates values with source counterparts. - * @returns {Object} Returns `object`. - */ - function baseMerge(object, source, customizer, stackA, stackB) { - if (!isObject(object)) { - return object; - } - var isSrcArr = isArrayLike(source) && (isArray(source) || isTypedArray(source)), - props = isSrcArr ? undefined : keys(source); - - arrayEach(props || source, function(srcValue, key) { - if (props) { - key = srcValue; - srcValue = source[key]; - } - if (isObjectLike(srcValue)) { - stackA || (stackA = []); - stackB || (stackB = []); - baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB); - } - else { - var value = object[key], - result = customizer ? customizer(value, srcValue, key, object, source) : undefined, - isCommon = result === undefined; - - if (isCommon) { - result = srcValue; - } - if ((result !== undefined || (isSrcArr && !(key in object))) && - (isCommon || (result === result ? (result !== value) : (value === value)))) { - object[key] = result; - } - } - }); - return object; - } - /** * A specialized version of `baseMerge` for arrays and objects which performs * deep merges and tracks traversed objects enabling objects with circular @@ -3097,7 +3051,7 @@ } /** - * Creates a `_.assign`, `_.defaults`, or `_.merge` function. + * Creates a `_.assign` or `_.merge` function. * * @private * @param {Function} assigner The function to assign values. @@ -3206,8 +3160,7 @@ } /** - * Creates a function that produces compound words out of the words in a - * given string. + * Creates a `_.camelCase`, `_.kebabCase`, `_.snakeCase`, or `_.startCase` function. * * @private * @param {Function} callback The function to combine each word. @@ -3260,57 +3213,6 @@ }; } - /** - * Creates a `_.curry` or `_.curryRight` function. - * - * @private - * @param {boolean} flag The curry bit flag. - * @returns {Function} Returns the new curry function. - */ - function createCurry(flag) { - function curryFunc(func, arity, guard) { - if (guard && isIterateeCall(func, arity, guard)) { - arity = undefined; - } - var result = createWrapper(func, flag, undefined, undefined, undefined, undefined, undefined, arity); - result.placeholder = curryFunc.placeholder; - return result; - } - return curryFunc; - } - - /** - * Creates a `_.defaults` or `_.defaultsDeep` function. - * - * @private - * @param {Function} assigner The function to assign values. - * @param {Function} customizer The function to customize assigned values. - * @returns {Function} Returns the new defaults function. - */ - function createDefaults(assigner, customizer) { - return restParam(function(args) { - var object = args[0]; - if (object == null) { - return object; - } - args.push(customizer); - return assigner.apply(undefined, args); - }); - } - - /** - * Creates a `_.max` or `_.min` function. - * - * @private - * @param {Function} extremumBy The function used to get the extremum value. - * @returns {Function} Returns the new extremum function. - */ - function createExtremum(extremumBy) { - return function(collection) { - return extremumBy(collection, identity); - }; - } - /** * Creates a `_.maxBy` or `_.minBy` function. * @@ -3339,56 +3241,6 @@ }; } - /** - * Creates a `_.find` or `_.findLast` function. - * - * @private - * @param {Function} eachFunc The function to iterate over a collection. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new find function. - */ - function createFind(eachFunc, fromRight) { - return function(collection, predicate) { - predicate = getIteratee(predicate); - if (isArray(collection)) { - var index = baseFindIndex(collection, predicate, fromRight); - return index > -1 ? collection[index] : undefined; - } - return baseFind(collection, predicate, eachFunc); - }; - } - - /** - * Creates a `_.findIndex` or `_.findLastIndex` function. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new find function. - */ - function createFindIndex(fromRight) { - return function(array, predicate) { - if (!(array && array.length)) { - return -1; - } - predicate = getIteratee(predicate); - return baseFindIndex(array, predicate, fromRight); - }; - } - - /** - * Creates a `_.findKey` or `_.findLastKey` function. - * - * @private - * @param {Function} objectFunc The function to iterate over an object. - * @returns {Function} Returns the new find function. - */ - function createFindKey(objectFunc) { - return function(object, predicate) { - predicate = getIteratee(predicate); - return baseFind(object, predicate, objectFunc, true); - }; - } - /** * Creates a `_.flow` or `_.flowRight` function. * @@ -3444,116 +3296,6 @@ }; } - /** - * Creates a function for `_.forEach` or `_.forEachRight`. - * - * @private - * @param {Function} arrayFunc The function to iterate over an array. - * @param {Function} eachFunc The function to iterate over a collection. - * @returns {Function} Returns the new each function. - */ - function createForEach(arrayFunc, eachFunc) { - return function(collection, iteratee) { - return (typeof iteratee == 'function' && isArray(collection)) - ? arrayFunc(collection, iteratee) - : eachFunc(collection, toFunction(iteratee)); - }; - } - - /** - * Creates a function for `_.forIn` or `_.forInRight`. - * - * @private - * @param {Function} objectFunc The function to iterate over an object. - * @returns {Function} Returns the new each function. - */ - function createForIn(objectFunc) { - return function(object, iteratee) { - return objectFunc(object, toFunction(iteratee), keysIn); - }; - } - - /** - * Creates a function for `_.forOwn` or `_.forOwnRight`. - * - * @private - * @param {Function} objectFunc The function to iterate over an object. - * @returns {Function} Returns the new each function. - */ - function createForOwn(objectFunc) { - return function(object, iteratee) { - return objectFunc(object, toFunction(iteratee)); - }; - } - - /** - * Creates a function for `_.mapKeys` or `_.mapValues`. - * - * @private - * @param {boolean} [isMapKeys] Specify mapping keys instead of values. - * @returns {Function} Returns the new map function. - */ - function createObjectMapper(isMapKeys) { - return function(object, iteratee) { - var result = {}; - iteratee = getIteratee(iteratee); - - baseForOwn(object, function(value, key, object) { - var mapped = iteratee(value, key, object); - key = isMapKeys ? mapped : key; - value = isMapKeys ? value : mapped; - result[key] = value; - }); - return result; - }; - } - - /** - * Creates a function for `_.padLeft` or `_.padRight`. - * - * @private - * @param {boolean} [fromRight] Specify padding from the right. - * @returns {Function} Returns the new pad function. - */ - function createPadDir(fromRight) { - return function(string, length, chars) { - string = baseToString(string); - return (fromRight ? string : '') + createPadding(string, length, chars) + (fromRight ? '' : string); - }; - } - - /** - * Creates a `_.partial` or `_.partialRight` function. - * - * @private - * @param {boolean} flag The partial bit flag. - * @returns {Function} Returns the new partial function. - */ - function createPartial(flag) { - var partialFunc = restParam(function(func, partials) { - var holders = replaceHolders(partials, partialFunc.placeholder); - return createWrapper(func, flag, undefined, partials, holders); - }); - return partialFunc; - } - - /** - * Creates a function for `_.reduce` or `_.reduceRight`. - * - * @private - * @param {Function} arrayFunc The function to iterate over an array. - * @param {Function} eachFunc The function to iterate over a collection. - * @returns {Function} Returns the new each function. - */ - function createReduce(arrayFunc, eachFunc) { - return function(collection, iteratee, accumulator) { - var initFromArray = arguments.length < 3; - return (typeof iteratee == 'function' && isArray(collection)) - ? arrayFunc(collection, iteratee, accumulator, initFromArray) - : baseReduce(collection, getIteratee(iteratee), accumulator, initFromArray, eachFunc); - }; - } - /** * Creates a function that wraps `func` and invokes it with optional `this` * binding of, partial application, and currying. @@ -3720,22 +3462,6 @@ }; } - /** - * Creates a `_.sortedIndex` or `_.sortedLastIndex` function. - * - * @private - * @param {boolean} [retHighest] Specify returning the highest qualified index. - * @returns {Function} Returns the new index function. - */ - function createSortedIndex(retHighest) { - return function(array, value, iteratee) { - var toIteratee = getIteratee(); - return (iteratee == null && toIteratee === baseIteratee) - ? binaryIndex(array, value, retHighest) - : binaryIndexBy(array, value, toIteratee(iteratee), retHighest); - }; - } - /** * Creates a function that either curries or invokes `func` with optional * `this` binding and partially applied arguments. @@ -4899,7 +4625,11 @@ * _.findIndex(users, 'active'); * // => 2 */ - var findIndex = createFindIndex(); + function findIndex(array, predicate) { + return (array && array.length) + ? baseFindIndex(array, getIteratee(predicate)) + : -1; + } /** * This method is like `_.findIndex` except that it iterates over elements @@ -4934,7 +4664,11 @@ * _.findLastIndex(users, 'active'); * // => 0 */ - var findLastIndex = createFindIndex(true); + function findLastIndex(array, predicate) { + return (array && array.length) + ? baseFindIndex(array, getIteratee(predicate), true) + : -1; + } /** * Gets the first element of `array`. @@ -5386,7 +5120,12 @@ * _.sortedIndex([{ 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x'); * // => 1 */ - var sortedIndex = createSortedIndex(); + function sortedIndex(array, value, iteratee) { + var toIteratee = getIteratee(); + return (iteratee == null && toIteratee === baseIteratee) + ? binaryIndex(array, value) + : binaryIndexBy(array, value, toIteratee(iteratee)); + } /** * This method is like `_.sortedIndex` except that it returns the highest @@ -5405,7 +5144,12 @@ * _.sortedLastIndex([4, 4, 5, 5], 5); * // => 4 */ - var sortedLastIndex = createSortedIndex(true); + function sortedLastIndex(array, value, iteratee) { + var toIteratee = getIteratee(); + return (iteratee == null && toIteratee === baseIteratee) + ? binaryIndex(array, value, true) + : binaryIndexBy(array, value, toIteratee(iteratee), true); + } /** * Creates a slice of `array` with `n` elements taken from the beginning. @@ -6302,7 +6046,14 @@ * resolve( _.find(users, 'active') ); * // => 'barney' */ - var find = createFind(baseEach); + function find(collection, predicate) { + predicate = getIteratee(predicate); + if (isArray(collection)) { + var index = baseFindIndex(collection, predicate); + return index > -1 ? collection[index] : undefined; + } + return baseFind(collection, predicate, baseEach); + } /** * This method is like `_.find` except that it iterates over elements of @@ -6321,7 +6072,14 @@ * }); * // => 3 */ - var findLast = createFind(baseEachRight, true); + function findLast(collection, predicate) { + predicate = getIteratee(predicate); + if (isArray(collection)) { + var index = baseFindIndex(collection, predicate, true); + return index > -1 ? collection[index] : undefined; + } + return baseFind(collection, predicate, baseEachRight); + } /** * Iterates over elements of `collection` invoking `iteratee` for each element. @@ -6351,7 +6109,11 @@ * }); * // => logs each value-key pair and returns the object (iteration order is not guaranteed) */ - var forEach = createForEach(arrayEach, baseEach); + function forEach(collection, iteratee) { + return (typeof iteratee == 'function' && isArray(collection)) + ? arrayEach(collection, iteratee) + : baseEach(collection, toFunction(iteratee)); + } /** * This method is like `_.forEach` except that it iterates over elements of @@ -6371,7 +6133,11 @@ * }); * // => logs each value from right to left and returns the array */ - var forEachRight = createForEach(arrayEachRight, baseEachRight); + function forEachRight(collection, iteratee) { + return (typeof iteratee == 'function' && isArray(collection)) + ? arrayEachRight(collection, iteratee) + : baseEachRight(collection, toFunction(iteratee)); + } /** * Creates an object composed of keys generated from the results of running @@ -6642,7 +6408,12 @@ * }, {}); * // => { 'a': 3, 'b': 6 } (iteration order is not guaranteed) */ - var reduce = createReduce(arrayReduce, baseEach); + function reduce(collection, iteratee, accumulator) { + var initFromArray = arguments.length < 3; + return (typeof iteratee == 'function' && isArray(collection)) + ? arrayReduce(collection, iteratee, accumulator, initFromArray) + : baseReduce(collection, getIteratee(iteratee), accumulator, initFromArray, baseEach); + } /** * This method is like `_.reduce` except that it iterates over elements of @@ -6665,7 +6436,12 @@ * }, []); * // => [4, 5, 2, 3, 0, 1] */ - var reduceRight = createReduce(arrayReduceRight, baseEachRight); + function reduceRight(collection, iteratee, accumulator) { + var initFromArray = arguments.length < 3; + return (typeof iteratee == 'function' && isArray(collection)) + ? arrayReduceRight(collection, iteratee, accumulator, initFromArray) + : baseReduce(collection, getIteratee(iteratee), accumulator, initFromArray, baseEachRight); + } /** * The opposite of `_.filter`; this method returns the elements of `collection` @@ -7237,7 +7013,14 @@ * curried(1)(_, 3)(2); * // => [1, 2, 3] */ - var curry = createCurry(CURRY_FLAG); + function curry(func, arity, guard) { + if (guard && isIterateeCall(func, arity, guard)) { + arity = undefined; + } + var result = createWrapper(func, CURRY_FLAG, undefined, undefined, undefined, undefined, undefined, arity); + result.placeholder = curry.placeholder; + return result; + } /** * This method is like `_.curry` except that arguments are applied to `func` @@ -7276,7 +7059,14 @@ * curried(3)(1, _)(2); * // => [1, 2, 3] */ - var curryRight = createCurry(CURRY_RIGHT_FLAG); + function curryRight(func, arity, guard) { + if (guard && isIterateeCall(func, arity, guard)) { + arity = undefined; + } + var result = createWrapper(func, CURRY_RIGHT_FLAG, undefined, undefined, undefined, undefined, undefined, arity); + result.placeholder = curryRight.placeholder; + return result; + } /** * Creates a debounced function that delays invoking `func` until after `wait` @@ -7734,7 +7524,10 @@ * greetFred('hi'); * // => 'hi fred' */ - var partial = createPartial(PARTIAL_FLAG); + var partial = restParam(function(func, partials) { + var holders = replaceHolders(partials, partial.placeholder); + return createWrapper(func, PARTIAL_FLAG, undefined, partials, holders); + }); /** * This method is like `_.partial` except that partially applied arguments @@ -7767,7 +7560,10 @@ * sayHelloTo('fred'); * // => 'hello fred' */ - var partialRight = createPartial(PARTIAL_RIGHT_FLAG); + var partialRight = restParam(function(func, partials) { + var holders = replaceHolders(partials, partialRight.placeholder); + return createWrapper(func, PARTIAL_RIGHT_FLAG, undefined, partials, holders); + }); /** * Creates a function that invokes `func` with arguments arranged according @@ -8862,7 +8658,39 @@ * }); * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] } */ - var merge = createAssigner(baseMerge); + var merge = createAssigner(function baseMerge(object, source, customizer, stackA, stackB) { + if (!isObject(object)) { + return object; + } + var isSrcArr = isArrayLike(source) && (isArray(source) || isTypedArray(source)), + props = isSrcArr ? undefined : keys(source); + + arrayEach(props || source, function(srcValue, key) { + if (props) { + key = srcValue; + srcValue = source[key]; + } + if (isObjectLike(srcValue)) { + stackA || (stackA = []); + stackB || (stackB = []); + baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB); + } + else { + var value = object[key], + result = customizer ? customizer(value, srcValue, key, object, source) : undefined, + isCommon = result === undefined; + + if (isCommon) { + result = srcValue; + } + if ((result !== undefined || (isSrcArr && !(key in object))) && + (isCommon || (result === result ? (result !== value) : (value === value)))) { + object[key] = result; + } + } + }); + return object; + }); /** * Assigns own enumerable properties of source object(s) to the destination @@ -8961,7 +8789,14 @@ * _.defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' }); * // => { 'user': 'barney', 'age': 36 } */ - var defaults = createDefaults(assign, assignDefaults); + var defaults = restParam(function(args) { + var object = args[0]; + if (object == null) { + return object; + } + args.push(assignDefaults); + return assign.apply(undefined, args); + }); /** * This method is like `_.defaults` except that it recursively assigns @@ -8981,7 +8816,14 @@ * // => { 'user': { 'name': 'barney', 'age': 36 } } * */ - var defaultsDeep = createDefaults(merge, mergeDefaults); + var defaultsDeep = restParam(function(args) { + var object = args[0]; + if (object == null) { + return object; + } + args.push(mergeDefaults); + return merge.apply(undefined, args); + }); /** * This method is like `_.find` except that it returns the key of the first @@ -9016,7 +8858,10 @@ * _.findKey(users, 'active'); * // => 'barney' */ - var findKey = createFindKey(baseForOwn); + function findKey(object, predicate) { + predicate = getIteratee(predicate); + return baseFind(object, predicate, baseForOwn, true); + } /** * This method is like `_.findKey` except that it iterates over elements of @@ -9051,7 +8896,10 @@ * _.findLastKey(users, 'active'); * // => 'pebbles' */ - var findLastKey = createFindKey(baseForOwnRight); + function findLastKey(object, predicate) { + predicate = getIteratee(predicate); + return baseFind(object, predicate, baseForOwnRight, true); + } /** * Iterates over own and inherited enumerable properties of an object invoking @@ -9079,7 +8927,9 @@ * }); * // => logs 'a', 'b', and 'c' (iteration order is not guaranteed) */ - var forIn = createForIn(baseFor); + function forIn(object, iteratee) { + return baseFor(object, toFunction(iteratee), keysIn); + } /** * This method is like `_.forIn` except that it iterates over properties of @@ -9105,7 +8955,9 @@ * }); * // => logs 'c', 'b', and 'a' assuming `_.forIn ` logs 'a', 'b', and 'c' */ - var forInRight = createForIn(baseForRight); + function forInRight(object, iteratee) { + return baseForRight(object, toFunction(iteratee), keysIn); + } /** * Iterates over own enumerable properties of an object invoking `iteratee` @@ -9133,7 +8985,9 @@ * }); * // => logs 'a' and 'b' (iteration order is not guaranteed) */ - var forOwn = createForOwn(baseForOwn); + function forOwn(object, iteratee) { + return baseForOwn(object, toFunction(iteratee)); + } /** * This method is like `_.forOwn` except that it iterates over properties of @@ -9159,7 +9013,10 @@ * }); * // => logs 'b' and 'a' assuming `_.forOwn` logs 'a' and 'b' */ - var forOwnRight = createForOwn(baseForOwnRight); + function forOwnRight(object, iteratee) { + return baseForOwnRight(object, toFunction(iteratee)); + } + /** * Creates an array of function property names from all enumerable properties, @@ -9432,7 +9289,15 @@ * }); * // => { 'a1': 1, 'b2': 2 } */ - var mapKeys = createObjectMapper(true); + function mapKeys(object, iteratee) { + var result = {}; + iteratee = getIteratee(iteratee); + + baseForOwn(object, function(value, key, object) { + result[iteratee(value, key, object)] = value; + }); + return result; + } /** * Creates an object with the same keys as `object` and values generated by @@ -9459,7 +9324,15 @@ * _.mapValues(users, 'age'); * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) */ - var mapValues = createObjectMapper(); + function mapValues(object, iteratee) { + var result = {}; + iteratee = getIteratee(iteratee); + + baseForOwn(object, function(value, key, object) { + result[key] = iteratee(value, key, object); + }); + return result; + } /** * The opposite of `_.pick`; this method creates an object composed of the @@ -10103,7 +9976,10 @@ * _.padLeft('abc', 3); * // => 'abc' */ - var padLeft = createPadDir(); + function padLeft(string, length, chars) { + string = baseToString(string); + return createPadding(string, length, chars) + string; + } /** * Pads `string` on the right side if it's shorter than `length`. Padding @@ -10127,7 +10003,10 @@ * _.padRight('abc', 3); * // => 'abc' */ - var padRight = createPadDir(true); + function padRight(string, length, chars) { + string = baseToString(string); + return string + createPadding(string, length, chars); + } /** * Converts `string` to an integer of the specified radix. If `radix` is @@ -11306,6 +11185,27 @@ */ var floor = createRound('floor'); + /** + * Gets the maximum value of `collection`. If `collection` is empty or falsey + * `-Infinity` is returned. + * + * @static + * @memberOf _ + * @category Math + * @param {Array|Object|string} collection The collection to iterate over. + * @returns {*} Returns the maximum value. + * @example + * + * _.max([4, 2, 8, 6]); + * // => 8 + * + * _.max([]); + * // => -Infinity + */ + function max(collection) { + return maxBy(collection, identity); + } + /** * This method is like `_.max` except that it accepts an iteratee which is * invoked for each value in `collection` to generate the criterion by which @@ -11335,23 +11235,25 @@ var maxBy = createExtremumBy(gt, NEGATIVE_INFINITY); /** - * Gets the maximum value of `collection`. If `collection` is empty or falsey - * `-Infinity` is returned. + * Gets the minimum value of `collection`. If `collection` is empty or falsey + * `Infinity` is returned. * * @static * @memberOf _ * @category Math * @param {Array|Object|string} collection The collection to iterate over. - * @returns {*} Returns the maximum value. + * @returns {*} Returns the minimum value. * @example * - * _.max([4, 2, 8, 6]); - * // => 8 + * _.min([4, 2, 8, 6]); + * // => 2 * - * _.max([]); - * // => -Infinity + * _.min([]); + * // => Infinity */ - var max = createExtremum(maxBy); + function min(collection) { + return minBy(collection, identity); + } /** * This method is like `_.min` except that it accepts an iteratee which is @@ -11381,25 +11283,6 @@ */ var minBy = createExtremumBy(lt, POSITIVE_INFINITY); - /** - * Gets the minimum value of `collection`. If `collection` is empty or falsey - * `Infinity` is returned. - * - * @static - * @memberOf _ - * @category Math - * @param {Array|Object|string} collection The collection to iterate over. - * @returns {*} Returns the minimum value. - * @example - * - * _.min([4, 2, 8, 6]); - * // => 2 - * - * _.min([]); - * // => Infinity - */ - var min = createExtremum(minBy); - /** * Calculates `n` rounded to `precision`. * From 9a9e4cddd7561131a2a2ec2ed8d5b9c5318070b9 Mon Sep 17 00:00:00 2001 From: jdalton Date: Sun, 5 Jul 2015 11:25:00 -0700 Subject: [PATCH 017/935] Rename `baseExtremumBy` and `createExtremumBy` helpers. --- lodash.src.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index da6cd435f6..537399ad68 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -1987,7 +1987,7 @@ * @param {*} exValue The initial extremum value. * @returns {*} Returns the extremum value. */ - function baseExtremumBy(collection, iteratee, comparator, exValue) { + function baseExtremum(collection, iteratee, comparator, exValue) { var computed = exValue, result = computed; @@ -3221,7 +3221,7 @@ * @param {*} exValue The initial extremum value. * @returns {Function} Returns the new extremum function. */ - function createExtremumBy(comparator, exValue) { + function createExtremum(comparator, exValue) { return function(collection, iteratee, guard) { if (guard && isIterateeCall(collection, iteratee, guard)) { iteratee = undefined; @@ -3237,7 +3237,7 @@ return result; } } - return baseExtremumBy(collection, iteratee, comparator, exValue); + return baseExtremum(collection, iteratee, comparator, exValue); }; } @@ -11232,7 +11232,7 @@ * _.maxBy(users, 'age'); * // => { 'user': 'fred', 'age': 40 } */ - var maxBy = createExtremumBy(gt, NEGATIVE_INFINITY); + var maxBy = createExtremum(gt, NEGATIVE_INFINITY); /** * Gets the minimum value of `collection`. If `collection` is empty or falsey @@ -11281,7 +11281,7 @@ * _.minBy(users, 'age'); * // => { 'user': 'barney', 'age': 36 } */ - var minBy = createExtremumBy(lt, POSITIVE_INFINITY); + var minBy = createExtremum(lt, POSITIVE_INFINITY); /** * Calculates `n` rounded to `precision`. From abd67d078606ab8c369b89237a4d8831a1506239 Mon Sep 17 00:00:00 2001 From: jdalton Date: Sun, 5 Jul 2015 16:45:54 -0700 Subject: [PATCH 018/935] Remove alias jsdoc tags for those no longer supported. [ci skip] --- lodash.src.js | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 537399ad68..0720007dda 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -4675,7 +4675,6 @@ * * @static * @memberOf _ - * @alias head * @category Array * @param {Array} array The array to query. * @returns {*} Returns the first element of `array`. @@ -5049,7 +5048,6 @@ * * @static * @memberOf _ - * @alias tail * @category Array * @param {Array} array The array to query. * @returns {Array} Returns the slice of `array`. @@ -5527,7 +5525,6 @@ * * @static * @memberOf _ - * @alias object * @category Array * @param {Array} props The property names. * @param {Array} [values=[]] The property values. @@ -5928,7 +5925,6 @@ * * @static * @memberOf _ - * @alias all * @category Collection * @param {Array|Object|string} collection The collection to iterate over. * @param {Function|Object|string} [predicate=_.identity] The function invoked per iteration. @@ -5974,7 +5970,6 @@ * * @static * @memberOf _ - * @alias select * @category Collection * @param {Array|Object|string} collection The collection to iterate over. * @param {Function|Object|string} [predicate=_.identity] The function invoked per iteration. @@ -6016,7 +6011,6 @@ * * @static * @memberOf _ - * @alias detect * @category Collection * @param {Array|Object|string} collection The collection to search. * @param {Function|Object|string} [predicate=_.identity] The function invoked per iteration. @@ -6178,7 +6172,6 @@ * * @static * @memberOf _ - * @alias contains, include * @category Collection * @param {Array|Object|string} collection The collection to search. * @param {*} target The value to search for. @@ -6297,7 +6290,6 @@ * * @static * @memberOf _ - * @alias collect * @category Collection * @param {Array|Object|string} collection The collection to iterate over. * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. @@ -6389,7 +6381,6 @@ * * @static * @memberOf _ - * @alias foldl, inject * @category Collection * @param {Array|Object|string} collection The collection to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. @@ -6421,7 +6412,6 @@ * * @static * @memberOf _ - * @alias foldr * @category Collection * @param {Array|Object|string} collection The collection to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. @@ -6577,7 +6567,6 @@ * * @static * @memberOf _ - * @alias any * @category Collection * @param {Array|Object|string} collection The collection to iterate over. * @param {Function|Object|string} [predicate=_.identity] The function invoked per iteration. @@ -7310,7 +7299,6 @@ * * @static * @memberOf _ - * @alias backflow, compose * @category Function * @param {...Function} [funcs] Functions to invoke. * @returns {Function} Returns the new function. @@ -8704,7 +8692,6 @@ * * @static * @memberOf _ - * @alias extend * @category Object * @param {Object} object The destination object. * @param {...Object} [sources] The source objects. @@ -9024,7 +9011,6 @@ * * @static * @memberOf _ - * @alias methods * @category Object * @param {Object} object The object to inspect. * @returns {Array} Returns the new array of property names. @@ -10678,7 +10664,6 @@ * * @static * @memberOf _ - * @alias iteratee * @category Utility * @param {*} [func=_.identity] The value to convert to a callback. * @returns {Function} Returns the callback. From 8ac1a67b7df3cb1e577058f51bd3fb13032c8255 Mon Sep 17 00:00:00 2001 From: jdalton Date: Sun, 5 Jul 2015 16:44:34 -0700 Subject: [PATCH 019/935] Split `_.uniq` out into `_.uniqBy`. --- lodash.src.js | 41 ++++++++++---- test/test.js | 151 +++++++++++++++++++++++++++++--------------------- 2 files changed, 118 insertions(+), 74 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 0720007dda..bd7157a1bb 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -5328,18 +5328,14 @@ * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) * for equality comparisons, in which only the first occurence of each element * is kept. Providing `true` for `isSorted` performs a faster search algorithm - * for sorted arrays. If an iteratee function is provided it's invoked for - * each element in the array to generate the criterion by which uniqueness - * is computed. The iteratee is invoked with three arguments: (value, index, array). + * for sorted arrays. * * @static * @memberOf _ - * @alias unique * @category Array * @param {Array} array The array to inspect. * @param {boolean} [isSorted] Specify the array is sorted. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. - * @returns {Array} Returns the new duplicate-value-free array. + * @returns {Array} Returns the new duplicate free array. * @example * * _.uniq([2, 1, 2]); @@ -5348,18 +5344,42 @@ * // using `isSorted` * _.uniq([1, 1, 2], true); * // => [1, 2] + */ + function uniq(array, isSorted) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + return (isSorted && typeof isSorted == 'boolean' && getIndexOf() == baseIndexOf) + ? sortedUniq(array) + : baseUniq(array); + } + + /** + * This method is like `_.uniq` except that it accepts an iteratee which is + * invoked for each value in `array` to generate the criterion by which + * uniqueness is computed. The iteratee is invoked with three arguments: + * (value, index, array). * - * // using an iteratee function - * _.uniq([1, 2.5, 1.5, 2], function(n) { + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to inspect. + * @param {boolean} [isSorted] Specify the array is sorted. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.uniqBy([1, 2.5, 1.5, 2], function(n) { * return Math.floor(n); * }); * // => [1, 2.5] * * // using the `_.property` callback shorthand - * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); + * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); * // => [{ 'x': 1 }, { 'x': 2 }] */ - function uniq(array, isSorted, iteratee) { + function uniqBy(array, isSorted, iteratee) { var length = array ? array.length : 0; if (!length) { return []; @@ -11444,6 +11464,7 @@ lodash.transform = transform; lodash.union = union; lodash.uniq = uniq; + lodash.uniqBy = uniqBy; lodash.unzip = unzip; lodash.unzipWith = unzipWith; lodash.values = values; diff --git a/test/test.js b/test/test.js index be4d9ec30e..326341a1fe 100644 --- a/test/test.js +++ b/test/test.js @@ -5963,8 +5963,8 @@ } }); - test('`_.uniq` should work with a custom `_.indexOf` method', 6, function() { - _.each([false, true, _.identity], function(param) { + test('`_.uniq` should work with a custom `_.indexOf` method', 4, function() { + _.each([false, true], function(param) { if (!isModularize) { _.indexOf = custom; deepEqual(_.uniq(array, param), array.slice(0, 3)); @@ -5976,6 +5976,20 @@ } }); }); + + test('`_.uniqBy` should work with a custom `_.indexOf` method', 6, function() { + _.each([[false, _.identity], [true, _.identity], [_.identity]], function(params) { + if (!isModularize) { + _.indexOf = custom; + deepEqual(_.uniqBy.apply(_, [array].concat(params)), array.slice(0, 3)); + deepEqual(_.uniqBy.apply(_, [largeArray].concat(params)), [largeArray[0]]); + _.indexOf = indexOf; + } + else { + skipTest(2); + } + }); + }); }()); /*--------------------------------------------------------------------------*/ @@ -8790,10 +8804,10 @@ } }); - test('`_.uniq` should use `_.iteratee` internally', 1, function() { + test('`_.uniqBy` should use `_.iteratee` internally', 1, function() { if (!isModularize) { _.iteratee = getPropB; - deepEqual(_.uniq(objects), [objects[0], objects[2]]); + deepEqual(_.uniqBy(objects), [objects[0], objects[2]]); _.iteratee = iteratee; } else { @@ -13831,7 +13845,7 @@ return _.shuffle([1, 2]); }); - deepEqual(_.sortBy(_.uniq(actual, String), '0'), [[1, 2], [2, 1]]); + deepEqual(_.sortBy(_.uniqBy(actual, String), '0'), [[1, 2], [2, 1]]); }); test('should treat number values for `collection` as empty', 1, function() { @@ -16077,42 +16091,17 @@ /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.uniq'); + QUnit.module('lodash.uniqBy'); (function() { var objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }, { 'a': 2 }, { 'a': 3 }, { 'a': 1 }]; - test('should return unique values of an unsorted array', 1, function() { - var array = [2, 3, 1, 2, 3, 1]; - deepEqual(_.uniq(array), [2, 3, 1]); - }); - - test('should return unique values of a sorted array', 1, function() { - var array = [1, 1, 2, 2, 3]; - deepEqual(_.uniq(array), [1, 2, 3]); - }); - - test('should treat object instances as unique', 1, function() { - deepEqual(_.uniq(objects), objects); - }); - - test('should not treat `NaN` as unique', 1, function() { - deepEqual(_.uniq([1, NaN, 3, NaN]), [1, NaN, 3]); - }); - - test('should work with `isSorted`', 3, function() { - var expected = [1, 2, 3]; - deepEqual(_.uniq([1, 2, 3], true), expected); - deepEqual(_.uniq([1, 1, 2, 2, 3], true), expected); - deepEqual(_.uniq([1, 2, 3, 3, 3, 3, 3], true), expected); - }); - test('should work with an `iteratee` argument', 2, function() { _.each([objects, _.sortBy(objects, 'a')], function(array, index) { var isSorted = !!index, expected = isSorted ? [objects[2], objects[0], objects[1]] : objects.slice(0, 3); - var actual = _.uniq(array, isSorted, function(object) { + var actual = _.uniqBy(array, isSorted, function(object) { return object.a; }); @@ -16123,7 +16112,7 @@ test('should provide the correct `iteratee` arguments', 1, function() { var args; - _.uniq(objects, function() { + _.uniqBy(objects, function() { args || (args = slice.call(arguments)); }); @@ -16131,7 +16120,7 @@ }); test('should work with `iteratee` without specifying `isSorted`', 1, function() { - var actual = _.uniq(objects, function(object) { + var actual = _.uniqBy(objects, function(object) { return object.a; }); @@ -16139,24 +16128,71 @@ }); test('should work with a "_.property" style `iteratee`', 2, function() { - var actual = _.uniq(objects, 'a'); + var actual = _.uniqBy(objects, 'a'); deepEqual(actual, objects.slice(0, 3)); var arrays = [[2], [3], [1], [2], [3], [1]]; - actual = _.uniq(arrays, 0); + actual = _.uniqBy(arrays, 0); deepEqual(actual, arrays.slice(0, 3)); }); - test('should perform an unsorted uniq when used as an iteratee for methods like `_.map`', 1, function() { + _.each({ + 'an array': [0, 'a'], + 'an object': { '0': 'a' }, + 'a number': 0, + 'a string': '0' + }, + function(iteratee, key) { + test('should work with ' + key + ' for `iteratee`', 1, function() { + var actual = _.uniqBy([['a'], ['b'], ['a']], iteratee); + deepEqual(actual, [['a'], ['b']]); + }); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('uniq methods'); + + _.each(['uniq', 'uniqBy'], function(methodName) { + var func = _[methodName], + objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }, { 'a': 2 }, { 'a': 3 }, { 'a': 1 }]; + + test('`_.' + methodName + '` should return unique values of an unsorted array', 1, function() { + var array = [2, 3, 1, 2, 3, 1]; + deepEqual(func(array), [2, 3, 1]); + }); + + test('`_.' + methodName + '` should return unique values of a sorted array', 1, function() { + var array = [1, 1, 2, 2, 3]; + deepEqual(func(array), [1, 2, 3]); + }); + + test('`_.' + methodName + '` should treat object instances as unique', 1, function() { + deepEqual(func(objects), objects); + }); + + test('`_.' + methodName + '` should not treat `NaN` as unique', 1, function() { + deepEqual(func([1, NaN, 3, NaN]), [1, NaN, 3]); + }); + + test('`_.' + methodName + '` should work with `isSorted`', 3, function() { + var expected = [1, 2, 3]; + deepEqual(func([1, 2, 3], true), expected); + deepEqual(func([1, 1, 2, 2, 3], true), expected); + deepEqual(func([1, 2, 3, 3, 3, 3, 3], true), expected); + }); + + test('`_.' + methodName + '` should perform an unsorted uniq when used as an iteratee for methods like `_.map`', 1, function() { var array = [[2, 1, 2], [1, 2, 1]], - actual = _.map(array, _.uniq); + actual = _.map(array, func); deepEqual(actual, [[2, 1], [1, 2]]); }); - test('should work with large arrays', 1, function() { + test('`_.' + methodName + '` should work with large arrays', 1, function() { var largeArray = [], expected = [0, 'a', {}], count = Math.ceil(LARGE_ARRAY_SIZE / expected.length); @@ -16165,10 +16201,10 @@ push.apply(largeArray, expected); }); - deepEqual(_.uniq(largeArray), expected); + deepEqual(func(largeArray), expected); }); - test('should work with large arrays of boolean, `NaN`, and nullish values', 1, function() { + test('`_.' + methodName + '` should work with large arrays of boolean, `NaN`, and nullish values', 1, function() { var largeArray = [], expected = [true, false, NaN, null, undefined], count = Math.ceil(LARGE_ARRAY_SIZE / expected.length); @@ -16177,24 +16213,24 @@ push.apply(largeArray, expected); }); - deepEqual(_.uniq(largeArray), expected); + deepEqual(func(largeArray), expected); }); - test('should work with large arrays of symbols', 1, function() { + test('`_.' + methodName + '` should work with large arrays of symbols', 1, function() { if (Symbol) { var largeArray = _.times(LARGE_ARRAY_SIZE, function() { return Symbol(); }); - deepEqual(_.uniq(largeArray), largeArray); + deepEqual(func(largeArray), largeArray); } else { skipTest(); } }); - test('should work with large arrays of well-known symbols', 1, function() { - // See https://people.mozilla.org/~jorendorff/es6-draft.html#sec-well-known-symbols. + test('`_.' + methodName + '` should work with large arrays of well-known symbols', 1, function() { + // See http://www.ecma-international.org/ecma-262/6.0/#sec-well-known-symbols. if (Symbol) { var expected = [ Symbol.hasInstance, Symbol.isConcatSpreadable, Symbol.iterator, @@ -16213,14 +16249,14 @@ push.apply(largeArray, expected); }); - deepEqual(_.uniq(largeArray), expected); + deepEqual(func(largeArray), expected); } else { skipTest(); } }); - test('should distinguish between numbers and numeric strings', 1, function() { + test('`_.' + methodName + '` should distinguish between numbers and numeric strings', 1, function() { var array = [], expected = ['2', 2, Object('2'), Object(2)], count = Math.ceil(LARGE_ARRAY_SIZE / expected.length); @@ -16229,22 +16265,9 @@ push.apply(array, expected); }); - deepEqual(_.uniq(array), expected); + deepEqual(func(array), expected); }); - - _.each({ - 'an array': [0, 'a'], - 'an object': { '0': 'a' }, - 'a number': 0, - 'a string': '0' - }, - function(callback, key) { - test('should work with ' + key + ' for `iteratee`', 1, function() { - var actual = _.uniq([['a'], ['b'], ['a']], callback); - deepEqual(actual, [['a'], ['b']]); - }); - }); - }()); + }); /*--------------------------------------------------------------------------*/ @@ -17515,7 +17538,7 @@ var acceptFalsey = _.difference(allMethods, rejectFalsey); - test('should accept falsey arguments', 207, function() { + test('should accept falsey arguments', 208, function() { var emptyArrays = _.map(falsey, _.constant([])); _.each(acceptFalsey, function(methodName) { From 83ac1686640848a72258c15ce977c40ecd17ba79 Mon Sep 17 00:00:00 2001 From: jdalton Date: Sun, 5 Jul 2015 20:18:22 -0700 Subject: [PATCH 020/935] Simplify `getIteratee` assignments in methods. --- lodash.src.js | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index bd7157a1bb..e94dc25b78 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -5977,10 +5977,7 @@ if (guard && isIterateeCall(collection, predicate, guard)) { predicate = undefined; } - if (typeof predicate != 'function') { - predicate = getIteratee(predicate); - } - return func(collection, predicate); + return func(collection, getIteratee(predicate)); } /** @@ -6020,8 +6017,7 @@ */ function filter(collection, predicate) { var func = isArray(collection) ? arrayFilter : baseFilter; - predicate = getIteratee(predicate); - return func(collection, predicate); + return func(collection, getIteratee(predicate)); } /** @@ -6337,8 +6333,7 @@ */ function map(collection, iteratee) { var func = isArray(collection) ? arrayMap : baseMap; - iteratee = getIteratee(iteratee); - return func(collection, iteratee); + return func(collection, getIteratee(iteratee)); } /** @@ -6619,10 +6614,7 @@ if (guard && isIterateeCall(collection, predicate, guard)) { predicate = undefined; } - if (typeof predicate != 'function') { - predicate = getIteratee(predicate); - } - return func(collection, predicate); + return func(collection, getIteratee(predicate)); } /** @@ -8866,8 +8858,7 @@ * // => 'barney' */ function findKey(object, predicate) { - predicate = getIteratee(predicate); - return baseFind(object, predicate, baseForOwn, true); + return baseFind(object, getIteratee(predicate), baseForOwn, true); } /** @@ -8904,8 +8895,7 @@ * // => 'pebbles' */ function findLastKey(object, predicate) { - predicate = getIteratee(predicate); - return baseFind(object, predicate, baseForOwnRight, true); + return baseFind(object, getIteratee(predicate), baseForOwnRight, true); } /** From 340a6d195f4335382746e48c093868b803b973d3 Mon Sep 17 00:00:00 2001 From: jdalton Date: Sun, 5 Jul 2015 23:18:10 -0700 Subject: [PATCH 021/935] Add `_.sumBy`. --- lodash.src.js | 106 +++++++++++++++++--------------------------------- test/test.js | 44 ++++++++------------- 2 files changed, 53 insertions(+), 97 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index e94dc25b78..bc725a40cb 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -1647,11 +1647,12 @@ * @returns {number} Returns the sum. */ function arraySum(array, iteratee) { - var length = array.length, + var index = -1, + length = array.length, result = 0; - while (length--) { - result += +iteratee(array[length]) || 0; + while (++index < length) { + result += +iteratee(array[index]) || 0; } return result; } @@ -1975,32 +1976,6 @@ return result; } - /** - * Gets the extremum value of `collection` invoking `iteratee` for each value - * in `collection` to generate the criterion by which the value is ranked. - * The iteratee is invoked with three arguments: (value, index|key, collection). - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {Function} comparator The function used to compare values. - * @param {*} exValue The initial extremum value. - * @returns {*} Returns the extremum value. - */ - function baseExtremum(collection, iteratee, comparator, exValue) { - var computed = exValue, - result = computed; - - baseEach(collection, function(value, index, collection) { - var current = +iteratee(value, index, collection); - if (comparator(current, computed) || (current === exValue && current === result)) { - computed = current; - result = value; - } - }); - return result; - } - /** * The base implementation of `_.fill` without an iteratee call guard. * @@ -2729,23 +2704,6 @@ }); } - /** - * The base implementation of `_.sum` without support for callback shorthands - * and `this` binding. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {number} Returns the sum. - */ - function baseSum(collection, iteratee) { - var result = 0; - baseEach(collection, function(value, index, collection) { - result += +iteratee(value, index, collection) || 0; - }); - return result; - } - /** * The base implementation of `_.uniq` without support for callback shorthands * and `this` binding. @@ -3222,22 +3180,13 @@ * @returns {Function} Returns the new extremum function. */ function createExtremum(comparator, exValue) { - return function(collection, iteratee, guard) { - if (guard && isIterateeCall(collection, iteratee, guard)) { + return function(array, iteratee, guard) { + if (guard && isIterateeCall(array, iteratee, guard)) { iteratee = undefined; } - iteratee = getIteratee(iteratee); - if (iteratee.length == 1) { - collection = isArray(collection) ? collection : toIterable(collection); - if (!collection.length) { - return exValue; - } - var result = arrayExtremum(collection, iteratee, comparator, exValue); - if (result !== exValue) { - return result; - } - } - return baseExtremum(collection, iteratee, comparator, exValue); + return (array && array.length) + ? arrayExtremum(array, getIteratee(iteratee), comparator, exValue) + : exValue; }; } @@ -11301,14 +11250,12 @@ var round = createRound('round'); /** - * Gets the sum of the values in `collection`. + * Gets the sum of the values in `array`. * * @static * @memberOf _ * @category Math - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. - * @param- {Object} [guard] Enables use as an iteratee for functions like `_.map`. + * @param {Array} array The array to iterate over. * @returns {number} Returns the sum. * @example * @@ -11317,6 +11264,24 @@ * * _.sum({ 'a': 4, 'b': 6 }); * // => 10 + */ + function sum(array) { + return sumBy(array, identity); + } + + /** + * This method is like `_.sum` except that it accepts an iteratee which is + * invoked for each element in `array` to generate the value to be summed. + * The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @category Math + * @param {Array} array The array to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. + * @param- {Object} [guard] Enables use as an iteratee for functions like `_.map`. + * @returns {number} Returns the sum. + * @example * * var objects = [ * { 'n': 4 }, @@ -11330,14 +11295,14 @@ * _.sum(objects, 'n'); * // => 10 */ - function sum(collection, iteratee, guard) { - if (guard && isIterateeCall(collection, iteratee, guard)) { + function sumBy(array, iteratee, guard) { + if (!(array && array.length)) { + return 0; + } + if (guard && isIterateeCall(array, iteratee, guard)) { iteratee = undefined; } - iteratee = getIteratee(iteratee); - return iteratee.length == 1 - ? arraySum(isArray(collection) ? collection : toIterable(collection), iteratee) - : baseSum(collection, iteratee); + return arraySum(array, getIteratee(iteratee)); } /*------------------------------------------------------------------------*/ @@ -11562,6 +11527,7 @@ lodash.startCase = startCase; lodash.startsWith = startsWith; lodash.sum = sum; + lodash.sumBy = sumBy; lodash.template = template; lodash.trim = trim; lodash.trimLeft = trimLeft; diff --git a/test/test.js b/test/test.js index 326341a1fe..db4ef127d9 100644 --- a/test/test.js +++ b/test/test.js @@ -14550,9 +14550,7 @@ QUnit.module('lodash.sum'); (function() { - var array = [6, 4, 2], - object = { 'a': 2, 'b': 3, 'c': 1 }, - objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }]; + var array = [6, 4, 2]; test('should return the sum of an array of numbers', 1, function() { strictEqual(_.sum(array), 12); @@ -14571,51 +14569,43 @@ test('should coerce values to numbers and `NaN` to `0`', 1, function() { strictEqual(_.sum(['1', NaN, '2']), 3); }); + }()); - test('should iterate an object', 1, function() { - strictEqual(_.sum(object), 6); - }); + /*--------------------------------------------------------------------------*/ - test('should iterate a string', 2, function() { - _.each(['123', Object('123')], function(value) { - strictEqual(_.sum(value), 6); - }); - }); + QUnit.module('lodash.sumBy'); + + (function() { + var array = [6, 4, 2], + objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }]; test('should work with an `iteratee` argument', 1, function() { - var actual = _.sum(objects, function(object) { + var actual = _.sumBy(objects, function(object) { return object.a; }); deepEqual(actual, 6); }); - test('should provide the correct `iteratee` arguments', 2, function() { + test('should provide the correct `iteratee` arguments', 1, function() { var args; - _.sum(array, function() { - args || (args = slice.call(arguments)); - }); - - deepEqual(args, [6, 0, array]); - - args = null; - _.sum(object, function() { + _.sumBy(array, function() { args || (args = slice.call(arguments)); }); - deepEqual(args, [2, 'a', object]); + deepEqual(args, [6]); }); test('should work with a "_.property" style `iteratee`', 2, function() { var arrays = [[2], [3], [1]]; - strictEqual(_.sum(arrays, 0), 6); - strictEqual(_.sum(objects, 'a'), 6); + strictEqual(_.sumBy(arrays, 0), 6); + strictEqual(_.sumBy(objects, 'a'), 6); }); test('should perform basic sum when used as an iteratee for methods like `_.map`', 1, function() { - var actual = _.map([array, object], _.sum); - deepEqual(actual, [12, 6]); + var actual = _.map([array, array], _.sumBy); + deepEqual(actual, [12, 12]); }); }()); @@ -17538,7 +17528,7 @@ var acceptFalsey = _.difference(allMethods, rejectFalsey); - test('should accept falsey arguments', 208, function() { + test('should accept falsey arguments', 209, function() { var emptyArrays = _.map(falsey, _.constant([])); _.each(acceptFalsey, function(methodName) { From 65d5bba7df5e09dd91ee78003f8a0b9f127616de Mon Sep 17 00:00:00 2001 From: jdalton Date: Sun, 5 Jul 2015 23:22:32 -0700 Subject: [PATCH 022/935] Make `_.maxBy`, `_.minBy`, `_.sumBy`, & `_.uniqBy` support only arrays and provide only 1 argument to iteratees. --- lodash.src.js | 42 +++++++++++++++++--------------- test/test.js | 66 ++++++++++++++++++++------------------------------- 2 files changed, 49 insertions(+), 59 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index bc725a40cb..d284576e0e 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -1504,6 +1504,13 @@ result = value; } } + index = result === exValue ? -1 : index; + while (++index < length) { + value = array[index]; + if (+iteratee(value) === exValue) { + return value; + } + } return result; } @@ -2732,7 +2739,7 @@ outer: while (++index < length) { var value = array[index], - computed = iteratee ? iteratee(value, index, array) : value; + computed = iteratee ? iteratee(value) : value; if (isCommon && value === value) { var seenIndex = seen.length; @@ -5306,9 +5313,8 @@ /** * This method is like `_.uniq` except that it accepts an iteratee which is - * invoked for each value in `array` to generate the criterion by which - * uniqueness is computed. The iteratee is invoked with three arguments: - * (value, index, array). + * invoked for each element in `array` to generate the criterion by which + * uniqueness is computed. The iteratee is invoked with one argument: (value). * * @static * @memberOf _ @@ -11136,7 +11142,7 @@ * @static * @memberOf _ * @category Math - * @param {Array|Object|string} collection The collection to iterate over. + * @param {Array} array The array to iterate over. * @returns {*} Returns the maximum value. * @example * @@ -11146,20 +11152,19 @@ * _.max([]); * // => -Infinity */ - function max(collection) { - return maxBy(collection, identity); + function max(array) { + return maxBy(array, identity); } /** * This method is like `_.max` except that it accepts an iteratee which is - * invoked for each value in `collection` to generate the criterion by which - * the value is ranked. The iteratee is invoked with three arguments: - * (value, index, collection). + * invoked for each element in `array` to generate the criterion by which + * the value is ranked. The iteratee is invoked with one argument: (value). * * @static * @memberOf _ * @category Math - * @param {Array|Object|string} collection The collection to iterate over. + * @param {Array} array The array to iterate over. * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. * @returns {*} Returns the maximum value. * @example @@ -11179,13 +11184,13 @@ var maxBy = createExtremum(gt, NEGATIVE_INFINITY); /** - * Gets the minimum value of `collection`. If `collection` is empty or falsey + * Gets the minimum value of `array`. If `array` is empty or falsey * `Infinity` is returned. * * @static * @memberOf _ * @category Math - * @param {Array|Object|string} collection The collection to iterate over. + * @param {Array} array The array to iterate over. * @returns {*} Returns the minimum value. * @example * @@ -11195,20 +11200,19 @@ * _.min([]); * // => Infinity */ - function min(collection) { - return minBy(collection, identity); + function min(array) { + return minBy(array, identity); } /** * This method is like `_.min` except that it accepts an iteratee which is - * invoked for each value in `collection` to generate the criterion by which - * the value is ranked. The iteratee is invoked with three arguments: - * (value, index, collection). + * invoked for each element in `array` to generate the criterion by which + * the value is ranked. The iteratee is invoked with one argument: (value). * * @static * @memberOf _ * @category Math - * @param {Array|Object|string} collection The collection to iterate over. + * @param {Array} array The array to iterate over. * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. * @returns {*} Returns the minimum value. * @example diff --git a/test/test.js b/test/test.js index db4ef127d9..fdc6b4d061 100644 --- a/test/test.js +++ b/test/test.js @@ -4735,7 +4735,9 @@ var arrayMethods = [ 'findIndex', - 'findLastIndex' + 'findLastIndex', + 'maxBy', + 'minBy' ]; var collectionMethods = [ @@ -4750,8 +4752,6 @@ 'groupBy', 'indexBy', 'map', - 'maxBy', - 'minBy', 'partition', 'reduce', 'reduceRight', @@ -4822,6 +4822,7 @@ _.each(methods, function(methodName) { var array = [1, 2, 3], func = _[methodName], + isExtremum = /^(?:max|min)/.test(methodName), isFind = /^find/.test(methodName), isSome = methodName == 'some'; @@ -4841,6 +4842,9 @@ if (_.includes(objectMethods, methodName)) { expected[1] += ''; } + if (isExtremum) { + expected.length = 1; + } deepEqual(args, expected); } else { @@ -4854,6 +4858,12 @@ array[2] = 3; var expected = [[1, 0, array], [undefined, 1, array], [3, 2, array]]; + + if (isExtremum) { + expected = _.map(expected, function(args) { + return args.slice(0, 1); + }); + } if (_.includes(objectMethods, methodName)) { expected = _.map(expected, function(args) { args[1] += ''; @@ -10059,11 +10069,12 @@ }); test('should return `-Infinity` for empty collections', 1, function() { - var expected = _.map(empties, _.constant(-Infinity)); + var values = falsey.concat([[]]), + expected = _.map(values, _.constant(-Infinity)); - var actual = _.map(empties, function(value) { + var actual = _.map(values, function(value, index) { try { - return _.max(value); + return index ? _.max(value) : _.max(); } catch(e) {} }); @@ -10071,16 +10082,7 @@ }); test('should return `-Infinity` for non-numeric collection values', 1, function() { - var collections = [['a', 'b'], { 'a': 'a', 'b': 'b' }], - expected = _.map(collections, _.constant(-Infinity)); - - var actual = _.map(collections, function(value) { - try { - return _.max(value); - } catch(e) {} - }); - - deepEqual(actual, expected); + strictEqual(_.max(['a', 'b']), -Infinity); }); }()); @@ -10820,11 +10822,12 @@ }); test('should return `Infinity` for empty collections', 1, function() { - var expected = _.map(empties, _.constant(Infinity)); + var values = falsey.concat([[]]), + expected = _.map(values, _.constant(Infinity)); - var actual = _.map(empties, function(value) { + var actual = _.map(values, function(value, index) { try { - return _.min(value); + return index ? _.min(value) : _.min(); } catch(e) {} }); @@ -10832,16 +10835,7 @@ }); test('should return `Infinity` for non-numeric collection values', 1, function() { - var collections = [['a', 'b'], { 'a': 'a', 'b': 'b' }], - expected = _.map(collections, _.constant(Infinity)); - - var actual = _.map(collections, function(value) { - try { - return _.min(value); - } catch(e) {} - }); - - deepEqual(actual, expected); + strictEqual(_.min(['a', 'b']), Infinity); }); }()); @@ -10861,24 +10855,16 @@ strictEqual(func([curr, past]), isMax ? curr : past); }); - test('`_.' + methodName + '` should iterate an object', 1, function() { - var actual = func({ 'a': 1, 'b': 2, 'c': 3 }); - strictEqual(actual, isMax ? 3 : 1); - }); - test('`_.' + methodName + '` should work with extremely large arrays', 1, function() { var array = _.range(0, 5e5); strictEqual(func(array), isMax ? 499999 : 0); }); - test('`_.' + methodName + '` should work as an iteratee for methods like `_.map`', 2, function() { + test('`_.' + methodName + '` should work as an iteratee for methods like `_.map`', 1, function() { var arrays = [[2, 1], [5, 4], [7, 8]], - objects = [{ 'a': 2, 'b': 1 }, { 'a': 5, 'b': 4 }, { 'a': 7, 'b': 8 }], expected = isMax ? [2, 5, 8] : [1, 4, 7]; - _.each([arrays, objects], function(values) { - deepEqual(_.map(values, func), expected); - }); + deepEqual(_.map(arrays, func), expected); }); test('`_.' + methodName + '` should work when chaining on an array with only one value', 1, function() { @@ -16106,7 +16092,7 @@ args || (args = slice.call(arguments)); }); - deepEqual(args, [objects[0], 0, objects]); + deepEqual(args, [objects[0]]); }); test('should work with `iteratee` without specifying `isSorted`', 1, function() { From bc7cabde4e6fcc39a27de5d883bb568ce46f22f7 Mon Sep 17 00:00:00 2001 From: jdalton Date: Sun, 5 Jul 2015 23:24:41 -0700 Subject: [PATCH 023/935] Cleanup `forEach` and friends doc examples. [ci skip] --- lodash.src.js | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index d284576e0e..934f98cfb4 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -6064,15 +6064,15 @@ * @returns {Array|Object|string} Returns `collection`. * @example * - * _([1, 2]).forEach(function(n) { - * console.log(n); + * _([1, 2]).forEach(function(value) { + * console.log(value); * }); - * // => logs each value from left to right and returns the array + * // => logs `1` then `2` * - * _.forEach({ 'a': 1, 'b': 2 }, function(n, key) { - * console.log(n, key); + * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) { + * console.log(key); * }); - * // => logs each value-key pair and returns the object (iteration order is not guaranteed) + * // => logs 'a' then 'b' (iteration order is not guaranteed) */ function forEach(collection, iteratee) { return (typeof iteratee == 'function' && isArray(collection)) @@ -6093,10 +6093,10 @@ * @returns {Array|Object|string} Returns `collection`. * @example * - * _.forEachRight([1, 2], function(n) { - * console.log(n); + * _.forEachRight([1, 2], function(value) { + * console.log(value); * }); - * // => logs each value from right to left and returns the array + * // => logs `2` then `1` */ function forEachRight(collection, iteratee) { return (typeof iteratee == 'function' && isArray(collection)) @@ -8835,7 +8835,7 @@ * }; * * _.findLastKey(users, function(o) { return o.age < 40; }); - * // => returns `pebbles` assuming `_.findKey` returns `barney` + * // => returns 'pebbles' assuming `_.findKey` returns 'barney' * * // using the `_.matches` callback shorthand * _.findLastKey(users, { 'age': 36, 'active': true }); @@ -8877,7 +8877,7 @@ * _.forIn(new Foo, function(value, key) { * console.log(key); * }); - * // => logs 'a', 'b', and 'c' (iteration order is not guaranteed) + * // => logs 'a', 'b', then 'c' (iteration order is not guaranteed) */ function forIn(object, iteratee) { return baseFor(object, toFunction(iteratee), keysIn); @@ -8905,7 +8905,7 @@ * _.forInRight(new Foo, function(value, key) { * console.log(key); * }); - * // => logs 'c', 'b', and 'a' assuming `_.forIn ` logs 'a', 'b', and 'c' + * // => logs 'c', 'b', then 'a' assuming `_.forIn` logs 'a', 'b', then 'c' */ function forInRight(object, iteratee) { return baseForRight(object, toFunction(iteratee), keysIn); @@ -8935,7 +8935,7 @@ * _.forOwn(new Foo, function(value, key) { * console.log(key); * }); - * // => logs 'a' and 'b' (iteration order is not guaranteed) + * // => logs 'a' then 'b' (iteration order is not guaranteed) */ function forOwn(object, iteratee) { return baseForOwn(object, toFunction(iteratee)); @@ -8963,13 +8963,12 @@ * _.forOwnRight(new Foo, function(value, key) { * console.log(key); * }); - * // => logs 'b' and 'a' assuming `_.forOwn` logs 'a' and 'b' + * // => logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b' */ function forOwnRight(object, iteratee) { return baseForOwnRight(object, toFunction(iteratee)); } - /** * Creates an array of function property names from all enumerable properties, * own and inherited, of `object`. From 41f248f54d1714150bccd6b847e62b7dda16e604 Mon Sep 17 00:00:00 2001 From: jdalton Date: Mon, 6 Jul 2015 08:11:19 -0700 Subject: [PATCH 024/935] Split out `_.sortedIndex` and `_.sortedLastIndex` into `_.sortedIndexBy` and `_.sortedLastIndexBy`. --- lodash.src.js | 76 +++++++++++++++++++++++++++++++++++---------------- test/test.js | 65 +++++++++++++++++++++++++------------------ 2 files changed, 91 insertions(+), 50 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 934f98cfb4..a9d83f8c3d 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -5044,41 +5044,51 @@ /** * Uses a binary search to determine the lowest index at which `value` should - * be inserted into `array` in order to maintain its sort order. If an iteratee - * function is provided it's invoked for `value` and each element of `array` - * to compute their sort ranking. The iteratee is invoked with one argument: - * (value). + * be inserted into `array` in order to maintain its sort order. * * @static * @memberOf _ * @category Array * @param {Array} array The sorted array to inspect. * @param {*} value The value to evaluate. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. * @returns {number} Returns the index at which `value` should be inserted into `array`. * @example * * _.sortedIndex([30, 50], 40); * // => 1 * - * _.sortedIndex([4, 4, 5, 5], 5); - * // => 2 + * _.sortedIndex([4, 5], 4); + * // => 0 + */ + function sortedIndex(array, value) { + return binaryIndex(array, value); + } + + /** + * This method is like `_.sortedIndex` except that it accepts an iteratee + * which is invoked for `value` and each element of `array` to compute their + * sort ranking. The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. + * @returns {number} Returns the index at which `value` should be inserted into `array`. + * @example * * var dict = { 'thirty': 30, 'forty': 40, 'fifty': 50 }; * - * // using an iteratee function - * _.sortedIndex(['thirty', 'fifty'], 'forty', _.propertyOf(dict)); + * _.sortedIndexBy(['thirty', 'fifty'], 'forty', _.propertyOf(dict)); * // => 1 * * // using the `_.property` callback shorthand - * _.sortedIndex([{ 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x'); - * // => 1 + * _.sortedIndexBy([{ 'x': 4 }, { 'x': 5 }], { 'x': 4 }, 'x'); + * // => 0 */ - function sortedIndex(array, value, iteratee) { - var toIteratee = getIteratee(); - return (iteratee == null && toIteratee === baseIteratee) - ? binaryIndex(array, value) - : binaryIndexBy(array, value, toIteratee(iteratee)); + function sortedIndexBy(array, value, iteratee) { + return binaryIndexBy(array, value, getIteratee(iteratee)); } /** @@ -5091,18 +5101,36 @@ * @category Array * @param {Array} array The sorted array to inspect. * @param {*} value The value to evaluate. + * @returns {number} Returns the index at which `value` should be inserted into `array`. + * @example + * + * _.sortedLastIndex([4, 5], 4); + * // => 1 + */ + function sortedLastIndex(array, value) { + return binaryIndex(array, value, true); + } + + /** + * This method is like `_.sortedLastIndex` except that it accepts an iteratee + * which is invoked for `value` and each element of `array` to compute their + * sort ranking. The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. * @returns {number} Returns the index at which `value` should be inserted into `array`. * @example * - * _.sortedLastIndex([4, 4, 5, 5], 5); - * // => 4 + * // using the `_.property` callback shorthand + * _.sortedLastIndexBy([{ 'x': 4 }, { 'x': 5 }], { 'x': 4 }, 'x'); + * // => 1 */ - function sortedLastIndex(array, value, iteratee) { - var toIteratee = getIteratee(); - return (iteratee == null && toIteratee === baseIteratee) - ? binaryIndex(array, value, true) - : binaryIndexBy(array, value, toIteratee(iteratee), true); + function sortedLastIndexBy(array, value, iteratee) { + return binaryIndexBy(array, value, getIteratee(iteratee), true); } /** @@ -11526,7 +11554,9 @@ lodash.snakeCase = snakeCase; lodash.some = some; lodash.sortedIndex = sortedIndex; + lodash.sortedIndexBy = sortedIndexBy; lodash.sortedLastIndex = sortedLastIndex; + lodash.sortedLastIndexBy = sortedLastIndexBy; lodash.startCase = startCase; lodash.startsWith = startsWith; lodash.sum = sum; diff --git a/test/test.js b/test/test.js index fdc6b4d061..962ff8de8c 100644 --- a/test/test.js +++ b/test/test.js @@ -8739,12 +8739,12 @@ } }); - test('`_.sortedIndex` should use `_.iteratee` internally', 1, function() { + test('`_.sortedIndexBy` should use `_.iteratee` internally', 1, function() { if (!isModularize) { var objects = [{ 'a': 30 }, { 'a': 50 }]; _.iteratee = getPropA; - strictEqual(_.sortedIndex(objects, { 'a': 40 }), 1); + strictEqual(_.sortedIndexBy(objects, { 'a': 40 }), 1); _.iteratee = iteratee; } else { @@ -8752,12 +8752,12 @@ } }); - test('`_.sortedLastIndex` should use `_.iteratee` internally', 1, function() { + test('`_.sortedLastIndexBy` should use `_.iteratee` internally', 1, function() { if (!isModularize) { var objects = [{ 'a': 30 }, { 'a': 50 }]; _.iteratee = getPropA; - strictEqual(_.sortedLastIndex(objects, { 'a': 40 }), 1); + strictEqual(_.sortedLastIndexBy(objects, { 'a': 40 }), 1); _.iteratee = iteratee; } else { @@ -14323,13 +14323,12 @@ QUnit.module('sortedIndex methods'); _.each(['sortedIndex', 'sortedLastIndex'], function(methodName) { - var array = [30, 50], - func = _[methodName], - isSortedIndex = methodName == 'sortedIndex', - objects = [{ 'x': 30 }, { 'x': 50 }]; + var func = _[methodName], + isSortedIndex = methodName == 'sortedIndex'; test('`_.' + methodName + '` should return the insert index', 1, function() { - var values = [30, 40, 50], + var array = [30, 50], + values = [30, 40, 50], expected = isSortedIndex ? [0, 1, 1] : [1, 1, 2]; var actual = _.map(values, function(value) { @@ -14361,21 +14360,6 @@ deepEqual(actual, expected); }); - test('`_.' + methodName + '` should provide the correct `iteratee` arguments', 1, function() { - var args; - - func(array, 40, function() { - args || (args = slice.call(arguments)); - }); - - deepEqual(args, [40]); - }); - - test('`_.' + methodName + '` should work with a "_.property" style `iteratee`', 1, function() { - var actual = func(objects, { 'x': 40 }, 'x'); - strictEqual(actual, 1); - }); - test('`_.' + methodName + '` should align with `_.sortBy`', 10, function() { var expected = [1, '2', {}, null, undefined, NaN, NaN]; @@ -14390,6 +14374,32 @@ strictEqual(func(expected, NaN), isSortedIndex ? 5 : 7); }); }); + }); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('sortedIndexBy methods'); + + _.each(['sortedIndexBy', 'sortedLastIndexBy'], function(methodName) { + var func = _[methodName], + isSortedIndexBy = methodName == 'sortedIndexBy'; + + test('`_.' + methodName + '` should provide the correct `iteratee` arguments', 1, function() { + var args; + + func([30, 50], 40, function() { + args || (args = slice.call(arguments)); + }); + + deepEqual(args, [40]); + }); + + test('`_.' + methodName + '` should work with a "_.property" style `iteratee`', 1, function() { + var objects = [{ 'x': 30 }, { 'x': 50 }], + actual = func(objects, { 'x': 40 }, 'x'); + + strictEqual(actual, 1); + }); test('`_.' + methodName + '` should support arrays larger than `MAX_ARRAY_LENGTH / 2`', 12, function() { _.each([Math.ceil(MAX_ARRAY_LENGTH / 2), MAX_ARRAY_LENGTH], function(length) { @@ -14402,7 +14412,7 @@ var steps = 0, actual = func(array, value, function(value) { steps++; return value; }); - var expected = (isSortedIndex ? !_.isNaN(value) : _.isFinite(value)) + var expected = (isSortedIndexBy ? !_.isNaN(value) : _.isFinite(value)) ? 0 : Math.min(length, MAX_ARRAY_INDEX); @@ -17347,7 +17357,7 @@ var args = arguments, array = [1, 2, 3, 4, 5, 6]; - test('should work with `arguments` objects', 27, function() { + test('should work with `arguments` objects', 28, function() { function message(methodName) { return '`_.' + methodName + '` should work with `arguments` objects'; } @@ -17374,6 +17384,7 @@ deepEqual(_.lastIndexOf(args, 1), 0, message('lastIndexOf')); deepEqual(_.rest(args, 4), [null, [3], null, 5], message('rest')); deepEqual(_.sortedIndex(args, 6), 5, message('sortedIndex')); + deepEqual(_.sortedLastIndex(args, 6), 5, message('sortedLastIndex')); deepEqual(_.take(args, 2), [1, null], message('take')); deepEqual(_.takeRight(args, 1), [5], message('takeRight')); deepEqual(_.takeRightWhile(args, _.identity), [5], message('takeRightWhile')); @@ -17514,7 +17525,7 @@ var acceptFalsey = _.difference(allMethods, rejectFalsey); - test('should accept falsey arguments', 209, function() { + test('should accept falsey arguments', 211, function() { var emptyArrays = _.map(falsey, _.constant([])); _.each(acceptFalsey, function(methodName) { From 0b7bffe3b54628bd62e1f56452e5490b34dee1d2 Mon Sep 17 00:00:00 2001 From: jdalton Date: Mon, 6 Jul 2015 08:11:54 -0700 Subject: [PATCH 025/935] Use more descriptive var names when mapping falsey values. --- test/test.js | 54 ++++++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/test/test.js b/test/test.js index 962ff8de8c..608098c065 100644 --- a/test/test.js +++ b/test/test.js @@ -1114,9 +1114,9 @@ test('should work with a falsey `collection` argument when keys are provided', 1, function() { var expected = _.map(falsey, _.constant(Array(4))); - var actual = _.map(falsey, function(value) { + var actual = _.map(falsey, function(collection) { try { - return _.at(value, 0, 1, 'pop', 'push'); + return _.at(collection, 0, 1, 'pop', 'push'); } catch(e) {} }); @@ -2503,8 +2503,8 @@ test('should accept a falsey `prototype` argument', 1, function() { var expected = _.map(falsey, _.constant({})); - var actual = _.map(falsey, function(value, index) { - return index ? _.create(value) : _.create(); + var actual = _.map(falsey, function(prototype, index) { + return index ? _.create(prototype) : _.create(); }); deepEqual(actual, expected); @@ -5142,8 +5142,8 @@ isDefaults = methodName == 'defaults'; test('`_.' + methodName + '` should pass thru falsey `object` values', 1, function() { - var actual = _.map(falsey, function(value, index) { - return index ? func(value) : func(); + var actual = _.map(falsey, function(object, index) { + return index ? func(object) : func(); }); deepEqual(actual, falsey); @@ -6012,9 +6012,9 @@ test('should accept a falsey `array` argument', 1, function() { var expected = _.map(falsey, _.constant([])); - var actual = _.map(falsey, function(value, index) { + var actual = _.map(falsey, function(array, index) { try { - return index ? _.initial(value) : _.initial(); + return index ? _.initial(array) : _.initial(); } catch(e) {} }); @@ -9214,9 +9214,9 @@ test('`_.' + methodName + '` should accept a falsey `array` argument', 1, function() { var expected = _.map(falsey, _.constant(-1)); - var actual = _.map(falsey, function(value, index) { + var actual = _.map(falsey, function(array, index) { try { - return index ? func(value) : func(); + return index ? func(array) : func(); } catch(e) {} }); @@ -9323,9 +9323,9 @@ test('should accept a falsey `collection` argument', 1, function() { var expected = _.map(falsey, _.constant([])); - var actual = _.map(falsey, function(value, index) { + var actual = _.map(falsey, function(collection, index) { try { - return index ? _.map(value) : _.map(); + return index ? _.map(collection) : _.map(); } catch(e) {} }); @@ -9469,9 +9469,9 @@ test('should accept a falsey `object` argument', 1, function() { var expected = _.map(falsey, _.constant({})); - var actual = _.map(falsey, function(value, index) { + var actual = _.map(falsey, function(object, index) { try { - return index ? func(value) : func(); + return index ? func(object) : func(); } catch(e) {} }); @@ -10112,12 +10112,12 @@ raises(function() { _.memoize(_.noop, {}); }, TypeError); }); - test('should not error if `resolve` is falsey', function() { + test('should not error if `resolver` is falsey', function() { var expected = _.map(falsey, _.constant(true)); - var actual = _.map(falsey, function(value, index) { + var actual = _.map(falsey, function(resolver, index) { try { - return _.isFunction(index ? _.memoize(_.noop, value) : _.memoize(_.noop)); + return _.isFunction(index ? _.memoize(_.noop, resolver) : _.memoize(_.noop)); } catch(e) {} }); @@ -12430,9 +12430,9 @@ test('should work with a falsey `array` argument when keys are provided', 1, function() { var expected = _.map(falsey, _.constant(Array(4))); - var actual = _.map(falsey, function(value) { + var actual = _.map(falsey, function(array) { try { - return _.pullAt(value, 0, 1, 'pop', 'push'); + return _.pullAt(array, 0, 1, 'pop', 'push'); } catch(e) {} }); @@ -13303,9 +13303,9 @@ test('should accept a falsey `array` argument', 1, function() { var expected = _.map(falsey, _.constant([])); - var actual = _.map(falsey, function(value, index) { + var actual = _.map(falsey, function(array, index) { try { - return index ? _.rest(value) : _.rest(); + return index ? _.rest(array) : _.rest(); } catch(e) {} }); @@ -13869,9 +13869,9 @@ test('should accept a falsey `object` argument', 1, function() { var expected = _.map(falsey, _.constant(0)); - var actual = _.map(falsey, function(value, index) { + var actual = _.map(falsey, function(object, index) { try { - return index ? _.size(value) : _.size(); + return index ? _.size(object) : _.size(); } catch(e) {} }); @@ -15861,8 +15861,8 @@ test('should create an empty object when provided a falsey `object` argument', 1, function() { var expected = _.map(falsey, _.constant({})); - var actual = _.map(falsey, function(value, index) { - return index ? _.transform(value) : _.transform(); + var actual = _.map(falsey, function(object, index) { + return index ? _.transform(object) : _.transform(); }); deepEqual(actual, expected); @@ -16541,9 +16541,9 @@ test('should accept a falsey `array` argument', 1, function() { var expected = _.map(falsey, _.constant({})); - var actual = _.map(falsey, function(value, index) { + var actual = _.map(falsey, function(array, index) { try { - return index ? _.zipObject(value) : _.zipObject(); + return index ? _.zipObject(array) : _.zipObject(); } catch(e) {} }); From 9aa34e2487d230e8856c95f7a5aee70f335d7d95 Mon Sep 17 00:00:00 2001 From: jdalton Date: Tue, 7 Jul 2015 08:34:06 -0700 Subject: [PATCH 026/935] Remove `isDeep` params from `_.clone` and `_.flatten`. --- lodash.src.js | 54 ++++++++++------------------------- test/test.js | 79 +++++++++++---------------------------------------- 2 files changed, 32 insertions(+), 101 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index a9d83f8c3d..22ffdf0792 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -4647,31 +4647,21 @@ } /** - * Flattens a nested array. If `isDeep` is `true` the array is recursively - * flattened, otherwise it's only flattened a single level. + * Flattens a nested array a single level. * * @static * @memberOf _ * @category Array * @param {Array} array The array to flatten. - * @param {boolean} [isDeep] Specify a deep flatten. - * @param- {Object} [guard] Enables use as an iteratee for functions like `_.map`. * @returns {Array} Returns the new flattened array. * @example * * _.flatten([1, [2, 3, [4]]]); * // => [1, 2, 3, [4]] - * - * // using `isDeep` - * _.flatten([1, [2, 3, [4]]], true); - * // => [1, 2, 3, 4] */ - function flatten(array, isDeep, guard) { + function flatten(array) { var length = array ? array.length : 0; - if (guard && isIterateeCall(array, isDeep, guard)) { - isDeep = false; - } - return length ? baseFlatten(array, isDeep) : []; + return length ? baseFlatten(array) : []; } /** @@ -6281,11 +6271,10 @@ * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`. * * The guarded methods are: - * `ary`, `callback`, `chunk`, `clone`, `create`, `curry`, `curryRight`, - * `drop`, `dropRight`, `every`, `fill`, `flatten`, `invert`, `max`, `min`, - * `parseInt`, `slice`, `sortBy`, `take`, `takeRight`, `template`, `trim`, - * `trimLeft`, `trimRight`, `trunc`, `random`, `range`, `sample`, `some`, - * `sum`, `uniq`, and `words` + * `ary`, `callback`, `chunk`, `create`, `curry`, `curryRight`, `drop`, + * `dropRight`, `every`, `fill`, `invert`, `parseInt`, `random`, `range`, + * `sample`, `slice`, `some`, `sortBy`, `sumBy`, `take`, `takeRight`, + * `template`, `trim`, `trimLeft`, `trimRight`, `trunc`, `uniqBy`, and `words` * * @static * @memberOf _ @@ -7755,11 +7744,10 @@ /*------------------------------------------------------------------------*/ /** - * Creates a clone of `value`. If `isDeep` is `true` nested objects are cloned, - * otherwise they are assigned by reference. If `customizer` is provided it's - * invoked to produce the cloned values. If `customizer` returns `undefined` - * cloning is handled by the method instead. The `customizer` is invoked with - * up to three argument; (value [, index|key, object]). + * Creates a clone of `value`. If `customizer` is provided it's invoked to + * produce the cloned values. If `customizer` returns `undefined` cloning is + * handled by the method instead. The `customizer` is invoked with up to + * three arguments; (value [, index|key, object]). * * **Note:** This method is loosely based on the * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm). @@ -7772,7 +7760,6 @@ * @memberOf _ * @category Lang * @param {*} value The value to clone. - * @param {boolean} [isDeep] Specify a deep clone. * @param {Function} [customizer] The function to customize cloning values. * @returns {*} Returns the cloned value. * @example @@ -7786,10 +7773,6 @@ * shallow[0] === users[0]; * // => true * - * var deep = _.clone(users, true); - * deep[0] === users[0]; - * // => false - * * // using a customizer callback * var el = _.clone(document.body, function(value) { * if (_.isElement(value)) { @@ -7804,24 +7787,17 @@ * el.childNodes.length; * // => 0 */ - function clone(value, isDeep, customizer) { - if (isDeep && typeof isDeep != 'boolean' && isIterateeCall(value, isDeep, customizer)) { - isDeep = false; - } - else if (typeof isDeep == 'function') { - customizer = isDeep; - isDeep = false; - } + function clone(value, customizer) { return typeof customizer == 'function' - ? baseClone(value, isDeep, customizer) - : baseClone(value, isDeep); + ? baseClone(value, false, customizer) + : baseClone(value); } /** * Creates a deep clone of `value`. If `customizer` is provided it's invoked * to produce the cloned values. If `customizer` returns `undefined` cloning * is handled by the method instead. The `customizer` is invoked with up to - * three argument; (value [, index|key, object]). + * three arguments; (value [, index|key, object]). * * **Note:** This method is loosely based on the * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm). diff --git a/test/test.js b/test/test.js index 608098c065..d24cb4085e 100644 --- a/test/test.js +++ b/test/test.js @@ -1949,17 +1949,6 @@ ok(actual !== array && actual[0] === array[0]); }); - test('`_.clone` should work with `isDeep`', 8, function() { - var array = [{ 'a': 0 }, { 'b': 1 }], - values = [true, 1, {}, '1']; - - _.each(values, function(isDeep) { - var actual = _.clone(array, isDeep); - deepEqual(actual, array); - ok(actual !== array && actual[0] !== array[0]); - }); - }); - test('`_.cloneDeep` should deep clone objects with circular references', 1, function() { var object = { 'foo': { 'b': { 'c': { 'd': {} } } }, @@ -4527,30 +4516,11 @@ deepEqual(_.flatten(array), [['a'], ['b']]); }); - test('should work with `isDeep`', 2, function() { - var array = [[['a']], [['b']]], - expected = ['a', 'b']; + test('should flatten `arguments` objects', 2, function() { + var array = [args, [args]]; - deepEqual(_.flatten(array, true), expected); - deepEqual(_.flattenDeep(array), expected); - }); - - test('should flatten `arguments` objects', 3, function() { - var array = [args, [args]], - expected = [1, 2, 3, args]; - - deepEqual(_.flatten(array), expected); - - expected = [1, 2, 3, 1, 2, 3]; - deepEqual(_.flatten(array, true), expected); - deepEqual(_.flattenDeep(array), expected); - }); - - test('should work as an iteratee for methods like `_.map`', 2, function() { - var array = [[[['a']]], [[['b']]]]; - - deepEqual(_.map(array, _.flatten), [[['a']], [['b']]]); - deepEqual(_.map(array, _.flattenDeep), [['a'], ['b']]); + deepEqual(_.flatten(array), [1, 2, 3, args]); + deepEqual(_.flattenDeep(array), [1, 2, 3, 1, 2, 3]); }); test('should treat sparse arrays as dense', 6, function() { @@ -4588,26 +4558,18 @@ }); }); - test('should work with empty arrays', 3, function() { - var array = [[], [[]], [[], [[[]]]]], - expected = [[], [], [[[]]]]; + test('should work with empty arrays', 2, function() { + var array = [[], [[]], [[], [[[]]]]]; - deepEqual(_.flatten(array), expected); - - expected = []; - deepEqual(_.flatten(array, true), expected); - deepEqual(_.flattenDeep(array), expected); + deepEqual(_.flatten(array), [[], [], [[[]]]]); + deepEqual(_.flattenDeep(array), []); }); - test('should support flattening of nested arrays', 3, function() { - var array = [1, [2, 3], 4, [[5]]], - expected = [1, 2, 3, 4, [5]]; - - deepEqual(_.flatten(array), expected); + test('should support flattening of nested arrays', 2, function() { + var array = [1, [2, 3], 4, [[5]]]; - expected = [1, 2, 3, 4, 5]; - deepEqual(_.flatten(array, true), expected); - deepEqual(_.flattenDeep(array), expected); + deepEqual(_.flatten(array), [1, 2, 3, 4, [5]]); + deepEqual(_.flattenDeep(array), [1, 2, 3, 4, 5]); }); test('should return an empty array for non array-like objects', 3, function() { @@ -4618,28 +4580,21 @@ deepEqual(_.flattenDeep({ 'a': 1 }), expected); }); - test('should return a wrapped value when chaining', 6, function() { + test('should return a wrapped value when chaining', 4, function() { if (!isNpm) { var wrapped = _([1, [2], [3, [4]]]), - actual = wrapped.flatten(), - expected = [1, 2, 3, [4]]; + actual = wrapped.flatten(); ok(actual instanceof _); - deepEqual(actual.value(), expected); - - expected = [1, 2, 3, 4]; - actual = wrapped.flatten(true); - - ok(actual instanceof _); - deepEqual(actual.value(), expected); + deepEqual(actual.value(), [1, 2, 3, [4]]); actual = wrapped.flattenDeep(); ok(actual instanceof _); - deepEqual(actual.value(), expected); + deepEqual(actual.value(), [1, 2, 3, 4]); } else { - skipTest(6); + skipTest(4); } }); }(1, 2, 3)); From 1f1bc393d380cbe9d83f993672020911cc4778e9 Mon Sep 17 00:00:00 2001 From: jdalton Date: Tue, 7 Jul 2015 11:02:47 -0700 Subject: [PATCH 027/935] Cleanup docs for deep methods and those that accept customizer functions. [ci skip] --- lodash.src.js | 49 +++++++++++++++++++------------------------------ 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 22ffdf0792..794138cbaa 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -1796,7 +1796,7 @@ * @private * @param {*} value The value to clone. * @param {boolean} [isDeep] Specify a deep clone. - * @param {Function} [customizer] The function to customize cloning values. + * @param {Function} [customizer] The function to customize cloning. * @param {string} [key] The key of `value`. * @param {Object} [object] The object `value` belongs to. * @param {Array} [stackA=[]] Tracks traversed source objects. @@ -2236,7 +2236,7 @@ * @private * @param {*} value The value to compare. * @param {*} other The other value to compare. - * @param {Function} [customizer] The function to customize comparing values. + * @param {Function} [customizer] The function to customize comparisons. * @param {boolean} [isLoose] Specify performing partial comparisons. * @param {Array} [stackA] Tracks traversed `value` objects. * @param {Array} [stackB] Tracks traversed `other` objects. @@ -2261,7 +2261,7 @@ * @param {Object} object The object to compare. * @param {Object} other The other object to compare. * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} [customizer] The function to customize comparing objects. + * @param {Function} [customizer] The function to customize comparisons. * @param {boolean} [isLoose] Specify performing partial comparisons. * @param {Array} [stackA=[]] Tracks traversed `value` objects. * @param {Array} [stackB=[]] Tracks traversed `other` objects. @@ -2337,7 +2337,7 @@ * @private * @param {Object} object The object to inspect. * @param {Array} matchData The propery names, values, and compare flags to match. - * @param {Function} [customizer] The function to customize comparing objects. + * @param {Function} [customizer] The function to customize comparisons. * @returns {boolean} Returns `true` if `object` is a match, else `false`. */ function baseIsMatch(object, matchData, customizer) { @@ -2467,7 +2467,7 @@ * @param {Object} source The source object. * @param {string} key The key of the value to merge. * @param {Function} mergeFunc The function to merge values. - * @param {Function} [customizer] The function to customize merged values. + * @param {Function} [customizer] The function to customize assigned values. * @param {Array} [stackA=[]] Tracks traversed source objects. * @param {Array} [stackB=[]] Associates values with source counterparts. * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. @@ -3491,7 +3491,7 @@ * @param {Array} array The array to compare. * @param {Array} other The other array to compare. * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} [customizer] The function to customize comparing arrays. + * @param {Function} [customizer] The function to customize comparisons. * @param {boolean} [isLoose] Specify performing partial comparisons. * @param {Array} [stackA] Tracks traversed `value` objects. * @param {Array} [stackB] Tracks traversed `other` objects. @@ -3578,7 +3578,7 @@ * @param {Object} object The object to compare. * @param {Object} other The other object to compare. * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} [customizer] The function to customize comparing values. + * @param {Function} [customizer] The function to customize comparisons. * @param {boolean} [isLoose] Specify performing partial comparisons. * @param {Array} [stackA] Tracks traversed `value` objects. * @param {Array} [stackB] Tracks traversed `other` objects. @@ -4647,7 +4647,7 @@ } /** - * Flattens a nested array a single level. + * Flattens `array` a single level. * * @static * @memberOf _ @@ -4665,7 +4665,7 @@ } /** - * Recursively flattens a nested array. + * This method is like `_.flatten` except that it recursively flattens `array`. * * @static * @memberOf _ @@ -7744,9 +7744,9 @@ /*------------------------------------------------------------------------*/ /** - * Creates a clone of `value`. If `customizer` is provided it's invoked to - * produce the cloned values. If `customizer` returns `undefined` cloning is - * handled by the method instead. The `customizer` is invoked with up to + * Creates a shallow clone of `value`. If `customizer` is provided it's invoked + * to produce the cloned value. If `customizer` returns `undefined` cloning + * is handled by the method instead. The `customizer` is invoked with up to * three arguments; (value [, index|key, object]). * * **Note:** This method is loosely based on the @@ -7760,7 +7760,7 @@ * @memberOf _ * @category Lang * @param {*} value The value to clone. - * @param {Function} [customizer] The function to customize cloning values. + * @param {Function} [customizer] The function to customize cloning. * @returns {*} Returns the cloned value. * @example * @@ -7794,23 +7794,13 @@ } /** - * Creates a deep clone of `value`. If `customizer` is provided it's invoked - * to produce the cloned values. If `customizer` returns `undefined` cloning - * is handled by the method instead. The `customizer` is invoked with up to - * three arguments; (value [, index|key, object]). - * - * **Note:** This method is loosely based on the - * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm). - * The enumerable properties of `arguments` objects and objects created by - * constructors other than `Object` are cloned to plain `Object` objects. An - * empty object is returned for uncloneable values such as functions, DOM nodes, - * Maps, Sets, and WeakMaps. + * This method is like `_.clone` except that it recursively clones `value`. * * @static * @memberOf _ * @category Lang - * @param {*} value The value to deep clone. - * @param {Function} [customizer] The function to customize cloning values. + * @param {*} value The value to recursively clone. + * @param {Function} [customizer] The function to customize cloning. * @returns {*} Returns the deep cloned value. * @example * @@ -8049,7 +8039,7 @@ * @category Lang * @param {*} value The value to compare. * @param {*} other The other value to compare. - * @param {Function} [customizer] The function to customize value comparisons. + * @param {Function} [customizer] The function to customize comparisons. * @returns {boolean} Returns `true` if the values are equivalent, else `false`. * @example * @@ -8198,7 +8188,7 @@ * @category Lang * @param {Object} object The object to inspect. * @param {Object} source The object of property values to match. - * @param {Function} [customizer] The function to customize value comparisons. + * @param {Function} [customizer] The function to customize comparisons. * @returns {boolean} Returns `true` if `object` is a match, else `false`. * @example * @@ -8655,8 +8645,7 @@ * Assigns own enumerable properties of source object(s) to the destination * object. Subsequent sources overwrite property assignments of previous sources. * If `customizer` is provided it's invoked to produce the assigned values. - * The `customizer` is invoked with five arguments: - * (objectValue, sourceValue, key, object, source). + * The `customizer` is invoked with five arguments: (objectValue, sourceValue, key, object, source). * * **Note:** This method mutates `object` and is based on * [`Object.assign`](http://ecma-international.org/ecma-262/6.0/#sec-object.assign). From d036ff6c4feddfe5766505ab2f11b93fc5c52e4f Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Wed, 8 Jul 2015 11:02:26 -0700 Subject: [PATCH 028/935] Drop IE 6/7 testing. --- test/saucelabs.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/saucelabs.js b/test/saucelabs.js index 72b9d46ab6..d9c4adcfeb 100644 --- a/test/saucelabs.js +++ b/test/saucelabs.js @@ -114,8 +114,6 @@ var platforms = [ ['Windows 8', 'internet explorer', '10'], ['Windows 7', 'internet explorer', '9'], ['Windows 7', 'internet explorer', '8'], - ['Windows XP', 'internet explorer', '7'], - ['Windows XP', 'internet explorer', '6'], ['OS X 10.9', 'ipad', '8.1'], ['OS X 10.6', 'ipad', '4'], ['OS X 10.10', 'safari', '8'], From 13e5d77041d9aeb29516f7ea1caa1d60a0732906 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 9 Jul 2015 19:33:26 -0700 Subject: [PATCH 029/935] Remove iOS 4.3 in sauce because they're eoling it. --- test/saucelabs.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/saucelabs.js b/test/saucelabs.js index d9c4adcfeb..b6f6de769d 100644 --- a/test/saucelabs.js +++ b/test/saucelabs.js @@ -115,7 +115,6 @@ var platforms = [ ['Windows 7', 'internet explorer', '9'], ['Windows 7', 'internet explorer', '8'], ['OS X 10.9', 'ipad', '8.1'], - ['OS X 10.6', 'ipad', '4'], ['OS X 10.10', 'safari', '8'], ['OS X 10.9', 'safari', '7'], ['OS X 10.8', 'safari', '6'], From 2586129dcd2fe8f017d4f755dbcf152171f221f8 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 9 Jul 2015 19:37:23 -0700 Subject: [PATCH 030/935] Replace `arrayCopy` and `baseCopy` with `copyArray`, `copyObject`, and `copyObjectWith`. --- lodash.src.js | 148 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 89 insertions(+), 59 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 794138cbaa..938c720df3 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -1164,12 +1164,12 @@ */ function lazyClone() { var result = new LazyWrapper(this.__wrapped__); - result.__actions__ = arrayCopy(this.__actions__); + result.__actions__ = copyArray(this.__actions__); result.__dir__ = this.__dir__; result.__filtered__ = this.__filtered__; - result.__iteratees__ = arrayCopy(this.__iteratees__); + result.__iteratees__ = copyArray(this.__iteratees__); result.__takeCount__ = this.__takeCount__; - result.__views__ = arrayCopy(this.__views__); + result.__views__ = copyArray(this.__views__); return result; } @@ -1397,25 +1397,6 @@ return result; } - /** - * Copies the values of `source` to `array`. - * - * @private - * @param {Array} source The array to copy values from. - * @param {Array} [array=[]] The array to copy values to. - * @returns {Array} Returns `array`. - */ - function arrayCopy(source, array) { - var index = -1, - length = source.length; - - array || (array = Array(length)); - while (++index < length) { - array[index] = source[index]; - } - return array; - } - /** * A specialized version of `_.forEach` for arrays without support for callback * shorthands and `this` binding. @@ -1768,30 +1749,8 @@ } /** - * Copies properties of `source` to `object`. - * - * @private - * @param {Object} source The object to copy properties from. - * @param {Array} props The property names to copy. - * @param {Object} [object={}] The object to copy properties to. - * @returns {Object} Returns `object`. - */ - function baseCopy(source, props, object) { - object || (object = {}); - - var index = -1, - length = props.length; - - while (++index < length) { - var key = props[index]; - object[key] = source[key]; - } - return object; - } - - /** - * The base implementation of `_.clone` without support for argument juggling - * and `this` binding `customizer` functions. + * The base implementation of `_.clone` and `_.cloneDeep` which tracks + * traversed objects. * * @private * @param {*} value The value to clone. @@ -1818,7 +1777,7 @@ if (isArr) { result = initCloneArray(value); if (!isDeep) { - return arrayCopy(value, result); + return copyArray(value, result); } } else { var tag = objToString.call(value), @@ -2491,7 +2450,7 @@ if (isArrayLike(srcValue) && (isArray(srcValue) || isTypedArray(srcValue))) { result = isArray(value) ? value - : (isArrayLike(value) ? arrayCopy(value) : []); + : (isArrayLike(value) ? copyArray(value) : []); } else if (isPlainObject(srcValue) || isArguments(srcValue)) { result = isArguments(value) @@ -2985,6 +2944,77 @@ return result; } + /** + * Copies the values of `source` to `array`. + * + * @private + * @param {Array} source The array to copy values from. + * @param {Array} [array=[]] The array to copy values to. + * @returns {Array} Returns `array`. + */ + function copyArray(source, array) { + var index = -1, + length = source.length; + + array || (array = Array(length)); + while (++index < length) { + array[index] = source[index]; + } + return array; + } + + /** + * Copies properties of `source` to `object`. + * + * @private + * @param {Object} source The object to copy properties from. + * @param {Array} props The property names to copy. + * @param {Object} [object={}] The object to copy properties to. + * @returns {Object} Returns `object`. + */ + function copyObject(source, props, object) { + object || (object = {}); + + var index = -1, + length = props.length; + + while (++index < length) { + var key = props[index]; + object[key] = source[key]; + } + return object; + } + + /** + * This function is like `copyObject` except that it accepts a function to + * customize copied values. + * + * @private + * @param {Object} source The object to copy properties from. + * @param {Array} props The property names to copy. + * @param {Function} customizer The function to customize copied values. + * @param {Object} [object={}] The object to copy properties to. + * @returns {Object} Returns `object`. + */ + function copyObjectWith(source, props, customizer, object) { + object || (object = {}); + + var index = -1, + length = props.length; + + while (++index < length) { + var key = props[index], + value = object[key], + result = customizer(value, source[key], key, object, source); + + if ((result === result ? (result !== value) : (value === value)) || + (value === undefined && !(key in object))) { + object[key] = result; + } + } + return object; + } + /** * Creates a `_.countBy`, `_.groupBy`, `_.indexBy`, or `_.partition` function. * @@ -3300,7 +3330,7 @@ length -= argsHolders.length; if (length < arity) { - var newArgPos = argPos ? arrayCopy(argPos) : undefined, + var newArgPos = argPos ? copyArray(argPos) : undefined, newArity = nativeMax(arity - length, 0), newsHolders = isCurry ? argsHolders : undefined, newHoldersRight = isCurry ? undefined : argsHolders, @@ -3453,7 +3483,7 @@ bitmask &= ~(PARTIAL_FLAG | PARTIAL_RIGHT_FLAG); partials = holders = undefined; } - length -= (holders ? holders.length : 0); + length -= holders ? holders.length : 0; if (bitmask & PARTIAL_RIGHT_FLAG) { var partialsRight = partials, holdersRight = holders; @@ -4011,20 +4041,20 @@ var value = source[3]; if (value) { var partials = data[3]; - data[3] = partials ? composeArgs(partials, value, source[4]) : arrayCopy(value); - data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : arrayCopy(source[4]); + data[3] = partials ? composeArgs(partials, value, source[4]) : copyArray(value); + data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : copyArray(source[4]); } // Compose partial right arguments. value = source[5]; if (value) { partials = data[5]; - data[5] = partials ? composeArgsRight(partials, value, source[6]) : arrayCopy(value); - data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : arrayCopy(source[6]); + data[5] = partials ? composeArgsRight(partials, value, source[6]) : copyArray(value); + data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : copyArray(source[6]); } // Use source `argPos` if available. value = source[7]; if (value) { - data[7] = arrayCopy(value); + data[7] = copyArray(value); } // Use source `ary` if it's smaller. if (srcBitmask & ARY_FLAG) { @@ -4110,7 +4140,7 @@ function reorder(array, indexes) { var arrLength = array.length, length = nativeMin(indexes.length, arrLength), - oldArray = arrayCopy(array); + oldArray = copyArray(array); while (length--) { var index = indexes[length]; @@ -4260,7 +4290,7 @@ function wrapperClone(wrapper) { return wrapper instanceof LazyWrapper ? wrapper.clone() - : new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__, arrayCopy(wrapper.__actions__)); + : new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__, copyArray(wrapper.__actions__)); } /*------------------------------------------------------------------------*/ @@ -8528,7 +8558,7 @@ } return (lodash.support.unindexedChars && isString(value)) ? value.split('') - : arrayCopy(value); + : copyArray(value); } /** @@ -8555,7 +8585,7 @@ * // => { 'a': 1, 'b': 2, 'c': 3 } */ function toPlainObject(value) { - return baseCopy(value, keysIn(value)); + return copyObject(value, keysIn(value)); } /*------------------------------------------------------------------------*/ From 2da1b2af1abe6d988c5a39dea6b687eb44ef5c56 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 9 Jul 2015 19:42:04 -0700 Subject: [PATCH 031/935] Drop boolean `orders` param support in `_.sortByOrder`. --- lodash.src.js | 6 +++--- test/test.js | 16 ++++++---------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 938c720df3..c2fa0d802d 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -473,7 +473,7 @@ return result; } var order = orders[index]; - return result * ((order === 'asc' || order === true) ? 1 : -1); + return result * (order === 'asc' ? 1 : -1); } } // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications @@ -2647,7 +2647,7 @@ * @private * @param {Array|Object|string} collection The collection to iterate over. * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. - * @param {boolean[]|string[]} orders The sort orders of `iteratees`. + * @param {string[]} orders The sort orders of `iteratees`. * @returns {Array} Returns the new sorted array. */ function baseSortByOrder(collection, iteratees, orders) { @@ -6679,7 +6679,7 @@ * @category Collection * @param {Array|Object|string} collection The collection to iterate over. * @param {Function[]|Object[]|string[]} [iteratees=[_.identity]] The iteratees to sort by. - * @param {boolean[]|string[]} [orders] The sort orders of `iteratees`. + * @param {string[]} [orders] The sort orders of `iteratees`. * @param- {Object} [guard] Enables use as an iteratee for functions like `_.reduce`. * @returns {Array} Returns the new sorted array. * @example diff --git a/test/test.js b/test/test.js index d24cb4085e..1b196ad3b3 100644 --- a/test/test.js +++ b/test/test.js @@ -14173,18 +14173,14 @@ { 'a': 'y', 'b': 2 } ]; - test('should sort multiple properties by specified orders', 2, function() { - _.each([[false, true], ['desc', 'asc']], function(orders) { - var actual = _.sortByOrder(objects, ['a', 'b'], orders); - deepEqual(actual, [objects[3], objects[1], objects[2], objects[0]]); - }); + test('should sort multiple properties by specified orders', 1, function() { + var actual = _.sortByOrder(objects, ['a', 'b'], ['desc', 'asc']); + deepEqual(actual, [objects[3], objects[1], objects[2], objects[0]]); }); - test('should sort a property in ascending order when its order is not specified', 2, function() { - _.each([[false], ['desc']], function(orders) { - var actual = _.sortByOrder(objects, ['a', 'b'], orders); - deepEqual(actual, [objects[3], objects[1], objects[2], objects[0]]); - }); + test('should sort a property in ascending order when its order is not specified', 1, function() { + var actual = _.sortByOrder(objects, ['a', 'b'], ['desc']); + deepEqual(actual, [objects[3], objects[1], objects[2], objects[0]]); }); }()); From ab26945eca3cb25b3797c01310fb6eb0a0752838 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 9 Jul 2015 19:45:12 -0700 Subject: [PATCH 032/935] Add `_.extend` and make it and `_.defaults`, `_.defaultsDeep`, and `_.merge` iterate over inherited properties. --- lodash.src.js | 119 ++++++++++++++++++++------------------------------ test/test.js | 48 ++++++++++---------- 2 files changed, 71 insertions(+), 96 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index c2fa0d802d..f21fd8376d 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -1646,68 +1646,8 @@ } /** - * Used by `_.defaults` to customize its `_.assign` use. - * - * @private - * @param {*} objectValue The destination object property value. - * @param {*} sourceValue The source object property value. - * @returns {*} Returns the value to assign to the destination object. - */ - function assignDefaults(objectValue, sourceValue) { - return objectValue === undefined ? sourceValue : objectValue; - } - - /** - * Used by `_.template` to customize its `_.assign` use. - * - * **Note:** This function is like `assignDefaults` except that it ignores - * inherited property values when checking if a property is `undefined`. - * - * @private - * @param {*} objectValue The destination object property value. - * @param {*} sourceValue The source object property value. - * @param {string} key The key associated with the object and source values. - * @param {Object} object The destination object. - * @returns {*} Returns the value to assign to the destination object. - */ - function assignOwnDefaults(objectValue, sourceValue, key, object) { - return (objectValue === undefined || !hasOwnProperty.call(object, key)) - ? sourceValue - : objectValue; - } - - /** - * A specialized version of `_.assign` for customizing assigned values without - * support for argument juggling, multiple sources, and `this` binding `customizer` - * functions. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @param {Function} customizer The function to customize assigned values. - * @returns {Object} Returns `object`. - */ - function assignWith(object, source, customizer) { - var index = -1, - props = keys(source), - length = props.length; - - while (++index < length) { - var key = props[index], - value = object[key], - result = customizer(value, source[key], key, object, source); - - if ((result === result ? (result !== value) : (value === value)) || - (value === undefined && !(key in object))) { - object[key] = result; - } - } - return object; - } - - /** - * The base implementation of `_.assign` without support for argument juggling, - * multiple sources, and `customizer` functions. + * The base implementation of `_.assign` without support for multiple sources + * and `customizer` functions. * * @private * @param {Object} object The destination object. @@ -1715,9 +1655,7 @@ * @returns {Object} Returns `object`. */ function baseAssign(object, source) { - return source == null - ? object - : baseCopy(source, keys(source), object); + return source == null ? object : copyObject(source, keys(source), object); } /** @@ -3658,6 +3596,18 @@ return true; } + /** + * Used by `_.defaults` to customize its `_.assign` use. + * + * @private + * @param {*} objectValue The destination object property value. + * @param {*} sourceValue The source object property value. + * @returns {*} Returns the value to assign to the destination object. + */ + function extendDefaults(objectValue, sourceValue) { + return objectValue === undefined ? sourceValue : objectValue; + } + /** * Gets metadata for `func`. * @@ -8642,7 +8592,7 @@ return object; } var isSrcArr = isArrayLike(source) && (isArray(source) || isTypedArray(source)), - props = isSrcArr ? undefined : keys(source); + props = isSrcArr ? undefined : keysIn(source); arrayEach(props || source, function(srcValue, key) { if (props) { @@ -8701,9 +8651,10 @@ * // => { 'user': 'barney', 'age': 36 } */ var assign = createAssigner(function(object, source, customizer) { + var props = keys(source); return customizer - ? assignWith(object, source, customizer) - : baseAssign(object, source); + ? copyObjectWith(source, props, customizer, object) + : copyObject(source, props, object) }); /** @@ -8771,8 +8722,8 @@ if (object == null) { return object; } - args.push(assignDefaults); - return assign.apply(undefined, args); + args.push(extendDefaults); + return extend.apply(undefined, args); }); /** @@ -8802,6 +8753,29 @@ return merge.apply(undefined, args); }); + /** + * This method is like `_.assign` except that it iterates over own and + * inherited source properties. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @param {Function} [customizer] The function to customize assigned values. + * @returns {Object} Returns `object`. + * @example + * + * _.extend({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' }); + * // => { 'user': 'fred', 'age': 40 } + */ + var extend = createAssigner(function(object, source, customizer) { + var props = keysIn(source); + return customizer + ? copyObjectWith(source, props, customizer, object) + : copyObject(source, props, object) + }); + /** * This method is like `_.find` except that it returns the key of the first * element `predicate` returns truthy for instead of the element itself. @@ -10238,9 +10212,9 @@ options = otherOptions = undefined; } string = baseToString(string); - options = assignWith(baseAssign({}, otherOptions || options), settings, assignOwnDefaults); + options = defaults({}, otherOptions || options, settings); - var imports = assignWith(baseAssign({}, options.imports), settings.imports, assignOwnDefaults), + var imports = defaults({}, options.imports, settings.imports), importsKeys = keys(imports), importsValues = baseValues(imports, importsKeys); @@ -11381,6 +11355,7 @@ lodash.dropRight = dropRight; lodash.dropRightWhile = dropRightWhile; lodash.dropWhile = dropWhile; + lodash.extend = extend; lodash.fill = fill; lodash.filter = filter; lodash.flatten = flatten; diff --git a/test/test.js b/test/test.js index 1b196ad3b3..943b58338d 100644 --- a/test/test.js +++ b/test/test.js @@ -1033,30 +1033,32 @@ /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.assign'); + QUnit.module('lodash.assign and lodash.extend'); - (function() { - test('should assign properties of a source object to the destination object', 1, function() { + _.each(['assign', 'extend'], function(methodName) { + var func = _[methodName]; + + test('`_.' + methodName + '` should assign properties of a source object to the destination object', 1, function() { deepEqual(_.assign({ 'a': 1 }, { 'b': 2 }), { 'a': 1, 'b': 2 }); }); - test('should accept multiple source objects', 2, function() { + test('`_.' + methodName + '` should accept multiple source objects', 2, function() { var expected = { 'a': 1, 'b': 2, 'c': 3 }; deepEqual(_.assign({ 'a': 1 }, { 'b': 2 }, { 'c': 3 }), expected); deepEqual(_.assign({ 'a': 1 }, { 'b': 2, 'c': 2 }, { 'c': 3 }), expected); }); - test('should overwrite destination properties', 1, function() { + test('`_.' + methodName + '` should overwrite destination properties', 1, function() { var expected = { 'a': 3, 'b': 2, 'c': 1 }; deepEqual(_.assign({ 'a': 1, 'b': 2 }, expected), expected); }); - test('should assign source properties with nullish values', 1, function() { + test('`_.' + methodName + '` should assign source properties with nullish values', 1, function() { var expected = { 'a': null, 'b': undefined, 'c': null }; deepEqual(_.assign({ 'a': 1, 'b': 2 }, expected), expected); }); - test('should work with a `customizer` callback', 1, function() { + test('`_.' + methodName + '` should work with a `customizer` callback', 1, function() { var actual = _.assign({ 'a': 1, 'b': 2 }, { 'a': 3, 'c': 3 }, function(a, b) { return typeof a == 'undefined' ? b : a; }); @@ -1064,11 +1066,11 @@ deepEqual(actual, { 'a': 1, 'b': 2, 'c': 3 }); }); - test('should work with a `customizer` that returns `undefined`', 1, function() { + test('`_.' + methodName + '` should work with a `customizer` that returns `undefined`', 1, function() { var expected = { 'a': undefined }; deepEqual(_.assign({}, expected, _.identity), expected); }); - }()); + }); /*--------------------------------------------------------------------------*/ @@ -2829,7 +2831,7 @@ asyncTest('subsequent "immediate" debounced calls return the last `func` result', 2, function() { if (!(isRhino && isModularize)) { - var debounced = _.debounce(_.identity, 32, true), + var debounced = _.debounce(_.identity, 32, { 'leading': true, 'trailing': false }), result = [debounced('x'), debounced('y')]; deepEqual(result, ['x', 'x']); @@ -3787,21 +3789,17 @@ QUnit.module('strict mode checks'); - _.each(['assign', 'bindAll', 'defaults'], function(methodName) { - var func = _[methodName]; + _.each(['assign', 'extend', 'bindAll', 'defaults'], function(methodName) { + var func = _[methodName], + isBindAll = methodName == 'bindAll'; test('`_.' + methodName + '` should ' + (isStrict ? '' : 'not ') + 'throw strict mode errors', 1, function() { if (freeze) { - var object = { 'a': undefined, 'b': function() {} }, + var object = freeze({ 'a': undefined, 'b': function() {} }), pass = !isStrict; - freeze(object); try { - if (methodName == 'bindAll') { - func(object); - } else { - func(object, { 'a': 1 }); - } + func(object, isBindAll ? 'b' : { 'a': 1 }); } catch(e) { pass = !pass; } @@ -5092,8 +5090,9 @@ QUnit.module('object assignments'); - _.each(['assign', 'defaults', 'merge'], function(methodName) { + _.each(['assign', 'defaults', 'extend', 'merge'], function(methodName) { var func = _[methodName], + isAssign = methodName == 'assign', isDefaults = methodName == 'defaults'; test('`_.' + methodName + '` should pass thru falsey `object` values', 1, function() { @@ -5104,13 +5103,14 @@ deepEqual(actual, falsey); }); - test('`_.' + methodName + '` should assign own source properties', 1, function() { + test('`_.' + methodName + '` should assign own ' + (isAssign ? '' : 'and inherited ') + 'source properties', 1, function() { function Foo() { this.a = 1; } Foo.prototype.b = 2; - deepEqual(func({}, new Foo), { 'a': 1 }); + var expected = isAssign ? { 'a': 1 } : { 'a': 1, 'b': 2 }; + deepEqual(func({}, new Foo), expected); }); test('`_.' + methodName + '` should assign problem JScript properties (test in IE < 9)', 1, function() { @@ -5189,7 +5189,7 @@ }); }); - _.each(['assign', 'merge'], function(methodName) { + _.each(['assign', 'extend', 'merge'], function(methodName) { var func = _[methodName], isMerge = methodName == 'merge'; @@ -17476,7 +17476,7 @@ var acceptFalsey = _.difference(allMethods, rejectFalsey); - test('should accept falsey arguments', 211, function() { + test('should accept falsey arguments', 212, function() { var emptyArrays = _.map(falsey, _.constant([])); _.each(acceptFalsey, function(methodName) { From d58cda122d7c9642907ded5e14daaea0fab78fe6 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 9 Jul 2015 19:48:44 -0700 Subject: [PATCH 033/935] Remove `_.bindAll` support for binding all methods when no method names are provided. --- lodash.src.js | 6 ++--- test/test.js | 61 ++++++++++++++------------------------------------- 2 files changed, 19 insertions(+), 48 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index f21fd8376d..134ddba606 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -6844,7 +6844,7 @@ * @memberOf _ * @category Function * @param {Object} object The object to bind and assign the bound methods to. - * @param {...(string|string[])} [methodNames] The object method names to bind, + * @param {...(string|string[])} methodNames The object method names to bind, * specified as individual method names or arrays of method names. * @returns {Object} Returns `object`. * @example @@ -6856,12 +6856,12 @@ * } * }; * - * _.bindAll(view); + * _.bindAll(view, 'onClick'); * jQuery('#docs').on('click', view.onClick); * // => logs 'clicked docs' when the element is clicked */ var bindAll = restParam(function(object, methodNames) { - methodNames = methodNames.length ? baseFlatten(methodNames) : functions(object); + methodNames = baseFlatten(methodNames); var index = -1, length = methodNames.length; diff --git a/test/test.js b/test/test.js index 943b58338d..91b2f41a6b 100644 --- a/test/test.js +++ b/test/test.js @@ -1503,37 +1503,22 @@ (function() { var args = arguments; - test('should bind all methods of `object`', 1, function() { - function Foo() { - this._a = 1; - this._b = 2; - this.a = function() { return this._a; }; - } - Foo.prototype.b = function() { return this._b; }; - - var object = new Foo; - _.bindAll(object); - - var actual = _.map(_.functions(object).sort(), function(methodName) { - return object[methodName].call({}); - }); - - deepEqual(actual, [1, 2]); - }); + var source = { + '_a': 1, + '_b': 2, + '_c': 3, + '_d': 4, + 'a': function() { return this._a; }, + 'b': function() { return this._b; }, + 'c': function() { return this._c; }, + 'd': function() { return this._d; } + }; test('should accept individual method names', 1, function() { - var object = { - '_a': 1, - '_b': 2, - '_c': 3, - 'a': function() { return this._a; }, - 'b': function() { return this._b; }, - 'c': function() { return this._c; } - }; - + var object = _.clone(source); _.bindAll(object, 'a', 'b'); - var actual = _.map(_.functions(object).sort(), function(methodName) { + var actual = _.map(['a', 'b', 'c'], function(methodName) { return object[methodName].call({}); }); @@ -1541,20 +1526,10 @@ }); test('should accept arrays of method names', 1, function() { - var object = { - '_a': 1, - '_b': 2, - '_c': 3, - '_d': 4, - 'a': function() { return this._a; }, - 'b': function() { return this._b; }, - 'c': function() { return this._c; }, - 'd': function() { return this._d; } - }; - + var object = _.clone(source); _.bindAll(object, ['a', 'b'], ['c']); - var actual = _.map(_.functions(object).sort(), function(methodName) { + var actual = _.map(['a', 'b', 'c', 'd'], function(methodName) { return object[methodName].call({}); }); @@ -1568,14 +1543,10 @@ }); test('should work with `arguments` objects as secondary arguments', 1, function() { - var object = { - '_a': 1, - 'a': function() { return this._a; } - }; - + var object = _.clone(source); _.bindAll(object, args); - var actual = _.map(_.functions(object).sort(), function(methodName) { + var actual = _.map(args, function(methodName) { return object[methodName].call({}); }); From 8cc19d908eb71cd4b82816eeae80639bf52e38b3 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 9 Jul 2015 19:51:11 -0700 Subject: [PATCH 034/935] Drop boolean `options` param support in `_.debounce` and `_.throttle`. --- lodash.src.js | 10 +++----- test/test.js | 65 +++++++++++++++++++-------------------------------- 2 files changed, 27 insertions(+), 48 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 134ddba606..88ed3ff87d 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -7093,6 +7093,7 @@ timeoutId, trailingCall, lastCalled = 0, + leading = false, maxWait = false, trailing = true; @@ -7100,10 +7101,7 @@ throw new TypeError(FUNC_ERROR_TEXT); } wait = wait < 0 ? 0 : (+wait || 0); - if (options === true) { - var leading = true; - trailing = false; - } else if (isObject(options)) { + if (isObject(options)) { leading = !!options.leading; maxWait = 'maxWait' in options && nativeMax(+options.maxWait || 0, wait); trailing = 'trailing' in options ? !!options.trailing : trailing; @@ -7686,9 +7684,7 @@ if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } - if (options === false) { - leading = false; - } else if (isObject(options)) { + if (isObject(options)) { leading = 'leading' in options ? !!options.leading : leading; trailing = 'trailing' in options ? !!options.trailing : trailing; } diff --git a/test/test.js b/test/test.js index 91b2f41a6b..faf9b314b0 100644 --- a/test/test.js +++ b/test/test.js @@ -2841,48 +2841,40 @@ } }); - asyncTest('should support a `leading` option', 7, function() { + asyncTest('should support a `leading` option', 5, function() { if (!(isRhino && isModularize)) { - var withLeading, - callCounts = [0, 0, 0]; + var callCounts = [0, 0]; - _.each([true, { 'leading': true }], function(options, index) { - var debounced = _.debounce(function(value) { - callCounts[index]++; - return value; - }, 32, options); + var withLeading = _.debounce(function(value) { + callCounts[0]++; + return value; + }, 32, { 'leading': true }); - if (index == 1) { - withLeading = debounced; - } - strictEqual(debounced('x'), 'x'); - }); + strictEqual(withLeading('x'), 'x'); - _.each([false, { 'leading': false }], function(options) { - var withoutLeading = _.debounce(_.identity, 32, options); - strictEqual(withoutLeading('x'), undefined); - }); + var withoutLeading = _.debounce(_.identity, 32, { 'leading': false }); + strictEqual(withoutLeading('x'), undefined); var withLeadingAndTrailing = _.debounce(function() { - callCounts[2]++; + callCounts[1]++; }, 32, { 'leading': true }); withLeadingAndTrailing(); withLeadingAndTrailing(); - strictEqual(callCounts[2], 1); + strictEqual(callCounts[1], 1); setTimeout(function() { - deepEqual(callCounts, [1, 1, 2]); + deepEqual(callCounts, [1, 2]); withLeading('x'); - strictEqual(callCounts[1], 2); + strictEqual(callCounts[0], 2); QUnit.start(); }, 64); } else { - skipTest(7); + skipTest(5); QUnit.start(); } }); @@ -15225,26 +15217,17 @@ } }); - test('should support a `leading` option', 4, function() { - _.each([true, { 'leading': true }], function(options) { - if (!(isRhino && isModularize)) { - var withLeading = _.throttle(_.identity, 32, options); - strictEqual(withLeading('a'), 'a'); - } - else { - skipTest(); - } - }); + test('should support a `leading` option', 2, function() { + if (!(isRhino && isModularize)) { + var withLeading = _.throttle(_.identity, 32, { 'leading': true }); + strictEqual(withLeading('a'), 'a'); - _.each([false, { 'leading': false }], function(options) { - if (!(isRhino && isModularize)) { - var withoutLeading = _.throttle(_.identity, 32, options); - strictEqual(withoutLeading('a'), undefined); - } - else { - skipTest(); - } - }); + var withoutLeading = _.throttle(_.identity, 32, { 'leading': false }); + strictEqual(withoutLeading('a'), undefined); + } + else { + skipTest(2); + } }); asyncTest('should support a `trailing` option', 6, function() { From a7b70008bab4010dc0aea993be8d1668dd608185 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 9 Jul 2015 19:52:18 -0700 Subject: [PATCH 035/935] Drop boolean `options` param support in `_.mixin`. --- lodash.src.js | 65 ++++++++++++++++++++++----------------------------- test/test.js | 9 +++---- 2 files changed, 33 insertions(+), 41 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 88ed3ff87d..300e693fd0 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -10804,52 +10804,43 @@ * // => ['e'] */ function mixin(object, source, options) { - if (options == null) { - var isObj = isObject(source), - props = isObj ? keys(source) : undefined, - methodNames = (props && props.length) ? baseFunctions(source, props) : undefined; - - if (!(methodNames ? methodNames.length : isObj)) { - methodNames = false; - options = source; - source = object; - object = this; - } - } - if (!methodNames) { + var props = keys(source), + methodNames = baseFunctions(source, props); + + if (options == null && + !(isObject(source) && (methodNames.length || !props.length))) { + options = source; + source = object; + object = this; methodNames = baseFunctions(source, keys(source)); } - var chain = true, + var chain = (isObject(options) && 'chain' in options) ? options.chain : true, index = -1, isFunc = isFunction(object), length = methodNames.length; - if (options === false) { - chain = false; - } else if (isObject(options) && 'chain' in options) { - chain = options.chain; - } while (++index < length) { var methodName = methodNames[index], func = source[methodName]; - object[methodName] = func; - if (isFunc) { - object.prototype[methodName] = (function(func) { - return function() { - var chainAll = this.__chain__; - if (chain || chainAll) { - var result = object(this.__wrapped__), - actions = result.__actions__ = arrayCopy(this.__actions__); - - actions.push({ 'func': func, 'args': arguments, 'thisArg': object }); - result.__chain__ = chainAll; - return result; - } - return func.apply(object, arrayPush([this.value()], arguments)); - }; - }(func)); - } + (function(func) { + object[methodName] = func; + if (!isFunc) { + return; + } + object.prototype[methodName] = function() { + var chainAll = this.__chain__; + if (chain || chainAll) { + var result = object(this.__wrapped__), + actions = result.__actions__ = copyArray(this.__actions__); + + actions.push({ 'func': func, 'args': arguments, 'thisArg': object }); + result.__chain__ = chainAll; + return result; + } + return func.apply(object, arrayPush([this.value()], arguments)); + }; + }(func)); } return object; } @@ -11547,7 +11538,7 @@ } }); return source; - }()), false); + }()), { 'chain': false }); /*------------------------------------------------------------------------*/ diff --git a/test/test.js b/test/test.js index faf9b314b0..e1dbf8cab8 100644 --- a/test/test.js +++ b/test/test.js @@ -10943,16 +10943,17 @@ function Foo() {} Foo.prototype.a = _.noop; - deepEqual(_.mixin({}, new Foo), {}); + var object = {}; + strictEqual(_.mixin(object, new Foo), object); }); - test('should accept an `options` argument', 16, function() { + test('should accept an `options` argument', 8, function() { function message(func, chain) { return (func === _ ? 'lodash' : 'provided') + ' function should ' + (chain ? '' : 'not ') + 'chain'; } _.each([_, Wrapper], function(func) { - _.each([false, true, { 'chain': false }, { 'chain': true }], function(options) { + _.each([{ 'chain': false }, { 'chain': true }], function(options) { if (!isNpm) { if (func === _) { _.mixin(source, options); @@ -10962,7 +10963,7 @@ var wrapped = func(array), actual = wrapped.a(); - if (options === true || (options && options.chain)) { + if (options.chain) { strictEqual(actual.value(), 'a', message(func, true)); ok(actual instanceof func, message(func, true)); } else { From 6cde31f8430198563066d26339b4dd5149754c1b Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 9 Jul 2015 19:55:42 -0700 Subject: [PATCH 036/935] Remove doc references to `this` bindings and other dropped features. [ci skip] --- lodash.src.js | 67 +++++++++++++++++++++------------------------------ 1 file changed, 27 insertions(+), 40 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 300e693fd0..592cfcc872 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -318,7 +318,7 @@ /** * The base implementation of `_.findIndex` and `_.findLastIndex` without - * support for callback shorthands and `this` binding. + * support for callback shorthands. * * @private * @param {Array} array The array to search. @@ -1777,8 +1777,8 @@ }()); /** - * The base implementation of `_.delay` and `_.defer` which accepts an index - * of where to slice the arguments to provide to `func`. + * The base implementation of `_.delay` and `_.defer` which accepts an array + * of `func` arguments. * * @private * @param {Function} func The function to delay. @@ -1841,8 +1841,7 @@ } /** - * The base implementation of `_.forEach` without support for callback - * shorthands and `this` binding. + * The base implementation of `_.forEach` without support for callback shorthands. * * @private * @param {Array|Object|string} collection The collection to iterate over. @@ -1852,8 +1851,7 @@ var baseEach = createBaseEach(baseForOwn); /** - * The base implementation of `_.forEachRight` without support for callback - * shorthands and `this` binding. + * The base implementation of `_.forEachRight` without support for callback shorthands. * * @private * @param {Array|Object|string} collection The collection to iterate over. @@ -1863,8 +1861,7 @@ var baseEachRight = createBaseEach(baseForOwnRight, true); /** - * The base implementation of `_.every` without support for callback - * shorthands and `this` binding. + * The base implementation of `_.every` without support for callback shorthands. * * @private * @param {Array|Object|string} collection The collection to iterate over. @@ -1911,8 +1908,7 @@ } /** - * The base implementation of `_.filter` without support for callback - * shorthands and `this` binding. + * The base implementation of `_.filter` without support for callback shorthands. * * @private * @param {Array|Object|string} collection The collection to iterate over. @@ -1931,8 +1927,8 @@ /** * The base implementation of `_.find`, `_.findLast`, `_.findKey`, and `_.findLastKey`, - * without support for callback shorthands and `this` binding, which iterates - * over `collection` using the provided `eachFunc`. + * without support for callback shorthands, which iterates over `collection` + * using the provided `eachFunc`. * * @private * @param {Array|Object|string} collection The collection to search. @@ -1953,8 +1949,7 @@ } /** - * The base implementation of `_.flatten` with added support for restricting - * flattening and specifying the start index. + * The base implementation of `_.flatten` with support for restricting flattening. * * @private * @param {Array} array The array to flatten. @@ -1987,8 +1982,7 @@ } /** - * The base implementation of `_.iteratee` which supports specifying the - * number of arguments to provide to `func`. + * The base implementation of `_.iteratee`. * * @private * @param {*} [func=_.identity] The value to convert to an iteratee. @@ -2037,8 +2031,7 @@ var baseForRight = createBaseFor(true); /** - * The base implementation of `_.forIn` without support for callback - * shorthands and `this` binding. + * The base implementation of `_.forIn` without support for callback shorthands. * * @private * @param {Object} object The object to iterate over. @@ -2050,8 +2043,7 @@ } /** - * The base implementation of `_.forOwn` without support for callback - * shorthands and `this` binding. + * The base implementation of `_.forOwn` without support for callback shorthands. * * @private * @param {Object} object The object to iterate over. @@ -2063,8 +2055,7 @@ } /** - * The base implementation of `_.forOwnRight` without support for callback - * shorthands and `this` binding. + * The base implementation of `_.forOwnRight` without support for callback shorthands. * * @private * @param {Object} object The object to iterate over. @@ -2100,8 +2091,7 @@ } /** - * The base implementation of `get` without support for string paths - * and default values. + * The base implementation of `get` without support for string paths and default values. * * @private * @param {Object} object The object to query. @@ -2127,8 +2117,8 @@ } /** - * The base implementation of `_.isEqual` without support for `this` binding - * `customizer` functions. + * The base implementation of `_.isEqual` which supports partial comparisons + * and tracks traversed objects. * * @private * @param {*} value The value to compare. @@ -2228,8 +2218,7 @@ } /** - * The base implementation of `_.isMatch` without support for callback - * shorthands and `this` binding. + * The base implementation of `_.isMatch` without support for callback shorthands. * * @private * @param {Object} object The object to inspect. @@ -2276,8 +2265,7 @@ } /** - * The base implementation of `_.map` without support for callback shorthands - * and `this` binding. + * The base implementation of `_.map` without support for callback shorthands. * * @private * @param {Array|Object|string} collection The collection to iterate over. @@ -2462,8 +2450,8 @@ } /** - * The base implementation of `_.random` without support for argument juggling - * and returning floating-point numbers. + * The base implementation of `_.random` without support for returning + * floating-point numbers. * * @private * @param {number} min The minimum possible value. @@ -2476,8 +2464,8 @@ /** * The base implementation of `_.reduce` and `_.reduceRight` without support - * for callback shorthands and `this` binding, which iterates over `collection` - * using the provided `eachFunc`. + * for callback shorthands, which iterates over `collection` using the provided + * `eachFunc`. * * @private * @param {Array|Object|string} collection The collection to iterate over. @@ -2541,8 +2529,7 @@ } /** - * The base implementation of `_.some` without support for callback shorthands - * and `this` binding. + * The base implementation of `_.some` without support for callback shorthands. * * @private * @param {Array|Object|string} collection The collection to iterate over. @@ -2609,8 +2596,8 @@ } /** - * The base implementation of `_.uniq` without support for callback shorthands - * and `this` binding. + * The base implementation of `_.uniq` and `_.uniqBy` without support for + * callback shorthands. * * @private * @param {Array} array The array to inspect. @@ -2683,7 +2670,7 @@ /** * The base implementation of `_.dropRightWhile`, `_.dropWhile`, `_.takeRightWhile`, - * and `_.takeWhile` without support for callback shorthands and `this` binding. + * and `_.takeWhile` without support for callback shorthands. * * @private * @param {Array} array The array to query. From 3e14d8f4dd22597a7081a7cd25ae9dccc7f374d3 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 9 Jul 2015 19:57:19 -0700 Subject: [PATCH 037/935] Minor doc formatting nits for `pickByArray` and `pickByPredicate`. [ci skip] --- lodash.src.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 592cfcc872..5b81b916e7 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -4021,8 +4021,8 @@ } /** - * A specialized version of `_.pick` which picks `object` properties specified - * by `props`. + * A specialized version of `_.pick` which picks `object` properties + * specified by `props`. * * @private * @param {Object} object The source object. @@ -4046,8 +4046,8 @@ } /** - * A specialized version of `_.pick` which picks `object` properties `predicate` - * returns truthy for. + * A specialized version of `_.pick` which picks `object` properties + * `predicate` returns truthy for. * * @private * @param {Object} object The source object. From c75ac3ac649ed97dd35d442e2909f5bc5ee371fc Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Fri, 10 Jul 2015 00:24:23 -0700 Subject: [PATCH 038/935] Simplify nullish and falsey checks. --- lodash.src.js | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 5b81b916e7..d78e63e777 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -1655,7 +1655,7 @@ * @returns {Object} Returns `object`. */ function baseAssign(object, source) { - return source == null ? object : copyObject(source, keys(source), object); + return object && copyObject(source, keys(source), object); } /** @@ -2039,7 +2039,7 @@ * @returns {Object} Returns `object`. */ function baseForIn(object, iteratee) { - return baseFor(object, iteratee, keysIn); + return object == null ? object : baseFor(object, iteratee, keysIn); } /** @@ -2051,7 +2051,7 @@ * @returns {Object} Returns `object`. */ function baseForOwn(object, iteratee) { - return baseFor(object, iteratee, keys); + return object && baseFor(object, iteratee, keys); } /** @@ -2063,7 +2063,7 @@ * @returns {Object} Returns `object`. */ function baseForOwnRight(object, iteratee) { - return baseForRight(object, iteratee, keys); + return object && baseForRight(object, iteratee, keys); } /** @@ -4128,16 +4128,18 @@ * @returns {Array} Returns the array of property names. */ function shimKeys(object) { - var props = keysIn(object), + var result = []; + if (!object) { + return result; + } + var index = -1, + props = keysIn(object), propsLength = props.length, length = propsLength && object.length; var allowIndexes = !!length && isLength(length) && (isArray(object) || isArguments(object) || isString(object)); - var index = -1, - result = []; - while (++index < propsLength) { var key = props[index]; if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) { @@ -6509,8 +6511,10 @@ * // => 7 */ function size(collection) { - var length = collection ? getLength(collection) : 0; - return isLength(length) ? length : keys(collection).length; + if (collection == null) { + return 0; + } + return isArrayLike(collection) ? collection.length : keys(collection).length; } /** @@ -8860,7 +8864,7 @@ * // => logs 'a', 'b', then 'c' (iteration order is not guaranteed) */ function forIn(object, iteratee) { - return baseFor(object, toFunction(iteratee), keysIn); + return object == null ? object : baseFor(object, toFunction(iteratee), keysIn); } /** @@ -8888,7 +8892,7 @@ * // => logs 'c', 'b', then 'a' assuming `_.forIn` logs 'a', 'b', then 'c' */ function forInRight(object, iteratee) { - return baseForRight(object, toFunction(iteratee), keysIn); + return object == null ? object : baseForRight(object, toFunction(iteratee), keysIn); } /** @@ -8918,7 +8922,7 @@ * // => logs 'a' then 'b' (iteration order is not guaranteed) */ function forOwn(object, iteratee) { - return baseForOwn(object, toFunction(iteratee)); + return object && baseForOwn(object, toFunction(iteratee)); } /** @@ -8946,7 +8950,7 @@ * // => logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b' */ function forOwnRight(object, iteratee) { - return baseForOwnRight(object, toFunction(iteratee)); + return object && baseForOwnRight(object, toFunction(iteratee)); } /** @@ -8964,7 +8968,7 @@ * // => ['after', 'ary', 'assign', ...] */ function functions(object) { - return baseFunctions(object, keysIn(object)); + return object == null ? [] : baseFunctions(object, keysIn(object)); } /** @@ -9114,7 +9118,10 @@ * // => ['0', '1'] */ var keys = !nativeKeys ? shimKeys : function(object) { - var Ctor = object == null ? undefined : object.constructor; + if (!object) { + return []; + } + var Ctor = object.constructor; if ((typeof Ctor == 'function' && Ctor.prototype === object) || (typeof object == 'function' ? lodash.support.enumPrototypes : isArrayLike(object))) { return shimKeys(object); @@ -9529,7 +9536,7 @@ * // => ['h', 'i'] */ function values(object) { - return baseValues(object, keys(object)); + return object ? baseValues(object, keys(object)) : []; } /** @@ -9556,7 +9563,7 @@ * // => [1, 2, 3] (iteration order is not guaranteed) */ function valuesIn(object) { - return baseValues(object, keysIn(object)); + return object == null ? baseValues(object, keysIn(object)) : []; } /*------------------------------------------------------------------------*/ From 31a7ac1e817da0c25f024f9d11d94da86217dcf9 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Fri, 10 Jul 2015 00:28:49 -0700 Subject: [PATCH 039/935] Ensure `_.assign`, `_.extend`, `_.defaults`, and `_.merge` coerce values to objects. --- lodash.src.js | 39 +++++++++++++++++++-------------------- test/test.js | 13 ++++++++----- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index d78e63e777..fb46a84231 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -2989,6 +2989,7 @@ customizer = length < 3 ? undefined : customizer; length = 1; } + object = toObject(object); while (++index < length) { var source = sources[index]; if (source) { @@ -4017,7 +4018,12 @@ * @returns {*} Returns the value to assign to the destination object. */ function mergeDefaults(objectValue, sourceValue) { - return objectValue === undefined ? sourceValue : merge(objectValue, sourceValue, mergeDefaults); + if (objectValue === undefined) { + return sourceValue; + } + return isObject(objectValue) + ? merge(objectValue, sourceValue, mergeDefaults) + : objectValue; } /** @@ -8575,9 +8581,6 @@ * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] } */ var merge = createAssigner(function baseMerge(object, source, customizer, stackA, stackB) { - if (!isObject(object)) { - return object; - } var isSrcArr = isArrayLike(source) && (isArray(source) || isTypedArray(source)), props = isSrcArr ? undefined : keysIn(source); @@ -8639,9 +8642,11 @@ */ var assign = createAssigner(function(object, source, customizer) { var props = keys(source); - return customizer - ? copyObjectWith(source, props, customizer, object) - : copyObject(source, props, object) + if (customizer) { + copyObjectWith(source, props, customizer, object); + } else { + copyObject(source, props, object); + } }); /** @@ -8705,11 +8710,7 @@ * // => { 'user': 'barney', 'age': 36 } */ var defaults = restParam(function(args) { - var object = args[0]; - if (object == null) { - return object; - } - args.push(extendDefaults); + args.push(undefined, extendDefaults); return extend.apply(undefined, args); }); @@ -8732,11 +8733,7 @@ * */ var defaultsDeep = restParam(function(args) { - var object = args[0]; - if (object == null) { - return object; - } - args.push(mergeDefaults); + args.push(undefined, mergeDefaults); return merge.apply(undefined, args); }); @@ -8758,9 +8755,11 @@ */ var extend = createAssigner(function(object, source, customizer) { var props = keysIn(source); - return customizer - ? copyObjectWith(source, props, customizer, object) - : copyObject(source, props, object) + if (customizer) { + copyObjectWith(source, props, customizer, object); + } else { + copyObject(source, props, object); + } }); /** diff --git a/test/test.js b/test/test.js index e1dbf8cab8..93d9caf282 100644 --- a/test/test.js +++ b/test/test.js @@ -5058,12 +5058,15 @@ isAssign = methodName == 'assign', isDefaults = methodName == 'defaults'; - test('`_.' + methodName + '` should pass thru falsey `object` values', 1, function() { + test('`_.' + methodName + '` should coerce primitives to objects', 1, function() { + var expected = _.map(falsey, _.constant(true)); + var actual = _.map(falsey, function(object, index) { - return index ? func(object) : func(); + var result = index ? func(object) : func(); + return _.isEqual(result, Object(object)); }); - deepEqual(actual, falsey); + deepEqual(actual, expected); }); test('`_.' + methodName + '` should assign own ' + (isAssign ? '' : 'and inherited ') + 'source properties', 1, function() { @@ -5122,7 +5125,7 @@ var actual = _.map([null, undefined], function(value) { try { - return _.isEqual(func(value, { 'a': 1 }), value); + return _.isEqual(func(value, { 'a': 1 }), {}); } catch(e) { return false; } @@ -11667,7 +11670,7 @@ expected = { 'a': { 'b': 1, 'c': 3 } }; var defaultsDeep = _.partialRight(_.merge, function deep(value, other) { - return _.merge(value, other, deep); + return _.isObject(value) ? _.merge(value, other, deep) : value; }); deepEqual(defaultsDeep(object, source), expected); From 06bc4aa50b5fc7fa6f14e54c14b44b61d917cb0e Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Fri, 10 Jul 2015 00:30:59 -0700 Subject: [PATCH 040/935] Make `isArayLike` return `false` for functions. --- lodash.src.js | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index fb46a84231..fbe8ba1d19 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -3010,11 +3010,14 @@ */ function createBaseEach(eachFunc, fromRight) { return function(collection, iteratee) { - var length = collection ? getLength(collection) : 0; - if (!isLength(length)) { + if (collection == null) { + return collection; + } + if (!isArrayLike(collection)) { return eachFunc(collection, iteratee); } - var index = fromRight ? length : -1, + var length = collection.length, + index = fromRight ? length : -1, iterable = toObject(collection); while ((fromRight ? index-- : ++index < length)) { @@ -3833,7 +3836,7 @@ * @returns {boolean} Returns `true` if `value` is array-like, else `false`. */ function isArrayLike(value) { - return value != null && isLength(getLength(value)); + return value != null && typeof value != 'function' && isLength(getLength(value)); } /** @@ -6157,11 +6160,8 @@ * // => true */ function includes(collection, target, fromIndex, guard) { - var length = collection ? getLength(collection) : 0; - if (!isLength(length)) { - collection = values(collection); - length = collection.length; - } + collection = isArrayLike(collection) ? collection : values(collection); + var length = collection.length; if (typeof fromIndex != 'number' || (guard && isIterateeCall(target, fromIndex, guard))) { fromIndex = 0; } else { @@ -8492,11 +8492,10 @@ * // => [2, 3] */ function toArray(value) { - var length = value ? getLength(value) : 0; - if (!isLength(length)) { + if (!isArrayLike(value)) { return values(value); } - if (!length) { + if (!value.length) { return []; } return (lodash.support.unindexedChars && isString(value)) From 4bae0c0139d4da4529238e287685c95fe5f4d7ae Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Fri, 10 Jul 2015 00:31:18 -0700 Subject: [PATCH 041/935] Minor formatting nit for `_.without`. --- lodash.src.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index fbe8ba1d19..a57aae42f0 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -5437,9 +5437,7 @@ * // => [3] */ var without = restParam(function(array, values) { - return isArrayLike(array) - ? baseDifference(array, values) - : []; + return isArrayLike(array) ? baseDifference(array, values) : []; }); /** From 64b9402e120d4df9ecbe780d546d96589cd8f90d Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Fri, 10 Jul 2015 08:36:07 -0700 Subject: [PATCH 042/935] Strict equal nit in `_.uniq`. --- lodash.src.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lodash.src.js b/lodash.src.js index a57aae42f0..524a38b803 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -5302,7 +5302,7 @@ if (!length) { return []; } - return (isSorted && typeof isSorted == 'boolean' && getIndexOf() == baseIndexOf) + return (isSorted && typeof isSorted == 'boolean' && getIndexOf() === baseIndexOf) ? sortedUniq(array) : baseUniq(array); } From 2e91cf727a4b05857e4b9bb5e1ea70d1fdc8b62e Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Fri, 10 Jul 2015 22:43:43 -0700 Subject: [PATCH 043/935] Simplify `checkGlobal`. --- lodash.src.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lodash.src.js b/lodash.src.js index 524a38b803..f8f093adb1 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -429,7 +429,7 @@ * @returns {null|Object} Returns `value` if it's a global object, else `null`. */ function checkGlobal(value) { - return (objectTypes[typeof value] && value && value.Object) ? value : null; + return (value && value.Object) ? value : null; } /** From 6d231fecd13e5bfb5c8fbbbe99c54389aa2175da Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Fri, 10 Jul 2015 22:46:47 -0700 Subject: [PATCH 044/935] Update html indent style in .editorconfig. --- .editorconfig | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.editorconfig b/.editorconfig index b2e3d806d9..ec3ebbd690 100644 --- a/.editorconfig +++ b/.editorconfig @@ -4,15 +4,14 @@ root = true [*] -end_of_line = lf charset = utf-8 +end_of_line = lf +indent_size = 2 +indent_style = space trim_trailing_whitespace = true [**.{js,json,md}] -indent_style = space -indent_size = 2 insert_final_newline = true [**.html] -indent_style = tab insert_final_newline = false From 56452d9fd82d85a193dade708c41457bb037f801 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sat, 11 Jul 2015 15:36:02 -0700 Subject: [PATCH 045/935] Document `start` and `end` swap for `_.inRange`. [ci skip] [closes #1332] --- lodash.src.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lodash.src.js b/lodash.src.js index f8f093adb1..52aba5e798 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -9567,6 +9567,8 @@ /** * Checks if `n` is between `start` and up to but not including, `end`. If * `end` is not specified it's set to `start` with `start` then set to `0`. + * If `start` is greater than `end` the params are swapped to support + * negative ranges. * * @static * @memberOf _ @@ -9594,6 +9596,9 @@ * * _.inRange(5.2, 4); * // => false + * + * _.inRange(-3, -2, -6); + * // => true */ function inRange(value, start, end) { start = +start || 0; From 974306d4f08fc667d79b28351461df9ffe5e9a01 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sun, 12 Jul 2015 10:08:57 -0700 Subject: [PATCH 046/935] Generalize the unwrapped value path in lazy method wrappers a bit. --- lodash.src.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 52aba5e798..5769531f9d 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -11680,9 +11680,8 @@ isLazy = useLazy = false; } var interceptor = function(value) { - return (retUnwrapped && chainAll) - ? lodashFunc(value, 1)[0] - : lodashFunc.apply(undefined, arrayPush([value], args)); + var result = lodashFunc.apply(lodash, arrayPush([value], args)); + return (retUnwrapped && chainAll) ? result[0] : result; }; var action = { 'func': thru, 'args': [interceptor], 'thisArg': undefined }, @@ -11692,13 +11691,14 @@ if (onlyLazy) { value = value.clone(); value.__actions__.push(action); - return func.call(value); + return func.apply(this, args); } - return lodashFunc.call(undefined, this.value())[0]; + var result = lodashFunc.apply(lodash, arrayPush([this.value()], args)); + return result[0]; } if (!retUnwrapped && useLazy) { value = onlyLazy ? value : new LazyWrapper(this); - var result = func.apply(value, args); + result = func.apply(value, args); result.__actions__.push(action); return new LodashWrapper(result, chainAll); } From fd526e8754b47fd98e137eb25ce56d35929ddb43 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sun, 12 Jul 2015 15:40:48 -0700 Subject: [PATCH 047/935] Split `_.omit` and `_.pick` into `_.omitBy` and `_.pickBy`. --- lodash.src.js | 171 ++++++++++++++++++++++++++-------------------- test/test.js | 183 ++++++++++++++++++++++++++++---------------------- 2 files changed, 198 insertions(+), 156 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 5769531f9d..fa1c4984e9 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -2400,6 +2400,48 @@ } } + /** + * The base implementation of `_.pick` without support for individual property names. + * + * @private + * @param {Object} object The source object. + * @param {string[]} props The property names to pick. + * @returns {Object} Returns the new object. + */ + function basePick(object, props) { + object = toObject(object); + + var index = -1, + length = props.length, + result = {}; + + while (++index < length) { + var key = props[index]; + if (key in object) { + result[key] = object[key]; + } + } + return result; + } + + /** + * The base implementation of `_.pickBy` without support for callback shorthands. + * + * @private + * @param {Object} object The source object. + * @param {Function} predicate The function invoked per iteration. + * @returns {Object} Returns the new object. + */ + function basePickBy(object, predicate) { + var result = {}; + baseForIn(object, function(value, key, object) { + if (predicate(value, key, object)) { + result[key] = value; + } + }); + return result; + } + /** * The base implementation of `_.property` without support for deep paths. * @@ -4029,50 +4071,6 @@ : objectValue; } - /** - * A specialized version of `_.pick` which picks `object` properties - * specified by `props`. - * - * @private - * @param {Object} object The source object. - * @param {string[]} props The property names to pick. - * @returns {Object} Returns the new object. - */ - function pickByArray(object, props) { - object = toObject(object); - - var index = -1, - length = props.length, - result = {}; - - while (++index < length) { - var key = props[index]; - if (key in object) { - result[key] = object[key]; - } - } - return result; - } - - /** - * A specialized version of `_.pick` which picks `object` properties - * `predicate` returns truthy for. - * - * @private - * @param {Object} object The source object. - * @param {Function} predicate The function invoked per iteration. - * @returns {Object} Returns the new object. - */ - function pickByPredicate(object, predicate) { - var result = {}; - baseForIn(object, function(value, key, object) { - if (predicate(value, key, object)) { - result[key] = value; - } - }); - return result; - } - /** * Reorder `array` according to the specified indexes where the element at * the first index is assigned as the first element, the element at @@ -9275,9 +9273,8 @@ * @memberOf _ * @category Object * @param {Object} object The source object. - * @param {Function|...(string|string[])} [predicate] The function invoked per - * iteration or property names to omit, specified as individual property - * names or arrays of property names. + * @param {string|string[]} [props] The property names to omit, specified as + * individual property names or arrays of property names. * @returns {Object} Returns the new object. * @example * @@ -9285,23 +9282,39 @@ * * _.omit(object, 'age'); * // => { 'user': 'fred' } - * - * _.omit(object, _.isNumber); - * // => { 'user': 'fred' } */ var omit = restParam(function(object, props) { if (object == null) { return {}; } - if (typeof props[0] != 'function') { - var props = arrayMap(baseFlatten(props), String); - return pickByArray(object, baseDifference(keysIn(object), props)); - } - var predicate = props[0]; - return pickByPredicate(object, function(value, key, object) { + var props = arrayMap(baseFlatten(props), String); + return basePick(object, baseDifference(keysIn(object), props)); + }); + + /** + * The opposite of `_.pickBy`; this method creates an object composed of the + * own and inherited enumerable properties of `object` that `predicate` does + * not return truthy for. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The source object. + * @param {Function|Object|string} [predicate=_.identity] The function invoked per iteration. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'user': 'fred', 'age': 40 }; + * + * _.omitBy(object, _.isNumber); + * // => { 'user': 'fred' } + */ + function omitBy(object, predicate) { + predicate = getIteratee(predicate); + return basePickBy(object, function(value, key, object) { return !predicate(value, key, object); }); - }); + } /** * Creates a two dimensional array of the key-value pairs for `object`, @@ -9333,19 +9346,14 @@ } /** - * Creates an object composed of the picked `object` properties. Property - * names may be specified as individual arguments or as arrays of property - * names. If `predicate` is provided it's invoked for each property of `object` - * picking the properties `predicate` returns truthy for. The predicate is - * invoked with three arguments: (value, key, object). + * Creates an object composed of the picked `object` properties. * * @static * @memberOf _ * @category Object * @param {Object} object The source object. - * @param {Function|...(string|string[])} [predicate] The function invoked per - * iteration or property names to pick, specified as individual property - * names or arrays of property names. + * @param {string|string[]} [props] The property names to pick, specified as + * individual property names or arrays of property names. * @returns {Object} Returns the new object. * @example * @@ -9353,19 +9361,32 @@ * * _.pick(object, 'user'); * // => { 'user': 'fred' } - * - * _.pick(object, _.isString); - * // => { 'user': 'fred' } */ var pick = restParam(function(object, props) { - if (object == null) { - return {}; - } - return typeof props[0] == 'function' - ? pickByPredicate(object, props[0]) - : pickByArray(object, baseFlatten(props)); + return object == null ? {} : basePick(object, baseFlatten(props)); }); + /** + * Creates an object composed of the `object` properties `predicate` returns + * truthy for. The predicate is invoked with three arguments: (value, key, object). + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The source object. + * @param {Function|Object|string} [predicate=_.identity] The function invoked per iteration. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'user': 'fred', 'age': 40 }; + * + * _.pickBy(object, _.isString); + * // => { 'user': 'fred' } + */ + function pickBy(object, predicate) { + return object == null ? {} : basePickBy(object, getIteratee(predicate)); + } + /** * This method is like `_.get` except that if the resolved value is a function * it's invoked with the `this` binding of its parent object and its result @@ -11367,12 +11388,14 @@ lodash.modArgs = modArgs; lodash.negate = negate; lodash.omit = omit; + lodash.omitBy = omitBy; lodash.once = once; lodash.pairs = pairs; lodash.partial = partial; lodash.partialRight = partialRight; lodash.partition = partition; lodash.pick = pick; + lodash.pickBy = pickBy; lodash.property = property; lodash.propertyOf = propertyOf; lodash.pull = pull; diff --git a/test/test.js b/test/test.js index 93d9caf282..05645729f7 100644 --- a/test/test.js +++ b/test/test.js @@ -4642,9 +4642,9 @@ 'mapValues', 'maxBy', 'minBy', - 'omit', + 'omitBy', 'partition', - 'pick', + 'pickBy', 'reject', 'some' ]; @@ -4678,8 +4678,8 @@ var forInMethods = [ 'forIn', 'forInRight', - 'omit', - 'pick' + 'omitBy', + 'pickBy' ]; var iterationMethods = [ @@ -4701,8 +4701,8 @@ 'forOwnRight', 'mapKeys', 'mapValues', - 'omit', - 'pick' + 'omitBy', + 'pickBy' ]; var rightMethods = [ @@ -4742,7 +4742,7 @@ isFind = /^find/.test(methodName), isSome = methodName == 'some'; - test('`_.' + methodName + '` should provide the correct `iteratee` arguments', 1, function() { + test('`_.' + methodName + '` should provide the correct iteratee arguments', 1, function() { if (func) { var args, expected = [1, 0, array]; @@ -11211,23 +11211,21 @@ (function() { var args = arguments, - object = { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, - expected = { 'b': 2, 'd': 4 }; + object = { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }; - test('should create an object with omitted properties', 2, function() { - deepEqual(_.omit(object, 'a'), { 'b': 2, 'c': 3, 'd': 4 }); - deepEqual(_.omit(object, 'a', 'c'), expected); - }); - - test('should flatten `props`', 1, function() { + test('should flatten `props`', 2, function() { + deepEqual(_.omit(object, 'a', 'c'), { 'b': 2, 'd': 4 }); deepEqual(_.omit(object, ['a', 'd'], 'c'), { 'b': 2 }); }); - test('should iterate over inherited properties', 1, function() { - function Foo() {} - Foo.prototype = object; + test('should work with a primitive `object` argument', 1, function() { + stringProto.a = 1; + stringProto.b = 2; + + deepEqual(_.omit('', 'b'), { 'a': 1 }); - deepEqual(_.omit(new Foo, 'a', 'c'), expected); + delete stringProto.a; + delete stringProto.b; }); test('should return an empty object when `object` is nullish', 2, function() { @@ -11239,51 +11237,62 @@ }); test('should work with `arguments` objects as secondary arguments', 1, function() { - deepEqual(_.omit(object, args), expected); + deepEqual(_.omit(object, args), { 'b': 2, 'd': 4 }); }); - test('should work with an array `object` argument', 1, function() { - deepEqual(_.omit([1, 2, 3], '0', '2'), { '1': 2 }); + test('should coerce property names to strings', 1, function() { + deepEqual(_.omit({ '0': 'a' }, 0), {}); }); + }('a', 'c')); - test('should work with a primitive `object` argument', 1, function() { - stringProto.a = 1; - stringProto.b = 2; + /*--------------------------------------------------------------------------*/ - deepEqual(_.omit('', 'b'), { 'a': 1 }); - - delete stringProto.a; - delete stringProto.b; - }); + QUnit.module('lodash.omitBy'); + (function() { test('should work with a predicate argument', 1, function() { - var actual = _.omit(object, function(num) { + var object = { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }; + + var actual = _.omitBy(object, function(num) { return num != 2 && num != 4; }); - deepEqual(actual, expected); + deepEqual(actual, { 'b': 2, 'd': 4 }); }); + }()); - test('should provide the correct predicate arguments', 1, function() { - var args, - object = { 'a': 1, 'b': 2 }, - lastKey = _.keys(object).pop(); + /*--------------------------------------------------------------------------*/ - var expected = lastKey == 'b' - ? [1, 'a', object] - : [2, 'b', object]; + QUnit.module('omit methods'); - _.omit(object, function() { - args || (args = slice.call(arguments)); - }); + _.each(['omit', 'omitBy'], function(methodName) { + var expected = { 'b': 2, 'd': 4 }, + func = _[methodName], + object = { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }; - deepEqual(args, expected); + var prop = methodName == 'omit' ? _.identity : function(props) { + props = typeof props == 'string' ? [props] : props; + return function(value, key) { + return _.includes(props, key); + }; + }; + + test('`_.' + methodName + '` should create an object with omitted properties', 2, function() { + deepEqual(func(object, prop('a')), { 'b': 2, 'c': 3, 'd': 4 }); + deepEqual(func(object, prop(['a', 'c'])), expected); }); - test('should coerce property names to strings', 1, function() { - deepEqual(_.omit({ '0': 'a' }, 0), {}); + test('`_.' + methodName + '` should iterate over inherited properties', 1, function() { + function Foo() {} + Foo.prototype = object; + + deepEqual(func(new Foo, prop(['a', 'c'])), expected); }); - }('a', 'c')); + + test('`_.' + methodName + '` should work with an array `object` argument', 1, function() { + deepEqual(func([1, 2, 3], prop(['0', '2'])), { '1': 2 }); + }); + }); /*--------------------------------------------------------------------------*/ @@ -11926,25 +11935,18 @@ (function() { var args = arguments, - object = { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, - expected = { 'a': 1, 'c': 3 }; + object = { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }; - test('should create an object of picked properties', 2, function() { - deepEqual(_.pick(object, 'a'), { 'a': 1 }); - deepEqual(_.pick(object, 'a', 'c'), expected); - }); - - test('should flatten `props`', 1, function() { + test('should flatten `props`', 2, function() { + deepEqual(_.pick(object, 'a', 'c'), { 'a': 1, 'c': 3 }); deepEqual(_.pick(object, ['a', 'd'], 'c'), { 'a': 1, 'c': 3, 'd': 4 }); }); - test('should iterate over inherited properties', 1, function() { - function Foo() {} - Foo.prototype = object; - - deepEqual(_.pick(new Foo, 'a', 'c'), expected); + test('should work with a primitive `object` argument', 1, function() { + deepEqual(_.pick('', 'slice'), { 'slice': ''.slice }); }); + test('should return an empty object when `object` is nullish', 2, function() { _.each([null, undefined], function(value) { deepEqual(_.pick(value, 'valueOf'), {}); @@ -11952,45 +11954,62 @@ }); test('should work with `arguments` objects as secondary arguments', 1, function() { - deepEqual(_.pick(object, args), expected); + deepEqual(_.pick(object, args), { 'a': 1, 'c': 3 }); }); - test('should work with an array `object` argument', 1, function() { - deepEqual(_.pick([1, 2, 3], '1'), { '1': 2 }); + test('should coerce property names to strings', 1, function() { + deepEqual(_.pick({ '0': 'a', '1': 'b' }, 0), { '0': 'a' }); }); + }('a', 'c')); - test('should work with a primitive `object` argument', 1, function() { - deepEqual(_.pick('', 'slice'), { 'slice': ''.slice }); - }); + /*--------------------------------------------------------------------------*/ + + QUnit.module('lodash.pickBy'); + (function() { test('should work with a predicate argument', 1, function() { - var actual = _.pick(object, function(num) { + var object = { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }; + + var actual = _.pickBy(object, function(num) { return num == 1 || num == 3; }); - deepEqual(actual, expected); + deepEqual(actual, { 'a': 1, 'c': 3 }); }); + }()); - test('should provide the correct predicate arguments', 1, function() { - var args, - object = { 'a': 1, 'b': 2 }, - lastKey = _.keys(object).pop(); + /*--------------------------------------------------------------------------*/ - var expected = lastKey == 'b' - ? [1, 'a', object] - : [2, 'b', object]; + QUnit.module('pick methods'); - _.pick(object, function() { - args || (args = slice.call(arguments)); - }); + _.each(['pick', 'pickBy'], function(methodName) { + var expected = { 'a': 1, 'c': 3 }, + func = _[methodName], + object = { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }; - deepEqual(args, expected); + var prop = methodName == 'pick' ? _.identity : function(props) { + props = typeof props == 'string' ? [props] : props; + return function(value, key) { + return _.includes(props, key); + }; + }; + + test('`_.' + methodName + '` should create an object of picked properties', 2, function() { + deepEqual(func(object, prop('a')), { 'a': 1 }); + deepEqual(func(object, prop(['a', 'c'])), expected); }); - test('should coerce property names to strings', 1, function() { - deepEqual(_.pick({ '0': 'a', '1': 'b' }, 0), { '0': 'a' }); + test('`_.' + methodName + '` should iterate over inherited properties', 1, function() { + function Foo() {} + Foo.prototype = object; + + deepEqual(func(new Foo, prop(['a', 'c'])), expected); }); - }('a', 'c')); + + test('`_.' + methodName + '` should work with an array `object` argument', 1, function() { + deepEqual(func([1, 2, 3], prop('1')), { '1': 2 }); + }); + }); /*--------------------------------------------------------------------------*/ @@ -17434,7 +17453,7 @@ var acceptFalsey = _.difference(allMethods, rejectFalsey); - test('should accept falsey arguments', 212, function() { + test('should accept falsey arguments', 214, function() { var emptyArrays = _.map(falsey, _.constant([])); _.each(acceptFalsey, function(methodName) { From 4c09879aabbe8fe5a10cf90161d75361bb9984ae Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sun, 12 Jul 2015 23:31:46 -0700 Subject: [PATCH 048/935] Add `_.assignWith`, `_.cloneDeepWith`, `_.cloneWith`, `_.extendWith`, `_.isEqualWith`, `_.isMatchWith`, and `_.mergeWith`. --- lodash.src.js | 378 +++++++++++++++++++++++++++++++++----------------- test/test.js | 313 +++++++++++++++++++++++------------------ 2 files changed, 422 insertions(+), 269 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index fa1c4984e9..a05f0da713 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -2342,6 +2342,48 @@ }; } + /** + * The base implementation of `_.merge` without support multiple sources. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {Function} [customizer] The function to customize merged values. + * @param {Array} [stackA=[]] Tracks traversed source objects. + * @param {Array} [stackB=[]] Associates values with source counterparts. + * @returns {Object} Returns `object`. + */ + function baseMerge(object, source, customizer, stackA, stackB) { + var isSrcArr = isArrayLike(source) && (isArray(source) || isTypedArray(source)), + props = isSrcArr ? undefined : keysIn(source); + + arrayEach(props || source, function(srcValue, key) { + if (props) { + key = srcValue; + srcValue = source[key]; + } + if (isObjectLike(srcValue)) { + stackA || (stackA = []); + stackB || (stackB = []); + baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB); + } + else { + var value = object[key], + result = customizer ? customizer(value, srcValue, key, object, source) : undefined, + isCommon = result === undefined; + + if (isCommon) { + result = srcValue; + } + if ((result !== undefined || (isSrcArr && !(key in object))) && + (isCommon || (result === result ? (result !== value) : (value === value)))) { + object[key] = result; + } + } + }); + return object; + } + /** * A specialized version of `baseMerge` for arrays and objects which performs * deep merges and tracks traversed objects enabling objects with circular @@ -2959,7 +3001,7 @@ * @private * @param {Object} source The object to copy properties from. * @param {Array} props The property names to copy. - * @param {Function} customizer The function to customize copied values. + * @param {Function} [customizer] The function to customize copied values. * @param {Object} [object={}] The object to copy properties to. * @returns {Object} Returns `object`. */ @@ -2972,9 +3014,10 @@ while (++index < length) { var key = props[index], value = object[key], - result = customizer(value, source[key], key, object, source); + result = customizer ? customizer(value, source[key], key, object, source) : source[key]; - if ((result === result ? (result !== value) : (value === value)) || + if (!customizer || + (result === result ? (result !== value) : (value === value)) || (value === undefined && !(key in object))) { object[key] = result; } @@ -4067,7 +4110,7 @@ return sourceValue; } return isObject(objectValue) - ? merge(objectValue, sourceValue, mergeDefaults) + ? mergeWith(objectValue, sourceValue, mergeDefaults) : objectValue; } @@ -7713,10 +7756,7 @@ /*------------------------------------------------------------------------*/ /** - * Creates a shallow clone of `value`. If `customizer` is provided it's invoked - * to produce the cloned value. If `customizer` returns `undefined` cloning - * is handled by the method instead. The `customizer` is invoked with up to - * three arguments; (value [, index|key, object]). + * Creates a shallow clone of `value`. * * **Note:** This method is loosely based on the * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm). @@ -7729,7 +7769,6 @@ * @memberOf _ * @category Lang * @param {*} value The value to clone. - * @param {Function} [customizer] The function to customize cloning. * @returns {*} Returns the cloned value. * @example * @@ -7741,8 +7780,25 @@ * var shallow = _.clone(users); * shallow[0] === users[0]; * // => true + */ + function clone(value) { + return baseClone(value); + } + + /** + * This method is like `_.clone` except that it accepts `customizer` which + * is invoked to produce the cloned value. If `customizer` returns `undefined` + * cloning is handled by the method instead. The `customizer` is invoked with + * up to three arguments; (value [, index|key, object]). + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to clone. + * @param {Function} [customizer] The function to customize cloning. + * @returns {*} Returns the cloned value. + * @example * - * // using a customizer callback * var el = _.clone(document.body, function(value) { * if (_.isElement(value)) { * return value.cloneNode(false); @@ -7756,10 +7812,8 @@ * el.childNodes.length; * // => 0 */ - function clone(value, customizer) { - return typeof customizer == 'function' - ? baseClone(value, false, customizer) - : baseClone(value); + function cloneWith(value, customizer) { + return baseClone(value, false, customizer); } /** @@ -7769,7 +7823,6 @@ * @memberOf _ * @category Lang * @param {*} value The value to recursively clone. - * @param {Function} [customizer] The function to customize cloning. * @returns {*} Returns the deep cloned value. * @example * @@ -7781,8 +7834,22 @@ * var deep = _.cloneDeep(users); * deep[0] === users[0]; * // => false + */ + function cloneDeep(value) { + return baseClone(value, true); + } + + /** + * This method is like `_.cloneWith` except that it recursively clones `value`. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to recursively clone. + * @param {Function} [customizer] The function to customize cloning. + * @returns {*} Returns the deep cloned value. + * @example * - * // using a customizer callback * var el = _.cloneDeep(document.body, function(value) { * if (_.isElement(value)) { * return value.cloneNode(true); @@ -7796,10 +7863,8 @@ * el.childNodes.length; * // => 20 */ - function cloneDeep(value, customizer) { - return typeof customizer == 'function' - ? baseClone(value, true, customizer) - : baseClone(value, true); + function cloneDeepWith(value, customizer) { + return baseClone(value, true, customizer); } /** @@ -7991,16 +8056,12 @@ /** * Performs a deep comparison between two values to determine if they are - * equivalent. If `customizer` is provided it's invoked to compare values. - * If `customizer` returns `undefined` comparisons are handled by the method - * instead. The `customizer` is invoked with up to three arguments: - * (value, other [, index|key]). + * equivalent. * * **Note:** This method supports comparing arrays, booleans, `Date` objects, * numbers, `Object` objects, regexes, and strings. Objects are compared by * their own, not inherited, enumerable properties. Functions and DOM nodes - * are **not** supported. Provide a customizer function to extend support - * for comparing other values. + * are **not** supported. * * @static * @memberOf _ @@ -8008,7 +8069,6 @@ * @category Lang * @param {*} value The value to compare. * @param {*} other The other value to compare. - * @param {Function} [customizer] The function to customize comparisons. * @returns {boolean} Returns `true` if the values are equivalent, else `false`. * @example * @@ -8020,19 +8080,38 @@ * * _.isEqual(object, other); * // => true + */ + function isEqual(value, other) { + return baseIsEqual(value, other); + } + + /** + * This method is like `_.isEqual` except that it accepts `customizer` which + * is invoked to compare values. If `customizer` returns `undefined` comparisons + * are handled by the method instead. The `customizer` is invoked with up to + * three arguments: (value, other [, index|key]). + * + * @static + * @memberOf _ + * @alias eq + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @param {Function} [customizer] The function to customize comparisons. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example * - * // using a customizer callback * var array = ['hello', 'goodbye']; * var other = ['hi', 'goodbye']; * - * _.isEqual(array, other, function(value, other) { + * _.isEqualWith(array, other, function(value, other) { * if (_.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/)) { * return true; * } * }); * // => true */ - function isEqual(value, other, customizer) { + function isEqualWith(value, other, customizer) { customizer = typeof customizer == 'function' ? customizer : undefined; var result = customizer ? customizer(value, other) : undefined; return result === undefined ? baseIsEqual(value, other, customizer) : !!result; @@ -8142,10 +8221,7 @@ /** * Performs a deep comparison between `object` and `source` to determine if - * `object` contains equivalent property values. If `customizer` is provided - * it's invoked to compare values. If `customizer` returns `undefined` - * comparisons are handled by the method instead. The `customizer` is invoked - * with three arguments: (value, other, index|key). + * `object` contains equivalent property values. * * **Note:** This method supports comparing properties of arrays, booleans, * `Date` objects, numbers, `Object` objects, regexes, and strings. Functions @@ -8157,7 +8233,6 @@ * @category Lang * @param {Object} object The object to inspect. * @param {Object} source The object of property values to match. - * @param {Function} [customizer] The function to customize comparisons. * @returns {boolean} Returns `true` if `object` is a match, else `false`. * @example * @@ -8168,8 +8243,26 @@ * * _.isMatch(object, { 'age': 36 }); * // => false + */ + function isMatch(object, source) { + return baseIsMatch(object, getMatchData(source)); + } + + /** + * This method is like `_.isMatch` except that it accepts `customizer` which + * is invoked to compare values. If `customizer` returns `undefined` comparisons + * are handled by the method instead. The `customizer` is invoked with three + * arguments: (value, other, index|key). + * + * @static + * @memberOf _ + * @category Lang + * @param {Object} object The object to inspect. + * @param {Object} source The object of property values to match. + * @param {Function} [customizer] The function to customize comparisons. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + * @example * - * // using a customizer callback * var object = { 'greeting': 'hello' }; * var source = { 'greeting': 'hi' }; * @@ -8178,7 +8271,7 @@ * }); * // => true */ - function isMatch(object, source, customizer) { + function isMatchWith(object, source, customizer) { customizer = typeof customizer == 'function' ? customizer : undefined; return baseIsMatch(object, getMatchData(source), customizer); } @@ -8529,119 +8622,52 @@ /*------------------------------------------------------------------------*/ /** - * Recursively merges own enumerable properties of the source object(s), that - * don't resolve to `undefined` into the destination object. Subsequent sources - * overwrite property assignments of previous sources. If `customizer` is - * provided it's invoked to produce the merged values of the destination and - * source properties. If `customizer` returns `undefined` merging is handled - * by the method instead. The `customizer` is invoked with five arguments: - * (objectValue, sourceValue, key, object, source). + * Assigns own enumerable properties of source object(s) to the destination + * object. Subsequent sources overwrite property assignments of previous sources. + * + * **Note:** This method mutates `object` and is based on + * [`Object.assign`](http://ecma-international.org/ecma-262/6.0/#sec-object.assign). * * @static * @memberOf _ * @category Object * @param {Object} object The destination object. * @param {...Object} [sources] The source objects. - * @param {Function} [customizer] The function to customize assigned values. * @returns {Object} Returns `object`. * @example * - * var users = { - * 'data': [{ 'user': 'barney' }, { 'user': 'fred' }] - * }; - * - * var ages = { - * 'data': [{ 'age': 36 }, { 'age': 40 }] - * }; - * - * _.merge(users, ages); - * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] } - * - * // using a customizer callback - * var object = { - * 'fruits': ['apple'], - * 'vegetables': ['beet'] - * }; - * - * var other = { - * 'fruits': ['banana'], - * 'vegetables': ['carrot'] - * }; - * - * _.merge(object, other, function(a, b) { - * if (_.isArray(a)) { - * return a.concat(b); - * } - * }); - * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] } + * _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' }); + * // => { 'user': 'fred', 'age': 40 } */ - var merge = createAssigner(function baseMerge(object, source, customizer, stackA, stackB) { - var isSrcArr = isArrayLike(source) && (isArray(source) || isTypedArray(source)), - props = isSrcArr ? undefined : keysIn(source); - - arrayEach(props || source, function(srcValue, key) { - if (props) { - key = srcValue; - srcValue = source[key]; - } - if (isObjectLike(srcValue)) { - stackA || (stackA = []); - stackB || (stackB = []); - baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB); - } - else { - var value = object[key], - result = customizer ? customizer(value, srcValue, key, object, source) : undefined, - isCommon = result === undefined; - - if (isCommon) { - result = srcValue; - } - if ((result !== undefined || (isSrcArr && !(key in object))) && - (isCommon || (result === result ? (result !== value) : (value === value)))) { - object[key] = result; - } - } - }); - return object; + var assign = createAssigner(function(object, source) { + copyObject(source, keys(source), object); }); /** - * Assigns own enumerable properties of source object(s) to the destination - * object. Subsequent sources overwrite property assignments of previous sources. - * If `customizer` is provided it's invoked to produce the assigned values. - * The `customizer` is invoked with five arguments: (objectValue, sourceValue, key, object, source). + * This method is like `_.assign` except that it accepts `customizer` which + * is invoked to produce the assigned values. The `customizer` is invoked + * with five arguments: (objectValue, sourceValue, key, object, source). * - * **Note:** This method mutates `object` and is based on - * [`Object.assign`](http://ecma-international.org/ecma-262/6.0/#sec-object.assign). + * **Note:** This method mutates `object`. * * @static * @memberOf _ * @category Object * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. + * @param {...Object} sources The source objects. * @param {Function} [customizer] The function to customize assigned values. * @returns {Object} Returns `object`. * @example * - * _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' }); - * // => { 'user': 'fred', 'age': 40 } - * - * // using a customizer callback - * var defaults = _.partialRight(_.assign, function(value, other) { + * var defaults = _.partialRight(_.assignWith, function(value, other) { * return _.isUndefined(value) ? other : value; * }); * * defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' }); * // => { 'user': 'barney', 'age': 36 } */ - var assign = createAssigner(function(object, source, customizer) { - var props = keys(source); - if (customizer) { - copyObjectWith(source, props, customizer, object); - } else { - copyObject(source, props, object); - } + var assignWith = createAssigner(function(object, source, customizer) { + copyObjectWith(source, keys(source), customizer, object); }); /** @@ -8706,7 +8732,7 @@ */ var defaults = restParam(function(args) { args.push(undefined, extendDefaults); - return extend.apply(undefined, args); + return extendWith.apply(undefined, args); }); /** @@ -8729,7 +8755,7 @@ */ var defaultsDeep = restParam(function(args) { args.push(undefined, mergeDefaults); - return merge.apply(undefined, args); + return mergeWith.apply(undefined, args); }); /** @@ -8741,20 +8767,38 @@ * @category Object * @param {Object} object The destination object. * @param {...Object} [sources] The source objects. - * @param {Function} [customizer] The function to customize assigned values. * @returns {Object} Returns `object`. * @example * * _.extend({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' }); * // => { 'user': 'fred', 'age': 40 } */ - var extend = createAssigner(function(object, source, customizer) { - var props = keysIn(source); - if (customizer) { - copyObjectWith(source, props, customizer, object); - } else { - copyObject(source, props, object); - } + var extend = createAssigner(function(object, source) { + copyObject(source, keysIn(source), object); + }); + + /** + * This method is like `_.assignWith` except that it iterates over own and + * inherited source properties. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The destination object. + * @param {...Object} sources The source objects. + * @param {Function} [customizer] The function to customize assigned values. + * @returns {Object} Returns `object`. + * @example + * + * var defaults = _.partialRight(_.extendWith, function(value, other) { + * return _.isUndefined(value) ? other : value; + * }); + * + * defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' }); + * // => { 'user': 'barney', 'age': 36 } + */ + var extendWith = createAssigner(function(object, source, customizer) { + copyObjectWith(source, keysIn(source), customizer, object); }); /** @@ -9265,6 +9309,71 @@ return result; } + /** + * Recursively merges own enumerable properties of the source object(s), that + * don't resolve to `undefined` into the destination object. Subsequent sources + * overwrite property assignments of previous sources. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @example + * + * var users = { + * 'data': [{ 'user': 'barney' }, { 'user': 'fred' }] + * }; + * + * var ages = { + * 'data': [{ 'age': 36 }, { 'age': 40 }] + * }; + * + * _.merge(users, ages); + * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] } + */ + var merge = createAssigner(function(object, source) { + baseMerge(object, source); + }); + + /** + * This method is like `_.merge` except that it accepts `customizer` which + * is invoked to produce the merged values of the destination and source + * properties. If `customizer` returns `undefined` merging is handled by the + * method instead. The `customizer` is invoked with five arguments: + * (objectValue, sourceValue, key, object, source). + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The destination object. + * @param {...Object} sources The source objects. + * @param {Function} customizer The function to customize assigned values. + * @returns {Object} Returns `object`. + * @example + * + * var object = { + * 'fruits': ['apple'], + * 'vegetables': ['beet'] + * }; + * + * var other = { + * 'fruits': ['banana'], + * 'vegetables': ['carrot'] + * }; + * + * _.mergeWith(object, other, function(a, b) { + * if (_.isArray(a)) { + * return a.concat(b); + * } + * }); + * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] } + */ + var mergeWith = createAssigner(function(object, source, customizer) { + baseMerge(object, source, customizer); + }); + /** * The opposite of `_.pick`; this method creates an object composed of the * own and inherited enumerable properties of `object` that are not omitted. @@ -11335,6 +11444,7 @@ lodash.after = after; lodash.ary = ary; lodash.assign = assign; + lodash.assignWith = assignWith; lodash.at = at; lodash.before = before; lodash.bind = bind; @@ -11359,6 +11469,7 @@ lodash.dropRightWhile = dropRightWhile; lodash.dropWhile = dropWhile; lodash.extend = extend; + lodash.extendWith = extendWith; lodash.fill = fill; lodash.filter = filter; lodash.flatten = flatten; @@ -11382,6 +11493,7 @@ lodash.matchesProperty = matchesProperty; lodash.memoize = memoize; lodash.merge = merge; + lodash.mergeWith = mergeWith; lodash.method = method; lodash.methodOf = methodOf; lodash.mixin = mixin; @@ -11454,6 +11566,8 @@ lodash.ceil = ceil; lodash.clone = clone; lodash.cloneDeep = cloneDeep; + lodash.cloneDeepWith = cloneDeepWith; + lodash.cloneWith = cloneWith; lodash.deburr = deburr; lodash.endsWith = endsWith; lodash.escape = escape; @@ -11488,10 +11602,12 @@ lodash.isElement = isElement; lodash.isEmpty = isEmpty; lodash.isEqual = isEqual; + lodash.isEqualWith = isEqualWith; lodash.isError = isError; lodash.isFinite = isFinite; lodash.isFunction = isFunction; lodash.isMatch = isMatch; + lodash.isMatchWith = isMatchWith; lodash.isNaN = isNaN; lodash.isNative = isNative; lodash.isNull = isNull; diff --git a/test/test.js b/test/test.js index 05645729f7..4dded1f694 100644 --- a/test/test.js +++ b/test/test.js @@ -1039,27 +1039,35 @@ var func = _[methodName]; test('`_.' + methodName + '` should assign properties of a source object to the destination object', 1, function() { - deepEqual(_.assign({ 'a': 1 }, { 'b': 2 }), { 'a': 1, 'b': 2 }); + deepEqual(func({ 'a': 1 }, { 'b': 2 }), { 'a': 1, 'b': 2 }); }); test('`_.' + methodName + '` should accept multiple source objects', 2, function() { var expected = { 'a': 1, 'b': 2, 'c': 3 }; - deepEqual(_.assign({ 'a': 1 }, { 'b': 2 }, { 'c': 3 }), expected); - deepEqual(_.assign({ 'a': 1 }, { 'b': 2, 'c': 2 }, { 'c': 3 }), expected); + deepEqual(func({ 'a': 1 }, { 'b': 2 }, { 'c': 3 }), expected); + deepEqual(func({ 'a': 1 }, { 'b': 2, 'c': 2 }, { 'c': 3 }), expected); }); test('`_.' + methodName + '` should overwrite destination properties', 1, function() { var expected = { 'a': 3, 'b': 2, 'c': 1 }; - deepEqual(_.assign({ 'a': 1, 'b': 2 }, expected), expected); + deepEqual(func({ 'a': 1, 'b': 2 }, expected), expected); }); test('`_.' + methodName + '` should assign source properties with nullish values', 1, function() { var expected = { 'a': null, 'b': undefined, 'c': null }; - deepEqual(_.assign({ 'a': 1, 'b': 2 }, expected), expected); + deepEqual(func({ 'a': 1, 'b': 2 }, expected), expected); }); + }); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('lodash.assignWith and lodash.extendWith'); + + _.each(['assignWith', 'extendWith'], function(methodName) { + var func = _[methodName]; test('`_.' + methodName + '` should work with a `customizer` callback', 1, function() { - var actual = _.assign({ 'a': 1, 'b': 2 }, { 'a': 3, 'c': 3 }, function(a, b) { + var actual = func({ 'a': 1, 'b': 2 }, { 'a': 3, 'c': 3 }, function(a, b) { return typeof a == 'undefined' ? b : a; }); @@ -1068,7 +1076,7 @@ test('`_.' + methodName + '` should work with a `customizer` that returns `undefined`', 1, function() { var expected = { 'a': undefined }; - deepEqual(_.assign({}, expected, _.identity), expected); + deepEqual(func({}, expected, _.identity), expected); }); }); @@ -1963,23 +1971,6 @@ var expected = typeof value == 'function' ? { 'c': Foo.c } : (value && {}); deepEqual(func(value), expected); }); - - test('`_.' + methodName + '` should work with a `customizer` callback and ' + key, 4, function() { - var customizer = function(value) { - return _.isPlainObject(value) ? undefined : value; - }; - - var actual = func(value, customizer); - - deepEqual(actual, value); - strictEqual(actual, value); - - var object = { 'a': value, 'b': { 'c': value } }; - actual = func(object, customizer); - - deepEqual(actual, object); - notStrictEqual(actual, object); - }); }); test('`_.' + methodName + '` should clone array buffers', 2, function() { @@ -2024,22 +2015,6 @@ notStrictEqual(actual, shadowObject); }); - test('`_.' + methodName + '` should provide the correct `customizer` arguments', 1, function() { - var argsList = [], - foo = new Foo; - - func(foo, function() { - argsList.push(slice.call(arguments)); - }); - - deepEqual(argsList, isDeep ? [[foo], [1, 'a', foo]] : [[foo]]); - }); - - test('`_.' + methodName + '` should handle cloning if `customizer` returns `undefined`', 1, function() { - var actual = func({ 'a': { 'b': 'c' } }, _.noop); - deepEqual(actual, { 'a': { 'b': 'c' } }); - }); - test('`_.' + methodName + '` should clone `index` and `input` array properties', 2, function() { var array = /x/.exec('vwxyz'), actual = func(array); @@ -2122,6 +2097,46 @@ } }); }); + + _.each(['cloneWith', 'cloneDeepWith'], function(methodName) { + var func = _[methodName], + isDeepWith = methodName == 'cloneDeepWith'; + + test('`_.' + methodName + '` should provide the correct `customizer` arguments', 1, function() { + var argsList = [], + foo = new Foo; + + func(foo, function() { + argsList.push(slice.call(arguments)); + }); + + deepEqual(argsList, isDeepWith ? [[foo], [1, 'a', foo]] : [[foo]]); + }); + + test('`_.' + methodName + '` should handle cloning if `customizer` returns `undefined`', 1, function() { + var actual = func({ 'a': { 'b': 'c' } }, _.noop); + deepEqual(actual, { 'a': { 'b': 'c' } }); + }); + + _.forOwn(uncloneable, function(value, key) { + test('`_.' + methodName + '` should work with a `customizer` callback and ' + key, 4, function() { + var customizer = function(value) { + return _.isPlainObject(value) ? undefined : value; + }; + + var actual = func(value, customizer); + + deepEqual(actual, value); + strictEqual(actual, value); + + var object = { 'a': value, 'b': { 'c': value } }; + actual = func(object, customizer); + + deepEqual(actual, object); + notStrictEqual(actual, object); + }); + }); + }); }(1, 2, 3)); /*--------------------------------------------------------------------------*/ @@ -5156,8 +5171,20 @@ }); _.each(['assign', 'extend', 'merge'], function(methodName) { + var func = _[methodName]; + + test('`_.' + methodName + '` should not treat `object` as `source`', 1, function() { + function Foo() {} + Foo.prototype.a = 1; + + var actual = func(new Foo, { 'b': 2 }); + ok(!_.has(actual, 'a')); + }); + }); + + _.each(['assignWith', 'extendWith', 'mergeWith'], function(methodName) { var func = _[methodName], - isMerge = methodName == 'merge'; + isMergeWith = methodName == 'mergeWith'; test('`_.' + methodName + '` should provide the correct `customizer` arguments', 3, function() { var args, @@ -5192,20 +5219,12 @@ }); var expected = [[objectValue, sourceValue, 'a', object, source]]; - if (isMerge) { + if (isMergeWith) { expected.push([undefined, 2, 'b', sourceValue, sourceValue]); } deepEqual(argsList, expected, 'object property values'); }); - test('`_.' + methodName + '` should not treat `object` as `source`', 1, function() { - function Foo() {} - Foo.prototype.a = 1; - - var actual = func(new Foo, { 'b': 2 }); - ok(!_.has(actual, 'a')); - }); - test('`_.' + methodName + '` should not treat the second argument as a `customizer` callback', 2, function() { function callback() {} callback.b = 2; @@ -6968,82 +6987,6 @@ deepEqual(actual, expected); }); - test('should provide the correct `customizer` arguments', 1, function() { - var argsList = [], - object1 = { 'a': [1, 2], 'b': null }, - object2 = { 'a': [1, 2], 'b': null }; - - object1.b = object2; - object2.b = object1; - - var expected = [ - [object1, object2], - [object1.a, object2.a, 'a'], - [object1.a[0], object2.a[0], 0], - [object1.a[1], object2.a[1], 1], - [object1.b, object2.b, 'b'], - [object1.b.a, object2.b.a, 'a'], - [object1.b.a[0], object2.b.a[0], 0], - [object1.b.a[1], object2.b.a[1], 1], - [object1.b.b, object2.b.b, 'b'] - ]; - - _.isEqual(object1, object2, function() { - argsList.push(slice.call(arguments)); - }); - - deepEqual(argsList, expected); - }); - - test('should handle comparisons if `customizer` returns `undefined`', 3, function() { - strictEqual(_.isEqual('a', 'a', _.noop), true); - strictEqual(_.isEqual(['a'], ['a'], _.noop), true); - strictEqual(_.isEqual({ '0': 'a' }, { '0': 'a' }, _.noop), true); - }); - - test('should not handle comparisons if `customizer` returns `true`', 3, function() { - var customizer = function(value) { - return _.isString(value) || undefined; - }; - - strictEqual(_.isEqual('a', 'b', customizer), true); - strictEqual(_.isEqual(['a'], ['b'], customizer), true); - strictEqual(_.isEqual({ '0': 'a' }, { '0': 'b' }, customizer), true); - }); - - test('should not handle comparisons if `customizer` returns `false`', 3, function() { - var customizer = function(value) { - return _.isString(value) ? false : undefined; - }; - - strictEqual(_.isEqual('a', 'a', customizer), false); - strictEqual(_.isEqual(['a'], ['a'], customizer), false); - strictEqual(_.isEqual({ '0': 'a' }, { '0': 'a' }, customizer), false); - }); - - test('should return a boolean value even if `customizer` does not', 2, function() { - var actual = _.isEqual('a', 'b', _.constant('c')); - strictEqual(actual, true); - - var values = _.without(falsey, undefined), - expected = _.map(values, _.constant(false)); - - actual = []; - _.each(values, function(value) { - actual.push(_.isEqual('a', 'a', _.constant(value))); - }); - - deepEqual(actual, expected); - }); - - test('should ensure `customizer` is a function', 1, function() { - var array = [1, 2, 3], - eq = _.partial(_.isEqual, array), - actual = _.map([array, [1, 0, 3]], eq); - - deepEqual(actual, [true, false]); - }); - test('should work as an iteratee for `_.every`', 1, function() { var actual = _.every([1, 1, 1], _.partial(_.isEqual, 1)); ok(actual); @@ -7175,6 +7118,88 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.isEqualWith'); + + (function() { + test('should provide the correct `customizer` arguments', 1, function() { + var argsList = [], + object1 = { 'a': [1, 2], 'b': null }, + object2 = { 'a': [1, 2], 'b': null }; + + object1.b = object2; + object2.b = object1; + + var expected = [ + [object1, object2], + [object1.a, object2.a, 'a'], + [object1.a[0], object2.a[0], 0], + [object1.a[1], object2.a[1], 1], + [object1.b, object2.b, 'b'], + [object1.b.a, object2.b.a, 'a'], + [object1.b.a[0], object2.b.a[0], 0], + [object1.b.a[1], object2.b.a[1], 1], + [object1.b.b, object2.b.b, 'b'] + ]; + + _.isEqualWith(object1, object2, function() { + argsList.push(slice.call(arguments)); + }); + + deepEqual(argsList, expected); + }); + + test('should handle comparisons if `customizer` returns `undefined`', 3, function() { + strictEqual(_.isEqualWith('a', 'a', _.noop), true); + strictEqual(_.isEqualWith(['a'], ['a'], _.noop), true); + strictEqual(_.isEqualWith({ '0': 'a' }, { '0': 'a' }, _.noop), true); + }); + + test('should not handle comparisons if `customizer` returns `true`', 3, function() { + var customizer = function(value) { + return _.isString(value) || undefined; + }; + + strictEqual(_.isEqualWith('a', 'b', customizer), true); + strictEqual(_.isEqualWith(['a'], ['b'], customizer), true); + strictEqual(_.isEqualWith({ '0': 'a' }, { '0': 'b' }, customizer), true); + }); + + test('should not handle comparisons if `customizer` returns `false`', 3, function() { + var customizer = function(value) { + return _.isString(value) ? false : undefined; + }; + + strictEqual(_.isEqualWith('a', 'a', customizer), false); + strictEqual(_.isEqualWith(['a'], ['a'], customizer), false); + strictEqual(_.isEqualWith({ '0': 'a' }, { '0': 'a' }, customizer), false); + }); + + test('should return a boolean value even if `customizer` does not', 2, function() { + var actual = _.isEqualWith('a', 'b', _.constant('c')); + strictEqual(actual, true); + + var values = _.without(falsey, undefined), + expected = _.map(values, _.constant(false)); + + actual = []; + _.each(values, function(value) { + actual.push(_.isEqualWith('a', 'a', _.constant(value))); + }); + + deepEqual(actual, expected); + }); + + test('should ensure `customizer` is a function', 1, function() { + var array = [1, 2, 3], + eq = _.partial(_.isEqualWith, array), + actual = _.map([array, [1, 0, 3]], eq); + + deepEqual(actual, [true, false]); + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.isError'); (function() { @@ -7567,7 +7592,13 @@ deepEqual(actual, [false, true]); }); + }()); + /*--------------------------------------------------------------------------*/ + + QUnit.module('lodash.isMatchWith'); + + (function() { test('should provide the correct `customizer` arguments', 1, function() { var argsList = [], object1 = { 'a': [1, 2], 'b': null }, @@ -7591,7 +7622,7 @@ [object1.b.b.b, object2.b.b.b, 'b'] ]; - _.isMatch(object1, object2, function() { + _.isMatchWith(object1, object2, function() { argsList.push(slice.call(arguments)); }); @@ -7599,12 +7630,12 @@ }); test('should handle comparisons if `customizer` returns `undefined`', 1, function() { - strictEqual(_.isMatch({ 'a': 1 }, { 'a': 1 }, _.noop), true); + strictEqual(_.isMatchWith({ 'a': 1 }, { 'a': 1 }, _.noop), true); }); test('should return a boolean value even if `customizer` does not', 2, function() { var object = { 'a': 1 }, - actual = _.isMatch(object, { 'a': 1 }, _.constant('a')); + actual = _.isMatchWith(object, { 'a': 1 }, _.constant('a')); strictEqual(actual, true); @@ -7612,7 +7643,7 @@ actual = []; _.each(falsey, function(value) { - actual.push(_.isMatch(object, { 'a': 2 }, _.constant(value))); + actual.push(_.isMatchWith(object, { 'a': 2 }, _.constant(value))); }); deepEqual(actual, expected); @@ -7620,7 +7651,7 @@ test('should ensure `customizer` is a function', 1, function() { var object = { 'a': 1 }, - matches = _.partial(_.isMatch, object), + matches = _.partial(_.isMatchWith, object), actual = _.map([object, { 'a': 2 }], matches); deepEqual(actual, [true, false]); @@ -10450,23 +10481,29 @@ deepEqual(actual, values); }); + }(1, 2, 3)); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('lodash.mergeWith'); + (function() { test('should handle merging if `customizer` returns `undefined`', 2, function() { - var actual = _.merge({ 'a': { 'b': [1, 1] } }, { 'a': { 'b': [0] } }, _.noop); + var actual = _.mergeWith({ 'a': { 'b': [1, 1] } }, { 'a': { 'b': [0] } }, _.noop); deepEqual(actual, { 'a': { 'b': [0, 1] } }); - actual = _.merge([], [undefined], _.identity); + actual = _.mergeWith([], [undefined], _.identity); deepEqual(actual, [undefined]); }); test('should defer to `customizer` when it returns a value other than `undefined`', 1, function() { - var actual = _.merge({ 'a': { 'b': [0, 1] } }, { 'a': { 'b': [2] } }, function(a, b) { + var actual = _.mergeWith({ 'a': { 'b': [0, 1] } }, { 'a': { 'b': [2] } }, function(a, b) { return _.isArray(a) ? a.concat(b) : undefined; }); deepEqual(actual, { 'a': { 'b': [0, 1, 2] } }); }); - }(1, 2, 3)); + }()); /*--------------------------------------------------------------------------*/ @@ -11678,8 +11715,8 @@ source = { 'a': { 'b': 2, 'c': 3 } }, expected = { 'a': { 'b': 1, 'c': 3 } }; - var defaultsDeep = _.partialRight(_.merge, function deep(value, other) { - return _.isObject(value) ? _.merge(value, other, deep) : value; + var defaultsDeep = _.partialRight(_.mergeWith, function deep(value, other) { + return _.isObject(value) ? _.mergeWith(value, other, deep) : value; }); deepEqual(defaultsDeep(object, source), expected); @@ -17453,7 +17490,7 @@ var acceptFalsey = _.difference(allMethods, rejectFalsey); - test('should accept falsey arguments', 214, function() { + test('should accept falsey arguments', 221, function() { var emptyArrays = _.map(falsey, _.constant([])); _.each(acceptFalsey, function(methodName) { From 211a6cc4f1413105405e810baea5d2287d1bddea Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Mon, 13 Jul 2015 07:14:13 -0700 Subject: [PATCH 049/935] Doc cleanup to turn "accepts an iteratee" to "accepts `iteratee`". [ci skip] --- lodash.src.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index a05f0da713..b16d4ddb84 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -5074,7 +5074,7 @@ } /** - * This method is like `_.sortedIndex` except that it accepts an iteratee + * This method is like `_.sortedIndex` except that it accepts `iteratee` * which is invoked for `value` and each element of `array` to compute their * sort ranking. The iteratee is invoked with one argument: (value). * @@ -5121,7 +5121,7 @@ } /** - * This method is like `_.sortedLastIndex` except that it accepts an iteratee + * This method is like `_.sortedLastIndex` except that it accepts `iteratee` * which is invoked for `value` and each element of `array` to compute their * sort ranking. The iteratee is invoked with one argument: (value). * @@ -5349,7 +5349,7 @@ } /** - * This method is like `_.uniq` except that it accepts an iteratee which is + * This method is like `_.uniq` except that it accepts `iteratee` which is * invoked for each element in `array` to generate the criterion by which * uniqueness is computed. The iteratee is invoked with one argument: (value). * @@ -5428,7 +5428,7 @@ } /** - * This method is like `_.unzip` except that it accepts an iteratee to specify + * This method is like `_.unzip` except that it accepts `iteratee` to specify * how regrouped values should be combined. The iteratee is invoked with four * arguments: (accumulator, value, index, group). * @@ -5567,7 +5567,7 @@ } /** - * This method is like `_.zip` except that it accepts an iteratee to specify + * This method is like `_.zip` except that it accepts `iteratee` to specify * how grouped values should be combined. The iteratee is invoked with four * arguments: (accumulator, value, index, group). * @@ -11265,7 +11265,7 @@ } /** - * This method is like `_.max` except that it accepts an iteratee which is + * This method is like `_.max` except that it accepts `iteratee` which is * invoked for each element in `array` to generate the criterion by which * the value is ranked. The iteratee is invoked with one argument: (value). * @@ -11313,7 +11313,7 @@ } /** - * This method is like `_.min` except that it accepts an iteratee which is + * This method is like `_.min` except that it accepts `iteratee` which is * invoked for each element in `array` to generate the criterion by which * the value is ranked. The iteratee is invoked with one argument: (value). * @@ -11382,7 +11382,7 @@ } /** - * This method is like `_.sum` except that it accepts an iteratee which is + * This method is like `_.sum` except that it accepts `iteratee` which is * invoked for each element in `array` to generate the value to be summed. * The iteratee is invoked with one argument: (value). * From ffd3e173644a0e32a01787e49ccb8d229c6fdb17 Mon Sep 17 00:00:00 2001 From: Graeme Yeates Date: Sun, 12 Jul 2015 19:12:13 -0400 Subject: [PATCH 050/935] Add `_.isFunction` test for `NodeList` instances. --- lodash.src.js | 5 +++-- test/test.js | 8 +++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index b16d4ddb84..4f5c101e64 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -8187,8 +8187,9 @@ */ function isFunction(value) { // The use of `Object#toString` avoids issues with the `typeof` operator - // in older versions of Chrome and Safari which return 'function' for regexes - // and Safari 8 which returns 'object' for typed array constructors. + // in older versions of Chrome and Safari which return 'function' for regexes, + // Safari 8 which returns 'object' for typed array constructors, and PhantomJS 1.9 + // which returns 'function' for `NodeList` instances. return isObject(value) && objToString.call(value) == funcTag; } diff --git a/test/test.js b/test/test.js index 4dded1f694..0a9da57fa4 100644 --- a/test/test.js +++ b/test/test.js @@ -7338,7 +7338,7 @@ deepEqual(actual, expected); }); - test('should return `false` for non-functions', 11, function() { + test('should return `false` for non-functions', 12, function() { var expected = _.map(falsey, _.constant(false)); var actual = _.map(falsey, function(value, index) { @@ -7357,6 +7357,12 @@ strictEqual(_.isFunction(NaN), false); strictEqual(_.isFunction(/x/), false); strictEqual(_.isFunction('a'), false); + + if (document) { + strictEqual(_.isFunction(document.getElementsByTagName('body')), false); + } else { + skipTest(); + } }); test('should work with host objects in IE 8 document mode (test in IE 11)', 2, function() { From df172443537f74145ad83775f1717cf2c79de85e Mon Sep 17 00:00:00 2001 From: Oliver Hoffmann Date: Mon, 13 Jul 2015 19:49:05 +0200 Subject: [PATCH 051/935] Update `root` assignment to work in Firefox extensions. [closes #1340] --- lodash.src.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 4f5c101e64..9164119863 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -279,7 +279,7 @@ * The `this` value is used if it's the global object to avoid Greasemonkey's * restricted `window` object, otherwise the `window` object is used. */ - var root = freeGlobal || ((freeWindow !== (thisGlobal && thisGlobal.window)) && freeWindow) || freeSelf || thisGlobal; + var root = freeGlobal || ((freeWindow !== (thisGlobal && thisGlobal.window)) && freeWindow) || freeSelf || thisGlobal || Function('return this')(); /*--------------------------------------------------------------------------*/ @@ -429,7 +429,7 @@ * @returns {null|Object} Returns `value` if it's a global object, else `null`. */ function checkGlobal(value) { - return (value && value.Object) ? value : null; + return (value && value.Object === Object) ? value : null; } /** From 8a9e9e9a11b9f4d1dc8bcc8955e79fdca4e6f9a8 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Mon, 13 Jul 2015 18:50:37 -0700 Subject: [PATCH 052/935] Remove support for pre-es5 environments. --- lodash.src.js | 323 +++++++++--------------------------------------- test/index.html | 48 +------ test/test.js | 96 +++----------- 3 files changed, 76 insertions(+), 391 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 9164119863..e02136c144 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -147,12 +147,6 @@ 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap' ]; - /** Used to fix the JScript `[[DontEnum]]` bug. */ - var shadowProps = [ - 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', - 'toLocaleString', 'toString', 'valueOf' - ]; - /** Used to make template sourceURLs easier to identify. */ var templateCounter = -1; @@ -755,7 +749,6 @@ /** Used for native method references. */ var arrayProto = Array.prototype, - errorProto = Error.prototype, objectProto = Object.prototype, stringProto = String.prototype; @@ -774,6 +767,9 @@ */ var objToString = objectProto.toString; + /** Used to infer the `Object` constructor. */ + var objCtorString = fnToString.call(Object); + /** Used to restore the original `_` reference in `_.noConflict`. */ var oldDash = root._; @@ -786,6 +782,7 @@ /** Native method references. */ var ArrayBuffer = context.ArrayBuffer, clearTimeout = context.clearTimeout, + getPrototypeOf = Object.getPrototypeOf, parseFloat = context.parseFloat, pow = Math.pow, propertyIsEnumerable = objectProto.propertyIsEnumerable, @@ -799,12 +796,10 @@ var nativeCeil = Math.ceil, nativeCreate = getNative(Object, 'create'), nativeFloor = Math.floor, - nativeIsArray = getNative(Array, 'isArray'), nativeIsFinite = context.isFinite, - nativeKeys = getNative(Object, 'keys'), + nativeKeys = Object.keys, nativeMax = Math.max, nativeMin = Math.min, - nativeNow = getNative(Date, 'now'), nativeParseInt = context.parseInt, nativeRandom = Math.random; @@ -829,34 +824,6 @@ /** Used to lookup unminified function names. */ var realNames = {}; - /** Used to lookup a type array constructors by `toStringTag`. */ - var ctorByTag = {}; - ctorByTag[float32Tag] = context.Float32Array; - ctorByTag[float64Tag] = context.Float64Array; - ctorByTag[int8Tag] = context.Int8Array; - ctorByTag[int16Tag] = context.Int16Array; - ctorByTag[int32Tag] = context.Int32Array; - ctorByTag[uint8Tag] = Uint8Array; - ctorByTag[uint8ClampedTag] = context.Uint8ClampedArray; - ctorByTag[uint16Tag] = context.Uint16Array; - ctorByTag[uint32Tag] = context.Uint32Array; - - /** Used to avoid iterating over non-enumerable properties in IE < 9. */ - var nonEnumProps = {}; - nonEnumProps[arrayTag] = nonEnumProps[dateTag] = nonEnumProps[numberTag] = { 'constructor': true, 'toLocaleString': true, 'toString': true, 'valueOf': true }; - nonEnumProps[boolTag] = nonEnumProps[stringTag] = { 'constructor': true, 'toString': true, 'valueOf': true }; - nonEnumProps[errorTag] = nonEnumProps[funcTag] = nonEnumProps[regexpTag] = { 'constructor': true, 'toString': true }; - nonEnumProps[objectTag] = { 'constructor': true }; - - arrayEach(shadowProps, function(key) { - for (var tag in nonEnumProps) { - if (hasOwnProperty.call(nonEnumProps, tag)) { - var props = nonEnumProps[tag]; - props[key] = hasOwnProperty.call(props, key); - } - } - }); - /*------------------------------------------------------------------------*/ /** @@ -989,92 +956,6 @@ this.__chain__ = !!chainAll; } - /** - * An object environment feature flags. - * - * @static - * @memberOf _ - * @type Object - */ - var support = lodash.support = {}; - - (function(x) { - var Ctor = function() { this.x = x; }, - object = { '0': x, 'length': x }, - props = []; - - Ctor.prototype = { 'valueOf': x, 'y': x }; - for (var key in new Ctor) { props.push(key); } - - /** - * Detect if `name` or `message` properties of `Error.prototype` are - * enumerable by default (IE < 9, Safari < 5.1). - * - * @memberOf _.support - * @type boolean - */ - support.enumErrorProps = propertyIsEnumerable.call(errorProto, 'message') || - propertyIsEnumerable.call(errorProto, 'name'); - - /** - * Detect if `prototype` properties are enumerable by default. - * - * Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1 - * (if the prototype or a property on the prototype has been set) - * incorrectly set the `[[Enumerable]]` value of a function's `prototype` - * property to `true`. - * - * @memberOf _.support - * @type boolean - */ - support.enumPrototypes = propertyIsEnumerable.call(Ctor, 'prototype'); - - /** - * Detect if properties shadowing those on `Object.prototype` are non-enumerable. - * - * In IE < 9 an object's own properties, shadowing non-enumerable ones, - * are made non-enumerable as well (a.k.a the JScript `[[DontEnum]]` bug). - * - * @memberOf _.support - * @type boolean - */ - support.nonEnumShadows = !/valueOf/.test(props); - - /** - * Detect if own properties are iterated after inherited properties (IE < 9). - * - * @memberOf _.support - * @type boolean - */ - support.ownLast = props[0] != 'x'; - - /** - * Detect if `Array#shift` and `Array#splice` augment array-like objects - * correctly. - * - * Firefox < 10, compatibility modes of IE 8, and IE < 9 have buggy Array - * `shift()` and `splice()` functions that fail to remove the last element, - * `value[0]`, of array-like objects even though the "length" property is - * set to `0`. The `shift()` method is buggy in compatibility modes of IE 8, - * while `splice()` is buggy regardless of mode in IE < 9. - * - * @memberOf _.support - * @type boolean - */ - support.spliceObjects = (splice.call(object, 0, 1), !object[0]); - - /** - * Detect lack of support for accessing string characters by index. - * - * IE < 8 can't access characters by index. IE 8 can only access characters - * by index on string literals, not string objects. - * - * @memberOf _.support - * @type boolean - */ - support.unindexedChars = ('x'[0] + Object('x')[0]) != 'xx'; - }(1, 0)); - /** * By default, the template delimiters used by lodash are like those in * embedded Ruby (ERB). Change the following template settings to use @@ -3845,10 +3726,7 @@ */ function initCloneObject(object) { var Ctor = object.constructor; - if (!(typeof Ctor == 'function' && Ctor instanceof Ctor)) { - Ctor = Object; - } - return new Ctor; + return (typeof Ctor == 'function' && Ctor instanceof Ctor) ? new Ctor : {}; } /** @@ -3876,10 +3754,6 @@ case float32Tag: case float64Tag: case int8Tag: case int16Tag: case int32Tag: case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag: - // Safari 5 mobile incorrectly has `Object` as the constructor of typed arrays. - if (Ctor instanceof Ctor) { - Ctor = ctorByTag[tag]; - } var buffer = object.buffer; return new Ctor(isDeep ? bufferClone(buffer) : buffer, object.byteOffset, object.length); @@ -4169,36 +4043,6 @@ }; }()); - /** - * A fallback implementation of `Object.keys` which creates an array of the - * own enumerable property names of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ - function shimKeys(object) { - var result = []; - if (!object) { - return result; - } - var index = -1, - props = keysIn(object), - propsLength = props.length, - length = propsLength && object.length; - - var allowIndexes = !!length && isLength(length) && - (isArray(object) || isArguments(object) || isString(object)); - - while (++index < propsLength) { - var key = props[index]; - if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) { - result.push(key); - } - } - return result; - } - /** * Converts `value` to a function if it's not one. * @@ -4224,7 +4068,7 @@ if (!isArrayLike(value)) { return values(value); } - if (lodash.support.unindexedChars && isString(value)) { + if (isString(value)) { return value.split(''); } return isObject(value) ? value : Object(value); @@ -4238,7 +4082,7 @@ * @returns {Object} Returns the object. */ function toObject(value) { - if (lodash.support.unindexedChars && isString(value)) { + if (isString(value)) { var index = -1, length = value.length, result = Object(value); @@ -5897,9 +5741,7 @@ * // => ['barney', 'pebbles'] */ var at = restParam(function(collection, props) { - if (isArrayLike(collection)) { - collection = toIterable(collection); - } + collection = isArrayLike(collection) ? toIterable(collection) : collection; return baseAt(collection, baseFlatten(props)); }); @@ -6707,6 +6549,7 @@ * * @static * @memberOf _ + * @type Function * @category Date * @example * @@ -6715,9 +6558,7 @@ * }, _.now()); * // => logs the number of milliseconds it took for the deferred function to be invoked */ - var now = nativeNow || function() { - return new Date().getTime(); - }; + var now = Date.now; /*------------------------------------------------------------------------*/ @@ -7941,6 +7782,7 @@ * * @static * @memberOf _ + * @type Function * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. @@ -7952,9 +7794,7 @@ * _.isArray(function() { return arguments; }()); * // => false */ - var isArray = nativeIsArray || function(value) { - return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag; - }; + var isArray = Array.isArray; /** * Checks if `value` is classified as a boolean primitive or object. @@ -8411,32 +8251,17 @@ * // => true */ function isPlainObject(value) { - var Ctor; - - // Exit early for non `Object` objects. - if (!(isObjectLike(value) && objToString.call(value) == objectTag && !isHostObject(value) && !isArguments(value)) || - (!hasOwnProperty.call(value, 'constructor') && (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor)))) { + if (!(value && objToString.call(value) == objectTag)) { return false; } - // IE < 9 iterates inherited properties before own properties. If the first - // iterated property is an object's own property then there are no inherited - // enumerable properties. - var result; - if (lodash.support.ownLast) { - baseForIn(value, function(subValue, key, object) { - result = hasOwnProperty.call(object, key); - return false; - }); - return result !== false; + var proto = getPrototypeOf(value); + if (proto === null) { + return true; } - // In most environments an object's own properties are iterated before - // its inherited properties. If the last iterated property is an object's - // own property then there are no inherited enumerable properties. - baseForIn(value, function(subValue, key) { - result = key; - }); - return result === undefined || hasOwnProperty.call(value, result); - } + var Ctor = proto.constructor; + return (typeof Ctor == 'function' && + Ctor instanceof Ctor && fnToString.call(Ctor) == objCtorString); + }; /** * Checks if `value` is classified as a `RegExp` object. @@ -8588,9 +8413,7 @@ if (!value.length) { return []; } - return (lodash.support.unindexedChars && isString(value)) - ? value.split('') - : copyArray(value); + return copyArray(toObject(value)); } /** @@ -9156,17 +8979,30 @@ * _.keys('hi'); * // => ['0', '1'] */ - var keys = !nativeKeys ? shimKeys : function(object) { - if (!object) { - return []; + function keys(object) { + object = toObject(object); + if (!isArrayLike(object)) { + return nativeKeys(object); } - var Ctor = object.constructor; - if ((typeof Ctor == 'function' && Ctor.prototype === object) || - (typeof object == 'function' ? lodash.support.enumPrototypes : isArrayLike(object))) { - return shimKeys(object); + var length = object.length; + length = (length && isLength(length) && + (isArray(object) || isArguments(object) || isString(object)) && length) || 0; + + var index = -1, + skipIndexes = length > 0, + result = Array(length); + + while (++index < length) { + result[index] = (index + ''); } - return isObject(object) ? nativeKeys(object) : []; - }; + for (var key in object) { + if (hasOwnProperty.call(object, key) && + !(skipIndexes && isIndex(key, length))) { + result.push(key); + } + } + return result; + } /** * Creates an array of the own and inherited enumerable property names of `object`. @@ -9191,58 +9027,24 @@ * // => ['a', 'b', 'c'] (iteration order is not guaranteed) */ function keysIn(object) { - if (object == null) { - return []; - } - if (!isObject(object)) { - object = Object(object); - } - var length = object.length, - support = lodash.support; - - length = (length && isLength(length) && - (isArray(object) || isArguments(object) || isString(object)) && length) || 0; + object = toObject(object); - var Ctor = object.constructor, - index = -1, - proto = (isFunction(Ctor) && Ctor.prototype) || objectProto, - isProto = proto === object, - result = Array(length), - skipIndexes = length > 0, - skipErrorProps = support.enumErrorProps && (object === errorProto || object instanceof Error), - skipProto = support.enumPrototypes && isFunction(object); + var cache = {}, + result = []; - while (++index < length) { - result[index] = (index + ''); - } - // lodash skips the `constructor` property when it infers it's iterating - // over a `prototype` object because IE < 9 can't set the `[[Enumerable]]` - // attribute of an existing property and the `constructor` property of a - // prototype defaults to non-enumerable. - for (var key in object) { - if (!(skipProto && key == 'prototype') && - !(skipErrorProps && (key == 'message' || key == 'name')) && - !(skipIndexes && isIndex(key, length)) && - !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { - result.push(key); - } - } - if (support.nonEnumShadows && object !== objectProto) { - var tag = object === stringProto ? stringTag : (object === errorProto ? errorTag : objToString.call(object)), - nonEnums = nonEnumProps[tag] || nonEnumProps[objectTag]; + while (object) { + var index = -1, + props = keys(object), + length = props.length; - if (tag == objectTag) { - proto = objectProto; - } - length = shadowProps.length; - while (length--) { - key = shadowProps[length]; - var nonEnum = nonEnums[key]; - if (!(isProto && nonEnum) && - (nonEnum ? hasOwnProperty.call(object, key) : object[key] !== proto[key])) { + while (++index < length) { + var key = props[index]; + if (cache[key] !== cache) { result.push(key); + cache[key] = cache; } } + object = getPrototypeOf(object); } return result; } @@ -11848,21 +11650,10 @@ // Add `Array` and `String` methods to `lodash.prototype`. arrayEach(['join', 'pop', 'push', 'replace', 'shift', 'sort', 'splice', 'split', 'unshift'], function(methodName) { - var protoFunc = (/^(?:replace|split)$/.test(methodName) ? stringProto : arrayProto)[methodName], + var func = (/^(?:replace|split)$/.test(methodName) ? stringProto : arrayProto)[methodName], chainName = /^(?:push|sort|unshift)$/.test(methodName) ? 'tap' : 'thru', - fixObjects = !support.spliceObjects && /^(?:pop|shift|splice)$/.test(methodName), retUnwrapped = /^(?:join|pop|replace|shift)$/.test(methodName); - // Avoid array-like object bugs with `Array#shift` and `Array#splice` in - // IE < 9, Firefox < 10, and RingoJS. - var func = !fixObjects ? protoFunc : function() { - var result = protoFunc.apply(this, arguments); - if (this.length === 0) { - delete this[0]; - } - return result; - }; - lodash.prototype[methodName] = function() { var args = arguments; if (retUnwrapped && !this.__chain__) { diff --git a/test/index.html b/test/index.html index 05ec942915..f2db1a236e 100644 --- a/test/index.html +++ b/test/index.html @@ -49,8 +49,7 @@ function addBizarroMethods() { var funcProto = Function.prototype, - objectProto = Object.prototype, - stringProto = String.prototype; + objectProto = Object.prototype; var hasOwnProperty = objectProto.hasOwnProperty, fnToString = funcProto.toString, @@ -82,26 +81,6 @@ funcProto._method = noop; // Set bad shims. - setProperty(Array, '_isArray', Array.isArray); - setProperty(Array, 'isArray', noop); - - setProperty(Date, '_now', Date.now); - setProperty(Date, 'now', noop); - - setProperty(Object, '_keys', Object.keys); - setProperty(Object, 'keys', noop); - - setProperty(objectProto, '_propertyIsEnumerable', propertyIsEnumerable); - setProperty(objectProto, 'propertyIsEnumerable', function(key) { - if (key == '1' && this && typeof this == 'object' && - hasOwnProperty.call(this, 'callee') && - !propertyIsEnumerable.call(this, 'callee') && - this.length === 2 && this[0] === 1 && this[1] === 0) { - throw new Error; - } - return propertyIsEnumerable.call(this, key); - }); - setProperty(window, '_Set', window.Set); setProperty(window, 'Set', noop); @@ -118,25 +97,8 @@ } function removeBizarroMethods() { - var funcProto = Function.prototype, - objectProto = Object.prototype, - stringProto = String.prototype; + var funcProto = Function.prototype; - if (Array._isArray) { - setProperty(Array, 'isArray', Array._isArray); - } else { - delete Array.isArray; - } - if (Date._now) { - setProperty(Date, 'now', Date._now); - } else { - delete Date.now; - } - if (Object._keys) { - setProperty(Object, 'keys', Object._keys); - } else { - delete Object.keys; - } if (window._Set) { Set = _Set; } @@ -153,13 +115,7 @@ setProperty(window, 'global', undefined); setProperty(window, 'module', undefined); - setProperty(objectProto, 'propertyIsEnumerable', objectProto._propertyIsEnumerable); - - delete Array._isArray; - delete Date._now; - delete Object._keys; delete funcProto._method; - delete objectProto._propertyIsEnumerable; } // Load lodash to expose it to the bad extensions/shims. diff --git a/test/test.js b/test/test.js index 0a9da57fa4..6e395176d3 100644 --- a/test/test.js +++ b/test/test.js @@ -428,24 +428,6 @@ // Add prototype extensions. funcProto._method = _.noop; - // Set bad shims. - var _isArray = Array.isArray; - setProperty(Array, 'isArray', _.noop); - - var _now = Date.now; - setProperty(Date, 'now', _.noop); - - var _keys = Object.keys; - setProperty(Object, 'keys', _.noop); - - var _propertyIsEnumerable = objectProto.propertyIsEnumerable; - setProperty(objectProto, 'propertyIsEnumerable', function(key) { - if (key == '1' && _.isArguments(this) && _.isEqual(_.values(this), [1, 0])) { - throw new Error; - } - return _propertyIsEnumerable.call(this, key); - }); - var _Set = root.Set; setProperty(root, 'Set', _.noop); @@ -463,12 +445,6 @@ root._ = oldDash; // Restore built-in methods. - setProperty(Array, 'isArray', _isArray); - setProperty(Date, 'now', _now); - setProperty(Object, 'keys', _keys); - - setProperty(objectProto, 'propertyIsEnumerable', _propertyIsEnumerable); - if (_Set) { setProperty(root, 'Set', Set); } else { @@ -644,7 +620,7 @@ } }); - test('should avoid overwritten native methods', 7, function() { + test('should avoid overwritten native methods', 1, function() { function Foo() {} function message(lodashMethod, nativeMethod) { @@ -657,28 +633,7 @@ if (lodashBizarro) { try { - var actual = [lodashBizarro.isArray([]), lodashBizarro.isArray({ 'length': 0 })]; - } catch(e) { - actual = null; - } - deepEqual(actual, [true, false], message('_.isArray', 'Array.isArray')); - - try { - actual = lodashBizarro.now(); - } catch(e) { - actual = null; - } - ok(typeof actual == 'number', message('_.now', 'Date.now')); - - try { - actual = [lodashBizarro.keys(object), lodashBizarro.keys()]; - } catch(e) { - actual = null; - } - deepEqual(actual, [['a'], []], message('_.keys', 'Object.keys')); - - try { - actual = [ + var actual = [ lodashBizarro.difference([object, otherObject], largeArray), lodashBizarro.intersection(largeArray, [object]), lodashBizarro.uniq(largeArray) @@ -687,25 +642,9 @@ actual = null; } deepEqual(actual, [[otherObject], [object], [object]], message('_.difference`, `_.intersection`, and `_.uniq', 'Set')); - - // Avoid comparing buffers with `deepEqual` in Rhino because it errors. - if (ArrayBuffer && Uint8Array) { - try { - var array = new Uint8Array(new ArrayBuffer(10)); - actual = lodashBizarro.cloneDeep(array); - } catch(e) { - actual = null; - } - deepEqual(actual, array, message('_.cloneDeep', 'Float64Array')); - notStrictEqual(actual && actual.buffer, array.buffer, message('_.cloneDeep', 'Float64Array')); - notStrictEqual(actual, array, message('_.cloneDeep', 'Float64Array')); - } - else { - skipTest(3); - } } else { - skipTest(7); + skipTest(); } }); }()); @@ -8800,15 +8739,10 @@ test('`_.' + methodName + '` should coerce primitives to objects (test in IE 9)', 2, function() { deepEqual(func('abc').sort(), ['0', '1', '2']); - if (!isKeys) { - // IE 9 doesn't box numbers in for-in loops. - Number.prototype.a = 1; - deepEqual(func(0).sort(), ['a']); - delete Number.prototype.a; - } - else { - skipTest(); - } + // IE 9 doesn't box numbers in for-in loops. + Number.prototype.a = 1; + deepEqual(func(0).sort(), isKeys ? [] : ['a']); + delete Number.prototype.a; }); test('`_.' + methodName + '` should treat sparse arrays as dense', 1, function() { @@ -8818,10 +8752,10 @@ deepEqual(func(array).sort(), ['0', '1', '2']); }); - test('`_.' + methodName + '` should return an empty array for nullish values', 2, function() { + test('`_.' + methodName + '` should coerce nullish values to objects', 2, function() { objectProto.a = 1; _.each([null, undefined], function(value) { - deepEqual(func(value), []); + deepEqual(func(value), isKeys ? [] : ['a']); }); delete objectProto.a; }); @@ -15188,9 +15122,11 @@ }; var lodash = _.runInContext(_.assign({}, root, { - 'Date': function() { + 'Date': _.assign(function() { return { 'getTime': getTime }; - } + }, { + 'now': Date.now + }) })); var throttled = lodash.throttle(function() { @@ -15465,9 +15401,11 @@ }; var lodash = _.runInContext(_.assign({}, root, { - 'Date': function() { + 'Date': _.assign(function() { return { 'getTime': getTime, 'valueOf': getTime }; - } + }, { + 'now': Date.now + }) })); var funced = lodash[methodName](function() { From 0beaf47a6444f27a821b29cf9946b4752691a16b Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Tue, 14 Jul 2015 22:46:17 -0700 Subject: [PATCH 053/935] Extract common components of `_.keys` and `_.keysIn` and make `_.keysIn` use the `Reflect.enumerate` shim as a compat path for older enviros. --- lodash.src.js | 167 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 115 insertions(+), 52 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index e02136c144..cbc7dfe98b 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -142,9 +142,9 @@ var contextProps = [ 'Array', 'ArrayBuffer', 'Date', 'Error', 'Float32Array', 'Float64Array', 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Math', 'Number', - 'Object', 'RegExp', 'Set', 'String', '_', 'clearTimeout', 'isFinite', - 'parseFloat', 'parseInt', 'setTimeout', 'TypeError', 'Uint8Array', - 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap' + 'Object', 'Reflect', 'RegExp', 'Set', 'String', 'TypeError', 'Uint8Array', + 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap', '_', + 'clearTimeout', 'isFinite', 'parseFloat', 'parseInt', 'setTimeout', ]; /** Used to make template sourceURLs easier to identify. */ @@ -743,6 +743,7 @@ Math = context.Math, Number = context.Number, Object = context.Object, + Reflect = context.Reflect, RegExp = context.RegExp, String = context.String, TypeError = context.TypeError; @@ -782,6 +783,7 @@ /** Native method references. */ var ArrayBuffer = context.ArrayBuffer, clearTimeout = context.clearTimeout, + enumerate = Reflect ? Reflect.enumerate : undefined, getPrototypeOf = Object.getPrototypeOf, parseFloat = context.parseFloat, pow = Math.pow, @@ -1862,29 +1864,6 @@ return result; } - /** - * The base implementation of `_.iteratee`. - * - * @private - * @param {*} [func=_.identity] The value to convert to an iteratee. - * @returns {Function} Returns the iteratee. - */ - function baseIteratee(func) { - var type = typeof func; - if (type == 'function') { - return func; - } - if (func == null) { - return identity; - } - if (type == 'object') { - return isArray(func) - ? baseMatchesProperty(func[0], func[1]) - : baseMatches(func); - } - return property(func); - } - /** * The base implementation of `baseForIn` and `baseForOwn` which iterates * over `object` properties returned by `keysFunc` invoking `iteratee` for @@ -2145,6 +2124,59 @@ return true; } + /** + * The base implementation of `_.iteratee`. + * + * @private + * @param {*} [func=_.identity] The value to convert to an iteratee. + * @returns {Function} Returns the iteratee. + */ + function baseIteratee(func) { + var type = typeof func; + if (type == 'function') { + return func; + } + if (func == null) { + return identity; + } + if (type == 'object') { + return isArray(func) + ? baseMatchesProperty(func[0], func[1]) + : baseMatches(func); + } + return property(func); + } + + /** + * The base implementation of `_.keysIn` which does not skip the constructor + * property of prototypes or treat sparse arrays as dense. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ + function baseKeysIn(object) { + var result = []; + for (var key in object) { + result.push(key); + } + return result; + } + + // An alternative implementation intended for IE < 9 with es6-shim. + if (enumerate && !propertyIsEnumerable.call({ 'valueOf': 1 }, 'valueOf')) { + var baseKeysIn = function(object) { + var data, + iterator = enumerate(object), + result = []; + + while (!(data = iterator.next()).done) { + result.push(data.value); + } + return result; + }; + } + /** * The base implementation of `_.map` without support for callback shorthands. * @@ -3768,6 +3800,29 @@ return result; } + /** + * Initializes an array of property names based on `object`. If `object` is + * an array, `arguments` object, or `string` its index keys are returned, + * otherwise an empty array is returned. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the initialized array of property names. + */ + function initKeys(object) { + var length = object.length; + length = (length && isLength(length) && + (isArray(object) || isArguments(object) || isString(object)) && length) || 0; + + var index = -1, + result = Array(length); + + while (++index < length) { + result[index] = (index + ''); + } + return result; + } + /** * Invokes the method at `path` on `object`. * @@ -3889,6 +3944,20 @@ return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; } + /** + * Checks if `value` is a prototype. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. + */ + function isPrototype(value) { + var Ctor = !!value && value.constructor, + proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; + + return value === proto; + } + /** * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. * @@ -8981,23 +9050,19 @@ */ function keys(object) { object = toObject(object); - if (!isArrayLike(object)) { + + var isProto = isPrototype(object); + if (!(isProto || isArrayLike(object))) { return nativeKeys(object); } - var length = object.length; - length = (length && isLength(length) && - (isArray(object) || isArguments(object) || isString(object)) && length) || 0; - - var index = -1, - skipIndexes = length > 0, - result = Array(length); + var result = initKeys(object), + length = result.length, + skipIndexes = !!length; - while (++index < length) { - result[index] = (index + ''); - } for (var key in object) { if (hasOwnProperty.call(object, key) && - !(skipIndexes && isIndex(key, length))) { + !(skipIndexes && isIndex(key, length)) && + !(isProto && key == 'constructor')) { result.push(key); } } @@ -9029,22 +9094,20 @@ function keysIn(object) { object = toObject(object); - var cache = {}, - result = []; - - while (object) { - var index = -1, - props = keys(object), - length = props.length; + var index = -1, + isProto = isPrototype(object), + props = baseKeysIn(object), + propsLength = props.length, + result = initKeys(object), + length = result.length, + skipIndexes = !!length; - while (++index < length) { - var key = props[index]; - if (cache[key] !== cache) { - result.push(key); - cache[key] = cache; - } + while (++index < propsLength) { + var key = props[index]; + if (!(skipIndexes && isIndex(key, length)) && + !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { + result.push(key); } - object = getPrototypeOf(object); } return result; } From b821660e799a2701d0a1b0a62e56a732e75791a9 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Tue, 14 Jul 2015 23:12:31 -0700 Subject: [PATCH 054/935] Remove irrelevant comments. [ci skip] --- lodash.src.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index cbc7dfe98b..b2ab5c7950 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -4941,8 +4941,8 @@ /** * Creates a slice of `array` from `start` up to, but not including, `end`. * - * **Note:** This method is used instead of `Array#slice` to support node - * lists in IE < 9 and to ensure dense arrays are returned. + * **Note:** This method is used instead of `Array#slice` to ensure dense + * arrays are returned. * * @static * @memberOf _ @@ -9799,7 +9799,6 @@ * // => 'fred, barney, & pebbles' */ function escape(string) { - // Reset `lastIndex` because in IE < 9 `String#replace` does not. string = baseToString(string); return (string && reHasUnescapedHtml.test(string)) ? string.replace(reUnescapedHtml, escapeHtmlChar) From e6b9aaf4995b6ff7051ccf10e3950aad2d802702 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Wed, 15 Jul 2015 07:41:05 -0700 Subject: [PATCH 055/935] Temporarily reduce scope of automated testing until things are more stable. --- .travis.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 33f4238c56..ba397bf175 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,10 +12,10 @@ env: - BUILD="modern" - BUILD="modern" - BUILD="modern" ISTANBUL=true - - BIN="phantomjs" - - BIN="rhino" OPTION="-opt -1" - - BIN="rhino" OPTION="-opt -1 -require" - - BIN="ringo" OPTION="-o -1" +# - BIN="phantomjs" +# - BIN="rhino" OPTION="-opt -1" +# - BIN="rhino" OPTION="-opt -1 -require" +# - BIN="ringo" OPTION="-o -1" matrix: include: - node_js: "iojs" @@ -66,11 +66,11 @@ script: - "[ $SAUCE_LABS == true ] || [ $ISTANBUL == true ] || cd ./test" - "[ $SAUCE_LABS == true ] || [ $ISTANBUL == true ] || $BIN $OPTION ./test.js ../lodash.$BUILD.js" - "[ $SAUCE_LABS == true ] || [ $ISTANBUL == true ] || [ $TRAVIS_SECURE_ENV_VARS == false ] || $BIN $OPTION ./test.js ../lodash.$BUILD.min.js" - - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"lodash tests\" runner=\"test/index.html?build=../lodash.$BUILD.js&noglobals=true\" tags=\"$BUILD,development\"" - - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"lodash tests\" runner=\"test/index.html?build=../lodash.$BUILD.min.js&noglobals=true\" tags=\"$BUILD,production\"" - - "[ $SAUCE_LABS == false ] || [ $BUILD != 'compat' ] || $BIN ./test/saucelabs.js name=\"lodash tests\" runner=\"test/index.html?build=../lodash.$BUILD.js\" tags=\"$BUILD,development,ie-compat\" compatMode=7" - - "[ $SAUCE_LABS == false ] || [ $BUILD != 'compat' ] || $BIN ./test/saucelabs.js name=\"lodash tests\" runner=\"test/index.html?build=../lodash.$BUILD.min.js\" tags=\"$BUILD,production,ie-compat\" compatMode=7" - - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"backbone tests\" runner=\"test/backbone.html?build=../lodash.$BUILD.min.js\" tags=\"$BUILD,production,backbone\"" - - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"backbone tests\" runner=\"test/backbone.html?build=../lodash.$BUILD.js\" tags=\"$BUILD,development,backbone\"" - - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"underscore tests\" runner=\"test/underscore.html?build=../lodash.$BUILD.min.js\" tags=\"$BUILD,production,underscore\"" - - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"underscore tests\" runner=\"test/underscore.html?build=../lodash.$BUILD.js\" tags=\"$BUILD,development,underscore\"" +# - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"lodash tests\" runner=\"test/index.html?build=../lodash.$BUILD.js&noglobals=true\" tags=\"$BUILD,development\"" +# - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"lodash tests\" runner=\"test/index.html?build=../lodash.$BUILD.min.js&noglobals=true\" tags=\"$BUILD,production\"" +# - "[ $SAUCE_LABS == false ] || [ $BUILD != 'compat' ] || $BIN ./test/saucelabs.js name=\"lodash tests\" runner=\"test/index.html?build=../lodash.$BUILD.js\" tags=\"$BUILD,development,ie-compat\" compatMode=7" +# - "[ $SAUCE_LABS == false ] || [ $BUILD != 'compat' ] || $BIN ./test/saucelabs.js name=\"lodash tests\" runner=\"test/index.html?build=../lodash.$BUILD.min.js\" tags=\"$BUILD,production,ie-compat\" compatMode=7" +# - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"backbone tests\" runner=\"test/backbone.html?build=../lodash.$BUILD.min.js\" tags=\"$BUILD,production,backbone\"" +# - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"backbone tests\" runner=\"test/backbone.html?build=../lodash.$BUILD.js\" tags=\"$BUILD,development,backbone\"" +# - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"underscore tests\" runner=\"test/underscore.html?build=../lodash.$BUILD.min.js\" tags=\"$BUILD,production,underscore\"" +# - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"underscore tests\" runner=\"test/underscore.html?build=../lodash.$BUILD.js\" tags=\"$BUILD,development,underscore\"" From 192e35882a6a0d863752bd2c6834c58e4da559b5 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Wed, 15 Jul 2015 07:58:25 -0700 Subject: [PATCH 056/935] Remove `toIterable` and `toObject`. --- lodash.src.js | 89 ++++++++++++--------------------------------------- 1 file changed, 20 insertions(+), 69 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index b2ab5c7950..c65640ed63 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -1963,15 +1963,14 @@ if (object == null) { return; } - object = toObject(object); - if (pathKey !== undefined && pathKey in object) { + if (pathKey !== undefined && pathKey in Object(object)) { path = [pathKey]; } var index = 0, length = path.length; while (object != null && index < length) { - object = toObject(object)[path[index++]]; + object = object[path[index++]]; } return (index && index == length) ? object : undefined; } @@ -2094,7 +2093,7 @@ if (object == null) { return !length; } - object = toObject(object); + object = Object(object); while (index--) { var data = matchData[index]; if ((noCustomizer && data[2]) @@ -2212,8 +2211,7 @@ if (object == null) { return false; } - object = toObject(object); - return object[key] === value && (value !== undefined || (key in object)); + return object[key] === value && (value !== undefined || (key in Object(object))); }; } return function(object) { @@ -2240,17 +2238,15 @@ return false; } var key = pathKey; - object = toObject(object); - if ((isArr || !isCommon) && !(key in object)) { + if ((isArr || !isCommon) && !(key in Object(object))) { object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); if (object == null) { return false; } key = last(path); - object = toObject(object); } return object[key] === srcValue - ? (srcValue !== undefined || (key in object)) + ? (srcValue !== undefined || (key in Object(object))) : baseIsEqual(srcValue, object[key], undefined, true); }; } @@ -2364,7 +2360,7 @@ * @returns {Object} Returns the new object. */ function basePick(object, props) { - object = toObject(object); + object = Object(object); var index = -1, length = props.length, @@ -2406,7 +2402,7 @@ */ function baseProperty(key) { return function(object) { - return object == null ? undefined : toObject(object)[key]; + return object == null ? undefined : object[key]; }; } @@ -2987,7 +2983,7 @@ customizer = length < 3 ? undefined : customizer; length = 1; } - object = toObject(object); + object = Object(object); while (++index < length) { var source = sources[index]; if (source) { @@ -3016,7 +3012,7 @@ } var length = collection.length, index = fromRight ? length : -1, - iterable = toObject(collection); + iterable = Object(collection); while ((fromRight ? index-- : ++index < length)) { if (iteratee(iterable[index], index, iterable) === false) { @@ -3036,7 +3032,7 @@ */ function createBaseFor(fromRight) { return function(object, iteratee, keysFunc) { - var iterable = toObject(object), + var iterable = Object(object), props = keysFunc(object), length = props.length, index = fromRight ? length : -1; @@ -3907,7 +3903,7 @@ return false; } var result = !reIsDeepProp.test(value); - return result || (object != null && value in toObject(object)); + return result || (object != null && value in Object(object)); } /** @@ -4123,47 +4119,6 @@ return typeof func == 'function' ? func : identity; } - /** - * Converts `value` to an array-like object if it's not one. - * - * @private - * @param {*} value The value to process. - * @returns {Array|Object} Returns the array-like object. - */ - function toIterable(value) { - if (value == null) { - return []; - } - if (!isArrayLike(value)) { - return values(value); - } - if (isString(value)) { - return value.split(''); - } - return isObject(value) ? value : Object(value); - } - - /** - * Converts `value` to an object if it's not one. - * - * @private - * @param {*} value The value to process. - * @returns {Object} Returns the object. - */ - function toObject(value) { - if (isString(value)) { - var index = -1, - length = value.length, - result = Object(value); - - while (++index < length) { - result[index] = value.charAt(index); - } - return result; - } - return isObject(value) ? value : Object(value); - } - /** * Converts `value` to property path array if it's not one. * @@ -5671,7 +5626,7 @@ var wrapperConcat = restParam(function(values) { values = baseFlatten(values); return this.thru(function(array) { - return arrayConcat(isArray(array) ? array : [toObject(array)], values); + return arrayConcat(isArray(array) ? array : [Object(array)], values); }); }); @@ -5810,7 +5765,6 @@ * // => ['barney', 'pebbles'] */ var at = restParam(function(collection, props) { - collection = isArrayLike(collection) ? toIterable(collection) : collection; return baseAt(collection, baseFlatten(props)); }); @@ -6407,7 +6361,7 @@ */ function sample(collection, n, guard) { if (guard ? isIterateeCall(collection, n, guard) : n == null) { - collection = toIterable(collection); + collection = isArrayLike(collection) ? collection : values(collection); var length = collection.length; return length > 0 ? collection[baseRandom(0, length - 1)] : undefined; } @@ -8479,10 +8433,7 @@ if (!isArrayLike(value)) { return values(value); } - if (!value.length) { - return []; - } - return copyArray(toObject(value)); + return value.length ? copyArray(value) : []; } /** @@ -9049,7 +9000,7 @@ * // => ['0', '1'] */ function keys(object) { - object = toObject(object); + object = Object(object); var isProto = isPrototype(object); if (!(isProto || isArrayLike(object))) { @@ -9092,7 +9043,7 @@ * // => ['a', 'b', 'c'] (iteration order is not guaranteed) */ function keysIn(object) { - object = toObject(object); + object = Object(object); var index = -1, isProto = isPrototype(object), @@ -9306,7 +9257,7 @@ * // => [['barney', 36], ['fred', 40]] (iteration order is not guaranteed) */ function pairs(object) { - object = toObject(object); + object = Object(object); var index = -1, props = keys(object), @@ -9391,12 +9342,12 @@ * // => 'default' */ function result(object, path, defaultValue) { - var result = object == null ? undefined : toObject(object)[path]; + var result = object == null ? undefined : object[path]; if (result === undefined) { if (object != null && !isKey(path, object)) { path = toPath(path); object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); - result = object == null ? undefined : toObject(object)[last(path)]; + result = object == null ? undefined : object[last(path)]; } result = result === undefined ? defaultValue : result; } From 33a9ebaba14c1d2d1c36b7ed18d31562522f1a17 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Wed, 15 Jul 2015 08:05:55 -0700 Subject: [PATCH 057/935] Fix `_.matches` and `_.matchesProperty` doc notes on inherited properties. [ci skip] [closes #1344] --- lodash.src.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index c65640ed63..44f6e9e230 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -10601,8 +10601,8 @@ * * **Note:** This method supports comparing arrays, booleans, `Date` objects, * numbers, `Object` objects, regexes, and strings. Objects are compared by - * their own, not inherited, enumerable properties. For comparing a single - * own or inherited property value see `_.matchesProperty`. + * their own and inherited enumerable properties. For comparing a single + * value see `_.matchesProperty`. * * @static * @memberOf _ @@ -10625,11 +10625,10 @@ /** * Creates a function that compares the property value of `path` on a given - * object to `value`. + * object to `srcValue`. * * **Note:** This method supports comparing arrays, booleans, `Date` objects, - * numbers, `Object` objects, regexes, and strings. Objects are compared by - * their own, not inherited, enumerable properties. + * numbers, `Object` objects, regexes, and strings. * * @static * @memberOf _ From 5d842273d94b116751aa68fa2ea489bbc77478fc Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Wed, 15 Jul 2015 09:33:55 -0700 Subject: [PATCH 058/935] Remove accidental trailing comma. --- lodash.src.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lodash.src.js b/lodash.src.js index 44f6e9e230..8d403a414a 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -144,7 +144,7 @@ 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Math', 'Number', 'Object', 'Reflect', 'RegExp', 'Set', 'String', 'TypeError', 'Uint8Array', 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap', '_', - 'clearTimeout', 'isFinite', 'parseFloat', 'parseInt', 'setTimeout', + 'clearTimeout', 'isFinite', 'parseFloat', 'parseInt', 'setTimeout' ]; /** Used to make template sourceURLs easier to identify. */ From 862c7fde6dd7323c3866057d2487fb06079d5ad2 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 16 Jul 2015 09:12:04 -0700 Subject: [PATCH 059/935] Docs cleanup pass. [ci skip] --- lodash.src.js | 69 +++++++++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 38 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 8d403a414a..188a2c4933 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -567,8 +567,8 @@ return function() { return false; }; } return function(value) { - // IE < 9 presents many host objects as `Object` objects that can coerce - // to strings despite having improperly defined `toString` methods. + // Many host objects are `Object` objects that can coerce to strings + // despite having improperly defined `toString` methods. return typeof value.toString != 'function' && typeof (value + '') == 'string'; }; }()); @@ -2147,7 +2147,7 @@ } /** - * The base implementation of `_.keysIn` which does not skip the constructor + * The base implementation of `_.keysIn` which doesn't skip the constructor * property of prototypes or treat sparse arrays as dense. * * @private @@ -2195,7 +2195,7 @@ } /** - * The base implementation of `_.matches` which does not clone `source`. + * The base implementation of `_.matches` which doesn't clone `source`. * * @private * @param {Object} source The object of property values to match. @@ -4120,7 +4120,7 @@ } /** - * Converts `value` to property path array if it's not one. + * Converts `value` to a property path array if it's not one. * * @private * @param {*} value The value to process. @@ -4798,8 +4798,7 @@ /** * Removes elements from `array` corresponding to the given indexes and returns - * an array of the removed elements. Indexes may be specified as an array of - * indexes or as individual arguments. + * an array of the removed elements. * * **Note:** Unlike `_.at`, this method mutates `array`. * @@ -4808,7 +4807,7 @@ * @category Array * @param {Array} array The array to modify. * @param {...(number|number[])} [indexes] The indexes of elements to remove, - * specified as individual indexes or arrays of indexes. + * specified individually or in arrays. * @returns {Array} Returns the new array of removed elements. * @example * @@ -6117,7 +6116,8 @@ * @memberOf _ * @category Collection * @param {Array|Object|string} collection The collection to iterate over. - * @param {Array|Function|string} path The path of the method to invoke or the function invoked per iteration. + * @param {Array|Function|string} path The path of the method to invoke or + * the function invoked per iteration. * @param {...*} [args] The arguments to invoke the method with. * @returns {Array} Returns the array of results. * @example @@ -6429,7 +6429,7 @@ /** * Checks if `predicate` returns truthy for **any** element of `collection`. - * The function returns as soon as it finds a passing value and does not iterate + * The function returns as soon as it finds a passing value and doesn't iterate * over the entire collection. The predicate is invoked with three arguments: * (value, index|key, collection). * @@ -6482,7 +6482,7 @@ * @category Collection * @param {Array|Object|string} collection The collection to iterate over. * @param {...(Function|Function[]|Object|Object[]|string|string[])} [iteratees=[_.identity]] - * The iteratees to sort by, specified as individual values or arrays of values. + * The iteratees to sort by, specified individually or in arrays. * @returns {Array} Returns the new sorted array. * @example * @@ -6696,7 +6696,7 @@ * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds, * may be used as a placeholder for partially applied arguments. * - * **Note:** Unlike native `Function#bind` this method does not set the "length" + * **Note:** Unlike native `Function#bind` this method doesn't set the "length" * property of bound functions. * * @static @@ -6734,18 +6734,16 @@ /** * Binds methods of an object to the object itself, overwriting the existing - * method. Method names may be specified as individual arguments or as arrays - * of method names. If no method names are provided all enumerable function - * properties, own and inherited, of `object` are bound. + * method. * - * **Note:** This method does not set the "length" property of bound functions. + * **Note:** This method doesn't set the "length" property of bound functions. * * @static * @memberOf _ * @category Function * @param {Object} object The object to bind and assign the bound methods to. * @param {...(string|string[])} methodNames The object method names to bind, - * specified as individual method names or arrays of method names. + * specified individually or in arrays. * @returns {Object} Returns `object`. * @example * @@ -6836,7 +6834,7 @@ * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds, * may be used as a placeholder for provided arguments. * - * **Note:** This method does not set the "length" property of curried functions. + * **Note:** This method doesn't set the "length" property of curried functions. * * @static * @memberOf _ @@ -6882,7 +6880,7 @@ * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic * builds, may be used as a placeholder for provided arguments. * - * **Note:** This method does not set the "length" property of curried functions. + * **Note:** This method doesn't set the "length" property of curried functions. * * @static * @memberOf _ @@ -7256,7 +7254,7 @@ * @category Function * @param {Function} func The function to wrap. * @param {...(Function|Function[])} [transforms] The functions to transform - * arguments, specified as individual functions or arrays of functions. + * arguments, specified individually or in arrays. * @returns {Function} Returns the new function. * @example * @@ -7350,7 +7348,7 @@ * The `_.partial.placeholder` value, which defaults to `_` in monolithic * builds, may be used as a placeholder for partially applied arguments. * - * **Note:** This method does not set the "length" property of partially + * **Note:** This method doesn't set the "length" property of partially * applied functions. * * @static @@ -7386,7 +7384,7 @@ * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic * builds, may be used as a placeholder for partially applied arguments. * - * **Note:** This method does not set the "length" property of partially + * **Note:** This method doesn't set the "length" property of partially * applied functions. * * @static @@ -7426,7 +7424,7 @@ * @category Function * @param {Function} func The function to rearrange arguments for. * @param {...(number|number[])} indexes The arranged argument indexes, - * specified as individual indexes or arrays of indexes. + * specified individually or in arrays. * @returns {Function} Returns the new function. * @example * @@ -8050,9 +8048,8 @@ */ function isFunction(value) { // The use of `Object#toString` avoids issues with the `typeof` operator - // in older versions of Chrome and Safari which return 'function' for regexes, - // Safari 8 which returns 'object' for typed array constructors, and PhantomJS 1.9 - // which returns 'function' for `NodeList` instances. + // in Safari 8 which returns 'object' for typed array constructors, and + // PhantomJS 1.9 which returns 'function' for `NodeList` instances. return isObject(value) && objToString.call(value) == funcTag; } @@ -8167,7 +8164,7 @@ */ function isNaN(value) { // An `NaN` primitive is the only value that is not equal to itself. - // Perform the `toStringTag` check first to avoid errors with some host objects in IE. + // Perform the `toStringTag` check first to avoid errors with some ActiveX objects in IE. return isNumber(value) && value != +value; } @@ -8247,9 +8244,6 @@ * Checks if `value` is a plain object, that is, an object created by the * `Object` constructor or one with a `[[Prototype]]` of `null`. * - * **Note:** This method assumes objects created by the `Object` constructor - * have no inherited enumerable properties. - * * @static * @memberOf _ * @category Lang @@ -9199,8 +9193,8 @@ * @memberOf _ * @category Object * @param {Object} object The source object. - * @param {string|string[]} [props] The property names to omit, specified as - * individual property names or arrays of property names. + * @param {string|string[]} [props] The property names to omit, specified + * individually or in arrays.. * @returns {Object} Returns the new object. * @example * @@ -9219,8 +9213,8 @@ /** * The opposite of `_.pickBy`; this method creates an object composed of the - * own and inherited enumerable properties of `object` that `predicate` does - * not return truthy for. + * own and inherited enumerable properties of `object` that `predicate` + * doesn't return truthy for. * * @static * @memberOf _ @@ -9278,8 +9272,8 @@ * @memberOf _ * @category Object * @param {Object} object The source object. - * @param {string|string[]} [props] The property names to pick, specified as - * individual property names or arrays of property names. + * @param {string|string[]} [props] The property names to pick, specified + * individually or in arrays. * @returns {Object} Returns the new object. * @example * @@ -9356,7 +9350,7 @@ /** * Sets the property value of `path` on `object`. If a portion of `path` - * does not exist it's created. + * doesn't exist it's created. * * @static * @memberOf _ @@ -9916,7 +9910,6 @@ * // => [6, 8, 10] */ function parseInt(string, radix, guard) { - // Firefox < 21 and Opera < 15 follow ES3 for `parseInt`. // Chrome fails to trim leading whitespace characters. // See https://code.google.com/p/v8/issues/detail?id=3109 for more details. if (guard ? isIterateeCall(string, radix, guard) : radix == null) { From 19836a55a3832f37d4f2475ecae3c8df9f5d55a0 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 16 Jul 2015 09:19:11 -0700 Subject: [PATCH 060/935] Remove an `isArray` check from `baseMatchesProperty`. --- lodash.src.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 188a2c4933..171a5e78f6 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -2220,7 +2220,7 @@ } /** - * The base implementation of `_.matchesProperty` which does not clone `srcValue`. + * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`. * * @private * @param {string} path The path of the property to get. @@ -2228,8 +2228,7 @@ * @returns {Function} Returns the new function. */ function baseMatchesProperty(path, srcValue) { - var isArr = isArray(path), - isCommon = isKey(path) && isStrictComparable(srcValue), + var isCommon = isKey(path) && isStrictComparable(srcValue), pathKey = (path + ''); path = toPath(path); @@ -2238,7 +2237,7 @@ return false; } var key = pathKey; - if ((isArr || !isCommon) && !(key in Object(object))) { + if (!isCommon && !(key in Object(object))) { object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); if (object == null) { return false; From c6f6eb294b66fcef9b2603a3cb6e005ac91b73df Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 16 Jul 2015 09:19:53 -0700 Subject: [PATCH 061/935] Use `numberProto` more in test/test.js. --- test/test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test.js b/test/test.js index 6e395176d3..b6ac3031ff 100644 --- a/test/test.js +++ b/test/test.js @@ -8740,9 +8740,9 @@ deepEqual(func('abc').sort(), ['0', '1', '2']); // IE 9 doesn't box numbers in for-in loops. - Number.prototype.a = 1; + numberProto.a = 1; deepEqual(func(0).sort(), isKeys ? [] : ['a']); - delete Number.prototype.a; + delete numberProto.a; }); test('`_.' + methodName + '` should treat sparse arrays as dense', 1, function() { @@ -8848,7 +8848,7 @@ 'Error': errorProto, 'Function': funcProto, 'Object': objectProto, - 'Number': Number.prototype, + 'Number': numberProto, 'TypeError': TypeError.prototype, 'RegExp': RegExp.prototype, 'String': stringProto From 76ab41a742313378905f33c33c9e18b102149e83 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 16 Jul 2015 09:23:46 -0700 Subject: [PATCH 062/935] Add `_.matches` and `_.matchesProperty` tests for primitive `object` and a `source` with `undefined` values. --- test/test.js | 53 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/test/test.js b/test/test.js index b6ac3031ff..dc833ac353 100644 --- a/test/test.js +++ b/test/test.js @@ -9596,6 +9596,33 @@ deepEqual(actual, expected); }); + test('should handle a primitive `object` and a `source` with `undefined` values', 3, function() { + numberProto.a = 1; + numberProto.b = undefined; + + try { + var matches = _.matches({ 'b': undefined }); + strictEqual(matches(1), true); + } catch(e) { + ok(false, e.message); + } + try { + matches = _.matches({ 'a': 1, 'b': undefined }); + strictEqual(matches(1), true); + } catch(e) { + ok(false, e.message); + } + numberProto.a = { 'b': 1, 'c': undefined }; + try { + matches = _.matches({ 'a': { 'c': undefined } }); + strictEqual(matches(1), true); + } catch(e) { + ok(false, e.message); + } + delete numberProto.a; + delete numberProto.b; + }); + test('should match properties when `value` is a function', 1, function() { function Foo() {} Foo.a = { 'b': 1, 'c': 2 }; @@ -9887,7 +9914,7 @@ deepEqual(actual, [objects[0]]); }); - test('should handle a `value` with `undefined` values', 3, function() { + test('should handle a `value` with `undefined` values', 2, function() { var objects = [{ 'a': 1 }, { 'a': 1, 'b': 1 }, { 'a': 1, 'b': undefined }], matches = _.matchesProperty('b', undefined), actual = _.map(objects, matches), @@ -9896,15 +9923,31 @@ deepEqual(actual, expected); objects = [{ 'a': { 'a': 1 } }, { 'a': { 'a': 1, 'b': 1 } }, { 'a': { 'a': 1, 'b': undefined } }]; - matches = _.matchesProperty('a', { 'a': 1, 'b': undefined }); + matches = _.matchesProperty('a', { 'b': undefined }); actual = _.map(objects, matches); deepEqual(actual, expected); + }); - matches = _.matchesProperty('a', { 'b': undefined }); - actual = _.map(objects, matches); + test('should handle a primitive `object` and a `source` with `undefined` values', 2, function() { + numberProto.a = 1; + numberProto.b = undefined; - deepEqual(actual, expected); + try { + var matches = _.matchesProperty('b', undefined); + strictEqual(matches(1), true); + } catch(e) { + ok(false, e.message); + } + numberProto.a = { 'b': 1, 'c': undefined }; + try { + matches = _.matchesProperty('a', { 'c': undefined }); + strictEqual(matches(1), true); + } catch(e) { + ok(false, e.message); + } + delete numberProto.a; + delete numberProto.b; }); test('should work with a function for `value`', 1, function() { From 9ca16e393357b84e513b4c6008583968ef550729 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 16 Jul 2015 09:40:52 -0700 Subject: [PATCH 063/935] Rename `baseCompareAscending` to `compareAscending`. --- lodash.src.js | 70 +++++++++++++++++++++------------------------------ 1 file changed, 28 insertions(+), 42 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 171a5e78f6..3f9dcc1f9b 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -277,39 +277,6 @@ /*--------------------------------------------------------------------------*/ - /** - * The base implementation of `compareAscending` which compares values and - * sorts them in ascending order without guaranteeing a stable sort. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {number} Returns the sort order indicator for `value`. - */ - function baseCompareAscending(value, other) { - if (value !== other) { - var valIsNull = value === null, - valIsUndef = value === undefined, - valIsReflexive = value === value; - - var othIsNull = other === null, - othIsUndef = other === undefined, - othIsReflexive = other === other; - - if ((value > other && !othIsNull) || !valIsReflexive || - (valIsNull && !othIsUndef && othIsReflexive) || - (valIsUndef && othIsReflexive)) { - return 1; - } - if ((value < other && !valIsNull) || !othIsReflexive || - (othIsNull && !valIsUndef && valIsReflexive) || - (othIsUndef && valIsReflexive)) { - return -1; - } - } - return 0; - } - /** * The base implementation of `_.findIndex` and `_.findLastIndex` without * support for callback shorthands. @@ -427,16 +394,35 @@ } /** - * Used by `_.sortBy` to compare transformed elements of a collection and stable - * sort them in ascending order. + * Compares values to sort them in ascending order. * * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @returns {number} Returns the sort order indicator for `object`. + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {number} Returns the sort order indicator for `value`. */ - function compareAscending(object, other) { - return baseCompareAscending(object.criteria, other.criteria) || (object.index - other.index); + function compareAscending(value, other) { + if (value !== other) { + var valIsNull = value === null, + valIsUndef = value === undefined, + valIsReflexive = value === value; + + var othIsNull = other === null, + othIsUndef = other === undefined, + othIsReflexive = other === other; + + if ((value > other && !othIsNull) || !valIsReflexive || + (valIsNull && !othIsUndef && othIsReflexive) || + (valIsUndef && othIsReflexive)) { + return 1; + } + if ((value < other && !valIsNull) || !othIsReflexive || + (othIsNull && !valIsUndef && valIsReflexive) || + (othIsUndef && valIsReflexive)) { + return -1; + } + } + return 0; } /** @@ -461,7 +447,7 @@ ordersLength = orders.length; while (++index < length) { - var result = baseCompareAscending(objCriteria[index], othCriteria[index]); + var result = compareAscending(objCriteria[index], othCriteria[index]); if (result) { if (index >= ordersLength) { return result; @@ -4823,7 +4809,7 @@ indexes = baseFlatten(indexes); var result = baseAt(array, indexes); - basePullAt(array, indexes.sort(baseCompareAscending)); + basePullAt(array, indexes.sort(compareAscending)); return result; }); From ab6210dc3088a61d8116a43b721f512a404558f7 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 16 Jul 2015 09:50:41 -0700 Subject: [PATCH 064/935] Avoid es-sham `getPrototypeOf` when constructor is not a function. --- lodash.src.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lodash.src.js b/lodash.src.js index 3f9dcc1f9b..ed54ebcbae 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -8256,7 +8256,10 @@ if (!(value && objToString.call(value) == objectTag)) { return false; } - var proto = getPrototypeOf(value); + var proto = typeof value.constructor == 'function' + ? getPrototypeOf(value) + : objectProto; + if (proto === null) { return true; } From b638f86b75f5d7abaa2245bc11df8e9264d88fa5 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 16 Jul 2015 09:56:20 -0700 Subject: [PATCH 065/935] Use a heavier function check in `isArrayLike`. --- lodash.src.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lodash.src.js b/lodash.src.js index ed54ebcbae..e2f42f4c44 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -3831,7 +3831,8 @@ * @returns {boolean} Returns `true` if `value` is array-like, else `false`. */ function isArrayLike(value) { - return value != null && typeof value != 'function' && isLength(getLength(value)); + return value != null && + !(typeof value == 'function' && objToString.call(value) == funcTag) && isLength(getLength(value)); } /** From bbad03547df47ff2ba3759c98cccb6b097574881 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 16 Jul 2015 10:24:30 -0700 Subject: [PATCH 066/935] Make `_.at` an "Object" method. --- lodash.src.js | 86 ++++++++++++++++++++++++--------------------------- test/test.js | 43 ++++++++++---------------- 2 files changed, 57 insertions(+), 72 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index e2f42f4c44..53ef589c29 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -1528,29 +1528,21 @@ } /** - * The base implementation of `_.at` without support for string collections - * and individual key arguments. + * The base implementation of `_.at` without support for individual path arguments. * * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {number[]|string[]} props The property names or indexes of elements to pick. + * @param {Object} object The object to iterate over. + * @param {string[]} paths The property paths of elements to pick. * @returns {Array} Returns the new array of picked elements. */ - function baseAt(collection, props) { + function baseAt(object, paths) { var index = -1, - isNil = collection == null, - isArr = !isNil && isArrayLike(collection), - length = isArr ? collection.length : 0, - propsLength = props.length, - result = Array(propsLength); + isNil = object == null, + length = paths.length, + result = Array(length); - while(++index < propsLength) { - var key = props[index]; - if (isArr) { - result[index] = isIndex(key, length) ? collection[key] : undefined; - } else { - result[index] = isNil ? undefined : collection[key]; - } + while(++index < length) { + result[index] = isNil ? undefined : get(object, paths[index]); } return result; } @@ -2419,9 +2411,13 @@ var length = array ? indexes.length : 0; while (length--) { var index = indexes[length]; - if (index != previous && isIndex(index)) { + if (index != previous) { var previous = index; - splice.call(array, index, 1); + if (isIndex(index)) { + splice.call(array, index, 1); + } else { + delete array[index]; + } } } return array; @@ -4783,8 +4779,8 @@ } /** - * Removes elements from `array` corresponding to the given indexes and returns - * an array of the removed elements. + * Removes elements from `array` corresponding to `indexes` and returns an + * array of removed elements. * * **Note:** Unlike `_.at`, this method mutates `array`. * @@ -5729,30 +5725,6 @@ /*------------------------------------------------------------------------*/ - /** - * Creates an array of elements corresponding to the given keys, or indexes, - * of `collection`. Keys may be specified as individual arguments or as arrays - * of keys. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {...(number|number[]|string|string[])} [props] The property names - * or indexes of elements to pick, specified individually or in arrays. - * @returns {Array} Returns the new array of picked elements. - * @example - * - * _.at(['a', 'b', 'c'], [0, 2]); - * // => ['a', 'c'] - * - * _.at(['barney', 'fred', 'pebbles'], 0, 2); - * // => ['barney', 'pebbles'] - */ - var at = restParam(function(collection, props) { - return baseAt(collection, baseFlatten(props)); - }); - /** * Creates an object composed of keys generated from the results of running * each element of `collection` through `iteratee`. The corresponding value @@ -8497,6 +8469,30 @@ copyObjectWith(source, keys(source), customizer, object); }); + /** + * Creates an array of values corresponding to `paths` of `object`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to iterate over. + * @param {...(string|string[])} [paths] The property paths of elements to pick, + * specified individually or in arrays. + * @returns {Array} Returns the new array of picked elements. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; + * + * _.at(object, ['a[0].b.c', 'a[1]']); + * // => [3, 4] + * + * _.at(['a', 'b', 'c'], 0, 2); + * // => ['a', 'c'] + */ + var at = restParam(function(object, paths) { + return baseAt(object, baseFlatten(paths)); + }); + /** * Creates an object that inherits from the given `prototype` object. If a * `properties` object is provided its own enumerable properties are assigned diff --git a/test/test.js b/test/test.js index dc833ac353..2ca18392e6 100644 --- a/test/test.js +++ b/test/test.js @@ -1027,6 +1027,12 @@ var args = arguments, array = ['a', 'b', 'c']; + _.each(empties, function(value) { + if (value !== 0) { + array[value] = 1; + } + }); + array['1.1'] = array['-1'] = 1; test('should return the elements corresponding to the specified keys', 1, function() { @@ -1039,12 +1045,12 @@ deepEqual(actual, ['c', undefined, 'a']); }); - test('should use `undefined` for non-index keys on array-like values', 1, function() { + test('should work with non-index keys on array-like values', 1, function() { var values = _.reject(empties, function(value) { return value === 0 || _.isArray(value); }).concat(-1, 1.1); - var expected = _.map(values, _.constant(undefined)), + var expected = _.map(values, _.constant(1)), actual = _.at(array, values); deepEqual(actual, expected); @@ -1060,19 +1066,19 @@ deepEqual(actual, ['d', 'a', 'c']); }); - test('should work with a falsey `collection` argument when keys are provided', 1, function() { + test('should work with a falsey `object` argument when keys are provided', 1, function() { var expected = _.map(falsey, _.constant(Array(4))); - var actual = _.map(falsey, function(collection) { + var actual = _.map(falsey, function(object) { try { - return _.at(collection, 0, 1, 'pop', 'push'); + return _.at(object, 0, 1, 'pop', 'push'); } catch(e) {} }); deepEqual(actual, expected); }); - test('should work with an `arguments` object for `collection`', 1, function() { + test('should work with an `arguments` object for `object`', 1, function() { var actual = _.at(args, [2, 0]); deepEqual(actual, [3, 1]); }); @@ -1082,7 +1088,7 @@ deepEqual(actual, [2, 3, 4]); }); - test('should work with an object for `collection`', 1, function() { + test('should work with an object for `object`', 1, function() { var actual = _.at({ 'a': 1, 'b': 2, 'c': 3 }, ['c', 'a']); deepEqual(actual, [3, 1]); }); @@ -1099,9 +1105,9 @@ 'literal': 'abc', 'object': Object('abc') }, - function(collection, key) { - test('should work with a string ' + key + ' for `collection`', 1, function() { - deepEqual(_.at(collection, [2, 0]), ['c', 'a']); + function(object, key) { + test('should work with a string ' + key + ' for `object`', 1, function() { + deepEqual(_.at(object, [2, 0]), ['c', 'a']); }); }); }(1, 2, 3)); @@ -12342,23 +12348,6 @@ deepEqual(actual, ['c', undefined, 'a']); }); - test('should ignore non-index keys', 2, function() { - var array = ['a', 'b', 'c'], - clone = array.slice(); - - array['1.1'] = array['-1'] = 1; - - var values = _.reject(empties, function(value) { - return value === 0 || _.isArray(value); - }).concat(-1, 1.1, 'pop', 'push'); - - var expected = _.map(values, _.constant(undefined)), - actual = _.pullAt(array, values); - - deepEqual(actual, expected); - deepEqual(array, clone); - }); - test('should return an empty array when no indexes are provided', 4, function() { var array = ['a', 'b', 'c'], actual = _.pullAt(array); From 77596157758b37d19a6379f774d9de620457779a Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 16 Jul 2015 10:41:12 -0700 Subject: [PATCH 067/935] Ensure "Collection" methods treat functions as objects. --- test/test.js | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/test/test.js b/test/test.js index 2ca18392e6..f2dc2e1767 100644 --- a/test/test.js +++ b/test/test.js @@ -4906,23 +4906,30 @@ _.each(collectionMethods, function(methodName) { var func = _[methodName]; - test('`_.' + methodName + '` should use `isLength` to determine whether a value is array-like', 2, function() { + test('`_.' + methodName + '` should use `isArrayLike` to determine whether a value is array-like', 3, function() { if (func) { - var isIteratedAsObject = function(length) { + var isIteratedAsObject = function(object) { var result = false; - func({ 'length': length }, function() { result = true; }, 0); + func(object, function() { result = true; }, 0); return result; }; var values = [-1, '1', 1.1, Object(1), MAX_SAFE_INTEGER + 1], - expected = _.map(values, _.constant(true)), - actual = _.map(values, isIteratedAsObject); + expected = _.map(values, _.constant(true)); + + var actual = _.map(values, function(length) { + return isIteratedAsObject({ 'length': length }); + }); + + var Foo = function(a) {}; + Foo.a = 1; deepEqual(actual, expected); - ok(!isIteratedAsObject(0)); + ok(isIteratedAsObject(Foo)); + ok(!isIteratedAsObject({ 'length': 0 })); } else { - skipTest(2); + skipTest(3); } }); }); From f695af587ab617f6bd57d55261c3e6cfd899a1f3 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 16 Jul 2015 13:08:44 -0700 Subject: [PATCH 068/935] Remove `createExtremum`. --- lodash.src.js | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 53ef589c29..de93375832 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -3112,25 +3112,6 @@ }; } - /** - * Creates a `_.maxBy` or `_.minBy` function. - * - * @private - * @param {Function} comparator The function used to compare values. - * @param {*} exValue The initial extremum value. - * @returns {Function} Returns the new extremum function. - */ - function createExtremum(comparator, exValue) { - return function(array, iteratee, guard) { - if (guard && isIterateeCall(array, iteratee, guard)) { - iteratee = undefined; - } - return (array && array.length) - ? arrayExtremum(array, getIteratee(iteratee), comparator, exValue) - : exValue; - }; - } - /** * Creates a `_.flow` or `_.flowRight` function. * @@ -11082,7 +11063,14 @@ * _.maxBy(users, 'age'); * // => { 'user': 'fred', 'age': 40 } */ - var maxBy = createExtremum(gt, NEGATIVE_INFINITY); + function maxBy(array, iteratee, guard) { + if (guard && isIterateeCall(array, iteratee, guard)) { + iteratee = undefined; + } + return (array && array.length) + ? arrayExtremum(array, getIteratee(iteratee), gt, NEGATIVE_INFINITY) + : NEGATIVE_INFINITY; + } /** * Gets the minimum value of `array`. If `array` is empty or falsey @@ -11130,7 +11118,14 @@ * _.minBy(users, 'age'); * // => { 'user': 'barney', 'age': 36 } */ - var minBy = createExtremum(lt, POSITIVE_INFINITY); + function minBy(array, iteratee, guard) { + if (guard && isIterateeCall(array, iteratee, guard)) { + iteratee = undefined; + } + return (array && array.length) + ? arrayExtremum(array, getIteratee(iteratee), lt, POSITIVE_INFINITY) + : POSITIVE_INFINITY; + } /** * Calculates `n` rounded to `precision`. From 7a34b2982f9247d2b81b81024fa68737737652f1 Mon Sep 17 00:00:00 2001 From: Michael Kearns Date: Wed, 15 Jul 2015 22:04:02 +0100 Subject: [PATCH 069/935] Reword `_.merge` docs for clarity. [ci skip] --- lodash.src.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index de93375832..6f95440605 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -9087,9 +9087,9 @@ } /** - * Recursively merges own enumerable properties of the source object(s), that - * don't resolve to `undefined` into the destination object. Subsequent sources - * overwrite property assignments of previous sources. + * Recursively merges own enumerable properties of the source object(s) into the + * destination object, for source properties which don't resolve to `undefined`. + * Subsequent sources overwrite property assignments of previous sources. * * @static * @memberOf _ From b8060a5bcc01abe4e1d5e4db033537aab9282e85 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 16 Jul 2015 20:59:02 -0700 Subject: [PATCH 070/935] Add more methods to the `lodash` doc note. [ci skip] --- lodash.src.js | 50 ++++++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/lodash.src.js b/lodash.src.js index 6f95440605..18c1692ae3 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -846,39 +846,41 @@ * `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray` * * The chainable wrapper methods are: - * `after`, `ary`, `assign`, `at`, `before`, `bind`, `bindAll`, `bindKey`, - * `callback`, `chain`, `chunk`, `commit`, `compact`, `concat`, `constant`, + * `after`, `ary`, `assign`, `assignWith`, `at`, `before`, `bind`, `bindAll`, + * `bindKey`, `chain`, `chunk`, `commit`, `compact`, `concat`, `constant`, * `countBy`, `create`, `curry`, `debounce`, `defaults`, `defaultsDeep`, * `defer`, `delay`, `difference`, `drop`, `dropRight`, `dropRightWhile`, - * `dropWhile`, `fill`, `filter`, `flatten`, `flattenDeep`, `flow`, `flowRight`, - * `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`, - * `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`, - * `invoke`, `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, - * `matchesProperty`, `memoize`, `merge`, `method`, `methodOf`, `mixin`, - * `modArgs`, `negate`, `omit`, `once`, `pairs`, `partial`, `partialRight`, - * `partition`, `pick`, `plant`, `property`, `propertyOf`, `pull`, `pullAt`, + * `dropWhile`, `extend`, `extendWith`, `fill`, `filter`, `flatten`, + * `flattenDeep`, `flow`, `flowRight`, `forEach`, `forEachRight`, `forIn`, + * `forInRight`, `forOwn`, `forOwnRight`, `functions`, `groupBy`, `indexBy`, + * `initial`, `intersection`, `invert`, `invoke`, `iteratee`, `keys`, `keysIn`, + * `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`, `memoize`, + * `merge`, `mergeWith` `method`, `methodOf`, `mixin`, `modArgs`, `negate`, + * `omit`, `omitBy`, `once`, `pairs`, `partial`, `partialRight`, `partition`, + * `pick`, `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAt`, * `push`, `range`, `rearg`, `reject`, `remove`, `rest`, `restParam`, `reverse`, * `set`, `shuffle`, `slice`, `sort`, `sortBy`, `sortByOrder`, `splice`, * `spread`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, `tap`, * `throttle`, `thru`, `times`, `toArray`, `toPlainObject`, `transform`, - * `union`, `uniq`, `unshift`, `unzip`, `unzipWith`, `values`, `valuesIn`, - * `without`, `wrap`, `xor`, `zip`, `zipObject`, `zipWith` + * `union`, `uniq`, `uniqBy`, `unshift`, `unzip`, `unzipWith`, `values`, + * `valuesIn`, `without`, `wrap`, `xor`, `zip`, `zipObject`, `zipWith` * * The wrapper methods that are **not** chainable by default are: * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clone`, `cloneDeep`, - * `deburr`, `endsWith`, `escape`, `escapeRegExp`, `every`, `find`, `findIndex`, - * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `first`, `floor`, - * `get`, `gt`, `gte`, `has`, `identity`, `includes`, `indexOf`, `inRange`, - * `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`, `isEmpty`, - * `isEqual`, `isError`, `isFinite` `isFunction`, `isMatch`, `isNative`, - * `isNaN`, `isNull`, `isNumber`, `isObject`, `isPlainObject`, `isRegExp`, - * `isString`, `isUndefined`, `isTypedArray`, `join`, `kebabCase`, `last`, - * `lastIndexOf`, `lt`, `lte`, `max`, `min`, `noConflict`, `noop`, `now`, `pad`, - * `padLeft`, `padRight`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`, - * `repeat`, `result`, `round`, `runInContext`, `shift`, `size`,`snakeCase`, - * `some`, `sortedIndex`, `sortedLastIndex`, `startCase`, `startsWith`, `sum`, - * `template`, `trim`, `trimLeft`, `trimRight`, `trunc`, `unescape`, `uniqueId`, - * `value`, and `words` + * `cloneDeepWith`, `cloneWith`, `deburr`, `endsWith`, `escape`, `escapeRegExp`, + * `every`, `find`, `findIndex`, `findKey`, `findLast`, `findLastIndex`, + * `findLastKey`, `first`, `floor`, `get`, `gt`, `gte`, `has`, `identity`, + * `includes`, `indexOf`, `inRange`, `isArguments`, `isArray`, `isBoolean`, + * `isDate`, `isElement`, `isEmpty`, `isEqual`, `isEqualWith`, `isError`, + * `isFinite` `isFunction`, `isMatch`, `isMatchWith`, `isNative`, `isNaN`, + * `isNull`, `isNumber`, `isObject`, `isPlainObject`, `isRegExp`, `isString`, + * `isUndefined`, `isTypedArray`, `join`, `kebabCase`, `last`, `lastIndexOf`, + * `lt`, `lte`, `max`, `min`, `noConflict`, `noop`, `now`, `pad`, `padLeft`, + * `padRight`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`, `repeat`, + * `result`, `round`, `runInContext`, `shift`, `size`, `snakeCase`, `some`, + * `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`, `sortedLastIndexBy`, + * `startCase`, `startsWith`, `sum`, `sumBy`, `template`, `trim`, `trimLeft`, + * `trimRight`, `trunc`, `unescape`, `uniqueId`, `value`, and `words` * * The wrapper method `sample` will return a wrapped value when `n` is provided, * otherwise an unwrapped value is returned. From 18f778ce1114aa112c675c397161727b3e035532 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 16 Jul 2015 20:59:21 -0700 Subject: [PATCH 071/935] Remove `var` use for the `baseKeysIn` fork assignment. --- lodash.src.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lodash.src.js b/lodash.src.js index 18c1692ae3..50c6327b81 100644 --- a/lodash.src.js +++ b/lodash.src.js @@ -2144,7 +2144,7 @@ // An alternative implementation intended for IE < 9 with es6-shim. if (enumerate && !propertyIsEnumerable.call({ 'valueOf': 1 }, 'valueOf')) { - var baseKeysIn = function(object) { + baseKeysIn = function(object) { var data, iterator = enumerate(object), result = []; From 881733e0998a11064c73f3b7189b9c709e98813c Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 16 Jul 2015 21:14:37 -0700 Subject: [PATCH 072/935] Temporarily disable a few more runs in travis.yml. --- .travis.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index ba397bf175..212a9e6d0e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,10 +30,10 @@ matrix: env: - node_js: "0.10" env: BUILD="modern" - - node_js: "0.12" - env: SAUCE_LABS=true - - node_js: "0.12" - env: SAUCE_LABS=true BUILD="modern" +# - node_js: "0.12" +# env: SAUCE_LABS=true +# - node_js: "0.12" +# env: SAUCE_LABS=true BUILD="modern" git: depth: 10 branches: @@ -51,10 +51,10 @@ before_install: - "npm i -g npm@\"$NPM_VERSION\"" - "[ $SAUCE_LABS == false ] || npm i chalk@\"^1.0.0\" ecstatic@\"0.8.0\" request@\"^2.0.0\" sauce-tunnel@\"2.2.3\"" - "[ $ISTANBUL == false ] || (npm i -g coveralls@\"^2.0.0\" && npm i istanbul@\"0.3.17\")" - - "[ $BIN != 'rhino' ] || (sudo mkdir /opt/rhino-1.7.6 && sudo wget --no-check-certificate -O $_/js.jar https://lodash.com/_travis/rhino-1.7.6.jar)" - - "[ $BIN != 'rhino' ] || (echo -e '#!/bin/sh\\njava -jar /opt/rhino-1.7.6/js.jar $@' | sudo tee /usr/local/bin/rhino && sudo chmod +x /usr/local/bin/rhino)" - - "[ $BIN != 'ringo' ] || (wget --no-check-certificate https://lodash.com/_travis/ringojs-0.11.zip && sudo unzip ringojs-0.11 -d /opt && rm ringojs-0.11.zip)" - - "[ $BIN != 'ringo' ] || (sudo ln -s /opt/ringojs-0.11/bin/ringo /usr/local/bin/ringo && sudo chmod +x $_)" +# - "[ $BIN != 'rhino' ] || (sudo mkdir /opt/rhino-1.7.6 && sudo wget --no-check-certificate -O $_/js.jar https://lodash.com/_travis/rhino-1.7.6.jar)" +# - "[ $BIN != 'rhino' ] || (echo -e '#!/bin/sh\\njava -jar /opt/rhino-1.7.6/js.jar $@' | sudo tee /usr/local/bin/rhino && sudo chmod +x /usr/local/bin/rhino)" +# - "[ $BIN != 'ringo' ] || (wget --no-check-certificate https://lodash.com/_travis/ringojs-0.11.zip && sudo unzip ringojs-0.11 -d /opt && rm ringojs-0.11.zip)" +# - "[ $BIN != 'ringo' ] || (sudo ln -s /opt/ringojs-0.11/bin/ringo /usr/local/bin/ringo && sudo chmod +x $_)" - "perl -pi -e 's|\"lodash\"|\"lodash-compat\"|' ./package.json" - "git clone --depth=10 --branch=master git://github.com/lodash/lodash-cli ./node_modules/lodash-cli && mkdir $_/node_modules && cd $_ && ln -s ../../../ ./lodash-compat && cd ../ && npm i && cd ../../" - "node ./node_modules/lodash-cli/bin/lodash $BUILD -o ./lodash.$BUILD.js" From 2e57123aa25bf638370a59fe6db97eb65c2da4b1 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Mon, 20 Jul 2015 11:29:16 -0700 Subject: [PATCH 073/935] Remove lodash.js --- lodash.js | 12352 ---------------------------------------------------- 1 file changed, 12352 deletions(-) delete mode 100644 lodash.js diff --git a/lodash.js b/lodash.js deleted file mode 100644 index d1f45b6ecd..0000000000 --- a/lodash.js +++ /dev/null @@ -1,12352 +0,0 @@ -/** - * @license - * lodash 3.10.1 (Custom Build) - * Build: `lodash modern -o ./lodash.js` - * Copyright 2012-2015 The Dojo Foundation - * Based on Underscore.js 1.8.3 - * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -;(function() { - - /** Used as a safe reference for `undefined` in pre-ES5 environments. */ - var undefined; - - /** Used as the semantic version number. */ - var VERSION = '3.10.1'; - - /** Used to compose bitmasks for wrapper metadata. */ - var BIND_FLAG = 1, - BIND_KEY_FLAG = 2, - CURRY_BOUND_FLAG = 4, - CURRY_FLAG = 8, - CURRY_RIGHT_FLAG = 16, - PARTIAL_FLAG = 32, - PARTIAL_RIGHT_FLAG = 64, - ARY_FLAG = 128, - REARG_FLAG = 256; - - /** Used as default options for `_.trunc`. */ - var DEFAULT_TRUNC_LENGTH = 30, - DEFAULT_TRUNC_OMISSION = '...'; - - /** Used to detect when a function becomes hot. */ - var HOT_COUNT = 150, - HOT_SPAN = 16; - - /** Used as the size to enable large array optimizations. */ - var LARGE_ARRAY_SIZE = 200; - - /** Used to indicate the type of lazy iteratees. */ - var LAZY_FILTER_FLAG = 1, - LAZY_MAP_FLAG = 2; - - /** Used as the `TypeError` message for "Functions" methods. */ - var FUNC_ERROR_TEXT = 'Expected a function'; - - /** Used as the internal argument placeholder. */ - var PLACEHOLDER = '__lodash_placeholder__'; - - /** `Object#toString` result references. */ - var argsTag = '[object Arguments]', - arrayTag = '[object Array]', - boolTag = '[object Boolean]', - dateTag = '[object Date]', - errorTag = '[object Error]', - funcTag = '[object Function]', - mapTag = '[object Map]', - numberTag = '[object Number]', - objectTag = '[object Object]', - regexpTag = '[object RegExp]', - setTag = '[object Set]', - stringTag = '[object String]', - weakMapTag = '[object WeakMap]'; - - var arrayBufferTag = '[object ArrayBuffer]', - float32Tag = '[object Float32Array]', - float64Tag = '[object Float64Array]', - int8Tag = '[object Int8Array]', - int16Tag = '[object Int16Array]', - int32Tag = '[object Int32Array]', - uint8Tag = '[object Uint8Array]', - uint8ClampedTag = '[object Uint8ClampedArray]', - uint16Tag = '[object Uint16Array]', - uint32Tag = '[object Uint32Array]'; - - /** Used to match empty string literals in compiled template source. */ - var reEmptyStringLeading = /\b__p \+= '';/g, - reEmptyStringMiddle = /\b(__p \+=) '' \+/g, - reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; - - /** Used to match HTML entities and HTML characters. */ - var reEscapedHtml = /&(?:amp|lt|gt|quot|#39|#96);/g, - reUnescapedHtml = /[&<>"'`]/g, - reHasEscapedHtml = RegExp(reEscapedHtml.source), - reHasUnescapedHtml = RegExp(reUnescapedHtml.source); - - /** Used to match template delimiters. */ - var reEscape = /<%-([\s\S]+?)%>/g, - reEvaluate = /<%([\s\S]+?)%>/g, - reInterpolate = /<%=([\s\S]+?)%>/g; - - /** Used to match property names within property paths. */ - var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\n\\]|\\.)*?\1)\]/, - reIsPlainProp = /^\w*$/, - rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\n\\]|\\.)*?)\2)\]/g; - - /** - * Used to match `RegExp` [syntax characters](http://ecma-international.org/ecma-262/6.0/#sec-patterns) - * and those outlined by [`EscapeRegExpPattern`](http://ecma-international.org/ecma-262/6.0/#sec-escaperegexppattern). - */ - var reRegExpChars = /^[:!,]|[\\^$.*+?()[\]{}|\/]|(^[0-9a-fA-Fnrtuvx])|([\n\r\u2028\u2029])/g, - reHasRegExpChars = RegExp(reRegExpChars.source); - - /** Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks). */ - var reComboMark = /[\u0300-\u036f\ufe20-\ufe23]/g; - - /** Used to match backslashes in property paths. */ - var reEscapeChar = /\\(\\)?/g; - - /** Used to match [ES template delimiters](http://ecma-international.org/ecma-262/6.0/#sec-template-literal-lexical-components). */ - var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; - - /** Used to match `RegExp` flags from their coerced string values. */ - var reFlags = /\w*$/; - - /** Used to detect hexadecimal string values. */ - var reHasHexPrefix = /^0[xX]/; - - /** Used to detect host constructors (Safari > 5). */ - var reIsHostCtor = /^\[object .+?Constructor\]$/; - - /** Used to detect unsigned integer values. */ - var reIsUint = /^\d+$/; - - /** Used to match latin-1 supplementary letters (excluding mathematical operators). */ - var reLatin1 = /[\xc0-\xd6\xd8-\xde\xdf-\xf6\xf8-\xff]/g; - - /** Used to ensure capturing order of template delimiters. */ - var reNoMatch = /($^)/; - - /** Used to match unescaped characters in compiled string literals. */ - var reUnescapedString = /['\n\r\u2028\u2029\\]/g; - - /** Used to match words to create compound words. */ - var reWords = (function() { - var upper = '[A-Z\\xc0-\\xd6\\xd8-\\xde]', - lower = '[a-z\\xdf-\\xf6\\xf8-\\xff]+'; - - return RegExp(upper + '+(?=' + upper + lower + ')|' + upper + '?' + lower + '|' + upper + '+|[0-9]+', 'g'); - }()); - - /** Used to assign default `context` object properties. */ - var contextProps = [ - 'Array', 'ArrayBuffer', 'Date', 'Error', 'Float32Array', 'Float64Array', - 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Math', 'Number', - 'Object', 'RegExp', 'Set', 'String', '_', 'clearTimeout', 'isFinite', - 'parseFloat', 'parseInt', 'setTimeout', 'TypeError', 'Uint8Array', - 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap' - ]; - - /** Used to make template sourceURLs easier to identify. */ - var templateCounter = -1; - - /** Used to identify `toStringTag` values of typed arrays. */ - var typedArrayTags = {}; - typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = - typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = - typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = - typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = - typedArrayTags[uint32Tag] = true; - typedArrayTags[argsTag] = typedArrayTags[arrayTag] = - typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = - typedArrayTags[dateTag] = typedArrayTags[errorTag] = - typedArrayTags[funcTag] = typedArrayTags[mapTag] = - typedArrayTags[numberTag] = typedArrayTags[objectTag] = - typedArrayTags[regexpTag] = typedArrayTags[setTag] = - typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false; - - /** Used to identify `toStringTag` values supported by `_.clone`. */ - var cloneableTags = {}; - cloneableTags[argsTag] = cloneableTags[arrayTag] = - cloneableTags[arrayBufferTag] = cloneableTags[boolTag] = - cloneableTags[dateTag] = cloneableTags[float32Tag] = - cloneableTags[float64Tag] = cloneableTags[int8Tag] = - cloneableTags[int16Tag] = cloneableTags[int32Tag] = - cloneableTags[numberTag] = cloneableTags[objectTag] = - cloneableTags[regexpTag] = cloneableTags[stringTag] = - cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = - cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; - cloneableTags[errorTag] = cloneableTags[funcTag] = - cloneableTags[mapTag] = cloneableTags[setTag] = - cloneableTags[weakMapTag] = false; - - /** Used to map latin-1 supplementary letters to basic latin letters. */ - var deburredLetters = { - '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A', - '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a', - '\xc7': 'C', '\xe7': 'c', - '\xd0': 'D', '\xf0': 'd', - '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E', - '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e', - '\xcC': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I', - '\xeC': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i', - '\xd1': 'N', '\xf1': 'n', - '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O', - '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o', - '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U', - '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u', - '\xdd': 'Y', '\xfd': 'y', '\xff': 'y', - '\xc6': 'Ae', '\xe6': 'ae', - '\xde': 'Th', '\xfe': 'th', - '\xdf': 'ss' - }; - - /** Used to map characters to HTML entities. */ - var htmlEscapes = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''', - '`': '`' - }; - - /** Used to map HTML entities to characters. */ - var htmlUnescapes = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - ''': "'", - '`': '`' - }; - - /** Used to determine if values are of the language type `Object`. */ - var objectTypes = { - 'function': true, - 'object': true - }; - - /** Used to escape characters for inclusion in compiled regexes. */ - var regexpEscapes = { - '0': 'x30', '1': 'x31', '2': 'x32', '3': 'x33', '4': 'x34', - '5': 'x35', '6': 'x36', '7': 'x37', '8': 'x38', '9': 'x39', - 'A': 'x41', 'B': 'x42', 'C': 'x43', 'D': 'x44', 'E': 'x45', 'F': 'x46', - 'a': 'x61', 'b': 'x62', 'c': 'x63', 'd': 'x64', 'e': 'x65', 'f': 'x66', - 'n': 'x6e', 'r': 'x72', 't': 'x74', 'u': 'x75', 'v': 'x76', 'x': 'x78' - }; - - /** Used to escape characters for inclusion in compiled string literals. */ - var stringEscapes = { - '\\': '\\', - "'": "'", - '\n': 'n', - '\r': 'r', - '\u2028': 'u2028', - '\u2029': 'u2029' - }; - - /** Detect free variable `exports`. */ - var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports; - - /** Detect free variable `module`. */ - var freeModule = objectTypes[typeof module] && module && !module.nodeType && module; - - /** Detect free variable `global` from Node.js. */ - var freeGlobal = freeExports && freeModule && typeof global == 'object' && global && global.Object && global; - - /** Detect free variable `self`. */ - var freeSelf = objectTypes[typeof self] && self && self.Object && self; - - /** Detect free variable `window`. */ - var freeWindow = objectTypes[typeof window] && window && window.Object && window; - - /** Detect the popular CommonJS extension `module.exports`. */ - var moduleExports = freeModule && freeModule.exports === freeExports && freeExports; - - /** - * Used as a reference to the global object. - * - * The `this` value is used if it's the global object to avoid Greasemonkey's - * restricted `window` object, otherwise the `window` object is used. - */ - var root = freeGlobal || ((freeWindow !== (this && this.window)) && freeWindow) || freeSelf || this; - - /*--------------------------------------------------------------------------*/ - - /** - * The base implementation of `compareAscending` which compares values and - * sorts them in ascending order without guaranteeing a stable sort. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {number} Returns the sort order indicator for `value`. - */ - function baseCompareAscending(value, other) { - if (value !== other) { - var valIsNull = value === null, - valIsUndef = value === undefined, - valIsReflexive = value === value; - - var othIsNull = other === null, - othIsUndef = other === undefined, - othIsReflexive = other === other; - - if ((value > other && !othIsNull) || !valIsReflexive || - (valIsNull && !othIsUndef && othIsReflexive) || - (valIsUndef && othIsReflexive)) { - return 1; - } - if ((value < other && !valIsNull) || !othIsReflexive || - (othIsNull && !valIsUndef && valIsReflexive) || - (othIsUndef && valIsReflexive)) { - return -1; - } - } - return 0; - } - - /** - * The base implementation of `_.findIndex` and `_.findLastIndex` without - * support for callback shorthands and `this` binding. - * - * @private - * @param {Array} array The array to search. - * @param {Function} predicate The function invoked per iteration. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function baseFindIndex(array, predicate, fromRight) { - var length = array.length, - index = fromRight ? length : -1; - - while ((fromRight ? index-- : ++index < length)) { - if (predicate(array[index], index, array)) { - return index; - } - } - return -1; - } - - /** - * The base implementation of `_.indexOf` without support for binary searches. - * - * @private - * @param {Array} array The array to search. - * @param {*} value The value to search for. - * @param {number} fromIndex The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function baseIndexOf(array, value, fromIndex) { - if (value !== value) { - return indexOfNaN(array, fromIndex); - } - var index = fromIndex - 1, - length = array.length; - - while (++index < length) { - if (array[index] === value) { - return index; - } - } - return -1; - } - - /** - * The base implementation of `_.isFunction` without support for environments - * with incorrect `typeof` results. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - */ - function baseIsFunction(value) { - // Avoid a Chakra JIT bug in compatibility modes of IE 11. - // See https://github.com/jashkenas/underscore/issues/1621 for more details. - return typeof value == 'function' || false; - } - - /** - * Converts `value` to a string if it's not one. An empty string is returned - * for `null` or `undefined` values. - * - * @private - * @param {*} value The value to process. - * @returns {string} Returns the string. - */ - function baseToString(value) { - return value == null ? '' : (value + ''); - } - - /** - * Used by `_.trim` and `_.trimLeft` to get the index of the first character - * of `string` that is not found in `chars`. - * - * @private - * @param {string} string The string to inspect. - * @param {string} chars The characters to find. - * @returns {number} Returns the index of the first character not found in `chars`. - */ - function charsLeftIndex(string, chars) { - var index = -1, - length = string.length; - - while (++index < length && chars.indexOf(string.charAt(index)) > -1) {} - return index; - } - - /** - * Used by `_.trim` and `_.trimRight` to get the index of the last character - * of `string` that is not found in `chars`. - * - * @private - * @param {string} string The string to inspect. - * @param {string} chars The characters to find. - * @returns {number} Returns the index of the last character not found in `chars`. - */ - function charsRightIndex(string, chars) { - var index = string.length; - - while (index-- && chars.indexOf(string.charAt(index)) > -1) {} - return index; - } - - /** - * Used by `_.sortBy` to compare transformed elements of a collection and stable - * sort them in ascending order. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @returns {number} Returns the sort order indicator for `object`. - */ - function compareAscending(object, other) { - return baseCompareAscending(object.criteria, other.criteria) || (object.index - other.index); - } - - /** - * Used by `_.sortByOrder` to compare multiple properties of a value to another - * and stable sort them. - * - * If `orders` is unspecified, all valuess are sorted in ascending order. Otherwise, - * a value is sorted in ascending order if its corresponding order is "asc", and - * descending if "desc". - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {boolean[]} orders The order to sort by for each property. - * @returns {number} Returns the sort order indicator for `object`. - */ - function compareMultiple(object, other, orders) { - var index = -1, - objCriteria = object.criteria, - othCriteria = other.criteria, - length = objCriteria.length, - ordersLength = orders.length; - - while (++index < length) { - var result = baseCompareAscending(objCriteria[index], othCriteria[index]); - if (result) { - if (index >= ordersLength) { - return result; - } - var order = orders[index]; - return result * ((order === 'asc' || order === true) ? 1 : -1); - } - } - // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications - // that causes it, under certain circumstances, to provide the same value for - // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247 - // for more details. - // - // This also ensures a stable sort in V8 and other engines. - // See https://code.google.com/p/v8/issues/detail?id=90 for more details. - return object.index - other.index; - } - - /** - * Used by `_.deburr` to convert latin-1 supplementary letters to basic latin letters. - * - * @private - * @param {string} letter The matched letter to deburr. - * @returns {string} Returns the deburred letter. - */ - function deburrLetter(letter) { - return deburredLetters[letter]; - } - - /** - * Used by `_.escape` to convert characters to HTML entities. - * - * @private - * @param {string} chr The matched character to escape. - * @returns {string} Returns the escaped character. - */ - function escapeHtmlChar(chr) { - return htmlEscapes[chr]; - } - - /** - * Used by `_.escapeRegExp` to escape characters for inclusion in compiled regexes. - * - * @private - * @param {string} chr The matched character to escape. - * @param {string} leadingChar The capture group for a leading character. - * @param {string} whitespaceChar The capture group for a whitespace character. - * @returns {string} Returns the escaped character. - */ - function escapeRegExpChar(chr, leadingChar, whitespaceChar) { - if (leadingChar) { - chr = regexpEscapes[chr]; - } else if (whitespaceChar) { - chr = stringEscapes[chr]; - } - return '\\' + chr; - } - - /** - * Used by `_.template` to escape characters for inclusion in compiled string literals. - * - * @private - * @param {string} chr The matched character to escape. - * @returns {string} Returns the escaped character. - */ - function escapeStringChar(chr) { - return '\\' + stringEscapes[chr]; - } - - /** - * Gets the index at which the first occurrence of `NaN` is found in `array`. - * - * @private - * @param {Array} array The array to search. - * @param {number} fromIndex The index to search from. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {number} Returns the index of the matched `NaN`, else `-1`. - */ - function indexOfNaN(array, fromIndex, fromRight) { - var length = array.length, - index = fromIndex + (fromRight ? 0 : -1); - - while ((fromRight ? index-- : ++index < length)) { - var other = array[index]; - if (other !== other) { - return index; - } - } - return -1; - } - - /** - * Checks if `value` is object-like. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is object-like, else `false`. - */ - function isObjectLike(value) { - return !!value && typeof value == 'object'; - } - - /** - * Used by `trimmedLeftIndex` and `trimmedRightIndex` to determine if a - * character code is whitespace. - * - * @private - * @param {number} charCode The character code to inspect. - * @returns {boolean} Returns `true` if `charCode` is whitespace, else `false`. - */ - function isSpace(charCode) { - return ((charCode <= 160 && (charCode >= 9 && charCode <= 13) || charCode == 32 || charCode == 160) || charCode == 5760 || charCode == 6158 || - (charCode >= 8192 && (charCode <= 8202 || charCode == 8232 || charCode == 8233 || charCode == 8239 || charCode == 8287 || charCode == 12288 || charCode == 65279))); - } - - /** - * Replaces all `placeholder` elements in `array` with an internal placeholder - * and returns an array of their indexes. - * - * @private - * @param {Array} array The array to modify. - * @param {*} placeholder The placeholder to replace. - * @returns {Array} Returns the new array of placeholder indexes. - */ - function replaceHolders(array, placeholder) { - var index = -1, - length = array.length, - resIndex = -1, - result = []; - - while (++index < length) { - if (array[index] === placeholder) { - array[index] = PLACEHOLDER; - result[++resIndex] = index; - } - } - return result; - } - - /** - * An implementation of `_.uniq` optimized for sorted arrays without support - * for callback shorthands and `this` binding. - * - * @private - * @param {Array} array The array to inspect. - * @param {Function} [iteratee] The function invoked per iteration. - * @returns {Array} Returns the new duplicate free array. - */ - function sortedUniq(array, iteratee) { - var seen, - index = -1, - length = array.length, - resIndex = -1, - result = []; - - while (++index < length) { - var value = array[index], - computed = iteratee ? iteratee(value, index, array) : value; - - if (!index || seen !== computed) { - seen = computed; - result[++resIndex] = value; - } - } - return result; - } - - /** - * Used by `_.trim` and `_.trimLeft` to get the index of the first non-whitespace - * character of `string`. - * - * @private - * @param {string} string The string to inspect. - * @returns {number} Returns the index of the first non-whitespace character. - */ - function trimmedLeftIndex(string) { - var index = -1, - length = string.length; - - while (++index < length && isSpace(string.charCodeAt(index))) {} - return index; - } - - /** - * Used by `_.trim` and `_.trimRight` to get the index of the last non-whitespace - * character of `string`. - * - * @private - * @param {string} string The string to inspect. - * @returns {number} Returns the index of the last non-whitespace character. - */ - function trimmedRightIndex(string) { - var index = string.length; - - while (index-- && isSpace(string.charCodeAt(index))) {} - return index; - } - - /** - * Used by `_.unescape` to convert HTML entities to characters. - * - * @private - * @param {string} chr The matched character to unescape. - * @returns {string} Returns the unescaped character. - */ - function unescapeHtmlChar(chr) { - return htmlUnescapes[chr]; - } - - /*--------------------------------------------------------------------------*/ - - /** - * Create a new pristine `lodash` function using the given `context` object. - * - * @static - * @memberOf _ - * @category Utility - * @param {Object} [context=root] The context object. - * @returns {Function} Returns a new `lodash` function. - * @example - * - * _.mixin({ 'foo': _.constant('foo') }); - * - * var lodash = _.runInContext(); - * lodash.mixin({ 'bar': lodash.constant('bar') }); - * - * _.isFunction(_.foo); - * // => true - * _.isFunction(_.bar); - * // => false - * - * lodash.isFunction(lodash.foo); - * // => false - * lodash.isFunction(lodash.bar); - * // => true - * - * // using `context` to mock `Date#getTime` use in `_.now` - * var mock = _.runInContext({ - * 'Date': function() { - * return { 'getTime': getTimeMock }; - * } - * }); - * - * // or creating a suped-up `defer` in Node.js - * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer; - */ - function runInContext(context) { - // Avoid issues with some ES3 environments that attempt to use values, named - // after built-in constructors like `Object`, for the creation of literals. - // ES5 clears this up by stating that literals must use built-in constructors. - // See https://es5.github.io/#x11.1.5 for more details. - context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root; - - /** Native constructor references. */ - var Array = context.Array, - Date = context.Date, - Error = context.Error, - Function = context.Function, - Math = context.Math, - Number = context.Number, - Object = context.Object, - RegExp = context.RegExp, - String = context.String, - TypeError = context.TypeError; - - /** Used for native method references. */ - var arrayProto = Array.prototype, - objectProto = Object.prototype, - stringProto = String.prototype; - - /** Used to resolve the decompiled source of functions. */ - var fnToString = Function.prototype.toString; - - /** Used to check objects for own properties. */ - var hasOwnProperty = objectProto.hasOwnProperty; - - /** Used to generate unique IDs. */ - var idCounter = 0; - - /** - * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) - * of values. - */ - var objToString = objectProto.toString; - - /** Used to restore the original `_` reference in `_.noConflict`. */ - var oldDash = root._; - - /** Used to detect if a method is native. */ - var reIsNative = RegExp('^' + - fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&') - .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' - ); - - /** Native method references. */ - var ArrayBuffer = context.ArrayBuffer, - clearTimeout = context.clearTimeout, - parseFloat = context.parseFloat, - pow = Math.pow, - propertyIsEnumerable = objectProto.propertyIsEnumerable, - Set = getNative(context, 'Set'), - setTimeout = context.setTimeout, - splice = arrayProto.splice, - Uint8Array = context.Uint8Array, - WeakMap = getNative(context, 'WeakMap'); - - /* Native method references for those with the same name as other `lodash` methods. */ - var nativeCeil = Math.ceil, - nativeCreate = getNative(Object, 'create'), - nativeFloor = Math.floor, - nativeIsArray = getNative(Array, 'isArray'), - nativeIsFinite = context.isFinite, - nativeKeys = getNative(Object, 'keys'), - nativeMax = Math.max, - nativeMin = Math.min, - nativeNow = getNative(Date, 'now'), - nativeParseInt = context.parseInt, - nativeRandom = Math.random; - - /** Used as references for `-Infinity` and `Infinity`. */ - var NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY, - POSITIVE_INFINITY = Number.POSITIVE_INFINITY; - - /** Used as references for the maximum length and index of an array. */ - var MAX_ARRAY_LENGTH = 4294967295, - MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1, - HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1; - - /** - * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer) - * of an array-like value. - */ - var MAX_SAFE_INTEGER = 9007199254740991; - - /** Used to store function metadata. */ - var metaMap = WeakMap && new WeakMap; - - /** Used to lookup unminified function names. */ - var realNames = {}; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a `lodash` object which wraps `value` to enable implicit chaining. - * Methods that operate on and return arrays, collections, and functions can - * be chained together. Methods that retrieve a single value or may return a - * primitive value will automatically end the chain returning the unwrapped - * value. Explicit chaining may be enabled using `_.chain`. The execution of - * chained methods is lazy, that is, execution is deferred until `_#value` - * is implicitly or explicitly called. - * - * Lazy evaluation allows several methods to support shortcut fusion. Shortcut - * fusion is an optimization strategy which merge iteratee calls; this can help - * to avoid the creation of intermediate data structures and greatly reduce the - * number of iteratee executions. - * - * Chaining is supported in custom builds as long as the `_#value` method is - * directly or indirectly included in the build. - * - * In addition to lodash methods, wrappers have `Array` and `String` methods. - * - * The wrapper `Array` methods are: - * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, - * `splice`, and `unshift` - * - * The wrapper `String` methods are: - * `replace` and `split` - * - * The wrapper methods that support shortcut fusion are: - * `compact`, `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, - * `first`, `initial`, `last`, `map`, `pluck`, `reject`, `rest`, `reverse`, - * `slice`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, `toArray`, - * and `where` - * - * The chainable wrapper methods are: - * `after`, `ary`, `assign`, `at`, `before`, `bind`, `bindAll`, `bindKey`, - * `callback`, `chain`, `chunk`, `commit`, `compact`, `concat`, `constant`, - * `countBy`, `create`, `curry`, `debounce`, `defaults`, `defaultsDeep`, - * `defer`, `delay`, `difference`, `drop`, `dropRight`, `dropRightWhile`, - * `dropWhile`, `fill`, `filter`, `flatten`, `flattenDeep`, `flow`, `flowRight`, - * `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`, - * `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`, - * `invoke`, `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, - * `matchesProperty`, `memoize`, `merge`, `method`, `methodOf`, `mixin`, - * `modArgs`, `negate`, `omit`, `once`, `pairs`, `partial`, `partialRight`, - * `partition`, `pick`, `plant`, `pluck`, `property`, `propertyOf`, `pull`, - * `pullAt`, `push`, `range`, `rearg`, `reject`, `remove`, `rest`, `restParam`, - * `reverse`, `set`, `shuffle`, `slice`, `sort`, `sortBy`, `sortByAll`, - * `sortByOrder`, `splice`, `spread`, `take`, `takeRight`, `takeRightWhile`, - * `takeWhile`, `tap`, `throttle`, `thru`, `times`, `toArray`, `toPlainObject`, - * `transform`, `union`, `uniq`, `unshift`, `unzip`, `unzipWith`, `values`, - * `valuesIn`, `where`, `without`, `wrap`, `xor`, `zip`, `zipObject`, `zipWith` - * - * The wrapper methods that are **not** chainable by default are: - * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clone`, `cloneDeep`, - * `deburr`, `endsWith`, `escape`, `escapeRegExp`, `every`, `find`, `findIndex`, - * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `findWhere`, `first`, - * `floor`, `get`, `gt`, `gte`, `has`, `identity`, `includes`, `indexOf`, - * `inRange`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`, - * `isEmpty`, `isEqual`, `isError`, `isFinite` `isFunction`, `isMatch`, - * `isNative`, `isNaN`, `isNull`, `isNumber`, `isObject`, `isPlainObject`, - * `isRegExp`, `isString`, `isUndefined`, `isTypedArray`, `join`, `kebabCase`, - * `last`, `lastIndexOf`, `lt`, `lte`, `max`, `min`, `noConflict`, `noop`, - * `now`, `pad`, `padLeft`, `padRight`, `parseInt`, `pop`, `random`, `reduce`, - * `reduceRight`, `repeat`, `result`, `round`, `runInContext`, `shift`, `size`, - * `snakeCase`, `some`, `sortedIndex`, `sortedLastIndex`, `startCase`, - * `startsWith`, `sum`, `template`, `trim`, `trimLeft`, `trimRight`, `trunc`, - * `unescape`, `uniqueId`, `value`, and `words` - * - * The wrapper method `sample` will return a wrapped value when `n` is provided, - * otherwise an unwrapped value is returned. - * - * @name _ - * @constructor - * @category Chain - * @param {*} value The value to wrap in a `lodash` instance. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var wrapped = _([1, 2, 3]); - * - * // returns an unwrapped value - * wrapped.reduce(function(total, n) { - * return total + n; - * }); - * // => 6 - * - * // returns a wrapped value - * var squares = wrapped.map(function(n) { - * return n * n; - * }); - * - * _.isArray(squares); - * // => false - * - * _.isArray(squares.value()); - * // => true - */ - function lodash(value) { - if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) { - if (value instanceof LodashWrapper) { - return value; - } - if (hasOwnProperty.call(value, '__chain__') && hasOwnProperty.call(value, '__wrapped__')) { - return wrapperClone(value); - } - } - return new LodashWrapper(value); - } - - /** - * The function whose prototype all chaining wrappers inherit from. - * - * @private - */ - function baseLodash() { - // No operation performed. - } - - /** - * The base constructor for creating `lodash` wrapper objects. - * - * @private - * @param {*} value The value to wrap. - * @param {boolean} [chainAll] Enable chaining for all wrapper methods. - * @param {Array} [actions=[]] Actions to peform to resolve the unwrapped value. - */ - function LodashWrapper(value, chainAll, actions) { - this.__wrapped__ = value; - this.__actions__ = actions || []; - this.__chain__ = !!chainAll; - } - - /** - * An object environment feature flags. - * - * @static - * @memberOf _ - * @type Object - */ - var support = lodash.support = {}; - - /** - * By default, the template delimiters used by lodash are like those in - * embedded Ruby (ERB). Change the following template settings to use - * alternative delimiters. - * - * @static - * @memberOf _ - * @type Object - */ - lodash.templateSettings = { - - /** - * Used to detect `data` property values to be HTML-escaped. - * - * @memberOf _.templateSettings - * @type RegExp - */ - 'escape': reEscape, - - /** - * Used to detect code to be evaluated. - * - * @memberOf _.templateSettings - * @type RegExp - */ - 'evaluate': reEvaluate, - - /** - * Used to detect `data` property values to inject. - * - * @memberOf _.templateSettings - * @type RegExp - */ - 'interpolate': reInterpolate, - - /** - * Used to reference the data object in the template text. - * - * @memberOf _.templateSettings - * @type string - */ - 'variable': '', - - /** - * Used to import variables into the compiled template. - * - * @memberOf _.templateSettings - * @type Object - */ - 'imports': { - - /** - * A reference to the `lodash` function. - * - * @memberOf _.templateSettings.imports - * @type Function - */ - '_': lodash - } - }; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation. - * - * @private - * @param {*} value The value to wrap. - */ - function LazyWrapper(value) { - this.__wrapped__ = value; - this.__actions__ = []; - this.__dir__ = 1; - this.__filtered__ = false; - this.__iteratees__ = []; - this.__takeCount__ = POSITIVE_INFINITY; - this.__views__ = []; - } - - /** - * Creates a clone of the lazy wrapper object. - * - * @private - * @name clone - * @memberOf LazyWrapper - * @returns {Object} Returns the cloned `LazyWrapper` object. - */ - function lazyClone() { - var result = new LazyWrapper(this.__wrapped__); - result.__actions__ = arrayCopy(this.__actions__); - result.__dir__ = this.__dir__; - result.__filtered__ = this.__filtered__; - result.__iteratees__ = arrayCopy(this.__iteratees__); - result.__takeCount__ = this.__takeCount__; - result.__views__ = arrayCopy(this.__views__); - return result; - } - - /** - * Reverses the direction of lazy iteration. - * - * @private - * @name reverse - * @memberOf LazyWrapper - * @returns {Object} Returns the new reversed `LazyWrapper` object. - */ - function lazyReverse() { - if (this.__filtered__) { - var result = new LazyWrapper(this); - result.__dir__ = -1; - result.__filtered__ = true; - } else { - result = this.clone(); - result.__dir__ *= -1; - } - return result; - } - - /** - * Extracts the unwrapped value from its lazy wrapper. - * - * @private - * @name value - * @memberOf LazyWrapper - * @returns {*} Returns the unwrapped value. - */ - function lazyValue() { - var array = this.__wrapped__.value(), - dir = this.__dir__, - isArr = isArray(array), - isRight = dir < 0, - arrLength = isArr ? array.length : 0, - view = getView(0, arrLength, this.__views__), - start = view.start, - end = view.end, - length = end - start, - index = isRight ? end : (start - 1), - iteratees = this.__iteratees__, - iterLength = iteratees.length, - resIndex = 0, - takeCount = nativeMin(length, this.__takeCount__); - - if (!isArr || arrLength < LARGE_ARRAY_SIZE || (arrLength == length && takeCount == length)) { - return baseWrapperValue(array, this.__actions__); - } - var result = []; - - outer: - while (length-- && resIndex < takeCount) { - index += dir; - - var iterIndex = -1, - value = array[index]; - - while (++iterIndex < iterLength) { - var data = iteratees[iterIndex], - iteratee = data.iteratee, - type = data.type, - computed = iteratee(value); - - if (type == LAZY_MAP_FLAG) { - value = computed; - } else if (!computed) { - if (type == LAZY_FILTER_FLAG) { - continue outer; - } else { - break outer; - } - } - } - result[resIndex++] = value; - } - return result; - } - - /*------------------------------------------------------------------------*/ - - /** - * Creates a cache object to store key/value pairs. - * - * @private - * @static - * @name Cache - * @memberOf _.memoize - */ - function MapCache() { - this.__data__ = {}; - } - - /** - * Removes `key` and its value from the cache. - * - * @private - * @name delete - * @memberOf _.memoize.Cache - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed successfully, else `false`. - */ - function mapDelete(key) { - return this.has(key) && delete this.__data__[key]; - } - - /** - * Gets the cached value for `key`. - * - * @private - * @name get - * @memberOf _.memoize.Cache - * @param {string} key The key of the value to get. - * @returns {*} Returns the cached value. - */ - function mapGet(key) { - return key == '__proto__' ? undefined : this.__data__[key]; - } - - /** - * Checks if a cached value for `key` exists. - * - * @private - * @name has - * @memberOf _.memoize.Cache - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function mapHas(key) { - return key != '__proto__' && hasOwnProperty.call(this.__data__, key); - } - - /** - * Sets `value` to `key` of the cache. - * - * @private - * @name set - * @memberOf _.memoize.Cache - * @param {string} key The key of the value to cache. - * @param {*} value The value to cache. - * @returns {Object} Returns the cache object. - */ - function mapSet(key, value) { - if (key != '__proto__') { - this.__data__[key] = value; - } - return this; - } - - /*------------------------------------------------------------------------*/ - - /** - * - * Creates a cache object to store unique values. - * - * @private - * @param {Array} [values] The values to cache. - */ - function SetCache(values) { - var length = values ? values.length : 0; - - this.data = { 'hash': nativeCreate(null), 'set': new Set }; - while (length--) { - this.push(values[length]); - } - } - - /** - * Checks if `value` is in `cache` mimicking the return signature of - * `_.indexOf` by returning `0` if the value is found, else `-1`. - * - * @private - * @param {Object} cache The cache to search. - * @param {*} value The value to search for. - * @returns {number} Returns `0` if `value` is found, else `-1`. - */ - function cacheIndexOf(cache, value) { - var data = cache.data, - result = (typeof value == 'string' || isObject(value)) ? data.set.has(value) : data.hash[value]; - - return result ? 0 : -1; - } - - /** - * Adds `value` to the cache. - * - * @private - * @name push - * @memberOf SetCache - * @param {*} value The value to cache. - */ - function cachePush(value) { - var data = this.data; - if (typeof value == 'string' || isObject(value)) { - data.set.add(value); - } else { - data.hash[value] = true; - } - } - - /*------------------------------------------------------------------------*/ - - /** - * Creates a new array joining `array` with `other`. - * - * @private - * @param {Array} array The array to join. - * @param {Array} other The other array to join. - * @returns {Array} Returns the new concatenated array. - */ - function arrayConcat(array, other) { - var index = -1, - length = array.length, - othIndex = -1, - othLength = other.length, - result = Array(length + othLength); - - while (++index < length) { - result[index] = array[index]; - } - while (++othIndex < othLength) { - result[index++] = other[othIndex]; - } - return result; - } - - /** - * Copies the values of `source` to `array`. - * - * @private - * @param {Array} source The array to copy values from. - * @param {Array} [array=[]] The array to copy values to. - * @returns {Array} Returns `array`. - */ - function arrayCopy(source, array) { - var index = -1, - length = source.length; - - array || (array = Array(length)); - while (++index < length) { - array[index] = source[index]; - } - return array; - } - - /** - * A specialized version of `_.forEach` for arrays without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns `array`. - */ - function arrayEach(array, iteratee) { - var index = -1, - length = array.length; - - while (++index < length) { - if (iteratee(array[index], index, array) === false) { - break; - } - } - return array; - } - - /** - * A specialized version of `_.forEachRight` for arrays without support for - * callback shorthands and `this` binding. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns `array`. - */ - function arrayEachRight(array, iteratee) { - var length = array.length; - - while (length--) { - if (iteratee(array[length], length, array) === false) { - break; - } - } - return array; - } - - /** - * A specialized version of `_.every` for arrays without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if all elements pass the predicate check, - * else `false`. - */ - function arrayEvery(array, predicate) { - var index = -1, - length = array.length; - - while (++index < length) { - if (!predicate(array[index], index, array)) { - return false; - } - } - return true; - } - - /** - * A specialized version of `baseExtremum` for arrays which invokes `iteratee` - * with one argument: (value). - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {Function} comparator The function used to compare values. - * @param {*} exValue The initial extremum value. - * @returns {*} Returns the extremum value. - */ - function arrayExtremum(array, iteratee, comparator, exValue) { - var index = -1, - length = array.length, - computed = exValue, - result = computed; - - while (++index < length) { - var value = array[index], - current = +iteratee(value); - - if (comparator(current, computed)) { - computed = current; - result = value; - } - } - return result; - } - - /** - * A specialized version of `_.filter` for arrays without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - */ - function arrayFilter(array, predicate) { - var index = -1, - length = array.length, - resIndex = -1, - result = []; - - while (++index < length) { - var value = array[index]; - if (predicate(value, index, array)) { - result[++resIndex] = value; - } - } - return result; - } - - /** - * A specialized version of `_.map` for arrays without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the new mapped array. - */ - function arrayMap(array, iteratee) { - var index = -1, - length = array.length, - result = Array(length); - - while (++index < length) { - result[index] = iteratee(array[index], index, array); - } - return result; - } - - /** - * Appends the elements of `values` to `array`. - * - * @private - * @param {Array} array The array to modify. - * @param {Array} values The values to append. - * @returns {Array} Returns `array`. - */ - function arrayPush(array, values) { - var index = -1, - length = values.length, - offset = array.length; - - while (++index < length) { - array[offset + index] = values[index]; - } - return array; - } - - /** - * A specialized version of `_.reduce` for arrays without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @param {boolean} [initFromArray] Specify using the first element of `array` - * as the initial value. - * @returns {*} Returns the accumulated value. - */ - function arrayReduce(array, iteratee, accumulator, initFromArray) { - var index = -1, - length = array.length; - - if (initFromArray && length) { - accumulator = array[++index]; - } - while (++index < length) { - accumulator = iteratee(accumulator, array[index], index, array); - } - return accumulator; - } - - /** - * A specialized version of `_.reduceRight` for arrays without support for - * callback shorthands and `this` binding. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @param {boolean} [initFromArray] Specify using the last element of `array` - * as the initial value. - * @returns {*} Returns the accumulated value. - */ - function arrayReduceRight(array, iteratee, accumulator, initFromArray) { - var length = array.length; - if (initFromArray && length) { - accumulator = array[--length]; - } - while (length--) { - accumulator = iteratee(accumulator, array[length], length, array); - } - return accumulator; - } - - /** - * A specialized version of `_.some` for arrays without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. - */ - function arraySome(array, predicate) { - var index = -1, - length = array.length; - - while (++index < length) { - if (predicate(array[index], index, array)) { - return true; - } - } - return false; - } - - /** - * A specialized version of `_.sum` for arrays without support for callback - * shorthands and `this` binding.. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {number} Returns the sum. - */ - function arraySum(array, iteratee) { - var length = array.length, - result = 0; - - while (length--) { - result += +iteratee(array[length]) || 0; - } - return result; - } - - /** - * Used by `_.defaults` to customize its `_.assign` use. - * - * @private - * @param {*} objectValue The destination object property value. - * @param {*} sourceValue The source object property value. - * @returns {*} Returns the value to assign to the destination object. - */ - function assignDefaults(objectValue, sourceValue) { - return objectValue === undefined ? sourceValue : objectValue; - } - - /** - * Used by `_.template` to customize its `_.assign` use. - * - * **Note:** This function is like `assignDefaults` except that it ignores - * inherited property values when checking if a property is `undefined`. - * - * @private - * @param {*} objectValue The destination object property value. - * @param {*} sourceValue The source object property value. - * @param {string} key The key associated with the object and source values. - * @param {Object} object The destination object. - * @returns {*} Returns the value to assign to the destination object. - */ - function assignOwnDefaults(objectValue, sourceValue, key, object) { - return (objectValue === undefined || !hasOwnProperty.call(object, key)) - ? sourceValue - : objectValue; - } - - /** - * A specialized version of `_.assign` for customizing assigned values without - * support for argument juggling, multiple sources, and `this` binding `customizer` - * functions. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @param {Function} customizer The function to customize assigned values. - * @returns {Object} Returns `object`. - */ - function assignWith(object, source, customizer) { - var index = -1, - props = keys(source), - length = props.length; - - while (++index < length) { - var key = props[index], - value = object[key], - result = customizer(value, source[key], key, object, source); - - if ((result === result ? (result !== value) : (value === value)) || - (value === undefined && !(key in object))) { - object[key] = result; - } - } - return object; - } - - /** - * The base implementation of `_.assign` without support for argument juggling, - * multiple sources, and `customizer` functions. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @returns {Object} Returns `object`. - */ - function baseAssign(object, source) { - return source == null - ? object - : baseCopy(source, keys(source), object); - } - - /** - * The base implementation of `_.at` without support for string collections - * and individual key arguments. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {number[]|string[]} props The property names or indexes of elements to pick. - * @returns {Array} Returns the new array of picked elements. - */ - function baseAt(collection, props) { - var index = -1, - isNil = collection == null, - isArr = !isNil && isArrayLike(collection), - length = isArr ? collection.length : 0, - propsLength = props.length, - result = Array(propsLength); - - while(++index < propsLength) { - var key = props[index]; - if (isArr) { - result[index] = isIndex(key, length) ? collection[key] : undefined; - } else { - result[index] = isNil ? undefined : collection[key]; - } - } - return result; - } - - /** - * Copies properties of `source` to `object`. - * - * @private - * @param {Object} source The object to copy properties from. - * @param {Array} props The property names to copy. - * @param {Object} [object={}] The object to copy properties to. - * @returns {Object} Returns `object`. - */ - function baseCopy(source, props, object) { - object || (object = {}); - - var index = -1, - length = props.length; - - while (++index < length) { - var key = props[index]; - object[key] = source[key]; - } - return object; - } - - /** - * The base implementation of `_.callback` which supports specifying the - * number of arguments to provide to `func`. - * - * @private - * @param {*} [func=_.identity] The value to convert to a callback. - * @param {*} [thisArg] The `this` binding of `func`. - * @param {number} [argCount] The number of arguments to provide to `func`. - * @returns {Function} Returns the callback. - */ - function baseCallback(func, thisArg, argCount) { - var type = typeof func; - if (type == 'function') { - return thisArg === undefined - ? func - : bindCallback(func, thisArg, argCount); - } - if (func == null) { - return identity; - } - if (type == 'object') { - return baseMatches(func); - } - return thisArg === undefined - ? property(func) - : baseMatchesProperty(func, thisArg); - } - - /** - * The base implementation of `_.clone` without support for argument juggling - * and `this` binding `customizer` functions. - * - * @private - * @param {*} value The value to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @param {Function} [customizer] The function to customize cloning values. - * @param {string} [key] The key of `value`. - * @param {Object} [object] The object `value` belongs to. - * @param {Array} [stackA=[]] Tracks traversed source objects. - * @param {Array} [stackB=[]] Associates clones with source counterparts. - * @returns {*} Returns the cloned value. - */ - function baseClone(value, isDeep, customizer, key, object, stackA, stackB) { - var result; - if (customizer) { - result = object ? customizer(value, key, object) : customizer(value); - } - if (result !== undefined) { - return result; - } - if (!isObject(value)) { - return value; - } - var isArr = isArray(value); - if (isArr) { - result = initCloneArray(value); - if (!isDeep) { - return arrayCopy(value, result); - } - } else { - var tag = objToString.call(value), - isFunc = tag == funcTag; - - if (tag == objectTag || tag == argsTag || (isFunc && !object)) { - result = initCloneObject(isFunc ? {} : value); - if (!isDeep) { - return baseAssign(result, value); - } - } else { - return cloneableTags[tag] - ? initCloneByTag(value, tag, isDeep) - : (object ? value : {}); - } - } - // Check for circular references and return its corresponding clone. - stackA || (stackA = []); - stackB || (stackB = []); - - var length = stackA.length; - while (length--) { - if (stackA[length] == value) { - return stackB[length]; - } - } - // Add the source value to the stack of traversed objects and associate it with its clone. - stackA.push(value); - stackB.push(result); - - // Recursively populate clone (susceptible to call stack limits). - (isArr ? arrayEach : baseForOwn)(value, function(subValue, key) { - result[key] = baseClone(subValue, isDeep, customizer, key, value, stackA, stackB); - }); - return result; - } - - /** - * The base implementation of `_.create` without support for assigning - * properties to the created object. - * - * @private - * @param {Object} prototype The object to inherit from. - * @returns {Object} Returns the new object. - */ - var baseCreate = (function() { - function object() {} - return function(prototype) { - if (isObject(prototype)) { - object.prototype = prototype; - var result = new object; - object.prototype = undefined; - } - return result || {}; - }; - }()); - - /** - * The base implementation of `_.delay` and `_.defer` which accepts an index - * of where to slice the arguments to provide to `func`. - * - * @private - * @param {Function} func The function to delay. - * @param {number} wait The number of milliseconds to delay invocation. - * @param {Object} args The arguments provide to `func`. - * @returns {number} Returns the timer id. - */ - function baseDelay(func, wait, args) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - return setTimeout(function() { func.apply(undefined, args); }, wait); - } - - /** - * The base implementation of `_.difference` which accepts a single array - * of values to exclude. - * - * @private - * @param {Array} array The array to inspect. - * @param {Array} values The values to exclude. - * @returns {Array} Returns the new array of filtered values. - */ - function baseDifference(array, values) { - var length = array ? array.length : 0, - result = []; - - if (!length) { - return result; - } - var index = -1, - indexOf = getIndexOf(), - isCommon = indexOf === baseIndexOf, - cache = (isCommon && values.length >= LARGE_ARRAY_SIZE) ? createCache(values) : null, - valuesLength = values.length; - - if (cache) { - indexOf = cacheIndexOf; - isCommon = false; - values = cache; - } - outer: - while (++index < length) { - var value = array[index]; - - if (isCommon && value === value) { - var valuesIndex = valuesLength; - while (valuesIndex--) { - if (values[valuesIndex] === value) { - continue outer; - } - } - result.push(value); - } - else if (indexOf(values, value, 0) < 0) { - result.push(value); - } - } - return result; - } - - /** - * The base implementation of `_.forEach` without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array|Object|string} Returns `collection`. - */ - var baseEach = createBaseEach(baseForOwn); - - /** - * The base implementation of `_.forEachRight` without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array|Object|string} Returns `collection`. - */ - var baseEachRight = createBaseEach(baseForOwnRight, true); - - /** - * The base implementation of `_.every` without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if all elements pass the predicate check, - * else `false` - */ - function baseEvery(collection, predicate) { - var result = true; - baseEach(collection, function(value, index, collection) { - result = !!predicate(value, index, collection); - return result; - }); - return result; - } - - /** - * Gets the extremum value of `collection` invoking `iteratee` for each value - * in `collection` to generate the criterion by which the value is ranked. - * The `iteratee` is invoked with three arguments: (value, index|key, collection). - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {Function} comparator The function used to compare values. - * @param {*} exValue The initial extremum value. - * @returns {*} Returns the extremum value. - */ - function baseExtremum(collection, iteratee, comparator, exValue) { - var computed = exValue, - result = computed; - - baseEach(collection, function(value, index, collection) { - var current = +iteratee(value, index, collection); - if (comparator(current, computed) || (current === exValue && current === result)) { - computed = current; - result = value; - } - }); - return result; - } - - /** - * The base implementation of `_.fill` without an iteratee call guard. - * - * @private - * @param {Array} array The array to fill. - * @param {*} value The value to fill `array` with. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns `array`. - */ - function baseFill(array, value, start, end) { - var length = array.length; - - start = start == null ? 0 : (+start || 0); - if (start < 0) { - start = -start > length ? 0 : (length + start); - } - end = (end === undefined || end > length) ? length : (+end || 0); - if (end < 0) { - end += length; - } - length = start > end ? 0 : (end >>> 0); - start >>>= 0; - - while (start < length) { - array[start++] = value; - } - return array; - } - - /** - * The base implementation of `_.filter` without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - */ - function baseFilter(collection, predicate) { - var result = []; - baseEach(collection, function(value, index, collection) { - if (predicate(value, index, collection)) { - result.push(value); - } - }); - return result; - } - - /** - * The base implementation of `_.find`, `_.findLast`, `_.findKey`, and `_.findLastKey`, - * without support for callback shorthands and `this` binding, which iterates - * over `collection` using the provided `eachFunc`. - * - * @private - * @param {Array|Object|string} collection The collection to search. - * @param {Function} predicate The function invoked per iteration. - * @param {Function} eachFunc The function to iterate over `collection`. - * @param {boolean} [retKey] Specify returning the key of the found element - * instead of the element itself. - * @returns {*} Returns the found element or its key, else `undefined`. - */ - function baseFind(collection, predicate, eachFunc, retKey) { - var result; - eachFunc(collection, function(value, key, collection) { - if (predicate(value, key, collection)) { - result = retKey ? key : value; - return false; - } - }); - return result; - } - - /** - * The base implementation of `_.flatten` with added support for restricting - * flattening and specifying the start index. - * - * @private - * @param {Array} array The array to flatten. - * @param {boolean} [isDeep] Specify a deep flatten. - * @param {boolean} [isStrict] Restrict flattening to arrays-like objects. - * @param {Array} [result=[]] The initial result value. - * @returns {Array} Returns the new flattened array. - */ - function baseFlatten(array, isDeep, isStrict, result) { - result || (result = []); - - var index = -1, - length = array.length; - - while (++index < length) { - var value = array[index]; - if (isObjectLike(value) && isArrayLike(value) && - (isStrict || isArray(value) || isArguments(value))) { - if (isDeep) { - // Recursively flatten arrays (susceptible to call stack limits). - baseFlatten(value, isDeep, isStrict, result); - } else { - arrayPush(result, value); - } - } else if (!isStrict) { - result[result.length] = value; - } - } - return result; - } - - /** - * The base implementation of `baseForIn` and `baseForOwn` which iterates - * over `object` properties returned by `keysFunc` invoking `iteratee` for - * each property. Iteratee functions may exit iteration early by explicitly - * returning `false`. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {Function} keysFunc The function to get the keys of `object`. - * @returns {Object} Returns `object`. - */ - var baseFor = createBaseFor(); - - /** - * This function is like `baseFor` except that it iterates over properties - * in the opposite order. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {Function} keysFunc The function to get the keys of `object`. - * @returns {Object} Returns `object`. - */ - var baseForRight = createBaseFor(true); - - /** - * The base implementation of `_.forIn` without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Object} Returns `object`. - */ - function baseForIn(object, iteratee) { - return baseFor(object, iteratee, keysIn); - } - - /** - * The base implementation of `_.forOwn` without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Object} Returns `object`. - */ - function baseForOwn(object, iteratee) { - return baseFor(object, iteratee, keys); - } - - /** - * The base implementation of `_.forOwnRight` without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Object} Returns `object`. - */ - function baseForOwnRight(object, iteratee) { - return baseForRight(object, iteratee, keys); - } - - /** - * The base implementation of `_.functions` which creates an array of - * `object` function property names filtered from those provided. - * - * @private - * @param {Object} object The object to inspect. - * @param {Array} props The property names to filter. - * @returns {Array} Returns the new array of filtered property names. - */ - function baseFunctions(object, props) { - var index = -1, - length = props.length, - resIndex = -1, - result = []; - - while (++index < length) { - var key = props[index]; - if (isFunction(object[key])) { - result[++resIndex] = key; - } - } - return result; - } - - /** - * The base implementation of `get` without support for string paths - * and default values. - * - * @private - * @param {Object} object The object to query. - * @param {Array} path The path of the property to get. - * @param {string} [pathKey] The key representation of path. - * @returns {*} Returns the resolved value. - */ - function baseGet(object, path, pathKey) { - if (object == null) { - return; - } - if (pathKey !== undefined && pathKey in toObject(object)) { - path = [pathKey]; - } - var index = 0, - length = path.length; - - while (object != null && index < length) { - object = object[path[index++]]; - } - return (index && index == length) ? object : undefined; - } - - /** - * The base implementation of `_.isEqual` without support for `this` binding - * `customizer` functions. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @param {Function} [customizer] The function to customize comparing values. - * @param {boolean} [isLoose] Specify performing partial comparisons. - * @param {Array} [stackA] Tracks traversed `value` objects. - * @param {Array} [stackB] Tracks traversed `other` objects. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - */ - function baseIsEqual(value, other, customizer, isLoose, stackA, stackB) { - if (value === other) { - return true; - } - if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) { - return value !== value && other !== other; - } - return baseIsEqualDeep(value, other, baseIsEqual, customizer, isLoose, stackA, stackB); - } - - /** - * A specialized version of `baseIsEqual` for arrays and objects which performs - * deep comparisons and tracks traversed objects enabling objects with circular - * references to be compared. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} [customizer] The function to customize comparing objects. - * @param {boolean} [isLoose] Specify performing partial comparisons. - * @param {Array} [stackA=[]] Tracks traversed `value` objects. - * @param {Array} [stackB=[]] Tracks traversed `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function baseIsEqualDeep(object, other, equalFunc, customizer, isLoose, stackA, stackB) { - var objIsArr = isArray(object), - othIsArr = isArray(other), - objTag = arrayTag, - othTag = arrayTag; - - if (!objIsArr) { - objTag = objToString.call(object); - if (objTag == argsTag) { - objTag = objectTag; - } else if (objTag != objectTag) { - objIsArr = isTypedArray(object); - } - } - if (!othIsArr) { - othTag = objToString.call(other); - if (othTag == argsTag) { - othTag = objectTag; - } else if (othTag != objectTag) { - othIsArr = isTypedArray(other); - } - } - var objIsObj = objTag == objectTag, - othIsObj = othTag == objectTag, - isSameTag = objTag == othTag; - - if (isSameTag && !(objIsArr || objIsObj)) { - return equalByTag(object, other, objTag); - } - if (!isLoose) { - var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), - othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); - - if (objIsWrapped || othIsWrapped) { - return equalFunc(objIsWrapped ? object.value() : object, othIsWrapped ? other.value() : other, customizer, isLoose, stackA, stackB); - } - } - if (!isSameTag) { - return false; - } - // Assume cyclic values are equal. - // For more information on detecting circular references see https://es5.github.io/#JO. - stackA || (stackA = []); - stackB || (stackB = []); - - var length = stackA.length; - while (length--) { - if (stackA[length] == object) { - return stackB[length] == other; - } - } - // Add `object` and `other` to the stack of traversed objects. - stackA.push(object); - stackB.push(other); - - var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, isLoose, stackA, stackB); - - stackA.pop(); - stackB.pop(); - - return result; - } - - /** - * The base implementation of `_.isMatch` without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Object} object The object to inspect. - * @param {Array} matchData The propery names, values, and compare flags to match. - * @param {Function} [customizer] The function to customize comparing objects. - * @returns {boolean} Returns `true` if `object` is a match, else `false`. - */ - function baseIsMatch(object, matchData, customizer) { - var index = matchData.length, - length = index, - noCustomizer = !customizer; - - if (object == null) { - return !length; - } - object = toObject(object); - while (index--) { - var data = matchData[index]; - if ((noCustomizer && data[2]) - ? data[1] !== object[data[0]] - : !(data[0] in object) - ) { - return false; - } - } - while (++index < length) { - data = matchData[index]; - var key = data[0], - objValue = object[key], - srcValue = data[1]; - - if (noCustomizer && data[2]) { - if (objValue === undefined && !(key in object)) { - return false; - } - } else { - var result = customizer ? customizer(objValue, srcValue, key) : undefined; - if (!(result === undefined ? baseIsEqual(srcValue, objValue, customizer, true) : result)) { - return false; - } - } - } - return true; - } - - /** - * The base implementation of `_.map` without support for callback shorthands - * and `this` binding. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the new mapped array. - */ - function baseMap(collection, iteratee) { - var index = -1, - result = isArrayLike(collection) ? Array(collection.length) : []; - - baseEach(collection, function(value, key, collection) { - result[++index] = iteratee(value, key, collection); - }); - return result; - } - - /** - * The base implementation of `_.matches` which does not clone `source`. - * - * @private - * @param {Object} source The object of property values to match. - * @returns {Function} Returns the new function. - */ - function baseMatches(source) { - var matchData = getMatchData(source); - if (matchData.length == 1 && matchData[0][2]) { - var key = matchData[0][0], - value = matchData[0][1]; - - return function(object) { - if (object == null) { - return false; - } - return object[key] === value && (value !== undefined || (key in toObject(object))); - }; - } - return function(object) { - return baseIsMatch(object, matchData); - }; - } - - /** - * The base implementation of `_.matchesProperty` which does not clone `srcValue`. - * - * @private - * @param {string} path The path of the property to get. - * @param {*} srcValue The value to compare. - * @returns {Function} Returns the new function. - */ - function baseMatchesProperty(path, srcValue) { - var isArr = isArray(path), - isCommon = isKey(path) && isStrictComparable(srcValue), - pathKey = (path + ''); - - path = toPath(path); - return function(object) { - if (object == null) { - return false; - } - var key = pathKey; - object = toObject(object); - if ((isArr || !isCommon) && !(key in object)) { - object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); - if (object == null) { - return false; - } - key = last(path); - object = toObject(object); - } - return object[key] === srcValue - ? (srcValue !== undefined || (key in object)) - : baseIsEqual(srcValue, object[key], undefined, true); - }; - } - - /** - * The base implementation of `_.merge` without support for argument juggling, - * multiple sources, and `this` binding `customizer` functions. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @param {Function} [customizer] The function to customize merged values. - * @param {Array} [stackA=[]] Tracks traversed source objects. - * @param {Array} [stackB=[]] Associates values with source counterparts. - * @returns {Object} Returns `object`. - */ - function baseMerge(object, source, customizer, stackA, stackB) { - if (!isObject(object)) { - return object; - } - var isSrcArr = isArrayLike(source) && (isArray(source) || isTypedArray(source)), - props = isSrcArr ? undefined : keys(source); - - arrayEach(props || source, function(srcValue, key) { - if (props) { - key = srcValue; - srcValue = source[key]; - } - if (isObjectLike(srcValue)) { - stackA || (stackA = []); - stackB || (stackB = []); - baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB); - } - else { - var value = object[key], - result = customizer ? customizer(value, srcValue, key, object, source) : undefined, - isCommon = result === undefined; - - if (isCommon) { - result = srcValue; - } - if ((result !== undefined || (isSrcArr && !(key in object))) && - (isCommon || (result === result ? (result !== value) : (value === value)))) { - object[key] = result; - } - } - }); - return object; - } - - /** - * A specialized version of `baseMerge` for arrays and objects which performs - * deep merges and tracks traversed objects enabling objects with circular - * references to be merged. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @param {string} key The key of the value to merge. - * @param {Function} mergeFunc The function to merge values. - * @param {Function} [customizer] The function to customize merged values. - * @param {Array} [stackA=[]] Tracks traversed source objects. - * @param {Array} [stackB=[]] Associates values with source counterparts. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) { - var length = stackA.length, - srcValue = source[key]; - - while (length--) { - if (stackA[length] == srcValue) { - object[key] = stackB[length]; - return; - } - } - var value = object[key], - result = customizer ? customizer(value, srcValue, key, object, source) : undefined, - isCommon = result === undefined; - - if (isCommon) { - result = srcValue; - if (isArrayLike(srcValue) && (isArray(srcValue) || isTypedArray(srcValue))) { - result = isArray(value) - ? value - : (isArrayLike(value) ? arrayCopy(value) : []); - } - else if (isPlainObject(srcValue) || isArguments(srcValue)) { - result = isArguments(value) - ? toPlainObject(value) - : (isPlainObject(value) ? value : {}); - } - else { - isCommon = false; - } - } - // Add the source value to the stack of traversed objects and associate - // it with its merged value. - stackA.push(srcValue); - stackB.push(result); - - if (isCommon) { - // Recursively merge objects and arrays (susceptible to call stack limits). - object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB); - } else if (result === result ? (result !== value) : (value === value)) { - object[key] = result; - } - } - - /** - * The base implementation of `_.property` without support for deep paths. - * - * @private - * @param {string} key The key of the property to get. - * @returns {Function} Returns the new function. - */ - function baseProperty(key) { - return function(object) { - return object == null ? undefined : object[key]; - }; - } - - /** - * A specialized version of `baseProperty` which supports deep paths. - * - * @private - * @param {Array|string} path The path of the property to get. - * @returns {Function} Returns the new function. - */ - function basePropertyDeep(path) { - var pathKey = (path + ''); - path = toPath(path); - return function(object) { - return baseGet(object, path, pathKey); - }; - } - - /** - * The base implementation of `_.pullAt` without support for individual - * index arguments and capturing the removed elements. - * - * @private - * @param {Array} array The array to modify. - * @param {number[]} indexes The indexes of elements to remove. - * @returns {Array} Returns `array`. - */ - function basePullAt(array, indexes) { - var length = array ? indexes.length : 0; - while (length--) { - var index = indexes[length]; - if (index != previous && isIndex(index)) { - var previous = index; - splice.call(array, index, 1); - } - } - return array; - } - - /** - * The base implementation of `_.random` without support for argument juggling - * and returning floating-point numbers. - * - * @private - * @param {number} min The minimum possible value. - * @param {number} max The maximum possible value. - * @returns {number} Returns the random number. - */ - function baseRandom(min, max) { - return min + nativeFloor(nativeRandom() * (max - min + 1)); - } - - /** - * The base implementation of `_.reduce` and `_.reduceRight` without support - * for callback shorthands and `this` binding, which iterates over `collection` - * using the provided `eachFunc`. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {*} accumulator The initial value. - * @param {boolean} initFromCollection Specify using the first or last element - * of `collection` as the initial value. - * @param {Function} eachFunc The function to iterate over `collection`. - * @returns {*} Returns the accumulated value. - */ - function baseReduce(collection, iteratee, accumulator, initFromCollection, eachFunc) { - eachFunc(collection, function(value, index, collection) { - accumulator = initFromCollection - ? (initFromCollection = false, value) - : iteratee(accumulator, value, index, collection); - }); - return accumulator; - } - - /** - * The base implementation of `setData` without support for hot loop detection. - * - * @private - * @param {Function} func The function to associate metadata with. - * @param {*} data The metadata. - * @returns {Function} Returns `func`. - */ - var baseSetData = !metaMap ? identity : function(func, data) { - metaMap.set(func, data); - return func; - }; - - /** - * The base implementation of `_.slice` without an iteratee call guard. - * - * @private - * @param {Array} array The array to slice. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns the slice of `array`. - */ - function baseSlice(array, start, end) { - var index = -1, - length = array.length; - - start = start == null ? 0 : (+start || 0); - if (start < 0) { - start = -start > length ? 0 : (length + start); - } - end = (end === undefined || end > length) ? length : (+end || 0); - if (end < 0) { - end += length; - } - length = start > end ? 0 : ((end - start) >>> 0); - start >>>= 0; - - var result = Array(length); - while (++index < length) { - result[index] = array[index + start]; - } - return result; - } - - /** - * The base implementation of `_.some` without support for callback shorthands - * and `this` binding. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. - */ - function baseSome(collection, predicate) { - var result; - - baseEach(collection, function(value, index, collection) { - result = predicate(value, index, collection); - return !result; - }); - return !!result; - } - - /** - * The base implementation of `_.sortBy` which uses `comparer` to define - * the sort order of `array` and replaces criteria objects with their - * corresponding values. - * - * @private - * @param {Array} array The array to sort. - * @param {Function} comparer The function to define sort order. - * @returns {Array} Returns `array`. - */ - function baseSortBy(array, comparer) { - var length = array.length; - - array.sort(comparer); - while (length--) { - array[length] = array[length].value; - } - return array; - } - - /** - * The base implementation of `_.sortByOrder` without param guards. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. - * @param {boolean[]} orders The sort orders of `iteratees`. - * @returns {Array} Returns the new sorted array. - */ - function baseSortByOrder(collection, iteratees, orders) { - var callback = getCallback(), - index = -1; - - iteratees = arrayMap(iteratees, function(iteratee) { return callback(iteratee); }); - - var result = baseMap(collection, function(value) { - var criteria = arrayMap(iteratees, function(iteratee) { return iteratee(value); }); - return { 'criteria': criteria, 'index': ++index, 'value': value }; - }); - - return baseSortBy(result, function(object, other) { - return compareMultiple(object, other, orders); - }); - } - - /** - * The base implementation of `_.sum` without support for callback shorthands - * and `this` binding. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {number} Returns the sum. - */ - function baseSum(collection, iteratee) { - var result = 0; - baseEach(collection, function(value, index, collection) { - result += +iteratee(value, index, collection) || 0; - }); - return result; - } - - /** - * The base implementation of `_.uniq` without support for callback shorthands - * and `this` binding. - * - * @private - * @param {Array} array The array to inspect. - * @param {Function} [iteratee] The function invoked per iteration. - * @returns {Array} Returns the new duplicate free array. - */ - function baseUniq(array, iteratee) { - var index = -1, - indexOf = getIndexOf(), - length = array.length, - isCommon = indexOf === baseIndexOf, - isLarge = isCommon && length >= LARGE_ARRAY_SIZE, - seen = isLarge ? createCache() : null, - result = []; - - if (seen) { - indexOf = cacheIndexOf; - isCommon = false; - } else { - isLarge = false; - seen = iteratee ? [] : result; - } - outer: - while (++index < length) { - var value = array[index], - computed = iteratee ? iteratee(value, index, array) : value; - - if (isCommon && value === value) { - var seenIndex = seen.length; - while (seenIndex--) { - if (seen[seenIndex] === computed) { - continue outer; - } - } - if (iteratee) { - seen.push(computed); - } - result.push(value); - } - else if (indexOf(seen, computed, 0) < 0) { - if (iteratee || isLarge) { - seen.push(computed); - } - result.push(value); - } - } - return result; - } - - /** - * The base implementation of `_.values` and `_.valuesIn` which creates an - * array of `object` property values corresponding to the property names - * of `props`. - * - * @private - * @param {Object} object The object to query. - * @param {Array} props The property names to get values for. - * @returns {Object} Returns the array of property values. - */ - function baseValues(object, props) { - var index = -1, - length = props.length, - result = Array(length); - - while (++index < length) { - result[index] = object[props[index]]; - } - return result; - } - - /** - * The base implementation of `_.dropRightWhile`, `_.dropWhile`, `_.takeRightWhile`, - * and `_.takeWhile` without support for callback shorthands and `this` binding. - * - * @private - * @param {Array} array The array to query. - * @param {Function} predicate The function invoked per iteration. - * @param {boolean} [isDrop] Specify dropping elements instead of taking them. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Array} Returns the slice of `array`. - */ - function baseWhile(array, predicate, isDrop, fromRight) { - var length = array.length, - index = fromRight ? length : -1; - - while ((fromRight ? index-- : ++index < length) && predicate(array[index], index, array)) {} - return isDrop - ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length)) - : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index)); - } - - /** - * The base implementation of `wrapperValue` which returns the result of - * performing a sequence of actions on the unwrapped `value`, where each - * successive action is supplied the return value of the previous. - * - * @private - * @param {*} value The unwrapped value. - * @param {Array} actions Actions to peform to resolve the unwrapped value. - * @returns {*} Returns the resolved value. - */ - function baseWrapperValue(value, actions) { - var result = value; - if (result instanceof LazyWrapper) { - result = result.value(); - } - var index = -1, - length = actions.length; - - while (++index < length) { - var action = actions[index]; - result = action.func.apply(action.thisArg, arrayPush([result], action.args)); - } - return result; - } - - /** - * Performs a binary search of `array` to determine the index at which `value` - * should be inserted into `array` in order to maintain its sort order. - * - * @private - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {boolean} [retHighest] Specify returning the highest qualified index. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - */ - function binaryIndex(array, value, retHighest) { - var low = 0, - high = array ? array.length : low; - - if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) { - while (low < high) { - var mid = (low + high) >>> 1, - computed = array[mid]; - - if ((retHighest ? (computed <= value) : (computed < value)) && computed !== null) { - low = mid + 1; - } else { - high = mid; - } - } - return high; - } - return binaryIndexBy(array, value, identity, retHighest); - } - - /** - * This function is like `binaryIndex` except that it invokes `iteratee` for - * `value` and each element of `array` to compute their sort ranking. The - * iteratee is invoked with one argument; (value). - * - * @private - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {Function} iteratee The function invoked per iteration. - * @param {boolean} [retHighest] Specify returning the highest qualified index. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - */ - function binaryIndexBy(array, value, iteratee, retHighest) { - value = iteratee(value); - - var low = 0, - high = array ? array.length : 0, - valIsNaN = value !== value, - valIsNull = value === null, - valIsUndef = value === undefined; - - while (low < high) { - var mid = nativeFloor((low + high) / 2), - computed = iteratee(array[mid]), - isDef = computed !== undefined, - isReflexive = computed === computed; - - if (valIsNaN) { - var setLow = isReflexive || retHighest; - } else if (valIsNull) { - setLow = isReflexive && isDef && (retHighest || computed != null); - } else if (valIsUndef) { - setLow = isReflexive && (retHighest || isDef); - } else if (computed == null) { - setLow = false; - } else { - setLow = retHighest ? (computed <= value) : (computed < value); - } - if (setLow) { - low = mid + 1; - } else { - high = mid; - } - } - return nativeMin(high, MAX_ARRAY_INDEX); - } - - /** - * A specialized version of `baseCallback` which only supports `this` binding - * and specifying the number of arguments to provide to `func`. - * - * @private - * @param {Function} func The function to bind. - * @param {*} thisArg The `this` binding of `func`. - * @param {number} [argCount] The number of arguments to provide to `func`. - * @returns {Function} Returns the callback. - */ - function bindCallback(func, thisArg, argCount) { - if (typeof func != 'function') { - return identity; - } - if (thisArg === undefined) { - return func; - } - switch (argCount) { - case 1: return function(value) { - return func.call(thisArg, value); - }; - case 3: return function(value, index, collection) { - return func.call(thisArg, value, index, collection); - }; - case 4: return function(accumulator, value, index, collection) { - return func.call(thisArg, accumulator, value, index, collection); - }; - case 5: return function(value, other, key, object, source) { - return func.call(thisArg, value, other, key, object, source); - }; - } - return function() { - return func.apply(thisArg, arguments); - }; - } - - /** - * Creates a clone of the given array buffer. - * - * @private - * @param {ArrayBuffer} buffer The array buffer to clone. - * @returns {ArrayBuffer} Returns the cloned array buffer. - */ - function bufferClone(buffer) { - var result = new ArrayBuffer(buffer.byteLength), - view = new Uint8Array(result); - - view.set(new Uint8Array(buffer)); - return result; - } - - /** - * Creates an array that is the composition of partially applied arguments, - * placeholders, and provided arguments into a single array of arguments. - * - * @private - * @param {Array|Object} args The provided arguments. - * @param {Array} partials The arguments to prepend to those provided. - * @param {Array} holders The `partials` placeholder indexes. - * @returns {Array} Returns the new array of composed arguments. - */ - function composeArgs(args, partials, holders) { - var holdersLength = holders.length, - argsIndex = -1, - argsLength = nativeMax(args.length - holdersLength, 0), - leftIndex = -1, - leftLength = partials.length, - result = Array(leftLength + argsLength); - - while (++leftIndex < leftLength) { - result[leftIndex] = partials[leftIndex]; - } - while (++argsIndex < holdersLength) { - result[holders[argsIndex]] = args[argsIndex]; - } - while (argsLength--) { - result[leftIndex++] = args[argsIndex++]; - } - return result; - } - - /** - * This function is like `composeArgs` except that the arguments composition - * is tailored for `_.partialRight`. - * - * @private - * @param {Array|Object} args The provided arguments. - * @param {Array} partials The arguments to append to those provided. - * @param {Array} holders The `partials` placeholder indexes. - * @returns {Array} Returns the new array of composed arguments. - */ - function composeArgsRight(args, partials, holders) { - var holdersIndex = -1, - holdersLength = holders.length, - argsIndex = -1, - argsLength = nativeMax(args.length - holdersLength, 0), - rightIndex = -1, - rightLength = partials.length, - result = Array(argsLength + rightLength); - - while (++argsIndex < argsLength) { - result[argsIndex] = args[argsIndex]; - } - var offset = argsIndex; - while (++rightIndex < rightLength) { - result[offset + rightIndex] = partials[rightIndex]; - } - while (++holdersIndex < holdersLength) { - result[offset + holders[holdersIndex]] = args[argsIndex++]; - } - return result; - } - - /** - * Creates a `_.countBy`, `_.groupBy`, `_.indexBy`, or `_.partition` function. - * - * @private - * @param {Function} setter The function to set keys and values of the accumulator object. - * @param {Function} [initializer] The function to initialize the accumulator object. - * @returns {Function} Returns the new aggregator function. - */ - function createAggregator(setter, initializer) { - return function(collection, iteratee, thisArg) { - var result = initializer ? initializer() : {}; - iteratee = getCallback(iteratee, thisArg, 3); - - if (isArray(collection)) { - var index = -1, - length = collection.length; - - while (++index < length) { - var value = collection[index]; - setter(result, value, iteratee(value, index, collection), collection); - } - } else { - baseEach(collection, function(value, key, collection) { - setter(result, value, iteratee(value, key, collection), collection); - }); - } - return result; - }; - } - - /** - * Creates a `_.assign`, `_.defaults`, or `_.merge` function. - * - * @private - * @param {Function} assigner The function to assign values. - * @returns {Function} Returns the new assigner function. - */ - function createAssigner(assigner) { - return restParam(function(object, sources) { - var index = -1, - length = object == null ? 0 : sources.length, - customizer = length > 2 ? sources[length - 2] : undefined, - guard = length > 2 ? sources[2] : undefined, - thisArg = length > 1 ? sources[length - 1] : undefined; - - if (typeof customizer == 'function') { - customizer = bindCallback(customizer, thisArg, 5); - length -= 2; - } else { - customizer = typeof thisArg == 'function' ? thisArg : undefined; - length -= (customizer ? 1 : 0); - } - if (guard && isIterateeCall(sources[0], sources[1], guard)) { - customizer = length < 3 ? undefined : customizer; - length = 1; - } - while (++index < length) { - var source = sources[index]; - if (source) { - assigner(object, source, customizer); - } - } - return object; - }); - } - - /** - * Creates a `baseEach` or `baseEachRight` function. - * - * @private - * @param {Function} eachFunc The function to iterate over a collection. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new base function. - */ - function createBaseEach(eachFunc, fromRight) { - return function(collection, iteratee) { - var length = collection ? getLength(collection) : 0; - if (!isLength(length)) { - return eachFunc(collection, iteratee); - } - var index = fromRight ? length : -1, - iterable = toObject(collection); - - while ((fromRight ? index-- : ++index < length)) { - if (iteratee(iterable[index], index, iterable) === false) { - break; - } - } - return collection; - }; - } - - /** - * Creates a base function for `_.forIn` or `_.forInRight`. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new base function. - */ - function createBaseFor(fromRight) { - return function(object, iteratee, keysFunc) { - var iterable = toObject(object), - props = keysFunc(object), - length = props.length, - index = fromRight ? length : -1; - - while ((fromRight ? index-- : ++index < length)) { - var key = props[index]; - if (iteratee(iterable[key], key, iterable) === false) { - break; - } - } - return object; - }; - } - - /** - * Creates a function that wraps `func` and invokes it with the `this` - * binding of `thisArg`. - * - * @private - * @param {Function} func The function to bind. - * @param {*} [thisArg] The `this` binding of `func`. - * @returns {Function} Returns the new bound function. - */ - function createBindWrapper(func, thisArg) { - var Ctor = createCtorWrapper(func); - - function wrapper() { - var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; - return fn.apply(thisArg, arguments); - } - return wrapper; - } - - /** - * Creates a `Set` cache object to optimize linear searches of large arrays. - * - * @private - * @param {Array} [values] The values to cache. - * @returns {null|Object} Returns the new cache object if `Set` is supported, else `null`. - */ - function createCache(values) { - return (nativeCreate && Set) ? new SetCache(values) : null; - } - - /** - * Creates a function that produces compound words out of the words in a - * given string. - * - * @private - * @param {Function} callback The function to combine each word. - * @returns {Function} Returns the new compounder function. - */ - function createCompounder(callback) { - return function(string) { - var index = -1, - array = words(deburr(string)), - length = array.length, - result = ''; - - while (++index < length) { - result = callback(result, array[index], index); - } - return result; - }; - } - - /** - * Creates a function that produces an instance of `Ctor` regardless of - * whether it was invoked as part of a `new` expression or by `call` or `apply`. - * - * @private - * @param {Function} Ctor The constructor to wrap. - * @returns {Function} Returns the new wrapped function. - */ - function createCtorWrapper(Ctor) { - return function() { - // Use a `switch` statement to work with class constructors. - // See http://ecma-international.org/ecma-262/6.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist - // for more details. - var args = arguments; - switch (args.length) { - case 0: return new Ctor; - case 1: return new Ctor(args[0]); - case 2: return new Ctor(args[0], args[1]); - case 3: return new Ctor(args[0], args[1], args[2]); - case 4: return new Ctor(args[0], args[1], args[2], args[3]); - case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]); - case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]); - case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); - } - var thisBinding = baseCreate(Ctor.prototype), - result = Ctor.apply(thisBinding, args); - - // Mimic the constructor's `return` behavior. - // See https://es5.github.io/#x13.2.2 for more details. - return isObject(result) ? result : thisBinding; - }; - } - - /** - * Creates a `_.curry` or `_.curryRight` function. - * - * @private - * @param {boolean} flag The curry bit flag. - * @returns {Function} Returns the new curry function. - */ - function createCurry(flag) { - function curryFunc(func, arity, guard) { - if (guard && isIterateeCall(func, arity, guard)) { - arity = undefined; - } - var result = createWrapper(func, flag, undefined, undefined, undefined, undefined, undefined, arity); - result.placeholder = curryFunc.placeholder; - return result; - } - return curryFunc; - } - - /** - * Creates a `_.defaults` or `_.defaultsDeep` function. - * - * @private - * @param {Function} assigner The function to assign values. - * @param {Function} customizer The function to customize assigned values. - * @returns {Function} Returns the new defaults function. - */ - function createDefaults(assigner, customizer) { - return restParam(function(args) { - var object = args[0]; - if (object == null) { - return object; - } - args.push(customizer); - return assigner.apply(undefined, args); - }); - } - - /** - * Creates a `_.max` or `_.min` function. - * - * @private - * @param {Function} comparator The function used to compare values. - * @param {*} exValue The initial extremum value. - * @returns {Function} Returns the new extremum function. - */ - function createExtremum(comparator, exValue) { - return function(collection, iteratee, thisArg) { - if (thisArg && isIterateeCall(collection, iteratee, thisArg)) { - iteratee = undefined; - } - iteratee = getCallback(iteratee, thisArg, 3); - if (iteratee.length == 1) { - collection = isArray(collection) ? collection : toIterable(collection); - var result = arrayExtremum(collection, iteratee, comparator, exValue); - if (!(collection.length && result === exValue)) { - return result; - } - } - return baseExtremum(collection, iteratee, comparator, exValue); - }; - } - - /** - * Creates a `_.find` or `_.findLast` function. - * - * @private - * @param {Function} eachFunc The function to iterate over a collection. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new find function. - */ - function createFind(eachFunc, fromRight) { - return function(collection, predicate, thisArg) { - predicate = getCallback(predicate, thisArg, 3); - if (isArray(collection)) { - var index = baseFindIndex(collection, predicate, fromRight); - return index > -1 ? collection[index] : undefined; - } - return baseFind(collection, predicate, eachFunc); - }; - } - - /** - * Creates a `_.findIndex` or `_.findLastIndex` function. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new find function. - */ - function createFindIndex(fromRight) { - return function(array, predicate, thisArg) { - if (!(array && array.length)) { - return -1; - } - predicate = getCallback(predicate, thisArg, 3); - return baseFindIndex(array, predicate, fromRight); - }; - } - - /** - * Creates a `_.findKey` or `_.findLastKey` function. - * - * @private - * @param {Function} objectFunc The function to iterate over an object. - * @returns {Function} Returns the new find function. - */ - function createFindKey(objectFunc) { - return function(object, predicate, thisArg) { - predicate = getCallback(predicate, thisArg, 3); - return baseFind(object, predicate, objectFunc, true); - }; - } - - /** - * Creates a `_.flow` or `_.flowRight` function. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new flow function. - */ - function createFlow(fromRight) { - return function() { - var wrapper, - length = arguments.length, - index = fromRight ? length : -1, - leftIndex = 0, - funcs = Array(length); - - while ((fromRight ? index-- : ++index < length)) { - var func = funcs[leftIndex++] = arguments[index]; - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - if (!wrapper && LodashWrapper.prototype.thru && getFuncName(func) == 'wrapper') { - wrapper = new LodashWrapper([], true); - } - } - index = wrapper ? -1 : length; - while (++index < length) { - func = funcs[index]; - - var funcName = getFuncName(func), - data = funcName == 'wrapper' ? getData(func) : undefined; - - if (data && isLaziable(data[0]) && data[1] == (ARY_FLAG | CURRY_FLAG | PARTIAL_FLAG | REARG_FLAG) && !data[4].length && data[9] == 1) { - wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]); - } else { - wrapper = (func.length == 1 && isLaziable(func)) ? wrapper[funcName]() : wrapper.thru(func); - } - } - return function() { - var args = arguments, - value = args[0]; - - if (wrapper && args.length == 1 && isArray(value) && value.length >= LARGE_ARRAY_SIZE) { - return wrapper.plant(value).value(); - } - var index = 0, - result = length ? funcs[index].apply(this, args) : value; - - while (++index < length) { - result = funcs[index].call(this, result); - } - return result; - }; - }; - } - - /** - * Creates a function for `_.forEach` or `_.forEachRight`. - * - * @private - * @param {Function} arrayFunc The function to iterate over an array. - * @param {Function} eachFunc The function to iterate over a collection. - * @returns {Function} Returns the new each function. - */ - function createForEach(arrayFunc, eachFunc) { - return function(collection, iteratee, thisArg) { - return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection)) - ? arrayFunc(collection, iteratee) - : eachFunc(collection, bindCallback(iteratee, thisArg, 3)); - }; - } - - /** - * Creates a function for `_.forIn` or `_.forInRight`. - * - * @private - * @param {Function} objectFunc The function to iterate over an object. - * @returns {Function} Returns the new each function. - */ - function createForIn(objectFunc) { - return function(object, iteratee, thisArg) { - if (typeof iteratee != 'function' || thisArg !== undefined) { - iteratee = bindCallback(iteratee, thisArg, 3); - } - return objectFunc(object, iteratee, keysIn); - }; - } - - /** - * Creates a function for `_.forOwn` or `_.forOwnRight`. - * - * @private - * @param {Function} objectFunc The function to iterate over an object. - * @returns {Function} Returns the new each function. - */ - function createForOwn(objectFunc) { - return function(object, iteratee, thisArg) { - if (typeof iteratee != 'function' || thisArg !== undefined) { - iteratee = bindCallback(iteratee, thisArg, 3); - } - return objectFunc(object, iteratee); - }; - } - - /** - * Creates a function for `_.mapKeys` or `_.mapValues`. - * - * @private - * @param {boolean} [isMapKeys] Specify mapping keys instead of values. - * @returns {Function} Returns the new map function. - */ - function createObjectMapper(isMapKeys) { - return function(object, iteratee, thisArg) { - var result = {}; - iteratee = getCallback(iteratee, thisArg, 3); - - baseForOwn(object, function(value, key, object) { - var mapped = iteratee(value, key, object); - key = isMapKeys ? mapped : key; - value = isMapKeys ? value : mapped; - result[key] = value; - }); - return result; - }; - } - - /** - * Creates a function for `_.padLeft` or `_.padRight`. - * - * @private - * @param {boolean} [fromRight] Specify padding from the right. - * @returns {Function} Returns the new pad function. - */ - function createPadDir(fromRight) { - return function(string, length, chars) { - string = baseToString(string); - return (fromRight ? string : '') + createPadding(string, length, chars) + (fromRight ? '' : string); - }; - } - - /** - * Creates a `_.partial` or `_.partialRight` function. - * - * @private - * @param {boolean} flag The partial bit flag. - * @returns {Function} Returns the new partial function. - */ - function createPartial(flag) { - var partialFunc = restParam(function(func, partials) { - var holders = replaceHolders(partials, partialFunc.placeholder); - return createWrapper(func, flag, undefined, partials, holders); - }); - return partialFunc; - } - - /** - * Creates a function for `_.reduce` or `_.reduceRight`. - * - * @private - * @param {Function} arrayFunc The function to iterate over an array. - * @param {Function} eachFunc The function to iterate over a collection. - * @returns {Function} Returns the new each function. - */ - function createReduce(arrayFunc, eachFunc) { - return function(collection, iteratee, accumulator, thisArg) { - var initFromArray = arguments.length < 3; - return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection)) - ? arrayFunc(collection, iteratee, accumulator, initFromArray) - : baseReduce(collection, getCallback(iteratee, thisArg, 4), accumulator, initFromArray, eachFunc); - }; - } - - /** - * Creates a function that wraps `func` and invokes it with optional `this` - * binding of, partial application, and currying. - * - * @private - * @param {Function|string} func The function or method name to reference. - * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details. - * @param {*} [thisArg] The `this` binding of `func`. - * @param {Array} [partials] The arguments to prepend to those provided to the new function. - * @param {Array} [holders] The `partials` placeholder indexes. - * @param {Array} [partialsRight] The arguments to append to those provided to the new function. - * @param {Array} [holdersRight] The `partialsRight` placeholder indexes. - * @param {Array} [argPos] The argument positions of the new function. - * @param {number} [ary] The arity cap of `func`. - * @param {number} [arity] The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createHybridWrapper(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) { - var isAry = bitmask & ARY_FLAG, - isBind = bitmask & BIND_FLAG, - isBindKey = bitmask & BIND_KEY_FLAG, - isCurry = bitmask & CURRY_FLAG, - isCurryBound = bitmask & CURRY_BOUND_FLAG, - isCurryRight = bitmask & CURRY_RIGHT_FLAG, - Ctor = isBindKey ? undefined : createCtorWrapper(func); - - function wrapper() { - // Avoid `arguments` object use disqualifying optimizations by - // converting it to an array before providing it to other functions. - var length = arguments.length, - index = length, - args = Array(length); - - while (index--) { - args[index] = arguments[index]; - } - if (partials) { - args = composeArgs(args, partials, holders); - } - if (partialsRight) { - args = composeArgsRight(args, partialsRight, holdersRight); - } - if (isCurry || isCurryRight) { - var placeholder = wrapper.placeholder, - argsHolders = replaceHolders(args, placeholder); - - length -= argsHolders.length; - if (length < arity) { - var newArgPos = argPos ? arrayCopy(argPos) : undefined, - newArity = nativeMax(arity - length, 0), - newsHolders = isCurry ? argsHolders : undefined, - newHoldersRight = isCurry ? undefined : argsHolders, - newPartials = isCurry ? args : undefined, - newPartialsRight = isCurry ? undefined : args; - - bitmask |= (isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG); - bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG); - - if (!isCurryBound) { - bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG); - } - var newData = [func, bitmask, thisArg, newPartials, newsHolders, newPartialsRight, newHoldersRight, newArgPos, ary, newArity], - result = createHybridWrapper.apply(undefined, newData); - - if (isLaziable(func)) { - setData(result, newData); - } - result.placeholder = placeholder; - return result; - } - } - var thisBinding = isBind ? thisArg : this, - fn = isBindKey ? thisBinding[func] : func; - - if (argPos) { - args = reorder(args, argPos); - } - if (isAry && ary < args.length) { - args.length = ary; - } - if (this && this !== root && this instanceof wrapper) { - fn = Ctor || createCtorWrapper(func); - } - return fn.apply(thisBinding, args); - } - return wrapper; - } - - /** - * Creates the padding required for `string` based on the given `length`. - * The `chars` string is truncated if the number of characters exceeds `length`. - * - * @private - * @param {string} string The string to create padding for. - * @param {number} [length=0] The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the pad for `string`. - */ - function createPadding(string, length, chars) { - var strLength = string.length; - length = +length; - - if (strLength >= length || !nativeIsFinite(length)) { - return ''; - } - var padLength = length - strLength; - chars = chars == null ? ' ' : (chars + ''); - return repeat(chars, nativeCeil(padLength / chars.length)).slice(0, padLength); - } - - /** - * Creates a function that wraps `func` and invokes it with the optional `this` - * binding of `thisArg` and the `partials` prepended to those provided to - * the wrapper. - * - * @private - * @param {Function} func The function to partially apply arguments to. - * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details. - * @param {*} thisArg The `this` binding of `func`. - * @param {Array} partials The arguments to prepend to those provided to the new function. - * @returns {Function} Returns the new bound function. - */ - function createPartialWrapper(func, bitmask, thisArg, partials) { - var isBind = bitmask & BIND_FLAG, - Ctor = createCtorWrapper(func); - - function wrapper() { - // Avoid `arguments` object use disqualifying optimizations by - // converting it to an array before providing it `func`. - var argsIndex = -1, - argsLength = arguments.length, - leftIndex = -1, - leftLength = partials.length, - args = Array(leftLength + argsLength); - - while (++leftIndex < leftLength) { - args[leftIndex] = partials[leftIndex]; - } - while (argsLength--) { - args[leftIndex++] = arguments[++argsIndex]; - } - var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; - return fn.apply(isBind ? thisArg : this, args); - } - return wrapper; - } - - /** - * Creates a `_.ceil`, `_.floor`, or `_.round` function. - * - * @private - * @param {string} methodName The name of the `Math` method to use when rounding. - * @returns {Function} Returns the new round function. - */ - function createRound(methodName) { - var func = Math[methodName]; - return function(number, precision) { - precision = precision === undefined ? 0 : (+precision || 0); - if (precision) { - precision = pow(10, precision); - return func(number * precision) / precision; - } - return func(number); - }; - } - - /** - * Creates a `_.sortedIndex` or `_.sortedLastIndex` function. - * - * @private - * @param {boolean} [retHighest] Specify returning the highest qualified index. - * @returns {Function} Returns the new index function. - */ - function createSortedIndex(retHighest) { - return function(array, value, iteratee, thisArg) { - var callback = getCallback(iteratee); - return (iteratee == null && callback === baseCallback) - ? binaryIndex(array, value, retHighest) - : binaryIndexBy(array, value, callback(iteratee, thisArg, 1), retHighest); - }; - } - - /** - * Creates a function that either curries or invokes `func` with optional - * `this` binding and partially applied arguments. - * - * @private - * @param {Function|string} func The function or method name to reference. - * @param {number} bitmask The bitmask of flags. - * The bitmask may be composed of the following flags: - * 1 - `_.bind` - * 2 - `_.bindKey` - * 4 - `_.curry` or `_.curryRight` of a bound function - * 8 - `_.curry` - * 16 - `_.curryRight` - * 32 - `_.partial` - * 64 - `_.partialRight` - * 128 - `_.rearg` - * 256 - `_.ary` - * @param {*} [thisArg] The `this` binding of `func`. - * @param {Array} [partials] The arguments to be partially applied. - * @param {Array} [holders] The `partials` placeholder indexes. - * @param {Array} [argPos] The argument positions of the new function. - * @param {number} [ary] The arity cap of `func`. - * @param {number} [arity] The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createWrapper(func, bitmask, thisArg, partials, holders, argPos, ary, arity) { - var isBindKey = bitmask & BIND_KEY_FLAG; - if (!isBindKey && typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - var length = partials ? partials.length : 0; - if (!length) { - bitmask &= ~(PARTIAL_FLAG | PARTIAL_RIGHT_FLAG); - partials = holders = undefined; - } - length -= (holders ? holders.length : 0); - if (bitmask & PARTIAL_RIGHT_FLAG) { - var partialsRight = partials, - holdersRight = holders; - - partials = holders = undefined; - } - var data = isBindKey ? undefined : getData(func), - newData = [func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity]; - - if (data) { - mergeData(newData, data); - bitmask = newData[1]; - arity = newData[9]; - } - newData[9] = arity == null - ? (isBindKey ? 0 : func.length) - : (nativeMax(arity - length, 0) || 0); - - if (bitmask == BIND_FLAG) { - var result = createBindWrapper(newData[0], newData[2]); - } else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !newData[4].length) { - result = createPartialWrapper.apply(undefined, newData); - } else { - result = createHybridWrapper.apply(undefined, newData); - } - var setter = data ? baseSetData : setData; - return setter(result, newData); - } - - /** - * A specialized version of `baseIsEqualDeep` for arrays with support for - * partial deep comparisons. - * - * @private - * @param {Array} array The array to compare. - * @param {Array} other The other array to compare. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} [customizer] The function to customize comparing arrays. - * @param {boolean} [isLoose] Specify performing partial comparisons. - * @param {Array} [stackA] Tracks traversed `value` objects. - * @param {Array} [stackB] Tracks traversed `other` objects. - * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. - */ - function equalArrays(array, other, equalFunc, customizer, isLoose, stackA, stackB) { - var index = -1, - arrLength = array.length, - othLength = other.length; - - if (arrLength != othLength && !(isLoose && othLength > arrLength)) { - return false; - } - // Ignore non-index properties. - while (++index < arrLength) { - var arrValue = array[index], - othValue = other[index], - result = customizer ? customizer(isLoose ? othValue : arrValue, isLoose ? arrValue : othValue, index) : undefined; - - if (result !== undefined) { - if (result) { - continue; - } - return false; - } - // Recursively compare arrays (susceptible to call stack limits). - if (isLoose) { - if (!arraySome(other, function(othValue) { - return arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB); - })) { - return false; - } - } else if (!(arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB))) { - return false; - } - } - return true; - } - - /** - * A specialized version of `baseIsEqualDeep` for comparing objects of - * the same `toStringTag`. - * - * **Note:** This function only supports comparing values with tags of - * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {string} tag The `toStringTag` of the objects to compare. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function equalByTag(object, other, tag) { - switch (tag) { - case boolTag: - case dateTag: - // Coerce dates and booleans to numbers, dates to milliseconds and booleans - // to `1` or `0` treating invalid dates coerced to `NaN` as not equal. - return +object == +other; - - case errorTag: - return object.name == other.name && object.message == other.message; - - case numberTag: - // Treat `NaN` vs. `NaN` as equal. - return (object != +object) - ? other != +other - : object == +other; - - case regexpTag: - case stringTag: - // Coerce regexes to strings and treat strings primitives and string - // objects as equal. See https://es5.github.io/#x15.10.6.4 for more details. - return object == (other + ''); - } - return false; - } - - /** - * A specialized version of `baseIsEqualDeep` for objects with support for - * partial deep comparisons. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} [customizer] The function to customize comparing values. - * @param {boolean} [isLoose] Specify performing partial comparisons. - * @param {Array} [stackA] Tracks traversed `value` objects. - * @param {Array} [stackB] Tracks traversed `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function equalObjects(object, other, equalFunc, customizer, isLoose, stackA, stackB) { - var objProps = keys(object), - objLength = objProps.length, - othProps = keys(other), - othLength = othProps.length; - - if (objLength != othLength && !isLoose) { - return false; - } - var index = objLength; - while (index--) { - var key = objProps[index]; - if (!(isLoose ? key in other : hasOwnProperty.call(other, key))) { - return false; - } - } - var skipCtor = isLoose; - while (++index < objLength) { - key = objProps[index]; - var objValue = object[key], - othValue = other[key], - result = customizer ? customizer(isLoose ? othValue : objValue, isLoose? objValue : othValue, key) : undefined; - - // Recursively compare objects (susceptible to call stack limits). - if (!(result === undefined ? equalFunc(objValue, othValue, customizer, isLoose, stackA, stackB) : result)) { - return false; - } - skipCtor || (skipCtor = key == 'constructor'); - } - if (!skipCtor) { - var objCtor = object.constructor, - othCtor = other.constructor; - - // Non `Object` object instances with different constructors are not equal. - if (objCtor != othCtor && - ('constructor' in object && 'constructor' in other) && - !(typeof objCtor == 'function' && objCtor instanceof objCtor && - typeof othCtor == 'function' && othCtor instanceof othCtor)) { - return false; - } - } - return true; - } - - /** - * Gets the appropriate "callback" function. If the `_.callback` method is - * customized this function returns the custom method, otherwise it returns - * the `baseCallback` function. If arguments are provided the chosen function - * is invoked with them and its result is returned. - * - * @private - * @returns {Function} Returns the chosen function or its result. - */ - function getCallback(func, thisArg, argCount) { - var result = lodash.callback || callback; - result = result === callback ? baseCallback : result; - return argCount ? result(func, thisArg, argCount) : result; - } - - /** - * Gets metadata for `func`. - * - * @private - * @param {Function} func The function to query. - * @returns {*} Returns the metadata for `func`. - */ - var getData = !metaMap ? noop : function(func) { - return metaMap.get(func); - }; - - /** - * Gets the name of `func`. - * - * @private - * @param {Function} func The function to query. - * @returns {string} Returns the function name. - */ - function getFuncName(func) { - var result = (func.name + ''), - array = realNames[result], - length = array ? array.length : 0; - - while (length--) { - var data = array[length], - otherFunc = data.func; - if (otherFunc == null || otherFunc == func) { - return data.name; - } - } - return result; - } - - /** - * Gets the appropriate "indexOf" function. If the `_.indexOf` method is - * customized this function returns the custom method, otherwise it returns - * the `baseIndexOf` function. If arguments are provided the chosen function - * is invoked with them and its result is returned. - * - * @private - * @returns {Function|number} Returns the chosen function or its result. - */ - function getIndexOf(collection, target, fromIndex) { - var result = lodash.indexOf || indexOf; - result = result === indexOf ? baseIndexOf : result; - return collection ? result(collection, target, fromIndex) : result; - } - - /** - * Gets the "length" property value of `object`. - * - * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) - * that affects Safari on at least iOS 8.1-8.3 ARM64. - * - * @private - * @param {Object} object The object to query. - * @returns {*} Returns the "length" value. - */ - var getLength = baseProperty('length'); - - /** - * Gets the propery names, values, and compare flags of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the match data of `object`. - */ - function getMatchData(object) { - var result = pairs(object), - length = result.length; - - while (length--) { - result[length][2] = isStrictComparable(result[length][1]); - } - return result; - } - - /** - * Gets the native function at `key` of `object`. - * - * @private - * @param {Object} object The object to query. - * @param {string} key The key of the method to get. - * @returns {*} Returns the function if it's native, else `undefined`. - */ - function getNative(object, key) { - var value = object == null ? undefined : object[key]; - return isNative(value) ? value : undefined; - } - - /** - * Gets the view, applying any `transforms` to the `start` and `end` positions. - * - * @private - * @param {number} start The start of the view. - * @param {number} end The end of the view. - * @param {Array} transforms The transformations to apply to the view. - * @returns {Object} Returns an object containing the `start` and `end` - * positions of the view. - */ - function getView(start, end, transforms) { - var index = -1, - length = transforms.length; - - while (++index < length) { - var data = transforms[index], - size = data.size; - - switch (data.type) { - case 'drop': start += size; break; - case 'dropRight': end -= size; break; - case 'take': end = nativeMin(end, start + size); break; - case 'takeRight': start = nativeMax(start, end - size); break; - } - } - return { 'start': start, 'end': end }; - } - - /** - * Initializes an array clone. - * - * @private - * @param {Array} array The array to clone. - * @returns {Array} Returns the initialized clone. - */ - function initCloneArray(array) { - var length = array.length, - result = new array.constructor(length); - - // Add array properties assigned by `RegExp#exec`. - if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) { - result.index = array.index; - result.input = array.input; - } - return result; - } - - /** - * Initializes an object clone. - * - * @private - * @param {Object} object The object to clone. - * @returns {Object} Returns the initialized clone. - */ - function initCloneObject(object) { - var Ctor = object.constructor; - if (!(typeof Ctor == 'function' && Ctor instanceof Ctor)) { - Ctor = Object; - } - return new Ctor; - } - - /** - * Initializes an object clone based on its `toStringTag`. - * - * **Note:** This function only supports cloning values with tags of - * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. - * - * @private - * @param {Object} object The object to clone. - * @param {string} tag The `toStringTag` of the object to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the initialized clone. - */ - function initCloneByTag(object, tag, isDeep) { - var Ctor = object.constructor; - switch (tag) { - case arrayBufferTag: - return bufferClone(object); - - case boolTag: - case dateTag: - return new Ctor(+object); - - case float32Tag: case float64Tag: - case int8Tag: case int16Tag: case int32Tag: - case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag: - var buffer = object.buffer; - return new Ctor(isDeep ? bufferClone(buffer) : buffer, object.byteOffset, object.length); - - case numberTag: - case stringTag: - return new Ctor(object); - - case regexpTag: - var result = new Ctor(object.source, reFlags.exec(object)); - result.lastIndex = object.lastIndex; - } - return result; - } - - /** - * Invokes the method at `path` on `object`. - * - * @private - * @param {Object} object The object to query. - * @param {Array|string} path The path of the method to invoke. - * @param {Array} args The arguments to invoke the method with. - * @returns {*} Returns the result of the invoked method. - */ - function invokePath(object, path, args) { - if (object != null && !isKey(path, object)) { - path = toPath(path); - object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); - path = last(path); - } - var func = object == null ? object : object[path]; - return func == null ? undefined : func.apply(object, args); - } - - /** - * Checks if `value` is array-like. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is array-like, else `false`. - */ - function isArrayLike(value) { - return value != null && isLength(getLength(value)); - } - - /** - * Checks if `value` is a valid array-like index. - * - * @private - * @param {*} value The value to check. - * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. - * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. - */ - function isIndex(value, length) { - value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1; - length = length == null ? MAX_SAFE_INTEGER : length; - return value > -1 && value % 1 == 0 && value < length; - } - - /** - * Checks if the provided arguments are from an iteratee call. - * - * @private - * @param {*} value The potential iteratee value argument. - * @param {*} index The potential iteratee index or key argument. - * @param {*} object The potential iteratee object argument. - * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`. - */ - function isIterateeCall(value, index, object) { - if (!isObject(object)) { - return false; - } - var type = typeof index; - if (type == 'number' - ? (isArrayLike(object) && isIndex(index, object.length)) - : (type == 'string' && index in object)) { - var other = object[index]; - return value === value ? (value === other) : (other !== other); - } - return false; - } - - /** - * Checks if `value` is a property name and not a property path. - * - * @private - * @param {*} value The value to check. - * @param {Object} [object] The object to query keys on. - * @returns {boolean} Returns `true` if `value` is a property name, else `false`. - */ - function isKey(value, object) { - var type = typeof value; - if ((type == 'string' && reIsPlainProp.test(value)) || type == 'number') { - return true; - } - if (isArray(value)) { - return false; - } - var result = !reIsDeepProp.test(value); - return result || (object != null && value in toObject(object)); - } - - /** - * Checks if `func` has a lazy counterpart. - * - * @private - * @param {Function} func The function to check. - * @returns {boolean} Returns `true` if `func` has a lazy counterpart, else `false`. - */ - function isLaziable(func) { - var funcName = getFuncName(func), - other = lodash[funcName]; - - if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) { - return false; - } - if (func === other) { - return true; - } - var data = getData(other); - return !!data && func === data[0]; - } - - /** - * Checks if `value` is a valid array-like length. - * - * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. - */ - function isLength(value) { - return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; - } - - /** - * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` if suitable for strict - * equality comparisons, else `false`. - */ - function isStrictComparable(value) { - return value === value && !isObject(value); - } - - /** - * Merges the function metadata of `source` into `data`. - * - * Merging metadata reduces the number of wrappers required to invoke a function. - * This is possible because methods like `_.bind`, `_.curry`, and `_.partial` - * may be applied regardless of execution order. Methods like `_.ary` and `_.rearg` - * augment function arguments, making the order in which they are executed important, - * preventing the merging of metadata. However, we make an exception for a safe - * common case where curried functions have `_.ary` and or `_.rearg` applied. - * - * @private - * @param {Array} data The destination metadata. - * @param {Array} source The source metadata. - * @returns {Array} Returns `data`. - */ - function mergeData(data, source) { - var bitmask = data[1], - srcBitmask = source[1], - newBitmask = bitmask | srcBitmask, - isCommon = newBitmask < ARY_FLAG; - - var isCombo = - (srcBitmask == ARY_FLAG && bitmask == CURRY_FLAG) || - (srcBitmask == ARY_FLAG && bitmask == REARG_FLAG && data[7].length <= source[8]) || - (srcBitmask == (ARY_FLAG | REARG_FLAG) && bitmask == CURRY_FLAG); - - // Exit early if metadata can't be merged. - if (!(isCommon || isCombo)) { - return data; - } - // Use source `thisArg` if available. - if (srcBitmask & BIND_FLAG) { - data[2] = source[2]; - // Set when currying a bound function. - newBitmask |= (bitmask & BIND_FLAG) ? 0 : CURRY_BOUND_FLAG; - } - // Compose partial arguments. - var value = source[3]; - if (value) { - var partials = data[3]; - data[3] = partials ? composeArgs(partials, value, source[4]) : arrayCopy(value); - data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : arrayCopy(source[4]); - } - // Compose partial right arguments. - value = source[5]; - if (value) { - partials = data[5]; - data[5] = partials ? composeArgsRight(partials, value, source[6]) : arrayCopy(value); - data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : arrayCopy(source[6]); - } - // Use source `argPos` if available. - value = source[7]; - if (value) { - data[7] = arrayCopy(value); - } - // Use source `ary` if it's smaller. - if (srcBitmask & ARY_FLAG) { - data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]); - } - // Use source `arity` if one is not provided. - if (data[9] == null) { - data[9] = source[9]; - } - // Use source `func` and merge bitmasks. - data[0] = source[0]; - data[1] = newBitmask; - - return data; - } - - /** - * Used by `_.defaultsDeep` to customize its `_.merge` use. - * - * @private - * @param {*} objectValue The destination object property value. - * @param {*} sourceValue The source object property value. - * @returns {*} Returns the value to assign to the destination object. - */ - function mergeDefaults(objectValue, sourceValue) { - return objectValue === undefined ? sourceValue : merge(objectValue, sourceValue, mergeDefaults); - } - - /** - * A specialized version of `_.pick` which picks `object` properties specified - * by `props`. - * - * @private - * @param {Object} object The source object. - * @param {string[]} props The property names to pick. - * @returns {Object} Returns the new object. - */ - function pickByArray(object, props) { - object = toObject(object); - - var index = -1, - length = props.length, - result = {}; - - while (++index < length) { - var key = props[index]; - if (key in object) { - result[key] = object[key]; - } - } - return result; - } - - /** - * A specialized version of `_.pick` which picks `object` properties `predicate` - * returns truthy for. - * - * @private - * @param {Object} object The source object. - * @param {Function} predicate The function invoked per iteration. - * @returns {Object} Returns the new object. - */ - function pickByCallback(object, predicate) { - var result = {}; - baseForIn(object, function(value, key, object) { - if (predicate(value, key, object)) { - result[key] = value; - } - }); - return result; - } - - /** - * Reorder `array` according to the specified indexes where the element at - * the first index is assigned as the first element, the element at - * the second index is assigned as the second element, and so on. - * - * @private - * @param {Array} array The array to reorder. - * @param {Array} indexes The arranged array indexes. - * @returns {Array} Returns `array`. - */ - function reorder(array, indexes) { - var arrLength = array.length, - length = nativeMin(indexes.length, arrLength), - oldArray = arrayCopy(array); - - while (length--) { - var index = indexes[length]; - array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined; - } - return array; - } - - /** - * Sets metadata for `func`. - * - * **Note:** If this function becomes hot, i.e. is invoked a lot in a short - * period of time, it will trip its breaker and transition to an identity function - * to avoid garbage collection pauses in V8. See [V8 issue 2070](https://code.google.com/p/v8/issues/detail?id=2070) - * for more details. - * - * @private - * @param {Function} func The function to associate metadata with. - * @param {*} data The metadata. - * @returns {Function} Returns `func`. - */ - var setData = (function() { - var count = 0, - lastCalled = 0; - - return function(key, value) { - var stamp = now(), - remaining = HOT_SPAN - (stamp - lastCalled); - - lastCalled = stamp; - if (remaining > 0) { - if (++count >= HOT_COUNT) { - return key; - } - } else { - count = 0; - } - return baseSetData(key, value); - }; - }()); - - /** - * A fallback implementation of `Object.keys` which creates an array of the - * own enumerable property names of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ - function shimKeys(object) { - var props = keysIn(object), - propsLength = props.length, - length = propsLength && object.length; - - var allowIndexes = !!length && isLength(length) && - (isArray(object) || isArguments(object)); - - var index = -1, - result = []; - - while (++index < propsLength) { - var key = props[index]; - if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) { - result.push(key); - } - } - return result; - } - - /** - * Converts `value` to an array-like object if it's not one. - * - * @private - * @param {*} value The value to process. - * @returns {Array|Object} Returns the array-like object. - */ - function toIterable(value) { - if (value == null) { - return []; - } - if (!isArrayLike(value)) { - return values(value); - } - return isObject(value) ? value : Object(value); - } - - /** - * Converts `value` to an object if it's not one. - * - * @private - * @param {*} value The value to process. - * @returns {Object} Returns the object. - */ - function toObject(value) { - return isObject(value) ? value : Object(value); - } - - /** - * Converts `value` to property path array if it's not one. - * - * @private - * @param {*} value The value to process. - * @returns {Array} Returns the property path array. - */ - function toPath(value) { - if (isArray(value)) { - return value; - } - var result = []; - baseToString(value).replace(rePropName, function(match, number, quote, string) { - result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match)); - }); - return result; - } - - /** - * Creates a clone of `wrapper`. - * - * @private - * @param {Object} wrapper The wrapper to clone. - * @returns {Object} Returns the cloned wrapper. - */ - function wrapperClone(wrapper) { - return wrapper instanceof LazyWrapper - ? wrapper.clone() - : new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__, arrayCopy(wrapper.__actions__)); - } - - /*------------------------------------------------------------------------*/ - - /** - * Creates an array of elements split into groups the length of `size`. - * If `collection` can't be split evenly, the final chunk will be the remaining - * elements. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to process. - * @param {number} [size=1] The length of each chunk. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Array} Returns the new array containing chunks. - * @example - * - * _.chunk(['a', 'b', 'c', 'd'], 2); - * // => [['a', 'b'], ['c', 'd']] - * - * _.chunk(['a', 'b', 'c', 'd'], 3); - * // => [['a', 'b', 'c'], ['d']] - */ - function chunk(array, size, guard) { - if (guard ? isIterateeCall(array, size, guard) : size == null) { - size = 1; - } else { - size = nativeMax(nativeFloor(size) || 1, 1); - } - var index = 0, - length = array ? array.length : 0, - resIndex = -1, - result = Array(nativeCeil(length / size)); - - while (index < length) { - result[++resIndex] = baseSlice(array, index, (index += size)); - } - return result; - } - - /** - * Creates an array with all falsey values removed. The values `false`, `null`, - * `0`, `""`, `undefined`, and `NaN` are falsey. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to compact. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * _.compact([0, 1, false, 2, '', 3]); - * // => [1, 2, 3] - */ - function compact(array) { - var index = -1, - length = array ? array.length : 0, - resIndex = -1, - result = []; - - while (++index < length) { - var value = array[index]; - if (value) { - result[++resIndex] = value; - } - } - return result; - } - - /** - * Creates an array of unique `array` values not included in the other - * provided arrays using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) - * for equality comparisons. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to inspect. - * @param {...Array} [values] The arrays of values to exclude. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * _.difference([1, 2, 3], [4, 2]); - * // => [1, 3] - */ - var difference = restParam(function(array, values) { - return (isObjectLike(array) && isArrayLike(array)) - ? baseDifference(array, baseFlatten(values, false, true)) - : []; - }); - - /** - * Creates a slice of `array` with `n` elements dropped from the beginning. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to drop. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.drop([1, 2, 3]); - * // => [2, 3] - * - * _.drop([1, 2, 3], 2); - * // => [3] - * - * _.drop([1, 2, 3], 5); - * // => [] - * - * _.drop([1, 2, 3], 0); - * // => [1, 2, 3] - */ - function drop(array, n, guard) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - if (guard ? isIterateeCall(array, n, guard) : n == null) { - n = 1; - } - return baseSlice(array, n < 0 ? 0 : n); - } - - /** - * Creates a slice of `array` with `n` elements dropped from the end. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to drop. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.dropRight([1, 2, 3]); - * // => [1, 2] - * - * _.dropRight([1, 2, 3], 2); - * // => [1] - * - * _.dropRight([1, 2, 3], 5); - * // => [] - * - * _.dropRight([1, 2, 3], 0); - * // => [1, 2, 3] - */ - function dropRight(array, n, guard) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - if (guard ? isIterateeCall(array, n, guard) : n == null) { - n = 1; - } - n = length - (+n || 0); - return baseSlice(array, 0, n < 0 ? 0 : n); - } - - /** - * Creates a slice of `array` excluding elements dropped from the end. - * Elements are dropped until `predicate` returns falsey. The predicate is - * bound to `thisArg` and invoked with three arguments: (value, index, array). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that match the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.dropRightWhile([1, 2, 3], function(n) { - * return n > 1; - * }); - * // => [1] - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': false } - * ]; - * - * // using the `_.matches` callback shorthand - * _.pluck(_.dropRightWhile(users, { 'user': 'pebbles', 'active': false }), 'user'); - * // => ['barney', 'fred'] - * - * // using the `_.matchesProperty` callback shorthand - * _.pluck(_.dropRightWhile(users, 'active', false), 'user'); - * // => ['barney'] - * - * // using the `_.property` callback shorthand - * _.pluck(_.dropRightWhile(users, 'active'), 'user'); - * // => ['barney', 'fred', 'pebbles'] - */ - function dropRightWhile(array, predicate, thisArg) { - return (array && array.length) - ? baseWhile(array, getCallback(predicate, thisArg, 3), true, true) - : []; - } - - /** - * Creates a slice of `array` excluding elements dropped from the beginning. - * Elements are dropped until `predicate` returns falsey. The predicate is - * bound to `thisArg` and invoked with three arguments: (value, index, array). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.dropWhile([1, 2, 3], function(n) { - * return n < 3; - * }); - * // => [3] - * - * var users = [ - * { 'user': 'barney', 'active': false }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': true } - * ]; - * - * // using the `_.matches` callback shorthand - * _.pluck(_.dropWhile(users, { 'user': 'barney', 'active': false }), 'user'); - * // => ['fred', 'pebbles'] - * - * // using the `_.matchesProperty` callback shorthand - * _.pluck(_.dropWhile(users, 'active', false), 'user'); - * // => ['pebbles'] - * - * // using the `_.property` callback shorthand - * _.pluck(_.dropWhile(users, 'active'), 'user'); - * // => ['barney', 'fred', 'pebbles'] - */ - function dropWhile(array, predicate, thisArg) { - return (array && array.length) - ? baseWhile(array, getCallback(predicate, thisArg, 3), true) - : []; - } - - /** - * Fills elements of `array` with `value` from `start` up to, but not - * including, `end`. - * - * **Note:** This method mutates `array`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to fill. - * @param {*} value The value to fill `array` with. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns `array`. - * @example - * - * var array = [1, 2, 3]; - * - * _.fill(array, 'a'); - * console.log(array); - * // => ['a', 'a', 'a'] - * - * _.fill(Array(3), 2); - * // => [2, 2, 2] - * - * _.fill([4, 6, 8], '*', 1, 2); - * // => [4, '*', 8] - */ - function fill(array, value, start, end) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - if (start && typeof start != 'number' && isIterateeCall(array, value, start)) { - start = 0; - end = length; - } - return baseFill(array, value, start, end); - } - - /** - * This method is like `_.find` except that it returns the index of the first - * element `predicate` returns truthy for instead of the element itself. - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to search. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {number} Returns the index of the found element, else `-1`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': false }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': true } - * ]; - * - * _.findIndex(users, function(chr) { - * return chr.user == 'barney'; - * }); - * // => 0 - * - * // using the `_.matches` callback shorthand - * _.findIndex(users, { 'user': 'fred', 'active': false }); - * // => 1 - * - * // using the `_.matchesProperty` callback shorthand - * _.findIndex(users, 'active', false); - * // => 0 - * - * // using the `_.property` callback shorthand - * _.findIndex(users, 'active'); - * // => 2 - */ - var findIndex = createFindIndex(); - - /** - * This method is like `_.findIndex` except that it iterates over elements - * of `collection` from right to left. - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to search. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {number} Returns the index of the found element, else `-1`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': false } - * ]; - * - * _.findLastIndex(users, function(chr) { - * return chr.user == 'pebbles'; - * }); - * // => 2 - * - * // using the `_.matches` callback shorthand - * _.findLastIndex(users, { 'user': 'barney', 'active': true }); - * // => 0 - * - * // using the `_.matchesProperty` callback shorthand - * _.findLastIndex(users, 'active', false); - * // => 2 - * - * // using the `_.property` callback shorthand - * _.findLastIndex(users, 'active'); - * // => 0 - */ - var findLastIndex = createFindIndex(true); - - /** - * Gets the first element of `array`. - * - * @static - * @memberOf _ - * @alias head - * @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 a nested array. If `isDeep` is `true` the array is recursively - * flattened, otherwise it's only flattened a single level. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to flatten. - * @param {boolean} [isDeep] Specify a deep flatten. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Array} Returns the new flattened array. - * @example - * - * _.flatten([1, [2, 3, [4]]]); - * // => [1, 2, 3, [4]] - * - * // using `isDeep` - * _.flatten([1, [2, 3, [4]]], true); - * // => [1, 2, 3, 4] - */ - function flatten(array, isDeep, guard) { - var length = array ? array.length : 0; - if (guard && isIterateeCall(array, isDeep, guard)) { - isDeep = false; - } - return length ? baseFlatten(array, isDeep) : []; - } - - /** - * Recursively flattens a nested array. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to recursively flatten. - * @returns {Array} Returns the new flattened array. - * @example - * - * _.flattenDeep([1, [2, 3, [4]]]); - * // => [1, 2, 3, 4] - */ - function flattenDeep(array) { - var length = array ? array.length : 0; - return length ? baseFlatten(array, true) : []; - } - - /** - * 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) - * for equality comparisons. If `fromIndex` is negative, it's used as the offset - * from the end of `array`. If `array` is sorted providing `true` for `fromIndex` - * performs a faster binary search. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to search. - * @param {*} value The value to search for. - * @param {boolean|number} [fromIndex=0] The index to search from or `true` - * to perform a binary search on a sorted array. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.indexOf([1, 2, 1, 2], 2); - * // => 1 - * - * // using `fromIndex` - * _.indexOf([1, 2, 1, 2], 2, 2); - * // => 3 - * - * // performing a binary search - * _.indexOf([1, 1, 2, 2], 2, true); - * // => 2 - */ - function indexOf(array, value, fromIndex) { - var length = array ? array.length : 0; - if (!length) { - return -1; - } - if (typeof fromIndex == 'number') { - fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : fromIndex; - } else if (fromIndex) { - var index = binaryIndex(array, value); - if (index < length && - (value === value ? (value === array[index]) : (array[index] !== array[index]))) { - return index; - } - return -1; - } - return baseIndexOf(array, value, fromIndex || 0); - } - - /** - * Gets all but the last element of `array`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.initial([1, 2, 3]); - * // => [1, 2] - */ - function initial(array) { - return dropRight(array, 1); - } - - /** - * Creates an array of unique values that are included in all of the provided - * arrays using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) - * for equality comparisons. - * - * @static - * @memberOf _ - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @returns {Array} Returns the new array of shared values. - * @example - * _.intersection([1, 2], [4, 2], [2, 1]); - * // => [2] - */ - var intersection = restParam(function(arrays) { - var othLength = arrays.length, - othIndex = othLength, - caches = Array(length), - indexOf = getIndexOf(), - isCommon = indexOf === baseIndexOf, - result = []; - - while (othIndex--) { - var value = arrays[othIndex] = isArrayLike(value = arrays[othIndex]) ? value : []; - caches[othIndex] = (isCommon && value.length >= 120) ? createCache(othIndex && value) : null; - } - var array = arrays[0], - index = -1, - length = array ? array.length : 0, - seen = caches[0]; - - outer: - while (++index < length) { - value = array[index]; - if ((seen ? cacheIndexOf(seen, value) : indexOf(result, value, 0)) < 0) { - var othIndex = othLength; - while (--othIndex) { - var cache = caches[othIndex]; - if ((cache ? cacheIndexOf(cache, value) : indexOf(arrays[othIndex], value, 0)) < 0) { - continue outer; - } - } - if (seen) { - seen.push(value); - } - result.push(value); - } - } - return result; - }); - - /** - * Gets the last element of `array`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @returns {*} Returns the last element of `array`. - * @example - * - * _.last([1, 2, 3]); - * // => 3 - */ - function last(array) { - var length = array ? array.length : 0; - return length ? array[length - 1] : undefined; - } - - /** - * This method is like `_.indexOf` except that it iterates over elements of - * `array` from right to left. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to search. - * @param {*} value The value to search for. - * @param {boolean|number} [fromIndex=array.length-1] The index to search from - * or `true` to perform a binary search on a sorted array. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.lastIndexOf([1, 2, 1, 2], 2); - * // => 3 - * - * // using `fromIndex` - * _.lastIndexOf([1, 2, 1, 2], 2, 2); - * // => 1 - * - * // performing a binary search - * _.lastIndexOf([1, 1, 2, 2], 2, true); - * // => 3 - */ - function lastIndexOf(array, value, fromIndex) { - var length = array ? array.length : 0; - if (!length) { - return -1; - } - var index = length; - if (typeof fromIndex == 'number') { - index = (fromIndex < 0 ? nativeMax(length + fromIndex, 0) : nativeMin(fromIndex || 0, length - 1)) + 1; - } else if (fromIndex) { - index = binaryIndex(array, value, true) - 1; - var other = array[index]; - if (value === value ? (value === other) : (other !== other)) { - return index; - } - return -1; - } - if (value !== value) { - return indexOfNaN(array, index, true); - } - while (index--) { - if (array[index] === value) { - return index; - } - } - return -1; - } - - /** - * Removes all provided values from `array` using - * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) - * for equality comparisons. - * - * **Note:** Unlike `_.without`, this method mutates `array`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to modify. - * @param {...*} [values] The values to remove. - * @returns {Array} Returns `array`. - * @example - * - * var array = [1, 2, 3, 1, 2, 3]; - * - * _.pull(array, 2, 3); - * console.log(array); - * // => [1, 1] - */ - function pull() { - var args = arguments, - array = args[0]; - - if (!(array && array.length)) { - return array; - } - var index = 0, - indexOf = getIndexOf(), - length = args.length; - - while (++index < length) { - var fromIndex = 0, - value = args[index]; - - while ((fromIndex = indexOf(array, value, fromIndex)) > -1) { - splice.call(array, fromIndex, 1); - } - } - return array; - } - - /** - * Removes elements from `array` corresponding to the given indexes and returns - * an array of the removed elements. Indexes may be specified as an array of - * indexes or as individual arguments. - * - * **Note:** Unlike `_.at`, this method mutates `array`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to modify. - * @param {...(number|number[])} [indexes] The indexes of elements to remove, - * specified as individual indexes or arrays of indexes. - * @returns {Array} Returns the new array of removed elements. - * @example - * - * var array = [5, 10, 15, 20]; - * var evens = _.pullAt(array, 1, 3); - * - * console.log(array); - * // => [5, 15] - * - * console.log(evens); - * // => [10, 20] - */ - var pullAt = restParam(function(array, indexes) { - indexes = baseFlatten(indexes); - - var result = baseAt(array, indexes); - basePullAt(array, indexes.sort(baseCompareAscending)); - return result; - }); - - /** - * Removes all elements from `array` that `predicate` returns truthy for - * and returns an array of the removed elements. The predicate is bound to - * `thisArg` and invoked with three arguments: (value, index, array). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * **Note:** Unlike `_.filter`, this method mutates `array`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to modify. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Array} Returns the new array of removed elements. - * @example - * - * var array = [1, 2, 3, 4]; - * var evens = _.remove(array, function(n) { - * return n % 2 == 0; - * }); - * - * console.log(array); - * // => [1, 3] - * - * console.log(evens); - * // => [2, 4] - */ - function remove(array, predicate, thisArg) { - var result = []; - if (!(array && array.length)) { - return result; - } - var index = -1, - indexes = [], - length = array.length; - - predicate = getCallback(predicate, thisArg, 3); - while (++index < length) { - var value = array[index]; - if (predicate(value, index, array)) { - result.push(value); - indexes.push(index); - } - } - basePullAt(array, indexes); - return result; - } - - /** - * Gets all but the first element of `array`. - * - * @static - * @memberOf _ - * @alias tail - * @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); - } - - /** - * Creates a slice of `array` from `start` up to, but not including, `end`. - * - * **Note:** This method is used instead of `Array#slice` to support node - * lists in IE < 9 and to ensure dense arrays are returned. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to slice. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns the slice of `array`. - */ - function slice(array, start, end) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - if (end && typeof end != 'number' && isIterateeCall(array, start, end)) { - start = 0; - end = length; - } - return baseSlice(array, start, end); - } - - /** - * Uses a binary search to determine the lowest index at which `value` should - * be inserted into `array` in order to maintain its sort order. If an iteratee - * function is provided it's invoked for `value` and each element of `array` - * to compute their sort ranking. The iteratee is bound to `thisArg` and - * invoked with one argument; (value). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - * @example - * - * _.sortedIndex([30, 50], 40); - * // => 1 - * - * _.sortedIndex([4, 4, 5, 5], 5); - * // => 2 - * - * var dict = { 'data': { 'thirty': 30, 'forty': 40, 'fifty': 50 } }; - * - * // using an iteratee function - * _.sortedIndex(['thirty', 'fifty'], 'forty', function(word) { - * return this.data[word]; - * }, dict); - * // => 1 - * - * // using the `_.property` callback shorthand - * _.sortedIndex([{ 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x'); - * // => 1 - */ - var sortedIndex = createSortedIndex(); - - /** - * This method is like `_.sortedIndex` except that it returns the highest - * index at which `value` should be inserted into `array` in order to - * maintain its sort order. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - * @example - * - * _.sortedLastIndex([4, 4, 5, 5], 5); - * // => 4 - */ - var sortedLastIndex = createSortedIndex(true); - - /** - * Creates a slice of `array` with `n` elements taken from the beginning. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to take. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.take([1, 2, 3]); - * // => [1] - * - * _.take([1, 2, 3], 2); - * // => [1, 2] - * - * _.take([1, 2, 3], 5); - * // => [1, 2, 3] - * - * _.take([1, 2, 3], 0); - * // => [] - */ - function take(array, n, guard) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - if (guard ? isIterateeCall(array, n, guard) : n == null) { - n = 1; - } - return baseSlice(array, 0, n < 0 ? 0 : n); - } - - /** - * Creates a slice of `array` with `n` elements taken from the end. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to take. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.takeRight([1, 2, 3]); - * // => [3] - * - * _.takeRight([1, 2, 3], 2); - * // => [2, 3] - * - * _.takeRight([1, 2, 3], 5); - * // => [1, 2, 3] - * - * _.takeRight([1, 2, 3], 0); - * // => [] - */ - function takeRight(array, n, guard) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - if (guard ? isIterateeCall(array, n, guard) : n == null) { - n = 1; - } - n = length - (+n || 0); - return baseSlice(array, n < 0 ? 0 : n); - } - - /** - * Creates a slice of `array` with elements taken from the end. Elements are - * taken until `predicate` returns falsey. The predicate is bound to `thisArg` - * and invoked with three arguments: (value, index, array). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.takeRightWhile([1, 2, 3], function(n) { - * return n > 1; - * }); - * // => [2, 3] - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': false } - * ]; - * - * // using the `_.matches` callback shorthand - * _.pluck(_.takeRightWhile(users, { 'user': 'pebbles', 'active': false }), 'user'); - * // => ['pebbles'] - * - * // using the `_.matchesProperty` callback shorthand - * _.pluck(_.takeRightWhile(users, 'active', false), 'user'); - * // => ['fred', 'pebbles'] - * - * // using the `_.property` callback shorthand - * _.pluck(_.takeRightWhile(users, 'active'), 'user'); - * // => [] - */ - function takeRightWhile(array, predicate, thisArg) { - return (array && array.length) - ? baseWhile(array, getCallback(predicate, thisArg, 3), false, true) - : []; - } - - /** - * Creates a slice of `array` with elements taken from the beginning. Elements - * are taken until `predicate` returns falsey. The predicate is bound to - * `thisArg` and invoked with three arguments: (value, index, array). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.takeWhile([1, 2, 3], function(n) { - * return n < 3; - * }); - * // => [1, 2] - * - * var users = [ - * { 'user': 'barney', 'active': false }, - * { 'user': 'fred', 'active': false}, - * { 'user': 'pebbles', 'active': true } - * ]; - * - * // using the `_.matches` callback shorthand - * _.pluck(_.takeWhile(users, { 'user': 'barney', 'active': false }), 'user'); - * // => ['barney'] - * - * // using the `_.matchesProperty` callback shorthand - * _.pluck(_.takeWhile(users, 'active', false), 'user'); - * // => ['barney', 'fred'] - * - * // using the `_.property` callback shorthand - * _.pluck(_.takeWhile(users, 'active'), 'user'); - * // => [] - */ - function takeWhile(array, predicate, thisArg) { - return (array && array.length) - ? baseWhile(array, getCallback(predicate, thisArg, 3)) - : []; - } - - /** - * Creates an array of unique values, in order, from all of the provided arrays - * using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) - * for equality comparisons. - * - * @static - * @memberOf _ - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @returns {Array} Returns the new array of combined values. - * @example - * - * _.union([1, 2], [4, 2], [2, 1]); - * // => [1, 2, 4] - */ - var union = restParam(function(arrays) { - return baseUniq(baseFlatten(arrays, false, true)); - }); - - /** - * Creates a duplicate-free version of an array, using - * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) - * for equality comparisons, in which only the first occurence of each element - * is kept. Providing `true` for `isSorted` performs a faster search algorithm - * for sorted arrays. If an iteratee function is provided it's invoked for - * each element in the array to generate the criterion by which uniqueness - * is computed. The `iteratee` is bound to `thisArg` and invoked with three - * arguments: (value, index, array). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @alias unique - * @category Array - * @param {Array} array The array to inspect. - * @param {boolean} [isSorted] Specify the array is sorted. - * @param {Function|Object|string} [iteratee] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Array} Returns the new duplicate-value-free array. - * @example - * - * _.uniq([2, 1, 2]); - * // => [2, 1] - * - * // using `isSorted` - * _.uniq([1, 1, 2], true); - * // => [1, 2] - * - * // using an iteratee function - * _.uniq([1, 2.5, 1.5, 2], function(n) { - * return this.floor(n); - * }, Math); - * // => [1, 2.5] - * - * // using the `_.property` callback shorthand - * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); - * // => [{ 'x': 1 }, { 'x': 2 }] - */ - function uniq(array, isSorted, iteratee, thisArg) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - if (isSorted != null && typeof isSorted != 'boolean') { - thisArg = iteratee; - iteratee = isIterateeCall(array, isSorted, thisArg) ? undefined : isSorted; - isSorted = false; - } - var callback = getCallback(); - if (!(iteratee == null && callback === baseCallback)) { - iteratee = callback(iteratee, thisArg, 3); - } - return (isSorted && getIndexOf() === baseIndexOf) - ? sortedUniq(array, iteratee) - : baseUniq(array, iteratee); - } - - /** - * This method is like `_.zip` except that it accepts an array of grouped - * elements and creates an array regrouping the elements to their pre-zip - * configuration. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array of grouped elements to process. - * @returns {Array} Returns the new array of regrouped elements. - * @example - * - * var zipped = _.zip(['fred', 'barney'], [30, 40], [true, false]); - * // => [['fred', 30, true], ['barney', 40, false]] - * - * _.unzip(zipped); - * // => [['fred', 'barney'], [30, 40], [true, false]] - */ - function unzip(array) { - if (!(array && array.length)) { - return []; - } - var index = -1, - length = 0; - - array = arrayFilter(array, function(group) { - if (isArrayLike(group)) { - length = nativeMax(group.length, length); - return true; - } - }); - var result = Array(length); - while (++index < length) { - result[index] = arrayMap(array, baseProperty(index)); - } - return result; - } - - /** - * This method is like `_.unzip` except that it accepts an iteratee to specify - * how regrouped values should be combined. The `iteratee` is bound to `thisArg` - * and invoked with four arguments: (accumulator, value, index, group). - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array of grouped elements to process. - * @param {Function} [iteratee] The function to combine regrouped values. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Array} Returns the new array of regrouped elements. - * @example - * - * var zipped = _.zip([1, 2], [10, 20], [100, 200]); - * // => [[1, 10, 100], [2, 20, 200]] - * - * _.unzipWith(zipped, _.add); - * // => [3, 30, 300] - */ - function unzipWith(array, iteratee, thisArg) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - var result = unzip(array); - if (iteratee == null) { - return result; - } - iteratee = bindCallback(iteratee, thisArg, 4); - return arrayMap(result, function(group) { - return arrayReduce(group, iteratee, undefined, true); - }); - } - - /** - * Creates an array excluding all provided values using - * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) - * for equality comparisons. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to filter. - * @param {...*} [values] The values to exclude. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * _.without([1, 2, 1, 3], 1, 2); - * // => [3] - */ - var without = restParam(function(array, values) { - return isArrayLike(array) - ? baseDifference(array, values) - : []; - }); - - /** - * Creates an array of unique values that is the [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference) - * of the provided arrays. - * - * @static - * @memberOf _ - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @returns {Array} Returns the new array of values. - * @example - * - * _.xor([1, 2], [4, 2]); - * // => [1, 4] - */ - function xor() { - var index = -1, - length = arguments.length; - - while (++index < length) { - var array = arguments[index]; - if (isArrayLike(array)) { - var result = result - ? arrayPush(baseDifference(result, array), baseDifference(array, result)) - : array; - } - } - return result ? baseUniq(result) : []; - } - - /** - * Creates an array of grouped elements, the first of which contains the first - * elements of the given arrays, the second of which contains the second elements - * of the given arrays, and so on. - * - * @static - * @memberOf _ - * @category Array - * @param {...Array} [arrays] The arrays to process. - * @returns {Array} Returns the new array of grouped elements. - * @example - * - * _.zip(['fred', 'barney'], [30, 40], [true, false]); - * // => [['fred', 30, true], ['barney', 40, false]] - */ - var zip = restParam(unzip); - - /** - * The inverse of `_.pairs`; this method returns an object composed from arrays - * of property names and values. Provide either a single two dimensional array, - * e.g. `[[key1, value1], [key2, value2]]` or two arrays, one of property names - * and one of corresponding values. - * - * @static - * @memberOf _ - * @alias object - * @category Array - * @param {Array} props The property names. - * @param {Array} [values=[]] The property values. - * @returns {Object} Returns the new object. - * @example - * - * _.zipObject([['fred', 30], ['barney', 40]]); - * // => { 'fred': 30, 'barney': 40 } - * - * _.zipObject(['fred', 'barney'], [30, 40]); - * // => { 'fred': 30, 'barney': 40 } - */ - function zipObject(props, values) { - var index = -1, - length = props ? props.length : 0, - result = {}; - - if (length && !values && !isArray(props[0])) { - values = []; - } - while (++index < length) { - var key = props[index]; - if (values) { - result[key] = values[index]; - } else if (key) { - result[key[0]] = key[1]; - } - } - return result; - } - - /** - * This method is like `_.zip` except that it accepts an iteratee to specify - * how grouped values should be combined. The `iteratee` is bound to `thisArg` - * and invoked with four arguments: (accumulator, value, index, group). - * - * @static - * @memberOf _ - * @category Array - * @param {...Array} [arrays] The arrays to process. - * @param {Function} [iteratee] The function to combine grouped values. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Array} Returns the new array of grouped elements. - * @example - * - * _.zipWith([1, 2], [10, 20], [100, 200], _.add); - * // => [111, 222] - */ - var zipWith = restParam(function(arrays) { - var length = arrays.length, - iteratee = length > 2 ? arrays[length - 2] : undefined, - thisArg = length > 1 ? arrays[length - 1] : undefined; - - if (length > 2 && typeof iteratee == 'function') { - length -= 2; - } else { - iteratee = (length > 1 && typeof thisArg == 'function') ? (--length, thisArg) : undefined; - thisArg = undefined; - } - arrays.length = length; - return unzipWith(arrays, iteratee, thisArg); - }); - - /*------------------------------------------------------------------------*/ - - /** - * Creates a `lodash` object that wraps `value` with explicit method - * chaining enabled. - * - * @static - * @memberOf _ - * @category Chain - * @param {*} value The value to wrap. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 }, - * { 'user': 'pebbles', 'age': 1 } - * ]; - * - * var youngest = _.chain(users) - * .sortBy('age') - * .map(function(chr) { - * return chr.user + ' is ' + chr.age; - * }) - * .first() - * .value(); - * // => 'pebbles is 1' - */ - function chain(value) { - var result = lodash(value); - result.__chain__ = true; - return result; - } - - /** - * This method invokes `interceptor` and returns `value`. The interceptor is - * bound to `thisArg` and invoked with one argument; (value). The purpose of - * this method is to "tap into" a method chain in order to perform operations - * on intermediate results within the chain. - * - * @static - * @memberOf _ - * @category Chain - * @param {*} value The value to provide to `interceptor`. - * @param {Function} interceptor The function to invoke. - * @param {*} [thisArg] The `this` binding of `interceptor`. - * @returns {*} Returns `value`. - * @example - * - * _([1, 2, 3]) - * .tap(function(array) { - * array.pop(); - * }) - * .reverse() - * .value(); - * // => [2, 1] - */ - function tap(value, interceptor, thisArg) { - interceptor.call(thisArg, value); - return value; - } - - /** - * This method is like `_.tap` except that it returns the result of `interceptor`. - * - * @static - * @memberOf _ - * @category Chain - * @param {*} value The value to provide to `interceptor`. - * @param {Function} interceptor The function to invoke. - * @param {*} [thisArg] The `this` binding of `interceptor`. - * @returns {*} Returns the result of `interceptor`. - * @example - * - * _(' abc ') - * .chain() - * .trim() - * .thru(function(value) { - * return [value]; - * }) - * .value(); - * // => ['abc'] - */ - function thru(value, interceptor, thisArg) { - return interceptor.call(thisArg, value); - } - - /** - * Enables explicit method chaining on the wrapper object. - * - * @name chain - * @memberOf _ - * @category Chain - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 } - * ]; - * - * // without explicit chaining - * _(users).first(); - * // => { 'user': 'barney', 'age': 36 } - * - * // with explicit chaining - * _(users).chain() - * .first() - * .pick('user') - * .value(); - * // => { 'user': 'barney' } - */ - function wrapperChain() { - return chain(this); - } - - /** - * Executes the chained sequence and returns the wrapped result. - * - * @name commit - * @memberOf _ - * @category Chain - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var array = [1, 2]; - * var wrapped = _(array).push(3); - * - * console.log(array); - * // => [1, 2] - * - * wrapped = wrapped.commit(); - * console.log(array); - * // => [1, 2, 3] - * - * wrapped.last(); - * // => 3 - * - * console.log(array); - * // => [1, 2, 3] - */ - function wrapperCommit() { - return new LodashWrapper(this.value(), this.__chain__); - } - - /** - * Creates a new array joining a wrapped array with any additional arrays - * and/or values. - * - * @name concat - * @memberOf _ - * @category Chain - * @param {...*} [values] The values to concatenate. - * @returns {Array} Returns the new concatenated array. - * @example - * - * var array = [1]; - * var wrapped = _(array).concat(2, [3], [[4]]); - * - * console.log(wrapped.value()); - * // => [1, 2, 3, [4]] - * - * console.log(array); - * // => [1] - */ - var wrapperConcat = restParam(function(values) { - values = baseFlatten(values); - return this.thru(function(array) { - return arrayConcat(isArray(array) ? array : [toObject(array)], values); - }); - }); - - /** - * Creates a clone of the chained sequence planting `value` as the wrapped value. - * - * @name plant - * @memberOf _ - * @category Chain - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var array = [1, 2]; - * var wrapped = _(array).map(function(value) { - * return Math.pow(value, 2); - * }); - * - * var other = [3, 4]; - * var otherWrapped = wrapped.plant(other); - * - * otherWrapped.value(); - * // => [9, 16] - * - * wrapped.value(); - * // => [1, 4] - */ - function wrapperPlant(value) { - var result, - parent = this; - - while (parent instanceof baseLodash) { - var clone = wrapperClone(parent); - if (result) { - previous.__wrapped__ = clone; - } else { - result = clone; - } - var previous = clone; - parent = parent.__wrapped__; - } - previous.__wrapped__ = value; - return result; - } - - /** - * Reverses the wrapped array so the first element becomes the last, the - * second element becomes the second to last, and so on. - * - * **Note:** This method mutates the wrapped array. - * - * @name reverse - * @memberOf _ - * @category Chain - * @returns {Object} Returns the new reversed `lodash` wrapper instance. - * @example - * - * var array = [1, 2, 3]; - * - * _(array).reverse().value() - * // => [3, 2, 1] - * - * console.log(array); - * // => [3, 2, 1] - */ - function wrapperReverse() { - var value = this.__wrapped__; - - var interceptor = function(value) { - return value.reverse(); - }; - if (value instanceof LazyWrapper) { - var wrapped = value; - if (this.__actions__.length) { - wrapped = new LazyWrapper(this); - } - wrapped = wrapped.reverse(); - wrapped.__actions__.push({ 'func': thru, 'args': [interceptor], 'thisArg': undefined }); - return new LodashWrapper(wrapped, this.__chain__); - } - return this.thru(interceptor); - } - - /** - * Produces the result of coercing the unwrapped value to a string. - * - * @name toString - * @memberOf _ - * @category Chain - * @returns {string} Returns the coerced string value. - * @example - * - * _([1, 2, 3]).toString(); - * // => '1,2,3' - */ - function wrapperToString() { - return (this.value() + ''); - } - - /** - * Executes the chained sequence to extract the unwrapped value. - * - * @name value - * @memberOf _ - * @alias run, toJSON, valueOf - * @category Chain - * @returns {*} Returns the resolved unwrapped value. - * @example - * - * _([1, 2, 3]).value(); - * // => [1, 2, 3] - */ - function wrapperValue() { - return baseWrapperValue(this.__wrapped__, this.__actions__); - } - - /*------------------------------------------------------------------------*/ - - /** - * Creates an array of elements corresponding to the given keys, or indexes, - * of `collection`. Keys may be specified as individual arguments or as arrays - * of keys. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {...(number|number[]|string|string[])} [props] The property names - * or indexes of elements to pick, specified individually or in arrays. - * @returns {Array} Returns the new array of picked elements. - * @example - * - * _.at(['a', 'b', 'c'], [0, 2]); - * // => ['a', 'c'] - * - * _.at(['barney', 'fred', 'pebbles'], 0, 2); - * // => ['barney', 'pebbles'] - */ - var at = restParam(function(collection, props) { - return baseAt(collection, baseFlatten(props)); - }); - - /** - * Creates an object composed of keys generated from the results of running - * each element of `collection` through `iteratee`. The corresponding value - * of each key is the number of times the key was returned by `iteratee`. - * The `iteratee` is bound to `thisArg` and invoked with three arguments: - * (value, index|key, collection). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns the composed aggregate object. - * @example - * - * _.countBy([4.3, 6.1, 6.4], function(n) { - * return Math.floor(n); - * }); - * // => { '4': 1, '6': 2 } - * - * _.countBy([4.3, 6.1, 6.4], function(n) { - * return this.floor(n); - * }, Math); - * // => { '4': 1, '6': 2 } - * - * _.countBy(['one', 'two', 'three'], 'length'); - * // => { '3': 2, '5': 1 } - */ - var countBy = createAggregator(function(result, value, key) { - hasOwnProperty.call(result, key) ? ++result[key] : (result[key] = 1); - }); - - /** - * Checks if `predicate` returns truthy for **all** elements of `collection`. - * The predicate is bound to `thisArg` and invoked with three arguments: - * (value, index|key, collection). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @alias all - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {boolean} Returns `true` if all elements pass the predicate check, - * else `false`. - * @example - * - * _.every([true, 1, null, 'yes'], Boolean); - * // => false - * - * var users = [ - * { 'user': 'barney', 'active': false }, - * { 'user': 'fred', 'active': false } - * ]; - * - * // using the `_.matches` callback shorthand - * _.every(users, { 'user': 'barney', 'active': false }); - * // => false - * - * // using the `_.matchesProperty` callback shorthand - * _.every(users, 'active', false); - * // => true - * - * // using the `_.property` callback shorthand - * _.every(users, 'active'); - * // => false - */ - function every(collection, predicate, thisArg) { - var func = isArray(collection) ? arrayEvery : baseEvery; - if (thisArg && isIterateeCall(collection, predicate, thisArg)) { - predicate = undefined; - } - if (typeof predicate != 'function' || thisArg !== undefined) { - predicate = getCallback(predicate, thisArg, 3); - } - return func(collection, predicate); - } - - /** - * Iterates over elements of `collection`, returning an array of all elements - * `predicate` returns truthy for. The predicate is bound to `thisArg` and - * invoked with three arguments: (value, index|key, collection). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @alias select - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Array} Returns the new filtered array. - * @example - * - * _.filter([4, 5, 6], function(n) { - * return n % 2 == 0; - * }); - * // => [4, 6] - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': true }, - * { 'user': 'fred', 'age': 40, 'active': false } - * ]; - * - * // using the `_.matches` callback shorthand - * _.pluck(_.filter(users, { 'age': 36, 'active': true }), 'user'); - * // => ['barney'] - * - * // using the `_.matchesProperty` callback shorthand - * _.pluck(_.filter(users, 'active', false), 'user'); - * // => ['fred'] - * - * // using the `_.property` callback shorthand - * _.pluck(_.filter(users, 'active'), 'user'); - * // => ['barney'] - */ - function filter(collection, predicate, thisArg) { - var func = isArray(collection) ? arrayFilter : baseFilter; - predicate = getCallback(predicate, thisArg, 3); - return func(collection, predicate); - } - - /** - * Iterates over elements of `collection`, returning the first element - * `predicate` returns truthy for. The predicate is bound to `thisArg` and - * invoked with three arguments: (value, index|key, collection). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @alias detect - * @category Collection - * @param {Array|Object|string} collection The collection to search. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {*} Returns the matched element, else `undefined`. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': true }, - * { 'user': 'fred', 'age': 40, 'active': false }, - * { 'user': 'pebbles', 'age': 1, 'active': true } - * ]; - * - * _.result(_.find(users, function(chr) { - * return chr.age < 40; - * }), 'user'); - * // => 'barney' - * - * // using the `_.matches` callback shorthand - * _.result(_.find(users, { 'age': 1, 'active': true }), 'user'); - * // => 'pebbles' - * - * // using the `_.matchesProperty` callback shorthand - * _.result(_.find(users, 'active', false), 'user'); - * // => 'fred' - * - * // using the `_.property` callback shorthand - * _.result(_.find(users, 'active'), 'user'); - * // => 'barney' - */ - var find = createFind(baseEach); - - /** - * This method is like `_.find` except that it iterates over elements of - * `collection` from right to left. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to search. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {*} Returns the matched element, else `undefined`. - * @example - * - * _.findLast([1, 2, 3, 4], function(n) { - * return n % 2 == 1; - * }); - * // => 3 - */ - var findLast = createFind(baseEachRight, true); - - /** - * Performs a deep comparison between each element in `collection` and the - * source object, returning the first element that has equivalent property - * values. - * - * **Note:** This method supports comparing arrays, booleans, `Date` objects, - * numbers, `Object` objects, regexes, and strings. Objects are compared by - * their own, not inherited, enumerable properties. For comparing a single - * own or inherited property value see `_.matchesProperty`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to search. - * @param {Object} source The object of property values to match. - * @returns {*} Returns the matched element, else `undefined`. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': true }, - * { 'user': 'fred', 'age': 40, 'active': false } - * ]; - * - * _.result(_.findWhere(users, { 'age': 36, 'active': true }), 'user'); - * // => 'barney' - * - * _.result(_.findWhere(users, { 'age': 40, 'active': false }), 'user'); - * // => 'fred' - */ - function findWhere(collection, source) { - return find(collection, baseMatches(source)); - } - - /** - * Iterates over elements of `collection` invoking `iteratee` for each element. - * The `iteratee` is bound to `thisArg` and invoked with three arguments: - * (value, index|key, collection). Iteratee functions may exit iteration early - * by explicitly returning `false`. - * - * **Note:** As with other "Collections" methods, objects with a "length" property - * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn` - * may be used for object iteration. - * - * @static - * @memberOf _ - * @alias each - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Array|Object|string} Returns `collection`. - * @example - * - * _([1, 2]).forEach(function(n) { - * console.log(n); - * }).value(); - * // => logs each value from left to right and returns the array - * - * _.forEach({ 'a': 1, 'b': 2 }, function(n, key) { - * console.log(n, key); - * }); - * // => logs each value-key pair and returns the object (iteration order is not guaranteed) - */ - var forEach = createForEach(arrayEach, baseEach); - - /** - * This method is like `_.forEach` except that it iterates over elements of - * `collection` from right to left. - * - * @static - * @memberOf _ - * @alias eachRight - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Array|Object|string} Returns `collection`. - * @example - * - * _([1, 2]).forEachRight(function(n) { - * console.log(n); - * }).value(); - * // => logs each value from right to left and returns the array - */ - var forEachRight = createForEach(arrayEachRight, baseEachRight); - - /** - * Creates an object composed of keys generated from the results of running - * each element of `collection` through `iteratee`. The corresponding value - * of each key is an array of the elements responsible for generating the key. - * The `iteratee` is bound to `thisArg` and invoked with three arguments: - * (value, index|key, collection). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns the composed aggregate object. - * @example - * - * _.groupBy([4.2, 6.1, 6.4], function(n) { - * return Math.floor(n); - * }); - * // => { '4': [4.2], '6': [6.1, 6.4] } - * - * _.groupBy([4.2, 6.1, 6.4], function(n) { - * return this.floor(n); - * }, Math); - * // => { '4': [4.2], '6': [6.1, 6.4] } - * - * // using the `_.property` callback shorthand - * _.groupBy(['one', 'two', 'three'], 'length'); - * // => { '3': ['one', 'two'], '5': ['three'] } - */ - var groupBy = createAggregator(function(result, value, key) { - if (hasOwnProperty.call(result, key)) { - result[key].push(value); - } else { - result[key] = [value]; - } - }); - - /** - * Checks if `target` is in `collection` using - * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) - * for equality comparisons. If `fromIndex` is negative, it's used as the offset - * from the end of `collection`. - * - * @static - * @memberOf _ - * @alias contains, include - * @category Collection - * @param {Array|Object|string} collection The collection to search. - * @param {*} target The value to search for. - * @param {number} [fromIndex=0] The index to search from. - * @param- {Object} [guard] Enables use as a callback for functions like `_.reduce`. - * @returns {boolean} Returns `true` if a matching element is found, else `false`. - * @example - * - * _.includes([1, 2, 3], 1); - * // => true - * - * _.includes([1, 2, 3], 1, 2); - * // => false - * - * _.includes({ 'user': 'fred', 'age': 40 }, 'fred'); - * // => true - * - * _.includes('pebbles', 'eb'); - * // => true - */ - function includes(collection, target, fromIndex, guard) { - var length = collection ? getLength(collection) : 0; - if (!isLength(length)) { - collection = values(collection); - length = collection.length; - } - if (typeof fromIndex != 'number' || (guard && isIterateeCall(target, fromIndex, guard))) { - fromIndex = 0; - } else { - fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0); - } - return (typeof collection == 'string' || !isArray(collection) && isString(collection)) - ? (fromIndex <= length && collection.indexOf(target, fromIndex) > -1) - : (!!length && getIndexOf(collection, target, fromIndex) > -1); - } - - /** - * Creates an object composed of keys generated from the results of running - * each element of `collection` through `iteratee`. The corresponding value - * of each key is the last element responsible for generating the key. The - * iteratee function is bound to `thisArg` and invoked with three arguments: - * (value, index|key, collection). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns the composed aggregate object. - * @example - * - * var keyData = [ - * { 'dir': 'left', 'code': 97 }, - * { 'dir': 'right', 'code': 100 } - * ]; - * - * _.indexBy(keyData, 'dir'); - * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } } - * - * _.indexBy(keyData, function(object) { - * return String.fromCharCode(object.code); - * }); - * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } - * - * _.indexBy(keyData, function(object) { - * return this.fromCharCode(object.code); - * }, String); - * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } - */ - var indexBy = createAggregator(function(result, value, key) { - result[key] = value; - }); - - /** - * Invokes the method at `path` of each element in `collection`, returning - * an array of the results of each invoked method. Any additional arguments - * are provided to each invoked method. If `methodName` is a function it's - * invoked for, and `this` bound to, each element in `collection`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Array|Function|string} path The path of the method to invoke or - * the function invoked per iteration. - * @param {...*} [args] The arguments to invoke the method with. - * @returns {Array} Returns the array of results. - * @example - * - * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort'); - * // => [[1, 5, 7], [1, 2, 3]] - * - * _.invoke([123, 456], String.prototype.split, ''); - * // => [['1', '2', '3'], ['4', '5', '6']] - */ - var invoke = restParam(function(collection, path, args) { - var index = -1, - isFunc = typeof path == 'function', - isProp = isKey(path), - result = isArrayLike(collection) ? Array(collection.length) : []; - - baseEach(collection, function(value) { - var func = isFunc ? path : ((isProp && value != null) ? value[path] : undefined); - result[++index] = func ? func.apply(value, args) : invokePath(value, path, args); - }); - return result; - }); - - /** - * Creates an array of values by running each element in `collection` through - * `iteratee`. The `iteratee` is bound to `thisArg` and invoked with three - * arguments: (value, index|key, collection). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * Many lodash methods are guarded to work as iteratees for methods like - * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`. - * - * The guarded methods are: - * `ary`, `callback`, `chunk`, `clone`, `create`, `curry`, `curryRight`, - * `drop`, `dropRight`, `every`, `fill`, `flatten`, `invert`, `max`, `min`, - * `parseInt`, `slice`, `sortBy`, `take`, `takeRight`, `template`, `trim`, - * `trimLeft`, `trimRight`, `trunc`, `random`, `range`, `sample`, `some`, - * `sum`, `uniq`, and `words` - * - * @static - * @memberOf _ - * @alias collect - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Array} Returns the new mapped array. - * @example - * - * function timesThree(n) { - * return n * 3; - * } - * - * _.map([1, 2], timesThree); - * // => [3, 6] - * - * _.map({ 'a': 1, 'b': 2 }, timesThree); - * // => [3, 6] (iteration order is not guaranteed) - * - * var users = [ - * { 'user': 'barney' }, - * { 'user': 'fred' } - * ]; - * - * // using the `_.property` callback shorthand - * _.map(users, 'user'); - * // => ['barney', 'fred'] - */ - function map(collection, iteratee, thisArg) { - var func = isArray(collection) ? arrayMap : baseMap; - iteratee = getCallback(iteratee, thisArg, 3); - return func(collection, iteratee); - } - - /** - * Creates an array of elements split into two groups, the first of which - * contains elements `predicate` returns truthy for, while the second of which - * contains elements `predicate` returns falsey for. The predicate is bound - * to `thisArg` and invoked with three arguments: (value, index|key, collection). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Array} Returns the array of grouped elements. - * @example - * - * _.partition([1, 2, 3], function(n) { - * return n % 2; - * }); - * // => [[1, 3], [2]] - * - * _.partition([1.2, 2.3, 3.4], function(n) { - * return this.floor(n) % 2; - * }, Math); - * // => [[1.2, 3.4], [2.3]] - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': false }, - * { 'user': 'fred', 'age': 40, 'active': true }, - * { 'user': 'pebbles', 'age': 1, 'active': false } - * ]; - * - * var mapper = function(array) { - * return _.pluck(array, 'user'); - * }; - * - * // using the `_.matches` callback shorthand - * _.map(_.partition(users, { 'age': 1, 'active': false }), mapper); - * // => [['pebbles'], ['barney', 'fred']] - * - * // using the `_.matchesProperty` callback shorthand - * _.map(_.partition(users, 'active', false), mapper); - * // => [['barney', 'pebbles'], ['fred']] - * - * // using the `_.property` callback shorthand - * _.map(_.partition(users, 'active'), mapper); - * // => [['fred'], ['barney', 'pebbles']] - */ - var partition = createAggregator(function(result, value, key) { - result[key ? 0 : 1].push(value); - }, function() { return [[], []]; }); - - /** - * Gets the property value of `path` from all elements in `collection`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Array|string} path The path of the property to pluck. - * @returns {Array} Returns the property values. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 } - * ]; - * - * _.pluck(users, 'user'); - * // => ['barney', 'fred'] - * - * var userIndex = _.indexBy(users, 'user'); - * _.pluck(userIndex, 'age'); - * // => [36, 40] (iteration order is not guaranteed) - */ - function pluck(collection, path) { - return map(collection, property(path)); - } - - /** - * Reduces `collection` to a value which is the accumulated result of running - * each element in `collection` through `iteratee`, where each successive - * invocation is supplied the return value of the previous. If `accumulator` - * is not provided the first element of `collection` is used as the initial - * value. The `iteratee` is bound to `thisArg` and invoked with four arguments: - * (accumulator, value, index|key, collection). - * - * Many lodash methods are guarded to work as iteratees for methods like - * `_.reduce`, `_.reduceRight`, and `_.transform`. - * - * The guarded methods are: - * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `sortByAll`, - * and `sortByOrder` - * - * @static - * @memberOf _ - * @alias foldl, inject - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {*} Returns the accumulated value. - * @example - * - * _.reduce([1, 2], function(total, n) { - * return total + n; - * }); - * // => 3 - * - * _.reduce({ 'a': 1, 'b': 2 }, function(result, n, key) { - * result[key] = n * 3; - * return result; - * }, {}); - * // => { 'a': 3, 'b': 6 } (iteration order is not guaranteed) - */ - var reduce = createReduce(arrayReduce, baseEach); - - /** - * This method is like `_.reduce` except that it iterates over elements of - * `collection` from right to left. - * - * @static - * @memberOf _ - * @alias foldr - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {*} Returns the accumulated value. - * @example - * - * var array = [[0, 1], [2, 3], [4, 5]]; - * - * _.reduceRight(array, function(flattened, other) { - * return flattened.concat(other); - * }, []); - * // => [4, 5, 2, 3, 0, 1] - */ - var reduceRight = createReduce(arrayReduceRight, baseEachRight); - - /** - * The opposite of `_.filter`; this method returns the elements of `collection` - * that `predicate` does **not** return truthy for. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Array} Returns the new filtered array. - * @example - * - * _.reject([1, 2, 3, 4], function(n) { - * return n % 2 == 0; - * }); - * // => [1, 3] - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': false }, - * { 'user': 'fred', 'age': 40, 'active': true } - * ]; - * - * // using the `_.matches` callback shorthand - * _.pluck(_.reject(users, { 'age': 40, 'active': true }), 'user'); - * // => ['barney'] - * - * // using the `_.matchesProperty` callback shorthand - * _.pluck(_.reject(users, 'active', false), 'user'); - * // => ['fred'] - * - * // using the `_.property` callback shorthand - * _.pluck(_.reject(users, 'active'), 'user'); - * // => ['barney'] - */ - function reject(collection, predicate, thisArg) { - var func = isArray(collection) ? arrayFilter : baseFilter; - predicate = getCallback(predicate, thisArg, 3); - return func(collection, function(value, index, collection) { - return !predicate(value, index, collection); - }); - } - - /** - * Gets a random element or `n` random elements from a collection. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to sample. - * @param {number} [n] The number of elements to sample. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {*} Returns the random sample(s). - * @example - * - * _.sample([1, 2, 3, 4]); - * // => 2 - * - * _.sample([1, 2, 3, 4], 2); - * // => [3, 1] - */ - function sample(collection, n, guard) { - if (guard ? isIterateeCall(collection, n, guard) : n == null) { - collection = toIterable(collection); - var length = collection.length; - return length > 0 ? collection[baseRandom(0, length - 1)] : undefined; - } - var index = -1, - result = toArray(collection), - length = result.length, - lastIndex = length - 1; - - n = nativeMin(n < 0 ? 0 : (+n || 0), length); - while (++index < n) { - var rand = baseRandom(index, lastIndex), - value = result[rand]; - - result[rand] = result[index]; - result[index] = value; - } - result.length = n; - return result; - } - - /** - * Creates an array of shuffled values, using a version of the - * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle). - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to shuffle. - * @returns {Array} Returns the new shuffled array. - * @example - * - * _.shuffle([1, 2, 3, 4]); - * // => [4, 1, 3, 2] - */ - function shuffle(collection) { - return sample(collection, POSITIVE_INFINITY); - } - - /** - * Gets the size of `collection` by returning its length for array-like - * values or the number of own enumerable properties for objects. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to inspect. - * @returns {number} Returns the size of `collection`. - * @example - * - * _.size([1, 2, 3]); - * // => 3 - * - * _.size({ 'a': 1, 'b': 2 }); - * // => 2 - * - * _.size('pebbles'); - * // => 7 - */ - function size(collection) { - var length = collection ? getLength(collection) : 0; - return isLength(length) ? length : keys(collection).length; - } - - /** - * Checks if `predicate` returns truthy for **any** element of `collection`. - * The function returns as soon as it finds a passing value and does not iterate - * over the entire collection. The predicate is bound to `thisArg` and invoked - * with three arguments: (value, index|key, collection). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @alias any - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. - * @example - * - * _.some([null, 0, 'yes', false], Boolean); - * // => true - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false } - * ]; - * - * // using the `_.matches` callback shorthand - * _.some(users, { 'user': 'barney', 'active': false }); - * // => false - * - * // using the `_.matchesProperty` callback shorthand - * _.some(users, 'active', false); - * // => true - * - * // using the `_.property` callback shorthand - * _.some(users, 'active'); - * // => true - */ - function some(collection, predicate, thisArg) { - var func = isArray(collection) ? arraySome : baseSome; - if (thisArg && isIterateeCall(collection, predicate, thisArg)) { - predicate = undefined; - } - if (typeof predicate != 'function' || thisArg !== undefined) { - predicate = getCallback(predicate, thisArg, 3); - } - return func(collection, predicate); - } - - /** - * Creates an array of elements, sorted in ascending order by the results of - * running each element in a collection through `iteratee`. This method performs - * a stable sort, that is, it preserves the original sort order of equal elements. - * The `iteratee` is bound to `thisArg` and invoked with three arguments: - * (value, index|key, collection). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Array} Returns the new sorted array. - * @example - * - * _.sortBy([1, 2, 3], function(n) { - * return Math.sin(n); - * }); - * // => [3, 1, 2] - * - * _.sortBy([1, 2, 3], function(n) { - * return this.sin(n); - * }, Math); - * // => [3, 1, 2] - * - * var users = [ - * { 'user': 'fred' }, - * { 'user': 'pebbles' }, - * { 'user': 'barney' } - * ]; - * - * // using the `_.property` callback shorthand - * _.pluck(_.sortBy(users, 'user'), 'user'); - * // => ['barney', 'fred', 'pebbles'] - */ - function sortBy(collection, iteratee, thisArg) { - if (collection == null) { - return []; - } - if (thisArg && isIterateeCall(collection, iteratee, thisArg)) { - iteratee = undefined; - } - var index = -1; - iteratee = getCallback(iteratee, thisArg, 3); - - var result = baseMap(collection, function(value, key, collection) { - return { 'criteria': iteratee(value, key, collection), 'index': ++index, 'value': value }; - }); - return baseSortBy(result, compareAscending); - } - - /** - * This method is like `_.sortBy` except that it can sort by multiple iteratees - * or property names. - * - * If a property name is provided for an iteratee the created `_.property` - * style callback returns the property value of the given element. - * - * If an object is provided for an iteratee the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {...(Function|Function[]|Object|Object[]|string|string[])} iteratees - * The iteratees to sort by, specified as individual values or arrays of values. - * @returns {Array} Returns the new sorted array. - * @example - * - * var users = [ - * { 'user': 'fred', 'age': 48 }, - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 42 }, - * { 'user': 'barney', 'age': 34 } - * ]; - * - * _.map(_.sortByAll(users, ['user', 'age']), _.values); - * // => [['barney', 34], ['barney', 36], ['fred', 42], ['fred', 48]] - * - * _.map(_.sortByAll(users, 'user', function(chr) { - * return Math.floor(chr.age / 10); - * }), _.values); - * // => [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]] - */ - var sortByAll = restParam(function(collection, iteratees) { - if (collection == null) { - return []; - } - var guard = iteratees[2]; - if (guard && isIterateeCall(iteratees[0], iteratees[1], guard)) { - iteratees.length = 1; - } - return baseSortByOrder(collection, baseFlatten(iteratees), []); - }); - - /** - * This method is like `_.sortByAll` except that it allows specifying the - * sort orders of the iteratees to sort by. If `orders` is unspecified, all - * values are sorted in ascending order. Otherwise, a value is sorted in - * ascending order if its corresponding order is "asc", and descending if "desc". - * - * If a property name is provided for an iteratee the created `_.property` - * style callback returns the property value of the given element. - * - * If an object is provided for an iteratee the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. - * @param {boolean[]} [orders] The sort orders of `iteratees`. - * @param- {Object} [guard] Enables use as a callback for functions like `_.reduce`. - * @returns {Array} Returns the new sorted array. - * @example - * - * var users = [ - * { 'user': 'fred', 'age': 48 }, - * { 'user': 'barney', 'age': 34 }, - * { 'user': 'fred', 'age': 42 }, - * { 'user': 'barney', 'age': 36 } - * ]; - * - * // sort by `user` in ascending order and by `age` in descending order - * _.map(_.sortByOrder(users, ['user', 'age'], ['asc', 'desc']), _.values); - * // => [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]] - */ - function sortByOrder(collection, iteratees, orders, guard) { - if (collection == null) { - return []; - } - if (guard && isIterateeCall(iteratees, orders, guard)) { - orders = undefined; - } - if (!isArray(iteratees)) { - iteratees = iteratees == null ? [] : [iteratees]; - } - if (!isArray(orders)) { - orders = orders == null ? [] : [orders]; - } - return baseSortByOrder(collection, iteratees, orders); - } - - /** - * Performs a deep comparison between each element in `collection` and the - * source object, returning an array of all elements that have equivalent - * property values. - * - * **Note:** This method supports comparing arrays, booleans, `Date` objects, - * numbers, `Object` objects, regexes, and strings. Objects are compared by - * their own, not inherited, enumerable properties. For comparing a single - * own or inherited property value see `_.matchesProperty`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to search. - * @param {Object} source The object of property values to match. - * @returns {Array} Returns the new filtered array. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': false, 'pets': ['hoppy'] }, - * { 'user': 'fred', 'age': 40, 'active': true, 'pets': ['baby puss', 'dino'] } - * ]; - * - * _.pluck(_.where(users, { 'age': 36, 'active': false }), 'user'); - * // => ['barney'] - * - * _.pluck(_.where(users, { 'pets': ['dino'] }), 'user'); - * // => ['fred'] - */ - function where(collection, source) { - return filter(collection, baseMatches(source)); - } - - /*------------------------------------------------------------------------*/ - - /** - * Gets the number of milliseconds that have elapsed since the Unix epoch - * (1 January 1970 00:00:00 UTC). - * - * @static - * @memberOf _ - * @category Date - * @example - * - * _.defer(function(stamp) { - * console.log(_.now() - stamp); - * }, _.now()); - * // => logs the number of milliseconds it took for the deferred function to be invoked - */ - var now = nativeNow || function() { - return new Date().getTime(); - }; - - /*------------------------------------------------------------------------*/ - - /** - * The opposite of `_.before`; this method creates a function that invokes - * `func` once it's called `n` or more times. - * - * @static - * @memberOf _ - * @category Function - * @param {number} n The number of calls before `func` is invoked. - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * var saves = ['profile', 'settings']; - * - * var done = _.after(saves.length, function() { - * console.log('done saving!'); - * }); - * - * _.forEach(saves, function(type) { - * asyncSave({ 'type': type, 'complete': done }); - * }); - * // => logs 'done saving!' after the two async saves have completed - */ - function after(n, func) { - if (typeof func != 'function') { - if (typeof n == 'function') { - var temp = n; - n = func; - func = temp; - } else { - throw new TypeError(FUNC_ERROR_TEXT); - } - } - n = nativeIsFinite(n = +n) ? n : 0; - return function() { - if (--n < 1) { - return func.apply(this, arguments); - } - }; - } - - /** - * Creates a function that accepts up to `n` arguments ignoring any - * additional arguments. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to cap arguments for. - * @param {number} [n=func.length] The arity cap. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Function} Returns the new function. - * @example - * - * _.map(['6', '8', '10'], _.ary(parseInt, 1)); - * // => [6, 8, 10] - */ - function ary(func, n, guard) { - if (guard && isIterateeCall(func, n, guard)) { - n = undefined; - } - n = (func && n == null) ? func.length : nativeMax(+n || 0, 0); - return createWrapper(func, ARY_FLAG, undefined, undefined, undefined, undefined, n); - } - - /** - * Creates a function that invokes `func`, with the `this` binding and arguments - * of the created function, while it's called less than `n` times. Subsequent - * calls to the created function return the result of the last `func` invocation. - * - * @static - * @memberOf _ - * @category Function - * @param {number} n The number of calls at which `func` is no longer invoked. - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * jQuery('#add').on('click', _.before(5, addContactToList)); - * // => allows adding up to 4 contacts to the list - */ - function before(n, func) { - var result; - if (typeof func != 'function') { - if (typeof n == 'function') { - var temp = n; - n = func; - func = temp; - } else { - throw new TypeError(FUNC_ERROR_TEXT); - } - } - return function() { - if (--n > 0) { - result = func.apply(this, arguments); - } - if (n <= 1) { - func = undefined; - } - return result; - }; - } - - /** - * Creates a function that invokes `func` with the `this` binding of `thisArg` - * and prepends any additional `_.bind` arguments to those provided to the - * bound function. - * - * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds, - * may be used as a placeholder for partially applied arguments. - * - * **Note:** Unlike native `Function#bind` this method does not set the "length" - * property of bound functions. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to bind. - * @param {*} thisArg The `this` binding of `func`. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new bound function. - * @example - * - * var greet = function(greeting, punctuation) { - * return greeting + ' ' + this.user + punctuation; - * }; - * - * var object = { 'user': 'fred' }; - * - * var bound = _.bind(greet, object, 'hi'); - * bound('!'); - * // => 'hi fred!' - * - * // using placeholders - * var bound = _.bind(greet, object, _, '!'); - * bound('hi'); - * // => 'hi fred!' - */ - var bind = restParam(function(func, thisArg, partials) { - var bitmask = BIND_FLAG; - if (partials.length) { - var holders = replaceHolders(partials, bind.placeholder); - bitmask |= PARTIAL_FLAG; - } - return createWrapper(func, bitmask, thisArg, partials, holders); - }); - - /** - * Binds methods of an object to the object itself, overwriting the existing - * method. Method names may be specified as individual arguments or as arrays - * of method names. If no method names are provided all enumerable function - * properties, own and inherited, of `object` are bound. - * - * **Note:** This method does not set the "length" property of bound functions. - * - * @static - * @memberOf _ - * @category Function - * @param {Object} object The object to bind and assign the bound methods to. - * @param {...(string|string[])} [methodNames] The object method names to bind, - * specified as individual method names or arrays of method names. - * @returns {Object} Returns `object`. - * @example - * - * var view = { - * 'label': 'docs', - * 'onClick': function() { - * console.log('clicked ' + this.label); - * } - * }; - * - * _.bindAll(view); - * jQuery('#docs').on('click', view.onClick); - * // => logs 'clicked docs' when the element is clicked - */ - var bindAll = restParam(function(object, methodNames) { - methodNames = methodNames.length ? baseFlatten(methodNames) : functions(object); - - var index = -1, - length = methodNames.length; - - while (++index < length) { - var key = methodNames[index]; - object[key] = createWrapper(object[key], BIND_FLAG, object); - } - return object; - }); - - /** - * Creates a function that invokes the method at `object[key]` and prepends - * any additional `_.bindKey` arguments to those provided to the bound function. - * - * This method differs from `_.bind` by allowing bound functions to reference - * methods that may be redefined or don't yet exist. - * See [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern) - * for more details. - * - * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for partially applied arguments. - * - * @static - * @memberOf _ - * @category Function - * @param {Object} object The object the method belongs to. - * @param {string} key The key of the method. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new bound function. - * @example - * - * var object = { - * 'user': 'fred', - * 'greet': function(greeting, punctuation) { - * return greeting + ' ' + this.user + punctuation; - * } - * }; - * - * var bound = _.bindKey(object, 'greet', 'hi'); - * bound('!'); - * // => 'hi fred!' - * - * object.greet = function(greeting, punctuation) { - * return greeting + 'ya ' + this.user + punctuation; - * }; - * - * bound('!'); - * // => 'hiya fred!' - * - * // using placeholders - * var bound = _.bindKey(object, 'greet', _, '!'); - * bound('hi'); - * // => 'hiya fred!' - */ - var bindKey = restParam(function(object, key, partials) { - var bitmask = BIND_FLAG | BIND_KEY_FLAG; - if (partials.length) { - var holders = replaceHolders(partials, bindKey.placeholder); - bitmask |= PARTIAL_FLAG; - } - return createWrapper(key, bitmask, object, partials, holders); - }); - - /** - * Creates a function that accepts one or more arguments of `func` that when - * called either invokes `func` returning its result, if all `func` arguments - * have been provided, or returns a function that accepts one or more of the - * remaining `func` arguments, and so on. The arity of `func` may be specified - * if `func.length` is not sufficient. - * - * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds, - * may be used as a placeholder for provided arguments. - * - * **Note:** This method does not set the "length" property of curried functions. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to curry. - * @param {number} [arity=func.length] The arity of `func`. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Function} Returns the new curried function. - * @example - * - * var abc = function(a, b, c) { - * return [a, b, c]; - * }; - * - * var curried = _.curry(abc); - * - * curried(1)(2)(3); - * // => [1, 2, 3] - * - * curried(1, 2)(3); - * // => [1, 2, 3] - * - * curried(1, 2, 3); - * // => [1, 2, 3] - * - * // using placeholders - * curried(1)(_, 3)(2); - * // => [1, 2, 3] - */ - var curry = createCurry(CURRY_FLAG); - - /** - * This method is like `_.curry` except that arguments are applied to `func` - * in the manner of `_.partialRight` instead of `_.partial`. - * - * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for provided arguments. - * - * **Note:** This method does not set the "length" property of curried functions. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to curry. - * @param {number} [arity=func.length] The arity of `func`. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Function} Returns the new curried function. - * @example - * - * var abc = function(a, b, c) { - * return [a, b, c]; - * }; - * - * var curried = _.curryRight(abc); - * - * curried(3)(2)(1); - * // => [1, 2, 3] - * - * curried(2, 3)(1); - * // => [1, 2, 3] - * - * curried(1, 2, 3); - * // => [1, 2, 3] - * - * // using placeholders - * curried(3)(1, _)(2); - * // => [1, 2, 3] - */ - var curryRight = createCurry(CURRY_RIGHT_FLAG); - - /** - * Creates a debounced function that delays invoking `func` until after `wait` - * milliseconds have elapsed since the last time the debounced function was - * invoked. The debounced function comes with a `cancel` method to cancel - * delayed invocations. Provide an options object to indicate that `func` - * should be invoked on the leading and/or trailing edge of the `wait` timeout. - * Subsequent calls to the debounced function return the result of the last - * `func` invocation. - * - * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked - * on the trailing edge of the timeout only if the the debounced function is - * invoked more than once during the `wait` timeout. - * - * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) - * for details over the differences between `_.debounce` and `_.throttle`. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to debounce. - * @param {number} [wait=0] The number of milliseconds to delay. - * @param {Object} [options] The options object. - * @param {boolean} [options.leading=false] Specify invoking on the leading - * edge of the timeout. - * @param {number} [options.maxWait] The maximum time `func` is allowed to be - * delayed before it's invoked. - * @param {boolean} [options.trailing=true] Specify invoking on the trailing - * edge of the timeout. - * @returns {Function} Returns the new debounced function. - * @example - * - * // avoid costly calculations while the window size is in flux - * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); - * - * // invoke `sendMail` when the click event is fired, debouncing subsequent calls - * jQuery('#postbox').on('click', _.debounce(sendMail, 300, { - * 'leading': true, - * 'trailing': false - * })); - * - * // ensure `batchLog` is invoked once after 1 second of debounced calls - * var source = new EventSource('/stream'); - * jQuery(source).on('message', _.debounce(batchLog, 250, { - * 'maxWait': 1000 - * })); - * - * // cancel a debounced call - * var todoChanges = _.debounce(batchLog, 1000); - * Object.observe(models.todo, todoChanges); - * - * Object.observe(models, function(changes) { - * if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) { - * todoChanges.cancel(); - * } - * }, ['delete']); - * - * // ...at some point `models.todo` is changed - * models.todo.completed = true; - * - * // ...before 1 second has passed `models.todo` is deleted - * // which cancels the debounced `todoChanges` call - * delete models.todo; - */ - function debounce(func, wait, options) { - var args, - maxTimeoutId, - result, - stamp, - thisArg, - timeoutId, - trailingCall, - lastCalled = 0, - maxWait = false, - trailing = true; - - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - wait = wait < 0 ? 0 : (+wait || 0); - if (options === true) { - var leading = true; - trailing = false; - } else if (isObject(options)) { - leading = !!options.leading; - maxWait = 'maxWait' in options && nativeMax(+options.maxWait || 0, wait); - trailing = 'trailing' in options ? !!options.trailing : trailing; - } - - function cancel() { - if (timeoutId) { - clearTimeout(timeoutId); - } - if (maxTimeoutId) { - clearTimeout(maxTimeoutId); - } - lastCalled = 0; - maxTimeoutId = timeoutId = trailingCall = undefined; - } - - function complete(isCalled, id) { - if (id) { - clearTimeout(id); - } - maxTimeoutId = timeoutId = trailingCall = undefined; - if (isCalled) { - lastCalled = now(); - result = func.apply(thisArg, args); - if (!timeoutId && !maxTimeoutId) { - args = thisArg = undefined; - } - } - } - - function delayed() { - var remaining = wait - (now() - stamp); - if (remaining <= 0 || remaining > wait) { - complete(trailingCall, maxTimeoutId); - } else { - timeoutId = setTimeout(delayed, remaining); - } - } - - function maxDelayed() { - complete(trailing, timeoutId); - } - - function debounced() { - args = arguments; - stamp = now(); - thisArg = this; - trailingCall = trailing && (timeoutId || !leading); - - if (maxWait === false) { - var leadingCall = leading && !timeoutId; - } else { - if (!maxTimeoutId && !leading) { - lastCalled = stamp; - } - var remaining = maxWait - (stamp - lastCalled), - isCalled = remaining <= 0 || remaining > maxWait; - - if (isCalled) { - if (maxTimeoutId) { - maxTimeoutId = clearTimeout(maxTimeoutId); - } - lastCalled = stamp; - result = func.apply(thisArg, args); - } - else if (!maxTimeoutId) { - maxTimeoutId = setTimeout(maxDelayed, remaining); - } - } - if (isCalled && timeoutId) { - timeoutId = clearTimeout(timeoutId); - } - else if (!timeoutId && wait !== maxWait) { - timeoutId = setTimeout(delayed, wait); - } - if (leadingCall) { - isCalled = true; - result = func.apply(thisArg, args); - } - if (isCalled && !timeoutId && !maxTimeoutId) { - args = thisArg = undefined; - } - return result; - } - debounced.cancel = cancel; - return debounced; - } - - /** - * Defers invoking the `func` until the current call stack has cleared. Any - * additional arguments are provided to `func` when it's invoked. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to defer. - * @param {...*} [args] The arguments to invoke the function with. - * @returns {number} Returns the timer id. - * @example - * - * _.defer(function(text) { - * console.log(text); - * }, 'deferred'); - * // logs 'deferred' after one or more milliseconds - */ - var defer = restParam(function(func, args) { - return baseDelay(func, 1, args); - }); - - /** - * Invokes `func` after `wait` milliseconds. Any additional arguments are - * provided to `func` when it's invoked. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to delay. - * @param {number} wait The number of milliseconds to delay invocation. - * @param {...*} [args] The arguments to invoke the function with. - * @returns {number} Returns the timer id. - * @example - * - * _.delay(function(text) { - * console.log(text); - * }, 1000, 'later'); - * // => logs 'later' after one second - */ - var delay = restParam(function(func, wait, args) { - return baseDelay(func, wait, args); - }); - - /** - * Creates a function that returns the result of invoking 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 square(n) { - * return n * n; - * } - * - * var addSquare = _.flow(_.add, square); - * addSquare(1, 2); - * // => 9 - */ - var flow = createFlow(); - - /** - * 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 square(n) { - * return n * n; - * } - * - * var addSquare = _.flowRight(square, _.add); - * addSquare(1, 2); - * // => 9 - */ - var flowRight = createFlow(true); - - /** - * 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 - * arguments provided to the memoized function. By default, the first argument - * provided to the memoized function is coerced to a string and used as the - * cache key. The `func` is invoked with the `this` binding of the memoized - * function. - * - * **Note:** The cache is exposed as the `cache` property on the memoized - * function. Its creation may be customized by replacing the `_.memoize.Cache` - * constructor with one whose instances implement the [`Map`](http://ecma-international.org/ecma-262/6.0/#sec-properties-of-the-map-prototype-object) - * method interface of `get`, `has`, and `set`. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to have its output memoized. - * @param {Function} [resolver] The function to resolve the cache key. - * @returns {Function} Returns the new memoizing function. - * @example - * - * var upperCase = _.memoize(function(string) { - * return string.toUpperCase(); - * }); - * - * upperCase('fred'); - * // => 'FRED' - * - * // modifying the result cache - * upperCase.cache.set('fred', 'BARNEY'); - * upperCase('fred'); - * // => 'BARNEY' - * - * // replacing `_.memoize.Cache` - * var object = { 'user': 'fred' }; - * var other = { 'user': 'barney' }; - * var identity = _.memoize(_.identity); - * - * identity(object); - * // => { 'user': 'fred' } - * identity(other); - * // => { 'user': 'fred' } - * - * _.memoize.Cache = WeakMap; - * var identity = _.memoize(_.identity); - * - * identity(object); - * // => { 'user': 'fred' } - * identity(other); - * // => { 'user': 'barney' } - */ - function memoize(func, resolver) { - if (typeof func != 'function' || (resolver && typeof resolver != 'function')) { - throw new TypeError(FUNC_ERROR_TEXT); - } - var memoized = function() { - var args = arguments, - key = resolver ? resolver.apply(this, args) : args[0], - cache = memoized.cache; - - if (cache.has(key)) { - return cache.get(key); - } - var result = func.apply(this, args); - memoized.cache = cache.set(key, result); - return result; - }; - memoized.cache = new memoize.Cache; - return memoized; - } - - /** - * Creates a function that runs each argument through a corresponding - * transform function. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to wrap. - * @param {...(Function|Function[])} [transforms] The functions to transform - * arguments, specified as individual functions or arrays of functions. - * @returns {Function} Returns the new function. - * @example - * - * function doubled(n) { - * return n * 2; - * } - * - * function square(n) { - * return n * n; - * } - * - * var modded = _.modArgs(function(x, y) { - * return [x, y]; - * }, square, doubled); - * - * modded(1, 2); - * // => [1, 4] - * - * modded(5, 10); - * // => [25, 20] - */ - var modArgs = restParam(function(func, transforms) { - transforms = baseFlatten(transforms); - if (typeof func != 'function' || !arrayEvery(transforms, baseIsFunction)) { - throw new TypeError(FUNC_ERROR_TEXT); - } - var length = transforms.length; - return restParam(function(args) { - var index = nativeMin(args.length, length); - while (index--) { - args[index] = transforms[index](args[index]); - } - return func.apply(this, args); - }); - }); - - /** - * Creates a function that negates the result of the predicate `func`. The - * `func` predicate is invoked with the `this` binding and arguments of the - * created function. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} predicate The predicate to negate. - * @returns {Function} Returns the new function. - * @example - * - * function isEven(n) { - * return n % 2 == 0; - * } - * - * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven)); - * // => [1, 3, 5] - */ - function negate(predicate) { - if (typeof predicate != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - return function() { - return !predicate.apply(this, arguments); - }; - } - - /** - * Creates a function that is restricted to invoking `func` once. Repeat calls - * to the function return the value of the first call. The `func` is invoked - * with the `this` binding and arguments of the created function. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * var initialize = _.once(createApplication); - * initialize(); - * initialize(); - * // `initialize` invokes `createApplication` once - */ - function once(func) { - return before(2, func); - } - - /** - * Creates a function that invokes `func` with `partial` arguments prepended - * to those provided to the new function. This method is like `_.bind` except - * it does **not** alter the `this` binding. - * - * The `_.partial.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for partially applied arguments. - * - * **Note:** This method does not set the "length" property of partially - * applied functions. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to partially apply arguments to. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new partially applied function. - * @example - * - * var greet = function(greeting, name) { - * return greeting + ' ' + name; - * }; - * - * var sayHelloTo = _.partial(greet, 'hello'); - * sayHelloTo('fred'); - * // => 'hello fred' - * - * // using placeholders - * var greetFred = _.partial(greet, _, 'fred'); - * greetFred('hi'); - * // => 'hi fred' - */ - var partial = createPartial(PARTIAL_FLAG); - - /** - * This method is like `_.partial` except that partially applied arguments - * are appended to those provided to the new function. - * - * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for partially applied arguments. - * - * **Note:** This method does not set the "length" property of partially - * applied functions. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to partially apply arguments to. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new partially applied function. - * @example - * - * var greet = function(greeting, name) { - * return greeting + ' ' + name; - * }; - * - * var greetFred = _.partialRight(greet, 'fred'); - * greetFred('hi'); - * // => 'hi fred' - * - * // using placeholders - * var sayHelloTo = _.partialRight(greet, 'hello', _); - * sayHelloTo('fred'); - * // => 'hello fred' - */ - var partialRight = createPartial(PARTIAL_RIGHT_FLAG); - - /** - * Creates a function that invokes `func` with arguments arranged according - * to the specified indexes where the argument value at the first index is - * provided as the first argument, the argument value at the second index is - * provided as the second argument, and so on. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to rearrange arguments for. - * @param {...(number|number[])} indexes The arranged argument indexes, - * specified as individual indexes or arrays of indexes. - * @returns {Function} Returns the new function. - * @example - * - * var rearged = _.rearg(function(a, b, c) { - * return [a, b, c]; - * }, 2, 0, 1); - * - * rearged('b', 'c', 'a') - * // => ['a', 'b', 'c'] - * - * var map = _.rearg(_.map, [1, 0]); - * map(function(n) { - * return n * 3; - * }, [1, 2, 3]); - * // => [3, 6, 9] - */ - var rearg = restParam(function(func, indexes) { - return createWrapper(func, REARG_FLAG, undefined, undefined, undefined, baseFlatten(indexes)); - }); - - /** - * Creates a function that invokes `func` with the `this` binding of the - * created function and arguments from `start` and beyond provided as an array. - * - * **Note:** This method is based on the [rest parameter](https://developer.mozilla.org/Web/JavaScript/Reference/Functions/rest_parameters). - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to apply a rest parameter to. - * @param {number} [start=func.length-1] The start position of the rest parameter. - * @returns {Function} Returns the new function. - * @example - * - * var say = _.restParam(function(what, names) { - * return what + ' ' + _.initial(names).join(', ') + - * (_.size(names) > 1 ? ', & ' : '') + _.last(names); - * }); - * - * say('hello', 'fred', 'barney', 'pebbles'); - * // => 'hello fred, barney, & pebbles' - */ - function restParam(func, start) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - start = nativeMax(start === undefined ? (func.length - 1) : (+start || 0), 0); - return function() { - var args = arguments, - index = -1, - length = nativeMax(args.length - start, 0), - rest = Array(length); - - while (++index < length) { - rest[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); - } - var otherArgs = Array(start + 1); - index = -1; - while (++index < start) { - otherArgs[index] = args[index]; - } - otherArgs[start] = rest; - return func.apply(this, otherArgs); - }; - } - - /** - * Creates a function that invokes `func` with the `this` binding of the created - * function and an array of arguments much like [`Function#apply`](https://es5.github.io/#x15.3.4.3). - * - * **Note:** This method is based on the [spread operator](https://developer.mozilla.org/Web/JavaScript/Reference/Operators/Spread_operator). - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to spread arguments over. - * @returns {Function} Returns the new function. - * @example - * - * var say = _.spread(function(who, what) { - * return who + ' says ' + what; - * }); - * - * say(['fred', 'hello']); - * // => 'fred says hello' - * - * // with a Promise - * var numbers = Promise.all([ - * Promise.resolve(40), - * Promise.resolve(36) - * ]); - * - * numbers.then(_.spread(function(x, y) { - * return x + y; - * })); - * // => a Promise of 76 - */ - function spread(func) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - return function(array) { - return func.apply(this, array); - }; - } - - /** - * Creates a throttled function that only invokes `func` at most once per - * every `wait` milliseconds. The throttled function comes with a `cancel` - * method to cancel delayed invocations. Provide an options object to indicate - * that `func` should be invoked on the leading and/or trailing edge of the - * `wait` timeout. Subsequent calls to the throttled function return the - * result of the last `func` call. - * - * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked - * on the trailing edge of the timeout only if the the throttled function is - * invoked more than once during the `wait` timeout. - * - * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) - * for details over the differences between `_.throttle` and `_.debounce`. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to throttle. - * @param {number} [wait=0] The number of milliseconds to throttle invocations to. - * @param {Object} [options] The options object. - * @param {boolean} [options.leading=true] Specify invoking on the leading - * edge of the timeout. - * @param {boolean} [options.trailing=true] Specify invoking on the trailing - * edge of the timeout. - * @returns {Function} Returns the new throttled function. - * @example - * - * // avoid excessively updating the position while scrolling - * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); - * - * // invoke `renewToken` when the click event is fired, but not more than once every 5 minutes - * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, { - * 'trailing': false - * })); - * - * // cancel a trailing throttled call - * jQuery(window).on('popstate', throttled.cancel); - */ - function throttle(func, wait, options) { - var leading = true, - trailing = true; - - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - if (options === false) { - leading = false; - } else if (isObject(options)) { - leading = 'leading' in options ? !!options.leading : leading; - trailing = 'trailing' in options ? !!options.trailing : trailing; - } - return debounce(func, wait, { 'leading': leading, 'maxWait': +wait, 'trailing': trailing }); - } - - /** - * Creates a function that provides `value` to the wrapper function as its - * first argument. Any additional arguments provided to the function are - * appended to those provided to the wrapper function. The wrapper is invoked - * with the `this` binding of the created function. - * - * @static - * @memberOf _ - * @category Function - * @param {*} value The value to wrap. - * @param {Function} wrapper The wrapper function. - * @returns {Function} Returns the new function. - * @example - * - * var p = _.wrap(_.escape, function(func, text) { - * return '

' + func(text) + '

'; - * }); - * - * p('fred, barney, & pebbles'); - * // => '

fred, barney, & pebbles

' - */ - function wrap(value, wrapper) { - wrapper = wrapper == null ? identity : wrapper; - return createWrapper(wrapper, PARTIAL_FLAG, undefined, [value], []); - } - - /*------------------------------------------------------------------------*/ - - /** - * Creates a clone of `value`. If `isDeep` is `true` nested objects are cloned, - * otherwise they are assigned by reference. If `customizer` is provided it's - * invoked to produce the cloned values. If `customizer` returns `undefined` - * cloning is handled by the method instead. The `customizer` is bound to - * `thisArg` and invoked with up to three argument; (value [, index|key, object]). - * - * **Note:** This method is loosely based on the - * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm). - * The enumerable properties of `arguments` objects and objects created by - * constructors other than `Object` are cloned to plain `Object` objects. An - * empty object is returned for uncloneable values such as functions, DOM nodes, - * Maps, Sets, and WeakMaps. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @param {Function} [customizer] The function to customize cloning values. - * @param {*} [thisArg] The `this` binding of `customizer`. - * @returns {*} Returns the cloned value. - * @example - * - * var users = [ - * { 'user': 'barney' }, - * { 'user': 'fred' } - * ]; - * - * var shallow = _.clone(users); - * shallow[0] === users[0]; - * // => true - * - * var deep = _.clone(users, true); - * deep[0] === users[0]; - * // => false - * - * // using a customizer callback - * var el = _.clone(document.body, function(value) { - * if (_.isElement(value)) { - * return value.cloneNode(false); - * } - * }); - * - * el === document.body - * // => false - * el.nodeName - * // => BODY - * el.childNodes.length; - * // => 0 - */ - function clone(value, isDeep, customizer, thisArg) { - if (isDeep && typeof isDeep != 'boolean' && isIterateeCall(value, isDeep, customizer)) { - isDeep = false; - } - else if (typeof isDeep == 'function') { - thisArg = customizer; - customizer = isDeep; - isDeep = false; - } - return typeof customizer == 'function' - ? baseClone(value, isDeep, bindCallback(customizer, thisArg, 3)) - : baseClone(value, isDeep); - } - - /** - * Creates a deep clone of `value`. If `customizer` is provided it's invoked - * to produce the cloned values. If `customizer` returns `undefined` cloning - * is handled by the method instead. The `customizer` is bound to `thisArg` - * and invoked with up to three argument; (value [, index|key, object]). - * - * **Note:** This method is loosely based on the - * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm). - * The enumerable properties of `arguments` objects and objects created by - * constructors other than `Object` are cloned to plain `Object` objects. An - * empty object is returned for uncloneable values such as functions, DOM nodes, - * Maps, Sets, and WeakMaps. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to deep clone. - * @param {Function} [customizer] The function to customize cloning values. - * @param {*} [thisArg] The `this` binding of `customizer`. - * @returns {*} Returns the deep cloned value. - * @example - * - * var users = [ - * { 'user': 'barney' }, - * { 'user': 'fred' } - * ]; - * - * var deep = _.cloneDeep(users); - * deep[0] === users[0]; - * // => false - * - * // using a customizer callback - * var el = _.cloneDeep(document.body, function(value) { - * if (_.isElement(value)) { - * return value.cloneNode(true); - * } - * }); - * - * el === document.body - * // => false - * el.nodeName - * // => BODY - * el.childNodes.length; - * // => 20 - */ - function cloneDeep(value, customizer, thisArg) { - return typeof customizer == 'function' - ? baseClone(value, true, bindCallback(customizer, thisArg, 3)) - : baseClone(value, true); - } - - /** - * Checks if `value` is greater than `other`. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is greater than `other`, else `false`. - * @example - * - * _.gt(3, 1); - * // => true - * - * _.gt(3, 3); - * // => false - * - * _.gt(1, 3); - * // => false - */ - function gt(value, other) { - return value > other; - } - - /** - * Checks if `value` is greater than or equal to `other`. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is greater than or equal to `other`, else `false`. - * @example - * - * _.gte(3, 1); - * // => true - * - * _.gte(3, 3); - * // => true - * - * _.gte(1, 3); - * // => false - */ - function gte(value, other) { - return value >= other; - } - - /** - * Checks if `value` is classified as an `arguments` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isArguments(function() { return arguments; }()); - * // => true - * - * _.isArguments([1, 2, 3]); - * // => false - */ - function isArguments(value) { - return isObjectLike(value) && isArrayLike(value) && - hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee'); - } - - /** - * Checks if `value` is classified as an `Array` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isArray([1, 2, 3]); - * // => true - * - * _.isArray(function() { return arguments; }()); - * // => false - */ - var isArray = nativeIsArray || function(value) { - return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag; - }; - - /** - * Checks if `value` is classified as a boolean primitive or object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isBoolean(false); - * // => true - * - * _.isBoolean(null); - * // => false - */ - function isBoolean(value) { - return value === true || value === false || (isObjectLike(value) && objToString.call(value) == boolTag); - } - - /** - * Checks if `value` is classified as a `Date` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isDate(new Date); - * // => true - * - * _.isDate('Mon April 23 2012'); - * // => false - */ - function isDate(value) { - return isObjectLike(value) && objToString.call(value) == dateTag; - } - - /** - * Checks if `value` is a DOM element. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`. - * @example - * - * _.isElement(document.body); - * // => true - * - * _.isElement(''); - * // => false - */ - function isElement(value) { - return !!value && value.nodeType === 1 && isObjectLike(value) && !isPlainObject(value); - } - - /** - * Checks if `value` is empty. A value is considered empty unless it's an - * `arguments` object, array, string, or jQuery-like collection with a length - * greater than `0` or an object with own enumerable properties. - * - * @static - * @memberOf _ - * @category Lang - * @param {Array|Object|string} value The value to inspect. - * @returns {boolean} Returns `true` if `value` is empty, else `false`. - * @example - * - * _.isEmpty(null); - * // => true - * - * _.isEmpty(true); - * // => true - * - * _.isEmpty(1); - * // => true - * - * _.isEmpty([1, 2, 3]); - * // => false - * - * _.isEmpty({ 'a': 1 }); - * // => false - */ - function isEmpty(value) { - if (value == null) { - return true; - } - if (isArrayLike(value) && (isArray(value) || isString(value) || isArguments(value) || - (isObjectLike(value) && isFunction(value.splice)))) { - return !value.length; - } - return !keys(value).length; - } - - /** - * Performs a deep comparison between two values to determine if they are - * equivalent. If `customizer` is provided it's invoked to compare values. - * If `customizer` returns `undefined` comparisons are handled by the method - * instead. The `customizer` is bound to `thisArg` and invoked with up to - * three arguments: (value, other [, index|key]). - * - * **Note:** This method supports comparing arrays, booleans, `Date` objects, - * numbers, `Object` objects, regexes, and strings. Objects are compared by - * their own, not inherited, enumerable properties. Functions and DOM nodes - * are **not** supported. Provide a customizer function to extend support - * for comparing other values. - * - * @static - * @memberOf _ - * @alias eq - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @param {Function} [customizer] The function to customize value comparisons. - * @param {*} [thisArg] The `this` binding of `customizer`. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * var object = { 'user': 'fred' }; - * var other = { 'user': 'fred' }; - * - * object == other; - * // => false - * - * _.isEqual(object, other); - * // => true - * - * // using a customizer callback - * var array = ['hello', 'goodbye']; - * var other = ['hi', 'goodbye']; - * - * _.isEqual(array, other, function(value, other) { - * if (_.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/)) { - * return true; - * } - * }); - * // => true - */ - function isEqual(value, other, customizer, thisArg) { - customizer = typeof customizer == 'function' ? bindCallback(customizer, thisArg, 3) : undefined; - var result = customizer ? customizer(value, other) : undefined; - return result === undefined ? baseIsEqual(value, other, customizer) : !!result; - } - - /** - * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`, - * `SyntaxError`, `TypeError`, or `URIError` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an error object, else `false`. - * @example - * - * _.isError(new Error); - * // => true - * - * _.isError(Error); - * // => false - */ - function isError(value) { - return isObjectLike(value) && typeof value.message == 'string' && objToString.call(value) == errorTag; - } - - /** - * Checks if `value` is a finite primitive number. - * - * **Note:** This method is based on [`Number.isFinite`](http://ecma-international.org/ecma-262/6.0/#sec-number.isfinite). - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a finite number, else `false`. - * @example - * - * _.isFinite(10); - * // => true - * - * _.isFinite('10'); - * // => false - * - * _.isFinite(true); - * // => false - * - * _.isFinite(Object(10)); - * // => false - * - * _.isFinite(Infinity); - * // => false - */ - function isFinite(value) { - return typeof value == 'number' && nativeIsFinite(value); - } - - /** - * Checks if `value` is classified as a `Function` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isFunction(_); - * // => true - * - * _.isFunction(/abc/); - * // => false - */ - function isFunction(value) { - // The use of `Object#toString` avoids issues with the `typeof` operator - // in older versions of Chrome and Safari which return 'function' for regexes - // and Safari 8 which returns 'object' for typed array constructors. - return isObject(value) && objToString.call(value) == funcTag; - } - - /** - * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. - * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(1); - * // => false - */ - function isObject(value) { - // Avoid a V8 JIT bug in Chrome 19-20. - // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. - var type = typeof value; - return !!value && (type == 'object' || type == 'function'); - } - - /** - * Performs a deep comparison between `object` and `source` to determine if - * `object` contains equivalent property values. If `customizer` is provided - * it's invoked to compare values. If `customizer` returns `undefined` - * comparisons are handled by the method instead. The `customizer` is bound - * to `thisArg` and invoked with three arguments: (value, other, index|key). - * - * **Note:** This method supports comparing properties of arrays, booleans, - * `Date` objects, numbers, `Object` objects, regexes, and strings. Functions - * and DOM nodes are **not** supported. Provide a customizer function to extend - * support for comparing other values. - * - * @static - * @memberOf _ - * @category Lang - * @param {Object} object The object to inspect. - * @param {Object} source The object of property values to match. - * @param {Function} [customizer] The function to customize value comparisons. - * @param {*} [thisArg] The `this` binding of `customizer`. - * @returns {boolean} Returns `true` if `object` is a match, else `false`. - * @example - * - * var object = { 'user': 'fred', 'age': 40 }; - * - * _.isMatch(object, { 'age': 40 }); - * // => true - * - * _.isMatch(object, { 'age': 36 }); - * // => false - * - * // using a customizer callback - * var object = { 'greeting': 'hello' }; - * var source = { 'greeting': 'hi' }; - * - * _.isMatch(object, source, function(value, other) { - * return _.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/) || undefined; - * }); - * // => true - */ - function isMatch(object, source, customizer, thisArg) { - customizer = typeof customizer == 'function' ? bindCallback(customizer, thisArg, 3) : undefined; - return baseIsMatch(object, getMatchData(source), customizer); - } - - /** - * Checks if `value` is `NaN`. - * - * **Note:** This method is not the same as [`isNaN`](https://es5.github.io/#x15.1.2.4) - * which returns `true` for `undefined` and other non-numeric values. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. - * @example - * - * _.isNaN(NaN); - * // => true - * - * _.isNaN(new Number(NaN)); - * // => true - * - * isNaN(undefined); - * // => true - * - * _.isNaN(undefined); - * // => false - */ - function isNaN(value) { - // An `NaN` primitive is the only value that is not equal to itself. - // Perform the `toStringTag` check first to avoid errors with some host objects in IE. - return isNumber(value) && value != +value; - } - - /** - * Checks if `value` is a native function. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a native function, else `false`. - * @example - * - * _.isNative(Array.prototype.push); - * // => true - * - * _.isNative(_); - * // => false - */ - function isNative(value) { - if (value == null) { - return false; - } - if (isFunction(value)) { - return reIsNative.test(fnToString.call(value)); - } - return isObjectLike(value) && reIsHostCtor.test(value); - } - - /** - * Checks if `value` is `null`. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `null`, else `false`. - * @example - * - * _.isNull(null); - * // => true - * - * _.isNull(void 0); - * // => false - */ - function isNull(value) { - return value === null; - } - - /** - * Checks if `value` is classified as a `Number` primitive or object. - * - * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are classified - * as numbers, use the `_.isFinite` method. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isNumber(8.4); - * // => true - * - * _.isNumber(NaN); - * // => true - * - * _.isNumber('8.4'); - * // => false - */ - function isNumber(value) { - return typeof value == 'number' || (isObjectLike(value) && objToString.call(value) == numberTag); - } - - /** - * Checks if `value` is a plain object, that is, an object created by the - * `Object` constructor or one with a `[[Prototype]]` of `null`. - * - * **Note:** This method assumes objects created by the `Object` constructor - * have no inherited enumerable properties. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. - * @example - * - * function Foo() { - * this.a = 1; - * } - * - * _.isPlainObject(new Foo); - * // => false - * - * _.isPlainObject([1, 2, 3]); - * // => false - * - * _.isPlainObject({ 'x': 0, 'y': 0 }); - * // => true - * - * _.isPlainObject(Object.create(null)); - * // => true - */ - function isPlainObject(value) { - var Ctor; - - // Exit early for non `Object` objects. - if (!(isObjectLike(value) && objToString.call(value) == objectTag && !isArguments(value)) || - (!hasOwnProperty.call(value, 'constructor') && (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor)))) { - return false; - } - // IE < 9 iterates inherited properties before own properties. If the first - // iterated property is an object's own property then there are no inherited - // enumerable properties. - var result; - // In most environments an object's own properties are iterated before - // its inherited properties. If the last iterated property is an object's - // own property then there are no inherited enumerable properties. - baseForIn(value, function(subValue, key) { - result = key; - }); - return result === undefined || hasOwnProperty.call(value, result); - } - - /** - * Checks if `value` is classified as a `RegExp` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isRegExp(/abc/); - * // => true - * - * _.isRegExp('/abc/'); - * // => false - */ - function isRegExp(value) { - return isObject(value) && objToString.call(value) == regexpTag; - } - - /** - * Checks if `value` is classified as a `String` primitive or object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isString('abc'); - * // => true - * - * _.isString(1); - * // => false - */ - function isString(value) { - return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag); - } - - /** - * Checks if `value` is classified as a typed array. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isTypedArray(new Uint8Array); - * // => true - * - * _.isTypedArray([]); - * // => false - */ - function isTypedArray(value) { - return isObjectLike(value) && isLength(value.length) && !!typedArrayTags[objToString.call(value)]; - } - - /** - * Checks if `value` is `undefined`. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. - * @example - * - * _.isUndefined(void 0); - * // => true - * - * _.isUndefined(null); - * // => false - */ - function isUndefined(value) { - return value === undefined; - } - - /** - * Checks if `value` is less than `other`. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is less than `other`, else `false`. - * @example - * - * _.lt(1, 3); - * // => true - * - * _.lt(3, 3); - * // => false - * - * _.lt(3, 1); - * // => false - */ - function lt(value, other) { - return value < other; - } - - /** - * Checks if `value` is less than or equal to `other`. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is less than or equal to `other`, else `false`. - * @example - * - * _.lte(1, 3); - * // => true - * - * _.lte(3, 3); - * // => true - * - * _.lte(3, 1); - * // => false - */ - function lte(value, other) { - return value <= other; - } - - /** - * Converts `value` to an array. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to convert. - * @returns {Array} Returns the converted array. - * @example - * - * (function() { - * return _.toArray(arguments).slice(1); - * }(1, 2, 3)); - * // => [2, 3] - */ - function toArray(value) { - var length = value ? getLength(value) : 0; - if (!isLength(length)) { - return values(value); - } - if (!length) { - return []; - } - return arrayCopy(value); - } - - /** - * Converts `value` to a plain object flattening inherited enumerable - * properties of `value` to own properties of the plain object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to convert. - * @returns {Object} Returns the converted plain object. - * @example - * - * function Foo() { - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.assign({ 'a': 1 }, new Foo); - * // => { 'a': 1, 'b': 2 } - * - * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); - * // => { 'a': 1, 'b': 2, 'c': 3 } - */ - function toPlainObject(value) { - return baseCopy(value, keysIn(value)); - } - - /*------------------------------------------------------------------------*/ - - /** - * Recursively merges own enumerable properties of the source object(s), that - * don't resolve to `undefined` into the destination object. Subsequent sources - * overwrite property assignments of previous sources. If `customizer` is - * provided it's invoked to produce the merged values of the destination and - * source properties. If `customizer` returns `undefined` merging is handled - * by the method instead. The `customizer` is bound to `thisArg` and invoked - * with five arguments: (objectValue, sourceValue, key, object, source). - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @param {Function} [customizer] The function to customize assigned values. - * @param {*} [thisArg] The `this` binding of `customizer`. - * @returns {Object} Returns `object`. - * @example - * - * var users = { - * 'data': [{ 'user': 'barney' }, { 'user': 'fred' }] - * }; - * - * var ages = { - * 'data': [{ 'age': 36 }, { 'age': 40 }] - * }; - * - * _.merge(users, ages); - * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] } - * - * // using a customizer callback - * var object = { - * 'fruits': ['apple'], - * 'vegetables': ['beet'] - * }; - * - * var other = { - * 'fruits': ['banana'], - * 'vegetables': ['carrot'] - * }; - * - * _.merge(object, other, function(a, b) { - * if (_.isArray(a)) { - * return a.concat(b); - * } - * }); - * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] } - */ - var merge = createAssigner(baseMerge); - - /** - * Assigns own enumerable properties of source object(s) to the destination - * object. Subsequent sources overwrite property assignments of previous sources. - * If `customizer` is provided it's invoked to produce the assigned values. - * The `customizer` is bound to `thisArg` and invoked with five arguments: - * (objectValue, sourceValue, key, object, source). - * - * **Note:** This method mutates `object` and is based on - * [`Object.assign`](http://ecma-international.org/ecma-262/6.0/#sec-object.assign). - * - * @static - * @memberOf _ - * @alias extend - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @param {Function} [customizer] The function to customize assigned values. - * @param {*} [thisArg] The `this` binding of `customizer`. - * @returns {Object} Returns `object`. - * @example - * - * _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' }); - * // => { 'user': 'fred', 'age': 40 } - * - * // using a customizer callback - * var defaults = _.partialRight(_.assign, function(value, other) { - * return _.isUndefined(value) ? other : value; - * }); - * - * defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' }); - * // => { 'user': 'barney', 'age': 36 } - */ - var assign = createAssigner(function(object, source, customizer) { - return customizer - ? assignWith(object, source, customizer) - : baseAssign(object, source); - }); - - /** - * Creates an object that inherits from the given `prototype` object. If a - * `properties` object is provided its own enumerable properties are assigned - * to the created object. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} prototype The object to inherit from. - * @param {Object} [properties] The properties to assign to the object. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Object} Returns the new object. - * @example - * - * function Shape() { - * this.x = 0; - * this.y = 0; - * } - * - * function Circle() { - * Shape.call(this); - * } - * - * Circle.prototype = _.create(Shape.prototype, { - * 'constructor': Circle - * }); - * - * var circle = new Circle; - * circle instanceof Circle; - * // => true - * - * circle instanceof Shape; - * // => true - */ - function create(prototype, properties, guard) { - var result = baseCreate(prototype); - if (guard && isIterateeCall(prototype, properties, guard)) { - properties = undefined; - } - return properties ? baseAssign(result, properties) : result; - } - - /** - * Assigns own enumerable properties of source object(s) to the destination - * object for all destination properties that resolve to `undefined`. Once a - * property is set, additional values of the same property are ignored. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @example - * - * _.defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' }); - * // => { 'user': 'barney', 'age': 36 } - */ - var defaults = createDefaults(assign, assignDefaults); - - /** - * This method is like `_.defaults` except that it recursively assigns - * default properties. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @example - * - * _.defaultsDeep({ 'user': { 'name': 'barney' } }, { 'user': { 'name': 'fred', 'age': 36 } }); - * // => { 'user': { 'name': 'barney', 'age': 36 } } - * - */ - var defaultsDeep = createDefaults(merge, mergeDefaults); - - /** - * This method is like `_.find` except that it returns the key of the first - * element `predicate` returns truthy for instead of the element itself. - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to search. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {string|undefined} Returns the key of the matched element, else `undefined`. - * @example - * - * var users = { - * 'barney': { 'age': 36, 'active': true }, - * 'fred': { 'age': 40, 'active': false }, - * 'pebbles': { 'age': 1, 'active': true } - * }; - * - * _.findKey(users, function(chr) { - * return chr.age < 40; - * }); - * // => 'barney' (iteration order is not guaranteed) - * - * // using the `_.matches` callback shorthand - * _.findKey(users, { 'age': 1, 'active': true }); - * // => 'pebbles' - * - * // using the `_.matchesProperty` callback shorthand - * _.findKey(users, 'active', false); - * // => 'fred' - * - * // using the `_.property` callback shorthand - * _.findKey(users, 'active'); - * // => 'barney' - */ - var findKey = createFindKey(baseForOwn); - - /** - * This method is like `_.findKey` except that it iterates over elements of - * a collection in the opposite order. - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to search. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {string|undefined} Returns the key of the matched element, else `undefined`. - * @example - * - * var users = { - * 'barney': { 'age': 36, 'active': true }, - * 'fred': { 'age': 40, 'active': false }, - * 'pebbles': { 'age': 1, 'active': true } - * }; - * - * _.findLastKey(users, function(chr) { - * return chr.age < 40; - * }); - * // => returns `pebbles` assuming `_.findKey` returns `barney` - * - * // using the `_.matches` callback shorthand - * _.findLastKey(users, { 'age': 36, 'active': true }); - * // => 'barney' - * - * // using the `_.matchesProperty` callback shorthand - * _.findLastKey(users, 'active', false); - * // => 'fred' - * - * // using the `_.property` callback shorthand - * _.findLastKey(users, 'active'); - * // => 'pebbles' - */ - var findLastKey = createFindKey(baseForOwnRight); - - /** - * Iterates over own and inherited enumerable properties of an object invoking - * `iteratee` for each property. The `iteratee` is bound to `thisArg` and invoked - * with three arguments: (value, key, object). Iteratee functions may exit - * iteration early by explicitly returning `false`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns `object`. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forIn(new Foo, function(value, key) { - * console.log(key); - * }); - * // => logs 'a', 'b', and 'c' (iteration order is not guaranteed) - */ - var forIn = createForIn(baseFor); - - /** - * This method is like `_.forIn` except that it iterates over properties of - * `object` in the opposite order. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns `object`. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forInRight(new Foo, function(value, key) { - * console.log(key); - * }); - * // => logs 'c', 'b', and 'a' assuming `_.forIn ` logs 'a', 'b', and 'c' - */ - var forInRight = createForIn(baseForRight); - - /** - * Iterates over own enumerable properties of an object invoking `iteratee` - * for each property. The `iteratee` is bound to `thisArg` and invoked with - * three arguments: (value, key, object). Iteratee functions may exit iteration - * early by explicitly returning `false`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns `object`. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forOwn(new Foo, function(value, key) { - * console.log(key); - * }); - * // => logs 'a' and 'b' (iteration order is not guaranteed) - */ - var forOwn = createForOwn(baseForOwn); - - /** - * This method is like `_.forOwn` except that it iterates over properties of - * `object` in the opposite order. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns `object`. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forOwnRight(new Foo, function(value, key) { - * console.log(key); - * }); - * // => logs 'b' and 'a' assuming `_.forOwn` logs 'a' and 'b' - */ - var forOwnRight = createForOwn(baseForOwnRight); - - /** - * Creates an array of function property names from all enumerable properties, - * own and inherited, of `object`. - * - * @static - * @memberOf _ - * @alias methods - * @category Object - * @param {Object} object The object to inspect. - * @returns {Array} Returns the new array of property names. - * @example - * - * _.functions(_); - * // => ['after', 'ary', 'assign', ...] - */ - function functions(object) { - return baseFunctions(object, keysIn(object)); - } - - /** - * Gets the property value at `path` of `object`. If the resolved value is - * `undefined` the `defaultValue` is used in its place. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to get. - * @param {*} [defaultValue] The value returned if the resolved value is `undefined`. - * @returns {*} Returns the resolved value. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }] }; - * - * _.get(object, 'a[0].b.c'); - * // => 3 - * - * _.get(object, ['a', '0', 'b', 'c']); - * // => 3 - * - * _.get(object, 'a.b.c', 'default'); - * // => 'default' - */ - function get(object, path, defaultValue) { - var result = object == null ? undefined : baseGet(object, toPath(path), (path + '')); - return result === undefined ? defaultValue : result; - } - - /** - * Checks if `path` is a direct property. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path to check. - * @returns {boolean} Returns `true` if `path` is a direct property, else `false`. - * @example - * - * var object = { 'a': { 'b': { 'c': 3 } } }; - * - * _.has(object, 'a'); - * // => true - * - * _.has(object, 'a.b.c'); - * // => true - * - * _.has(object, ['a', 'b', 'c']); - * // => true - */ - function has(object, path) { - if (object == null) { - return false; - } - var result = hasOwnProperty.call(object, path); - if (!result && !isKey(path)) { - path = toPath(path); - object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); - if (object == null) { - return false; - } - path = last(path); - result = hasOwnProperty.call(object, path); - } - return result || (isLength(object.length) && isIndex(path, object.length) && - (isArray(object) || isArguments(object))); - } - - /** - * Creates an object composed of the inverted keys and values of `object`. - * If `object` contains duplicate values, subsequent values overwrite property - * assignments of previous values unless `multiValue` is `true`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to invert. - * @param {boolean} [multiValue] Allow multiple values per key. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Object} Returns the new inverted object. - * @example - * - * var object = { 'a': 1, 'b': 2, 'c': 1 }; - * - * _.invert(object); - * // => { '1': 'c', '2': 'b' } - * - * // with `multiValue` - * _.invert(object, true); - * // => { '1': ['a', 'c'], '2': ['b'] } - */ - function invert(object, multiValue, guard) { - if (guard && isIterateeCall(object, multiValue, guard)) { - multiValue = undefined; - } - var index = -1, - props = keys(object), - length = props.length, - result = {}; - - while (++index < length) { - var key = props[index], - value = object[key]; - - if (multiValue) { - if (hasOwnProperty.call(result, value)) { - result[value].push(key); - } else { - result[value] = [key]; - } - } - else { - result[value] = key; - } - } - return result; - } - - /** - * Creates an array of the own enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. See the - * [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys) - * for more details. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keys(new Foo); - * // => ['a', 'b'] (iteration order is not guaranteed) - * - * _.keys('hi'); - * // => ['0', '1'] - */ - var keys = !nativeKeys ? shimKeys : function(object) { - var Ctor = object == null ? undefined : object.constructor; - if ((typeof Ctor == 'function' && Ctor.prototype === object) || - (typeof object != 'function' && isArrayLike(object))) { - return shimKeys(object); - } - return isObject(object) ? nativeKeys(object) : []; - }; - - /** - * Creates an array of the own and inherited enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keysIn(new Foo); - * // => ['a', 'b', 'c'] (iteration order is not guaranteed) - */ - function keysIn(object) { - if (object == null) { - return []; - } - if (!isObject(object)) { - object = Object(object); - } - var length = object.length; - length = (length && isLength(length) && - (isArray(object) || isArguments(object)) && length) || 0; - - var Ctor = object.constructor, - index = -1, - isProto = typeof Ctor == 'function' && Ctor.prototype === object, - result = Array(length), - skipIndexes = length > 0; - - while (++index < length) { - result[index] = (index + ''); - } - for (var key in object) { - if (!(skipIndexes && isIndex(key, length)) && - !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { - result.push(key); - } - } - return result; - } - - /** - * The opposite of `_.mapValues`; this method creates an object with the - * same values as `object` and keys generated by running each own enumerable - * property of `object` through `iteratee`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns the new mapped object. - * @example - * - * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) { - * return key + value; - * }); - * // => { 'a1': 1, 'b2': 2 } - */ - var mapKeys = createObjectMapper(true); - - /** - * Creates an object with the same keys as `object` and values generated by - * running each own enumerable property of `object` through `iteratee`. The - * iteratee function is bound to `thisArg` and invoked with three arguments: - * (value, key, object). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns the new mapped object. - * @example - * - * _.mapValues({ 'a': 1, 'b': 2 }, function(n) { - * return n * 3; - * }); - * // => { 'a': 3, 'b': 6 } - * - * var users = { - * 'fred': { 'user': 'fred', 'age': 40 }, - * 'pebbles': { 'user': 'pebbles', 'age': 1 } - * }; - * - * // using the `_.property` callback shorthand - * _.mapValues(users, 'age'); - * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) - */ - var mapValues = createObjectMapper(); - - /** - * The opposite of `_.pick`; this method creates an object composed of the - * own and inherited enumerable properties of `object` that are not omitted. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The source object. - * @param {Function|...(string|string[])} [predicate] The function invoked per - * iteration or property names to omit, specified as individual property - * names or arrays of property names. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'user': 'fred', 'age': 40 }; - * - * _.omit(object, 'age'); - * // => { 'user': 'fred' } - * - * _.omit(object, _.isNumber); - * // => { 'user': 'fred' } - */ - var omit = restParam(function(object, props) { - if (object == null) { - return {}; - } - if (typeof props[0] != 'function') { - var props = arrayMap(baseFlatten(props), String); - return pickByArray(object, baseDifference(keysIn(object), props)); - } - var predicate = bindCallback(props[0], props[1], 3); - return pickByCallback(object, function(value, key, object) { - return !predicate(value, key, object); - }); - }); - - /** - * Creates a two dimensional array of the key-value pairs for `object`, - * e.g. `[[key1, value1], [key2, value2]]`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the new array of key-value pairs. - * @example - * - * _.pairs({ 'barney': 36, 'fred': 40 }); - * // => [['barney', 36], ['fred', 40]] (iteration order is not guaranteed) - */ - function pairs(object) { - object = toObject(object); - - var index = -1, - props = keys(object), - length = props.length, - result = Array(length); - - while (++index < length) { - var key = props[index]; - result[index] = [key, object[key]]; - } - return result; - } - - /** - * Creates an object composed of the picked `object` properties. Property - * names may be specified as individual arguments or as arrays of property - * names. If `predicate` is provided it's invoked for each property of `object` - * picking the properties `predicate` returns truthy for. The predicate is - * bound to `thisArg` and invoked with three arguments: (value, key, object). - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The source object. - * @param {Function|...(string|string[])} [predicate] The function invoked per - * iteration or property names to pick, specified as individual property - * names or arrays of property names. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'user': 'fred', 'age': 40 }; - * - * _.pick(object, 'user'); - * // => { 'user': 'fred' } - * - * _.pick(object, _.isString); - * // => { 'user': 'fred' } - */ - var pick = restParam(function(object, props) { - if (object == null) { - return {}; - } - return typeof props[0] == 'function' - ? pickByCallback(object, bindCallback(props[0], props[1], 3)) - : pickByArray(object, baseFlatten(props)); - }); - - /** - * This method is like `_.get` except that if the resolved value is a function - * it's invoked with the `this` binding of its parent object and its result - * is returned. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to resolve. - * @param {*} [defaultValue] The value returned if the resolved value is `undefined`. - * @returns {*} Returns the resolved value. - * @example - * - * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] }; - * - * _.result(object, 'a[0].b.c1'); - * // => 3 - * - * _.result(object, 'a[0].b.c2'); - * // => 4 - * - * _.result(object, 'a.b.c', 'default'); - * // => 'default' - * - * _.result(object, 'a.b.c', _.constant('default')); - * // => 'default' - */ - function result(object, path, defaultValue) { - var result = object == null ? undefined : object[path]; - if (result === undefined) { - if (object != null && !isKey(path, object)) { - path = toPath(path); - object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); - result = object == null ? undefined : object[last(path)]; - } - result = result === undefined ? defaultValue : result; - } - return isFunction(result) ? result.call(object) : result; - } - - /** - * Sets the property value of `path` on `object`. If a portion of `path` - * does not exist it's created. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to augment. - * @param {Array|string} path The path of the property to set. - * @param {*} value The value to set. - * @returns {Object} Returns `object`. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }] }; - * - * _.set(object, 'a[0].b.c', 4); - * console.log(object.a[0].b.c); - * // => 4 - * - * _.set(object, 'x[0].y.z', 5); - * console.log(object.x[0].y.z); - * // => 5 - */ - function set(object, path, value) { - if (object == null) { - return object; - } - var pathKey = (path + ''); - path = (object[pathKey] != null || isKey(path, object)) ? [pathKey] : toPath(path); - - var index = -1, - length = path.length, - lastIndex = length - 1, - nested = object; - - while (nested != null && ++index < length) { - var key = path[index]; - if (isObject(nested)) { - if (index == lastIndex) { - nested[key] = value; - } else if (nested[key] == null) { - nested[key] = isIndex(path[index + 1]) ? [] : {}; - } - } - nested = nested[key]; - } - return object; - } - - /** - * An alternative to `_.reduce`; this method transforms `object` to a new - * `accumulator` object which is the result of running each of its own enumerable - * properties through `iteratee`, with each invocation potentially mutating - * the `accumulator` object. The `iteratee` is bound to `thisArg` and invoked - * with four arguments: (accumulator, value, key, object). Iteratee functions - * may exit iteration early by explicitly returning `false`. - * - * @static - * @memberOf _ - * @category Object - * @param {Array|Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [accumulator] The custom accumulator value. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {*} Returns the accumulated value. - * @example - * - * _.transform([2, 3, 4], function(result, n) { - * result.push(n *= n); - * return n % 2 == 0; - * }); - * // => [4, 9] - * - * _.transform({ 'a': 1, 'b': 2 }, function(result, n, key) { - * result[key] = n * 3; - * }); - * // => { 'a': 3, 'b': 6 } - */ - function transform(object, iteratee, accumulator, thisArg) { - var isArr = isArray(object) || isTypedArray(object); - iteratee = getCallback(iteratee, thisArg, 4); - - if (accumulator == null) { - if (isArr || isObject(object)) { - var Ctor = object.constructor; - if (isArr) { - accumulator = isArray(object) ? new Ctor : []; - } else { - accumulator = baseCreate(isFunction(Ctor) ? Ctor.prototype : undefined); - } - } else { - accumulator = {}; - } - } - (isArr ? arrayEach : baseForOwn)(object, function(value, index, object) { - return iteratee(accumulator, value, index, object); - }); - return accumulator; - } - - /** - * Creates an array of the own enumerable property values of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property values. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.values(new Foo); - * // => [1, 2] (iteration order is not guaranteed) - * - * _.values('hi'); - * // => ['h', 'i'] - */ - function values(object) { - return baseValues(object, keys(object)); - } - - /** - * Creates an array of the own and inherited enumerable property values - * of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property values. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.valuesIn(new Foo); - * // => [1, 2, 3] (iteration order is not guaranteed) - */ - function valuesIn(object) { - return baseValues(object, keysIn(object)); - } - - /*------------------------------------------------------------------------*/ - - /** - * Checks if `n` is between `start` and up to but not including, `end`. If - * `end` is not specified it's set to `start` with `start` then set to `0`. - * - * @static - * @memberOf _ - * @category Number - * @param {number} n The number to check. - * @param {number} [start=0] The start of the range. - * @param {number} end The end of the range. - * @returns {boolean} Returns `true` if `n` is in the range, else `false`. - * @example - * - * _.inRange(3, 2, 4); - * // => true - * - * _.inRange(4, 8); - * // => true - * - * _.inRange(4, 2); - * // => false - * - * _.inRange(2, 2); - * // => false - * - * _.inRange(1.2, 2); - * // => true - * - * _.inRange(5.2, 4); - * // => false - */ - function inRange(value, start, end) { - start = +start || 0; - if (end === undefined) { - end = start; - start = 0; - } else { - end = +end || 0; - } - return value >= nativeMin(start, end) && value < nativeMax(start, end); - } - - /** - * Produces a random number between `min` and `max` (inclusive). If only one - * argument is provided a number between `0` and the given number is returned. - * If `floating` is `true`, or either `min` or `max` are floats, a floating-point - * number is returned instead of an integer. - * - * @static - * @memberOf _ - * @category Number - * @param {number} [min=0] The minimum possible value. - * @param {number} [max=1] The maximum possible value. - * @param {boolean} [floating] Specify returning a floating-point number. - * @returns {number} Returns the random number. - * @example - * - * _.random(0, 5); - * // => an integer between 0 and 5 - * - * _.random(5); - * // => also an integer between 0 and 5 - * - * _.random(5, true); - * // => a floating-point number between 0 and 5 - * - * _.random(1.2, 5.2); - * // => a floating-point number between 1.2 and 5.2 - */ - function random(min, max, floating) { - if (floating && isIterateeCall(min, max, floating)) { - max = floating = undefined; - } - var noMin = min == null, - noMax = max == null; - - if (floating == null) { - if (noMax && typeof min == 'boolean') { - floating = min; - min = 1; - } - else if (typeof max == 'boolean') { - floating = max; - noMax = true; - } - } - if (noMin && noMax) { - max = 1; - noMax = false; - } - min = +min || 0; - if (noMax) { - max = min; - min = 0; - } else { - max = +max || 0; - } - if (floating || min % 1 || max % 1) { - var rand = nativeRandom(); - return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand + '').length - 1)))), max); - } - return baseRandom(min, max); - } - - /*------------------------------------------------------------------------*/ - - /** - * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase). - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the camel cased string. - * @example - * - * _.camelCase('Foo Bar'); - * // => 'fooBar' - * - * _.camelCase('--foo-bar'); - * // => 'fooBar' - * - * _.camelCase('__foo_bar__'); - * // => 'fooBar' - */ - var camelCase = createCompounder(function(result, word, index) { - word = word.toLowerCase(); - return result + (index ? (word.charAt(0).toUpperCase() + word.slice(1)) : word); - }); - - /** - * Capitalizes the first character of `string`. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to capitalize. - * @returns {string} Returns the capitalized string. - * @example - * - * _.capitalize('fred'); - * // => 'Fred' - */ - function capitalize(string) { - string = baseToString(string); - return string && (string.charAt(0).toUpperCase() + string.slice(1)); - } - - /** - * Deburrs `string` by converting [latin-1 supplementary letters](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table) - * to basic latin letters and removing [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks). - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to deburr. - * @returns {string} Returns the deburred string. - * @example - * - * _.deburr('déjà vu'); - * // => 'deja vu' - */ - function deburr(string) { - string = baseToString(string); - return string && string.replace(reLatin1, deburrLetter).replace(reComboMark, ''); - } - - /** - * Checks if `string` ends with the given target string. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to search. - * @param {string} [target] The string to search for. - * @param {number} [position=string.length] The position to search from. - * @returns {boolean} Returns `true` if `string` ends with `target`, else `false`. - * @example - * - * _.endsWith('abc', 'c'); - * // => true - * - * _.endsWith('abc', 'b'); - * // => false - * - * _.endsWith('abc', 'b', 2); - * // => true - */ - function endsWith(string, target, position) { - string = baseToString(string); - target = (target + ''); - - var length = string.length; - position = position === undefined - ? length - : nativeMin(position < 0 ? 0 : (+position || 0), length); - - position -= target.length; - return position >= 0 && string.indexOf(target, position) == position; - } - - /** - * Converts the characters "&", "<", ">", '"', "'", and "\`", in `string` to - * their corresponding HTML entities. - * - * **Note:** No other characters are escaped. To escape additional characters - * use a third-party library like [_he_](https://mths.be/he). - * - * Though the ">" character is escaped for symmetry, characters like - * ">" and "/" don't need escaping in HTML and have no special meaning - * unless they're part of a tag or unquoted attribute value. - * See [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands) - * (under "semi-related fun fact") for more details. - * - * Backticks are escaped because in Internet Explorer < 9, they can break out - * of attribute values or HTML comments. See [#59](https://html5sec.org/#59), - * [#102](https://html5sec.org/#102), [#108](https://html5sec.org/#108), and - * [#133](https://html5sec.org/#133) of the [HTML5 Security Cheatsheet](https://html5sec.org/) - * for more details. - * - * When working with HTML you should always [quote attribute values](http://wonko.com/post/html-escaping) - * to reduce XSS vectors. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to escape. - * @returns {string} Returns the escaped string. - * @example - * - * _.escape('fred, barney, & pebbles'); - * // => 'fred, barney, & pebbles' - */ - function escape(string) { - // Reset `lastIndex` because in IE < 9 `String#replace` does not. - string = baseToString(string); - return (string && reHasUnescapedHtml.test(string)) - ? string.replace(reUnescapedHtml, escapeHtmlChar) - : string; - } - - /** - * Escapes the `RegExp` special characters "\", "/", "^", "$", ".", "|", "?", - * "*", "+", "(", ")", "[", "]", "{" and "}" in `string`. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to escape. - * @returns {string} Returns the escaped string. - * @example - * - * _.escapeRegExp('[lodash](https://lodash.com/)'); - * // => '\[lodash\]\(https:\/\/lodash\.com\/\)' - */ - function escapeRegExp(string) { - string = baseToString(string); - return (string && reHasRegExpChars.test(string)) - ? string.replace(reRegExpChars, escapeRegExpChar) - : (string || '(?:)'); - } - - /** - * Converts `string` to [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles). - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the kebab cased string. - * @example - * - * _.kebabCase('Foo Bar'); - * // => 'foo-bar' - * - * _.kebabCase('fooBar'); - * // => 'foo-bar' - * - * _.kebabCase('__foo_bar__'); - * // => 'foo-bar' - */ - var kebabCase = createCompounder(function(result, word, index) { - return result + (index ? '-' : '') + word.toLowerCase(); - }); - - /** - * Pads `string` on the left and right sides if it's shorter than `length`. - * Padding characters are truncated if they can't be evenly divided by `length`. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to pad. - * @param {number} [length=0] The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padded string. - * @example - * - * _.pad('abc', 8); - * // => ' abc ' - * - * _.pad('abc', 8, '_-'); - * // => '_-abc_-_' - * - * _.pad('abc', 3); - * // => 'abc' - */ - function pad(string, length, chars) { - string = baseToString(string); - length = +length; - - var strLength = string.length; - if (strLength >= length || !nativeIsFinite(length)) { - return string; - } - var mid = (length - strLength) / 2, - leftLength = nativeFloor(mid), - rightLength = nativeCeil(mid); - - chars = createPadding('', rightLength, chars); - return chars.slice(0, leftLength) + string + chars; - } - - /** - * Pads `string` on the left side if it's shorter than `length`. Padding - * characters are truncated if they exceed `length`. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to pad. - * @param {number} [length=0] The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padded string. - * @example - * - * _.padLeft('abc', 6); - * // => ' abc' - * - * _.padLeft('abc', 6, '_-'); - * // => '_-_abc' - * - * _.padLeft('abc', 3); - * // => 'abc' - */ - var padLeft = createPadDir(); - - /** - * Pads `string` on the right side if it's shorter than `length`. Padding - * characters are truncated if they exceed `length`. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to pad. - * @param {number} [length=0] The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padded string. - * @example - * - * _.padRight('abc', 6); - * // => 'abc ' - * - * _.padRight('abc', 6, '_-'); - * // => 'abc_-_' - * - * _.padRight('abc', 3); - * // => 'abc' - */ - var padRight = createPadDir(true); - - /** - * Converts `string` to an integer of the specified radix. If `radix` is - * `undefined` or `0`, a `radix` of `10` is used unless `value` is a hexadecimal, - * in which case a `radix` of `16` is used. - * - * **Note:** This method aligns with the [ES5 implementation](https://es5.github.io/#E) - * of `parseInt`. - * - * @static - * @memberOf _ - * @category String - * @param {string} string The string to convert. - * @param {number} [radix] The radix to interpret `value` by. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {number} Returns the converted integer. - * @example - * - * _.parseInt('08'); - * // => 8 - * - * _.map(['6', '08', '10'], _.parseInt); - * // => [6, 8, 10] - */ - function parseInt(string, radix, guard) { - // Firefox < 21 and Opera < 15 follow ES3 for `parseInt`. - // Chrome fails to trim leading whitespace characters. - // See https://code.google.com/p/v8/issues/detail?id=3109 for more details. - if (guard ? isIterateeCall(string, radix, guard) : radix == null) { - radix = 0; - } else if (radix) { - radix = +radix; - } - string = trim(string); - return nativeParseInt(string, radix || (reHasHexPrefix.test(string) ? 16 : 10)); - } - - /** - * Repeats the given string `n` times. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to repeat. - * @param {number} [n=0] The number of times to repeat the string. - * @returns {string} Returns the repeated string. - * @example - * - * _.repeat('*', 3); - * // => '***' - * - * _.repeat('abc', 2); - * // => 'abcabc' - * - * _.repeat('abc', 0); - * // => '' - */ - function repeat(string, n) { - var result = ''; - string = baseToString(string); - n = +n; - if (n < 1 || !string || !nativeIsFinite(n)) { - return result; - } - // Leverage the exponentiation by squaring algorithm for a faster repeat. - // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details. - do { - if (n % 2) { - result += string; - } - n = nativeFloor(n / 2); - string += string; - } while (n); - - return result; - } - - /** - * Converts `string` to [snake case](https://en.wikipedia.org/wiki/Snake_case). - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the snake cased string. - * @example - * - * _.snakeCase('Foo Bar'); - * // => 'foo_bar' - * - * _.snakeCase('fooBar'); - * // => 'foo_bar' - * - * _.snakeCase('--foo-bar'); - * // => 'foo_bar' - */ - var snakeCase = createCompounder(function(result, word, index) { - return result + (index ? '_' : '') + word.toLowerCase(); - }); - - /** - * Converts `string` to [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage). - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the start cased string. - * @example - * - * _.startCase('--foo-bar'); - * // => 'Foo Bar' - * - * _.startCase('fooBar'); - * // => 'Foo Bar' - * - * _.startCase('__foo_bar__'); - * // => 'Foo Bar' - */ - var startCase = createCompounder(function(result, word, index) { - return result + (index ? ' ' : '') + (word.charAt(0).toUpperCase() + word.slice(1)); - }); - - /** - * Checks if `string` starts with the given target string. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to search. - * @param {string} [target] The string to search for. - * @param {number} [position=0] The position to search from. - * @returns {boolean} Returns `true` if `string` starts with `target`, else `false`. - * @example - * - * _.startsWith('abc', 'a'); - * // => true - * - * _.startsWith('abc', 'b'); - * // => false - * - * _.startsWith('abc', 'b', 1); - * // => true - */ - function startsWith(string, target, position) { - string = baseToString(string); - position = position == null - ? 0 - : nativeMin(position < 0 ? 0 : (+position || 0), string.length); - - return string.lastIndexOf(target, position) == position; - } - - /** - * Creates a compiled template function that can interpolate data properties - * in "interpolate" delimiters, HTML-escape interpolated data properties in - * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data - * properties may be accessed as free variables in the template. If a setting - * object is provided it takes precedence over `_.templateSettings` values. - * - * **Note:** In the development build `_.template` utilizes - * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) - * for easier debugging. - * - * For more information on precompiling templates see - * [lodash's custom builds documentation](https://lodash.com/custom-builds). - * - * For more information on Chrome extension sandboxes see - * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval). - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The template string. - * @param {Object} [options] The options object. - * @param {RegExp} [options.escape] The HTML "escape" delimiter. - * @param {RegExp} [options.evaluate] The "evaluate" delimiter. - * @param {Object} [options.imports] An object to import into the template as free variables. - * @param {RegExp} [options.interpolate] The "interpolate" delimiter. - * @param {string} [options.sourceURL] The sourceURL of the template's compiled source. - * @param {string} [options.variable] The data object variable name. - * @param- {Object} [otherOptions] Enables the legacy `options` param signature. - * @returns {Function} Returns the compiled template function. - * @example - * - * // using the "interpolate" delimiter to create a compiled template - * var compiled = _.template('hello <%= user %>!'); - * compiled({ 'user': 'fred' }); - * // => 'hello fred!' - * - * // using the HTML "escape" delimiter to escape data property values - * var compiled = _.template('<%- value %>'); - * compiled({ 'value': ' - + diff --git a/perf/perf.js b/perf/perf.js index da375fbb7a..27b291dbac 100644 --- a/perf/perf.js +++ b/perf/perf.js @@ -38,7 +38,7 @@ result = params; } var last = result[result.length - 1]; - result = (result.length > min && !/perf(?:\.js)?$/.test(last)) ? last : '../lodash.src.js'; + result = (result.length > min && !/perf(?:\.js)?$/.test(last)) ? last : '../lodash.js'; if (!amd) { try { diff --git a/perf/run-perf.sh b/perf/run-perf.sh index c219fd18a6..eaa63ae4c4 100755 --- a/perf/run-perf.sh +++ b/perf/run-perf.sh @@ -6,7 +6,7 @@ node perf.js ../lodash.js && node perf.js ../lodash.min.js for cmd in rhino "rhino -require" narwhal ringo phantomjs; do echo "" echo "Running performance suite in $cmd..." - $cmd perf.js ../lodash.src.js + $cmd perf.js ../lodash.min.js done echo "" diff --git a/test/asset/test-ui.js b/test/asset/test-ui.js index f5b9eed2b9..c3167c5f1b 100644 --- a/test/asset/test-ui.js +++ b/test/asset/test-ui.js @@ -64,12 +64,10 @@ buildList.selectedIndex = (function() { switch (build) { - case 'lodash-compat': return 1; - case 'lodash-modern-dev': return 2; - case 'lodash-modern': return 3; - case 'lodash-custom-dev': return 4; - case 'lodash-custom': return 5; - case 'lodash-compat-dev': + case 'lodash': return 1; + case 'lodash-custom-dev': return 2; + case 'lodash-custom': return 3; + case 'lodash-dev': case null: return 0; } return -1; @@ -95,10 +93,8 @@ span1.innerHTML = '' + ''; @@ -140,13 +136,11 @@ ui.buildPath = (function() { var result; switch (build) { - case 'lodash-compat': result = 'lodash.compat.min.js'; break; - case 'lodash-modern-dev': result = 'lodash.js'; break; - case 'lodash-modern': result = 'lodash.min.js'; break; + case 'lodash': result = 'lodash.min.js'; break; case 'lodash-custom-dev': result = 'lodash.custom.js'; break; case 'lodash-custom': result = 'lodash.custom.min.js'; break; - case null: build = 'lodash-compat-dev'; - case 'lodash-compat-dev': result = 'lodash.src.js'; break; + case null: build = 'lodash-dev'; + case 'lodash-dev': result = 'lodash.js'; break; default: return build; } return basePath + result; diff --git a/test/backbone.html b/test/backbone.html index b01da499e1..6c037bb1a6 100644 --- a/test/backbone.html +++ b/test/backbone.html @@ -22,7 +22,7 @@ - + + + + + - -
@@ -107,12 +105,15 @@ if (window._Set) { Set = _Set; + } else { + setProperty(window, 'Set', undefined); } - setProperty(window, '_Set', undefined); - if (window._WeakMap) { WeakMap = _WeakMap; + } else { + setProperty(window, 'WeakMap', undefined); } + setProperty(window, '_Set', undefined); setProperty(window, '_WeakMap', undefined); setProperty(window, 'WinRTError', undefined); diff --git a/test/test.js b/test/test.js index c1e1c6ae3b..7716092857 100644 --- a/test/test.js +++ b/test/test.js @@ -215,8 +215,6 @@ /** Load QUnit Extras and ES6 Set/WeakMap shims. */ (function() { var paths = [ - './asset/set.js', - './asset/weakmap.js', '../node_modules/qunit-extras/qunit-extras.js' ]; From 830be3d918d0054981989a474f84f715302d3d79 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Wed, 2 Sep 2015 20:06:14 -0700 Subject: [PATCH 233/935] Add strict mode test for `_.isArguments`. --- test/test.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/test.js b/test/test.js index 7716092857..80af296ebd 100644 --- a/test/test.js +++ b/test/test.js @@ -6084,10 +6084,12 @@ QUnit.module('lodash.isArguments'); (function() { - var args = arguments; + var args = (function() { return arguments; }(1, 2, 3)), + strictArgs = (function() { 'use strict'; return arguments; }(1, 2, 3)); - test('should return `true` for `arguments` objects', 1, function() { + test('should return `true` for `arguments` objects', 2, function() { strictEqual(_.isArguments(args), true); + strictEqual(_.isArguments(strictArgs), true); }); test('should return `false` for non `arguments` objects', 12, function() { @@ -6120,7 +6122,7 @@ skipTest(); } }); - }(1, 2, 3)); + }()); /*--------------------------------------------------------------------------*/ From fce2bd89c7c5865a08ed81cd51fc413319b7a458 Mon Sep 17 00:00:00 2001 From: Ray Hammond Date: Wed, 2 Sep 2015 21:49:44 +0100 Subject: [PATCH 234/935] Added jscs code style checker. --- .jscsrc | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lodash.js | 10 +++--- package.json | 6 +++- 3 files changed, 98 insertions(+), 6 deletions(-) create mode 100644 .jscsrc diff --git a/.jscsrc b/.jscsrc new file mode 100644 index 0000000000..7cdd0fa4b3 --- /dev/null +++ b/.jscsrc @@ -0,0 +1,88 @@ +{ + "maxErrors": "2000", + "requireCurlyBraces": [ + "if", + "else", + "for", + "while", + "do", + "try", + "catch" + ], + "requireOperatorBeforeLineBreak": [ + "=", + "+", + "-", + "/", + "*", + "==", + "===", + "!=", + "!==", + ">", + ">=", + "<", + "<=" + ], + "requireCamelCaseOrUpperCaseIdentifiers": true, + "maximumLineLength": false, + "validateIndentation": 2, + + "disallowMultipleLineStrings": true, + "disallowMixedSpacesAndTabs": true, + "disallowTrailingWhitespace": true, + "disallowSpaceAfterPrefixUnaryOperators": true, + "disallowMultipleVarDecl": false, + "disallowKeywordsOnNewLine": false, + + "requireSpaceAfterKeywords": [ + "if", + "else", + "for", + "while", + "do", + "switch", + "return", + "try", + "catch" + ], + "requireSpaceBeforeBinaryOperators": [ + "=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=", + "&=", "|=", "^=", "+=", + + "+", "-", "*", "/", "%", "<<", ">>", ">>>", "&", + "|", "^", "&&", "||", "===", "==", ">=", + "<=", "<", ">", "!=", "!==" + ], + "requireSpaceAfterBinaryOperators": true, + "requireSpacesInConditionalExpression": true, + "requireSpaceBeforeBlockStatements": true, + "requireSpacesInForStatement": true, + "requireLineFeedAtFileEnd": true, + "requireSpacesInFunctionExpression": { + "beforeOpeningCurlyBrace": true + }, + "disallowSpacesInAnonymousFunctionExpression": { + "beforeOpeningRoundBrace": true + }, + "disallowSpacesInsideObjectBrackets": false, + "disallowSpacesInsideArrayBrackets": "all", + "disallowSpacesInsideParentheses": true, + + "disallowMultipleLineBreaks": true, + "disallowNewlineBeforeBlockStatements": true, + "disallowKeywords": ["with"], + "disallowSpacesInFunctionExpression": { + "beforeOpeningRoundBrace": true + }, + "disallowSpacesInFunctionDeclaration": { + "beforeOpeningRoundBrace": true + }, + "disallowSpacesInCallExpression": true, + "disallowSpaceAfterObjectKeys": true, + "requireSpaceBeforeObjectValues": true, + "requireCapitalizedConstructors": false, + "requireDotNotation": false, + "requireSemicolons": true, + "validateParameterSeparator": ", " +} diff --git a/lodash.js b/lodash.js index d6ccc3e7eb..5f9a8f5a18 100644 --- a/lodash.js +++ b/lodash.js @@ -757,7 +757,7 @@ * @returns {Array} Returns the array of results. */ function baseTimes(n, iteratee) { - var index = -1, + var index = -1, result = Array(n); while (++index < n) { @@ -1072,7 +1072,7 @@ if (value != null && typeof value.toString != 'function') { try { result = !!(value + ''); - } catch(e) {} + } catch (e) {} } return result; } @@ -1824,7 +1824,7 @@ length = paths.length, result = Array(length); - while(++index < length) { + while (++index < length) { result[index] = isNil ? undefined : get(object, paths[index]); } return result; @@ -10842,7 +10842,7 @@ var attempt = restParam(function(func, args) { try { return func.apply(undefined, args); - } catch(e) { + } catch (e) { return isError(e) ? e : new Error(e); } }); @@ -12068,8 +12068,8 @@ if (moduleExports) { (freeModule.exports = _)._ = _; } - // Export for Rhino with CommonJS support. else { + // Export for Rhino with CommonJS support. freeExports._ = _; } } diff --git a/package.json b/package.json index fdf85ddea7..a1fae2e644 100644 --- a/package.json +++ b/package.json @@ -7,12 +7,16 @@ "curl-amd": "0.8.12", "dojo": "~1.10.0", "jquery": "~1.11.0", + "jscs": "^2.1.1", "platform": "~1.3.0", "qunit-extras": "~1.4.0", "qunitjs": "~1.18.0", "requirejs": "~2.1.0" }, - "scripts": { "test": "node test/test" }, + "scripts": { + "test": "node test/test", + "lint": "jscs lodash.js" + }, "volo": { "type": "directory", "ignore": [ From 51006e8304b48cfb1d8bdad1092dc130c44803f6 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 3 Sep 2015 08:22:33 -0700 Subject: [PATCH 235/935] Tweak test try-catch style to be consistent with lodash. --- test/test.js | 150 +++++++++++++++++++++++++-------------------------- 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/test/test.js b/test/test.js index 80af296ebd..0334e2c085 100644 --- a/test/test.js +++ b/test/test.js @@ -73,7 +73,7 @@ var o = {}, func = Object.defineProperty, result = func(o, o, o) && func; - } catch(e) {} + } catch (e) {} return result; }()); @@ -99,11 +99,11 @@ if (!amd) { try { result = require('fs').realpathSync(result); - } catch(e) {} + } catch (e) {} try { result = require.resolve(result); - } catch(e) {} + } catch (e) {} } return result; }()); @@ -190,7 +190,7 @@ /** Used to test host objects in IE. */ try { var xml = new ActiveXObject('Microsoft.XMLDOM'); - } catch(e) {} + } catch (e) {} /** Poison the free variable `root` in Node.js */ try { @@ -199,7 +199,7 @@ 'enumerable': false, 'get': function() { throw new ReferenceError; } }); - } catch(e) {} + } catch (e) {} /** Use a single "load" function. */ var load = (!amd && typeof require == 'function') @@ -362,7 +362,7 @@ 'writable': true, 'value': value }); - } catch(e) { + } catch (e) { object[key] = value; } } @@ -617,7 +617,7 @@ if (lodashBizarro) { try { var actual = _.keysIn(new Foo).sort(); - } catch(e) { + } catch (e) { actual = null; } deepEqual(actual, ['a', 'b'], message('_.keysIn', 'Object#propertyIsEnumerable')); @@ -628,7 +628,7 @@ lodashBizarro.intersection(largeArray, [object]), lodashBizarro.uniq(largeArray) ]; - } catch(e) { + } catch (e) { actual = null; } deepEqual(actual, [[otherObject], [object], [object]], message('_.difference`, `_.intersection`, and `_.uniq', 'Set')); @@ -721,7 +721,7 @@ if (func) { try { var actual = func(1, { 'toString': null }, [1]); - } catch(e) { + } catch (e) { var message = e.message; } strictEqual(actual, false, message || ''); @@ -909,7 +909,7 @@ try { var actual = capped('a'); - } catch(e) {} + } catch (e) {} deepEqual(actual, []); }); @@ -1052,7 +1052,7 @@ var actual = _.map(falsey, function(object) { try { return _.at(object, 0, 1, 'pop', 'push'); - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -1203,7 +1203,7 @@ try { var bound = _.bind(fn, value); return bound(); - } catch(e) {} + } catch (e) {} }); ok(_.every(actual, function(value, index) { @@ -1297,7 +1297,7 @@ case 7: return (new bound(1, 2, 3, 4, 5, 6, 7)).a; case 8: return (new bound(1, 2, 3, 4, 5, 6, 7, 8)).a; } - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -1342,7 +1342,7 @@ try { var actual = new Ctor(2012, 4, 23, 0, 0, 0, 0); - } catch(e) {} + } catch (e) {} deepEqual(actual, expected); @@ -1350,7 +1350,7 @@ try { actual = new Ctor(0, 0, 0, 0); - } catch(e) {} + } catch (e) {} deepEqual(actual, expected); }); @@ -1375,7 +1375,7 @@ case 6: return !!(new bound(1, 2, 3, 4, 5, 6)); case 7: return !!(new bound(1, 2, 3, 4, 5, 6, 7)); } - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -1937,7 +1937,7 @@ try { deepEqual(func(element), {}); - } catch(e) { + } catch (e) { ok(false, e.message); } } @@ -2096,7 +2096,7 @@ try { strictEqual(combined('a'), 'a'); - } catch(e) { + } catch (e) { ok(false, e.message); } strictEqual(combined.length, 0); @@ -2637,7 +2637,7 @@ try { var actual = curried(1)(2); - } catch(e) {} + } catch (e) {} strictEqual(actual, 3); }); @@ -3622,7 +3622,7 @@ var actual = _.map(empties, function(value) { try { return _.every(value, _.identity); - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -3693,7 +3693,7 @@ try { func(object, isBindAll ? 'b' : { 'a': 1 }); - } catch(e) { + } catch (e) { pass = !pass; } ok(pass); @@ -3916,7 +3916,7 @@ var actual = _.map(emptyValues, function(value) { try { return func(value, { 'a': 3 }); - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expecting); @@ -4500,7 +4500,7 @@ actual = _.flatten(expected); } deepEqual(actual, expected); - } catch(e) { + } catch (e) { ok(false, e.message); } } @@ -5010,7 +5010,7 @@ test('`_.' + methodName + '` should not error on nullish sources', 1, function() { try { deepEqual(func({ 'a': 1 }, undefined, { 'b': 2 }, null), { 'a': 1, 'b': 2 }); - } catch(e) { + } catch (e) { ok(false, e.message); } }); @@ -5021,7 +5021,7 @@ var actual = _.map([null, undefined], function(value) { try { return _.isEqual(func(value, { 'a': 1 }), {}); - } catch(e) { + } catch (e) { return false; } }); @@ -5572,7 +5572,7 @@ var actual = _.map(empties, function(value) { try { return _.includes(value); - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -5781,7 +5781,7 @@ var actual = _.map(falsey, function(array, index) { try { return index ? _.initial(array) : _.initial(); - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -6051,7 +6051,7 @@ try { var actual = _.invoke(array, 'toUpperCase'); - } catch(e) {} + } catch (e) {} deepEqual(_.invoke(array, 'toUpperCase'), ['A', undefined, undefined, 'D']); }); @@ -6065,7 +6065,7 @@ try { var actual = _.invoke(objects, 'a'); - } catch(e) {} + } catch (e) {} deepEqual(actual, expected); }); @@ -6891,7 +6891,7 @@ try { strictEqual(_.isEqual(element1, element2), false); - } catch(e) { + } catch (e) { ok(false, e.message); } } @@ -7301,7 +7301,7 @@ var actual = _.map(values, function(value) { try { return _.isMatch(value, source); - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -7360,7 +7360,7 @@ var actual = _.map(values, function(value) { try { return _.isMatch(value, source); - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -8146,7 +8146,7 @@ try { _[methodName](xml); - } catch(e) { + } catch (e) { pass = false; } ok(pass, '`_.' + methodName + '` should not error'); @@ -9057,7 +9057,7 @@ var actual = _.map(falsey, function(array, index) { try { return index ? func(array) : func(); - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -9165,7 +9165,7 @@ var actual = _.map(falsey, function(collection, index) { try { return index ? _.map(collection) : _.map(); - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -9311,7 +9311,7 @@ var actual = _.map(falsey, function(object, index) { try { return index ? func(object) : func(); - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -9396,7 +9396,7 @@ var actual = _.map(values, function(value, index) { try { return index ? matches(value) : matches(); - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -9477,7 +9477,7 @@ var actual = _.map(values, function(value, index) { try { return index ? matches(value) : matches(); - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -9538,20 +9538,20 @@ try { var matches = _.matches({ 'b': undefined }); strictEqual(matches(1), true); - } catch(e) { + } catch (e) { ok(false, e.message); } try { matches = _.matches({ 'a': 1, 'b': undefined }); strictEqual(matches(1), true); - } catch(e) { + } catch (e) { ok(false, e.message); } numberProto.a = { 'b': 1, 'c': undefined }; try { matches = _.matches({ 'a': { 'c': undefined } }); strictEqual(matches(1), true); - } catch(e) { + } catch (e) { ok(false, e.message); } delete numberProto.a; @@ -9717,7 +9717,7 @@ var actual = _.map(values, function(value, index) { try { return index ? matches(value) : matches(); - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -9734,7 +9734,7 @@ var actual = _.map(values, function(value, index) { try { return index ? matches(value) : matches(); - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -9843,14 +9843,14 @@ try { var matches = _.matchesProperty('b', undefined); strictEqual(matches(1), true); - } catch(e) { + } catch (e) { ok(false, e.message); } numberProto.a = { 'b': 1, 'c': undefined }; try { matches = _.matchesProperty('a', { 'c': undefined }); strictEqual(matches(1), true); - } catch(e) { + } catch (e) { ok(false, e.message); } delete numberProto.a; @@ -9896,7 +9896,7 @@ var actual = _.map(values, function(value, index) { try { return index ? _.max(value) : _.max(); - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -9939,7 +9939,7 @@ var actual = _.map(falsey, function(resolver, index) { try { return _.isFunction(index ? _.memoize(_.noop, resolver) : _.memoize(_.noop)); - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -10300,7 +10300,7 @@ var actual = _.map(pairs, function(pair) { try { return _.merge(pair[0], pair[1]).el === pair[1].el; - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -10689,7 +10689,7 @@ var actual = _.map(values, function(value, index) { try { return index ? _.min(value) : _.min(); - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -10929,7 +10929,7 @@ try { _.mixin({}, source, 1); - } catch(e) { + } catch (e) { pass = false; } ok(pass); @@ -10938,7 +10938,7 @@ try { _.mixin(source, 1); - } catch(e) { + } catch (e) { pass = false; } delete _.a; @@ -11274,7 +11274,7 @@ try { once(); - } catch(e) { + } catch (e) { pass = false; } ok(pass); @@ -12294,7 +12294,7 @@ var actual = _.map(values, function(array) { try { return _.pullAt(array, 0, 1, 'pop', 'push'); - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -12651,7 +12651,7 @@ _.each(empties, function(value) { try { actual.push(func(value, _.noop)); - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -12663,7 +12663,7 @@ var actual = _.map(empties, function(value) { try { return func(value, _.noop, 'x'); - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -13113,7 +13113,7 @@ var actual = _.map(falsey, function(array, index) { try { return index ? _.rest(array) : _.rest(); - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -13394,7 +13394,7 @@ _.each(empties, function(value) { try { actual.push(_.sample(value), _.sample(value, 1)); - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -13591,7 +13591,7 @@ var actual = _.map(values, function(value) { try { return [func(value, 'a.b', 1), func(value, ['a', 'b'], 1)]; - } catch(e) { + } catch (e) { return e.message; } }); @@ -13623,7 +13623,7 @@ try { func(0, path, 1); strictEqual(0..a, 0); - } catch(e) { + } catch (e) { ok(false, e.message); } numberProto.a = 0; @@ -13712,7 +13712,7 @@ var actual = _.map(falsey, function(object, index) { try { return index ? _.size(object) : _.size(); - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -13891,7 +13891,7 @@ var actual = _.map(empties, function(value) { try { return _.some(value, _.identity); - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -14100,7 +14100,7 @@ test('`_.' + methodName + '` should not error on nullish elements', 1, function() { try { var actual = func(objects.concat(null, undefined), ['a', 'b']); - } catch(e) {} + } catch (e) {} deepEqual(actual, [objects[2], objects[0], objects[3], objects[1], null, undefined]); }); @@ -14549,7 +14549,7 @@ try { var actual = compiled(); - } catch(e) {} + } catch (e) {} strictEqual(actual, 'function'); }); @@ -14671,7 +14671,7 @@ try { strictEqual(compiled(data), '123'); - } catch(e) { + } catch (e) { ok(false, e.message); } }); @@ -14748,7 +14748,7 @@ /*@cc_on @*/ try { compiled(); - } catch(e) { + } catch (e) { pass = false; } ok(pass); @@ -14832,7 +14832,7 @@ try { _.template('')(1); - } catch(e) { + } catch (e) { pass = false; } ok(pass, '`data` value'); @@ -14841,7 +14841,7 @@ try { _.template('', 1)(1); - } catch(e) { + } catch (e) { pass = false; } ok(pass, '`options` value'); @@ -14862,7 +14862,7 @@ test('should expose the source when a SyntaxError occurs', 1, function() { try { _.template('<% if x %>'); - } catch(e) { + } catch (e) { var source = e.source; } ok(_.includes(source, '__p')); @@ -14875,7 +14875,7 @@ try { _.template('<% if x %>', options); - } catch(e) { + } catch (e) { values[1] = e.source; } var expected = _.map(values, _.constant(false)); @@ -15204,7 +15204,7 @@ try { func(_.noop, 32, 1); - } catch(e) { + } catch (e) { pass = false; } ok(pass); @@ -15516,7 +15516,7 @@ if (document) { try { var actual = func(document.getElementsByTagName('body')); - } catch(e) {} + } catch (e) {} deepEqual(actual, [body]); } @@ -16370,7 +16370,7 @@ var actual = _.map(falsey, function(array, index) { try { return index ? _.zipObject(array) : _.zipObject(); - } catch(e) {} + } catch (e) {} }); deepEqual(actual, expected); @@ -16868,7 +16868,7 @@ try { var wrapped = _(array).slice(1).map(String).reverse(), actual = wrapped.last(); - } catch(e) {} + } catch (e) {} ok(wrapped instanceof _); strictEqual(actual, '1'); @@ -17449,7 +17449,7 @@ var actual = _.map(falsey, function(value, index) { try { return index ? func(value) : func(); - } catch(e) { + } catch (e) { pass = false; } }); @@ -17508,7 +17508,7 @@ try { index ? func(value) : func(); - } catch(e) { + } catch (e) { pass = _.includes(checkFuncs, methodName) ? e.message == FUNC_ERROR_TEXT : !pass; From 8e9f9f6f2fc93a30eb333a547d78432422a70dc6 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 3 Sep 2015 08:47:08 -0700 Subject: [PATCH 236/935] Detect maps and sets in IE11. --- lodash.js | 68 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 55 insertions(+), 13 deletions(-) diff --git a/lodash.js b/lodash.js index 5f9a8f5a18..90c0c15c62 100644 --- a/lodash.js +++ b/lodash.js @@ -1285,6 +1285,10 @@ // See https://es5.github.io/#x11.1.5 for more details. context = context ? _.defaults({}, context, _.pick(root, contextProps)) : root; + /** Used as references for `-Infinity` and `Infinity`. */ + var NEGATIVE_INFINITY = context.Number.NEGATIVE_INFINITY, + POSITIVE_INFINITY = context.Number.POSITIVE_INFINITY; + /** Native constructor references. */ var Date = context.Date, Error = context.Error, @@ -1320,7 +1324,7 @@ /** Used to detect if a method is native. */ var reIsNative = RegExp('^' + - fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&') + fnToString.call(hasOwnProperty).replace(reRegExpChars, '\\$&') .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' ); @@ -1346,19 +1350,24 @@ nativeFloor = Math.floor, nativeIsFinite = context.isFinite, nativeKeys = Object.keys, + nativeMap = getNative(context, 'Map'), nativeMax = Math.max, nativeMin = Math.min, nativeParseInt = context.parseInt, nativeRandom = Math.random, nativeSet = getNative(context, 'Set'); - /** Used as references for `-Infinity` and `Infinity`. */ - var NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY, - POSITIVE_INFINITY = Number.POSITIVE_INFINITY; - /** Used to store function metadata. */ var metaMap = WeakMap && new WeakMap; + /** Used to detect maps and sets. */ + var mapCtorString = nativeMap ? fnToString.call(nativeMap) : '', + setCtorString = nativeSet ? fnToString.call(nativeSet) : ''; + + /** Detect support for map and set `toStringTag` values. */ + var noMapSetTag = nativeMap && nativeSet && + !(objToString.call(new Map) == mapTag && objToString.call(new Set) == setTag); + /** Used to lookup unminified function names. */ var realNames = {}; @@ -1865,6 +1874,9 @@ var tag = objToString.call(value), isFunc = tag == funcTag; + if (tag == objectTag && noMapSetTag) { + tag = isMap(value) ? mapTag : (isSet(value) ? setTag : tag); + } if (tag == objectTag || tag == argsTag || (isFunc && !object)) { if (isHostObject(value)) { return object ? value : {}; @@ -2272,17 +2284,21 @@ if (!objIsArr) { objTag = objToString.call(object); - if (objTag == argsTag) { + if (othTag == objectTag && noMapSetTag) { + objTag = isMap(object) ? mapTag : (isSet(object) ? setTag : objTag); + } else if (objTag == argsTag) { objTag = objectTag; - } else if (objTag != objectTag) { + } else { objIsArr = isTypedArray(object); } } if (!othIsArr) { othTag = objToString.call(other); - if (othTag == argsTag) { + if (othTag == objectTag && noMapSetTag) { + othTag = isMap(other) ? mapTag : (isSet(other) ? setTag : othTag); + } else if (othTag == argsTag) { othTag = objectTag; - } else if (othTag != objectTag) { + } else { othIsArr = isTypedArray(other); } } @@ -4132,6 +4148,18 @@ return !!data && func === data[0]; } + /** + * Checks if `value` is classified as a `Map` object. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + */ + function isMap(value) { + var Ctor = value && value.constructor; + return typeof Ctor == 'function' && fnToString.call(Ctor) == mapCtorString; + } + /** * Checks if `value` is a prototype. * @@ -4140,12 +4168,24 @@ * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. */ function isPrototype(value) { - var Ctor = !!value && value.constructor, + var Ctor = value && value.constructor, proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; return value === proto; } + /** + * Checks if `value` is classified as a `Set` object. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + */ + function isSet(value) { + var Ctor = value && value.constructor; + return typeof Ctor == 'function' && fnToString.call(Ctor) == setCtorString; + } + /** * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. * @@ -8754,9 +8794,11 @@ if (iteratorSymbol && value[iteratorSymbol]) { return iteratorToArray(value[iteratorSymbol]()); } - var tag = objToString.call(value), - func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values); - + var tag = objToString.call(value); + if (tag == objectTag && noMapSetTag) { + tag = isMap(value) ? mapTag : (isSet(value) ? setTag : tag); + } + var func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values); return func(value); } From cc77eb7855ad20048ed1eb846585439ef02c441f Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 3 Sep 2015 09:04:26 -0700 Subject: [PATCH 237/935] Change `augment` to `modify`. [ci skip] --- lodash.js | 10 +++++----- test/test.js | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lodash.js b/lodash.js index 90c0c15c62..ceb97a3627 100644 --- a/lodash.js +++ b/lodash.js @@ -573,7 +573,7 @@ * for equality comparisons. * * @private - * @param {Object} object The object to augment. + * @param {Object} object The object to modify. * @param {string} key The key of the property to assign. * @param {*} value The value to assign. */ @@ -589,7 +589,7 @@ * This function is like `assignValue` except that it doesn't assign `undefined` values. * * @private - * @param {Object} object The object to augment. + * @param {Object} object The object to modify. * @param {string} key The key of the property to assign. * @param {*} value The value to assign. */ @@ -4204,7 +4204,7 @@ * Merging metadata reduces the number of wrappers required to invoke a function. * This is possible because methods like `_.bind`, `_.curry`, and `_.partial` * may be applied regardless of execution order. Methods like `_.ary` and `_.rearg` - * augment function arguments, making the order in which they are executed important, + * modify function arguments, making the order in which they are executed important, * preventing the merging of metadata. However, we make an exception for a safe * common case where curried functions have `_.ary` and or `_.rearg` applied. * @@ -9745,7 +9745,7 @@ * @static * @memberOf _ * @category Object - * @param {Object} object The object to augment. + * @param {Object} object The object to modify. * @param {Array|string} path The path of the property to set. * @param {*} value The value to set. * @returns {Object} Returns `object`. @@ -9774,7 +9774,7 @@ * @static * @memberOf _ * @category Object - * @param {Object} object The object to augment. + * @param {Object} object The object to modify. * @param {Array|string} path The path of the property to set. * @param {*} value The value to set. * @param {Function} [customizer] The function to customize assigned values. diff --git a/test/test.js b/test/test.js index 0334e2c085..9bf8d5a7fe 100644 --- a/test/test.js +++ b/test/test.js @@ -350,7 +350,7 @@ * See https://code.google.com/p/v8/issues/detail?id=1623 * * @private - * @param {Object} object The object augment. + * @param {Object} object The object modify. * @param {string} key The name of the property to set. * @param {*} value The property value. */ @@ -8190,7 +8190,7 @@ strictEqual(matches({ 'b': 2 }), false); }); - test('should not change match behavior if `source` is augmented', 9, function() { + test('should not change match behavior if `source` is modified', 9, function() { var sources = [ { 'a': { 'b': 2, 'c': 3 } }, { 'a': 1, 'b': 2 }, @@ -9434,7 +9434,7 @@ strictEqual(matches(object3), false); }); - test('should not change match behavior if `source` is augmented', 9, function() { + test('should not change match behavior if `source` is modified', 9, function() { var sources = [ { 'a': { 'b': 2, 'c': 3 } }, { 'a': 1, 'b': 2 }, @@ -9761,7 +9761,7 @@ strictEqual(matches({ 'a': object3 }), false); }); - test('should not change match behavior if `value` is augmented', 9, function() { + test('should not change match behavior if `value` is modified', 9, function() { _.each([{ 'a': { 'b': 2, 'c': 3 } }, { 'a': 1, 'b': 2 }, { 'a': 1 }], function(source, index) { var object = _.cloneDeep(source), matches = _.matchesProperty('a', source); @@ -14811,7 +14811,7 @@ strictEqual(_.template(object)(data), '1'); }); - test('should not augment the `options` object', 1, function() { + test('should not modify the `options` object', 1, function() { var options = {}; _.template('', options); deepEqual(options, {}); From 085e2c24d3d401636f8515712cda3d382ae59d73 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 3 Sep 2015 09:12:29 -0700 Subject: [PATCH 238/935] Remove weakmap and set shims. --- test/asset/set.js | 157 ------------------------------------------ test/asset/weakmap.js | 102 --------------------------- 2 files changed, 259 deletions(-) delete mode 100644 test/asset/set.js delete mode 100644 test/asset/weakmap.js diff --git a/test/asset/set.js b/test/asset/set.js deleted file mode 100644 index 7b888ed2d7..0000000000 --- a/test/asset/set.js +++ /dev/null @@ -1,157 +0,0 @@ -;(function() { - - /** Used to determine if values are of the language type Object. */ - var objectTypes = { - 'function': true, - 'object': true - }; - - /** Used as the `Set#toString` return value. */ - var nativeString = String(Object.prototype.toString).replace(/toString/g, 'Set'); - - /** Detect free variable `exports`. */ - var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports; - - /** Detect free variable `module`. */ - var freeModule = objectTypes[typeof module] && module && !module.nodeType && module; - - /** Detect free variable `global` from Node.js. */ - var freeGlobal = freeExports && freeModule && typeof global == 'object' && global; - - /** Detect free variable `self`. */ - var freeSelf = objectTypes[typeof self] && self && self.Object && self; - - /** Detect free variable `window`. */ - var freeWindow = objectTypes[typeof window] && window && window.Object && window; - - /** - * Used as a reference to the global object. - * - * The `this` value is used if it is the global object to avoid Greasemonkey's - * restricted `window` object, otherwise the `window` object is used. - */ - var root = freeGlobal || ((freeWindow !== (this && this.window)) && freeWindow) || freeSelf || this; - - /*--------------------------------------------------------------------------*/ - - /** - * Installs `Set` on the given `context` object. - * - * @memberOf exports - * @param {Object} context The context object. - */ - function runInContext(context) { - - /** - * Creates a `Set` object. - */ - function Set() { - this.__cache__ = {}; - } - - /** - * Gets the index at which the first occurrence of `value` is found using - * strict equality for comparisons, i.e. `===`. - * - * @private - * @param {Array} array The array to search. - * @param {*} value The value to search for. - * @returns {number} Returns the index of the matched value or `-1`. - */ - function indexOf(array, value) { - var index = -1, - length = array.length; - - while (++index < length) { - if (array[index] === value) { - return index; - } - } - return -1; - } - - /** - * Checks if `value` is in the set. - * - * @memberOf Set - * @param {*} value The value to search for. - * @returns {boolean} Returns `true` if `value` is found, else `false`. - */ - function has(value) { - var type = typeof value, - cache = this.__cache__; - - if (type == 'boolean' || value == null) { - return cache[value] || false; - } - if (type != 'number' && type != 'string') { - type = 'object'; - } - var key = type == 'number' ? value : '_' + value; - cache = (cache = cache[type]) && cache[key]; - - return type == 'object' - ? (cache && indexOf(cache, value) > -1 ? true : false) - : (cache || false); - } - - /** - * Adds `value` to the set. - * - * @memberOf Set - * @param {*} value The value to add. - */ - function add(value) { - var cache = this.__cache__, - type = typeof value; - - if (type == 'boolean' || value == null) { - cache[value] = true; - } else { - if (type != 'number' && type != 'string') { - type = 'object'; - } - var key = type == 'number' ? value : '_' + value, - typeCache = cache[type] || (cache[type] = {}); - - if (type == 'object') { - var array = typeCache[key]; - if (array) { - array.push(value); - } else { - typeCache[key] = [value]; - } - } else { - typeCache[key] = true; - } - } - } - - /** - * Produces the `toString` result of `Set`. - * - * @static - * @memberOf Set - * @returns {string} Returns the string result. - */ - function toString() { - return nativeString; - } - - Set.toString = toString; - Set.prototype.add = add; - Set.prototype.has = has; - - if (!root.Set) { - context.Set = Set; - } - } - - /*--------------------------------------------------------------------------*/ - - if (freeExports) { - freeExports.runInContext = runInContext; - } else { - runInContext(root); - } -}.call(this)); diff --git a/test/asset/weakmap.js b/test/asset/weakmap.js deleted file mode 100644 index 17ef091202..0000000000 --- a/test/asset/weakmap.js +++ /dev/null @@ -1,102 +0,0 @@ -;(function() { - - /** Used to determine if values are of the language type Object. */ - var objectTypes = { - 'function': true, - 'object': true - }; - - /** Used as the `WeakMap#toString` return value. */ - var nativeString = String(Object.prototype.toString).replace(/toString/g, 'WeakMap'); - - /** Detect free variable `exports`. */ - var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports; - - /** Detect free variable `module`. */ - var freeModule = objectTypes[typeof module] && module && !module.nodeType && module; - - /** Detect free variable `global` from Node.js. */ - var freeGlobal = freeExports && freeModule && typeof global == 'object' && global; - - /** Detect free variable `self`. */ - var freeSelf = objectTypes[typeof self] && self && self.Object && self; - - /** Detect free variable `window`. */ - var freeWindow = objectTypes[typeof window] && window && window.Object && window; - - /** - * Used as a reference to the global object. - * - * The `this` value is used if it is the global object to avoid Greasemonkey's - * restricted `window` object, otherwise the `window` object is used. - */ - var root = freeGlobal || ((freeWindow !== (this && this.window)) && freeWindow) || freeSelf || this; - - /*--------------------------------------------------------------------------*/ - - /** - * Installs `WeakMap` on the given `context` object. - * - * @memberOf exports - * @param {Object} context The context object. - */ - function runInContext(context) { - - /** - * Creates a `WeakMap` object. - */ - function WeakMap() { - // No operation performed. - } - - /** - * Gets the value associated with the given key. - * - * @memberOf WeakMap - * @param {Object} key The key object. - * @returns {*} Returns the associated value, else `undefined`. - */ - function get(key) { - return key.__weakmap__; - } - - /** - * Sets a value for the given key. - * - * @memberOf WeakMap - * @param {Object} key The key object. - * @param {*} value The value to set. - */ - function set(key, value) { - key.__weakmap__ = value; - return this; - } - - /** - * Produces the `toString` result of `WeakMap`. - * - * @static - * @memberOf WeakMap - * @returns {string} Returns the string result. - */ - function toString() { - return nativeString; - } - - WeakMap.toString = toString; - WeakMap.prototype.get = get; - WeakMap.prototype.set = set; - - if (!root.WeakMap) { - context.WeakMap = WeakMap; - } - } - - /*--------------------------------------------------------------------------*/ - - if (freeExports) { - freeExports.runInContext = runInContext; - } else { - runInContext(root); - } -}.call(this)); From 6898b896d19a493a5ce56da519c698c0baabeff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Lipi=C5=84ski?= Date: Wed, 2 Sep 2015 11:22:26 +0200 Subject: [PATCH 239/935] Add `_.unset`. --- lodash.js | 44 +++++++++++++++++++++++++++ test/test.js | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 129 insertions(+), 1 deletion(-) diff --git a/lodash.js b/lodash.js index ceb97a3627..84c7eed103 100644 --- a/lodash.js +++ b/lodash.js @@ -2959,6 +2959,21 @@ return result; } + /** + * The base implementation of `_.unset`. + * + * @private + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to unset. + * @returns {boolean} Returns `true` if the property is deleted, else `false`. + */ + function baseUnset(object, path) { + path = isKey(path, object) ? [path + ''] : toPath(path); + object = parent(object, path); + var key = last(path); + return (object != null && has(object, key)) ? delete object[key] : true; + } + /** * The base implementation of methods like `_.dropWhile` and `_.takeWhile` * without support for callback shorthands. @@ -9843,6 +9858,34 @@ return accumulator; } + /** + * Removes the property at `path` of `object`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to unset. + * @returns {boolean} Returns `true` if the property is deleted, else `false`. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 7 } }] }; + * _.unset(object, 'a[0].b.c'); + * // => true + * + * console.log(object); + * // => { 'a': [{ 'b': {} }] }; + * + * _.unset(object, 'a[0].b.c'); + * // => true + * + * console.log(object); + * // => { 'a': [{ 'b': {} }] }; + */ + function unset(object, path) { + return object == null ? true : baseUnset(object, path); + } + /** * Creates an array of the own enumerable property values of `object`. * @@ -11721,6 +11764,7 @@ lodash.union = union; lodash.uniq = uniq; lodash.uniqBy = uniqBy; + lodash.unset = unset; lodash.unzip = unzip; lodash.unzipWith = unzipWith; lodash.values = values; diff --git a/test/test.js b/test/test.js index 9bf8d5a7fe..6476525355 100644 --- a/test/test.js +++ b/test/test.js @@ -16106,6 +16106,90 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.unset'); + + (function() { + test('should unset property on given `object`', 4, function() { + _.each(['a', ['a']], function(path) { + var object = { 'a': 1, 'c': 2 }; + strictEqual(_.unset(object, path), true); + deepEqual(object, { 'c': 2 }); + }); + }); + + test('should unset deep property on given `object`', 4, function() { + _.each(['a.b.c', ['a', 'b', 'c']], function(path) { + var object = { 'a': { 'b': { 'c': null } } }; + strictEqual(_.unset(object, path), true); + deepEqual(object, { 'a': { 'b': {} } }); + }); + }); + + test('should handle complex paths', 4, function() { + var paths = [ + 'a[-1.23]["[\\"b\\"]"].c[\'[\\\'d\\\']\'][\ne\n][f].g', + ['a', '-1.23', '["b"]', 'c', "['d']", '\ne\n', 'f', 'g'] + ]; + + _.each(paths, function(path) { + var object = { 'a': { '-1.23': { '["b"]': { 'c': { "['d']": { '\ne\n': { 'f': { 'g': 8 } } } } } } } }; + strictEqual(_.unset(object, path), true); + + ok(!('g' in object.a[-1.23]['["b"]'].c["['d']"]['\ne\n'].f)); + }); + }); + + test('should return `true` for nonexistent paths', 5, function() { + var object = { 'a': { 'b': { 'c': null } } }; + + _.each(['z', 'a.z', 'a.b.z', 'a.b.c.z'], function(path) { + strictEqual(_.unset(object, path), true); + }); + + deepEqual(object, { 'a': { 'b': { 'c': null } } }); + }); + + test('should not error when `object` is nullish', 1, function() { + var values = [null, undefined], + expected = [[true, true], [true, true]]; + + var actual = _.map(values, function(value) { + try { + return [_.unset(value, 'a.b'), _.unset(value, ['a', 'b'])]; + } catch(e) { + return e.message; + } + }); + + deepEqual(actual, expected); + }); + + test('should follow `path` over non-plain objects', 2, function() { + function Foo() {}; + Foo.prototype.a = 1; + + strictEqual(_.unset(Foo, 'prototype.a'), true); + strictEqual(Foo.prototype.a, undefined); + }); + + test('should return `false` for non-configurable properties', 1, function() { + var object = {}; + + if (defineProperty) { + defineProperty(object, 'a', { + 'configurable': false, + 'value': null + }); + strictEqual(_.unset(object, 'a'), false); + } + else { + skipTest(); + } + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.unzipWith'); (function() { @@ -17438,7 +17522,7 @@ var acceptFalsey = _.difference(allMethods, rejectFalsey); - test('should accept falsey arguments', 228, function() { + test('should accept falsey arguments', 229, function() { var emptyArrays = _.map(falsey, _.constant([])); _.each(acceptFalsey, function(methodName) { From 7e73b27edf7ad599c1cff9314bd3e421c6af9a38 Mon Sep 17 00:00:00 2001 From: Ray Hammond Date: Thu, 3 Sep 2015 19:45:44 +0100 Subject: [PATCH 240/935] Updated contributing text to include code style linter details. [ci skip] --- CONTRIBUTING.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index df0e4aa42c..e2bcfa11f0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -37,3 +37,9 @@ In addition to the following guidelines, please follow the conventions already e - **Comments**:
Please use single-line comments to annotate significant additions, & [JSDoc-style](http://www.2ality.com/2011/08/jsdoc-intro.html) comments for new methods. + +Guidelines are enforced using [JSSC](https://www.npmjs.com/package/jscs): + +```bash +$ npm run lint +``` From e63d7ff9d56ea11f6928e3fef86bdb0cfee40ff5 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 3 Sep 2015 12:58:42 -0700 Subject: [PATCH 241/935] Rename var `initFromArray` to `initFromCollection` in `_.reduce` and `_.reduceRight`. --- lodash.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lodash.js b/lodash.js index 84c7eed103..be0c95106f 100644 --- a/lodash.js +++ b/lodash.js @@ -6610,10 +6610,10 @@ * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed) */ function reduce(collection, iteratee, accumulator) { - var initFromArray = arguments.length < 3; + var initFromCollection = arguments.length < 3; return (typeof iteratee == 'function' && isArray(collection)) - ? arrayReduce(collection, iteratee, accumulator, initFromArray) - : baseReduce(collection, getIteratee(iteratee, 4), accumulator, initFromArray, baseEach); + ? arrayReduce(collection, iteratee, accumulator, initFromCollection) + : baseReduce(collection, getIteratee(iteratee, 4), accumulator, initFromCollection, baseEach); } /** @@ -6637,10 +6637,10 @@ * // => [4, 5, 2, 3, 0, 1] */ function reduceRight(collection, iteratee, accumulator) { - var initFromArray = arguments.length < 3; + var initFromCollection = arguments.length < 3; return (typeof iteratee == 'function' && isArray(collection)) - ? arrayReduceRight(collection, iteratee, accumulator, initFromArray) - : baseReduce(collection, getIteratee(iteratee, 4), accumulator, initFromArray, baseEachRight); + ? arrayReduceRight(collection, iteratee, accumulator, initFromCollection) + : baseReduce(collection, getIteratee(iteratee, 4), accumulator, initFromCollection, baseEachRight); } /** From 617dd703e192495b68eff0ab986949ccec33d059 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 3 Sep 2015 15:22:10 -0700 Subject: [PATCH 242/935] Soften language on isXyz methods that use duck typing. [ci skip] --- lodash.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lodash.js b/lodash.js index be0c95106f..683ed04607 100644 --- a/lodash.js +++ b/lodash.js @@ -4164,7 +4164,7 @@ } /** - * Checks if `value` is classified as a `Map` object. + * Checks if `value` is likely a `Map` object. * * @private * @param {*} value The value to check. @@ -4176,7 +4176,7 @@ } /** - * Checks if `value` is a prototype. + * Checks if `value` is likely a prototype object. * * @private * @param {*} value The value to check. @@ -4190,7 +4190,7 @@ } /** - * Checks if `value` is classified as a `Set` object. + * Checks if `value` is likely a `Set` object. * * @private * @param {*} value The value to check. @@ -8131,7 +8131,7 @@ } /** - * Checks if `value` is classified as an `arguments` object. + * Checks if `value` is likely an `arguments` object. * * @static * @memberOf _ @@ -8211,7 +8211,7 @@ } /** - * Checks if `value` is a DOM element. + * Checks if `value` is likely a DOM element. * * @static * @memberOf _ From 3e42a817a1dd9ed8bae3519721c77d0c0ec2e5fd Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 3 Sep 2015 12:58:06 -0700 Subject: [PATCH 243/935] Fix failing map/set tests in IE11. --- lodash.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lodash.js b/lodash.js index 683ed04607..cd969e213b 100644 --- a/lodash.js +++ b/lodash.js @@ -300,7 +300,8 @@ * @returns {Object} Returns `map`. */ function addMapEntry(map, pair) { - return map.set(pair[0], pair[1]); + map.set(pair[0], pair[1]); + return map; } /** @@ -312,7 +313,8 @@ * @returns {Object} Returns `set`. */ function addSetEntry(set, value) { - return set.add(value); + set.add(value); + return set; } /** @@ -1874,7 +1876,7 @@ var tag = objToString.call(value), isFunc = tag == funcTag; - if (tag == objectTag && noMapSetTag) { + if (noMapSetTag && tag == objectTag) { tag = isMap(value) ? mapTag : (isSet(value) ? setTag : tag); } if (tag == objectTag || tag == argsTag || (isFunc && !object)) { @@ -2284,7 +2286,7 @@ if (!objIsArr) { objTag = objToString.call(object); - if (othTag == objectTag && noMapSetTag) { + if (noMapSetTag && objTag == objectTag) { objTag = isMap(object) ? mapTag : (isSet(object) ? setTag : objTag); } else if (objTag == argsTag) { objTag = objectTag; @@ -2294,7 +2296,7 @@ } if (!othIsArr) { othTag = objToString.call(other); - if (othTag == objectTag && noMapSetTag) { + if (noMapSetTag && othTag == objectTag) { othTag = isMap(other) ? mapTag : (isSet(other) ? setTag : othTag); } else if (othTag == argsTag) { othTag = objectTag; @@ -8810,7 +8812,7 @@ return iteratorToArray(value[iteratorSymbol]()); } var tag = objToString.call(value); - if (tag == objectTag && noMapSetTag) { + if (noMapSetTag && tag == objectTag) { tag = isMap(value) ? mapTag : (isSet(value) ? setTag : tag); } var func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values); From a1f29d8f4a2efbfd37403942a58c22d28bd518d7 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 3 Sep 2015 18:28:57 -0700 Subject: [PATCH 244/935] Cleanup get/set/unset tests. --- test/test.js | 54 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/test/test.js b/test/test.js index 6476525355..534cb9890b 100644 --- a/test/test.js +++ b/test/test.js @@ -13066,16 +13066,20 @@ _.each(paths, function(path) { numberProto.a = 1; + var actual = func(0, path); strictEqual(actual, 1); + delete numberProto.a; }); - _.each(['a.a.a', ['a', 'a', 'a']], function(path) { - stringProto.a = '_'; + _.each(['a.replace.b', ['a', 'replace', 'b']], function(path) { + stringProto.replace.b = 1; + var actual = func(object, path); - strictEqual(actual, '_'); - delete stringProto.a; + strictEqual(actual, 1); + + delete stringProto.replace.b; }); }); @@ -13505,8 +13509,10 @@ _.each(['a', ['a']], function(path) { var actual = func(object, path, 2); + strictEqual(actual, object); strictEqual(object.a, 2); + object.a = 1; }); }); @@ -13516,8 +13522,10 @@ _.each(['a.b.c', ['a', 'b', 'c']], function(path) { var actual = func(object, path, 4); + strictEqual(actual, object); strictEqual(object.a.b.c, 4); + object.a.b.c = 3; }); }); @@ -13527,8 +13535,10 @@ _.each(['a.b.c', ['a.b.c']], function(path) { var actual = func(object, path, 4); + strictEqual(actual, object); deepEqual(object, { 'a.b.c': 4 }); + object['a.b.c'] = 3; }); }); @@ -13577,9 +13587,11 @@ _.each(['a[1].b.c', ['a', '1', 'b', 'c']], function(path) { var actual = func(object, path, 4); + strictEqual(actual, object); deepEqual(actual, { 'a': [undefined, { 'b': { 'c': 4 } }] }); ok(!(0 in object.a)); + delete object.a; }); }); @@ -16109,7 +16121,7 @@ QUnit.module('lodash.unset'); (function() { - test('should unset property on given `object`', 4, function() { + test('should unset property values', 4, function() { _.each(['a', ['a']], function(path) { var object = { 'a': 1, 'c': 2 }; strictEqual(_.unset(object, path), true); @@ -16117,7 +16129,7 @@ }); }); - test('should unset deep property on given `object`', 4, function() { + test('should unset deep property values', 4, function() { _.each(['a.b.c', ['a', 'b', 'c']], function(path) { var object = { 'a': { 'b': { 'c': null } } }; strictEqual(_.unset(object, path), true); @@ -16134,7 +16146,6 @@ _.each(paths, function(path) { var object = { 'a': { '-1.23': { '["b"]': { 'c': { "['d']": { '\ne\n': { 'f': { 'g': 8 } } } } } } } }; strictEqual(_.unset(object, path), true); - ok(!('g' in object.a[-1.23]['["b"]'].c["['d']"]['\ne\n'].f)); }); }); @@ -16164,12 +16175,29 @@ deepEqual(actual, expected); }); - test('should follow `path` over non-plain objects', 2, function() { - function Foo() {}; - Foo.prototype.a = 1; + test('should follow `path` over non-plain objects', 8, function() { + var object = { 'a': '' }, + paths = ['constructor.prototype.a', ['constructor', 'prototype', 'a']]; + + _.each(paths, function(path) { + numberProto.a = 1; - strictEqual(_.unset(Foo, 'prototype.a'), true); - strictEqual(Foo.prototype.a, undefined); + var actual = _.unset(0, path); + strictEqual(actual, true); + ok(!('a' in numberProto)); + + delete numberProto.a; + }); + + _.each(['a.replace.b', ['a', 'replace', 'b']], function(path) { + stringProto.replace.b = 1; + + var actual = _.unset(object, path); + strictEqual(actual, true); + ok(!('a' in stringProto.replace)); + + delete stringProto.replace.b; + }); }); test('should return `false` for non-configurable properties', 1, function() { @@ -16178,7 +16206,7 @@ if (defineProperty) { defineProperty(object, 'a', { 'configurable': false, - 'value': null + 'value': 1 }); strictEqual(_.unset(object, 'a'), false); } From ee776fd0de1807a51fd75d9183301c256ef77209 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 3 Sep 2015 19:52:55 -0700 Subject: [PATCH 245/935] Add IE11 note to `noMapSetTag` definition. [ci skip] --- lodash.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lodash.js b/lodash.js index cd969e213b..ad77447716 100644 --- a/lodash.js +++ b/lodash.js @@ -1366,7 +1366,7 @@ var mapCtorString = nativeMap ? fnToString.call(nativeMap) : '', setCtorString = nativeSet ? fnToString.call(nativeSet) : ''; - /** Detect support for map and set `toStringTag` values. */ + /** Detect lack of support for map and set `toStringTag` values (IE 11). */ var noMapSetTag = nativeMap && nativeSet && !(objToString.call(new Map) == mapTag && objToString.call(new Set) == setTag); From 38a802fed35672ae9abd38122fb63315c8f87c71 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 3 Sep 2015 19:17:11 -0700 Subject: [PATCH 246/935] Fix `_.isArguments` in Safari 8.1. --- lodash.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lodash.js b/lodash.js index ad77447716..a0b4e38d1f 100644 --- a/lodash.js +++ b/lodash.js @@ -8149,8 +8149,8 @@ * // => false */ function isArguments(value) { - return isObjectLike(value) && isArrayLike(value) && - hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee'); + return isObjectLike(value) && isArrayLike(value) && hasOwnProperty.call(value, 'callee') && + (!propertyIsEnumerable.call(value, 'callee') || objToString.call(value) == argsTag); } /** From 824d3b75f903a0d75f8fb4844415760cf36e4adc Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 3 Sep 2015 20:05:39 -0700 Subject: [PATCH 247/935] Add Safari 8.1 note to `_.isArguments`. [ci skip] --- lodash.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lodash.js b/lodash.js index a0b4e38d1f..2e5732aae5 100644 --- a/lodash.js +++ b/lodash.js @@ -8149,6 +8149,7 @@ * // => false */ function isArguments(value) { + // Safari 8.1 incorrectly makes `arguments.callee` enumerable in strict mode. return isObjectLike(value) && isArrayLike(value) && hasOwnProperty.call(value, 'callee') && (!propertyIsEnumerable.call(value, 'callee') || objToString.call(value) == argsTag); } From 3ef7ae24e5d85920fae35dd942e78e842c52cfdc Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 3 Sep 2015 22:08:02 -0700 Subject: [PATCH 248/935] Expose `_.isArrayLike`. --- lodash.js | 40 ++++++++++++++++++++++++----------- test/test.js | 60 +++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 83 insertions(+), 17 deletions(-) diff --git a/lodash.js b/lodash.js index 2e5732aae5..43c1695a39 100644 --- a/lodash.js +++ b/lodash.js @@ -4092,18 +4092,6 @@ return func == null ? undefined : func.apply(object, args); } - /** - * Checks if `value` is array-like. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is array-like, else `false`. - */ - function isArrayLike(value) { - return value != null && - !(typeof value == 'function' && objToString.call(value) == funcTag) && isLength(getLength(value)); - } - /** * Checks if the provided arguments are from an iteratee call. * @@ -8173,6 +8161,33 @@ */ var isArray = Array.isArray; + /** + * Checks if `value` is array-like. A value is considered array-like if it's + * not a function and has a `value.length` that's an integer greater than or + * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. + * + * @static + * @memberOf _ + * @type Function + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + * @example + * + * _.isArrayLike([1, 2, 3]); + * // => true + * + * _.isArrayLike(function() { return arguments; }()); + * // => true + * + * _.isArrayLike(_.noop); + * // => false + */ + function isArrayLike(value) { + return value != null && + !(typeof value == 'function' && objToString.call(value) == funcTag) && isLength(getLength(value)); + } + /** * Checks if `value` is classified as a boolean primitive or object. * @@ -11829,6 +11844,7 @@ lodash.inRange = inRange; lodash.isArguments = isArguments; lodash.isArray = isArray; + lodash.isArrayLike = isArrayLike; lodash.isBoolean = isBoolean; lodash.isDate = isDate; lodash.isElement = isElement; diff --git a/test/test.js b/test/test.js index 534cb9890b..d82f5e0fe1 100644 --- a/test/test.js +++ b/test/test.js @@ -6169,6 +6169,55 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.isArrayLike'); + + (function() { + var args = arguments; + + test('should return `true` for array-like values', 1, function() { + var values = [args, [1, 2, 3], { '0': 1, 'length': 1 }, 'a'], + expected = _.map(values, _.constant(true)), + actual = _.map(values, _.isArrayLike); + + deepEqual(actual, expected); + }); + + test('should return `false` for non-arrays', 10, function() { + var expected = _.map(falsey, function(value) { return value === ''; }); + + var actual = _.map(falsey, function(value, index) { + return index ? _.isArrayLike(value) : _.isArrayLike(); + }); + + deepEqual(actual, expected); + + strictEqual(_.isArrayLike(true), false); + strictEqual(_.isArrayLike(new Date), false); + strictEqual(_.isArrayLike(new Error), false); + strictEqual(_.isArrayLike(_), false); + strictEqual(_.isArrayLike(slice), false); + strictEqual(_.isArrayLike(), false); + strictEqual(_.isArrayLike(1), false); + strictEqual(_.isArrayLike(NaN), false); + strictEqual(_.isArrayLike(/x/), false); + }); + + test('should work with an array from another realm', 1, function() { + if (_._object) { + var values = [_._arguments, _._array, _._string], + expected = _.map(values, _.constant(true)), + actual = _.map(values, _.isArrayLike); + + deepEqual(actual, expected); + } + else { + skipTest(); + } + }); + }(1, 2, 3)); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.isBoolean'); (function() { @@ -8133,11 +8182,11 @@ }); }); - test('should not error on host objects (test in IE)', 16, function() { + test('should not error on host objects (test in IE)', 17, function() { var funcs = [ - 'isArguments', 'isArray', 'isBoolean', 'isDate', 'isElement', - 'isError', 'isFinite', 'isFunction', 'isNaN', 'isNil', 'isNull', - 'isNumber', 'isObject', 'isRegExp', 'isString', 'isUndefined' + 'isArguments', 'isArray', 'isArrayLike', 'isBoolean', 'isDate', + 'isElement', 'isError', 'isFinite', 'isFunction', 'isNaN', 'isNil', + 'isNull', 'isNumber', 'isObject', 'isRegExp', 'isString', 'isUndefined' ]; _.each(funcs, function(methodName) { @@ -17310,6 +17359,7 @@ 'includes', 'isArguments', 'isArray', + 'isArrayLike', 'isBoolean', 'isDate', 'isElement', @@ -17550,7 +17600,7 @@ var acceptFalsey = _.difference(allMethods, rejectFalsey); - test('should accept falsey arguments', 229, function() { + test('should accept falsey arguments', 230, function() { var emptyArrays = _.map(falsey, _.constant([])); _.each(acceptFalsey, function(methodName) { From 41d3b66867c587dae5e76617d5eb7b1665e11ff5 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 3 Sep 2015 22:12:17 -0700 Subject: [PATCH 249/935] Move `NEGATIVE_INFINITY` and `POSITIVE_INFINITY` out of `runInContext`. --- lodash.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lodash.js b/lodash.js index 43c1695a39..0af18d89fc 100644 --- a/lodash.js +++ b/lodash.js @@ -58,6 +58,10 @@ */ var MAX_SAFE_INTEGER = 9007199254740991; + /** Used as references for `-Infinity` and `Infinity`. */ + var NEGATIVE_INFINITY = 1 / -0, + POSITIVE_INFINITY = 1 / 0; + /** Used as the internal argument placeholder. */ var PLACEHOLDER = '__lodash_placeholder__'; @@ -1287,10 +1291,6 @@ // See https://es5.github.io/#x11.1.5 for more details. context = context ? _.defaults({}, context, _.pick(root, contextProps)) : root; - /** Used as references for `-Infinity` and `Infinity`. */ - var NEGATIVE_INFINITY = context.Number.NEGATIVE_INFINITY, - POSITIVE_INFINITY = context.Number.POSITIVE_INFINITY; - /** Native constructor references. */ var Date = context.Date, Error = context.Error, From 4a87acf1accaa1af00f46141d701e4b35c4f3413 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 3 Sep 2015 22:13:57 -0700 Subject: [PATCH 250/935] Remove "Number" and "String" from `contextProps`. --- lodash.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lodash.js b/lodash.js index 0af18d89fc..c5ea086e27 100644 --- a/lodash.js +++ b/lodash.js @@ -159,10 +159,10 @@ /** Used to assign default `context` object properties. */ var contextProps = [ 'Array', 'ArrayBuffer', 'Date', 'Error', 'Float32Array', 'Float64Array', - 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Math', 'Number', - 'Object', 'Reflect', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', - 'Uint8Array', 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap', - '_', 'clearTimeout', 'isFinite', 'parseFloat', 'parseInt', 'setTimeout' + 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Math', 'Object', + 'Reflect', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array', + 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap', '_', + 'clearTimeout', 'isFinite', 'parseFloat', 'parseInt', 'setTimeout' ]; /** Used to make template sourceURLs easier to identify. */ From 41b537249b82f5a852b8ccb7c820357694788960 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Fri, 4 Sep 2015 00:20:37 -0700 Subject: [PATCH 251/935] Expose `_.isObjectLike` and `_.toPath`. --- lodash.js | 119 +++++++++++++++++++++++++++++++++++---------------- test/test.js | 11 ++--- 2 files changed, 88 insertions(+), 42 deletions(-) diff --git a/lodash.js b/lodash.js index c5ea086e27..a7364a7583 100644 --- a/lodash.js +++ b/lodash.js @@ -1110,17 +1110,6 @@ return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; } - /** - * Checks if `value` is object-like. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is object-like, else `false`. - */ - function isObjectLike(value) { - return !!value && typeof value == 'object'; - } - /** * Used by `trimmedLeftIndex` and `trimmedRightIndex` to determine if a * character code is whitespace. @@ -2202,7 +2191,7 @@ * @returns {*} Returns the resolved value. */ function baseGet(object, path) { - path = isKey(path, object) ? [path + ''] : toPath(path); + path = isKey(path, object) ? [path + ''] : baseToPath(path); var index = 0, length = path.length; @@ -2691,7 +2680,7 @@ splice.call(array, index, 1); } else if (!isKey(index, array)) { - var path = toPath(index), + var path = baseToPath(index), object = parent(array, path); if (object != null) { @@ -2730,7 +2719,7 @@ * @returns {Object} Returns `object`. */ function baseSet(object, path, value, customizer) { - path = isKey(path, object) ? [path + ''] : toPath(path); + path = isKey(path, object) ? [path + ''] : baseToPath(path); var index = -1, length = path.length, @@ -2898,6 +2887,18 @@ return result; } + /** + * The base implementation of `_.toPath` which only converts `value` to a + * path if it's not one. + * + * @private + * @param {*} value The value to process. + * @returns {Array} Returns the property path array. + */ + function baseToPath(value) { + return isArray(value) ? value : stringToPath(value); + } + /** * The base implementation of `_.uniq`. * @@ -2970,7 +2971,7 @@ * @returns {boolean} Returns `true` if the property is deleted, else `false`. */ function baseUnset(object, path) { - path = isKey(path, object) ? [path + ''] : toPath(path); + path = isKey(path, object) ? [path + ''] : baseToPath(path); object = parent(object, path); var key = last(path); return (object != null && has(object, key)) ? delete object[key] : true; @@ -3969,7 +3970,7 @@ } var result = hasFunc(object, path); if (!result && !isKey(path)) { - path = toPath(path); + path = baseToPath(path); object = parent(object, path); if (object != null) { path = last(path); @@ -4084,7 +4085,7 @@ */ function invokePath(object, path, args) { if (!isKey(path, object)) { - path = toPath(path); + path = baseToPath(path); object = parent(object, path); path = last(path); } @@ -4357,6 +4358,21 @@ }; }()); + /** + * Converts `string` to a property path array. + * + * @private + * @param {string} string The string to process. + * @returns {Array} Returns the property path array. + */ + function stringToPath(string) { + var result = []; + baseToString(string).replace(rePropName, function(match, number, quote, string) { + result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match)); + }); + return result; + } + /** * Converts `value` to a function if it's not one. * @@ -4379,24 +4395,6 @@ return nativeFloor(value) || 0; } - /** - * Converts `value` to a property path array if it's not one. - * - * @private - * @param {*} value The value to process. - * @returns {Array} Returns the property path array. - */ - function toPath(value) { - if (isArray(value)) { - return value; - } - var result = []; - baseToString(value).replace(rePropName, function(match, number, quote, string) { - result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match)); - }); - return result; - } - /** * Creates a clone of `wrapper`. * @@ -8435,7 +8433,10 @@ * _.isObject([1, 2, 3]); * // => true * - * _.isObject(1); + * _.isObject(_.noop); + * // => true + * + * _.isObject(null); * // => false */ function isObject(value) { @@ -8445,6 +8446,33 @@ return !!value && (type == 'object' || type == 'function'); } + /** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ + function isObjectLike(value) { + return !!value && typeof value == 'object'; + } + /** * Performs a deep comparison between `object` and `source` to determine if * `object` contains equivalent property values. @@ -9759,7 +9787,7 @@ */ function result(object, path, defaultValue) { if (!isKey(path, object)) { - path = toPath(path); + path = baseToPath(path); var result = get(object, path); object = parent(object, path); } else { @@ -11392,6 +11420,21 @@ return result; } + /** + * Converts `value` to a property path array. + * + * @static + * @memberOf _ + * @category Utility + * @param {*} value The value to process. + * @returns {Array} Returns the new property path array. + * @example + * + */ + function toPath(value) { + return isArray(value) ? copyArray(value) : stringToPath(value); + } + /** * Generates a unique ID. If `prefix` is provided the ID is appended to it. * @@ -11777,6 +11820,7 @@ lodash.thru = thru; lodash.times = times; lodash.toArray = toArray; + lodash.toPath = toPath; lodash.toPlainObject = toPlainObject; lodash.transform = transform; lodash.union = union; @@ -11862,6 +11906,7 @@ lodash.isNull = isNull; lodash.isNumber = isNumber; lodash.isObject = isObject; + lodash.isObjectLike = isObjectLike; lodash.isPlainObject = isPlainObject; lodash.isRegExp = isRegExp; lodash.isString = isString; diff --git a/test/test.js b/test/test.js index d82f5e0fe1..8d975d5808 100644 --- a/test/test.js +++ b/test/test.js @@ -8182,11 +8182,11 @@ }); }); - test('should not error on host objects (test in IE)', 17, function() { + test('should not error on host objects (test in IE)', 18, function() { var funcs = [ - 'isArguments', 'isArray', 'isArrayLike', 'isBoolean', 'isDate', - 'isElement', 'isError', 'isFinite', 'isFunction', 'isNaN', 'isNil', - 'isNull', 'isNumber', 'isObject', 'isRegExp', 'isString', 'isUndefined' + 'isArguments', 'isArray', 'isArrayLike', 'isBoolean', 'isDate', 'isElement', + 'isError', 'isFinite', 'isFunction', 'isNaN', 'isNil', 'isNull', 'isNumber', + 'isObject', 'isObjectLike', 'isRegExp', 'isString', 'isUndefined' ]; _.each(funcs, function(methodName) { @@ -17374,6 +17374,7 @@ 'isNull', 'isNumber', 'isObject', + 'isObjectLike', 'isPlainObject', 'isRegExp', 'isString', @@ -17600,7 +17601,7 @@ var acceptFalsey = _.difference(allMethods, rejectFalsey); - test('should accept falsey arguments', 230, function() { + test('should accept falsey arguments', 232, function() { var emptyArrays = _.map(falsey, _.constant([])); _.each(acceptFalsey, function(methodName) { From b534b83756952f12a9c0f1b5396ad8acc26746ff Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Fri, 4 Sep 2015 01:02:47 -0700 Subject: [PATCH 252/935] Fix failing tests in strict mode. --- test/test.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/test/test.js b/test/test.js index 8d975d5808..c7ec4ba735 100644 --- a/test/test.js +++ b/test/test.js @@ -8847,12 +8847,7 @@ }); test('`_.' + methodName + '` should work with `arguments` objects', 1, function() { - if (!isStrict) { - deepEqual(func(args).sort(), ['0', '1', '2']); - } - else { - skipTest(); - } + deepEqual(func(args).sort(), ['0', '1', '2']); }); test('`_.' + methodName + '` should return keys for custom properties on `arguments` objects', 1, function() { @@ -16252,7 +16247,7 @@ test('should return `false` for non-configurable properties', 1, function() { var object = {}; - if (defineProperty) { + if (!isStrict && defineProperty) { defineProperty(object, 'a', { 'configurable': false, 'value': 1 From e516d99b2d53a4d416e3993e31411af41ea24b92 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Fri, 4 Sep 2015 08:35:36 -0700 Subject: [PATCH 253/935] Expose `_.toInteger`. --- lodash.js | 37 ++++++++++++++++++++++++++----------- test/test.js | 5 +++-- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/lodash.js b/lodash.js index a7364a7583..57f34df1e4 100644 --- a/lodash.js +++ b/lodash.js @@ -4384,17 +4384,6 @@ return typeof value == 'function' ? value : identity; } - /** - * Converts `value` to an integer. - * - * @private - * @param {*} value The value to convert. - * @returns {number} Returns the integer. - */ - function toInteger(value) { - return nativeFloor(value) || 0; - } - /** * Creates a clone of `wrapper`. * @@ -8863,6 +8852,31 @@ return func(value); } + /** + * Converts `value` to an integer. + * + * **Note:** This function is based on [`ToInteger`](http://www.ecma-international.org/ecma-262/6.0/#sec-tointeger). + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted integer. + * @example + * + * _.toInteger('3.14'); + * // => 3 + * + * _.toInteger(NaN); + * // => 0 + * + * _.toInteger(Infinity); + * // => Infinity + */ + function toInteger(value) { + return nativeFloor(value) || 0; + } + /** * Converts `value` to a plain object flattening inherited enumerable * properties of `value` to own properties of the plain object. @@ -11949,6 +11963,7 @@ lodash.sum = sum; lodash.sumBy = sumBy; lodash.template = template; + lodash.toInteger = toInteger; lodash.trim = trim; lodash.trimLeft = trimLeft; lodash.trimRight = trimRight; diff --git a/test/test.js b/test/test.js index c7ec4ba735..1e1fb4428a 100644 --- a/test/test.js +++ b/test/test.js @@ -17387,7 +17387,8 @@ 'random', 'reduce', 'reduceRight', - 'some' + 'some', + 'toInteger' ]; _.each(funcs, function(methodName) { @@ -17596,7 +17597,7 @@ var acceptFalsey = _.difference(allMethods, rejectFalsey); - test('should accept falsey arguments', 232, function() { + test('should accept falsey arguments', 233, function() { var emptyArrays = _.map(falsey, _.constant([])); _.each(acceptFalsey, function(methodName) { From 4510ada21e55037ef20403c244f2b9872ec33247 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Fri, 4 Sep 2015 08:44:28 -0700 Subject: [PATCH 254/935] Update lodash doc block. [ci skip] --- lodash.js | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/lodash.js b/lodash.js index 57f34df1e4..4e8fa19fe9 100644 --- a/lodash.js +++ b/lodash.js @@ -1412,9 +1412,10 @@ * `push`, `range`, `rearg`, `reject`, `remove`, `rest`, `restParam`, `reverse`, * `set`, `setWith`, `shuffle`, `slice`, `sort`, `sortBy`, `sortByOrder`, * `splice`, `spread`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, - * `tap`, `throttle`, `thru`, `times`, `toArray`, `toPlainObject`, `transform`, - * `union`, `uniq`, `uniqBy`, `unshift`, `unzip`, `unzipWith`, `values`, - * `valuesIn`, `without`, `wrap`, `xor`, `zip`, `zipObject`, `zipWith` + * `tap`, `throttle`, `thru`, `times`, `toArray`, `toPath`, `toPlainObject`, + * `transform`, `union`, `uniq`, `uniqBy`, `unset`, `unshift`, `unzip`, + * `unzipWith`, `values`, `valuesIn`, `without`, `wrap`, `xor`, `zip`, + * `zipObject`, and `zipWith` * * The wrapper methods that are **not** chainable by default are: * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clone`, `cloneDeep`, @@ -1422,17 +1423,17 @@ * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`, * `findLastIndex`, `findLastKey`, `first`, `floor`, `get`, `gt`, `gte`, * `has`, `hasIn`, `identity`, `includes`, `indexOf`, `inRange`, `isArguments`, - * `isArray`, `isBoolean`, `isDate`, `isElement`, `isEmpty`, `isEqual`, - * `isEqualWith`, `isError`, `isFinite` `isFunction`, `isMatch`, `isMatchWith`, - * `isNaN`, `isNative`, `isNil`, `isNull`, `isNumber`, `isObject`, `isPlainObject`, - * `isRegExp`, `isString`, `isUndefined`, `isTypedArray`, `join`, `kebabCase`, - * `last`, `lastIndexOf`, `lt`, `lte`, `max`, `min`, `noConflict`, `noop`, - * `now`, `pad`, `padLeft`, `padRight`, `parseInt`, `pop`, `random`, `reduce`, - * `reduceRight`, `repeat`, `result`, `round`, `runInContext`, `shift`, `size`, - * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`, - * `sortedLastIndexBy`, `startCase`, `startsWith`, `sum`, `sumBy`, `template`, - * `trim`, `trimLeft`, `trimRight`, `trunc`, `unescape`, `uniqueId`, `value`, - * and `words` + * `isArray`, `isArrayLike`, `isBoolean`, `isDate`, `isElement`, `isEmpty`, + * `isEqual`, `isEqualWith`, `isError`, `isFinite` `isFunction`, `isMatch`, + * `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`, `isNumber`, `isObject`, + * `isObjectLike`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, + * `isTypedArray`, `join`, `kebabCase`, `last`, `lastIndexOf`, `lt`, `lte`, + * `max`, `min`, `noConflict`, `noop`, `now`, `pad`, `padLeft`, `padRight`, + * `parseInt`, `pop`, `random`, `reduce`, `reduceRight`, `repeat`, `result`, + * `round`, `runInContext`, `shift`, `size`, `snakeCase`, `some`, `sortedIndex`, + * `sortedIndexBy`, `sortedLastIndex`, `sortedLastIndexBy`, `startCase`, + * `startsWith`, `sum`, `sumBy`, `template`, `toInteger', 'trim`, `trimLeft`, + * `trimRight`, `trunc`, `unescape`, `uniqueId`, `value`, and `words` * * The wrapper method `sample` will return a wrapped value when `n` is provided, * otherwise an unwrapped value is returned. From 1be4adf365dfa7f7fcf5edf1213e9677ba9c68c4 Mon Sep 17 00:00:00 2001 From: Philippe Lhoste Date: Fri, 4 Sep 2015 13:05:02 +0200 Subject: [PATCH 255/935] Improve documentation for method chaining. [ci skip] --- lodash.js | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/lodash.js b/lodash.js index 4e8fa19fe9..1dcf57970b 100644 --- a/lodash.js +++ b/lodash.js @@ -1365,13 +1365,18 @@ /*------------------------------------------------------------------------*/ /** - * Creates a `lodash` object which wraps `value` to enable implicit chaining. - * Methods that operate on and return arrays, collections, and functions can - * be chained together. Methods that retrieve a single value or may return a - * primitive value will automatically end the chain returning the unwrapped - * value. Explicit chaining may be enabled using `_.chain`. The execution of - * chained methods is lazy, that is, execution is deferred until `_#value` - * is implicitly or explicitly called. + * Creates a `lodash` object which wraps `value` to enable implicit method + * chaining. Methods that operate on and return arrays, collections, and + * functions can be chained together. Methods that retrieve a single value or + * may return a primitive value will automatically end the chain sequence and + * return the unwrapped value. Otherwise, the value must be unwrapped with + * `_#value`. + * + * Explicit chaining, which requires unwrapping with `_#value` in all cases, + * may be enabled using `_.chain`. + * + * The execution of chained methods is lazy, that is, execution is deferred + * until `_#value` is implicitly or explicitly called. * * Lazy evaluation allows several methods to support shortcut fusion. Shortcut * fusion is an optimization strategy which merge iteratee calls; this can help @@ -5751,8 +5756,8 @@ /*------------------------------------------------------------------------*/ /** - * Creates a `lodash` object that wraps `value` with explicit method - * chaining enabled. + * Creates a `lodash` object that wraps `value` with explicit method chaining enabled. + * The result of such method chaining must be unwrapped with `_#value`. * * @static * @memberOf _ From 1422f50ee9f41de048a963f4cbd15b0f8b0116b4 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Fri, 4 Sep 2015 08:36:05 -0700 Subject: [PATCH 256/935] Remove `isStrict` guards from tests. --- test/test.js | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/test/test.js b/test/test.js index 1e1fb4428a..2cabad3ed6 100644 --- a/test/test.js +++ b/test/test.js @@ -8851,27 +8851,17 @@ }); test('`_.' + methodName + '` should return keys for custom properties on `arguments` objects', 1, function() { - if (!isStrict) { - args.a = 1; - deepEqual(func(args).sort(), ['0', '1', '2', 'a']); - delete args.a; - } - else { - skipTest(); - } + args.a = 1; + deepEqual(func(args).sort(), ['0', '1', '2', 'a']); + delete args.a; }); test('`_.' + methodName + '` should ' + (isKeys ? 'not' : '') + ' include inherited properties of `arguments` objects', 1, function() { - if (!isStrict) { - var expected = isKeys ? ['0', '1', '2'] : ['0', '1', '2', 'a']; + var expected = isKeys ? ['0', '1', '2'] : ['0', '1', '2', 'a']; - objectProto.a = 1; - deepEqual(func(args).sort(), expected); - delete objectProto.a; - } - else { - skipTest(); - } + objectProto.a = 1; + deepEqual(func(args).sort(), expected); + delete objectProto.a; }); test('`_.' + methodName + '` should work with string objects', 1, function() { From 556eee85633d262ca8e865912390c4f3f975ce9e Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sat, 5 Sep 2015 09:04:46 -0700 Subject: [PATCH 257/935] Use a create function helper for `modArgs`. --- lodash.js | 40 +++++++++++++++++++++++++++------------- test/test.js | 6 +++--- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/lodash.js b/lodash.js index 1dcf57970b..263cef5b4b 100644 --- a/lodash.js +++ b/lodash.js @@ -3513,6 +3513,31 @@ return wrapper; } + /** + * Creates a function like `_.modArgs`. + * + * @private + * @param {Function} resolver The function to resolve which invocation + * arguments are provided to each transform. + * @returns {Function} Returns the new arguments modifier function. + */ + function createModArgs(resolver) { + return restParam(function(func, transforms) { + transforms = baseFlatten(transforms); + if (typeof func != 'function' || !arrayEvery(transforms, baseIsFunction)) { + throw new TypeError(FUNC_ERROR_TEXT); + } + var length = transforms.length; + return restParam(function(args) { + var index = nativeMin(args.length, length); + while (index--) { + args[index] = transforms[index].apply(this, resolver(args[index], index, args)); + } + return func.apply(this, args); + }); + }); + } + /** * Creates the padding required for `string` based on the given `length`. * The `chars` string is truncated if the number of characters exceeds `length`. @@ -7578,19 +7603,8 @@ * modded(5, 10); * // => [25, 20] */ - var modArgs = restParam(function(func, transforms) { - transforms = baseFlatten(transforms); - if (typeof func != 'function' || !arrayEvery(transforms, baseIsFunction)) { - throw new TypeError(FUNC_ERROR_TEXT); - } - var length = transforms.length; - return restParam(function(args) { - var index = nativeMin(args.length, length); - while (index--) { - args[index] = transforms[index](args[index]); - } - return func.apply(this, args); - }); + var modArgs = createModArgs(function(value) { + return [value]; }); /** diff --git a/test/test.js b/test/test.js index 2cabad3ed6..9ac313e81a 100644 --- a/test/test.js +++ b/test/test.js @@ -11057,19 +11057,19 @@ deepEqual(modded(5, 10, 18), [5, 10, 18]); }); - test('should not pass `undefined` if there are more `transforms` than `arguments`', 1, function() { + test('should not pass `undefined` if there are more transforms than arguments', 1, function() { var modded = _.modArgs(fn, doubled, _.identity); deepEqual(modded(5), [10]); }); - test('should not set a `this` binding', 1, function() { + test('should use `this` binding of function for transforms', 1, function() { var modded = _.modArgs(function(x) { return this[x]; }, function(x) { return this === x; }); - var object = { 'modded': modded, 'false': 1 }; + var object = { 'modded': modded, 'true': 1 }; strictEqual(object.modded(object), 1); }); }()); From 58d7404ee4a0a205647cbe558d63dc352b71a214 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sat, 5 Sep 2015 09:14:38 -0700 Subject: [PATCH 258/935] Add a `_.memoize` test for the `this` binding of `resolver`. --- test/test.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/test.js b/test/test.js index 9ac313e81a..d6ce4c1b91 100644 --- a/test/test.js +++ b/test/test.js @@ -9963,6 +9963,18 @@ strictEqual(memoized(1, 3, 5), 9); }); + test('should use `this` binding of function for `resolver`', 2, function() { + var fn = function(a, b, c) { return a + this.b + this.c; }, + memoized = _.memoize(fn, fn); + + var object = { 'b': 2, 'c': 3, 'memoized': memoized }; + strictEqual(object.memoized(1), 6); + + object.b = 3; + object.c = 5; + strictEqual(object.memoized(1), 9); + }); + test('should throw a TypeError if `resolve` is truthy and not a function', function() { raises(function() { _.memoize(_.noop, {}); }, TypeError); }); From a4fee3a3adacdb43f06012caf19905904ba3a48b Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sat, 5 Sep 2015 09:26:09 -0700 Subject: [PATCH 259/935] Add `_.isObjectLike` tests. --- test/test.js | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/test/test.js b/test/test.js index d6ce4c1b91..783ff40540 100644 --- a/test/test.js +++ b/test/test.js @@ -7877,6 +7877,52 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.isObjectLike'); + + (function() { + var args = arguments; + + test('should return `true` for objects', 9, function() { + strictEqual(_.isObjectLike(args), true); + strictEqual(_.isObjectLike([1, 2, 3]), true); + strictEqual(_.isObjectLike(Object(false)), true); + strictEqual(_.isObjectLike(new Date), true); + strictEqual(_.isObjectLike(new Error), true); + strictEqual(_.isObjectLike({ 'a': 1 }), true); + strictEqual(_.isObjectLike(Object(0)), true); + strictEqual(_.isObjectLike(/x/), true); + strictEqual(_.isObjectLike(Object('a')), true); + }); + + test('should return `false` for non-objects', 1, function() { + var symbol = (Symbol || noop)(), + values = falsey.concat(true, _, slice, 1, 'a', symbol), + expected = _.map(values, _.constant(false)); + + var actual = _.map(values, function(value, index) { + return index ? _.isObjectLike(value) : _.isObjectLike(); + }); + + deepEqual(actual, expected); + }); + + test('should work with objects from another realm', 6, function() { + if (_._object) { + strictEqual(_.isObjectLike(_._object), true); + strictEqual(_.isObjectLike(_._boolean), true); + strictEqual(_.isObjectLike(_._date), true); + strictEqual(_.isObjectLike(_._number), true); + strictEqual(_.isObjectLike(_._regexp), true); + strictEqual(_.isObjectLike(_._string), true); + } + else { + skipTest(6); + } + }); + }(1, 2, 3)); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.isPlainObject'); (function() { From ded3cfc2512f3ca89becd0fc81bdcac391935c35 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sat, 5 Sep 2015 09:30:52 -0700 Subject: [PATCH 260/935] Add `_.toInteger` tests. --- lodash.js | 4 ++-- test/test.js | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/lodash.js b/lodash.js index 263cef5b4b..c876d6a6ac 100644 --- a/lodash.js +++ b/lodash.js @@ -8890,8 +8890,8 @@ * _.toInteger(NaN); * // => 0 * - * _.toInteger(Infinity); - * // => Infinity + * _.toInteger(-Infinity); + * // => -Infinity */ function toInteger(value) { return nativeFloor(value) || 0; diff --git a/test/test.js b/test/test.js index 783ff40540..44e162af9d 100644 --- a/test/test.js +++ b/test/test.js @@ -15632,6 +15632,19 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.toInteger'); + + (function() { + test('should convert values to integers', 4, function() { + strictEqual(_.toInteger('3.14'), 3); + strictEqual(_.toInteger(), 0); + strictEqual(_.toInteger(NaN), 0); + strictEqual(_.toInteger(-Infinity), -Infinity); + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.toPlainObject'); (function() { From 650282b186ce569823ae712102188cd7c9ee457e Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sat, 5 Sep 2015 09:59:38 -0700 Subject: [PATCH 261/935] Add `console.log`s to doc examples. [ci skip] --- lodash.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lodash.js b/lodash.js index c876d6a6ac..35eebe3ab9 100644 --- a/lodash.js +++ b/lodash.js @@ -7956,7 +7956,7 @@ * ]; * * var shallow = _.clone(users); - * shallow[0] === users[0]; + * console.log(shallow[0] === users[0]); * // => true */ function clone(value) { @@ -7983,11 +7983,11 @@ * } * }); * - * el === document.body + * console.log(el === document.body); * // => false - * el.nodeName + * console.log(el.nodeName); * // => BODY - * el.childNodes.length; + * console.log(el.childNodes.length); * // => 0 */ function cloneWith(value, customizer) { @@ -8010,7 +8010,7 @@ * ]; * * var deep = _.cloneDeep(users); - * deep[0] === users[0]; + * console.log(deep[0] === users[0]); * // => false */ function cloneDeep(value) { @@ -8034,11 +8034,11 @@ * } * }); * - * el === document.body + * console.log(el === document.body); * // => false - * el.nodeName + * console.log(el.nodeName); * // => BODY - * el.childNodes.length; + * console.log(el.childNodes.length); * // => 20 */ function cloneDeepWith(value, customizer) { From 7bb10d56f8b4332067b33af6ecdbe4a408c4bcb0 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sat, 5 Sep 2015 10:00:08 -0700 Subject: [PATCH 262/935] Add `_.toPath` doc examples. [ci skip] --- lodash.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lodash.js b/lodash.js index 35eebe3ab9..d1f20b1f96 100644 --- a/lodash.js +++ b/lodash.js @@ -11464,6 +11464,20 @@ * @returns {Array} Returns the new property path array. * @example * + * _.toPath('a.b.c'); + * // => ['a', 'b', 'c'] + * + * _.toPath('a[0].b.c'); + * // => ['a', '0', 'b', 'c'] + * + * var path = ['a', 'b', 'c'], + * newPath = _.toPath(path); + * + * console.log(newPath); + * // => ['a', 'b', 'c'] + * + * console.log(path === newPath); + * // => false */ function toPath(value) { return isArray(value) ? copyArray(value) : stringToPath(value); From 15a4fb7adf497e94681c149c8e903aebfd41f5e7 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sat, 5 Sep 2015 10:00:21 -0700 Subject: [PATCH 263/935] Add `_.toPath` tests. --- test/test.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/test.js b/test/test.js index 44e162af9d..89966bac94 100644 --- a/test/test.js +++ b/test/test.js @@ -15645,6 +15645,30 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.toPath'); + + (function() { + test('should convert a string to a path', 2, function() { + deepEqual(_.toPath('a.b.c'), ['a', 'b', 'c']); + deepEqual(_.toPath('a[0].b.c'), ['a', '0', 'b', 'c']); + }); + + test('should shallow clone array path', 2, function() { + var array = ['a', 'b', 'c'], + actual = _.toPath(array); + + deepEqual(actual, array); + notStrictEqual(actual, array); + }); + + test('should handle complex paths', 1, function() { + var actual = _.toPath('a[-1.23]["[\\"b\\"]"].c[\'[\\\'d\\\']\'][\ne\n][f].g'); + deepEqual(actual, ['a', '-1.23', '["b"]', 'c', "['d']", '\ne\n', 'f', 'g']); + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.toPlainObject'); (function() { From dc2e769d9ad84a29e5e6b830e8774d78fd8076d4 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sat, 5 Sep 2015 11:25:06 -0700 Subject: [PATCH 264/935] Ensure `_.toPath` converts array values to strings. --- lodash.js | 2 +- test/test.js | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lodash.js b/lodash.js index d1f20b1f96..d3f048af01 100644 --- a/lodash.js +++ b/lodash.js @@ -11480,7 +11480,7 @@ * // => false */ function toPath(value) { - return isArray(value) ? copyArray(value) : stringToPath(value); + return isArray(value) ? arrayMap(value, String) : stringToPath(value); } /** diff --git a/test/test.js b/test/test.js index 89966bac94..eac16e5aa3 100644 --- a/test/test.js +++ b/test/test.js @@ -15653,12 +15653,14 @@ deepEqual(_.toPath('a[0].b.c'), ['a', '0', 'b', 'c']); }); - test('should shallow clone array path', 2, function() { - var array = ['a', 'b', 'c'], - actual = _.toPath(array); + test('should coerce array elements to strings', 4, function() { + var array = ['a', 'b', 'c']; - deepEqual(actual, array); - notStrictEqual(actual, array); + _.each([array, _.map(array, Object)], function(value) { + var actual = _.toPath(value); + deepEqual(actual, array); + notStrictEqual(actual, array); + }); }); test('should handle complex paths', 1, function() { From 5c9585b2b0d10521c9e73053e3d7acc3cda95c35 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sat, 5 Sep 2015 22:29:11 -0700 Subject: [PATCH 265/935] Ensure correct execution order of `_.modArgs` transforms. --- lodash.js | 13 ++++++++----- test/test.js | 9 +++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/lodash.js b/lodash.js index d3f048af01..a045e7c981 100644 --- a/lodash.js +++ b/lodash.js @@ -3527,13 +3527,16 @@ if (typeof func != 'function' || !arrayEvery(transforms, baseIsFunction)) { throw new TypeError(FUNC_ERROR_TEXT); } - var length = transforms.length; + var funcsLength = transforms.length; return restParam(function(args) { - var index = nativeMin(args.length, length); - while (index--) { - args[index] = transforms[index].apply(this, resolver(args[index], index, args)); + var index = -1, + length = nativeMin(args.length, funcsLength), + modded = copyArray(args); + + while (++index < length) { + modded[index] = transforms[index].apply(this, resolver(args[index], index, args)); } - return func.apply(this, args); + return func.apply(this, modded); }); }); } diff --git a/test/test.js b/test/test.js index eac16e5aa3..9e9f407c28 100644 --- a/test/test.js +++ b/test/test.js @@ -11120,6 +11120,15 @@ deepEqual(modded(5), [10]); }); + test('should provide the correct argument to each transform', 1, function() { + var argsList = [], + transform = function() { argsList.push(slice.call(arguments)); }, + modded = _.modArgs(_.noop, transform, transform, transform); + + modded('a', 'b', 'c'); + deepEqual(argsList, [['a'], ['b'], ['c']]); + }); + test('should use `this` binding of function for transforms', 1, function() { var modded = _.modArgs(function(x) { return this[x]; From dfd4ae9ea4f0ec88f3b234c29590de872cfde1af Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sat, 5 Sep 2015 22:29:38 -0700 Subject: [PATCH 266/935] Add `_.modArgsSet`. --- lodash.js | 44 ++++++++++++++++++++++++++++++++++++++++---- test/test.js | 3 ++- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/lodash.js b/lodash.js index a045e7c981..5c2e0de1d3 100644 --- a/lodash.js +++ b/lodash.js @@ -7600,16 +7600,51 @@ * return [x, y]; * }, square, doubled); * - * modded(3, 4); - * // => [9, 8] + * modded(9, 3); + * // => [81, 6] * - * modded(5, 10); - * // => [25, 20] + * modded(10, 5); + * // => [100, 10] */ var modArgs = createModArgs(function(value) { return [value]; }); + /** + * This method is like `_.modArgs` except that each transform function is + * provided all arguments the created function is invoked with. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to wrap. + * @param {...(Function|Function[])} [transforms] The functions to transform + * arguments, specified individually or in arrays. + * @returns {Function} Returns the new function. + * @example + * + * function multiply(x, y) { + * return x * y; + * } + * + * function divide(x, y) { + * return x / y; + * } + * + * var modded = _.modArgsSet(function(x, y) { + * return [x, y]; + * }, multiply, divide); + * + * modded(9, 3); + * // => [27, 3] + * + * modded(10, 5); + * // => [50, 2] + */ + var modArgsSet = createModArgs(function(value, index, args) { + return args; + }); + /** * Creates a function that negates the result of the predicate `func`. The * `func` predicate is invoked with the `this` binding and arguments of the @@ -11833,6 +11868,7 @@ lodash.methodOf = methodOf; lodash.mixin = mixin; lodash.modArgs = modArgs; + lodash.modArgsSet = modArgsSet; lodash.negate = negate; lodash.omit = omit; lodash.omitBy = omitBy; diff --git a/test/test.js b/test/test.js index 9e9f407c28..3e71144ac6 100644 --- a/test/test.js +++ b/test/test.js @@ -17638,6 +17638,7 @@ 'delay', 'memoize', 'modArgs', + 'modArgsSet', 'negate', 'once', 'partial', @@ -17753,7 +17754,7 @@ }); }); - test('should throw an error for falsey arguments', 23, function() { + test('should throw an error for falsey arguments', 24, function() { _.each(rejectFalsey, function(methodName) { var expected = _.map(falsey, _.constant(true)), func = _[methodName]; From 38a16805ede182832109eaaf58cba1c0f30c3518 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sun, 6 Sep 2015 17:01:17 -0700 Subject: [PATCH 267/935] Optimize map and set comparisons in `_.isEqual`. --- lodash.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lodash.js b/lodash.js index 5c2e0de1d3..e076f883a8 100644 --- a/lodash.js +++ b/lodash.js @@ -2304,7 +2304,7 @@ isSameTag = objTag == othTag; if (isSameTag && !(objIsArr || objIsObj)) { - return equalByTag(object, other, objTag, equalFunc); + return equalByTag(object, other, objTag, equalFunc, bitmask); } var isPartial = bitmask & PARTIAL_COMPARE_FLAG; if (!isPartial) { @@ -3753,9 +3753,10 @@ * @param {Object} other The other object to compare. * @param {string} tag The `toStringTag` of the objects to compare. * @param {Function} equalFunc The function to determine equivalents of values. + * @param {number} [bitmask] The bitmask of comparison flags. See `baseIsEqual` for more details. * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. */ - function equalByTag(object, other, tag, equalFunc) { + function equalByTag(object, other, tag, equalFunc, bitmask) { switch (tag) { case boolTag: case dateTag: @@ -3782,8 +3783,10 @@ var convert = mapToArray; case setTag: + var isPartial = bitmask & PARTIAL_COMPARE_FLAG; convert || (convert = setToArray); - return equalFunc(convert(object), convert(other), undefined, UNORDERED_COMPARE_FLAG); + return (isPartial || object.size == other.size) && + equalFunc(convert(object), convert(other), undefined, bitmask | UNORDERED_COMPARE_FLAG); } return false; } From fc69fe1f2146733698548c63d558b33caa16ea68 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sun, 6 Sep 2015 18:00:28 -0700 Subject: [PATCH 268/935] Use map.size and set.size in `mapToArray` and `setToArray`. --- lodash.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lodash.js b/lodash.js index e076f883a8..94acc1b205 100644 --- a/lodash.js +++ b/lodash.js @@ -1148,9 +1148,11 @@ * @returns {Array} Returns the converted array. */ function mapToArray(map) { - var result = []; + var index = -1, + result = Array(map.size); + map.forEach(function(value, key) { - result.push([key, value]); + result[++index] = [key, value]; }); return result; } @@ -1187,9 +1189,11 @@ * @returns {Array} Returns the converted array. */ function setToArray(set) { - var result = []; + var index = -1, + result = Array(set.size); + set.forEach(function(value) { - result.push(value); + result[++index] = value; }); return result; } From 08f8e659fdd47b453d537f532014f8f1cb0a30ff Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sun, 6 Sep 2015 19:38:42 -0700 Subject: [PATCH 269/935] Cleanup `_.matches` and `_.matchesProperty` tests. --- test/test.js | 432 ++++++++++++++++++++++++--------------------------- 1 file changed, 206 insertions(+), 226 deletions(-) diff --git a/test/test.js b/test/test.js index 3e71144ac6..577c0a2505 100644 --- a/test/test.js +++ b/test/test.js @@ -9434,7 +9434,7 @@ strictEqual(matches(object), true); }); - test('should match inherited `value` properties', 1, function() { + test('should match inherited `object` properties', 1, function() { function Foo() { this.a = 1; } Foo.prototype.b = 2; @@ -9444,56 +9444,18 @@ strictEqual(matches(object), true); }); - test('should match `-0` as `0`', 2, function() { - var object1 = { 'a': -0 }, - object2 = { 'a': 0 }, - matches = _.matches(object1); - - strictEqual(matches(object2), true); - - matches = _.matches(object2); - strictEqual(matches(object1), true); - }); - test('should not match by inherited `source` properties', 1, function() { function Foo() { this.a = 1; } Foo.prototype.b = 2; var objects = [{ 'a': 1 }, { 'a': 1, 'b': 2 }], source = new Foo, - matches = _.matches(source), - actual = _.map(objects, matches), + actual = _.map(objects, _.matches(source)), expected = _.map(objects, _.constant(true)); deepEqual(actual, expected); }); - test('should return `false` when `object` is nullish', 1, function() { - var values = [, null, undefined], - expected = _.map(values, _.constant(false)), - matches = _.matches({ 'a': 1 }); - - var actual = _.map(values, function(value, index) { - try { - return index ? matches(value) : matches(); - } catch (e) {} - }); - - deepEqual(actual, expected); - }); - - test('should return `true` when comparing an empty `source`', 1, function() { - var object = { 'a': 1 }, - expected = _.map(empties, _.constant(true)); - - var actual = _.map(empties, function(value) { - var matches = _.matches(value); - return matches(object); - }); - - deepEqual(actual, expected); - }); - test('should compare a variety of `source` property values', 2, function() { var object1 = { 'a': false, 'b': true, 'c': '3', 'd': 4, 'e': [5], 'f': { 'g': 6 } }, object2 = { 'a': 0, 'b': 1, 'c': 3, 'd': '4', 'e': ['5'], 'f': { 'g': '6' } }, @@ -9503,6 +9465,17 @@ strictEqual(matches(object2), false); }); + test('should match `-0` as `0`', 2, function() { + var object1 = { 'a': -0 }, + object2 = { 'a': 0 }, + matches = _.matches(object1); + + strictEqual(matches(object2), true); + + matches = _.matches(object2); + strictEqual(matches(object1), true); + }); + test('should compare functions by reference', 3, function() { var object1 = { 'a': _.noop }, object2 = { 'a': noop }, @@ -9514,104 +9487,76 @@ strictEqual(matches(object3), false); }); - test('should not change match behavior if `source` is modified', 9, function() { - var sources = [ - { 'a': { 'b': 2, 'c': 3 } }, - { 'a': 1, 'b': 2 }, - { 'a': 1 } - ]; - - _.each(sources, function(source, index) { - var object = _.cloneDeep(source), - matches = _.matches(source); - - strictEqual(matches(object), true); - - if (index) { - source.a = 2; - source.b = 1; - source.c = 3; - } else { - source.a.b = 1; - source.a.c = 2; - source.a.d = 3; - } - strictEqual(matches(object), true); - strictEqual(matches(source), false); - }); - }); - - test('should return `true` when comparing a `source` of empty arrays and objects', 1, function() { - var objects = [{ 'a': [1], 'b': { 'c': 1 } }, { 'a': [2, 3], 'b': { 'd': 2 } }], - matches = _.matches({ 'a': [], 'b': {} }), - actual = _.filter(objects, matches); + test('should work with a function for `object`', 1, function() { + function Foo() {} + Foo.a = { 'b': 1, 'c': 2 }; - deepEqual(actual, objects); + var matches = _.matches({ 'a': { 'b': 1 } }); + strictEqual(matches(Foo), true); }); - test('should return `true` when comparing an empty `source` to a nullish `object`', 1, function() { - var values = [, null, undefined], - expected = _.map(values, _.constant(true)), - matches = _.matches({}); + test('should work with a function for `source`', 1, function() { + function Foo() {} + Foo.a = 1; + Foo.b = function() {}; + Foo.c = 3; - var actual = _.map(values, function(value, index) { - try { - return index ? matches(value) : matches(); - } catch (e) {} - }); + var objects = [{ 'a': 1 }, { 'a': 1, 'b': Foo.b, 'c': 3 }], + actual = _.map(objects, _.matches(Foo)); - deepEqual(actual, expected); + deepEqual(actual, [false, true]); }); - test('should search arrays of `source` for values', 3, function() { + test('should partial match arrays', 3, function() { var objects = [{ 'a': ['b'] }, { 'a': ['c', 'd'] }], - matches = _.matches({ 'a': ['d'] }), - actual = _.filter(objects, matches); + actual = _.filter(objects, _.matches({ 'a': ['d'] })); deepEqual(actual, [objects[1]]); - matches = _.matches({ 'a': ['b', 'd'] }); - actual = _.filter(objects, matches); + actual = _.filter(objects, _.matches({ 'a': ['b', 'd'] })); deepEqual(actual, []); - matches = _.matches({ 'a': ['d', 'b'] }); - actual = _.filter(objects, matches); + actual = _.filter(objects, _.matches({ 'a': ['d', 'b'] })); deepEqual(actual, []); }); - test('should perform a partial comparison of all objects within arrays of `source`', 1, function() { + test('should partial match arrays of objects', 1, function() { var objects = [ { 'a': [{ 'b': 1, 'c': 2 }, { 'b': 4, 'c': 5, 'd': 6 }] }, { 'a': [{ 'b': 1, 'c': 2 }, { 'b': 4, 'c': 6, 'd': 7 }] } ]; - var matches = _.matches({ 'a': [{ 'b': 1 }, { 'b': 4, 'c': 5 }] }), - actual = _.filter(objects, matches); - + var actual = _.filter(objects, _.matches({ 'a': [{ 'b': 1 }, { 'b': 4, 'c': 5 }] })); deepEqual(actual, [objects[0]]); }); - test('should handle a `source` with `undefined` values', 3, function() { + test('should match properties when `object` is not a plain object', 1, function() { + function Foo(object) { _.assign(this, object); } + + var object = new Foo({ 'a': new Foo({ 'b': 1, 'c': 2 }) }), + matches = _.matches({ 'a': { 'b': 1 } }); + + strictEqual(matches(object), true); + }); + + test('should match `undefined` values', 3, function() { var objects = [{ 'a': 1 }, { 'a': 1, 'b': 1 }, { 'a': 1, 'b': undefined }], - matches = _.matches({ 'b': undefined }), - actual = _.map(objects, matches), + actual = _.map(objects, _.matches({ 'b': undefined })), expected = [false, false, true]; deepEqual(actual, expected); - matches = _.matches({ 'a': 1, 'b': undefined }); - actual = _.map(objects, matches); + actual = _.map(objects, _.matches({ 'a': 1, 'b': undefined })); deepEqual(actual, expected); objects = [{ 'a': { 'b': 1 } }, { 'a': { 'b':1, 'c': 1 } }, { 'a': { 'b': 1, 'c': undefined } }]; - matches = _.matches({ 'a': { 'c': undefined } }); - actual = _.map(objects, matches); + actual = _.map(objects, _.matches({ 'a': { 'c': undefined } })); deepEqual(actual, expected); }); - test('should handle a primitive `object` and a `source` with `undefined` values', 3, function() { + test('should match `undefined` values on primitives', 3, function() { numberProto.a = 1; numberProto.b = undefined; @@ -9638,34 +9583,78 @@ delete numberProto.b; }); - test('should match properties when `value` is a function', 1, function() { - function Foo() {} - Foo.a = { 'b': 1, 'c': 2 }; + test('should return `false` when `object` is nullish', 1, function() { + var values = [, null, undefined], + expected = _.map(values, _.constant(false)), + matches = _.matches({ 'a': 1 }); - var matches = _.matches({ 'a': { 'b': 1 } }); - strictEqual(matches(Foo), true); + var actual = _.map(values, function(value, index) { + try { + return index ? matches(value) : matches(); + } catch (e) {} + }); + + deepEqual(actual, expected); }); - test('should match properties when `value` is not a plain object', 1, function() { - function Foo(object) { _.assign(this, object); } + test('should return `true` when comparing an empty `source` to a nullish `object`', 1, function() { + var values = [, null, undefined], + expected = _.map(values, _.constant(true)), + matches = _.matches({}); - var object = new Foo({ 'a': new Foo({ 'b': 1, 'c': 2 }) }), - matches = _.matches({ 'a': { 'b': 1 } }); + var actual = _.map(values, function(value, index) { + try { + return index ? matches(value) : matches(); + } catch (e) {} + }); - strictEqual(matches(object), true); + deepEqual(actual, expected); }); - test('should work with a function for `source`', 1, function() { - function source() {} - source.a = 1; - source.b = function() {}; - source.c = 3; + test('should return `true` when comparing an empty `source`', 1, function() { + var object = { 'a': 1 }, + expected = _.map(empties, _.constant(true)); + + var actual = _.map(empties, function(value) { + var matches = _.matches(value); + return matches(object); + }); - var matches = _.matches(source), - objects = [{ 'a': 1 }, { 'a': 1, 'b': source.b, 'c': 3 }], - actual = _.map(objects, matches); + deepEqual(actual, expected); + }); - deepEqual(actual, [false, true]); + test('should return `true` when comparing a `source` of empty arrays and objects', 1, function() { + var objects = [{ 'a': [1], 'b': { 'c': 1 } }, { 'a': [2, 3], 'b': { 'd': 2 } }], + actual = _.filter(objects, _.matches({ 'a': [], 'b': {} })); + + deepEqual(actual, objects); + }); + + test('should not change match behavior if `source` is modified', 9, function() { + var sources = [ + { 'a': { 'b': 2, 'c': 3 } }, + { 'a': 1, 'b': 2 }, + { 'a': 1 } + ]; + + _.each(sources, function(source, index) { + var object = _.cloneDeep(source), + matches = _.matches(source); + + strictEqual(matches(object), true); + + if (index) { + source.a = 2; + source.b = 1; + source.c = 3; + } else { + source.a.b = 1; + source.a.c = 2; + source.a.d = 3; + } + strictEqual(matches(object), true); + strictEqual(matches(source), false); + }); }); }()); @@ -9674,7 +9663,7 @@ QUnit.module('lodash.matchesProperty'); (function() { - test('should create a function that performs a deep comparison between a property value and `value`', 6, function() { + test('should create a function that performs a deep comparison between a property value and `srcValue`', 6, function() { var object = { 'a': 1, 'b': 2, 'c': 3 }, matches = _.matchesProperty('a', 1); @@ -9754,44 +9743,11 @@ }); }); - test('should match inherited `value` properties', 2, function() { - function Foo() {} - Foo.prototype.b = 2; - - var object = { 'a': new Foo }; - - _.each(['a', ['a']], function(path) { - var matches = _.matchesProperty(path, { 'b': 2 }); - strictEqual(matches(object), true); - }); - }); - - test('should match `-0` as `0`', 2, function() { - var matches = _.matchesProperty('a', -0); - strictEqual(matches({ 'a': 0 }), true); - - matches = _.matchesProperty('a', 0); - strictEqual(matches({ 'a': -0 }), true); - }); - - test('should not match by inherited `source` properties', 2, function() { - function Foo() { this.a = 1; } - Foo.prototype.b = 2; - - var objects = [{ 'a': { 'a': 1 } }, { 'a': { 'a': 1, 'b': 2 } }], - expected = _.map(objects, _.constant(true)); - - _.each(['a', ['a']], function(path) { - var matches = _.matchesProperty(path, new Foo); - deepEqual(_.map(objects, matches), expected); - }); - }); - - test('should return `false` when `object` is nullish', 2, function() { + test('should return `false` with deep paths when `object` is nullish', 2, function() { var values = [, null, undefined], expected = _.map(values, _.constant(false)); - _.each(['constructor', ['constructor']], function(path) { + _.each(['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']], function(path) { var matches = _.matchesProperty(path, 1); var actual = _.map(values, function(value, index) { @@ -9804,20 +9760,27 @@ }); }); - test('should return `false` with deep paths when `object` is nullish', 2, function() { - var values = [, null, undefined], - expected = _.map(values, _.constant(false)); + test('should match inherited `srcValue` properties', 2, function() { + function Foo() {} + Foo.prototype.b = 2; - _.each(['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']], function(path) { - var matches = _.matchesProperty(path, 1); + var object = { 'a': new Foo }; - var actual = _.map(values, function(value, index) { - try { - return index ? matches(value) : matches(); - } catch (e) {} - }); + _.each(['a', ['a']], function(path) { + var matches = _.matchesProperty(path, { 'b': 2 }); + strictEqual(matches(object), true); + }); + }); - deepEqual(actual, expected); + test('should not match by inherited `srcValue` properties', 2, function() { + function Foo() { this.a = 1; } + Foo.prototype.b = 2; + + var objects = [{ 'a': { 'a': 1 } }, { 'a': { 'a': 1, 'b': 2 } }], + expected = _.map(objects, _.constant(true)); + + _.each(['a', ['a']], function(path) { + deepEqual(_.map(objects, _.matchesProperty(path, new Foo)), expected); }); }); @@ -9830,6 +9793,14 @@ strictEqual(matches({ 'a': object2 }), false); }); + test('should match `-0` as `0`', 2, function() { + var matches = _.matchesProperty('a', -0); + strictEqual(matches({ 'a': 0 }), true); + + matches = _.matchesProperty('a', 0); + strictEqual(matches({ 'a': -0 }), true); + }); + test('should compare functions by reference', 3, function() { var object1 = { 'a': _.noop }, object2 = { 'a': noop }, @@ -9841,82 +9812,81 @@ strictEqual(matches({ 'a': object3 }), false); }); - test('should not change match behavior if `value` is modified', 9, function() { - _.each([{ 'a': { 'b': 2, 'c': 3 } }, { 'a': 1, 'b': 2 }, { 'a': 1 }], function(source, index) { - var object = _.cloneDeep(source), - matches = _.matchesProperty('a', source); - - strictEqual(matches({ 'a': object }), true); - - if (index) { - source.a = 2; - source.b = 1; - source.c = 3; - } else { - source.a.b = 1; - source.a.c = 2; - source.a.d = 3; - } - strictEqual(matches({ 'a': object }), true); - strictEqual(matches({ 'a': source }), false); - }); - }); - - test('should return `true` when comparing a `value` of empty arrays and objects', 1, function() { - var objects = [{ 'a': [1], 'b': { 'c': 1 } }, { 'a': [2, 3], 'b': { 'd': 2 } }], - matches = _.matchesProperty('a', { 'a': [], 'b': {} }); + test('should work with a function for `srcValue`', 1, function() { + function Foo() {} + Foo.a = 1; + Foo.b = function() {}; + Foo.c = 3; - var actual = _.filter(objects, function(object) { - return matches({ 'a': object }); - }); + var objects = [{ 'a': { 'a': 1 } }, { 'a': { 'a': 1, 'b': Foo.b, 'c': 3 } }], + actual = _.map(objects, _.matchesProperty('a', Foo)); - deepEqual(actual, objects); + deepEqual(actual, [false, true]); }); - test('should search arrays of `value` for values', 3, function() { + test('should partial match arrays', 3, function() { var objects = [{ 'a': ['b'] }, { 'a': ['c', 'd'] }], - matches = _.matchesProperty('a', ['d']), - actual = _.filter(objects, matches); + actual = _.filter(objects, _.matchesProperty('a', ['d'])); deepEqual(actual, [objects[1]]); - matches = _.matchesProperty('a', ['b', 'd']); - actual = _.filter(objects, matches); + actual = _.filter(objects, _.matchesProperty('a', ['b', 'd'])); deepEqual(actual, []); - matches = _.matchesProperty('a', ['d', 'b']); - actual = _.filter(objects, matches); + actual = _.filter(objects, _.matchesProperty('a', ['d', 'b'])); deepEqual(actual, []); }); - test('should perform a partial comparison of all objects within arrays of `value`', 1, function() { + test('should partial match arrays of objects', 1, function() { var objects = [ { 'a': [{ 'a': 1, 'b': 2 }, { 'a': 4, 'b': 5, 'c': 6 }] }, { 'a': [{ 'a': 1, 'b': 2 }, { 'a': 4, 'b': 6, 'c': 7 }] } ]; - var matches = _.matchesProperty('a', [{ 'a': 1 }, { 'a': 4, 'b': 5 }]), - actual = _.filter(objects, matches); - + var actual = _.filter(objects, _.matchesProperty('a', [{ 'a': 1 }, { 'a': 4, 'b': 5 }])); deepEqual(actual, [objects[0]]); }); - test('should handle a `value` with `undefined` values', 2, function() { + test('should match properties when `srcValue` is not a plain object', 1, function() { + function Foo(object) { _.assign(this, object); } + + var object = new Foo({ 'a': new Foo({ 'b': 1, 'c': 2 }) }), + matches = _.matchesProperty('a', { 'b': 1 }); + + strictEqual(matches(object), true); + }); + + test('should match `undefined` values', 2, function() { var objects = [{ 'a': 1 }, { 'a': 1, 'b': 1 }, { 'a': 1, 'b': undefined }], - matches = _.matchesProperty('b', undefined), - actual = _.map(objects, matches), + actual = _.map(objects, _.matchesProperty('b', undefined)), expected = [false, false, true]; deepEqual(actual, expected); objects = [{ 'a': { 'a': 1 } }, { 'a': { 'a': 1, 'b': 1 } }, { 'a': { 'a': 1, 'b': undefined } }]; - matches = _.matchesProperty('a', { 'b': undefined }); - actual = _.map(objects, matches); + actual = _.map(objects, _.matchesProperty('a', { 'b': undefined })); deepEqual(actual, expected); }); - test('should handle a primitive `object` and a `source` with `undefined` values', 2, function() { + test('should return `false` when `object` is nullish', 2, function() { + var values = [, null, undefined], + expected = _.map(values, _.constant(false)); + + _.each(['constructor', ['constructor']], function(path) { + var matches = _.matchesProperty(path, 1); + + var actual = _.map(values, function(value, index) { + try { + return index ? matches(value) : matches(); + } catch (e) {} + }); + + deepEqual(actual, expected); + }); + }); + + test('should match `undefined` values on primitives', 2, function() { numberProto.a = 1; numberProto.b = undefined; @@ -9937,26 +9907,36 @@ delete numberProto.b; }); - test('should work with a function for `value`', 1, function() { - function source() {} - source.a = 1; - source.b = function() {}; - source.c = 3; + test('should return `true` when comparing a `srcValue` of empty arrays and objects', 1, function() { + var objects = [{ 'a': [1], 'b': { 'c': 1 } }, { 'a': [2, 3], 'b': { 'd': 2 } }], + matches = _.matchesProperty('a', { 'a': [], 'b': {} }); - var matches = _.matchesProperty('a', source), - objects = [{ 'a': { 'a': 1 } }, { 'a': { 'a': 1, 'b': source.b, 'c': 3 } }], - actual = _.map(objects, matches); + var actual = _.filter(objects, function(object) { + return matches({ 'a': object }); + }); - deepEqual(actual, [false, true]); + deepEqual(actual, objects); }); - test('should match properties when `value` is not a plain object', 1, function() { - function Foo(object) { _.assign(this, object); } + test('should not change match behavior if `srcValue` is modified', 9, function() { + _.each([{ 'a': { 'b': 2, 'c': 3 } }, { 'a': 1, 'b': 2 }, { 'a': 1 }], function(source, index) { + var object = _.cloneDeep(source), + matches = _.matchesProperty('a', source); - var object = new Foo({ 'a': new Foo({ 'b': 1, 'c': 2 }) }), - matches = _.matchesProperty('a', { 'b': 1 }); + strictEqual(matches({ 'a': object }), true); - strictEqual(matches(object), true); + if (index) { + source.a = 2; + source.b = 1; + source.c = 3; + } else { + source.a.b = 1; + source.a.c = 2; + source.a.d = 3; + } + strictEqual(matches({ 'a': object }), true); + strictEqual(matches({ 'a': source }), false); + }); }); }()); From 1e1e4fd557664ea5a6f1e8c1b5f4d0890fed6469 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sun, 6 Sep 2015 20:04:30 -0700 Subject: [PATCH 270/935] Add `_.matches` and `_.matchesProperty` tests for partial matching maps and sets. --- test/test.js | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/test/test.js b/test/test.js index 577c0a2505..c008555fa7 100644 --- a/test/test.js +++ b/test/test.js @@ -9530,6 +9530,52 @@ deepEqual(actual, [objects[0]]); }); + test('should partial match maps', 3, function() { + var objects = [{ 'a': new Map }, { 'a': new Map }]; + objects[0].a.set('a', 1); + objects[1].a.set('a', 1); + objects[1].a.set('b', 2); + + var map = new Map; + map.set('b', 2); + var actual = _.filter(objects, _.matches({ 'a': map })); + + deepEqual(actual, [objects[1]]); + + map['delete']('b'); + actual = _.filter(objects, _.matches({ 'a': map })); + + deepEqual(actual, objects); + + map.set('c', 3); + actual = _.filter(objects, _.matches({ 'a': map })); + + deepEqual(actual, []); + }); + + test('should partial match sets', 3, function() { + var objects = [{ 'a': new Set }, { 'a': new Set }]; + objects[0].a.add(1); + objects[1].a.add(1); + objects[1].a.add(2); + + var set = new Set; + set.add(2); + var actual = _.filter(objects, _.matches({ 'a': set })); + + deepEqual(actual, [objects[1]]); + + set['delete'](2); + actual = _.filter(objects, _.matches({ 'a': set })); + + deepEqual(actual, objects); + + set.add(3); + actual = _.filter(objects, _.matches({ 'a': set })); + + deepEqual(actual, []); + }); + test('should match properties when `object` is not a plain object', 1, function() { function Foo(object) { _.assign(this, object); } @@ -9846,6 +9892,51 @@ var actual = _.filter(objects, _.matchesProperty('a', [{ 'a': 1 }, { 'a': 4, 'b': 5 }])); deepEqual(actual, [objects[0]]); }); + test('should partial match maps', 3, function() { + var objects = [{ 'a': new Map }, { 'a': new Map }]; + objects[0].a.set('a', 1); + objects[1].a.set('a', 1); + objects[1].a.set('b', 2); + + var map = new Map; + map.set('b', 2); + var actual = _.filter(objects, _.matchesProperty('a', map)); + + deepEqual(actual, [objects[1]]); + + map['delete']('b'); + actual = _.filter(objects, _.matchesProperty('a', map)); + + deepEqual(actual, objects); + + map.set('c', 3); + actual = _.filter(objects, _.matchesProperty('a', map)); + + deepEqual(actual, []); + }); + + test('should partial match sets', 3, function() { + var objects = [{ 'a': new Set }, { 'a': new Set }]; + objects[0].a.add(1); + objects[1].a.add(1); + objects[1].a.add(2); + + var set = new Set; + set.add(2); + var actual = _.filter(objects, _.matchesProperty('a', set)); + + deepEqual(actual, [objects[1]]); + + set['delete'](2); + actual = _.filter(objects, _.matchesProperty('a', set)); + + deepEqual(actual, objects); + + set.add(3); + actual = _.filter(objects, _.matchesProperty('a', set)); + + deepEqual(actual, []); + }); test('should match properties when `srcValue` is not a plain object', 1, function() { function Foo(object) { _.assign(this, object); } From 9da03f529f69a91d90627ae206c29c14005f7feb Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sun, 6 Sep 2015 21:05:05 -0700 Subject: [PATCH 271/935] Ensure `equalByTag` passing `customizer` to `equalFunc`. --- lodash.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lodash.js b/lodash.js index 94acc1b205..a0e0ce0595 100644 --- a/lodash.js +++ b/lodash.js @@ -2308,7 +2308,7 @@ isSameTag = objTag == othTag; if (isSameTag && !(objIsArr || objIsObj)) { - return equalByTag(object, other, objTag, equalFunc, bitmask); + return equalByTag(object, other, objTag, equalFunc, customizer, bitmask); } var isPartial = bitmask & PARTIAL_COMPARE_FLAG; if (!isPartial) { @@ -3757,10 +3757,11 @@ * @param {Object} other The other object to compare. * @param {string} tag The `toStringTag` of the objects to compare. * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Function} [customizer] The function to customize comparisons. * @param {number} [bitmask] The bitmask of comparison flags. See `baseIsEqual` for more details. * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. */ - function equalByTag(object, other, tag, equalFunc, bitmask) { + function equalByTag(object, other, tag, equalFunc, customizer, bitmask) { switch (tag) { case boolTag: case dateTag: @@ -3789,8 +3790,10 @@ case setTag: var isPartial = bitmask & PARTIAL_COMPARE_FLAG; convert || (convert = setToArray); + + // Recursively compare objects (susceptible to call stack limits). return (isPartial || object.size == other.size) && - equalFunc(convert(object), convert(other), undefined, bitmask | UNORDERED_COMPARE_FLAG); + equalFunc(convert(object), convert(other), customizer, bitmask | UNORDERED_COMPARE_FLAG); } return false; } From f6500eafb61b3fdd0970ef1fef2fbf3b7fad428c Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sun, 6 Sep 2015 22:29:50 -0700 Subject: [PATCH 272/935] Cleanup `_.isMatch` tests. --- test/test.js | 233 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 160 insertions(+), 73 deletions(-) diff --git a/test/test.js b/test/test.js index c008555fa7..fe5ed11efe 100644 --- a/test/test.js +++ b/test/test.js @@ -7319,14 +7319,6 @@ strictEqual(_.isMatch({ 'a': new Foo }, { 'a': { 'b': 2 } }), true); }); - test('should match `-0` as `0`', 2, function() { - var object1 = { 'a': -0 }, - object2 = { 'a': 0 }; - - strictEqual(_.isMatch(object1, object2), true); - strictEqual(_.isMatch(object2, object1), true); - }); - test('should not match by inherited `source` properties', 1, function() { function Foo() { this.a = 1; } Foo.prototype.b = 2; @@ -7342,31 +7334,6 @@ deepEqual(actual, expected); }); - test('should return `false` when `object` is nullish', 1, function() { - var values = [null, undefined], - expected = _.map(values, _.constant(false)), - source = { 'a': 1 }; - - var actual = _.map(values, function(value) { - try { - return _.isMatch(value, source); - } catch (e) {} - }); - - deepEqual(actual, expected); - }); - - test('should return `true` when comparing an empty `source`', 1, function() { - var object = { 'a': 1 }, - expected = _.map(empties, _.constant(true)); - - var actual = _.map(empties, function(value) { - return _.isMatch(object, value); - }); - - deepEqual(actual, expected); - }); - test('should compare a variety of `source` property values', 2, function() { var object1 = { 'a': false, 'b': true, 'c': '3', 'd': 4, 'e': [5], 'f': { 'g': 6 } }, object2 = { 'a': 0, 'b': 1, 'c': 3, 'd': '4', 'e': ['5'], 'f': { 'g': '6' } }; @@ -7375,47 +7342,47 @@ strictEqual(_.isMatch(object1, object2), false); }); - test('should work with a function for `source`', 1, function() { - function source() {} - source.a = 1; - source.b = function() {}; - source.c = 3; + test('should match `-0` as `0`', 2, function() { + var object1 = { 'a': -0 }, + object2 = { 'a': 0 }; - var objects = [{ 'a': 1 }, { 'a': 1, 'b': source.b, 'c': 3 }]; + strictEqual(_.isMatch(object1, object2), true); + strictEqual(_.isMatch(object2, object1), true); + }); - var actual = _.map(objects, function(object) { - return _.isMatch(object, source); - }); + test('should compare functions by reference', 3, function() { + var object1 = { 'a': _.noop }, + object2 = { 'a': noop }, + object3 = { 'a': {} }; - deepEqual(actual, [false, true]); + strictEqual(_.isMatch(object1, object1), true); + strictEqual(_.isMatch(object2, object1), false); + strictEqual(_.isMatch(object3, object1), false); }); - test('should return `true` when comparing a `source` of empty arrays and objects', 1, function() { - var objects = [{ 'a': [1], 'b': { 'c': 1 } }, { 'a': [2, 3], 'b': { 'd': 2 } }], - source = { 'a': [], 'b': {} }; - - var actual = _.filter(objects, function(object) { - return _.isMatch(object, source); - }); + test('should work with a function for `object`', 1, function() { + function Foo() {} + Foo.a = { 'b': 1, 'c': 2 }; - deepEqual(actual, objects); + strictEqual(_.isMatch(Foo, { 'a': { 'b': 1 } }), true); }); - test('should return `true` when comparing an empty `source` to a nullish `object`', 1, function() { - var values = [null, undefined], - expected = _.map(values, _.constant(true)), - source = {}; + test('should work with a function for `source`', 1, function() { + function Foo() {} + Foo.a = 1; + Foo.b = function() {}; + Foo.c = 3; - var actual = _.map(values, function(value) { - try { - return _.isMatch(value, source); - } catch (e) {} + var objects = [{ 'a': 1 }, { 'a': 1, 'b': Foo.b, 'c': 3 }]; + + var actual = _.map(objects, function(object) { + return _.isMatch(object, Foo); }); - deepEqual(actual, expected); + deepEqual(actual, [false, true]); }); - test('should search arrays of `source` for values', 3, function() { + test('should partial match arrays', 3, function() { var objects = [{ 'a': ['b'] }, { 'a': ['c', 'd'] }], source = { 'a': ['d'] }, predicate = function(object) { return _.isMatch(object, source); }, @@ -7433,7 +7400,7 @@ deepEqual(actual, []); }); - test('should perform a partial comparison of all objects within arrays of `source`', 1, function() { + test('should partial match arrays of objects', 1, function() { var source = { 'a': [{ 'b': 1 }, { 'b': 4, 'c': 5 }] }; var objects = [ @@ -7448,7 +7415,70 @@ deepEqual(actual, [objects[0]]); }); - test('should handle a `source` with `undefined` values', 3, function() { + test('should partial match maps', 3, function() { + var objects = [{ 'a': new Map }, { 'a': new Map }]; + objects[0].a.set('a', 1); + objects[1].a.set('a', 1); + objects[1].a.set('b', 2); + + var map = new Map; + map.set('b', 2); + + var source = { 'a': map }, + predicate = function(object) { return _.isMatch(object, source); }, + actual = _.filter(objects, predicate); + + deepEqual(actual, [objects[1]]); + + map['delete']('b'); + sourece = { 'a': map }; + actual = _.filter(objects, predicate); + + deepEqual(actual, objects); + + map.set('c', 3); + source = { 'a': map }; + actual = _.filter(objects, predicate); + + deepEqual(actual, []); + }); + + test('should partial match sets', 3, function() { + var objects = [{ 'a': new Set }, { 'a': new Set }]; + objects[0].a.add(1); + objects[1].a.add(1); + objects[1].a.add(2); + + var set = new Set; + set.add(2); + + var source = { 'a': set }, + predicate = function(object) { return _.isMatch(object, source); }, + actual = _.filter(objects, predicate); + + deepEqual(actual, [objects[1]]); + + set['delete'](2); + source = { 'a': set }; + actual = _.filter(objects, predicate); + + deepEqual(actual, objects); + + set.add(3); + source = { 'a': set }; + actual = _.filter(objects, predicate); + + deepEqual(actual, []); + }); + + test('should match properties when `object` is not a plain object', 1, function() { + function Foo(object) { _.assign(this, object); } + + var object = new Foo({ 'a': new Foo({ 'b': 1, 'c': 2 }) }); + strictEqual(_.isMatch(object, { 'a': { 'b': 1 } }), true); + }); + + test('should match `undefined` values', 3, function() { var objects = [{ 'a': 1 }, { 'a': 1, 'b': 1 }, { 'a': 1, 'b': undefined }], source = { 'b': undefined }, predicate = function(object) { return _.isMatch(object, source); }, @@ -7469,21 +7499,78 @@ deepEqual(actual, expected); }); - test('should match properties when `value` is a function', 1, function() { - function Foo() {} - Foo.a = { 'b': 1, 'c': 2 }; + test('should match `undefined` values on primitives', 3, function() { + numberProto.a = 1; + numberProto.b = undefined; - var matches = _.matches({ 'a': { 'b': 1 } }); - strictEqual(matches(Foo), true); + try { + strictEqual(_.isMatch(1, { 'b': undefined }), true); + } catch (e) { + ok(false, e.message); + } + try { + strictEqual(_.isMatch(1, { 'a': 1, 'b': undefined }), true); + } catch (e) { + ok(false, e.message); + } + numberProto.a = { 'b': 1, 'c': undefined }; + try { + strictEqual(_.isMatch(1, { 'a': { 'c': undefined } }), true); + } catch (e) { + ok(false, e.message); + } + delete numberProto.a; + delete numberProto.b; }); - test('should match properties when `value` is not a plain object', 1, function() { - function Foo(object) { _.assign(this, object); } + test('should return `false` when `object` is nullish', 1, function() { + var values = [null, undefined], + expected = _.map(values, _.constant(false)), + source = { 'a': 1 }; - var object = new Foo({ 'a': new Foo({ 'b': 1, 'c': 2 }) }), - matches = _.matches({ 'a': { 'b': 1 } }); + var actual = _.map(values, function(value) { + try { + return _.isMatch(value, source); + } catch (e) {} + }); - strictEqual(matches(object), true); + deepEqual(actual, expected); + }); + + test('should return `true` when comparing an empty `source` to a nullish `object`', 1, function() { + var values = [null, undefined], + expected = _.map(values, _.constant(true)), + source = {}; + + var actual = _.map(values, function(value) { + try { + return _.isMatch(value, source); + } catch (e) {} + }); + + deepEqual(actual, expected); + }); + + test('should return `true` when comparing an empty `source`', 1, function() { + var object = { 'a': 1 }, + expected = _.map(empties, _.constant(true)); + + var actual = _.map(empties, function(value) { + return _.isMatch(object, value); + }); + + deepEqual(actual, expected); + }); + + test('should return `true` when comparing a `source` of empty arrays and objects', 1, function() { + var objects = [{ 'a': [1], 'b': { 'c': 1 } }, { 'a': [2, 3], 'b': { 'd': 2 } }], + source = { 'a': [], 'b': {} }; + + var actual = _.filter(objects, function(object) { + return _.isMatch(object, source); + }); + + deepEqual(actual, objects); }); }()); From d81e029ec07b67a3cd7554959a209c09859f1b88 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sun, 6 Sep 2015 22:32:09 -0700 Subject: [PATCH 273/935] Add `_.isMatchWith` tests. --- test/test.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/test.js b/test/test.js index fe5ed11efe..1820a325e9 100644 --- a/test/test.js +++ b/test/test.js @@ -7613,6 +7613,24 @@ strictEqual(_.isMatchWith({ 'a': 1 }, { 'a': 1 }, _.noop), true); }); + test('should not handle comparisons if `customizer` returns `true`', 2, function() { + var customizer = function(value) { + return _.isString(value) || undefined; + }; + + strictEqual(_.isMatchWith(['a'], ['b'], customizer), true); + strictEqual(_.isMatchWith({ '0': 'a' }, { '0': 'b' }, customizer), true); + }); + + test('should not handle comparisons if `customizer` returns `false`', 2, function() { + var customizer = function(value) { + return _.isString(value) ? false : undefined; + }; + + strictEqual(_.isMatchWith(['a'], ['a'], customizer), false); + strictEqual(_.isMatchWith({ '0': 'a' }, { '0': 'a' }, customizer), false); + }); + test('should return a boolean value even if `customizer` does not', 2, function() { var object = { 'a': 1 }, actual = _.isMatchWith(object, { 'a': 1 }, _.constant('a')); From 7863256de5901d1907603da3a4250088a04fa9e0 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sun, 6 Sep 2015 22:41:07 -0700 Subject: [PATCH 274/935] Add map and set guards to tests to fix travis runs. --- test/test.js | 214 +++++++++++++++++++++++++++++---------------------- 1 file changed, 122 insertions(+), 92 deletions(-) diff --git a/test/test.js b/test/test.js index 1820a325e9..1dc5648433 100644 --- a/test/test.js +++ b/test/test.js @@ -7416,59 +7416,69 @@ }); test('should partial match maps', 3, function() { - var objects = [{ 'a': new Map }, { 'a': new Map }]; - objects[0].a.set('a', 1); - objects[1].a.set('a', 1); - objects[1].a.set('b', 2); + if (Map) { + var objects = [{ 'a': new Map }, { 'a': new Map }]; + objects[0].a.set('a', 1); + objects[1].a.set('a', 1); + objects[1].a.set('b', 2); - var map = new Map; - map.set('b', 2); + var map = new Map; + map.set('b', 2); - var source = { 'a': map }, - predicate = function(object) { return _.isMatch(object, source); }, - actual = _.filter(objects, predicate); + var source = { 'a': map }, + predicate = function(object) { return _.isMatch(object, source); }, + actual = _.filter(objects, predicate); - deepEqual(actual, [objects[1]]); + deepEqual(actual, [objects[1]]); - map['delete']('b'); - sourece = { 'a': map }; - actual = _.filter(objects, predicate); + map['delete']('b'); + sourece = { 'a': map }; + actual = _.filter(objects, predicate); - deepEqual(actual, objects); + deepEqual(actual, objects); - map.set('c', 3); - source = { 'a': map }; - actual = _.filter(objects, predicate); + map.set('c', 3); + source = { 'a': map }; + actual = _.filter(objects, predicate); - deepEqual(actual, []); + deepEqual(actual, []); + } + else { + skipTest(3); + } }); test('should partial match sets', 3, function() { - var objects = [{ 'a': new Set }, { 'a': new Set }]; - objects[0].a.add(1); - objects[1].a.add(1); - objects[1].a.add(2); + if (Set) { + var objects = [{ 'a': new Set }, { 'a': new Set }]; + objects[0].a.add(1); + objects[1].a.add(1); + objects[1].a.add(2); - var set = new Set; - set.add(2); + var set = new Set; + set.add(2); - var source = { 'a': set }, - predicate = function(object) { return _.isMatch(object, source); }, - actual = _.filter(objects, predicate); + var source = { 'a': set }, + predicate = function(object) { return _.isMatch(object, source); }, + actual = _.filter(objects, predicate); - deepEqual(actual, [objects[1]]); + deepEqual(actual, [objects[1]]); - set['delete'](2); - source = { 'a': set }; - actual = _.filter(objects, predicate); + set['delete'](2); + source = { 'a': set }; + actual = _.filter(objects, predicate); - deepEqual(actual, objects); + deepEqual(actual, objects); - set.add(3); - source = { 'a': set }; - actual = _.filter(objects, predicate); + set.add(3); + source = { 'a': set }; + actual = _.filter(objects, predicate); - deepEqual(actual, []); + deepEqual(actual, []); + } + else { + skipTest(3); + } }); test('should match properties when `object` is not a plain object', 1, function() { @@ -9636,49 +9646,59 @@ }); test('should partial match maps', 3, function() { - var objects = [{ 'a': new Map }, { 'a': new Map }]; - objects[0].a.set('a', 1); - objects[1].a.set('a', 1); - objects[1].a.set('b', 2); + if (Map) { + var objects = [{ 'a': new Map }, { 'a': new Map }]; + objects[0].a.set('a', 1); + objects[1].a.set('a', 1); + objects[1].a.set('b', 2); - var map = new Map; - map.set('b', 2); - var actual = _.filter(objects, _.matches({ 'a': map })); + var map = new Map; + map.set('b', 2); + var actual = _.filter(objects, _.matches({ 'a': map })); - deepEqual(actual, [objects[1]]); + deepEqual(actual, [objects[1]]); - map['delete']('b'); - actual = _.filter(objects, _.matches({ 'a': map })); + map['delete']('b'); + actual = _.filter(objects, _.matches({ 'a': map })); - deepEqual(actual, objects); + deepEqual(actual, objects); - map.set('c', 3); - actual = _.filter(objects, _.matches({ 'a': map })); + map.set('c', 3); + actual = _.filter(objects, _.matches({ 'a': map })); - deepEqual(actual, []); + deepEqual(actual, []); + } + else { + skipTest(3); + } }); test('should partial match sets', 3, function() { - var objects = [{ 'a': new Set }, { 'a': new Set }]; - objects[0].a.add(1); - objects[1].a.add(1); - objects[1].a.add(2); + if (Set) { + var objects = [{ 'a': new Set }, { 'a': new Set }]; + objects[0].a.add(1); + objects[1].a.add(1); + objects[1].a.add(2); - var set = new Set; - set.add(2); - var actual = _.filter(objects, _.matches({ 'a': set })); + var set = new Set; + set.add(2); + var actual = _.filter(objects, _.matches({ 'a': set })); - deepEqual(actual, [objects[1]]); + deepEqual(actual, [objects[1]]); - set['delete'](2); - actual = _.filter(objects, _.matches({ 'a': set })); + set['delete'](2); + actual = _.filter(objects, _.matches({ 'a': set })); - deepEqual(actual, objects); + deepEqual(actual, objects); - set.add(3); - actual = _.filter(objects, _.matches({ 'a': set })); + set.add(3); + actual = _.filter(objects, _.matches({ 'a': set })); - deepEqual(actual, []); + deepEqual(actual, []); + } + else { + skipTest(3); + } }); test('should match properties when `object` is not a plain object', 1, function() { @@ -9998,49 +10018,59 @@ deepEqual(actual, [objects[0]]); }); test('should partial match maps', 3, function() { - var objects = [{ 'a': new Map }, { 'a': new Map }]; - objects[0].a.set('a', 1); - objects[1].a.set('a', 1); - objects[1].a.set('b', 2); + if (Map) { + var objects = [{ 'a': new Map }, { 'a': new Map }]; + objects[0].a.set('a', 1); + objects[1].a.set('a', 1); + objects[1].a.set('b', 2); - var map = new Map; - map.set('b', 2); - var actual = _.filter(objects, _.matchesProperty('a', map)); + var map = new Map; + map.set('b', 2); + var actual = _.filter(objects, _.matchesProperty('a', map)); - deepEqual(actual, [objects[1]]); + deepEqual(actual, [objects[1]]); - map['delete']('b'); - actual = _.filter(objects, _.matchesProperty('a', map)); + map['delete']('b'); + actual = _.filter(objects, _.matchesProperty('a', map)); - deepEqual(actual, objects); + deepEqual(actual, objects); - map.set('c', 3); - actual = _.filter(objects, _.matchesProperty('a', map)); + map.set('c', 3); + actual = _.filter(objects, _.matchesProperty('a', map)); - deepEqual(actual, []); + deepEqual(actual, []); + } + else { + skipTest(3); + } }); test('should partial match sets', 3, function() { - var objects = [{ 'a': new Set }, { 'a': new Set }]; - objects[0].a.add(1); - objects[1].a.add(1); - objects[1].a.add(2); + if (Set) { + var objects = [{ 'a': new Set }, { 'a': new Set }]; + objects[0].a.add(1); + objects[1].a.add(1); + objects[1].a.add(2); - var set = new Set; - set.add(2); - var actual = _.filter(objects, _.matchesProperty('a', set)); + var set = new Set; + set.add(2); + var actual = _.filter(objects, _.matchesProperty('a', set)); - deepEqual(actual, [objects[1]]); + deepEqual(actual, [objects[1]]); - set['delete'](2); - actual = _.filter(objects, _.matchesProperty('a', set)); + set['delete'](2); + actual = _.filter(objects, _.matchesProperty('a', set)); - deepEqual(actual, objects); + deepEqual(actual, objects); - set.add(3); - actual = _.filter(objects, _.matchesProperty('a', set)); + set.add(3); + actual = _.filter(objects, _.matchesProperty('a', set)); - deepEqual(actual, []); + deepEqual(actual, []); + } + else { + skipTest(3); + } }); test('should match properties when `srcValue` is not a plain object', 1, function() { From 13e4ba622eccbdab67d3f6cc18e096bdecc4efeb Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Mon, 7 Sep 2015 19:39:21 -0700 Subject: [PATCH 275/935] Add code of conduct doc. [ci skip] --- CODE_OF_CONDUCT.md | 22 ++++++++++++++++++++++ CONTRIBUTING.md | 4 ++-- 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..5a9be09941 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,22 @@ +# Contributor Code of Conduct + +As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. + +We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery +* Personal attacks +* Trolling or insulting/derogatory comments +* Public or private harassment +* Publishing other’s private information, such as physical or electronic addresses, without explicit permission +* Other unethical or unprofessional conduct. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. + +This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. + +This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/) \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e2bcfa11f0..a5af43c354 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,7 @@ # Contributing to lodash -If you’d like to contribute a feature or bug fix, you can [fork](https://help.github.com/articles/fork-a-repo/) lodash, commit your changes, & [send a pull request](https://help.github.com/articles/using-pull-requests/). -Please make sure to [search the issue tracker](https://github.com/lodash/lodash/issues) first; your issue may have already been discussed or fixed in `master`. +Contributions are always welcome. Before contributing, please read the [code of conduct](https://github.com/lodash/lodash/blob/master/CODE_OF_CONDUCT.md) & [search the issue tracker](https://github.com/lodash/lodash/issues); +your issue may have already been discussed or fixed in `master`. To contribute, [fork](https://help.github.com/articles/fork-a-repo/) lodash, commit your changes, & [send a pull request](https://help.github.com/articles/using-pull-requests/). ## Tests From b9c8c877b7eea12300b94528a4227e376053b7ca Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Mon, 7 Sep 2015 20:37:07 -0700 Subject: [PATCH 276/935] Minor contributing text nit, `new methods` to `functions`. [ci skip] --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a5af43c354..67f5c76f6b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -36,7 +36,7 @@ In addition to the following guidelines, please follow the conventions already e Single-quoted strings are preferred to double-quoted strings; however, please use a double-quoted string if the value contains a single-quote character to avoid unnecessary escaping. - **Comments**:
- Please use single-line comments to annotate significant additions, & [JSDoc-style](http://www.2ality.com/2011/08/jsdoc-intro.html) comments for new methods. + Please use single-line comments to annotate significant additions, & [JSDoc-style](http://www.2ality.com/2011/08/jsdoc-intro.html) comments for functions. Guidelines are enforced using [JSSC](https://www.npmjs.com/package/jscs): From 2f411230c5bbc996a9c6ba5cf86cba3cf21a54c0 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Mon, 7 Sep 2015 21:36:49 -0700 Subject: [PATCH 277/935] Add `_.isEqualWith` and `_.isMatchWith` tests for maps and sets. --- test/test.js | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/test/test.js b/test/test.js index 1dc5648433..0dfc9d5f73 100644 --- a/test/test.js +++ b/test/test.js @@ -7103,6 +7103,50 @@ deepEqual(actual, [true, false]); }); + + test('should call `customizer` for values maps and sets', 2, function() { + var value = { 'a': { 'b': 2 } }; + + if (Map) { + var map1 = new Map; + map1.set('a', value); + + var map2 = new Map; + map2.set('a', value); + } + if (Set) { + var set1 = new Set; + set1.add(value); + + var set2 = new Set; + set2.add(value); + } + _.each([[map1, map2], [set1, set2]], function(pair, index) { + if (pair[0]) { + var argsList = [], + array = _.toArray(pair[0]); + + var expected = [ + [pair[0], pair[1]], + [array[0], array[0], 0, array, array, [], []], + [array[0][0], array[0][0], 0, array[0], array[0], [], []], + [array[0][1], array[0][1], 1, array[0], array[0], [], []] + ]; + + if (index) { + expected.length = 2; + } + _.isEqualWith(pair[0], pair[1], function() { + argsList.push(slice.call(arguments)); + }); + + deepEqual(argsList, expected, index ? 'Set' : 'Map'); + } + else { + skipTest(); + } + }); + }); }()); /*--------------------------------------------------------------------------*/ @@ -7664,6 +7708,52 @@ deepEqual(actual, [true, false]); }); + + test('should call `customizer` for values maps and sets', 2, function() { + var value = { 'a': { 'b': 2 } }; + + if (Map) { + var map1 = new Map; + map1.set('a', value); + + var map2 = new Map; + map2.set('a', value); + } + if (Set) { + var set1 = new Set; + set1.add(value); + + var set2 = new Set; + set2.add(value); + } + _.each([[map1, map2], [set1, set2]], function(pair, index) { + if (pair[0]) { + var argsList = [], + array = _.toArray(pair[0]), + object1 = { 'a': pair[0] }, + object2 = { 'a': pair[1] }; + + var expected = [ + [pair[0], pair[1], 'a', object1, object2, [], []], + [array[0], array[0], 0, array, array, [], []], + [array[0][0], array[0][0], 0, array[0], array[0], [], []], + [array[0][1], array[0][1], 1, array[0], array[0], [], []] + ]; + + if (index) { + expected.length = 2; + } + _.isMatchWith({ 'a': pair[0] }, { 'a': pair[1] }, function() { + argsList.push(slice.call(arguments)); + }); + + deepEqual(argsList, expected, index ? 'Set' : 'Map'); + } + else { + skipTest(); + } + }); + }); }()); /*--------------------------------------------------------------------------*/ From cbc188916d3c48c030881e02fa20cfabd6a56b5b Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Mon, 7 Sep 2015 21:59:57 -0700 Subject: [PATCH 278/935] Fix typo and fail in `_.isMatch` test. --- test/test.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/test.js b/test/test.js index 0dfc9d5f73..94670bbb35 100644 --- a/test/test.js +++ b/test/test.js @@ -7476,13 +7476,11 @@ deepEqual(actual, [objects[1]]); map['delete']('b'); - sourece = { 'a': map }; actual = _.filter(objects, predicate); deepEqual(actual, objects); map.set('c', 3); - source = { 'a': map }; actual = _.filter(objects, predicate); deepEqual(actual, []); From db86a6ff1cb92407d2381f66fb65b7a182b8231e Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Mon, 7 Sep 2015 22:05:44 -0700 Subject: [PATCH 279/935] Simplify `_.isMatch` set test. --- test/test.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/test.js b/test/test.js index 94670bbb35..2254a2474f 100644 --- a/test/test.js +++ b/test/test.js @@ -7507,13 +7507,11 @@ deepEqual(actual, [objects[1]]); set['delete'](2); - source = { 'a': set }; actual = _.filter(objects, predicate); deepEqual(actual, objects); set.add(3); - source = { 'a': set }; actual = _.filter(objects, predicate); deepEqual(actual, []); From 99b0094dcd10742a4b878177eae8dee3e3f41a00 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Mon, 7 Sep 2015 22:14:20 -0700 Subject: [PATCH 280/935] Minor code style nit in tests. [ci skip] --- test/test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test.js b/test/test.js index 2254a2474f..b21e16cfab 100644 --- a/test/test.js +++ b/test/test.js @@ -7542,7 +7542,7 @@ deepEqual(actual, expected); - objects = [{ 'a': { 'b': 1 } }, { 'a':{ 'b':1, 'c': 1 } }, { 'a': { 'b': 1, 'c': undefined } }]; + objects = [{ 'a': { 'b': 1 } }, { 'a':{ 'b': 1, 'c': 1 } }, { 'a': { 'b': 1, 'c': undefined } }]; source = { 'a': { 'c': undefined } }; actual = _.map(objects, predicate); @@ -9807,7 +9807,7 @@ deepEqual(actual, expected); - objects = [{ 'a': { 'b': 1 } }, { 'a': { 'b':1, 'c': 1 } }, { 'a': { 'b': 1, 'c': undefined } }]; + objects = [{ 'a': { 'b': 1 } }, { 'a': { 'b': 1, 'c': 1 } }, { 'a': { 'b': 1, 'c': undefined } }]; actual = _.map(objects, _.matches({ 'a': { 'c': undefined } })); deepEqual(actual, expected); From f86bff3bf70b7c692517454ebb692d835245fd36 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Mon, 7 Sep 2015 22:29:13 -0700 Subject: [PATCH 281/935] Minor `_.modArgsSet` doc example tweak. [ci skip] --- lodash.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lodash.js b/lodash.js index a0e0ce0595..fed6cd91eb 100644 --- a/lodash.js +++ b/lodash.js @@ -7633,14 +7633,14 @@ * @returns {Function} Returns the new function. * @example * - * function multiply(x, y) { - * return x * y; - * } - * * function divide(x, y) { * return x / y; * } * + * function multiply(x, y) { + * return x * y; + * } + * * var modded = _.modArgsSet(function(x, y) { * return [x, y]; * }, multiply, divide); From f0010ea3a8f1d5c006c5a0ae3bd3bf6ef47b849a Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Mon, 7 Sep 2015 22:51:33 -0700 Subject: [PATCH 282/935] Add additional guard to `isCombo` check in `mergeData`. --- lodash.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lodash.js b/lodash.js index fed6cd91eb..c63dc31168 100644 --- a/lodash.js +++ b/lodash.js @@ -4270,9 +4270,9 @@ isCommon = newBitmask < ARY_FLAG; var isCombo = - (srcBitmask == ARY_FLAG && bitmask == CURRY_FLAG) || - (srcBitmask == ARY_FLAG && bitmask == REARG_FLAG && data[7].length <= source[8]) || - (srcBitmask == (ARY_FLAG | REARG_FLAG) && bitmask == CURRY_FLAG); + (srcBitmask == ARY_FLAG && (bitmask == CURRY_FLAG)) || + (srcBitmask == ARY_FLAG && (bitmask == REARG_FLAG) && (data[7].length <= source[8])) || + (srcBitmask == (ARY_FLAG | REARG_FLAG) && (source[7].length <= source[8]) && (bitmask == CURRY_FLAG)); // Exit early if metadata can't be merged. if (!(isCommon || isCombo)) { From 8bad4ae636fe3011a213cc9d28dda4ca345e0804 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Mon, 7 Sep 2015 23:35:06 -0700 Subject: [PATCH 283/935] Rename `multiValue` param to `multiVal`. [ci skip] --- lodash.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lodash.js b/lodash.js index c63dc31168..b17ae1da97 100644 --- a/lodash.js +++ b/lodash.js @@ -9474,13 +9474,13 @@ /** * Creates an object composed of the inverted keys and values of `object`. * If `object` contains duplicate values, subsequent values overwrite property - * assignments of previous values unless `multiValue` is `true`. + * assignments of previous values unless `multiVal` is `true`. * * @static * @memberOf _ * @category Object * @param {Object} object The object to invert. - * @param {boolean} [multiValue] Allow multiple values per key. + * @param {boolean} [multiVal] Allow multiple values per key. * @param- {Object} [guard] Enables use as an iteratee for functions like `_.map`. * @returns {Object} Returns the new inverted object. * @example @@ -9490,14 +9490,14 @@ * _.invert(object); * // => { '1': 'c', '2': 'b' } * - * // with `multiValue` + * // with `multiVal` * _.invert(object, true); * // => { '1': ['a', 'c'], '2': ['b'] } */ - function invert(object, multiValue, guard) { + function invert(object, multiVal, guard) { return arrayReduce(keys(object), function(result, key) { var value = object[key]; - if (multiValue && !guard) { + if (multiVal && !guard) { if (hasOwnProperty.call(result, value)) { result[value].push(key); } else { From 2ac6e31cc3d6ddbaf58abd5e13cdfad4e9d879b9 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Tue, 8 Sep 2015 19:49:33 -0700 Subject: [PATCH 284/935] Update QUnit to 1.19.0. --- package.json | 2 +- test/test.js | 10953 ++++++++++++++++++++++++++++++------------------- 2 files changed, 6826 insertions(+), 4129 deletions(-) diff --git a/package.json b/package.json index a1fae2e644..ff4e6f66fc 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "jscs": "^2.1.1", "platform": "~1.3.0", "qunit-extras": "~1.4.0", - "qunitjs": "~1.18.0", + "qunitjs": "~1.19.0", "requirejs": "~2.1.0" }, "scripts": { diff --git a/test/test.js b/test/test.js index b21e16cfab..e2b9826528 100644 --- a/test/test.js +++ b/test/test.js @@ -371,12 +371,13 @@ * Skips a given number of tests with a passing result. * * @private + * @param {Object} assert The QUnit assert object. * @param {number} [count=1] The number of tests to skip. */ - function skipTest(count) { + function skipTest(assert, count) { count || (count = 1); while (count--) { - ok(true, 'test skipped'); + assert.ok(true, 'test skipped'); } } @@ -544,33 +545,41 @@ QUnit.module(basename); (function() { - test('should support loading ' + basename + ' as the "lodash" module', 1, function() { + QUnit.test('should support loading ' + basename + ' as the "lodash" module', function(assert) { + assert.expect(1); + if (amd) { - strictEqual((lodashModule || {}).moduleName, 'lodash'); + assert.strictEqual((lodashModule || {}).moduleName, 'lodash'); } else { - skipTest(); + skipTest(assert); } }); - test('should support loading ' + basename + ' with the Require.js "shim" configuration option', 1, function() { + QUnit.test('should support loading ' + basename + ' with the Require.js "shim" configuration option', function(assert) { + assert.expect(1); + if (amd && _.includes(ui.loaderPath, 'requirejs')) { - strictEqual((shimmedModule || {}).moduleName, 'shimmed'); + assert.strictEqual((shimmedModule || {}).moduleName, 'shimmed'); } else { - skipTest(); + skipTest(assert); } }); - test('should support loading ' + basename + ' as the "underscore" module', 1, function() { + QUnit.test('should support loading ' + basename + ' as the "underscore" module', function(assert) { + assert.expect(1); + if (amd) { - strictEqual((underscoreModule || {}).moduleName, 'underscore'); + assert.strictEqual((underscoreModule || {}).moduleName, 'underscore'); } else { - skipTest(); + skipTest(assert); } }); - asyncTest('should support loading ' + basename + ' in a web worker', 1, function() { + QUnit.asyncTest('should support loading ' + basename + ' in a web worker', function(assert) { + assert.expect(1); + if (Worker) { var limit = 30000 / QUnit.config.asyncRetries, start = +new Date; @@ -581,28 +590,32 @@ setTimeout(attempt, 16); return; } - strictEqual(actual, _.VERSION); + assert.strictEqual(actual, _.VERSION); QUnit.start(); }; attempt(); } else { - skipTest(); + skipTest(assert); QUnit.start(); } }); - test('should not add `Function.prototype` extensions to lodash', 1, function() { + QUnit.test('should not add `Function.prototype` extensions to lodash', function(assert) { + assert.expect(1); + if (lodashBizarro) { - ok(!('_method' in lodashBizarro)); + assert.notOk('_method' in lodashBizarro); } else { - skipTest(); + skipTest(assert); } }); - test('should avoid overwritten native methods', 2, function() { + QUnit.test('should avoid overwritten native methods', function(assert) { + assert.expect(2); + function message(lodashMethod, nativeMethod) { return '`' + lodashMethod + '` should avoid overwritten native `' + nativeMethod + '`'; } @@ -620,7 +633,7 @@ } catch (e) { actual = null; } - deepEqual(actual, ['a', 'b'], message('_.keysIn', 'Object#propertyIsEnumerable')); + assert.deepEqual(actual, ['a', 'b'], message('_.keysIn', 'Object#propertyIsEnumerable')); try { actual = [ @@ -631,10 +644,10 @@ } catch (e) { actual = null; } - deepEqual(actual, [[otherObject], [object], [object]], message('_.difference`, `_.intersection`, and `_.uniq', 'Set')); + assert.deepEqual(actual, [[otherObject], [object], [object]], message('_.difference`, `_.intersection`, and `_.uniq', 'Set')); } else { - skipTest(2); + skipTest(assert, 2); } }); }()); @@ -646,28 +659,32 @@ (function() { var func = _._isIndex; - test('should return `true` for indexes', 4, function() { + QUnit.test('should return `true` for indexes', function(assert) { + assert.expect(4); + if (func) { - strictEqual(func(0), true); - strictEqual(func('1'), true); - strictEqual(func(3, 4), true); - strictEqual(func(MAX_SAFE_INTEGER - 1), true); + assert.strictEqual(func(0), true); + assert.strictEqual(func('1'), true); + assert.strictEqual(func(3, 4), true); + assert.strictEqual(func(MAX_SAFE_INTEGER - 1), true); } else { - skipTest(4); + skipTest(assert, 4); } }); - test('should return `false` for non-indexes', 5, function() { + QUnit.test('should return `false` for non-indexes', function(assert) { + assert.expect(5); + if (func) { - strictEqual(func('1abc'), false); - strictEqual(func(-1), false); - strictEqual(func(3, 3), false); - strictEqual(func(1.1), false); - strictEqual(func(MAX_SAFE_INTEGER), false); + assert.strictEqual(func('1abc'), false); + assert.strictEqual(func(-1), false); + assert.strictEqual(func(3, 3), false); + assert.strictEqual(func(1.1), false); + assert.strictEqual(func(MAX_SAFE_INTEGER), false); } else { - skipTest(5); + skipTest(assert, 5); } }); }()); @@ -681,53 +698,61 @@ func = _._isIterateeCall, object = { 'a': 1 }; - test('should return `true` for iteratee calls', 3, function() { + QUnit.test('should return `true` for iteratee calls', function(assert) { + assert.expect(3); + function Foo() {} Foo.prototype.a = 1; if (func) { - strictEqual(func(1, 0, array), true); - strictEqual(func(1, 'a', object), true); - strictEqual(func(1, 'a', new Foo), true); + assert.strictEqual(func(1, 0, array), true); + assert.strictEqual(func(1, 'a', object), true); + assert.strictEqual(func(1, 'a', new Foo), true); } else { - skipTest(3); + skipTest(assert, 3); } }); - test('should return `false` for non-iteratee calls', 4, function() { + QUnit.test('should return `false` for non-iteratee calls', function(assert) { + assert.expect(4); + if (func) { - strictEqual(func(2, 0, array), false); - strictEqual(func(1, 1.1, array), false); - strictEqual(func(1, 0, { 'length': MAX_SAFE_INTEGER + 1 }), false); - strictEqual(func(1, 'b', object), false); + assert.strictEqual(func(2, 0, array), false); + assert.strictEqual(func(1, 1.1, array), false); + assert.strictEqual(func(1, 0, { 'length': MAX_SAFE_INTEGER + 1 }), false); + assert.strictEqual(func(1, 'b', object), false); } else { - skipTest(4); + skipTest(assert, 4); } }); - test('should work with `NaN` values', 2, function() { + QUnit.test('should work with `NaN` values', function(assert) { + assert.expect(2); + if (func) { - strictEqual(func(NaN, 0, [NaN]), true); - strictEqual(func(NaN, 'a', { 'a': NaN }), true); + assert.strictEqual(func(NaN, 0, [NaN]), true); + assert.strictEqual(func(NaN, 'a', { 'a': NaN }), true); } else { - skipTest(2); + skipTest(assert, 2); } }); - test('should not error when `index` is an object without a `toString` method', 1, function() { + QUnit.test('should not error when `index` is an object without a `toString` method', function(assert) { + assert.expect(1); + if (func) { try { var actual = func(1, { 'toString': null }, [1]); } catch (e) { var message = e.message; } - strictEqual(actual, false, message || ''); + assert.strictEqual(actual, false, message || ''); } else { - skipTest(); + skipTest(assert); } }); }()); @@ -739,26 +764,30 @@ (function() { var func = _._isLength; - test('should return `true` for lengths', 3, function() { + QUnit.test('should return `true` for lengths', function(assert) { + assert.expect(3); + if (func) { - strictEqual(func(0), true); - strictEqual(func(3), true); - strictEqual(func(MAX_SAFE_INTEGER), true); + assert.strictEqual(func(0), true); + assert.strictEqual(func(3), true); + assert.strictEqual(func(MAX_SAFE_INTEGER), true); } else { - skipTest(3); + skipTest(assert, 3); } }); - test('should return `false` for non-lengths', 4, function() { + QUnit.test('should return `false` for non-lengths', function(assert) { + assert.expect(4); + if (func) { - strictEqual(func(-1), false); - strictEqual(func('1'), false); - strictEqual(func(1.1), false); - strictEqual(func(MAX_SAFE_INTEGER + 1), false); + assert.strictEqual(func(-1), false); + assert.strictEqual(func('1'), false); + assert.strictEqual(func(1.1), false); + assert.strictEqual(func(MAX_SAFE_INTEGER + 1), false); } else { - skipTest(4); + skipTest(assert, 4); } }); }()); @@ -771,34 +800,40 @@ var values = empties.concat(true, 1, 'a'), expected = _.map(values, _.constant(true)); - test('should create a new instance when called without the `new` operator', 1, function() { + QUnit.test('should create a new instance when called without the `new` operator', function(assert) { + assert.expect(1); + if (!isNpm) { var actual = _.map(values, function(value) { return _(value) instanceof _; }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); } else { - skipTest(); + skipTest(assert); } }); - test('should return provided `lodash` instances', 1, function() { + QUnit.test('should return provided `lodash` instances', function(assert) { + assert.expect(1); + if (!isNpm) { var actual = _.map(values, function(value) { var wrapped = _(value); return _(wrapped) === wrapped; }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); } else { - skipTest(); + skipTest(assert); } }); - test('should convert foreign wrapped values to `lodash` instances', 1, function() { + QUnit.test('should convert foreign wrapped values to `lodash` instances', function(assert) { + assert.expect(1); + if (!isNpm && lodashBizarro) { var actual = _.map(values, function(value) { var wrapped = _(lodashBizarro(value)), @@ -808,10 +843,10 @@ (unwrapped === value || (_.isNaN(unwrapped) && _.isNaN(value))); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); } else { - skipTest(); + skipTest(assert); } }); }()); @@ -821,31 +856,39 @@ QUnit.module('lodash.add'); (function() { - test('should add two numbers together', 1, function() { - strictEqual(_.add(6, 4), 10); + QUnit.test('should add two numbers together', function(assert) { + assert.expect(1); + + assert.strictEqual(_.add(6, 4), 10); }); - test('should coerce params to numbers', 3, function() { - strictEqual(_.add('6', '4'), 10); - strictEqual(_.add('6', 'y'), 6); - strictEqual(_.add('x', 'y'), 0); + QUnit.test('should coerce params to numbers', function(assert) { + assert.expect(3); + + assert.strictEqual(_.add('6', '4'), 10); + assert.strictEqual(_.add('6', 'y'), 6); + assert.strictEqual(_.add('x', 'y'), 0); }); - test('should return an unwrapped value when implicitly chaining', 1, function() { + QUnit.test('should return an unwrapped value when implicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - strictEqual(_(1).add(2), 3); + assert.strictEqual(_(1).add(2), 3); } else { - skipTest(); + skipTest(assert); } }); - test('should return a wrapped value when explicitly chaining', 1, function() { + QUnit.test('should return a wrapped value when explicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - ok(_(1).chain().add(2) instanceof _); + assert.ok(_(1).chain().add(2) instanceof _); } else { - skipTest(); + skipTest(assert); } }); }()); @@ -861,24 +904,30 @@ return count; } - test('should create a function that invokes `func` after `n` calls', 4, function() { - strictEqual(after(5, 5), 1, 'after(n) should invoke `func` after being called `n` times'); - strictEqual(after(5, 4), 0, 'after(n) should not invoke `func` before being called `n` times'); - strictEqual(after(0, 0), 0, 'after(0) should not invoke `func` immediately'); - strictEqual(after(0, 1), 1, 'after(0) should invoke `func` when called once'); + QUnit.test('should create a function that invokes `func` after `n` calls', function(assert) { + assert.expect(4); + + assert.strictEqual(after(5, 5), 1, 'after(n) should invoke `func` after being called `n` times'); + assert.strictEqual(after(5, 4), 0, 'after(n) should not invoke `func` before being called `n` times'); + assert.strictEqual(after(0, 0), 0, 'after(0) should not invoke `func` immediately'); + assert.strictEqual(after(0, 1), 1, 'after(0) should invoke `func` when called once'); }); - test('should coerce `n` values of `NaN` to `0`', 1, function() { - strictEqual(after(NaN, 1), 1); + QUnit.test('should coerce `n` values of `NaN` to `0`', function(assert) { + assert.expect(1); + + assert.strictEqual(after(NaN, 1), 1); }); - test('should not set a `this` binding', 2, function() { - var after = _.after(1, function() { return ++this.count; }), + QUnit.test('should not set a `this` binding', function(assert) { + assert.expect(2); + + var after = _.after(1, function(assert) { return ++this.count; }), object = { 'count': 0, 'after': after }; object.after(); - strictEqual(object.after(), 2); - strictEqual(object.count, 2); + assert.strictEqual(object.after(), 2); + assert.strictEqual(object.count, 2); }); }()); @@ -891,30 +940,38 @@ return slice.call(arguments); } - test('should cap the number of params provided to `func`', 2, function() { + QUnit.test('should cap the number of params provided to `func`', function(assert) { + assert.expect(2); + var actual = _.map(['6', '8', '10'], _.ary(parseInt, 1)); - deepEqual(actual, [6, 8, 10]); + assert.deepEqual(actual, [6, 8, 10]); var capped = _.ary(fn, 2); - deepEqual(capped('a', 'b', 'c', 'd'), ['a', 'b']); + assert.deepEqual(capped('a', 'b', 'c', 'd'), ['a', 'b']); }); - test('should use `func.length` if `n` is not provided', 1, function() { + QUnit.test('should use `func.length` if `n` is not provided', function(assert) { + assert.expect(1); + var capped = _.ary(fn); - deepEqual(capped('a', 'b', 'c', 'd'), ['a', 'b', 'c']); + assert.deepEqual(capped('a', 'b', 'c', 'd'), ['a', 'b', 'c']); }); - test('should treat a negative `n` as `0`', 1, function() { + QUnit.test('should treat a negative `n` as `0`', function(assert) { + assert.expect(1); + var capped = _.ary(fn, -1); try { var actual = capped('a'); } catch (e) {} - deepEqual(actual, []); + assert.deepEqual(actual, []); }); - test('should coerce `n` to an integer', 1, function() { + QUnit.test('should coerce `n` to an integer', function(assert) { + assert.expect(1); + var values = ['1', 1.6, 'xyz'], expected = [['a'], ['a'], []]; @@ -923,33 +980,39 @@ return capped('a', 'b'); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work when provided less than the capped numer of arguments', 1, function() { + QUnit.test('should work when provided less than the capped numer of arguments', function(assert) { + assert.expect(1); + var capped = _.ary(fn, 3); - deepEqual(capped('a'), ['a']); + assert.deepEqual(capped('a'), ['a']); }); - test('should work as an iteratee for methods like `_.map`', 1, function() { + QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { + assert.expect(1); + var funcs = _.map([fn], _.ary), actual = funcs[0]('a', 'b', 'c'); - deepEqual(actual, ['a', 'b', 'c']); + assert.deepEqual(actual, ['a', 'b', 'c']); }); - test('should work when combined with other methods that use metadata', 2, function() { + QUnit.test('should work when combined with other methods that use metadata', function(assert) { + assert.expect(2); + var array = ['a', 'b', 'c'], includes = _.curry(_.rearg(_.ary(_.includes, 2), 1, 0), 2); - strictEqual(includes('b')(array, 2), true); + assert.strictEqual(includes('b')(array, 2), true); if (!isNpm) { includes = _(_.includes).ary(2).rearg(1, 0).curry(2).value(); - strictEqual(includes('b')(array, 2), true); + assert.strictEqual(includes('b')(array, 2), true); } else { - skipTest(); + skipTest(assert); } }); }()); @@ -961,24 +1024,32 @@ _.each(['assign', 'extend'], function(methodName) { var func = _[methodName]; - test('`_.' + methodName + '` should assign properties of a source object to the destination object', 1, function() { - deepEqual(func({ 'a': 1 }, { 'b': 2 }), { 'a': 1, 'b': 2 }); + QUnit.test('`_.' + methodName + '` should assign properties of a source object to the destination object', function(assert) { + assert.expect(1); + + assert.deepEqual(func({ 'a': 1 }, { 'b': 2 }), { 'a': 1, 'b': 2 }); }); - test('`_.' + methodName + '` should accept multiple source objects', 2, function() { + QUnit.test('`_.' + methodName + '` should accept multiple source objects', function(assert) { + assert.expect(2); + var expected = { 'a': 1, 'b': 2, 'c': 3 }; - deepEqual(func({ 'a': 1 }, { 'b': 2 }, { 'c': 3 }), expected); - deepEqual(func({ 'a': 1 }, { 'b': 2, 'c': 2 }, { 'c': 3 }), expected); + assert.deepEqual(func({ 'a': 1 }, { 'b': 2 }, { 'c': 3 }), expected); + assert.deepEqual(func({ 'a': 1 }, { 'b': 2, 'c': 2 }, { 'c': 3 }), expected); }); - test('`_.' + methodName + '` should overwrite destination properties', 1, function() { + QUnit.test('`_.' + methodName + '` should overwrite destination properties', function(assert) { + assert.expect(1); + var expected = { 'a': 3, 'b': 2, 'c': 1 }; - deepEqual(func({ 'a': 1, 'b': 2 }, expected), expected); + assert.deepEqual(func({ 'a': 1, 'b': 2 }, expected), expected); }); - test('`_.' + methodName + '` should assign source properties with nullish values', 1, function() { + QUnit.test('`_.' + methodName + '` should assign source properties with nullish values', function(assert) { + assert.expect(1); + var expected = { 'a': null, 'b': undefined, 'c': null }; - deepEqual(func({ 'a': 1, 'b': 2 }, expected), expected); + assert.deepEqual(func({ 'a': 1, 'b': 2 }, expected), expected); }); }); @@ -989,17 +1060,21 @@ _.each(['assignWith', 'extendWith'], function(methodName) { var func = _[methodName]; - test('`_.' + methodName + '` should work with a `customizer` callback', 1, function() { + QUnit.test('`_.' + methodName + '` should work with a `customizer` callback', function(assert) { + assert.expect(1); + var actual = func({ 'a': 1, 'b': 2 }, { 'a': 3, 'c': 3 }, function(a, b) { return a === undefined ? b : a; }); - deepEqual(actual, { 'a': 1, 'b': 2, 'c': 3 }); + assert.deepEqual(actual, { 'a': 1, 'b': 2, 'c': 3 }); }); - test('`_.' + methodName + '` should work with a `customizer` that returns `undefined`', 1, function() { + QUnit.test('`_.' + methodName + '` should work with a `customizer` that returns `undefined`', function(assert) { + assert.expect(1); + var expected = { 'a': undefined }; - deepEqual(func({}, expected, _.constant(undefined)), expected); + assert.deepEqual(func({}, expected, _.constant(undefined)), expected); }); }); @@ -1011,17 +1086,23 @@ var args = arguments, array = ['a', 'b', 'c']; - test('should return the elements corresponding to the specified keys', 1, function() { + QUnit.test('should return the elements corresponding to the specified keys', function(assert) { + assert.expect(1); + var actual = _.at(array, [0, 2]); - deepEqual(actual, ['a', 'c']); + assert.deepEqual(actual, ['a', 'c']); }); - test('should return `undefined` for nonexistent keys', 1, function() { + QUnit.test('should return `undefined` for nonexistent keys', function(assert) { + assert.expect(1); + var actual = _.at(array, [2, 4, 0]); - deepEqual(actual, ['c', undefined, 'a']); + assert.deepEqual(actual, ['c', undefined, 'a']); }); - test('should work with non-index keys on array values', 1, function() { + QUnit.test('should work with non-index keys on array values', function(assert) { + assert.expect(1); + var values = _.reject(empties, function(value) { return value === 0 || _.isArray(value); }).concat(-1, 1.1); @@ -1033,20 +1114,26 @@ var expected = _.map(values, _.constant(1)), actual = _.at(array, values); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return an empty array when no keys are provided', 2, function() { - deepEqual(_.at(array), []); - deepEqual(_.at(array, [], []), []); + QUnit.test('should return an empty array when no keys are provided', function(assert) { + assert.expect(2); + + assert.deepEqual(_.at(array), []); + assert.deepEqual(_.at(array, [], []), []); }); - test('should accept multiple key arguments', 1, function() { + QUnit.test('should accept multiple key arguments', function(assert) { + assert.expect(1); + var actual = _.at(['a', 'b', 'c', 'd'], 3, 0, 2); - deepEqual(actual, ['d', 'a', 'c']); + assert.deepEqual(actual, ['d', 'a', 'c']); }); - test('should work with a falsey `object` argument when keys are provided', 1, function() { + QUnit.test('should work with a falsey `object` argument when keys are provided', function(assert) { + assert.expect(1); + var expected = _.map(falsey, _.constant(Array(4))); var actual = _.map(falsey, function(object) { @@ -1055,30 +1142,38 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work with an `arguments` object for `object`', 1, function() { + QUnit.test('should work with an `arguments` object for `object`', function(assert) { + assert.expect(1); + var actual = _.at(args, [2, 0]); - deepEqual(actual, [3, 1]); + assert.deepEqual(actual, [3, 1]); }); - test('should work with `arguments` object as secondary arguments', 1, function() { + QUnit.test('should work with `arguments` object as secondary arguments', function(assert) { + assert.expect(1); + var actual = _.at([1, 2, 3, 4, 5], args); - deepEqual(actual, [2, 3, 4]); + assert.deepEqual(actual, [2, 3, 4]); }); - test('should work with an object for `object`', 1, function() { + QUnit.test('should work with an object for `object`', function(assert) { + assert.expect(1); + var actual = _.at({ 'a': 1, 'b': 2, 'c': 3 }, ['c', 'a']); - deepEqual(actual, [3, 1]); + assert.deepEqual(actual, [3, 1]); }); - test('should pluck inherited property values', 1, function() { + QUnit.test('should pluck inherited property values', function(assert) { + assert.expect(1); + function Foo() { this.a = 1; } Foo.prototype.b = 2; var actual = _.at(new Foo, 'b'); - deepEqual(actual, [2]); + assert.deepEqual(actual, [2]); }); }(1, 2, 3)); @@ -1087,31 +1182,41 @@ QUnit.module('lodash.attempt'); (function() { - test('should return the result of `func`', 1, function() { - strictEqual(_.attempt(_.constant('x')), 'x'); + QUnit.test('should return the result of `func`', function(assert) { + assert.expect(1); + + assert.strictEqual(_.attempt(_.constant('x')), 'x'); }); - test('should provide additional arguments to `func`', 1, function() { + QUnit.test('should provide additional arguments to `func`', function(assert) { + assert.expect(1); + var actual = _.attempt(function() { return slice.call(arguments); }, 1, 2); - deepEqual(actual, [1, 2]); + assert.deepEqual(actual, [1, 2]); }); - test('should return the caught error', 1, function() { + QUnit.test('should return the caught error', function(assert) { + assert.expect(1); + var expected = _.map(errors, _.constant(true)); var actual = _.map(errors, function(error) { return _.attempt(function() { throw error; }) === error; }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should coerce errors to error objects', 1, function() { + QUnit.test('should coerce errors to error objects', function(assert) { + assert.expect(1); + var actual = _.attempt(function() { throw 'x'; }); - ok(_.isEqual(actual, Error('x'))); + assert.ok(_.isEqual(actual, Error('x'))); }); - test('should work with an error object from another realm', 1, function() { + QUnit.test('should work with an error object from another realm', function(assert) { + assert.expect(1); + if (_._object) { var expected = _.map(_._errors, _.constant(true)); @@ -1119,28 +1224,32 @@ return _.attempt(function() { throw error; }) === error; }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); } else { - skipTest(); + skipTest(assert); } }); - test('should return an unwrapped value when implicitly chaining', 1, function() { + QUnit.test('should return an unwrapped value when implicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - strictEqual(_(_.constant('x')).attempt(), 'x'); + assert.strictEqual(_(_.constant('x')).attempt(), 'x'); } else { - skipTest(); + skipTest(assert); } }); - test('should return a wrapped value when explicitly chaining', 1, function() { + QUnit.test('should return a wrapped value when explicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - ok(_(_.constant('x')).chain().attempt() instanceof _); + assert.ok(_(_.constant('x')).chain().attempt() instanceof _); } else { - skipTest(); + skipTest(assert); } }); }()); @@ -1156,24 +1265,30 @@ return count; } - test('should create a function that invokes `func` after `n` calls', 4, function() { - strictEqual(before(5, 4), 4, 'before(n) should invoke `func` before being called `n` times'); - strictEqual(before(5, 6), 4, 'before(n) should not invoke `func` after being called `n - 1` times'); - strictEqual(before(0, 0), 0, 'before(0) should not invoke `func` immediately'); - strictEqual(before(0, 1), 0, 'before(0) should not invoke `func` when called'); + QUnit.test('should create a function that invokes `func` after `n` calls', function(assert) { + assert.expect(4); + + assert.strictEqual(before(5, 4), 4, 'before(n) should invoke `func` before being called `n` times'); + assert.strictEqual(before(5, 6), 4, 'before(n) should not invoke `func` after being called `n - 1` times'); + assert.strictEqual(before(0, 0), 0, 'before(0) should not invoke `func` immediately'); + assert.strictEqual(before(0, 1), 0, 'before(0) should not invoke `func` when called'); }); - test('should coerce `n` values of `NaN` to `0`', 1, function() { - strictEqual(before(NaN, 1), 0); + QUnit.test('should coerce `n` values of `NaN` to `0`', function(assert) { + assert.expect(1); + + assert.strictEqual(before(NaN, 1), 0); }); - test('should not set a `this` binding', 2, function() { - var before = _.before(2, function() { return ++this.count; }), + QUnit.test('should not set a `this` binding', function(assert) { + assert.expect(2); + + var before = _.before(2, function(assert) { return ++this.count; }), object = { 'count': 0, 'before': before }; object.before(); - strictEqual(object.before(), 1); - strictEqual(object.count, 1); + assert.strictEqual(object.before(), 1); + assert.strictEqual(object.count, 1); }); }()); @@ -1188,14 +1303,18 @@ return result; } - test('should bind a function to an object', 1, function() { + QUnit.test('should bind a function to an object', function(assert) { + assert.expect(1); + var object = {}, bound = _.bind(fn, object); - deepEqual(bound('a'), [object, 'a']); + assert.deepEqual(bound('a'), [object, 'a']); }); - test('should accept a falsey `thisArg` argument', 1, function() { + QUnit.test('should accept a falsey `thisArg` argument', function(assert) { + assert.expect(1); + var values = _.reject(falsey.slice(1), function(value) { return value == null; }), expected = _.map(values, function(value) { return [value]; }); @@ -1206,63 +1325,73 @@ } catch (e) {} }); - ok(_.every(actual, function(value, index) { + assert.ok(_.every(actual, function(value, index) { return _.isEqual(value, expected[index]); })); }); - test('should bind a function to nullish values', 6, function() { + QUnit.test('should bind a function to nullish values', function(assert) { + assert.expect(6); + var bound = _.bind(fn, null), actual = bound('a'); - ok(actual[0] === null || actual[0] && actual[0].Array); - strictEqual(actual[1], 'a'); + assert.ok(actual[0] === null || actual[0] && actual[0].Array); + assert.strictEqual(actual[1], 'a'); _.times(2, function(index) { bound = index ? _.bind(fn, undefined) : _.bind(fn); actual = bound('b'); - ok(actual[0] === undefined || actual[0] && actual[0].Array); - strictEqual(actual[1], 'b'); + assert.ok(actual[0] === undefined || actual[0] && actual[0].Array); + assert.strictEqual(actual[1], 'b'); }); }); - test('should partially apply arguments ', 4, function() { + QUnit.test('should partially apply arguments ', function(assert) { + assert.expect(4); + var object = {}, bound = _.bind(fn, object, 'a'); - deepEqual(bound(), [object, 'a']); + assert.deepEqual(bound(), [object, 'a']); bound = _.bind(fn, object, 'a'); - deepEqual(bound('b'), [object, 'a', 'b']); + assert.deepEqual(bound('b'), [object, 'a', 'b']); bound = _.bind(fn, object, 'a', 'b'); - deepEqual(bound(), [object, 'a', 'b']); - deepEqual(bound('c', 'd'), [object, 'a', 'b', 'c', 'd']); + assert.deepEqual(bound(), [object, 'a', 'b']); + assert.deepEqual(bound('c', 'd'), [object, 'a', 'b', 'c', 'd']); }); - test('should support placeholders', 4, function() { + QUnit.test('should support placeholders', function(assert) { + assert.expect(4); + var object = {}, ph = _.bind.placeholder, bound = _.bind(fn, object, ph, 'b', ph); - deepEqual(bound('a', 'c'), [object, 'a', 'b', 'c']); - deepEqual(bound('a'), [object, 'a', 'b', undefined]); - deepEqual(bound('a', 'c', 'd'), [object, 'a', 'b', 'c', 'd']); - deepEqual(bound(), [object, undefined, 'b', undefined]); + assert.deepEqual(bound('a', 'c'), [object, 'a', 'b', 'c']); + assert.deepEqual(bound('a'), [object, 'a', 'b', undefined]); + assert.deepEqual(bound('a', 'c', 'd'), [object, 'a', 'b', 'c', 'd']); + assert.deepEqual(bound(), [object, undefined, 'b', undefined]); }); - test('should create a function with a `length` of `0`', 2, function() { + QUnit.test('should create a function with a `length` of `0`', function(assert) { + assert.expect(2); + var fn = function(a, b, c) {}, bound = _.bind(fn, {}); - strictEqual(bound.length, 0); + assert.strictEqual(bound.length, 0); bound = _.bind(fn, {}, 1); - strictEqual(bound.length, 0); + assert.strictEqual(bound.length, 0); }); - test('should ignore binding when called with the `new` operator', 3, function() { + QUnit.test('should ignore binding when called with the `new` operator', function(assert) { + assert.expect(3); + function Foo() { return this; } @@ -1270,12 +1399,14 @@ var bound = _.bind(Foo, { 'a': 1 }), newBound = new bound; - strictEqual(bound().a, 1); - strictEqual(newBound.a, undefined); - ok(newBound instanceof Foo); + assert.strictEqual(bound().a, 1); + assert.strictEqual(newBound.a, undefined); + assert.ok(newBound instanceof Foo); }); - test('should handle a number of arguments when called with the `new` operator', 1, function() { + QUnit.test('should handle a number of arguments when called with the `new` operator', function(assert) { + assert.expect(1); + function Foo() { return this; } @@ -1300,10 +1431,12 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should ensure `new bound` is an instance of `func`', 2, function() { + QUnit.test('should ensure `new bound` is an instance of `func`', function(assert) { + assert.expect(2); + function Foo(value) { return value && object; } @@ -1311,18 +1444,22 @@ var bound = _.bind(Foo), object = {}; - ok(new bound instanceof Foo); - strictEqual(new bound(true), object); + assert.ok(new bound instanceof Foo); + assert.strictEqual(new bound(true), object); }); - test('should append array arguments to partially applied arguments', 1, function() { + QUnit.test('should append array arguments to partially applied arguments', function(assert) { + assert.expect(1); + var object = {}, bound = _.bind(fn, object, 'a'); - deepEqual(bound(['b'], 'c'), [object, 'a', ['b'], 'c']); + assert.deepEqual(bound(['b'], 'c'), [object, 'a', ['b'], 'c']); }); - test('should not rebind functions', 3, function() { + QUnit.test('should not rebind functions', function(assert) { + assert.expect(3); + var object1 = {}, object2 = {}, object3 = {}; @@ -1331,12 +1468,14 @@ bound2 = _.bind(bound1, object2, 'a'), bound3 = _.bind(bound1, object3, 'b'); - deepEqual(bound1(), [object1]); - deepEqual(bound2(), [object1, 'a']); - deepEqual(bound3(), [object1, 'b']); + assert.deepEqual(bound1(), [object1]); + assert.deepEqual(bound2(), [object1, 'a']); + assert.deepEqual(bound3(), [object1, 'b']); }); - test('should not error when instantiating bound built-ins', 2, function() { + QUnit.test('should not error when instantiating bound built-ins', function(assert) { + assert.expect(2); + var Ctor = _.bind(Date, null), expected = new Date(2012, 4, 23, 0, 0, 0, 0); @@ -1344,7 +1483,7 @@ var actual = new Ctor(2012, 4, 23, 0, 0, 0, 0); } catch (e) {} - deepEqual(actual, expected); + assert.deepEqual(actual, expected); Ctor = _.bind(Date, null, 2012, 4, 23); @@ -1352,10 +1491,12 @@ actual = new Ctor(0, 0, 0, 0); } catch (e) {} - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should not error when calling bound class constructors with the `new` operator', 1, function() { + QUnit.test('should not error when calling bound class constructors with the `new` operator', function(assert) { + assert.expect(1); + var createCtor = _.attempt(Function, '"use strict";return class A{}'); if (typeof createCtor == 'function') { @@ -1378,25 +1519,27 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); } else { - skipTest(); + skipTest(assert); } }); - test('should return a wrapped value when chaining', 2, function() { + QUnit.test('should return a wrapped value when chaining', function(assert) { + assert.expect(2); + if (!isNpm) { var object = {}, bound = _(fn).bind({}, 'a', 'b'); - ok(bound instanceof _); + assert.ok(bound instanceof _); var actual = bound.value()('c'); - deepEqual(actual, [object, 'a', 'b', 'c']); + assert.deepEqual(actual, [object, 'a', 'b', 'c']); } else { - skipTest(2); + skipTest(assert, 2); } }); }()); @@ -1419,7 +1562,9 @@ 'd': function() { return this._d; } }; - test('should accept individual method names', 1, function() { + QUnit.test('should accept individual method names', function(assert) { + assert.expect(1); + var object = _.clone(source); _.bindAll(object, 'a', 'b'); @@ -1427,10 +1572,12 @@ return object[methodName].call({}); }); - deepEqual(actual, [1, 2, undefined]); + assert.deepEqual(actual, [1, 2, undefined]); }); - test('should accept arrays of method names', 1, function() { + QUnit.test('should accept arrays of method names', function(assert) { + assert.expect(1); + var object = _.clone(source); _.bindAll(object, ['a', 'b'], ['c']); @@ -1438,16 +1585,20 @@ return object[methodName].call({}); }); - deepEqual(actual, [1, 2, 3, undefined]); + assert.deepEqual(actual, [1, 2, 3, undefined]); }); - test('should work with an array `object` argument', 1, function() { + QUnit.test('should work with an array `object` argument', function(assert) { + assert.expect(1); + var array = ['push', 'pop']; _.bindAll(array); - strictEqual(array.pop, arrayProto.pop); + assert.strictEqual(array.pop, arrayProto.pop); }); - test('should work with `arguments` objects as secondary arguments', 1, function() { + QUnit.test('should work with `arguments` objects as secondary arguments', function(assert) { + assert.expect(1); + var object = _.clone(source); _.bindAll(object, args); @@ -1455,7 +1606,7 @@ return object[methodName].call({}); }); - deepEqual(actual, [1]); + assert.deepEqual(actual, [1]); }); }('a')); @@ -1464,7 +1615,9 @@ QUnit.module('lodash.bindKey'); (function() { - test('should work when the target function is overwritten', 2, function() { + QUnit.test('should work when the target function is overwritten', function(assert) { + assert.expect(2); + var object = { 'user': 'fred', 'greet': function(greeting) { @@ -1473,16 +1626,18 @@ }; var bound = _.bindKey(object, 'greet', 'hi'); - strictEqual(bound(), 'fred says: hi'); + assert.strictEqual(bound(), 'fred says: hi'); object.greet = function(greeting) { return this.user + ' says: ' + greeting + '!'; }; - strictEqual(bound(), 'fred says: hi!'); + assert.strictEqual(bound(), 'fred says: hi!'); }); - test('should support placeholders', 4, function() { + QUnit.test('should support placeholders', function(assert) { + assert.expect(4); + var object = { 'fn': function() { return slice.call(arguments); @@ -1492,10 +1647,10 @@ var ph = _.bindKey.placeholder, bound = _.bindKey(object, 'fn', ph, 'b', ph); - deepEqual(bound('a', 'c'), ['a', 'b', 'c']); - deepEqual(bound('a'), ['a', 'b', undefined]); - deepEqual(bound('a', 'c', 'd'), ['a', 'b', 'c', 'd']); - deepEqual(bound(), [undefined, 'b', undefined]); + assert.deepEqual(bound('a', 'c'), ['a', 'b', 'c']); + assert.deepEqual(bound('a'), ['a', 'b', undefined]); + assert.deepEqual(bound('a', 'c', 'd'), ['a', 'b', 'c', 'd']); + assert.deepEqual(bound(), [undefined, 'b', undefined]); }); }()); @@ -1521,73 +1676,89 @@ } }()); - test('`_.' + methodName + '` should convert `string` to ' + caseName + ' case', 1, function() { + QUnit.test('`_.' + methodName + '` should convert `string` to ' + caseName + ' case', function(assert) { + assert.expect(1); + var actual = _.map(strings, function(string) { var expected = (caseName === 'start' && string === 'FOO BAR') ? string : converted; return func(string) === expected; }); - deepEqual(actual, _.map(strings, _.constant(true))); + assert.deepEqual(actual, _.map(strings, _.constant(true))); }); - test('`_.' + methodName + '` should handle double-converting strings', 1, function() { + QUnit.test('`_.' + methodName + '` should handle double-converting strings', function(assert) { + assert.expect(1); + var actual = _.map(strings, function(string) { var expected = (caseName === 'start' && string === 'FOO BAR') ? string : converted; return func(func(string)) === expected; }); - deepEqual(actual, _.map(strings, _.constant(true))); + assert.deepEqual(actual, _.map(strings, _.constant(true))); }); - test('`_.' + methodName + '` should deburr letters', 1, function() { + QUnit.test('`_.' + methodName + '` should deburr letters', function(assert) { + assert.expect(1); + var actual = _.map(burredLetters, function(burred, index) { var letter = deburredLetters[index]; letter = caseName == 'start' ? _.capitalize(letter) : letter.toLowerCase(); return func(burred) === letter; }); - deepEqual(actual, _.map(burredLetters, _.constant(true))); + assert.deepEqual(actual, _.map(burredLetters, _.constant(true))); }); - test('`_.' + methodName + '` should trim latin-1 mathematical operators', 1, function() { + QUnit.test('`_.' + methodName + '` should trim latin-1 mathematical operators', function(assert) { + assert.expect(1); + var actual = _.map(['\xd7', '\xf7'], func); - deepEqual(actual, ['', '']); + assert.deepEqual(actual, ['', '']); }); - test('`_.' + methodName + '` should coerce `string` to a string', 2, function() { + QUnit.test('`_.' + methodName + '` should coerce `string` to a string', function(assert) { + assert.expect(2); + var string = 'foo bar'; - strictEqual(func(Object(string)), converted); - strictEqual(func({ 'toString': _.constant(string) }), converted); + assert.strictEqual(func(Object(string)), converted); + assert.strictEqual(func({ 'toString': _.constant(string) }), converted); }); - test('`_.' + methodName + '` should return an unwrapped value implicitly when chaining', 1, function() { + QUnit.test('`_.' + methodName + '` should return an unwrapped value implicitly when chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - strictEqual(_('foo bar')[methodName](), converted); + assert.strictEqual(_('foo bar')[methodName](), converted); } else { - skipTest(); + skipTest(assert); } }); - test('`_.' + methodName + '` should return a wrapped value when explicitly chaining', 1, function() { + QUnit.test('`_.' + methodName + '` should return a wrapped value when explicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - ok(_('foo bar').chain()[methodName]() instanceof _); + assert.ok(_('foo bar').chain()[methodName]() instanceof _); } else { - skipTest(); + skipTest(assert); } }); }); (function() { - test('should get the original value after cycling through all case methods', 1, function() { + QUnit.test('should get the original value after cycling through all case methods', function(assert) { + assert.expect(1); + var funcs = [_.camelCase, _.kebabCase, _.snakeCase, _.startCase, _.camelCase]; var actual = _.reduce(funcs, function(result, func) { return func(result); }, 'enable 24h format'); - strictEqual(actual, 'enable24HFormat'); + assert.strictEqual(actual, 'enable24HFormat'); }); }()); @@ -1596,24 +1767,28 @@ QUnit.module('lodash.camelCase'); (function() { - test('should work with numbers', 4, function() { - strictEqual(_.camelCase('enable 24h format'), 'enable24HFormat'); - strictEqual(_.camelCase('too legit 2 quit'), 'tooLegit2Quit'); - strictEqual(_.camelCase('walk 500 miles'), 'walk500Miles'); - strictEqual(_.camelCase('xhr2 request'), 'xhr2Request'); + QUnit.test('should work with numbers', function(assert) { + assert.expect(4); + + assert.strictEqual(_.camelCase('enable 24h format'), 'enable24HFormat'); + assert.strictEqual(_.camelCase('too legit 2 quit'), 'tooLegit2Quit'); + assert.strictEqual(_.camelCase('walk 500 miles'), 'walk500Miles'); + assert.strictEqual(_.camelCase('xhr2 request'), 'xhr2Request'); }); - test('should handle acronyms', 6, function() { + QUnit.test('should handle acronyms', function(assert) { + assert.expect(6); + _.each(['safe HTML', 'safeHTML'], function(string) { - strictEqual(_.camelCase(string), 'safeHtml'); + assert.strictEqual(_.camelCase(string), 'safeHtml'); }); _.each(['escape HTML entities', 'escapeHTMLEntities'], function(string) { - strictEqual(_.camelCase(string), 'escapeHtmlEntities'); + assert.strictEqual(_.camelCase(string), 'escapeHtmlEntities'); }); _.each(['XMLHttpRequest', 'XmlHTTPRequest'], function(string) { - strictEqual(_.camelCase(string), 'xmlHttpRequest'); + assert.strictEqual(_.camelCase(string), 'xmlHttpRequest'); }); }); }()); @@ -1623,27 +1798,33 @@ QUnit.module('lodash.capitalize'); (function() { - test('should capitalize the first character of a string', 3, function() { - strictEqual(_.capitalize('fred'), 'Fred'); - strictEqual(_.capitalize('Fred'), 'Fred'); - strictEqual(_.capitalize(' fred'), ' fred'); + QUnit.test('should capitalize the first character of a string', function(assert) { + assert.expect(3); + + assert.strictEqual(_.capitalize('fred'), 'Fred'); + assert.strictEqual(_.capitalize('Fred'), 'Fred'); + assert.strictEqual(_.capitalize(' fred'), ' fred'); }); - test('should return an unwrapped value when implicitly chaining', 1, function() { + QUnit.test('should return an unwrapped value when implicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - strictEqual(_('fred').capitalize(), 'Fred'); + assert.strictEqual(_('fred').capitalize(), 'Fred'); } else { - skipTest(); + skipTest(assert); } }); - test('should return a wrapped value when explicitly chaining', 1, function() { + QUnit.test('should return a wrapped value when explicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - ok(_('fred').chain().capitalize() instanceof _); + assert.ok(_('fred').chain().capitalize() instanceof _); } else { - skipTest(); + skipTest(assert); } }); }()); @@ -1653,46 +1834,54 @@ QUnit.module('lodash.chain'); (function() { - test('should return a wrapped value', 1, function() { + QUnit.test('should return a wrapped value', function(assert) { + assert.expect(1); + if (!isNpm) { var actual = _.chain({ 'a': 0 }); - ok(actual instanceof _); + assert.ok(actual instanceof _); } else { - skipTest(); + skipTest(assert); } }); - test('should return existing wrapped values', 2, function() { + QUnit.test('should return existing wrapped values', function(assert) { + assert.expect(2); + if (!isNpm) { var wrapped = _({ 'a': 0 }); - strictEqual(_.chain(wrapped), wrapped); - strictEqual(wrapped.chain(), wrapped); + assert.strictEqual(_.chain(wrapped), wrapped); + assert.strictEqual(wrapped.chain(), wrapped); } else { - skipTest(2); + skipTest(assert, 2); } }); - test('should enable chaining of methods that return unwrapped values by default', 6, function() { + QUnit.test('should enable chaining of methods that return unwrapped values by default', function(assert) { + assert.expect(6); + if (!isNpm) { var array = ['c', 'b', 'a']; - ok(_.chain(array).first() instanceof _); - ok(_(array).chain().first() instanceof _); + assert.ok(_.chain(array).first() instanceof _); + assert.ok(_(array).chain().first() instanceof _); - ok(_.chain(array).isArray() instanceof _); - ok(_(array).chain().isArray() instanceof _); + assert.ok(_.chain(array).isArray() instanceof _); + assert.ok(_(array).chain().isArray() instanceof _); - ok(_.chain(array).sortBy().first() instanceof _); - ok(_(array).chain().sortBy().first() instanceof _); + assert.ok(_.chain(array).sortBy().first() instanceof _); + assert.ok(_(array).chain().sortBy().first() instanceof _); } else { - skipTest(6); + skipTest(assert, 6); } }); - test('should chain multiple methods', 6, function() { + QUnit.test('should chain multiple methods', function(assert) { + assert.expect(6); + if (!isNpm) { _.times(2, function(index) { var array = ['one two three four', 'five six seven eight', 'nine ten eleven twelve'], @@ -1710,7 +1899,7 @@ }, {}) .value(); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); array = [1, 2, 3, 4, 5, 6]; wrapped = index ? _(array).chain() : _.chain(array); @@ -1721,7 +1910,7 @@ .sortBy(function(n) { return -n; }) .value(); - deepEqual(actual, [5, 1]); + assert.deepEqual(actual, [5, 1]); array = [3, 4]; wrapped = index ? _(array).chain() : _.chain(array); @@ -1733,11 +1922,11 @@ .map(square) .value(); - deepEqual(actual,[25, 16, 9, 4]); + assert.deepEqual(actual,[25, 16, 9, 4]); }); } else { - skipTest(6); + skipTest(assert, 6); } }); }()); @@ -1749,17 +1938,23 @@ (function() { var array = [0, 1, 2, 3, 4, 5]; - test('should return chunked arrays', 1, function() { + QUnit.test('should return chunked arrays', function(assert) { + assert.expect(1); + var actual = _.chunk(array, 3); - deepEqual(actual, [[0, 1, 2], [3, 4, 5]]); + assert.deepEqual(actual, [[0, 1, 2], [3, 4, 5]]); }); - test('should return the last chunk as remaining elements', 1, function() { + QUnit.test('should return the last chunk as remaining elements', function(assert) { + assert.expect(1); + var actual = _.chunk(array, 4); - deepEqual(actual, [[0, 1, 2, 3], [4, 5]]); + assert.deepEqual(actual, [[0, 1, 2, 3], [4, 5]]); }); - test('should ensure the minimum `size` is `0`', 1, function() { + QUnit.test('should ensure the minimum `size` is `0`', function(assert) { + assert.expect(1); + var values = falsey.concat(-1, -Infinity), expected = _.map(values, _.constant([])); @@ -1767,11 +1962,13 @@ return index ? _.chunk(array, value) : _.chunk(array); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should coerce `size` to an integer', 1, function() { - deepEqual(_.chunk(array, array.length / 4), [[0], [1], [2], [3], [4], [5]]); + QUnit.test('should coerce `size` to an integer', function(assert) { + assert.expect(1); + + assert.deepEqual(_.chunk(array, array.length / 4), [[0], [1], [2], [3], [4], [5]]); }); }()); @@ -1827,15 +2024,19 @@ uncloneable[error.name + 's'] = error; }); - test('`_.clone` should perform a shallow clone', 2, function() { + QUnit.test('`_.clone` should perform a shallow clone', function(assert) { + assert.expect(2); + var array = [{ 'a': 0 }, { 'b': 1 }], actual = _.clone(array); - deepEqual(actual, array); - ok(actual !== array && actual[0] === array[0]); + assert.deepEqual(actual, array); + assert.ok(actual !== array && actual[0] === array[0]); }); - test('`_.cloneDeep` should deep clone objects with circular references', 1, function() { + QUnit.test('`_.cloneDeep` should deep clone objects with circular references', function(assert) { + assert.expect(1); + var object = { 'foo': { 'b': { 'c': { 'd': {} } } }, 'bar': {} @@ -1845,7 +2046,7 @@ object.bar.b = object.foo.b; var actual = _.cloneDeep(object); - ok(actual.bar.b === actual.foo.b && actual === actual.foo.b.c.d && actual !== object); + assert.ok(actual.bar.b === actual.foo.b && actual === actual.foo.b.c.d && actual !== object); }); _.each(['clone', 'cloneDeep'], function(methodName) { @@ -1853,46 +2054,54 @@ isDeep = methodName == 'cloneDeep'; _.forOwn(objects, function(object, key) { - test('`_.' + methodName + '` should clone ' + key, 2, function() { + QUnit.test('`_.' + methodName + '` should clone ' + key, function(assert) { + assert.expect(2); + var actual = func(object); - ok(_.isEqual(actual, object)); + assert.ok(_.isEqual(actual, object)); if (_.isObject(object)) { - notStrictEqual(actual, object); + assert.notStrictEqual(actual, object); } else { - strictEqual(actual, object); + assert.strictEqual(actual, object); } }); }); _.forOwn(uncloneable, function(value, key) { - test('`_.' + methodName + '` should not clone ' + key, 3, function() { + QUnit.test('`_.' + methodName + '` should not clone ' + key, function(assert) { + assert.expect(3); + var object = { 'a': value, 'b': { 'c': value } }, actual = func(object); - deepEqual(actual, object); - notStrictEqual(actual, object); + assert.deepEqual(actual, object); + assert.notStrictEqual(actual, object); var expected = typeof value == 'function' ? { 'c': Foo.c } : (value && {}); - deepEqual(func(value), expected); + assert.deepEqual(func(value), expected); }); }); - test('`_.' + methodName + '` should clone array buffers', 2, function() { + QUnit.test('`_.' + methodName + '` should clone array buffers', function(assert) { + assert.expect(2); + if (ArrayBuffer) { var buffer = new ArrayBuffer(10), actual = func(buffer); - strictEqual(actual.byteLength, buffer.byteLength); - notStrictEqual(actual, buffer); + assert.strictEqual(actual.byteLength, buffer.byteLength); + assert.notStrictEqual(actual, buffer); } else { - skipTest(2); + skipTest(assert, 2); } }); _.each(typedArrays, function(type) { - test('`_.' + methodName + '` should clone ' + type + ' arrays', 10, function() { + QUnit.test('`_.' + methodName + '` should clone ' + type + ' arrays', function(assert) { + assert.expect(10); + var Ctor = root[type]; _.times(2, function(index) { @@ -1901,65 +2110,75 @@ array = index ? new Ctor(buffer, 8, 1) : new Ctor(buffer), actual = func(array); - deepEqual(actual, array); - notStrictEqual(actual, array); - strictEqual(actual.buffer === array.buffer, !isDeep); - strictEqual(actual.byteOffset, array.byteOffset); - strictEqual(actual.length, array.length); + assert.deepEqual(actual, array); + assert.notStrictEqual(actual, array); + assert.strictEqual(actual.buffer === array.buffer, !isDeep); + assert.strictEqual(actual.byteOffset, array.byteOffset); + assert.strictEqual(actual.length, array.length); } else { - skipTest(5); + skipTest(assert, 5); } }); }); }); - test('`_.' + methodName + '` should clone `index` and `input` array properties', 2, function() { + QUnit.test('`_.' + methodName + '` should clone `index` and `input` array properties', function(assert) { + assert.expect(2); + var array = /x/.exec('vwxyz'), actual = func(array); - strictEqual(actual.index, 2); - strictEqual(actual.input, 'vwxyz'); + assert.strictEqual(actual.index, 2); + assert.strictEqual(actual.input, 'vwxyz'); }); - test('`_.' + methodName + '` should clone `lastIndex` regexp property', 1, function() { + QUnit.test('`_.' + methodName + '` should clone `lastIndex` regexp property', function(assert) { + assert.expect(1); + // Avoid a regexp literal for older Opera and use `exec` for older Safari. var regexp = RegExp('x', 'g'); regexp.exec('vwxyz'); var actual = func(regexp); - strictEqual(actual.lastIndex, 3); + assert.strictEqual(actual.lastIndex, 3); }); - test('`_.' + methodName + '` should not error on DOM elements', 1, function() { + QUnit.test('`_.' + methodName + '` should not error on DOM elements', function(assert) { + assert.expect(1); + if (document) { var element = document.createElement('div'); try { - deepEqual(func(element), {}); + assert.deepEqual(func(element), {}); } catch (e) { - ok(false, e.message); + assert.ok(false, e.message); } } else { - skipTest(); + skipTest(assert); } }); - test('`_.' + methodName + '` should perform a ' + (isDeep ? 'deep' : 'shallow') + ' clone when used as an iteratee for methods like `_.map`', 2, function() { + QUnit.test('`_.' + methodName + '` should perform a ' + (isDeep ? 'deep' : 'shallow') + ' clone when used as an iteratee for methods like `_.map`', function(assert) { + assert.expect(2); + var expected = [{ 'a': [0] }, { 'b': [1] }], actual = _.map(expected, func); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); if (isDeep) { - ok(actual[0] !== expected[0] && actual[0].a !== expected[0].a && actual[1].b !== expected[1].b); + assert.ok(actual[0] !== expected[0] && actual[0].a !== expected[0].a && actual[1].b !== expected[1].b); } else { - ok(actual[0] !== expected[0] && actual[0].a === expected[0].a && actual[1].b === expected[1].b); + assert.ok(actual[0] !== expected[0] && actual[0].a === expected[0].a && actual[1].b === expected[1].b); } }); - test('`_.' + methodName + '` should create an object from the same realm as `value`', 1, function() { + QUnit.test('`_.' + methodName + '` should create an object from the same realm as `value`', function(assert) { + assert.expect(1); + var props = []; var objects = _.transform(_, function(result, value, key) { @@ -1978,19 +2197,21 @@ return result !== object && (result instanceof Ctor || !(new Ctor instanceof Ctor)); }); - deepEqual(actual, expected, props.join(', ')); + assert.deepEqual(actual, expected, props.join(', ')); }); - test('`_.' + methodName + '` should return a unwrapped value when chaining', 2, function() { + QUnit.test('`_.' + methodName + '` should return a unwrapped value when chaining', function(assert) { + assert.expect(2); + if (!isNpm) { var object = objects['objects'], actual = _(object)[methodName](); - deepEqual(actual, object); - notStrictEqual(actual, object); + assert.deepEqual(actual, object); + assert.notStrictEqual(actual, object); } else { - skipTest(2); + skipTest(assert, 2); } }); }); @@ -1999,7 +2220,9 @@ var func = _[methodName], isDeepWith = methodName == 'cloneDeepWith'; - test('`_.' + methodName + '` should provide the correct `customizer` arguments', 1, function() { + QUnit.test('`_.' + methodName + '` should provide the correct `customizer` arguments', function(assert) { + assert.expect(1); + var argsList = [], foo = new Foo; @@ -2007,30 +2230,34 @@ argsList.push(slice.call(arguments)); }); - deepEqual(argsList, isDeepWith ? [[foo], [1, 'a', foo, [foo], [{ 'a': 1 }]]] : [[foo]]); + assert.deepEqual(argsList, isDeepWith ? [[foo], [1, 'a', foo, [foo], [{ 'a': 1 }]]] : [[foo]]); }); - test('`_.' + methodName + '` should handle cloning if `customizer` returns `undefined`', 1, function() { + QUnit.test('`_.' + methodName + '` should handle cloning if `customizer` returns `undefined`', function(assert) { + assert.expect(1); + var actual = func({ 'a': { 'b': 'c' } }, _.noop); - deepEqual(actual, { 'a': { 'b': 'c' } }); + assert.deepEqual(actual, { 'a': { 'b': 'c' } }); }); _.forOwn(uncloneable, function(value, key) { - test('`_.' + methodName + '` should work with a `customizer` callback and ' + key, 4, function() { + QUnit.test('`_.' + methodName + '` should work with a `customizer` callback and ' + key, function(assert) { + assert.expect(4); + var customizer = function(value) { return _.isPlainObject(value) ? undefined : value; }; var actual = func(value, customizer); - deepEqual(actual, value); - strictEqual(actual, value); + assert.deepEqual(actual, value); + assert.strictEqual(actual, value); var object = { 'a': value, 'b': { 'c': value } }; actual = func(object, customizer); - deepEqual(actual, object); - notStrictEqual(actual, object); + assert.deepEqual(actual, object); + assert.notStrictEqual(actual, object); }); }); }); @@ -2041,33 +2268,39 @@ QUnit.module('lodash.compact'); (function() { - test('should filter falsey values', 1, function() { + QUnit.test('should filter falsey values', function(assert) { + assert.expect(1); + var array = ['0', '1', '2']; - deepEqual(_.compact(falsey.concat(array)), array); + assert.deepEqual(_.compact(falsey.concat(array)), array); }); - test('should work when in between lazy operators', 2, function() { + QUnit.test('should work when in between lazy operators', function(assert) { + assert.expect(2); + if (!isNpm) { var actual = _(falsey).thru(_.slice).compact().thru(_.slice).value(); - deepEqual(actual, []); + assert.deepEqual(actual, []); actual = _(falsey).thru(_.slice).push(true, 1).compact().push('a').value(); - deepEqual(actual, [true, 1, 'a']); + assert.deepEqual(actual, [true, 1, 'a']); } else { - skipTest(2); + skipTest(assert, 2); } }); - test('should work in a lazy chain sequence', 1, function() { + QUnit.test('should work in a lazy chain sequence', function(assert) { + assert.expect(1); + if (!isNpm) { var array = _.range(LARGE_ARRAY_SIZE).concat(null), actual = _(array).slice(1).compact().reverse().take().value(); - deepEqual(actual, _.take(_.compact(_.slice(array, 1)).reverse())); + assert.deepEqual(actual, _.take(_.compact(_.slice(array, 1)).reverse())); } else { - skipTest(); + skipTest(assert); } }); }()); @@ -2080,40 +2313,50 @@ var func = _[methodName], isFlow = methodName == 'flow'; - test('`_.' + methodName + '` should supply each function with the return value of the previous', 1, function() { + QUnit.test('`_.' + methodName + '` should supply each function with the return value of the previous', function(assert) { + assert.expect(1); + var fixed = function(n) { return n.toFixed(1); }, combined = isFlow ? func(add, square, fixed) : func(fixed, square, add); - strictEqual(combined(1, 2), '9.0'); + assert.strictEqual(combined(1, 2), '9.0'); }); - test('`_.' + methodName + '` should return a new function', 1, function() { - notStrictEqual(func(_.noop), _.noop); + QUnit.test('`_.' + methodName + '` should return a new function', function(assert) { + assert.expect(1); + + assert.notStrictEqual(func(_.noop), _.noop); }); - test('`_.' + methodName + '` should return an identity function when no arguments are provided', 3, function() { + QUnit.test('`_.' + methodName + '` should return an identity function when no arguments are provided', function(assert) { + assert.expect(3); + var combined = func(); try { - strictEqual(combined('a'), 'a'); + assert.strictEqual(combined('a'), 'a'); } catch (e) { - ok(false, e.message); + assert.ok(false, e.message); } - strictEqual(combined.length, 0); - notStrictEqual(combined, _.identity); + assert.strictEqual(combined.length, 0); + assert.notStrictEqual(combined, _.identity); }); - test('`_.' + methodName + '` should work with a curried function and `_.first`', 1, function() { + QUnit.test('`_.' + methodName + '` should work with a curried function and `_.first`', function(assert) { + assert.expect(1); + var curried = _.curry(_.identity); var combined = isFlow ? func(_.first, curried) : func(curried, _.first); - strictEqual(combined([1]), 1); + assert.strictEqual(combined([1]), 1); }); - test('`_.' + methodName + '` should support shortcut fusion', 12, function() { + QUnit.test('`_.' + methodName + '` should support shortcut fusion', function(assert) { + assert.expect(12); + var filterCount, mapCount, array = _.range(LARGE_ARRAY_SIZE), @@ -2136,7 +2379,7 @@ _.times(2, function(index) { var fn = index ? _['_' + methodName] : func; if (!fn) { - skipTest(3); + skipTest(assert, 3); return; } var combined = isFlow @@ -2144,14 +2387,14 @@ : fn(take3, _.compact, filter3, map3); filterCount = mapCount = 0; - deepEqual(combined(array), [4, 16]); + assert.deepEqual(combined(array), [4, 16]); if (!isNpm && WeakMap && WeakMap.name) { - strictEqual(filterCount, 5, 'filterCount'); - strictEqual(mapCount, 5, 'mapCount'); + assert.strictEqual(filterCount, 5, 'filterCount'); + assert.strictEqual(mapCount, 5, 'mapCount'); } else { - skipTest(2); + skipTest(assert, 2); } }); @@ -2161,7 +2404,9 @@ }); }); - test('`_.' + methodName + '` should work with curried functions with placeholders', 1, function() { + QUnit.test('`_.' + methodName + '` should work with curried functions with placeholders', function(assert) { + assert.expect(1); + var curried = _.curry(_.ary(_.map, 2), 2), getProp = curried(curried.placeholder, 'a'), objects = [{ 'a': 1 }, { 'a': 2 }, { 'a': 1 }]; @@ -2170,16 +2415,18 @@ ? func(getProp, _.uniq) : func(_.uniq, getProp); - deepEqual(combined(objects), [1, 2]); + assert.deepEqual(combined(objects), [1, 2]); }); - test('`_.' + methodName + '` should return a wrapped value when chaining', 1, function() { + QUnit.test('`_.' + methodName + '` should return a wrapped value when chaining', function(assert) { + assert.expect(1); + if (!isNpm) { var wrapped = _(_.noop)[methodName](); - ok(wrapped instanceof _); + assert.ok(wrapped instanceof _); } else { - skipTest(); + skipTest(assert); } }); }); @@ -2189,7 +2436,9 @@ QUnit.module('lodash.constant'); (function() { - test('should create a function that returns `value`', 1, function() { + QUnit.test('should create a function that returns `value`', function(assert) { + assert.expect(1); + var object = { 'a': 1 }, values = Array(2).concat(empties, true, 1, 'a'), constant = _.constant(object), @@ -2206,10 +2455,12 @@ return result === object; }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work with falsey values', 1, function() { + QUnit.test('should work with falsey values', function(assert) { + assert.expect(1); + var expected = _.map(falsey, function() { return true; }); var actual = _.map(falsey, function(value, index) { @@ -2219,16 +2470,18 @@ return result === value || (_.isNaN(result) && _.isNaN(value)); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return a wrapped value when chaining', 1, function() { + QUnit.test('should return a wrapped value when chaining', function(assert) { + assert.expect(1); + if (!isNpm) { var wrapped = _(true).constant(); - ok(wrapped instanceof _); + assert.ok(wrapped instanceof _); } else { - skipTest(); + skipTest(assert); } }); }()); @@ -2240,15 +2493,19 @@ (function() { var array = [4.2, 6.1, 6.4]; - test('should work with an iteratee', 1, function() { + QUnit.test('should work with an iteratee', function(assert) { + assert.expect(1); + var actual = _.countBy(array, function(num) { return Math.floor(num); }, Math); - deepEqual(actual, { '4': 1, '6': 2 }); + assert.deepEqual(actual, { '4': 1, '6': 2 }); }); - test('should use `_.identity` when `iteratee` is nullish', 1, function() { + QUnit.test('should use `_.identity` when `iteratee` is nullish', function(assert) { + assert.expect(1); + var array = [4, 6, 6], values = [, null, undefined], expected = _.map(values, _.constant({ '4': 1, '6': 2 })); @@ -2257,43 +2514,53 @@ return index ? _.countBy(array, value) : _.countBy(array); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work with a "_.property" style `iteratee`', 1, function() { + QUnit.test('should work with a "_.property" style `iteratee`', function(assert) { + assert.expect(1); + var actual = _.countBy(['one', 'two', 'three'], 'length'); - deepEqual(actual, { '3': 2, '5': 1 }); + assert.deepEqual(actual, { '3': 2, '5': 1 }); }); - test('should only add values to own, not inherited, properties', 2, function() { + QUnit.test('should only add values to own, not inherited, properties', function(assert) { + assert.expect(2); + var actual = _.countBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num) > 4 ? 'hasOwnProperty' : 'constructor'; }); - deepEqual(actual.constructor, 1); - deepEqual(actual.hasOwnProperty, 2); + assert.deepEqual(actual.constructor, 1); + assert.deepEqual(actual.hasOwnProperty, 2); }); - test('should work with a number for `iteratee`', 2, function() { + QUnit.test('should work with a number for `iteratee`', function(assert) { + assert.expect(2); + var array = [ [1, 'a'], [2, 'a'], [2, 'b'] ]; - deepEqual(_.countBy(array, 0), { '1': 1, '2': 2 }); - deepEqual(_.countBy(array, 1), { 'a': 2, 'b': 1 }); + assert.deepEqual(_.countBy(array, 0), { '1': 1, '2': 2 }); + assert.deepEqual(_.countBy(array, 1), { 'a': 2, 'b': 1 }); }); - test('should work with an object for `collection`', 1, function() { + QUnit.test('should work with an object for `collection`', function(assert) { + assert.expect(1); + var actual = _.countBy({ 'a': 4.2, 'b': 6.1, 'c': 6.4 }, function(num) { return Math.floor(num); }); - deepEqual(actual, { '4': 1, '6': 2 }); + assert.deepEqual(actual, { '4': 1, '6': 2 }); }); - test('should work in a lazy chain sequence', 1, function() { + QUnit.test('should work in a lazy chain sequence', function(assert) { + assert.expect(1); + if (!isNpm) { var array = _.range(LARGE_ARRAY_SIZE).concat( _.range(Math.floor(LARGE_ARRAY_SIZE / 2), LARGE_ARRAY_SIZE), @@ -2302,10 +2569,10 @@ var actual = _(array).countBy().map(square).filter(isEven).take().value(); - deepEqual(actual, _.take(_.filter(_.map(_.countBy(array), square), isEven))); + assert.deepEqual(actual, _.take(_.filter(_.map(_.countBy(array), square), isEven))); } else { - skipTest(); + skipTest(assert); } }); }()); @@ -2324,49 +2591,59 @@ Shape.call(this); } - test('should create an object that inherits from the given `prototype` object', 3, function() { + QUnit.test('should create an object that inherits from the given `prototype` object', function(assert) { + assert.expect(3); + Circle.prototype = _.create(Shape.prototype); Circle.prototype.constructor = Circle; var actual = new Circle; - ok(actual instanceof Circle); - ok(actual instanceof Shape); - notStrictEqual(Circle.prototype, Shape.prototype); + assert.ok(actual instanceof Circle); + assert.ok(actual instanceof Shape); + assert.notStrictEqual(Circle.prototype, Shape.prototype); }); - test('should assign `properties` to the created object', 3, function() { + QUnit.test('should assign `properties` to the created object', function(assert) { + assert.expect(3); + var expected = { 'constructor': Circle, 'radius': 0 }; Circle.prototype = _.create(Shape.prototype, expected); var actual = new Circle; - ok(actual instanceof Circle); - ok(actual instanceof Shape); - deepEqual(Circle.prototype, expected); + assert.ok(actual instanceof Circle); + assert.ok(actual instanceof Shape); + assert.deepEqual(Circle.prototype, expected); }); - test('should assign own properties', 1, function() { + QUnit.test('should assign own properties', function(assert) { + assert.expect(1); + function Foo() { this.a = 1; this.c = 3; } Foo.prototype.b = 2; - deepEqual(_.create({}, new Foo), { 'a': 1, 'c': 3 }); + assert.deepEqual(_.create({}, new Foo), { 'a': 1, 'c': 3 }); }); - test('should accept a falsey `prototype` argument', 1, function() { + QUnit.test('should accept a falsey `prototype` argument', function(assert) { + assert.expect(1); + var expected = _.map(falsey, _.constant({})); var actual = _.map(falsey, function(prototype, index) { return index ? _.create(prototype) : _.create(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should ignore primitive `prototype` arguments and use an empty object instead', 1, function() { + QUnit.test('should ignore primitive `prototype` arguments and use an empty object instead', function(assert) { + assert.expect(1); + var primitives = [true, null, 1, 'a', undefined], expected = _.map(primitives, _.constant(true)); @@ -2374,10 +2651,12 @@ return _.isPlainObject(index ? _.create(value) : _.create()); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work as an iteratee for methods like `_.map`', 1, function() { + QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { + assert.expect(1); + var array = [{ 'a': 1 }, { 'a': 1 }, { 'a': 1 }], expected = _.map(array, _.constant(true)), objects = _.map(array, _.create); @@ -2386,7 +2665,7 @@ return object.a === 1 && !_.keys(object).length; }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }()); @@ -2399,25 +2678,31 @@ return slice.call(arguments); } - test('should curry based on the number of arguments provided', 3, function() { + QUnit.test('should curry based on the number of arguments provided', function(assert) { + assert.expect(3); + var curried = _.curry(fn), expected = [1, 2, 3, 4]; - deepEqual(curried(1)(2)(3)(4), expected); - deepEqual(curried(1, 2)(3, 4), expected); - deepEqual(curried(1, 2, 3, 4), expected); + assert.deepEqual(curried(1)(2)(3)(4), expected); + assert.deepEqual(curried(1, 2)(3, 4), expected); + assert.deepEqual(curried(1, 2, 3, 4), expected); }); - test('should allow specifying `arity`', 3, function() { + QUnit.test('should allow specifying `arity`', function(assert) { + assert.expect(3); + var curried = _.curry(fn, 3), expected = [1, 2, 3]; - deepEqual(curried(1)(2, 3), expected); - deepEqual(curried(1, 2)(3), expected); - deepEqual(curried(1, 2, 3), expected); + assert.deepEqual(curried(1)(2, 3), expected); + assert.deepEqual(curried(1, 2)(3), expected); + assert.deepEqual(curried(1, 2, 3), expected); }); - test('should coerce `arity` to an integer', 2, function() { + QUnit.test('should coerce `arity` to an integer', function(assert) { + assert.expect(2); + var values = ['0', 0.6, 'xyz'], expected = _.map(values, _.constant([])); @@ -2425,37 +2710,45 @@ return _.curry(fn, arity)(); }); - deepEqual(actual, expected); - deepEqual(_.curry(fn, '2')(1)(2), [1, 2]); + assert.deepEqual(actual, expected); + assert.deepEqual(_.curry(fn, '2')(1)(2), [1, 2]); }); - test('should support placeholders', 4, function() { + QUnit.test('should support placeholders', function(assert) { + assert.expect(4); + var curried = _.curry(fn), ph = curried.placeholder; - deepEqual(curried(1)(ph, 3)(ph, 4)(2), [1, 2, 3, 4]); - deepEqual(curried(ph, 2)(1)(ph, 4)(3), [1, 2, 3, 4]); - deepEqual(curried(ph, ph, 3)(ph, 2)(ph, 4)(1), [1, 2, 3, 4]); - deepEqual(curried(ph, ph, ph, 4)(ph, ph, 3)(ph, 2)(1), [1, 2, 3, 4]); + assert.deepEqual(curried(1)(ph, 3)(ph, 4)(2), [1, 2, 3, 4]); + assert.deepEqual(curried(ph, 2)(1)(ph, 4)(3), [1, 2, 3, 4]); + assert.deepEqual(curried(ph, ph, 3)(ph, 2)(ph, 4)(1), [1, 2, 3, 4]); + assert.deepEqual(curried(ph, ph, ph, 4)(ph, ph, 3)(ph, 2)(1), [1, 2, 3, 4]); }); - test('should provide additional arguments after reaching the target arity', 3, function() { + QUnit.test('should provide additional arguments after reaching the target arity', function(assert) { + assert.expect(3); + var curried = _.curry(fn, 3); - deepEqual(curried(1)(2, 3, 4), [1, 2, 3, 4]); - deepEqual(curried(1, 2)(3, 4, 5), [1, 2, 3, 4, 5]); - deepEqual(curried(1, 2, 3, 4, 5, 6), [1, 2, 3, 4, 5, 6]); + assert.deepEqual(curried(1)(2, 3, 4), [1, 2, 3, 4]); + assert.deepEqual(curried(1, 2)(3, 4, 5), [1, 2, 3, 4, 5]); + assert.deepEqual(curried(1, 2, 3, 4, 5, 6), [1, 2, 3, 4, 5, 6]); }); - test('should return a function with a `length` of `0`', 6, function() { + QUnit.test('should return a function with a `length` of `0`', function(assert) { + assert.expect(6); + _.times(2, function(index) { var curried = index ? _.curry(fn, 4) : _.curry(fn); - strictEqual(curried.length, 0); - strictEqual(curried(1).length, 0); - strictEqual(curried(1, 2).length, 0); + assert.strictEqual(curried.length, 0); + assert.strictEqual(curried(1).length, 0); + assert.strictEqual(curried(1, 2).length, 0); }); }); - test('should ensure `new curried` is an instance of `func`', 2, function() { + QUnit.test('should ensure `new curried` is an instance of `func`', function(assert) { + assert.expect(2); + var Foo = function(value) { return value && object; }; @@ -2463,11 +2756,13 @@ var curried = _.curry(Foo), object = {}; - ok(new curried(false) instanceof Foo); - strictEqual(new curried(true), object); + assert.ok(new curried(false) instanceof Foo); + assert.strictEqual(new curried(true), object); }); - test('should not set a `this` binding', 9, function() { + QUnit.test('should not set a `this` binding', function(assert) { + assert.expect(9); + var fn = function(a, b, c) { var value = this || {}; return [value[a], value[b], value[c]]; @@ -2476,21 +2771,23 @@ var object = { 'a': 1, 'b': 2, 'c': 3 }, expected = [1, 2, 3]; - deepEqual(_.curry(_.bind(fn, object), 3)('a')('b')('c'), expected); - deepEqual(_.curry(_.bind(fn, object), 3)('a', 'b')('c'), expected); - deepEqual(_.curry(_.bind(fn, object), 3)('a', 'b', 'c'), expected); + assert.deepEqual(_.curry(_.bind(fn, object), 3)('a')('b')('c'), expected); + assert.deepEqual(_.curry(_.bind(fn, object), 3)('a', 'b')('c'), expected); + assert.deepEqual(_.curry(_.bind(fn, object), 3)('a', 'b', 'c'), expected); - deepEqual(_.bind(_.curry(fn), object)('a')('b')('c'), Array(3)); - deepEqual(_.bind(_.curry(fn), object)('a', 'b')('c'), Array(3)); - deepEqual(_.bind(_.curry(fn), object)('a', 'b', 'c'), expected); + assert.deepEqual(_.bind(_.curry(fn), object)('a')('b')('c'), Array(3)); + assert.deepEqual(_.bind(_.curry(fn), object)('a', 'b')('c'), Array(3)); + assert.deepEqual(_.bind(_.curry(fn), object)('a', 'b', 'c'), expected); object.curried = _.curry(fn); - deepEqual(object.curried('a')('b')('c'), Array(3)); - deepEqual(object.curried('a', 'b')('c'), Array(3)); - deepEqual(object.curried('a', 'b', 'c'), expected); + assert.deepEqual(object.curried('a')('b')('c'), Array(3)); + assert.deepEqual(object.curried('a', 'b')('c'), Array(3)); + assert.deepEqual(object.curried('a', 'b', 'c'), expected); }); - test('should work with partialed methods', 2, function() { + QUnit.test('should work with partialed methods', function(assert) { + assert.expect(2); + var curried = _.curry(fn), expected = [1, 2, 3, 4]; @@ -2499,8 +2796,8 @@ c = _.partialRight(b, 4), d = _.partialRight(b(3), 4); - deepEqual(c(3), expected); - deepEqual(d(), expected); + assert.deepEqual(c(3), expected); + assert.deepEqual(d(), expected); }); }()); @@ -2513,25 +2810,31 @@ return slice.call(arguments); } - test('should curry based on the number of arguments provided', 3, function() { + QUnit.test('should curry based on the number of arguments provided', function(assert) { + assert.expect(3); + var curried = _.curryRight(fn), expected = [1, 2, 3, 4]; - deepEqual(curried(4)(3)(2)(1), expected); - deepEqual(curried(3, 4)(1, 2), expected); - deepEqual(curried(1, 2, 3, 4), expected); + assert.deepEqual(curried(4)(3)(2)(1), expected); + assert.deepEqual(curried(3, 4)(1, 2), expected); + assert.deepEqual(curried(1, 2, 3, 4), expected); }); - test('should allow specifying `arity`', 3, function() { + QUnit.test('should allow specifying `arity`', function(assert) { + assert.expect(3); + var curried = _.curryRight(fn, 3), expected = [1, 2, 3]; - deepEqual(curried(3)(1, 2), expected); - deepEqual(curried(2, 3)(1), expected); - deepEqual(curried(1, 2, 3), expected); + assert.deepEqual(curried(3)(1, 2), expected); + assert.deepEqual(curried(2, 3)(1), expected); + assert.deepEqual(curried(1, 2, 3), expected); }); - test('should coerce `arity` to an integer', 2, function() { + QUnit.test('should coerce `arity` to an integer', function(assert) { + assert.expect(2); + var values = ['0', 0.6, 'xyz'], expected = _.map(values, _.constant([])); @@ -2539,38 +2842,46 @@ return _.curryRight(fn, arity)(); }); - deepEqual(actual, expected); - deepEqual(_.curryRight(fn, '2')(1)(2), [2, 1]); + assert.deepEqual(actual, expected); + assert.deepEqual(_.curryRight(fn, '2')(1)(2), [2, 1]); }); - test('should support placeholders', 4, function() { + QUnit.test('should support placeholders', function(assert) { + assert.expect(4); + var curried = _.curryRight(fn), expected = [1, 2, 3, 4], ph = curried.placeholder; - deepEqual(curried(4)(2, ph)(1, ph)(3), expected); - deepEqual(curried(3, ph)(4)(1, ph)(2), expected); - deepEqual(curried(ph, ph, 4)(ph, 3)(ph, 2)(1), expected); - deepEqual(curried(ph, ph, ph, 4)(ph, ph, 3)(ph, 2)(1), expected); + assert.deepEqual(curried(4)(2, ph)(1, ph)(3), expected); + assert.deepEqual(curried(3, ph)(4)(1, ph)(2), expected); + assert.deepEqual(curried(ph, ph, 4)(ph, 3)(ph, 2)(1), expected); + assert.deepEqual(curried(ph, ph, ph, 4)(ph, ph, 3)(ph, 2)(1), expected); }); - test('should provide additional arguments after reaching the target arity', 3, function() { + QUnit.test('should provide additional arguments after reaching the target arity', function(assert) { + assert.expect(3); + var curried = _.curryRight(fn, 3); - deepEqual(curried(4)(1, 2, 3), [1, 2, 3, 4]); - deepEqual(curried(4, 5)(1, 2, 3), [1, 2, 3, 4, 5]); - deepEqual(curried(1, 2, 3, 4, 5, 6), [1, 2, 3, 4, 5, 6]); + assert.deepEqual(curried(4)(1, 2, 3), [1, 2, 3, 4]); + assert.deepEqual(curried(4, 5)(1, 2, 3), [1, 2, 3, 4, 5]); + assert.deepEqual(curried(1, 2, 3, 4, 5, 6), [1, 2, 3, 4, 5, 6]); }); - test('should return a function with a `length` of `0`', 6, function() { + QUnit.test('should return a function with a `length` of `0`', function(assert) { + assert.expect(6); + _.times(2, function(index) { var curried = index ? _.curryRight(fn, 4) : _.curryRight(fn); - strictEqual(curried.length, 0); - strictEqual(curried(4).length, 0); - strictEqual(curried(3, 4).length, 0); + assert.strictEqual(curried.length, 0); + assert.strictEqual(curried(4).length, 0); + assert.strictEqual(curried(3, 4).length, 0); }); }); - test('should ensure `new curried` is an instance of `func`', 2, function() { + QUnit.test('should ensure `new curried` is an instance of `func`', function(assert) { + assert.expect(2); + var Foo = function(value) { return value && object; }; @@ -2578,11 +2889,13 @@ var curried = _.curryRight(Foo), object = {}; - ok(new curried(false) instanceof Foo); - strictEqual(new curried(true), object); + assert.ok(new curried(false) instanceof Foo); + assert.strictEqual(new curried(true), object); }); - test('should not set a `this` binding', 9, function() { + QUnit.test('should not set a `this` binding', function(assert) { + assert.expect(9); + var fn = function(a, b, c) { var value = this || {}; return [value[a], value[b], value[c]]; @@ -2591,21 +2904,23 @@ var object = { 'a': 1, 'b': 2, 'c': 3 }, expected = [1, 2, 3]; - deepEqual(_.curryRight(_.bind(fn, object), 3)('c')('b')('a'), expected); - deepEqual(_.curryRight(_.bind(fn, object), 3)('b', 'c')('a'), expected); - deepEqual(_.curryRight(_.bind(fn, object), 3)('a', 'b', 'c'), expected); + assert.deepEqual(_.curryRight(_.bind(fn, object), 3)('c')('b')('a'), expected); + assert.deepEqual(_.curryRight(_.bind(fn, object), 3)('b', 'c')('a'), expected); + assert.deepEqual(_.curryRight(_.bind(fn, object), 3)('a', 'b', 'c'), expected); - deepEqual(_.bind(_.curryRight(fn), object)('c')('b')('a'), Array(3)); - deepEqual(_.bind(_.curryRight(fn), object)('b', 'c')('a'), Array(3)); - deepEqual(_.bind(_.curryRight(fn), object)('a', 'b', 'c'), expected); + assert.deepEqual(_.bind(_.curryRight(fn), object)('c')('b')('a'), Array(3)); + assert.deepEqual(_.bind(_.curryRight(fn), object)('b', 'c')('a'), Array(3)); + assert.deepEqual(_.bind(_.curryRight(fn), object)('a', 'b', 'c'), expected); object.curried = _.curryRight(fn); - deepEqual(object.curried('c')('b')('a'), Array(3)); - deepEqual(object.curried('b', 'c')('a'), Array(3)); - deepEqual(object.curried('a', 'b', 'c'), expected); + assert.deepEqual(object.curried('c')('b')('a'), Array(3)); + assert.deepEqual(object.curried('b', 'c')('a'), Array(3)); + assert.deepEqual(object.curried('a', 'b', 'c'), expected); }); - test('should work with partialed methods', 2, function() { + QUnit.test('should work with partialed methods', function(assert) { + assert.expect(2); + var curried = _.curryRight(fn), expected = [1, 2, 3, 4]; @@ -2614,8 +2929,8 @@ c = _.bind(b, null, 1), d = _.partial(b(2), 1); - deepEqual(c(2), expected); - deepEqual(d(), expected); + assert.deepEqual(c(2), expected); + assert.deepEqual(d(), expected); }); }()); @@ -2628,7 +2943,9 @@ fn = function(a, b) { return slice.call(arguments); }, isCurry = methodName == 'curry'; - test('`_.' + methodName + '` should not error on functions with the same name as lodash methods', 1, function() { + QUnit.test('`_.' + methodName + '` should not error on functions with the same name as lodash methods', function(assert) { + assert.expect(1); + function run(a, b) { return a + b; } @@ -2639,10 +2956,12 @@ var actual = curried(1)(2); } catch (e) {} - strictEqual(actual, 3); + assert.strictEqual(actual, 3); }); - test('`_.' + methodName + '` should work as an iteratee for methods like `_.map`', 2, function() { + QUnit.test('`_.' + methodName + '` should work as an iteratee for methods like `_.map`', function(assert) { + assert.expect(2); + var array = [fn, fn, fn], object = { 'a': fn, 'b': fn, 'c': fn }; @@ -2654,7 +2973,7 @@ return curried('a')('b'); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }); }); @@ -2664,7 +2983,9 @@ QUnit.module('lodash.debounce'); (function() { - asyncTest('should debounce a function', 2, function() { + QUnit.asyncTest('should debounce a function', function(assert) { + assert.expect(2); + if (!(isRhino && isModularize)) { var callCount = 0, debounced = _.debounce(function() { callCount++; }, 32); @@ -2673,59 +2994,65 @@ debounced(); debounced(); - strictEqual(callCount, 0); + assert.strictEqual(callCount, 0); setTimeout(function() { - strictEqual(callCount, 1); + assert.strictEqual(callCount, 1); QUnit.start(); }, 96); } else { - skipTest(2); + skipTest(assert, 2); QUnit.start(); } }); - asyncTest('subsequent debounced calls return the last `func` result', 2, function() { + QUnit.asyncTest('subsequent debounced calls return the last `func` result', function(assert) { + assert.expect(2); + if (!(isRhino && isModularize)) { var debounced = _.debounce(_.identity, 32); debounced('x'); setTimeout(function() { - notEqual(debounced('y'), 'y'); + assert.notEqual(debounced('y'), 'y'); }, 64); setTimeout(function() { - notEqual(debounced('z'), 'z'); + assert.notEqual(debounced('z'), 'z'); QUnit.start(); }, 128); } else { - skipTest(2); + skipTest(assert, 2); QUnit.start(); } }); - asyncTest('subsequent "immediate" debounced calls return the last `func` result', 2, function() { + QUnit.asyncTest('subsequent "immediate" debounced calls return the last `func` result', function(assert) { + assert.expect(2); + if (!(isRhino && isModularize)) { var debounced = _.debounce(_.identity, 32, { 'leading': true, 'trailing': false }), result = [debounced('x'), debounced('y')]; - deepEqual(result, ['x', 'x']); + assert.deepEqual(result, ['x', 'x']); setTimeout(function() { var result = [debounced('a'), debounced('b')]; - deepEqual(result, ['a', 'a']); + assert.deepEqual(result, ['a', 'a']); QUnit.start(); }, 64); } else { - skipTest(2); + skipTest(assert, 2); QUnit.start(); } }); - asyncTest('should apply default options', 2, function() { + QUnit.asyncTest('should apply default options', function(assert) { + assert.expect(2); + if (!(isRhino && isModularize)) { var callCount = 0; @@ -2734,20 +3061,22 @@ return value; }, 32, {}); - strictEqual(debounced('x'), undefined); + assert.strictEqual(debounced('x'), undefined); setTimeout(function() { - strictEqual(callCount, 1); + assert.strictEqual(callCount, 1); QUnit.start(); }, 64); } else { - skipTest(2); + skipTest(assert, 2); QUnit.start(); } }); - asyncTest('should support a `leading` option', 5, function() { + QUnit.asyncTest('should support a `leading` option', function(assert) { + assert.expect(5); + if (!(isRhino && isModularize)) { var callCounts = [0, 0]; @@ -2756,10 +3085,10 @@ return value; }, 32, { 'leading': true }); - strictEqual(withLeading('x'), 'x'); + assert.strictEqual(withLeading('x'), 'x'); var withoutLeading = _.debounce(_.identity, 32, { 'leading': false }); - strictEqual(withoutLeading('x'), undefined); + assert.strictEqual(withoutLeading('x'), undefined); var withLeadingAndTrailing = _.debounce(function() { callCounts[1]++; @@ -2768,24 +3097,26 @@ withLeadingAndTrailing(); withLeadingAndTrailing(); - strictEqual(callCounts[1], 1); + assert.strictEqual(callCounts[1], 1); setTimeout(function() { - deepEqual(callCounts, [1, 2]); + assert.deepEqual(callCounts, [1, 2]); withLeading('x'); - strictEqual(callCounts[0], 2); + assert.strictEqual(callCounts[0], 2); QUnit.start(); }, 64); } else { - skipTest(5); + skipTest(assert, 5); QUnit.start(); } }); - asyncTest('should support a `trailing` option', 4, function() { + QUnit.asyncTest('should support a `trailing` option', function(assert) { + assert.expect(4); + if (!(isRhino && isModularize)) { var withCount = 0, withoutCount = 0; @@ -2800,22 +3131,24 @@ return value; }, 32, { 'trailing': false }); - strictEqual(withTrailing('x'), undefined); - strictEqual(withoutTrailing('x'), undefined); + assert.strictEqual(withTrailing('x'), undefined); + assert.strictEqual(withoutTrailing('x'), undefined); setTimeout(function() { - strictEqual(withCount, 1); - strictEqual(withoutCount, 0); + assert.strictEqual(withCount, 1); + assert.strictEqual(withoutCount, 0); QUnit.start(); }, 64); } else { - skipTest(4); + skipTest(assert, 4); QUnit.start(); } }); - asyncTest('should support a `maxWait` option', 1, function() { + QUnit.asyncTest('should support a `maxWait` option', function(assert) { + assert.expect(1); + if (!(isRhino && isModularize)) { var limit = (argv || isPhantom) ? 1000 : 320, withCount = 0, @@ -2837,17 +3170,19 @@ var actual = [Boolean(withCount), Boolean(withoutCount)]; setTimeout(function() { - deepEqual(actual, [true, false]); + assert.deepEqual(actual, [true, false]); QUnit.start(); }, 1); } else { - skipTest(); + skipTest(assert); QUnit.start(); } }); - asyncTest('should cancel `maxDelayed` when `delayed` is invoked', 1, function() { + QUnit.asyncTest('should cancel `maxDelayed` when `delayed` is invoked', function(assert) { + assert.expect(1); + if (!(isRhino && isModularize)) { var callCount = 0; @@ -2858,17 +3193,19 @@ debounced(); setTimeout(function() { - strictEqual(callCount, 1); + assert.strictEqual(callCount, 1); QUnit.start(); }, 128); } else { - skipTest(); + skipTest(assert); QUnit.start(); } }); - asyncTest('should invoke the `trailing` call with the correct arguments and `this` binding', 2, function() { + QUnit.asyncTest('should invoke the `trailing` call with the correct arguments and `this` binding', function(assert) { + assert.expect(2); + if (!(isRhino && isModularize)) { var actual, callCount = 0, @@ -2886,13 +3223,13 @@ } } setTimeout(function() { - strictEqual(callCount, 2); - deepEqual(actual, [object, 'a']); + assert.strictEqual(callCount, 2); + assert.deepEqual(actual, [object, 'a']); QUnit.start(); }, 64); } else { - skipTest(2); + skipTest(assert, 2); QUnit.start(); } }); @@ -2903,19 +3240,25 @@ QUnit.module('lodash.deburr'); (function() { - test('should convert latin-1 supplementary letters to basic latin', 1, function() { + QUnit.test('should convert latin-1 supplementary letters to basic latin', function(assert) { + assert.expect(1); + var actual = _.map(burredLetters, _.deburr); - deepEqual(actual, deburredLetters); + assert.deepEqual(actual, deburredLetters); }); - test('should not deburr latin-1 mathematical operators', 1, function() { + QUnit.test('should not deburr latin-1 mathematical operators', function(assert) { + assert.expect(1); + var operators = ['\xd7', '\xf7'], actual = _.map(operators, _.deburr); - deepEqual(actual, operators); + assert.deepEqual(actual, operators); }); - test('should deburr combining diacritical marks', 1, function() { + QUnit.test('should deburr combining diacritical marks', function(assert) { + assert.expect(1); + var values = comboMarks.concat(comboHalfs), expected = _.map(values, _.constant('ei')); @@ -2923,7 +3266,7 @@ return _.deburr('e' + chr + 'i'); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }()); @@ -2932,24 +3275,32 @@ QUnit.module('lodash.defaults'); (function() { - test('should assign properties of a source object if missing on the destination object', 1, function() { - deepEqual(_.defaults({ 'a': 1 }, { 'a': 2, 'b': 2 }), { 'a': 1, 'b': 2 }); + QUnit.test('should assign properties of a source object if missing on the destination object', function(assert) { + assert.expect(1); + + assert.deepEqual(_.defaults({ 'a': 1 }, { 'a': 2, 'b': 2 }), { 'a': 1, 'b': 2 }); }); - test('should accept multiple source objects', 2, function() { + QUnit.test('should accept multiple source objects', function(assert) { + assert.expect(2); + var expected = { 'a': 1, 'b': 2, 'c': 3 }; - deepEqual(_.defaults({ 'a': 1, 'b': 2 }, { 'b': 3 }, { 'c': 3 }), expected); - deepEqual(_.defaults({ 'a': 1, 'b': 2 }, { 'b': 3, 'c': 3 }, { 'c': 2 }), expected); + assert.deepEqual(_.defaults({ 'a': 1, 'b': 2 }, { 'b': 3 }, { 'c': 3 }), expected); + assert.deepEqual(_.defaults({ 'a': 1, 'b': 2 }, { 'b': 3, 'c': 3 }, { 'c': 2 }), expected); }); - test('should not overwrite `null` values', 1, function() { + QUnit.test('should not overwrite `null` values', function(assert) { + assert.expect(1); + var actual = _.defaults({ 'a': null }, { 'a': 1 }); - strictEqual(actual.a, null); + assert.strictEqual(actual.a, null); }); - test('should overwrite `undefined` values', 1, function() { + QUnit.test('should overwrite `undefined` values', function(assert) { + assert.expect(1); + var actual = _.defaults({ 'a': undefined }, { 'a': 1 }); - strictEqual(actual.a, 1); + assert.strictEqual(actual.a, 1); }); }()); @@ -2958,42 +3309,52 @@ QUnit.module('lodash.defaultsDeep'); (function() { - test('should deep assign properties of a source object if missing on the destination object', 1, function() { + QUnit.test('should deep assign properties of a source object if missing on the destination object', function(assert) { + assert.expect(1); + var object = { 'a': { 'b': 2 }, 'd': 4 }, source = { 'a': { 'b': 1, 'c': 3 }, 'e': 5 }, expected = { 'a': { 'b': 2, 'c': 3 }, 'd': 4, 'e': 5 }; - deepEqual(_.defaultsDeep(object, source), expected); + assert.deepEqual(_.defaultsDeep(object, source), expected); }); - test('should accept multiple source objects', 2, function() { + QUnit.test('should accept multiple source objects', function(assert) { + assert.expect(2); + var source1 = { 'a': { 'b': 3 } }, source2 = { 'a': { 'c': 3 } }, source3 = { 'a': { 'b': 3, 'c': 3 } }, source4 = { 'a': { 'c': 4 } }, expected = { 'a': { 'b': 2, 'c': 3 } }; - deepEqual(_.defaultsDeep({ 'a': { 'b': 2 } }, source1, source2), expected); - deepEqual(_.defaultsDeep({ 'a': { 'b': 2 } }, source3, source4), expected); + assert.deepEqual(_.defaultsDeep({ 'a': { 'b': 2 } }, source1, source2), expected); + assert.deepEqual(_.defaultsDeep({ 'a': { 'b': 2 } }, source3, source4), expected); }); - test('should not overwrite `null` values', 1, function() { + QUnit.test('should not overwrite `null` values', function(assert) { + assert.expect(1); + var object = { 'a': { 'b': null } }, source = { 'a': { 'b': 2 } }, actual = _.defaultsDeep(object, source); - strictEqual(actual.a.b, null); + assert.strictEqual(actual.a.b, null); }); - test('should overwrite `undefined` values', 1, function() { + QUnit.test('should overwrite `undefined` values', function(assert) { + assert.expect(1); + var object = { 'a': { 'b': undefined } }, source = { 'a': { 'b': 2 } }, actual = _.defaultsDeep(object, source); - strictEqual(actual.a.b, 2); + assert.strictEqual(actual.a.b, 2); }); - test('should merge sources containing circular references', 1, function() { + QUnit.test('should merge sources containing circular references', function(assert) { + assert.expect(1); + var object = { 'foo': { 'b': { 'c': { 'd': {} } } }, 'bar': { 'a': 2 } @@ -3009,7 +3370,7 @@ source.bar.b = source.foo.b; var actual = _.defaultsDeep(object, source); - ok(actual.bar.b === source.foo.b && actual.foo.b.c.d === actual.foo.b.c.d.foo.b.c.d); + assert.ok(actual.bar.b === source.foo.b && actual.foo.b.c.d === actual.foo.b.c.d.foo.b.c.d); }); }()); @@ -3018,23 +3379,27 @@ QUnit.module('lodash.defer'); (function() { - asyncTest('should defer `func` execution', 1, function() { + QUnit.asyncTest('should defer `func` execution', function(assert) { + assert.expect(1); + if (!(isRhino && isModularize)) { var pass = false; _.defer(function() { pass = true; }); setTimeout(function() { - ok(pass); + assert.ok(pass); QUnit.start(); }, 32); } else { - skipTest(); + skipTest(assert); QUnit.start(); } }); - asyncTest('should provide additional arguments to `func`', 1, function() { + QUnit.asyncTest('should provide additional arguments to `func`', function(assert) { + assert.expect(1); + if (!(isRhino && isModularize)) { var args; @@ -3043,17 +3408,19 @@ }, 1, 2); setTimeout(function() { - deepEqual(args, [1, 2]); + assert.deepEqual(args, [1, 2]); QUnit.start(); }, 32); } else { - skipTest(); + skipTest(assert); QUnit.start(); } }); - asyncTest('should be cancelable', 1, function() { + QUnit.asyncTest('should be cancelable', function(assert) { + assert.expect(1); + if (!(isRhino && isModularize)) { var pass = true; @@ -3064,12 +3431,12 @@ clearTimeout(timerId); setTimeout(function() { - ok(pass); + assert.ok(pass); QUnit.start(); }, 32); } else { - skipTest(); + skipTest(assert); QUnit.start(); } }); @@ -3080,27 +3447,31 @@ QUnit.module('lodash.delay'); (function() { - asyncTest('should delay `func` execution', 2, function() { + QUnit.asyncTest('should delay `func` execution', function(assert) { + assert.expect(2); + if (!(isRhino && isModularize)) { var pass = false; _.delay(function() { pass = true; }, 32); setTimeout(function() { - ok(!pass); + assert.notOk(pass); }, 1); setTimeout(function() { - ok(pass); + assert.ok(pass); QUnit.start(); }, 64); } else { - skipTest(2); + skipTest(assert, 2); QUnit.start(); } }); - asyncTest('should provide additional arguments to `func`', 1, function() { + QUnit.asyncTest('should provide additional arguments to `func`', function(assert) { + assert.expect(1); + if (!(isRhino && isModularize)) { var args; @@ -3109,17 +3480,19 @@ }, 32, 1, 2); setTimeout(function() { - deepEqual(args, [1, 2]); + assert.deepEqual(args, [1, 2]); QUnit.start(); }, 64); } else { - skipTest(); + skipTest(assert); QUnit.start(); } }); - asyncTest('should be cancelable', 1, function() { + QUnit.asyncTest('should be cancelable', function(assert) { + assert.expect(1); + if (!(isRhino && isModularize)) { var pass = true; @@ -3130,12 +3503,12 @@ clearTimeout(timerId); setTimeout(function() { - ok(pass); + assert.ok(pass); QUnit.start(); }, 64); } else { - skipTest(); + skipTest(assert); QUnit.start(); } }); @@ -3148,19 +3521,25 @@ (function() { var args = arguments; - test('should return the difference of the given arrays', 2, function() { + QUnit.test('should return the difference of the given arrays', function(assert) { + assert.expect(2); + var actual = _.difference([1, 2, 3, 4, 5], [5, 2, 10]); - deepEqual(actual, [1, 3, 4]); + assert.deepEqual(actual, [1, 3, 4]); actual = _.difference([1, 2, 3, 4, 5], [5, 2, 10], [8, 4]); - deepEqual(actual, [1, 3]); + assert.deepEqual(actual, [1, 3]); }); - test('should match `NaN`', 1, function() { - deepEqual(_.difference([1, NaN, 3], [NaN, 5, NaN]), [1, 3]); + QUnit.test('should match `NaN`', function(assert) { + assert.expect(1); + + assert.deepEqual(_.difference([1, NaN, 3], [NaN, 5, NaN]), [1, 3]); }); - test('should work with large arrays', 1, function() { + QUnit.test('should work with large arrays', function(assert) { + assert.expect(1); + var array1 = _.range(LARGE_ARRAY_SIZE + 1), array2 = _.range(LARGE_ARRAY_SIZE), a = {}, @@ -3170,27 +3549,33 @@ array1.push(a, b, c); array2.push(b, c, a); - deepEqual(_.difference(array1, array2), [LARGE_ARRAY_SIZE]); + assert.deepEqual(_.difference(array1, array2), [LARGE_ARRAY_SIZE]); }); - test('should work with large arrays of objects', 1, function() { + QUnit.test('should work with large arrays of objects', function(assert) { + assert.expect(1); + var object1 = {}, object2 = {}, largeArray = _.times(LARGE_ARRAY_SIZE, _.constant(object1)); - deepEqual(_.difference([object1, object2], largeArray), [object2]); + assert.deepEqual(_.difference([object1, object2], largeArray), [object2]); }); - test('should work with large arrays of `NaN`', 1, function() { + QUnit.test('should work with large arrays of `NaN`', function(assert) { + assert.expect(1); + var largeArray = _.times(LARGE_ARRAY_SIZE, _.constant(NaN)); - deepEqual(_.difference([1, NaN, 3], largeArray), [1, 3]); + assert.deepEqual(_.difference([1, NaN, 3], largeArray), [1, 3]); }); - test('should ignore values that are not array-like', 3, function() { + QUnit.test('should ignore values that are not array-like', function(assert) { + assert.expect(3); + var array = [1, null, 3]; - deepEqual(_.difference(args, 3, { '0': 1 }), [1, 2, 3]); - deepEqual(_.difference(null, array, 1), []); - deepEqual(_.difference(array, args, null), [null]); + assert.deepEqual(_.difference(args, 3, { '0': 1 }), [1, 2, 3]); + assert.deepEqual(_.difference(null, array, 1), []); + assert.deepEqual(_.difference(array, args, null), [null]); }); }(1, 2, 3)); @@ -3201,11 +3586,15 @@ (function() { var array = [1, 2, 3]; - test('should drop the first two elements', 1, function() { - deepEqual(_.drop(array, 2), [3]); + QUnit.test('should drop the first two elements', function(assert) { + assert.expect(1); + + assert.deepEqual(_.drop(array, 2), [3]); }); - test('should treat falsey `n` values, except nullish, as `0`', 1, function() { + QUnit.test('should treat falsey `n` values, except nullish, as `0`', function(assert) { + assert.expect(1); + var expected = _.map(falsey, function(value) { return value == null ? [2, 3] : array; }); @@ -3214,56 +3603,66 @@ return _.drop(array, n); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return all elements when `n` < `1`', 3, function() { + QUnit.test('should return all elements when `n` < `1`', function(assert) { + assert.expect(3); + _.each([0, -1, -Infinity], function(n) { - deepEqual(_.drop(array, n), array); + assert.deepEqual(_.drop(array, n), array); }); }); - test('should return an empty array when `n` >= `array.length`', 4, function() { + QUnit.test('should return an empty array when `n` >= `array.length`', function(assert) { + assert.expect(4); + _.each([3, 4, Math.pow(2, 32), Infinity], function(n) { - deepEqual(_.drop(array, n), []); + assert.deepEqual(_.drop(array, n), []); }); }); - test('should coerce `n` to an integer', 1, function() { - deepEqual(_.drop(array, 1.2), [2, 3]); + QUnit.test('should coerce `n` to an integer', function(assert) { + assert.expect(1); + + assert.deepEqual(_.drop(array, 1.2), [2, 3]); }); - test('should work as an iteratee for methods like `_.map`', 1, function() { + 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, _.drop); - deepEqual(actual, [[2, 3], [5, 6], [8, 9]]); + assert.deepEqual(actual, [[2, 3], [5, 6], [8, 9]]); }); - test('should work in a lazy chain sequence', 6, function() { + 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).drop(2).drop().value(); - deepEqual(actual, array.slice(3)); + assert.deepEqual(actual, array.slice(3)); actual = _(array).filter(predicate).drop(2).drop().value(); - deepEqual(values, array); - deepEqual(actual, _.drop(_.drop(_.filter(array, predicate), 2))); + assert.deepEqual(values, array); + assert.deepEqual(actual, _.drop(_.drop(_.filter(array, predicate), 2))); actual = _(array).drop(2).dropRight().drop().dropRight(2).value(); - deepEqual(actual, _.dropRight(_.drop(_.dropRight(_.drop(array, 2))), 2)); + assert.deepEqual(actual, _.dropRight(_.drop(_.dropRight(_.drop(array, 2))), 2)); values = []; actual = _(array).drop().filter(predicate).drop(2).dropRight().drop().dropRight(2).value(); - deepEqual(values, array.slice(1)); - deepEqual(actual, _.dropRight(_.drop(_.dropRight(_.drop(_.filter(_.drop(array), predicate), 2))), 2)); + assert.deepEqual(values, array.slice(1)); + assert.deepEqual(actual, _.dropRight(_.drop(_.dropRight(_.drop(_.filter(_.drop(array), predicate), 2))), 2)); } else { - skipTest(6); + skipTest(assert, 6); } }); }()); @@ -3275,11 +3674,15 @@ (function() { var array = [1, 2, 3]; - test('should drop the last two elements', 1, function() { - deepEqual(_.dropRight(array, 2), [1]); + QUnit.test('should drop the last two elements', function(assert) { + assert.expect(1); + + assert.deepEqual(_.dropRight(array, 2), [1]); }); - test('should treat falsey `n` values, except nullish, as `0`', 1, function() { + QUnit.test('should treat falsey `n` values, except nullish, as `0`', function(assert) { + assert.expect(1); + var expected = _.map(falsey, function(value) { return value == null ? [1, 2] : array; }); @@ -3288,56 +3691,66 @@ return _.dropRight(array, n); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return all elements when `n` < `1`', 3, function() { + QUnit.test('should return all elements when `n` < `1`', function(assert) { + assert.expect(3); + _.each([0, -1, -Infinity], function(n) { - deepEqual(_.dropRight(array, n), array); + assert.deepEqual(_.dropRight(array, n), array); }); }); - test('should return an empty array when `n` >= `array.length`', 4, function() { + QUnit.test('should return an empty array when `n` >= `array.length`', function(assert) { + assert.expect(4); + _.each([3, 4, Math.pow(2, 32), Infinity], function(n) { - deepEqual(_.dropRight(array, n), []); + assert.deepEqual(_.dropRight(array, n), []); }); }); - test('should coerce `n` to an integer', 1, function() { - deepEqual(_.dropRight(array, 1.2), [1, 2]); + QUnit.test('should coerce `n` to an integer', function(assert) { + assert.expect(1); + + assert.deepEqual(_.dropRight(array, 1.2), [1, 2]); }); - test('should work as an iteratee for methods like `_.map`', 1, function() { + 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, _.dropRight); - deepEqual(actual, [[1, 2], [4, 5], [7, 8]]); + assert.deepEqual(actual, [[1, 2], [4, 5], [7, 8]]); }); - test('should work in a lazy chain sequence', 6, function() { + 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).dropRight(2).dropRight().value(); - deepEqual(actual, array.slice(0, -3)); + assert.deepEqual(actual, array.slice(0, -3)); actual = _(array).filter(predicate).dropRight(2).dropRight().value(); - deepEqual(values, array); - deepEqual(actual, _.dropRight(_.dropRight(_.filter(array, predicate), 2))); + assert.deepEqual(values, array); + assert.deepEqual(actual, _.dropRight(_.dropRight(_.filter(array, predicate), 2))); actual = _(array).dropRight(2).drop().dropRight().drop(2).value(); - deepEqual(actual, _.drop(_.dropRight(_.drop(_.dropRight(array, 2))), 2)); + assert.deepEqual(actual, _.drop(_.dropRight(_.drop(_.dropRight(array, 2))), 2)); values = []; actual = _(array).dropRight().filter(predicate).dropRight(2).drop().dropRight().drop(2).value(); - deepEqual(values, array.slice(0, -1)); - deepEqual(actual, _.drop(_.dropRight(_.drop(_.dropRight(_.filter(_.dropRight(array), predicate), 2))), 2)); + assert.deepEqual(values, array.slice(0, -1)); + assert.deepEqual(actual, _.drop(_.dropRight(_.drop(_.dropRight(_.filter(_.dropRight(array), predicate), 2))), 2)); } else { - skipTest(6); + skipTest(assert, 6); } }); }()); @@ -3355,47 +3768,59 @@ { 'a': 2, 'b': 2 } ]; - test('should drop elements while `predicate` returns truthy', 1, function() { + QUnit.test('should drop elements while `predicate` returns truthy', function(assert) { + assert.expect(1); + var actual = _.dropRightWhile(array, function(num) { return num > 2; }); - deepEqual(actual, [1, 2]); + assert.deepEqual(actual, [1, 2]); }); - test('should provide the correct `predicate` arguments', 1, function() { + QUnit.test('should provide the correct `predicate` arguments', function(assert) { + assert.expect(1); + var args; _.dropRightWhile(array, function() { args = slice.call(arguments); }); - deepEqual(args, [4, 3, array]); + assert.deepEqual(args, [4, 3, array]); }); - test('should work with a "_.matches" style `predicate`', 1, function() { - deepEqual(_.dropRightWhile(objects, { 'b': 2 }), objects.slice(0, 2)); + QUnit.test('should work with a "_.matches" style `predicate`', function(assert) { + assert.expect(1); + + assert.deepEqual(_.dropRightWhile(objects, { 'b': 2 }), objects.slice(0, 2)); }); - test('should work with a "_.matchesProperty" style `predicate`', 1, function() { - deepEqual(_.dropRightWhile(objects, ['b', 2]), objects.slice(0, 2)); + QUnit.test('should work with a "_.matchesProperty" style `predicate`', function(assert) { + assert.expect(1); + + assert.deepEqual(_.dropRightWhile(objects, ['b', 2]), objects.slice(0, 2)); }); - test('should work with a "_.property" style `predicate`', 1, function() { - deepEqual(_.dropRightWhile(objects, 'b'), objects.slice(0, 1)); + QUnit.test('should work with a "_.property" style `predicate`', function(assert) { + assert.expect(1); + + assert.deepEqual(_.dropRightWhile(objects, 'b'), objects.slice(0, 1)); }); - test('should return a wrapped value when chaining', 2, function() { + QUnit.test('should return a wrapped value when chaining', function(assert) { + assert.expect(2); + if (!isNpm) { var wrapped = _(array).dropRightWhile(function(num) { return num > 2; }); - ok(wrapped instanceof _); - deepEqual(wrapped.value(), [1, 2]); + assert.ok(wrapped instanceof _); + assert.deepEqual(wrapped.value(), [1, 2]); } else { - skipTest(2); + skipTest(assert, 2); } }); }()); @@ -3413,53 +3838,67 @@ { 'a': 0, 'b': 0 } ]; - test('should drop elements while `predicate` returns truthy', 1, function() { + QUnit.test('should drop elements while `predicate` returns truthy', function(assert) { + assert.expect(1); + var actual = _.dropWhile(array, function(num) { return num < 3; }); - deepEqual(actual, [3, 4]); + assert.deepEqual(actual, [3, 4]); }); - test('should provide the correct `predicate` arguments', 1, function() { + QUnit.test('should provide the correct `predicate` arguments', function(assert) { + assert.expect(1); + var args; _.dropWhile(array, function() { args = slice.call(arguments); }); - deepEqual(args, [1, 0, array]); + assert.deepEqual(args, [1, 0, array]); }); - test('should work with a "_.matches" style `predicate`', 1, function() { - deepEqual(_.dropWhile(objects, { 'b': 2 }), objects.slice(1)); + QUnit.test('should work with a "_.matches" style `predicate`', function(assert) { + assert.expect(1); + + assert.deepEqual(_.dropWhile(objects, { 'b': 2 }), objects.slice(1)); }); - test('should work with a "_.matchesProperty" style `predicate`', 1, function() { - deepEqual(_.dropWhile(objects, ['b', 2]), objects.slice(1)); + QUnit.test('should work with a "_.matchesProperty" style `predicate`', function(assert) { + assert.expect(1); + + assert.deepEqual(_.dropWhile(objects, ['b', 2]), objects.slice(1)); }); - test('should work with a "_.property" style `predicate`', 1, function() { - deepEqual(_.dropWhile(objects, 'b'), objects.slice(2)); + QUnit.test('should work with a "_.property" style `predicate`', function(assert) { + assert.expect(1); + + assert.deepEqual(_.dropWhile(objects, 'b'), objects.slice(2)); }); - test('should work in a lazy chain sequence', 3, function() { + QUnit.test('should work in a lazy chain sequence', function(assert) { + assert.expect(3); + if (!isNpm) { var array = _.range(1, LARGE_ARRAY_SIZE + 3), predicate = function(num) { return num < 3; }, expected = _.dropWhile(array, predicate), wrapped = _(array).dropWhile(predicate); - deepEqual(wrapped.value(), expected); - deepEqual(wrapped.reverse().value(), expected.slice().reverse()); - strictEqual(wrapped.last(), _.last(expected)); + assert.deepEqual(wrapped.value(), expected); + assert.deepEqual(wrapped.reverse().value(), expected.slice().reverse()); + assert.strictEqual(wrapped.last(), _.last(expected)); } else { - skipTest(3); + skipTest(assert, 3); } }); - test('should work in a lazy chain sequence with `drop`', 1, function() { + QUnit.test('should work in a lazy chain sequence with `drop`', function(assert) { + assert.expect(1); + if (!isNpm) { var array = _.range(1, LARGE_ARRAY_SIZE + 3); @@ -3469,10 +3908,10 @@ .dropWhile(function(num) { return num == 3; }) .value(); - deepEqual(actual, array.slice(3)); + assert.deepEqual(actual, array.slice(3)); } else { - skipTest(); + skipTest(assert); } }); }()); @@ -3484,49 +3923,65 @@ (function() { var string = 'abc'; - test('should return `true` if a string ends with `target`', 1, function() { - strictEqual(_.endsWith(string, 'c'), true); + QUnit.test('should return `true` if a string ends with `target`', function(assert) { + assert.expect(1); + + assert.strictEqual(_.endsWith(string, 'c'), true); }); - test('should return `false` if a string does not end with `target`', 1, function() { - strictEqual(_.endsWith(string, 'b'), false); + QUnit.test('should return `false` if a string does not end with `target`', function(assert) { + assert.expect(1); + + assert.strictEqual(_.endsWith(string, 'b'), false); }); - test('should work with a `position` argument', 1, function() { - strictEqual(_.endsWith(string, 'b', 2), true); + QUnit.test('should work with a `position` argument', function(assert) { + assert.expect(1); + + assert.strictEqual(_.endsWith(string, 'b', 2), true); }); - test('should work with `position` >= `string.length`', 4, function() { + QUnit.test('should work with `position` >= `string.length`', function(assert) { + assert.expect(4); + _.each([3, 5, MAX_SAFE_INTEGER, Infinity], function(position) { - strictEqual(_.endsWith(string, 'c', position), true); + assert.strictEqual(_.endsWith(string, 'c', position), true); }); }); - test('should treat falsey `position` values, except `undefined`, as `0`', 1, function() { + QUnit.test('should treat falsey `position` values, except `undefined`, as `0`', function(assert) { + assert.expect(1); + var expected = _.map(falsey, _.constant(true)); var actual = _.map(falsey, function(position) { return _.endsWith(string, position === undefined ? 'c' : '', position); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should treat a negative `position` as `0`', 6, function() { + QUnit.test('should treat a negative `position` as `0`', function(assert) { + assert.expect(6); + _.each([-1, -3, -Infinity], function(position) { - ok(_.every(string, function(chr) { + assert.ok(_.every(string, function(chr) { return _.endsWith(string, chr, position) === false; })); - strictEqual(_.endsWith(string, '', position), true); + assert.strictEqual(_.endsWith(string, '', position), true); }); }); - test('should coerce `position` to an integer', 1, function() { - strictEqual(_.endsWith(string, 'ab', 2.2), true); + QUnit.test('should coerce `position` to an integer', function(assert) { + assert.expect(1); + + assert.strictEqual(_.endsWith(string, 'ab', 2.2), true); }); - test('should return `true` when `target` is an empty string regardless of `position`', 1, function() { - ok(_.every([-Infinity, NaN, -3, -1, 0, 1, 2, 3, 5, MAX_SAFE_INTEGER, Infinity], function(position) { + QUnit.test('should return `true` when `target` is an empty string regardless of `position`', function(assert) { + assert.expect(1); + + assert.ok(_.every([-Infinity, NaN, -3, -1, 0, 1, 2, 3, 5, MAX_SAFE_INTEGER, Infinity], function(position) { return _.endsWith(string, '', position, true); })); }); @@ -3537,21 +3992,23 @@ QUnit.module('lodash.eq'); (function() { - test('should perform a `SameValueZero` comparison of two values', 11, function() { - strictEqual(_.eq(), true); - strictEqual(_.eq(undefined), true); - strictEqual(_.eq(0, -0), true); - strictEqual(_.eq(NaN, NaN), true); - strictEqual(_.eq(1, 1), true); - - strictEqual(_.eq(null, undefined), false); - strictEqual(_.eq(1, Object(1)), false); - strictEqual(_.eq(1, '1'), false); - strictEqual(_.eq(1, '1'), false); + QUnit.test('should perform a `SameValueZero` comparison of two values', function(assert) { + assert.expect(11); + + assert.strictEqual(_.eq(), true); + assert.strictEqual(_.eq(undefined), true); + assert.strictEqual(_.eq(0, -0), true); + assert.strictEqual(_.eq(NaN, NaN), true); + assert.strictEqual(_.eq(1, 1), true); + + assert.strictEqual(_.eq(null, undefined), false); + assert.strictEqual(_.eq(1, Object(1)), false); + assert.strictEqual(_.eq(1, '1'), false); + assert.strictEqual(_.eq(1, '1'), false); var object = { 'a': 1 }; - strictEqual(_.eq(object, object), true); - strictEqual(_.eq(object, { 'a': 1 }), false); + assert.strictEqual(_.eq(object, object), true); + assert.strictEqual(_.eq(object, { 'a': 1 }), false); }); }()); @@ -3566,20 +4023,28 @@ escaped += escaped; unescaped += unescaped; - test('should escape values', 1, function() { - strictEqual(_.escape(unescaped), escaped); + QUnit.test('should escape values', function(assert) { + assert.expect(1); + + assert.strictEqual(_.escape(unescaped), escaped); }); - test('should not escape the "/" character', 1, function() { - strictEqual(_.escape('/'), '/'); + QUnit.test('should not escape the "/" character', function(assert) { + assert.expect(1); + + assert.strictEqual(_.escape('/'), '/'); }); - test('should handle strings with nothing to escape', 1, function() { - strictEqual(_.escape('abc'), 'abc'); + QUnit.test('should handle strings with nothing to escape', function(assert) { + assert.expect(1); + + assert.strictEqual(_.escape('abc'), 'abc'); }); - test('should escape the same characters unescaped by `_.unescape`', 1, function() { - strictEqual(_.escape(_.unescape(escaped)), escaped); + QUnit.test('should escape the same characters unescaped by `_.unescape`', function(assert) { + assert.expect(1); + + assert.strictEqual(_.escape(_.unescape(escaped)), escaped); }); }()); @@ -3591,15 +4056,21 @@ var escaped = '\\^\\$\\.\\*\\+\\?\\(\\)\\[\\]\\{\\}\\|\\\\', unescaped = '^$.*+?()[]{}|\\'; - test('should escape values', 1, function() { - strictEqual(_.escapeRegExp(unescaped + unescaped), escaped + escaped); + QUnit.test('should escape values', function(assert) { + assert.expect(1); + + assert.strictEqual(_.escapeRegExp(unescaped + unescaped), escaped + escaped); }); - test('should handle strings with nothing to escape', 1, function() { - strictEqual(_.escapeRegExp('ghi'), 'ghi'); + QUnit.test('should handle strings with nothing to escape', function(assert) { + assert.expect(1); + + assert.strictEqual(_.escapeRegExp('ghi'), 'ghi'); }); - test('should return an empty string for empty values', 1, function() { + QUnit.test('should return an empty string for empty values', function(assert) { + assert.expect(1); + var values = [, null, undefined, ''], expected = _.map(values, _.constant('')); @@ -3607,7 +4078,7 @@ return index ? _.escapeRegExp(value) : _.escapeRegExp(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }()); @@ -3616,7 +4087,9 @@ QUnit.module('lodash.every'); (function() { - test('should return `true` for empty collections', 1, function() { + QUnit.test('should return `true` for empty collections', function(assert) { + assert.expect(1); + var expected = _.map(empties, _.constant(true)); var actual = _.map(empties, function(value) { @@ -3625,22 +4098,30 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return `true` if `predicate` returns truthy for all elements in the collection', 1, function() { - strictEqual(_.every([true, 1, 'a'], _.identity), true); + QUnit.test('should return `true` if `predicate` returns truthy for all elements in the collection', function(assert) { + assert.expect(1); + + assert.strictEqual(_.every([true, 1, 'a'], _.identity), true); }); - test('should return `false` as soon as `predicate` returns falsey', 1, function() { - strictEqual(_.every([true, null, true], _.identity), false); + QUnit.test('should return `false` as soon as `predicate` returns falsey', function(assert) { + assert.expect(1); + + assert.strictEqual(_.every([true, null, true], _.identity), false); }); - test('should work with collections of `undefined` values (test in IE < 9)', 1, function() { - strictEqual(_.every([undefined, undefined, undefined], _.identity), false); + QUnit.test('should work with collections of `undefined` values (test in IE < 9)', function(assert) { + assert.expect(1); + + assert.strictEqual(_.every([undefined, undefined, undefined], _.identity), false); }); - test('should use `_.identity` when `predicate` is nullish', 2, function() { + QUnit.test('should use `_.identity` when `predicate` is nullish', function(assert) { + assert.expect(2); + var values = [, null, undefined], expected = _.map(values, _.constant(false)); @@ -3649,7 +4130,7 @@ return index ? _.every(array, value) : _.every(array); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); expected = _.map(values, _.constant(true)); actual = _.map(values, function(value, index) { @@ -3657,24 +4138,30 @@ return index ? _.every(array, value) : _.every(array); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work with a "_.property" style `predicate`', 2, function() { + QUnit.test('should work with a "_.property" style `predicate`', function(assert) { + assert.expect(2); + var objects = [{ 'a': 0, 'b': 1 }, { 'a': 1, 'b': 2 }]; - strictEqual(_.every(objects, 'a'), false); - strictEqual(_.every(objects, 'b'), true); + assert.strictEqual(_.every(objects, 'a'), false); + assert.strictEqual(_.every(objects, 'b'), true); }); - test('should work with a "_.matches" style `predicate`', 2, function() { + QUnit.test('should work with a "_.matches" style `predicate`', function(assert) { + assert.expect(2); + var objects = [{ 'a': 0, 'b': 0 }, { 'a': 0, 'b': 1 }]; - strictEqual(_.every(objects, { 'a': 0 }), true); - strictEqual(_.every(objects, { 'b': 1 }), false); + assert.strictEqual(_.every(objects, { 'a': 0 }), true); + assert.strictEqual(_.every(objects, { 'b': 1 }), false); }); - test('should work as an iteratee for methods like `_.map`', 1, function() { + QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { + assert.expect(1); + var actual = _.map([[1]], _.every); - deepEqual(actual, [true]); + assert.deepEqual(actual, [true]); }); }()); @@ -3686,7 +4173,9 @@ var func = _[methodName], isBindAll = methodName == 'bindAll'; - test('`_.' + methodName + '` should ' + (isStrict ? '' : 'not ') + 'throw strict mode errors', 1, function() { + QUnit.test('`_.' + methodName + '` should ' + (isStrict ? '' : 'not ') + 'throw strict mode errors', function(assert) { + assert.expect(1); + if (freeze) { var object = freeze({ 'a': undefined, 'b': function() {} }), pass = !isStrict; @@ -3696,10 +4185,10 @@ } catch (e) { pass = !pass; } - ok(pass); + assert.ok(pass); } else { - skipTest(); + skipTest(assert); } }); }); @@ -3709,32 +4198,42 @@ QUnit.module('lodash.fill'); (function() { - test('should use a default `start` of `0` and a default `end` of `array.length`', 1, function() { + QUnit.test('should use a default `start` of `0` and a default `end` of `array.length`', function(assert) { + assert.expect(1); + var array = [1, 2, 3]; - deepEqual(_.fill(array, 'a'), ['a', 'a', 'a']); + assert.deepEqual(_.fill(array, 'a'), ['a', 'a', 'a']); }); - test('should use `undefined` for `value` if not provided', 2, function() { + QUnit.test('should use `undefined` for `value` if not provided', function(assert) { + assert.expect(2); + var array = [1, 2, 3], actual = _.fill(array); - deepEqual(actual, Array(3)); - ok(_.every(actual, function(value, index) { return index in actual; })); + assert.deepEqual(actual, Array(3)); + assert.ok(_.every(actual, function(value, index) { return index in actual; })); }); - test('should work with a positive `start`', 1, function() { + QUnit.test('should work with a positive `start`', function(assert) { + assert.expect(1); + var array = [1, 2, 3]; - deepEqual(_.fill(array, 'a', 1), [1, 'a', 'a']); + assert.deepEqual(_.fill(array, 'a', 1), [1, 'a', 'a']); }); - test('should work with a `start` >= `array.length`', 4, function() { + QUnit.test('should work with a `start` >= `array.length`', function(assert) { + assert.expect(4); + _.each([3, 4, Math.pow(2, 32), Infinity], function(start) { var array = [1, 2, 3]; - deepEqual(_.fill(array, 'a', start), [1, 2, 3]); + assert.deepEqual(_.fill(array, 'a', start), [1, 2, 3]); }); }); - test('should treat falsey `start` values as `0`', 1, function() { + QUnit.test('should treat falsey `start` values as `0`', function(assert) { + assert.expect(1); + var expected = _.map(falsey, _.constant(['a', 'a', 'a'])); var actual = _.map(falsey, function(start) { @@ -3742,41 +4241,53 @@ return _.fill(array, 'a', start); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work with a negative `start`', 1, function() { + QUnit.test('should work with a negative `start`', function(assert) { + assert.expect(1); + var array = [1, 2, 3]; - deepEqual(_.fill(array, 'a', -1), [1, 2, 'a']); + assert.deepEqual(_.fill(array, 'a', -1), [1, 2, 'a']); }); - test('should work with a negative `start` <= negative `array.length`', 3, function() { + QUnit.test('should work with a negative `start` <= negative `array.length`', function(assert) { + assert.expect(3); + _.each([-3, -4, -Infinity], function(start) { var array = [1, 2, 3]; - deepEqual(_.fill(array, 'a', start), ['a', 'a', 'a']); + assert.deepEqual(_.fill(array, 'a', start), ['a', 'a', 'a']); }); }); - test('should work with `start` >= `end`', 2, function() { + QUnit.test('should work with `start` >= `end`', function(assert) { + assert.expect(2); + _.each([2, 3], function(start) { var array = [1, 2, 3]; - deepEqual(_.fill(array, 'a', start, 2), [1, 2, 3]); + assert.deepEqual(_.fill(array, 'a', start, 2), [1, 2, 3]); }); }); - test('should work with a positive `end`', 1, function() { + QUnit.test('should work with a positive `end`', function(assert) { + assert.expect(1); + var array = [1, 2, 3]; - deepEqual(_.fill(array, 'a', 0, 1), ['a', 2, 3]); + assert.deepEqual(_.fill(array, 'a', 0, 1), ['a', 2, 3]); }); - test('should work with a `end` >= `array.length`', 4, function() { + QUnit.test('should work with a `end` >= `array.length`', function(assert) { + assert.expect(4); + _.each([3, 4, Math.pow(2, 32), Infinity], function(end) { var array = [1, 2, 3]; - deepEqual(_.fill(array, 'a', 0, end), ['a', 'a', 'a']); + assert.deepEqual(_.fill(array, 'a', 0, end), ['a', 'a', 'a']); }); }); - test('should treat falsey `end` values, except `undefined`, as `0`', 1, function() { + QUnit.test('should treat falsey `end` values, except `undefined`, as `0`', function(assert) { + assert.expect(1); + var expected = _.map(falsey, function(value) { return value === undefined ? ['a', 'a', 'a'] : [1, 2, 3]; }); @@ -3786,22 +4297,28 @@ return _.fill(array, 'a', 0, end); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work with a negative `end`', 1, function() { + QUnit.test('should work with a negative `end`', function(assert) { + assert.expect(1); + var array = [1, 2, 3]; - deepEqual(_.fill(array, 'a', 0, -1), ['a', 'a', 3]); + assert.deepEqual(_.fill(array, 'a', 0, -1), ['a', 'a', 3]); }); - test('should work with a negative `end` <= negative `array.length`', 3, function() { + QUnit.test('should work with a negative `end` <= negative `array.length`', function(assert) { + assert.expect(3); + _.each([-3, -4, -Infinity], function(end) { var array = [1, 2, 3]; - deepEqual(_.fill(array, 'a', 0, end), [1, 2, 3]); + assert.deepEqual(_.fill(array, 'a', 0, end), [1, 2, 3]); }); }); - test('should coerce `start` and `end` to integers', 1, function() { + QUnit.test('should coerce `start` and `end` to integers', function(assert) { + assert.expect(1); + var positions = [[0.1, 1.6], ['0', 1], [0, '1'], ['1'], [NaN, 1], [1, NaN]]; var actual = _.map(positions, function(pos) { @@ -3809,28 +4326,32 @@ return _.fill.apply(_, [array, 'a'].concat(pos)); }); - deepEqual(actual, [['a', 2, 3], ['a', 2, 3], ['a', 2, 3], [1, 'a', 'a'], ['a', 2, 3], [1, 2, 3]]); + assert.deepEqual(actual, [['a', 2, 3], ['a', 2, 3], ['a', 2, 3], [1, 'a', 'a'], ['a', 2, 3], [1, 2, 3]]); }); - test('should work as an iteratee for methods like `_.map`', 1, function() { + QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { + assert.expect(1); + var array = [[1, 2], [3, 4]], actual = _.map(array, _.fill); - deepEqual(actual, [[0, 0], [1, 1]]); + assert.deepEqual(actual, [[0, 0], [1, 1]]); }); - test('should return a wrapped value when chaining', 3, function() { + QUnit.test('should return a wrapped value when chaining', function(assert) { + assert.expect(3); + if (!isNpm) { var array = [1, 2, 3], wrapped = _(array).fill('a'), actual = wrapped.value(); - ok(wrapped instanceof _); - deepEqual(actual, ['a', 'a', 'a']); - strictEqual(actual, array); + assert.ok(wrapped instanceof _); + assert.deepEqual(actual, ['a', 'a', 'a']); + assert.strictEqual(actual, array); } else { - skipTest(3); + skipTest(assert, 3); } }); }()); @@ -3842,17 +4363,21 @@ (function() { var array = [1, 2, 3]; - test('should return elements `predicate` returns truthy for', 1, function() { - deepEqual(_.filter(array, isEven), [2]); + QUnit.test('should return elements `predicate` returns truthy for', function(assert) { + assert.expect(1); + + assert.deepEqual(_.filter(array, isEven), [2]); }); - test('should iterate over an object with numeric keys (test in Mobile Safari 8)', 1, function() { + QUnit.test('should iterate over an object with numeric keys (test in Mobile Safari 8)', function(assert) { + assert.expect(1); + // Trigger a Mobile Safari 8 JIT bug. // See https://github.com/lodash/lodash/issues/799. var counter = 0, object = { '1': 'foo', '8': 'bar', '50': 'baz' }; - _.times(1000, function() { + _.times(1000, function(assert) { _.filter([], _.constant(true)); }); @@ -3861,7 +4386,7 @@ return true; }); - strictEqual(counter, 3); + assert.strictEqual(counter, 3); }); }()); @@ -3889,27 +4414,39 @@ 'findLastKey': ['2', undefined, '2', '2'] })[methodName]; - test('should return the found value', 1, function() { - strictEqual(func(objects, function(object) { return object.a; }), expected[0]); + QUnit.test('should return the found value', function(assert) { + assert.expect(1); + + assert.strictEqual(func(objects, function(object) { return object.a; }), expected[0]); }); - test('should return `' + expected[1] + '` if value is not found', 1, function() { - strictEqual(func(objects, function(object) { return object.a === 3; }), expected[1]); + QUnit.test('should return `' + expected[1] + '` if value is not found', function(assert) { + assert.expect(1); + + assert.strictEqual(func(objects, function(object) { return object.a === 3; }), expected[1]); }); - test('should work with a "_.matches" style `predicate`', 1, function() { - strictEqual(func(objects, { 'b': 2 }), expected[2]); + QUnit.test('should work with a "_.matches" style `predicate`', function(assert) { + assert.expect(1); + + assert.strictEqual(func(objects, { 'b': 2 }), expected[2]); }); - test('should work with a "_.matchesProperty" style `predicate`', 1, function() { - strictEqual(func(objects, ['b', 2]), expected[2]); + QUnit.test('should work with a "_.matchesProperty" style `predicate`', function(assert) { + assert.expect(1); + + assert.strictEqual(func(objects, ['b', 2]), expected[2]); }); - test('should work with a "_.property" style `predicate`', 1, function() { - strictEqual(func(objects, 'b'), expected[3]); + QUnit.test('should work with a "_.property" style `predicate`', function(assert) { + assert.expect(1); + + assert.strictEqual(func(objects, 'b'), expected[3]); }); - test('should return `' + expected[1] + '` for empty collections', 1, function() { + QUnit.test('should return `' + expected[1] + '` for empty collections', function(assert) { + assert.expect(1); + var emptyValues = _.endsWith(methodName, 'Index') ? _.reject(empties, _.isPlainObject) : empties, expecting = _.map(emptyValues, _.constant(expected[1])); @@ -3919,7 +4456,7 @@ } catch (e) {} }); - deepEqual(actual, expecting); + assert.deepEqual(actual, expecting); }); }()); @@ -3935,35 +4472,43 @@ 'findLastKey': '3' })[methodName]; - test('should return an unwrapped value when implicitly chaining', 1, function() { + QUnit.test('should return an unwrapped value when implicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - strictEqual(_(array)[methodName](), expected); + assert.strictEqual(_(array)[methodName](), expected); } else { - skipTest(); + skipTest(assert); } }); - test('should return a wrapped value when explicitly chaining', 1, function() { + QUnit.test('should return a wrapped value when explicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - ok(_(array).chain()[methodName]() instanceof _); + assert.ok(_(array).chain()[methodName]() instanceof _); } else { - skipTest(); + skipTest(assert); } }); - test('should not execute immediately when explicitly chaining', 1, function() { + QUnit.test('should not execute immediately when explicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { var wrapped = _(array).chain()[methodName](); - strictEqual(wrapped.__wrapped__, array); + assert.strictEqual(wrapped.__wrapped__, array); } else { - skipTest(); + skipTest(assert); } }); - test('should work in a lazy chain sequence', 2, function() { + QUnit.test('should work in a lazy chain sequence', function(assert) { + assert.expect(2); + if (!isNpm) { var largeArray = _.range(1, LARGE_ARRAY_SIZE + 1), smallArray = array; @@ -3972,11 +4517,11 @@ var array = index ? largeArray : smallArray, wrapped = _(array).filter(isEven); - strictEqual(wrapped[methodName](), func(_.filter(array, isEven))); + assert.strictEqual(wrapped[methodName](), func(_.filter(array, isEven))); }); } else { - skipTest(2); + skipTest(assert, 2); } }); }()); @@ -3990,12 +4535,14 @@ })[methodName]; if (expected != null) { - test('should work with an object for `collection`', 1, function() { + QUnit.test('should work with an object for `collection`', function(assert) { + assert.expect(1); + var actual = func({ 'a': 1, 'b': 2, 'c': 3 }, function(num) { return num < 3; }); - strictEqual(actual, expected); + assert.strictEqual(actual, expected); }); } }()); @@ -4008,7 +4555,9 @@ _.each(['find', 'findLast'], function(methodName) { var isFind = methodName == 'find'; - test('`_.' + methodName + '` should support shortcut fusion', 3, function() { + QUnit.test('`_.' + methodName + '` should support shortcut fusion', function(assert) { + assert.expect(3); + if (!isNpm) { var findCount = 0, mapCount = 0, @@ -4017,12 +4566,12 @@ predicate = function(value) { findCount++; return isEven(value); }, actual = _(array).map(iteratee)[methodName](predicate); - strictEqual(findCount, isFind ? 2 : 1); - strictEqual(mapCount, isFind ? 2 : 1); - strictEqual(actual, isFind ? 4 : square(LARGE_ARRAY_SIZE)); + assert.strictEqual(findCount, isFind ? 2 : 1); + assert.strictEqual(mapCount, isFind ? 2 : 1); + assert.strictEqual(actual, isFind ? 4 : square(LARGE_ARRAY_SIZE)); } else { - skipTest(3); + skipTest(assert, 3); } }); }); @@ -4034,53 +4583,67 @@ (function() { var array = [1, 2, 3, 4]; - test('should return the first element', 1, function() { - strictEqual(_.first(array), 1); + QUnit.test('should return the first element', function(assert) { + assert.expect(1); + + assert.strictEqual(_.first(array), 1); }); - test('should return `undefined` when querying empty arrays', 1, function() { + QUnit.test('should return `undefined` when querying empty arrays', function(assert) { + assert.expect(1); + var array = []; array['-1'] = 1; - strictEqual(_.first(array), undefined); + assert.strictEqual(_.first(array), undefined); }); - test('should work as an iteratee for methods like `_.map`', 1, function() { + 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); - deepEqual(actual, [1, 4, 7]); + assert.deepEqual(actual, [1, 4, 7]); }); - test('should return an unwrapped value when implicitly chaining', 1, function() { + QUnit.test('should return an unwrapped value when implicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - strictEqual(_(array).first(), 1); + assert.strictEqual(_(array).first(), 1); } else { - skipTest(); + skipTest(assert); } }); - test('should return a wrapped value when explicitly chaining', 1, function() { + QUnit.test('should return a wrapped value when explicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - ok(_(array).chain().first() instanceof _); + assert.ok(_(array).chain().first() instanceof _); } else { - skipTest(); + skipTest(assert); } }); - test('should not execute immediately when explicitly chaining', 1, function() { + QUnit.test('should not execute immediately when explicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { var wrapped = _(array).chain().first(); - strictEqual(wrapped.__wrapped__, array); + assert.strictEqual(wrapped.__wrapped__, array); } else { - skipTest(); + skipTest(assert); } }); - test('should work in a lazy chain sequence', 2, function() { + QUnit.test('should work in a lazy chain sequence', function(assert) { + assert.expect(2); + if (!isNpm) { var largeArray = _.range(LARGE_ARRAY_SIZE), smallArray = array; @@ -4089,11 +4652,11 @@ var array = index ? largeArray : smallArray, wrapped = _(array).filter(isEven); - strictEqual(wrapped.first(), _.first(_.filter(array, isEven))); + assert.strictEqual(wrapped.first(), _.first(_.filter(array, isEven))); }); } else { - skipTest(2); + skipTest(assert, 2); } }); }()); @@ -4105,11 +4668,15 @@ (function() { var array = [1, 2, 3]; - test('should take the first two elements', 1, function() { - deepEqual(_.take(array, 2), [1, 2]); + QUnit.test('should take the first two elements', function(assert) { + assert.expect(1); + + assert.deepEqual(_.take(array, 2), [1, 2]); }); - test('should treat falsey `n` values, except nullish, as `0`', 1, function() { + QUnit.test('should treat falsey `n` values, except nullish, as `0`', function(assert) { + assert.expect(1); + var expected = _.map(falsey, function(value) { return value == null ? [1] : []; }); @@ -4118,52 +4685,60 @@ return _.take(array, n); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return an empty array when `n` < `1`', 3, function() { + QUnit.test('should return an empty array when `n` < `1`', function(assert) { + assert.expect(3); + _.each([0, -1, -Infinity], function(n) { - deepEqual(_.take(array, n), []); + assert.deepEqual(_.take(array, n), []); }); }); - test('should return all elements when `n` >= `array.length`', 4, function() { + 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) { - deepEqual(_.take(array, n), array); + assert.deepEqual(_.take(array, n), array); }); }); - test('should work as an iteratee for methods like `_.map`', 1, function() { + 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); - deepEqual(actual, [[1], [4], [7]]); + assert.deepEqual(actual, [[1], [4], [7]]); }); - test('should work in a lazy chain sequence', 6, function() { + 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(); - deepEqual(actual, _.take(_.take(array, 2))); + assert.deepEqual(actual, _.take(_.take(array, 2))); actual = _(array).filter(predicate).take(2).take().value(); - deepEqual(values, [1, 2]); - deepEqual(actual, _.take(_.take(_.filter(array, predicate), 2))); + assert.deepEqual(values, [1, 2]); + assert.deepEqual(actual, _.take(_.take(_.filter(array, predicate), 2))); actual = _(array).take(6).takeRight(4).take(2).takeRight().value(); - deepEqual(actual, _.takeRight(_.take(_.takeRight(_.take(array, 6), 4), 2))); + 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(); - deepEqual(values, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]); - deepEqual(actual, _.takeRight(_.take(_.takeRight(_.take(_.filter(_.take(array, array.length - 1), predicate), 6), 4), 2))); + 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(6); + skipTest(assert, 6); } }); }()); @@ -4175,11 +4750,15 @@ (function() { var array = [1, 2, 3]; - test('should take the last two elements', 1, function() { - deepEqual(_.takeRight(array, 2), [2, 3]); + QUnit.test('should take the last two elements', function(assert) { + assert.expect(1); + + assert.deepEqual(_.takeRight(array, 2), [2, 3]); }); - test('should treat falsey `n` values, except nullish, as `0`', 1, function() { + QUnit.test('should treat falsey `n` values, except nullish, as `0`', function(assert) { + assert.expect(1); + var expected = _.map(falsey, function(value) { return value == null ? [3] : []; }); @@ -4188,52 +4767,60 @@ return _.takeRight(array, n); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return an empty array when `n` < `1`', 3, function() { + QUnit.test('should return an empty array when `n` < `1`', function(assert) { + assert.expect(3); + _.each([0, -1, -Infinity], function(n) { - deepEqual(_.takeRight(array, n), []); + assert.deepEqual(_.takeRight(array, n), []); }); }); - test('should return all elements when `n` >= `array.length`', 4, function() { + 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) { - deepEqual(_.takeRight(array, n), array); + assert.deepEqual(_.takeRight(array, n), array); }); }); - test('should work as an iteratee for methods like `_.map`', 1, function() { + 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); - deepEqual(actual, [[3], [6], [9]]); + assert.deepEqual(actual, [[3], [6], [9]]); }); - test('should work in a lazy chain sequence', 6, function() { + 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(); - deepEqual(actual, _.takeRight(_.takeRight(array))); + assert.deepEqual(actual, _.takeRight(_.takeRight(array))); actual = _(array).filter(predicate).takeRight(2).takeRight().value(); - deepEqual(values, array); - deepEqual(actual, _.takeRight(_.takeRight(_.filter(array, predicate), 2))); + assert.deepEqual(values, array); + assert.deepEqual(actual, _.takeRight(_.takeRight(_.filter(array, predicate), 2))); actual = _(array).takeRight(6).take(4).takeRight(2).take().value(); - deepEqual(actual, _.take(_.takeRight(_.take(_.takeRight(array, 6), 4), 2))); + assert.deepEqual(actual, _.take(_.takeRight(_.take(_.takeRight(array, 6), 4), 2))); values = []; actual = _(array).filter(predicate).takeRight(6).take(4).takeRight(2).take().value(); - deepEqual(values, array); - deepEqual(actual, _.take(_.takeRight(_.take(_.takeRight(_.filter(array, predicate), 6), 4), 2))); + assert.deepEqual(values, array); + assert.deepEqual(actual, _.take(_.takeRight(_.take(_.takeRight(_.filter(array, predicate), 6), 4), 2))); } else { - skipTest(6); + skipTest(assert, 6); } }); }()); @@ -4251,53 +4838,67 @@ { 'a': 2, 'b': 2 } ]; - test('should take elements while `predicate` returns truthy', 1, function() { + QUnit.test('should take elements while `predicate` returns truthy', function(assert) { + assert.expect(1); + var actual = _.takeRightWhile(array, function(num) { return num > 2; }); - deepEqual(actual, [3, 4]); + assert.deepEqual(actual, [3, 4]); }); - test('should provide the correct `predicate` arguments', 1, function() { + QUnit.test('should provide the correct `predicate` arguments', function(assert) { + assert.expect(1); + var args; _.takeRightWhile(array, function() { args = slice.call(arguments); }); - deepEqual(args, [4, 3, array]); + assert.deepEqual(args, [4, 3, array]); }); - test('should work with a "_.matches" style `predicate`', 1, function() { - deepEqual(_.takeRightWhile(objects, { 'b': 2 }), objects.slice(2)); + QUnit.test('should work with a "_.matches" style `predicate`', function(assert) { + assert.expect(1); + + assert.deepEqual(_.takeRightWhile(objects, { 'b': 2 }), objects.slice(2)); }); - test('should work with a "_.matchesProperty" style `predicate`', 1, function() { - 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)); }); - test('should work with a "_.property" style `predicate`', 1, function() { - deepEqual(_.takeRightWhile(objects, 'b'), objects.slice(1)); + QUnit.test('should work with a "_.property" style `predicate`', function(assert) { + assert.expect(1); + + assert.deepEqual(_.takeRightWhile(objects, 'b'), objects.slice(1)); }); - test('should work in a lazy chain sequence', 3, function() { + 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); - deepEqual(wrapped.value(), expected); - deepEqual(wrapped.reverse().value(), expected.slice().reverse()); - strictEqual(wrapped.last(), _.last(expected)); + assert.deepEqual(wrapped.value(), expected); + assert.deepEqual(wrapped.reverse().value(), expected.slice().reverse()); + assert.strictEqual(wrapped.last(), _.last(expected)); } else { - skipTest(3); + skipTest(assert, 3); } }); - test('should provide the correct `predicate` arguments in a lazy chain sequence', 5, function() { + 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), @@ -4307,34 +4908,34 @@ args = slice.call(arguments); }).value(); - deepEqual(args, [LARGE_ARRAY_SIZE, LARGE_ARRAY_SIZE - 1, array.slice(1)]); + 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(); - deepEqual(args, expected); + assert.deepEqual(args, expected); _(array).slice(1).map(square).takeRightWhile(function(value, index) { args = slice.call(arguments); }).value(); - deepEqual(args, expected); + assert.deepEqual(args, expected); _(array).slice(1).map(square).takeRightWhile(function(index) { args = slice.call(arguments); }).value(); - deepEqual(args, [square(LARGE_ARRAY_SIZE)]); + assert.deepEqual(args, [square(LARGE_ARRAY_SIZE)]); _(array).slice(1).map(square).takeRightWhile(function() { args = slice.call(arguments); }).value(); - deepEqual(args, expected); + assert.deepEqual(args, expected); } else { - skipTest(5); + skipTest(assert, 5); } }); }()); @@ -4352,52 +4953,66 @@ { 'a': 0, 'b': 0 } ]; - test('should take elements while `predicate` returns truthy', 1, function() { + QUnit.test('should take elements while `predicate` returns truthy', function(assert) { + assert.expect(1); + var actual = _.takeWhile(array, function(num) { return num < 3; }); - deepEqual(actual, [1, 2]); + assert.deepEqual(actual, [1, 2]); }); - test('should provide the correct `predicate` arguments', 1, function() { + QUnit.test('should provide the correct `predicate` arguments', function(assert) { + assert.expect(1); + var args; _.takeWhile(array, function() { args = slice.call(arguments); }); - deepEqual(args, [1, 0, array]); + assert.deepEqual(args, [1, 0, array]); }); - test('should work with a "_.matches" style `predicate`', 1, function() { - deepEqual(_.takeWhile(objects, { 'b': 2 }), objects.slice(0, 1)); + QUnit.test('should work with a "_.matches" style `predicate`', function(assert) { + assert.expect(1); + + assert.deepEqual(_.takeWhile(objects, { 'b': 2 }), objects.slice(0, 1)); }); - test('should work with a "_.matchesProperty" style `predicate`', 1, function() { - 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)); }); - test('should work with a "_.property" style `predicate`', 1, function() { - deepEqual(_.takeWhile(objects, 'b'), objects.slice(0, 2)); + QUnit.test('should work with a "_.property" style `predicate`', function(assert) { + assert.expect(1); + + assert.deepEqual(_.takeWhile(objects, 'b'), objects.slice(0, 2)); }); - test('should work in a lazy chain sequence', 3, function() { + 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); - deepEqual(wrapped.value(), expected); - deepEqual(wrapped.reverse().value(), expected.slice().reverse()); - strictEqual(wrapped.last(), _.last(expected)); + assert.deepEqual(wrapped.value(), expected); + assert.deepEqual(wrapped.reverse().value(), expected.slice().reverse()); + assert.strictEqual(wrapped.last(), _.last(expected)); } else { - skipTest(3); + skipTest(assert, 3); } }); - test('should work in a lazy chain sequence with `take`', 1, function() { + QUnit.test('should work in a lazy chain sequence with `take`', function(assert) { + assert.expect(1); + if (!isNpm) { var array = _.range(LARGE_ARRAY_SIZE); @@ -4407,14 +5022,16 @@ .takeWhile(function(num) { return num == 0; }) .value(); - deepEqual(actual, [0]); + assert.deepEqual(actual, [0]); } else { - skipTest(); + skipTest(assert); } }); - test('should provide the correct `predicate` arguments in a lazy chain sequence', 5, function() { + 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), @@ -4424,34 +5041,34 @@ args = slice.call(arguments); }).value(); - deepEqual(args, [1, 0, array.slice(1)]); + assert.deepEqual(args, [1, 0, array.slice(1)]); _(array).slice(1).map(square).takeWhile(function(value, index, array) { args = slice.call(arguments); }).value(); - deepEqual(args, expected); + assert.deepEqual(args, expected); _(array).slice(1).map(square).takeWhile(function(value, index) { args = slice.call(arguments); }).value(); - deepEqual(args, expected); + assert.deepEqual(args, expected); _(array).slice(1).map(square).takeWhile(function(value) { args = slice.call(arguments); }).value(); - deepEqual(args, [1]); + assert.deepEqual(args, [1]); _(array).slice(1).map(square).takeWhile(function() { args = slice.call(arguments); }).value(); - deepEqual(args, expected); + assert.deepEqual(args, expected); } else { - skipTest(5); + skipTest(assert, 5); } }); }()); @@ -4463,31 +5080,39 @@ (function() { var args = arguments; - test('should perform a shallow flatten', 1, function() { + QUnit.test('should perform a shallow flatten', function(assert) { + assert.expect(1); + var array = [[['a']], [['b']]]; - deepEqual(_.flatten(array), [['a'], ['b']]); + assert.deepEqual(_.flatten(array), [['a'], ['b']]); }); - test('should flatten `arguments` objects', 2, function() { + QUnit.test('should flatten `arguments` objects', function(assert) { + assert.expect(2); + var array = [args, [args]]; - deepEqual(_.flatten(array), [1, 2, 3, args]); - deepEqual(_.flattenDeep(array), [1, 2, 3, 1, 2, 3]); + assert.deepEqual(_.flatten(array), [1, 2, 3, args]); + assert.deepEqual(_.flattenDeep(array), [1, 2, 3, 1, 2, 3]); }); - test('should treat sparse arrays as dense', 6, function() { + QUnit.test('should treat sparse arrays as dense', function(assert) { + assert.expect(6); + var array = [[1, 2, 3], Array(3)], expected = [1, 2, 3]; expected.push(undefined, undefined, undefined); _.each([_.flatten(array), _.flatten(array, true), _.flattenDeep(array)], function(actual) { - deepEqual(actual, expected); - ok('4' in actual); + assert.deepEqual(actual, expected); + assert.ok('4' in actual); }); }); - test('should work with extremely large arrays', 3, function() { + QUnit.test('should work with extremely large arrays', function(assert) { + assert.expect(3); + // Test in modern browsers only to avoid browser hangs. _.times(3, function(index) { if (freeze) { @@ -4499,54 +5124,62 @@ } else { actual = _.flatten(expected); } - deepEqual(actual, expected); + assert.deepEqual(actual, expected); } catch (e) { - ok(false, e.message); + assert.ok(false, e.message); } } else { - skipTest(); + skipTest(assert); } }); }); - test('should work with empty arrays', 2, function() { + QUnit.test('should work with empty arrays', function(assert) { + assert.expect(2); + var array = [[], [[]], [[], [[[]]]]]; - deepEqual(_.flatten(array), [[], [], [[[]]]]); - deepEqual(_.flattenDeep(array), []); + assert.deepEqual(_.flatten(array), [[], [], [[[]]]]); + assert.deepEqual(_.flattenDeep(array), []); }); - test('should support flattening of nested arrays', 2, function() { + QUnit.test('should support flattening of nested arrays', function(assert) { + assert.expect(2); + var array = [1, [2, 3], 4, [[5]]]; - deepEqual(_.flatten(array), [1, 2, 3, 4, [5]]); - deepEqual(_.flattenDeep(array), [1, 2, 3, 4, 5]); + assert.deepEqual(_.flatten(array), [1, 2, 3, 4, [5]]); + assert.deepEqual(_.flattenDeep(array), [1, 2, 3, 4, 5]); }); - test('should return an empty array for non array-like objects', 3, function() { + QUnit.test('should return an empty array for non array-like objects', function(assert) { + assert.expect(3); + var expected = []; - deepEqual(_.flatten({ 'a': 1 }), expected); - deepEqual(_.flatten({ 'a': 1 }, true), expected); - deepEqual(_.flattenDeep({ 'a': 1 }), expected); + assert.deepEqual(_.flatten({ 'a': 1 }), expected); + assert.deepEqual(_.flatten({ 'a': 1 }, true), expected); + assert.deepEqual(_.flattenDeep({ 'a': 1 }), expected); }); - test('should return a wrapped value when chaining', 4, function() { + QUnit.test('should return a wrapped value when chaining', function(assert) { + assert.expect(4); + if (!isNpm) { var wrapped = _([1, [2], [3, [4]]]), actual = wrapped.flatten(); - ok(actual instanceof _); - deepEqual(actual.value(), [1, 2, 3, [4]]); + assert.ok(actual instanceof _); + assert.deepEqual(actual.value(), [1, 2, 3, [4]]); actual = wrapped.flattenDeep(); - ok(actual instanceof _); - deepEqual(actual.value(), [1, 2, 3, 4]); + assert.ok(actual instanceof _); + assert.deepEqual(actual.value(), [1, 2, 3, 4]); } else { - skipTest(4); + skipTest(assert, 4); } }); }(1, 2, 3)); @@ -4556,8 +5189,10 @@ QUnit.module('lodash.forEach'); (function() { - test('should be aliased', 1, function() { - strictEqual(_.each, _.forEach); + QUnit.test('should be aliased', function(assert) { + assert.expect(1); + + assert.strictEqual(_.each, _.forEach); }); }()); @@ -4566,8 +5201,10 @@ QUnit.module('lodash.forEachRight'); (function() { - test('should be aliased', 1, function() { - strictEqual(_.eachRight, _.forEachRight); + QUnit.test('should be aliased', function(assert) { + assert.expect(1); + + assert.strictEqual(_.eachRight, _.forEachRight); }); }()); @@ -4578,13 +5215,15 @@ _.each(['forIn', 'forInRight'], function(methodName) { var func = _[methodName]; - test('`_.' + methodName + '` iterates over inherited properties', 1, function() { + QUnit.test('`_.' + methodName + '` iterates over inherited properties', function(assert) { + assert.expect(1); + function Foo() { this.a = 1; } Foo.prototype.b = 2; var keys = []; func(new Foo, function(value, key) { keys.push(key); }); - deepEqual(keys.sort(), ['a', 'b']); + assert.deepEqual(keys.sort(), ['a', 'b']); }); }); @@ -4595,12 +5234,14 @@ _.each(['forOwn', 'forOwnRight'], function(methodName) { var func = _[methodName]; - test('should iterate over `length` properties', 1, function() { + QUnit.test('should iterate over `length` properties', function(assert) { + assert.expect(1); + var object = { '0': 'zero', '1': 'one', 'length': 2 }, props = []; func(object, function(value, prop) { props.push(prop); }); - deepEqual(props.sort(), ['0', '1', 'length']); + assert.deepEqual(props.sort(), ['0', '1', 'length']); }); }); @@ -4733,7 +5374,9 @@ isFind = /^find/.test(methodName), isSome = methodName == 'some'; - test('`_.' + methodName + '` should provide the correct iteratee arguments', 1, function() { + QUnit.test('`_.' + methodName + '` should provide the correct iteratee arguments', function(assert) { + assert.expect(1); + if (func) { var args, expected = [1, 0, array]; @@ -4752,14 +5395,16 @@ if (isBy) { expected.length = 1; } - deepEqual(args, expected); + assert.deepEqual(args, expected); } else { - skipTest(); + skipTest(assert); } }); - test('`_.' + methodName + '` should treat sparse arrays as dense', 1, function() { + QUnit.test('`_.' + methodName + '` should treat sparse arrays as dense', function(assert) { + assert.expect(1); + if (func) { var array = [1]; array[2] = 3; @@ -4786,10 +5431,10 @@ return !(isFind || isSome); }); - deepEqual(argsList, expected); + assert.deepEqual(argsList, expected); } else { - skipTest(); + skipTest(assert); } }); }); @@ -4801,7 +5446,9 @@ array.a = 1; - test('`_.' + methodName + '` should not iterate custom properties on arrays', 1, function() { + QUnit.test('`_.' + methodName + '` should not iterate custom properties on arrays', function(assert) { + assert.expect(1); + if (func) { var keys = []; func(array, function(value, key) { @@ -4809,10 +5456,10 @@ return isEvery; }); - ok(!_.includes(keys, 'a')); + assert.notOk(_.includes(keys, 'a')); } else { - skipTest(); + skipTest(assert); } }); }); @@ -4822,13 +5469,15 @@ func = _[methodName], isBaseEach = methodName == '_baseEach'; - test('`_.' + methodName + '` should return a wrapped value when implicitly chaining', 1, function() { + QUnit.test('`_.' + methodName + '` should return a wrapped value when implicitly chaining', function(assert) { + assert.expect(1); + if (!(isBaseEach || isNpm)) { var wrapped = _(array)[methodName](_.noop); - ok(wrapped instanceof _); + assert.ok(wrapped instanceof _); } else { - skipTest(); + skipTest(assert); } }); }); @@ -4837,26 +5486,30 @@ var array = [1, 2, 3], func = _[methodName]; - test('`_.' + methodName + '` should return an unwrapped value when implicitly chaining', 1, function() { + QUnit.test('`_.' + methodName + '` should return an unwrapped value when implicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { var actual = _(array)[methodName](_.noop); - ok(!(actual instanceof _)); + assert.notOk(actual instanceof _); } else { - skipTest(); + skipTest(assert); } }); - test('`_.' + methodName + '` should return a wrapped value when explicitly chaining', 2, function() { + QUnit.test('`_.' + methodName + '` should return a wrapped value when explicitly chaining', function(assert) { + assert.expect(2); + if (!isNpm) { var wrapped = _(array).chain(), actual = wrapped[methodName](_.noop); - ok(actual instanceof _); - notStrictEqual(actual, wrapped); + assert.ok(actual instanceof _); + assert.notStrictEqual(actual, wrapped); } else { - skipTest(2); + skipTest(assert, 2); } }); }); @@ -4865,17 +5518,19 @@ var array = [1, 2, 3], func = _[methodName]; - test('`_.' + methodName + '` iterates over own properties of objects', 1, function() { + QUnit.test('`_.' + methodName + '` iterates over own properties of objects', function(assert) { + assert.expect(1); + function Foo() { this.a = 1; } Foo.prototype.b = 2; if (func) { var values = []; func(new Foo, function(value) { values.push(value); }); - deepEqual(values, [1]); + assert.deepEqual(values, [1]); } else { - skipTest(); + skipTest(assert); } }); }); @@ -4884,12 +5539,14 @@ var array = [1, 2, 3], func = _[methodName]; - test('`_.' + methodName + '` should return the collection', 1, function() { + QUnit.test('`_.' + methodName + '` should return the collection', function(assert) { + assert.expect(1); + if (func) { - strictEqual(func(array, Boolean), array); + assert.strictEqual(func(array, Boolean), array); } else { - skipTest(); + skipTest(assert); } }); }); @@ -4897,7 +5554,9 @@ _.each(collectionMethods, function(methodName) { var func = _[methodName]; - test('`_.' + methodName + '` should use `isArrayLike` to determine whether a value is array-like', 3, function() { + QUnit.test('`_.' + methodName + '` should use `isArrayLike` to determine whether a value is array-like', function(assert) { + assert.expect(3); + if (func) { var isIteratedAsObject = function(object) { var result = false; @@ -4915,12 +5574,12 @@ var Foo = function(a) {}; Foo.a = 1; - deepEqual(actual, expected); - ok(isIteratedAsObject(Foo)); - ok(!isIteratedAsObject({ 'length': 0 })); + assert.deepEqual(actual, expected); + assert.ok(isIteratedAsObject(Foo)); + assert.notOk(isIteratedAsObject({ 'length': 0 })); } else { - skipTest(3); + skipTest(assert, 3); } }); }); @@ -4932,7 +5591,9 @@ isSome = methodName == 'some', isReduce = /^reduce/.test(methodName); - test('`_.' + methodName + '` should ignore changes to `array.length`', 1, function() { + QUnit.test('`_.' + methodName + '` should ignore changes to `array.length`', function(assert) { + assert.expect(1); + if (func) { var count = 0, array = [1]; @@ -4944,10 +5605,10 @@ return !(isFind || isSome); }, isReduce ? array : null); - strictEqual(count, 1); + assert.strictEqual(count, 1); } else { - skipTest(); + skipTest(assert); } }); }); @@ -4958,7 +5619,9 @@ isSome = methodName == 'some', isReduce = /^reduce/.test(methodName); - test('`_.' + methodName + '` should ignore added `object` properties', 1, function() { + QUnit.test('`_.' + methodName + '` should ignore added `object` properties', function(assert) { + assert.expect(1); + if (func) { var count = 0, object = { 'a': 1 }; @@ -4970,10 +5633,10 @@ return !(isFind || isSome); }, isReduce ? object : null); - strictEqual(count, 1); + assert.strictEqual(count, 1); } else { - skipTest(); + skipTest(assert); } }); }); @@ -4988,7 +5651,9 @@ isAssign = methodName == 'assign', isDefaults = methodName == 'defaults'; - test('`_.' + methodName + '` should coerce primitives to objects', 1, function() { + QUnit.test('`_.' + methodName + '` should coerce primitives to objects', function(assert) { + assert.expect(1); + var expected = _.map(falsey, _.constant(true)); var actual = _.map(falsey, function(object, index) { @@ -4996,26 +5661,32 @@ return _.isEqual(result, Object(object)); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('`_.' + methodName + '` should assign own ' + (isAssign ? '' : 'and inherited ') + 'source properties', 1, function() { + QUnit.test('`_.' + methodName + '` should assign own ' + (isAssign ? '' : 'and inherited ') + 'source properties', function(assert) { + assert.expect(1); + function Foo() { this.a = 1; } Foo.prototype.b = 2; var expected = isAssign ? { 'a': 1 } : { 'a': 1, 'b': 2 }; - deepEqual(func({}, new Foo), expected); + assert.deepEqual(func({}, new Foo), expected); }); - test('`_.' + methodName + '` should not error on nullish sources', 1, function() { + QUnit.test('`_.' + methodName + '` should not error on nullish sources', function(assert) { + assert.expect(1); + try { - deepEqual(func({ 'a': 1 }, undefined, { 'b': 2 }, null), { 'a': 1, 'b': 2 }); + assert.deepEqual(func({ 'a': 1 }, undefined, { 'b': 2 }, null), { 'a': 1, 'b': 2 }); } catch (e) { - ok(false, e.message); + assert.ok(false, e.message); } }); - test('`_.' + methodName + '` should not error when `object` is nullish and source objects are provided', 1, function() { + QUnit.test('`_.' + methodName + '` should not error when `object` is nullish and source objects are provided', function(assert) { + assert.expect(1); + var expected = _.times(2, _.constant(true)); var actual = _.map([null, undefined], function(value) { @@ -5026,26 +5697,30 @@ } }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('`_.' + methodName + '` should work as an iteratee for methods like `_.reduce`', 1, function() { + QUnit.test('`_.' + methodName + '` should work as an iteratee for methods like `_.reduce`', function(assert) { + assert.expect(1); + var array = [{ 'a': 1 }, { 'b': 2 }, { 'c': 3 }], expected = { 'a': 1, 'b': 2, 'c': 3 }; expected.a = isDefaults ? 0 : 1; - deepEqual(_.reduce(array, func, { 'a': 0 }), expected); + assert.deepEqual(_.reduce(array, func, { 'a': 0 }), expected); }); - test('`_.' + methodName + '` should not return the existing wrapped value when chaining', 1, function() { + QUnit.test('`_.' + methodName + '` should not return the existing wrapped value when chaining', function(assert) { + assert.expect(1); + if (!isNpm) { var wrapped = _({ 'a': 1 }), actual = wrapped[methodName]({ 'b': 2 }); - notStrictEqual(actual, wrapped); + assert.notStrictEqual(actual, wrapped); } else { - skipTest(); + skipTest(assert); } }); }); @@ -5053,19 +5728,23 @@ _.each(['assign', 'extend', 'merge'], function(methodName) { var func = _[methodName]; - test('`_.' + methodName + '` should not treat `object` as `source`', 1, function() { + QUnit.test('`_.' + methodName + '` should not treat `object` as `source`', function(assert) { + assert.expect(1); + function Foo() {} Foo.prototype.a = 1; var actual = func(new Foo, { 'b': 2 }); - ok(!_.has(actual, 'a')); + assert.notOk(_.has(actual, 'a')); }); }); _.each(['assign', 'assignWith', 'defaults', 'extend', 'extendWith', 'merge', 'mergeWith'], function(methodName) { var func = _[methodName]; - test('`_.' + methodName + '` should not assign values that are the same as their destinations', 4, function() { + QUnit.test('`_.' + methodName + '` should not assign values that are the same as their destinations', function(assert) { + assert.expect(4); + _.each(['a', ['a'], { 'a': 1 }, NaN], function(value) { if (defineProperty) { var object = {}, @@ -5077,10 +5756,10 @@ }); func(object, { 'a': value }); - ok(pass, value); + assert.ok(pass, value); } else { - skipTest(); + skipTest(assert); } }); }); @@ -5090,7 +5769,9 @@ var func = _[methodName], isMergeWith = methodName == 'mergeWith'; - test('`_.' + methodName + '` should provide the correct `customizer` arguments', 3, function() { + QUnit.test('`_.' + methodName + '` should provide the correct `customizer` arguments', function(assert) { + assert.expect(3); + var args, object = { 'a': 1 }, source = { 'a': 2 }, @@ -5103,7 +5784,7 @@ args || (args = _.map(arguments, _.clone)); }); - deepEqual(args, expected, 'primitive property values'); + assert.deepEqual(args, expected, 'primitive property values'); args = null; object = { 'a': 1 }; @@ -5117,7 +5798,7 @@ args || (args = _.map(arguments, _.clone)); }); - deepEqual(args, expected, 'missing destination property'); + assert.deepEqual(args, expected, 'missing destination property'); var argsList = [], objectValue = [1, 2], @@ -5135,18 +5816,20 @@ argsList.push(_.map(arguments, _.cloneDeep)); }); - deepEqual(argsList, expected, 'object property values'); + assert.deepEqual(argsList, expected, 'object property values'); }); - test('`_.' + methodName + '` should not treat the second argument as a `customizer` callback', 2, function() { + QUnit.test('`_.' + methodName + '` should not treat the second argument as a `customizer` callback', function(assert) { + assert.expect(2); + function callback() {} callback.b = 2; var actual = func({ 'a': 1 }, callback); - deepEqual(actual, { 'a': 1, 'b': 2 }); + assert.deepEqual(actual, { 'a': 1, 'b': 2 }); actual = func({ 'a': 1 }, callback, { 'c': 3 }); - deepEqual(actual, { 'a': 1, 'b': 2, 'c': 3 }); + assert.deepEqual(actual, { 'a': 1, 'b': 2, 'c': 3 }); }); }); @@ -5157,7 +5840,9 @@ _.each(['_baseEach', 'forEach', 'forEachRight', 'forIn', 'forInRight', 'forOwn', 'forOwnRight', 'transform'], function(methodName) { var func = _[methodName]; - test('`_.' + methodName + '` can exit early when iterating arrays', 1, function() { + QUnit.test('`_.' + methodName + '` can exit early when iterating arrays', function(assert) { + assert.expect(1); + if (func) { var array = [1, 2, 3], values = []; @@ -5167,14 +5852,16 @@ return false; }); - deepEqual(values, [_.endsWith(methodName, 'Right') ? 3 : 1]); + assert.deepEqual(values, [_.endsWith(methodName, 'Right') ? 3 : 1]); } else { - skipTest(); + skipTest(assert); } }); - test('`_.' + methodName + '` can exit early when iterating objects', 1, function() { + QUnit.test('`_.' + methodName + '` can exit early when iterating objects', function(assert) { + assert.expect(1); + if (func) { var object = { 'a': 1, 'b': 2, 'c': 3 }, values = []; @@ -5184,10 +5871,10 @@ return false; }); - strictEqual(values.length, 1); + assert.strictEqual(values.length, 1); } else { - skipTest(); + skipTest(assert); } }); }); @@ -5197,7 +5884,9 @@ QUnit.module('`__proto__` property bugs'); (function() { - test('internal data objects should work with the `__proto__` key', 4, function() { + QUnit.test('internal data objects should work with the `__proto__` key', function(assert) { + assert.expect(4); + var stringLiteral = '__proto__', stringObject = Object(stringLiteral), expected = [stringLiteral, stringObject]; @@ -5206,10 +5895,10 @@ return isEven(count) ? stringLiteral : stringObject; }); - deepEqual(_.difference(largeArray, largeArray), []); - deepEqual(_.intersection(largeArray, largeArray), expected); - deepEqual(_.uniq(largeArray), expected); - deepEqual(_.without.apply(_, [largeArray].concat(largeArray)), []); + assert.deepEqual(_.difference(largeArray, largeArray), []); + assert.deepEqual(_.intersection(largeArray, largeArray), expected); + assert.deepEqual(_.uniq(largeArray), expected); + assert.deepEqual(_.without.apply(_, [largeArray].concat(largeArray)), []); }); }()); @@ -5218,18 +5907,22 @@ QUnit.module('lodash.functions'); (function() { - test('should return the function names of an object', 1, function() { + QUnit.test('should return the function names of an object', function(assert) { + assert.expect(1); + var object = { 'a': 'a', 'b': _.identity, 'c': /x/, 'd': _.each }; - deepEqual(_.functions(object).sort(), ['b', 'd']); + assert.deepEqual(_.functions(object).sort(), ['b', 'd']); }); - test('should include inherited functions', 1, function() { + QUnit.test('should include inherited functions', function(assert) { + assert.expect(1); + function Foo() { this.a = _.identity; this.b = 'b'; } Foo.prototype.c = _.noop; - deepEqual(_.functions(new Foo).sort(), ['a', 'c']); + assert.deepEqual(_.functions(new Foo).sort(), ['a', 'c']); }); }()); @@ -5240,7 +5933,9 @@ (function() { var array = [4.2, 6.1, 6.4]; - test('should use `_.identity` when `iteratee` is nullish', 1, function() { + QUnit.test('should use `_.identity` when `iteratee` is nullish', function(assert) { + assert.expect(1); + var array = [4, 6, 6], values = [, null, undefined], expected = _.map(values, _.constant({ '4': [4], '6': [6, 6] })); @@ -5249,43 +5944,53 @@ return index ? _.groupBy(array, value) : _.groupBy(array); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work with a "_.property" style `iteratee`', 1, function() { + QUnit.test('should work with a "_.property" style `iteratee`', function(assert) { + assert.expect(1); + var actual = _.groupBy(['one', 'two', 'three'], 'length'); - deepEqual(actual, { '3': ['one', 'two'], '5': ['three'] }); + assert.deepEqual(actual, { '3': ['one', 'two'], '5': ['three'] }); }); - test('should only add values to own, not inherited, properties', 2, function() { + QUnit.test('should only add values to own, not inherited, properties', function(assert) { + assert.expect(2); + var actual = _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num) > 4 ? 'hasOwnProperty' : 'constructor'; }); - deepEqual(actual.constructor, [4.2]); - deepEqual(actual.hasOwnProperty, [6.1, 6.4]); + assert.deepEqual(actual.constructor, [4.2]); + assert.deepEqual(actual.hasOwnProperty, [6.1, 6.4]); }); - test('should work with a number for `iteratee`', 2, function() { + QUnit.test('should work with a number for `iteratee`', function(assert) { + assert.expect(2); + var array = [ [1, 'a'], [2, 'a'], [2, 'b'] ]; - deepEqual(_.groupBy(array, 0), { '1': [[1, 'a']], '2': [[2, 'a'], [2, 'b']] }); - deepEqual(_.groupBy(array, 1), { 'a': [[1, 'a'], [2, 'a']], 'b': [[2, 'b']] }); + assert.deepEqual(_.groupBy(array, 0), { '1': [[1, 'a']], '2': [[2, 'a'], [2, 'b']] }); + assert.deepEqual(_.groupBy(array, 1), { 'a': [[1, 'a'], [2, 'a']], 'b': [[2, 'b']] }); }); - test('should work with an object for `collection`', 1, function() { + QUnit.test('should work with an object for `collection`', function(assert) { + assert.expect(1); + var actual = _.groupBy({ 'a': 4.2, 'b': 6.1, 'c': 6.4 }, function(num) { return Math.floor(num); }); - deepEqual(actual, { '4': [4.2], '6': [6.1, 6.4] }); + assert.deepEqual(actual, { '4': [4.2], '6': [6.1, 6.4] }); }); - test('should work in a lazy chain sequence', 1, function() { + QUnit.test('should work in a lazy chain sequence', function(assert) { + assert.expect(1); + if (!isNpm) { var array = _.range(LARGE_ARRAY_SIZE).concat( _.range(Math.floor(LARGE_ARRAY_SIZE / 2), LARGE_ARRAY_SIZE), @@ -5296,10 +6001,10 @@ predicate = function(value) { return isEven(value[0]); }, actual = _(array).groupBy().map(iteratee).filter(predicate).take().value(); - deepEqual(actual, _.take(_.filter(_.map(_.groupBy(array), iteratee), predicate))); + assert.deepEqual(actual, _.take(_.filter(_.map(_.groupBy(array), iteratee), predicate))); } else { - skipTest(); + skipTest(assert); } }); }()); @@ -5309,16 +6014,20 @@ QUnit.module('lodash.gt'); (function() { - test('should return `true` if `value` is greater than `other`', 2, function() { - strictEqual(_.gt(3, 1), true); - strictEqual(_.gt('def', 'abc'), true); + QUnit.test('should return `true` if `value` is greater than `other`', function(assert) { + assert.expect(2); + + assert.strictEqual(_.gt(3, 1), true); + assert.strictEqual(_.gt('def', 'abc'), true); }); - test('should return `false` if `value` is less than or equal to `other`', 4, function() { - strictEqual(_.gt(1, 3), false); - strictEqual(_.gt(3, 3), false); - strictEqual(_.gt('abc', 'def'), false); - strictEqual(_.gt('def', 'def'), false); + QUnit.test('should return `false` if `value` is less than or equal to `other`', function(assert) { + assert.expect(4); + + assert.strictEqual(_.gt(1, 3), false); + assert.strictEqual(_.gt(3, 3), false); + assert.strictEqual(_.gt('abc', 'def'), false); + assert.strictEqual(_.gt('def', 'def'), false); }); }()); @@ -5327,16 +6036,20 @@ QUnit.module('lodash.gte'); (function() { - test('should return `true` if `value` is greater than or equal to `other`', 4, function() { - strictEqual(_.gte(3, 1), true); - strictEqual(_.gte(3, 3), true); - strictEqual(_.gte('def', 'abc'), true); - strictEqual(_.gte('def', 'def'), true); + QUnit.test('should return `true` if `value` is greater than or equal to `other`', function(assert) { + assert.expect(4); + + assert.strictEqual(_.gte(3, 1), true); + assert.strictEqual(_.gte(3, 3), true); + assert.strictEqual(_.gte('def', 'abc'), true); + assert.strictEqual(_.gte('def', 'def'), true); }); - test('should return `false` if `value` is less than `other`', 2, function() { - strictEqual(_.gte(1, 3), false); - strictEqual(_.gte('abc', 'def'), false); + QUnit.test('should return `false` if `value` is less than `other`', function(assert) { + assert.expect(2); + + assert.strictEqual(_.gte(1, 3), false); + assert.strictEqual(_.gte('abc', 'def'), false); }); }()); @@ -5349,36 +6062,46 @@ func = _[methodName], isHas = methodName == 'has'; - test('`_.' + methodName + '` should check for own properties', 2, function() { + QUnit.test('`_.' + methodName + '` should check for own properties', function(assert) { + assert.expect(2); + var object = { 'a': 1 }; _.each(['a', ['a']], function(path) { - strictEqual(func(object, path), true); + assert.strictEqual(func(object, path), true); }); }); - test('`_.' + methodName + '` should not use the `hasOwnProperty` method of the object', 1, function() { + QUnit.test('`_.' + methodName + '` should not use the `hasOwnProperty` method of the object', function(assert) { + assert.expect(1); + var object = { 'hasOwnProperty': null, 'a': 1 }; - strictEqual(func(object, 'a'), true); + assert.strictEqual(func(object, 'a'), true); }); - test('`_.' + methodName + '` should support deep paths', 2, function() { + QUnit.test('`_.' + methodName + '` should support deep paths', function(assert) { + assert.expect(2); + var object = { 'a': { 'b': { 'c': 3 } } }; _.each(['a.b.c', ['a', 'b', 'c']], function(path) { - strictEqual(func(object, path), true); + assert.strictEqual(func(object, path), true); }); }); - test('`_.' + methodName + '` should work with non-string `path` arguments', 2, function() { + QUnit.test('`_.' + methodName + '` should work with non-string `path` arguments', function(assert) { + assert.expect(2); + var array = [1, 2, 3]; _.each([1, [1]], function(path) { - strictEqual(func(array, path), true); + assert.strictEqual(func(array, path), true); }); }); - test('`_.' + methodName + '` should coerce key to a string', 1, function() { + QUnit.test('`_.' + methodName + '` should coerce key to a string', function(assert) { + assert.expect(1); + function fn() {} fn.toString = _.constant('fn'); @@ -5394,35 +6117,45 @@ }); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('`_.' + methodName + '` should return `' + (isHas ? 'false' : 'true') + '` for inherited properties', 2, function() { + QUnit.test('`_.' + methodName + '` should return `' + (isHas ? 'false' : 'true') + '` for inherited properties', function(assert) { + assert.expect(2); + function Foo() {} Foo.prototype.a = 1; _.each(['a', ['a']], function(path) { - strictEqual(func(new Foo, path), !isHas); + assert.strictEqual(func(new Foo, path), !isHas); }); }); - test('`_.' + methodName + '` should treat sparse arrays as dense', 1, function() { - strictEqual(func(Array(1), 0), true); + QUnit.test('`_.' + methodName + '` should treat sparse arrays as dense', function(assert) { + assert.expect(1); + + assert.strictEqual(func(Array(1), 0), true); }); - test('`_.' + methodName + '` should work with `arguments` objects', 1, function() { - strictEqual(func(args, 1), true); + QUnit.test('`_.' + methodName + '` should work with `arguments` objects', function(assert) { + assert.expect(1); + + assert.strictEqual(func(args, 1), true); }); - test('`_.' + methodName + '` should check for a key over a path', 2, function() { + QUnit.test('`_.' + methodName + '` should check for a key over a path', function(assert) { + assert.expect(2); + var object = { 'a.b.c': 3, 'a': { 'b': { 'c': 4 } } }; _.each(['a.b.c', ['a.b.c']], function(path) { - strictEqual(func(object, path), true); + assert.strictEqual(func(object, path), true); }); }); - test('`_.' + methodName + '` should return `false` when `object` is nullish', 2, function() { + QUnit.test('`_.' + methodName + '` should return `false` when `object` is nullish', function(assert) { + assert.expect(2); + var values = [null, undefined], expected = _.map(values, _.constant(false)); @@ -5431,11 +6164,13 @@ return func(value, path); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }); - test('`_.' + methodName + '` should return `false` with deep paths when `object` is nullish', 2, function() { + QUnit.test('`_.' + methodName + '` should return `false` with deep paths when `object` is nullish', function(assert) { + assert.expect(2); + var values = [null, undefined], expected = _.map(values, _.constant(false)); @@ -5444,15 +6179,17 @@ return func(value, path); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }); - test('`_.' + methodName + '` should return `false` if parts of `path` are missing', 4, function() { + QUnit.test('`_.' + methodName + '` should return `false` if parts of `path` are missing', function(assert) { + assert.expect(4); + var object = {}; _.each(['a', 'a[1].b.c', ['a'], ['a', '1', 'b', 'c']], function(path) { - strictEqual(func(object, path), false); + assert.strictEqual(func(object, path), false); }); }); }); @@ -5462,9 +6199,11 @@ QUnit.module('lodash.identity'); (function() { - test('should return the first argument provided', 1, function() { + QUnit.test('should return the first argument provided', function(assert) { + assert.expect(1); + var object = { 'name': 'fred' }; - strictEqual(_.identity(object), object); + assert.strictEqual(_.identity(object), object); }); }()); @@ -5484,73 +6223,95 @@ values = _.toArray(collection), length = values.length; - test('should work with ' + key + ' and return `true` for matched values', 1, function() { - strictEqual(_.includes(collection, 3), true); + QUnit.test('should work with ' + key + ' and return `true` for matched values', function(assert) { + assert.expect(1); + + assert.strictEqual(_.includes(collection, 3), true); }); - test('should work with ' + key + ' and return `false` for unmatched values', 1, function() { - strictEqual(_.includes(collection, 5), false); + QUnit.test('should work with ' + key + ' and return `false` for unmatched values', function(assert) { + assert.expect(1); + + assert.strictEqual(_.includes(collection, 5), false); }); - test('should work with ' + key + ' and a positive `fromIndex`', 2, function() { - strictEqual(_.includes(collection, values[2], 2), true); - strictEqual(_.includes(collection, values[1], 2), false); + QUnit.test('should work with ' + key + ' and a positive `fromIndex`', function(assert) { + assert.expect(2); + + assert.strictEqual(_.includes(collection, values[2], 2), true); + assert.strictEqual(_.includes(collection, values[1], 2), false); }); - test('should work with ' + key + ' and a `fromIndex` >= `collection.length`', 12, function() { + QUnit.test('should work with ' + key + ' and a `fromIndex` >= `collection.length`', function(assert) { + assert.expect(12); + _.each([4, 6, Math.pow(2, 32), Infinity], function(fromIndex) { - strictEqual(_.includes(collection, 1, fromIndex), false); - strictEqual(_.includes(collection, undefined, fromIndex), false); - strictEqual(_.includes(collection, '', fromIndex), (isStr && fromIndex == length)); + assert.strictEqual(_.includes(collection, 1, fromIndex), false); + assert.strictEqual(_.includes(collection, undefined, fromIndex), false); + assert.strictEqual(_.includes(collection, '', fromIndex), (isStr && fromIndex == length)); }); }); - test('should work with ' + key + ' and treat falsey `fromIndex` values as `0`', 1, function() { + QUnit.test('should work with ' + key + ' and treat falsey `fromIndex` values as `0`', function(assert) { + assert.expect(1); + var expected = _.map(falsey, _.constant(true)); var actual = _.map(falsey, function(fromIndex) { return _.includes(collection, values[0], fromIndex); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work with ' + key + ' and coerce non-integer `fromIndex` values to integers', 3, function() { - strictEqual(_.includes(collection, values[0], '1'), false); - strictEqual(_.includes(collection, values[0], 0.1), true); - strictEqual(_.includes(collection, values[0], NaN), true); + QUnit.test('should work with ' + key + ' and coerce non-integer `fromIndex` values to integers', function(assert) { + assert.expect(3); + + assert.strictEqual(_.includes(collection, values[0], '1'), false); + assert.strictEqual(_.includes(collection, values[0], 0.1), true); + assert.strictEqual(_.includes(collection, values[0], NaN), true); }); - test('should work with ' + key + ' and a negative `fromIndex`', 2, function() { - strictEqual(_.includes(collection, values[2], -2), true); - strictEqual(_.includes(collection, values[1], -2), false); + QUnit.test('should work with ' + key + ' and a negative `fromIndex`', function(assert) { + assert.expect(2); + + assert.strictEqual(_.includes(collection, values[2], -2), true); + assert.strictEqual(_.includes(collection, values[1], -2), false); }); - test('should work with ' + key + ' and a negative `fromIndex` <= negative `collection.length`', 3, function() { + QUnit.test('should work with ' + key + ' and a negative `fromIndex` <= negative `collection.length`', function(assert) { + assert.expect(3); + _.each([-4, -6, -Infinity], function(fromIndex) { - strictEqual(_.includes(collection, values[0], fromIndex), true); + assert.strictEqual(_.includes(collection, values[0], fromIndex), true); }); }); - test('should work with ' + key + ' and floor `position` values', 1, function() { - strictEqual(_.includes(collection, 2, 1.2), true); + QUnit.test('should work with ' + key + ' and floor `position` values', function(assert) { + assert.expect(1); + + assert.strictEqual(_.includes(collection, 2, 1.2), true); }); - test('should work with ' + key + ' and return an unwrapped value implicitly when chaining', 1, function() { + QUnit.test('should work with ' + key + ' and return an unwrapped value implicitly when chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - strictEqual(_(collection).includes(3), true); + assert.strictEqual(_(collection).includes(3), true); } else { - skipTest(); + skipTest(assert); } }); - test('should work with ' + key + ' and return a wrapped value when explicitly chaining', 1, function() { + QUnit.test('should work with ' + key + ' and return a wrapped value when explicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - ok(_(collection).chain().includes(3) instanceof _); + assert.ok(_(collection).chain().includes(3) instanceof _); } else { - skipTest(); + skipTest(assert); } }); }); @@ -5560,13 +6321,17 @@ 'object': Object('abc') }, function(collection, key) { - test('should work with a string ' + key + ' for `collection`', 2, function() { - strictEqual(_.includes(collection, 'bc'), true); - strictEqual(_.includes(collection, 'd'), false); + QUnit.test('should work with a string ' + key + ' for `collection`', function(assert) { + assert.expect(2); + + assert.strictEqual(_.includes(collection, 'bc'), true); + assert.strictEqual(_.includes(collection, 'd'), false); }); }); - test('should return `false` for empty collections', 1, function() { + QUnit.test('should return `false` for empty collections', function(assert) { + assert.expect(1); + var expected = _.map(empties, _.constant(false)); var actual = _.map(empties, function(value) { @@ -5575,23 +6340,29 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should match `NaN`', 1, function() { - strictEqual(_.includes([1, NaN, 3], NaN), true); + QUnit.test('should match `NaN`', function(assert) { + assert.expect(1); + + assert.strictEqual(_.includes([1, NaN, 3], NaN), true); }); - test('should match `-0` as `0`', 2, function() { - strictEqual(_.includes([-0], 0), true); - strictEqual(_.includes([0], -0), true); + QUnit.test('should match `-0` as `0`', function(assert) { + assert.expect(2); + + assert.strictEqual(_.includes([-0], 0), true); + assert.strictEqual(_.includes([0], -0), true); }); - test('should work as an iteratee for methods like `_.reduce`', 1, function() { + QUnit.test('should work as an iteratee for methods like `_.reduce`', function(assert) { + assert.expect(1); + var array1 = [1, 2, 3], array2 = [2, 3, 1]; - ok(_.every(array1, _.partial(_.includes, array2))); + assert.ok(_.every(array1, _.partial(_.includes, array2))); }); }(1, 2, 3, 4)); @@ -5602,15 +6373,21 @@ (function() { var array = [1, 2, 3, 1, 2, 3]; - test('should return the index of the first matched value', 1, function() { - strictEqual(_.indexOf(array, 3), 2); + QUnit.test('should return the index of the first matched value', function(assert) { + assert.expect(1); + + assert.strictEqual(_.indexOf(array, 3), 2); }); - test('should work with a positive `fromIndex`', 1, function() { - strictEqual(_.indexOf(array, 1, 2), 3); + QUnit.test('should work with a positive `fromIndex`', function(assert) { + assert.expect(1); + + assert.strictEqual(_.indexOf(array, 1, 2), 3); }); - test('should work with `fromIndex` >= `array.length`', 1, function() { + QUnit.test('should work with `fromIndex` >= `array.length`', function(assert) { + assert.expect(1); + var values = [6, 8, Math.pow(2, 32), Infinity], expected = _.map(values, _.constant([-1, -1, -1])); @@ -5622,14 +6399,18 @@ ]; }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work with a negative `fromIndex`', 1, function() { - strictEqual(_.indexOf(array, 2, -3), 4); + QUnit.test('should work with a negative `fromIndex`', function(assert) { + assert.expect(1); + + assert.strictEqual(_.indexOf(array, 2, -3), 4); }); - test('should work with a negative `fromIndex` <= `-array.length`', 1, function() { + QUnit.test('should work with a negative `fromIndex` <= `-array.length`', function(assert) { + assert.expect(1); + var values = [-6, -8, -Infinity], expected = _.map(values, _.constant(0)); @@ -5637,21 +6418,25 @@ return _.indexOf(array, 1, fromIndex); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should treat falsey `fromIndex` values as `0`', 1, function() { + QUnit.test('should treat falsey `fromIndex` values as `0`', function(assert) { + assert.expect(1); + var expected = _.map(falsey, _.constant(0)); var actual = _.map(falsey, function(fromIndex) { return _.indexOf(array, 1, fromIndex); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should coerce `fromIndex` to an integer', 1, function() { - strictEqual(_.indexOf(array, 2, 1.2), 1); + QUnit.test('should coerce `fromIndex` to an integer', function(assert) { + assert.expect(1); + + assert.strictEqual(_.indexOf(array, 2, 1.2), 1); }); }()); @@ -5683,87 +6468,101 @@ return new Foo; }); - test('`_.includes` should work with a custom `_.indexOf` method', 2, function() { + QUnit.test('`_.includes` should work with a custom `_.indexOf` method', function(assert) { + assert.expect(2); + if (!isModularize) { _.indexOf = custom; - ok(_.includes(array, new Foo)); - ok(_.includes({ 'a': 1, 'b': new Foo, 'c': 3 }, new Foo)); + assert.ok(_.includes(array, new Foo)); + assert.ok(_.includes({ 'a': 1, 'b': new Foo, 'c': 3 }, new Foo)); _.indexOf = indexOf; } else { - skipTest(2); + skipTest(assert, 2); } }); - test('`_.difference` should work with a custom `_.indexOf` method', 2, function() { + QUnit.test('`_.difference` should work with a custom `_.indexOf` method', function(assert) { + assert.expect(2); + if (!isModularize) { _.indexOf = custom; - deepEqual(_.difference(array, [new Foo]), [1, 3]); - deepEqual(_.difference(array, largeArray), [1, 3]); + assert.deepEqual(_.difference(array, [new Foo]), [1, 3]); + assert.deepEqual(_.difference(array, largeArray), [1, 3]); _.indexOf = indexOf; } else { - skipTest(2); + skipTest(assert, 2); } }); - test('`_.intersection` should work with a custom `_.indexOf` method', 2, function() { + QUnit.test('`_.intersection` should work with a custom `_.indexOf` method', function(assert) { + assert.expect(2); + if (!isModularize) { _.indexOf = custom; - deepEqual(_.intersection(array, [new Foo]), [array[1]]); - deepEqual(_.intersection(largeArray, [new Foo]), [array[1]]); + assert.deepEqual(_.intersection(array, [new Foo]), [array[1]]); + assert.deepEqual(_.intersection(largeArray, [new Foo]), [array[1]]); _.indexOf = indexOf; } else { - skipTest(2); + skipTest(assert, 2); } }); - test('`_.uniq` should work with a custom `_.indexOf` method', 2, function() { + QUnit.test('`_.uniq` should work with a custom `_.indexOf` method', function(assert) { + assert.expect(2); + if (!isModularize) { _.indexOf = custom; - deepEqual(_.uniq(array), array.slice(0, 3)); - deepEqual(_.uniq(largeArray), [largeArray[0]]); + assert.deepEqual(_.uniq(array), array.slice(0, 3)); + assert.deepEqual(_.uniq(largeArray), [largeArray[0]]); _.indexOf = indexOf; } else { - skipTest(2); + skipTest(assert, 2); } }); - test('`_.uniqBy` should work with a custom `_.indexOf` method', 2, function() { + QUnit.test('`_.uniqBy` should work with a custom `_.indexOf` method', function(assert) { + assert.expect(2); + if (!isModularize) { _.indexOf = custom; - deepEqual(_.uniqBy(array, _.identity), array.slice(0, 3)); - deepEqual(_.uniqBy(largeArray, _.identity), [largeArray[0]]); + assert.deepEqual(_.uniqBy(array, _.identity), array.slice(0, 3)); + assert.deepEqual(_.uniqBy(largeArray, _.identity), [largeArray[0]]); _.indexOf = indexOf; } else { - skipTest(2); + skipTest(assert, 2); } }); - test('`_.sortedUniq` should work with a custom `_.indexOf` method', 2, function() { + QUnit.test('`_.sortedUniq` should work with a custom `_.indexOf` method', function(assert) { + assert.expect(2); + if (!isModularize) { _.indexOf = custom; - deepEqual(_.sortedUniq(sorted), sorted.slice(0, 3)); - deepEqual(_.sortedUniq(largeArray), [largeArray[0]]); + assert.deepEqual(_.sortedUniq(sorted), sorted.slice(0, 3)); + assert.deepEqual(_.sortedUniq(largeArray), [largeArray[0]]); _.indexOf = indexOf; } else { - skipTest(2); + skipTest(assert, 2); } }); - test('`_.sortedUniqBy` should work with a custom `_.indexOf` method', 2, function() { + QUnit.test('`_.sortedUniqBy` should work with a custom `_.indexOf` method', function(assert) { + assert.expect(2); + if (!isModularize) { _.indexOf = custom; - deepEqual(_.sortedUniqBy(sorted, _.identity), sorted.slice(0, 3)); - deepEqual(_.sortedUniqBy(largeArray, _.identity), [largeArray[0]]); + assert.deepEqual(_.sortedUniqBy(sorted, _.identity), sorted.slice(0, 3)); + assert.deepEqual(_.sortedUniqBy(largeArray, _.identity), [largeArray[0]]); _.indexOf = indexOf; } else { - skipTest(2); + skipTest(assert, 2); } }); }()); @@ -5775,7 +6574,9 @@ (function() { var array = [1, 2, 3]; - test('should accept a falsey `array` argument', 1, function() { + 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) { @@ -5784,25 +6585,33 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should exclude last element', 1, function() { - deepEqual(_.initial(array), [1, 2]); + QUnit.test('should exclude last element', function(assert) { + assert.expect(1); + + assert.deepEqual(_.initial(array), [1, 2]); }); - test('should return an empty when querying empty arrays', 1, function() { - deepEqual(_.initial([]), []); + QUnit.test('should return an empty when querying empty arrays', function(assert) { + assert.expect(1); + + assert.deepEqual(_.initial([]), []); }); - test('should work as an iteratee for methods like `_.map`', 1, function() { + 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, _.initial); - deepEqual(actual, [[1, 2], [4, 5], [7, 8]]); + assert.deepEqual(actual, [[1, 2], [4, 5], [7, 8]]); }); - test('should work in a lazy chain sequence', 4, function() { + QUnit.test('should work in a lazy chain sequence', function(assert) { + assert.expect(4); + if (!isNpm) { var array = _.range(LARGE_ARRAY_SIZE), values = []; @@ -5813,8 +6622,8 @@ }) .value(); - deepEqual(actual, []); - deepEqual(values, _.initial(array)); + assert.deepEqual(actual, []); + assert.deepEqual(values, _.initial(array)); values = []; @@ -5825,11 +6634,11 @@ .initial() .value(); - deepEqual(actual, _.initial(_.filter(array, isEven))); - deepEqual(values, array); + assert.deepEqual(actual, _.initial(_.filter(array, isEven))); + assert.deepEqual(values, array); } else { - skipTest(4); + skipTest(assert, 4); } }); }()); @@ -5839,47 +6648,59 @@ QUnit.module('lodash.inRange'); (function() { - test('should work with an `end` argument', 3, function() { - strictEqual(_.inRange(3, 5), true); - strictEqual(_.inRange(5, 5), false); - strictEqual(_.inRange(6, 5), false); + QUnit.test('should work with an `end` argument', function(assert) { + assert.expect(3); + + assert.strictEqual(_.inRange(3, 5), true); + assert.strictEqual(_.inRange(5, 5), false); + assert.strictEqual(_.inRange(6, 5), false); }); - test('should work with `start` and `end` arguments', 4, function() { - strictEqual(_.inRange(1, 1, 5), true); - strictEqual(_.inRange(3, 1, 5), true); - strictEqual(_.inRange(0, 1, 5), false); - strictEqual(_.inRange(5, 1, 5), false); + QUnit.test('should work with `start` and `end` arguments', function(assert) { + assert.expect(4); + + assert.strictEqual(_.inRange(1, 1, 5), true); + assert.strictEqual(_.inRange(3, 1, 5), true); + assert.strictEqual(_.inRange(0, 1, 5), false); + assert.strictEqual(_.inRange(5, 1, 5), false); }); - test('should treat falsey `start` arguments as `0`', 13, function() { + QUnit.test('should treat falsey `start` arguments as `0`', function(assert) { + assert.expect(13); + _.each(falsey, function(value, index) { if (index) { - strictEqual(_.inRange(0, value), false); - strictEqual(_.inRange(0, value, 1), true); + assert.strictEqual(_.inRange(0, value), false); + assert.strictEqual(_.inRange(0, value, 1), true); } else { - strictEqual(_.inRange(0), false); + assert.strictEqual(_.inRange(0), false); } }); }); - test('should swap `start` and `end` when `start` is greater than `end`', 2, function() { - strictEqual(_.inRange(2, 5, 1), true); - strictEqual(_.inRange(-3, -2, -6), true); + QUnit.test('should swap `start` and `end` when `start` is greater than `end`', function(assert) { + assert.expect(2); + + assert.strictEqual(_.inRange(2, 5, 1), true); + assert.strictEqual(_.inRange(-3, -2, -6), true); }); - test('should work with a floating point `n` value', 4, function() { - strictEqual(_.inRange(0.5, 5), true); - strictEqual(_.inRange(1.2, 1, 5), true); - strictEqual(_.inRange(5.2, 5), false); - strictEqual(_.inRange(0.5, 1, 5), false); + QUnit.test('should work with a floating point `n` value', function(assert) { + assert.expect(4); + + assert.strictEqual(_.inRange(0.5, 5), true); + assert.strictEqual(_.inRange(1.2, 1, 5), true); + assert.strictEqual(_.inRange(5.2, 5), false); + assert.strictEqual(_.inRange(0.5, 1, 5), false); }); - test('should coerce arguments to finite numbers', 1, function() { + QUnit.test('should coerce arguments to finite numbers', function(assert) { + assert.expect(1); + var actual = [_.inRange(0, '0', 1), _.inRange(0, '1'), _.inRange(0, 0, '1'), _.inRange(0, NaN, 1), _.inRange(-1, -1, NaN)], expected = _.map(actual, _.constant(true)); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }()); @@ -5890,64 +6711,82 @@ (function() { var args = arguments; - test('should return the intersection of the given arrays', 1, function() { + QUnit.test('should return the intersection of the given arrays', function(assert) { + assert.expect(1); + var actual = _.intersection([1, 3, 2], [5, 2, 1, 4], [2, 1]); - deepEqual(actual, [1, 2]); + assert.deepEqual(actual, [1, 2]); }); - test('should return an array of unique values', 1, function() { + QUnit.test('should return an array of unique values', function(assert) { + assert.expect(1); + var actual = _.intersection([1, 1, 3, 2, 2], [5, 2, 2, 1, 4], [2, 1, 1]); - deepEqual(actual, [1, 2]); + assert.deepEqual(actual, [1, 2]); }); - test('should match `NaN`', 1, function() { + QUnit.test('should match `NaN`', function(assert) { + assert.expect(1); + var actual = _.intersection([1, NaN, 3], [NaN, 5, NaN]); - deepEqual(actual, [NaN]); + assert.deepEqual(actual, [NaN]); }); - test('should work with large arrays of objects', 2, function() { + QUnit.test('should work with large arrays of objects', function(assert) { + assert.expect(2); + var object = {}, largeArray = _.times(LARGE_ARRAY_SIZE, _.constant(object)); - deepEqual(_.intersection([object], largeArray), [object]); - deepEqual(_.intersection(_.range(LARGE_ARRAY_SIZE), [1]), [1]); + assert.deepEqual(_.intersection([object], largeArray), [object]); + assert.deepEqual(_.intersection(_.range(LARGE_ARRAY_SIZE), [1]), [1]); }); - test('should work with large arrays of `NaN`', 1, function() { + QUnit.test('should work with large arrays of `NaN`', function(assert) { + assert.expect(1); + var largeArray = _.times(LARGE_ARRAY_SIZE, _.constant(NaN)); - deepEqual(_.intersection([1, NaN, 3], largeArray), [NaN]); + assert.deepEqual(_.intersection([1, NaN, 3], largeArray), [NaN]); }); - test('should work with `arguments` objects', 2, function() { + QUnit.test('should work with `arguments` objects', function(assert) { + assert.expect(2); + var array = [0, 1, null, 3], expected = [1, 3]; - deepEqual(_.intersection(array, args), expected); - deepEqual(_.intersection(args, array), expected); + assert.deepEqual(_.intersection(array, args), expected); + assert.deepEqual(_.intersection(args, array), expected); }); - test('should work with a single array', 1, function() { + QUnit.test('should work with a single array', function(assert) { + assert.expect(1); + var actual = _.intersection([1, 1, 3, 2, 2]); - deepEqual(actual, [1, 3, 2]); + assert.deepEqual(actual, [1, 3, 2]); }); - test('should treat values that are not arrays or `arguments` objects as empty', 3, function() { + QUnit.test('should treat values that are not arrays or `arguments` objects as empty', function(assert) { + assert.expect(3); + var array = [0, 1, null, 3], values = [3, null, { '0': 1 }]; _.each(values, function(value) { - deepEqual(_.intersection(array, value), []); + assert.deepEqual(_.intersection(array, value), []); }); }); - test('should return a wrapped value when chaining', 2, function() { + QUnit.test('should return a wrapped value when chaining', function(assert) { + assert.expect(2); + if (!isNpm) { var wrapped = _([1, 3, 2]).intersection([5, 2, 1, 4]); - ok(wrapped instanceof _); - deepEqual(wrapped.value(), [1, 2]); + assert.ok(wrapped instanceof _); + assert.deepEqual(wrapped.value(), [1, 2]); } else { - skipTest(2); + skipTest(assert, 2); } }); }(1, 2, 3)); @@ -5957,32 +6796,42 @@ QUnit.module('lodash.invert'); (function() { - test('should invert an object', 2, function() { + QUnit.test('should invert an object', function(assert) { + assert.expect(2); + var object = { 'a': 1, 'b': 2 }, actual = _.invert(object); - deepEqual(actual, { '1': 'a', '2': 'b' }); - deepEqual(_.invert(actual), { 'a': '1', 'b': '2' }); + assert.deepEqual(actual, { '1': 'a', '2': 'b' }); + assert.deepEqual(_.invert(actual), { 'a': '1', 'b': '2' }); }); - test('should work with an object that has a `length` property', 1, function() { + QUnit.test('should work with an object that has a `length` property', function(assert) { + assert.expect(1); + var object = { '0': 'a', '1': 'b', 'length': 2 }; - deepEqual(_.invert(object), { 'a': '0', 'b': '1', '2': 'length' }); + assert.deepEqual(_.invert(object), { 'a': '0', 'b': '1', '2': 'length' }); }); - test('should accept a `multiValue` flag', 1, function() { + QUnit.test('should accept a `multiValue` flag', function(assert) { + assert.expect(1); + var object = { 'a': 1, 'b': 2, 'c': 1 }; - deepEqual(_.invert(object, true), { '1': ['a', 'c'], '2': ['b'] }); + assert.deepEqual(_.invert(object, true), { '1': ['a', 'c'], '2': ['b'] }); }); - test('should only add multiple values to own, not inherited, properties', 2, function() { + QUnit.test('should only add multiple values to own, not inherited, properties', function(assert) { + assert.expect(2); + var object = { 'a': 'hasOwnProperty', 'b': 'constructor' }; - deepEqual(_.invert(object), { 'hasOwnProperty': 'a', 'constructor': 'b' }); - ok(_.isEqual(_.invert(object, true), { 'hasOwnProperty': ['a'], 'constructor': ['b'] })); + assert.deepEqual(_.invert(object), { 'hasOwnProperty': 'a', 'constructor': 'b' }); + assert.ok(_.isEqual(_.invert(object, true), { 'hasOwnProperty': ['a'], 'constructor': ['b'] })); }); - test('should work as an iteratee for methods like `_.map`', 2, function() { + QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { + assert.expect(2); + var regular = { 'a': 1, 'b': 2, 'c': 1 }, inverted = { '1': 'c', '2': 'b' }; @@ -5992,20 +6841,22 @@ _.each([array, object], function(collection) { var actual = _.map(collection, _.invert); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }); - test('should return a wrapped value when chaining', 2, function() { + QUnit.test('should return a wrapped value when chaining', function(assert) { + assert.expect(2); + if (!isNpm) { var object = { 'a': 1, 'b': 2 }, wrapped = _(object).invert(); - ok(wrapped instanceof _); - deepEqual(wrapped.value(), { '1': 'a', '2': 'b' }); + assert.ok(wrapped instanceof _); + assert.deepEqual(wrapped.value(), { '1': 'a', '2': 'b' }); } else { - skipTest(2); + skipTest(assert, 2); } }); }()); @@ -6015,48 +6866,62 @@ QUnit.module('lodash.invoke'); (function() { - test('should invoke a methods on each element of a collection', 1, function() { + QUnit.test('should invoke a methods on each element of a collection', function(assert) { + assert.expect(1); + var array = ['a', 'b', 'c']; - deepEqual(_.invoke(array, 'toUpperCase'), ['A', 'B', 'C']); + assert.deepEqual(_.invoke(array, 'toUpperCase'), ['A', 'B', 'C']); }); - test('should support invoking with arguments', 1, function() { + QUnit.test('should support invoking with arguments', function(assert) { + assert.expect(1); + var array = [function() { return slice.call(arguments); }], actual = _.invoke(array, 'call', null, 'a', 'b', 'c'); - deepEqual(actual, [['a', 'b', 'c']]); + assert.deepEqual(actual, [['a', 'b', 'c']]); }); - test('should work with a function for `methodName`', 1, function() { + QUnit.test('should work with a function for `methodName`', function(assert) { + assert.expect(1); + var array = ['a', 'b', 'c']; var actual = _.invoke(array, function(left, right) { return left + this.toUpperCase() + right; }, '(', ')'); - deepEqual(actual, ['(A)', '(B)', '(C)']); + assert.deepEqual(actual, ['(A)', '(B)', '(C)']); }); - test('should work with an object for `collection`', 1, function() { + QUnit.test('should work with an object for `collection`', function(assert) { + assert.expect(1); + var object = { 'a': 1, 'b': 2, 'c': 3 }; - deepEqual(_.invoke(object, 'toFixed', 1), ['1.0', '2.0', '3.0']); + assert.deepEqual(_.invoke(object, 'toFixed', 1), ['1.0', '2.0', '3.0']); }); - test('should treat number values for `collection` as empty', 1, function() { - deepEqual(_.invoke(1), []); + QUnit.test('should treat number values for `collection` as empty', function(assert) { + assert.expect(1); + + assert.deepEqual(_.invoke(1), []); }); - test('should not error on nullish elements', 1, function() { + QUnit.test('should not error on nullish elements', function(assert) { + assert.expect(1); + var array = ['a', null, undefined, 'd']; try { var actual = _.invoke(array, 'toUpperCase'); } catch (e) {} - deepEqual(_.invoke(array, 'toUpperCase'), ['A', undefined, undefined, 'D']); + assert.deepEqual(_.invoke(array, 'toUpperCase'), ['A', undefined, undefined, 'D']); }); - test('should not error on elements with missing properties', 1, function() { + QUnit.test('should not error on elements with missing properties', function(assert) { + assert.expect(1); + var objects = _.map([null, undefined, _.constant(1)], function(value) { return { 'a': value }; }); @@ -6067,14 +6932,16 @@ var actual = _.invoke(objects, 'a'); } catch (e) {} - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should invoke deep property methods with the correct `this` binding', 2, function() { + QUnit.test('should invoke deep property methods with the correct `this` binding', function(assert) { + assert.expect(2); + var object = { 'a': { 'b': function() { return this.c; }, 'c': 1 } }; _.each(['a.b', ['a', 'b']], function(path) { - deepEqual(_.invoke([object], path), [1]); + assert.deepEqual(_.invoke([object], path), [1]); }); }); }()); @@ -6087,39 +6954,45 @@ var args = (function() { return arguments; }(1, 2, 3)), strictArgs = (function() { 'use strict'; return arguments; }(1, 2, 3)); - test('should return `true` for `arguments` objects', 2, function() { - strictEqual(_.isArguments(args), true); - strictEqual(_.isArguments(strictArgs), true); + QUnit.test('should return `true` for `arguments` objects', function(assert) { + assert.expect(2); + + assert.strictEqual(_.isArguments(args), true); + assert.strictEqual(_.isArguments(strictArgs), true); }); - test('should return `false` for non `arguments` objects', 12, function() { + QUnit.test('should return `false` for non `arguments` objects', function(assert) { + assert.expect(12); + var expected = _.map(falsey, _.constant(false)); var actual = _.map(falsey, function(value, index) { return index ? _.isArguments(value) : _.isArguments(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); - strictEqual(_.isArguments([1, 2, 3]), false); - strictEqual(_.isArguments(true), false); - strictEqual(_.isArguments(new Date), false); - strictEqual(_.isArguments(new Error), false); - strictEqual(_.isArguments(_), false); - strictEqual(_.isArguments(slice), false); - strictEqual(_.isArguments({ '0': 1, 'callee': _.noop, 'length': 1 }), false); - strictEqual(_.isArguments(1), false); - strictEqual(_.isArguments(NaN), false); - strictEqual(_.isArguments(/x/), false); - strictEqual(_.isArguments('a'), false); + assert.strictEqual(_.isArguments([1, 2, 3]), false); + assert.strictEqual(_.isArguments(true), false); + assert.strictEqual(_.isArguments(new Date), false); + assert.strictEqual(_.isArguments(new Error), false); + assert.strictEqual(_.isArguments(_), false); + assert.strictEqual(_.isArguments(slice), false); + assert.strictEqual(_.isArguments({ '0': 1, 'callee': _.noop, 'length': 1 }), false); + assert.strictEqual(_.isArguments(1), false); + assert.strictEqual(_.isArguments(NaN), false); + assert.strictEqual(_.isArguments(/x/), false); + assert.strictEqual(_.isArguments('a'), false); }); - test('should work with an `arguments` object from another realm', 1, function() { + QUnit.test('should work with an `arguments` object from another realm', function(assert) { + assert.expect(1); + if (_._object) { - strictEqual(_.isArguments(_._arguments), true); + assert.strictEqual(_.isArguments(_._arguments), true); } else { - skipTest(); + skipTest(assert); } }); }()); @@ -6131,38 +7004,44 @@ (function() { var args = arguments; - test('should return `true` for arrays', 1, function() { - strictEqual(_.isArray([1, 2, 3]), true); + QUnit.test('should return `true` for arrays', function(assert) { + assert.expect(1); + + assert.strictEqual(_.isArray([1, 2, 3]), true); }); - test('should return `false` for non-arrays', 12, function() { + QUnit.test('should return `false` for non-arrays', function(assert) { + assert.expect(12); + var expected = _.map(falsey, _.constant(false)); var actual = _.map(falsey, function(value, index) { return index ? _.isArray(value) : _.isArray(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); - strictEqual(_.isArray(args), false); - strictEqual(_.isArray(true), false); - strictEqual(_.isArray(new Date), false); - strictEqual(_.isArray(new Error), false); - strictEqual(_.isArray(_), false); - strictEqual(_.isArray(slice), false); - strictEqual(_.isArray({ '0': 1, 'length': 1 }), false); - strictEqual(_.isArray(1), false); - strictEqual(_.isArray(NaN), false); - strictEqual(_.isArray(/x/), false); - strictEqual(_.isArray('a'), false); + assert.strictEqual(_.isArray(args), false); + assert.strictEqual(_.isArray(true), false); + assert.strictEqual(_.isArray(new Date), false); + assert.strictEqual(_.isArray(new Error), false); + assert.strictEqual(_.isArray(_), false); + assert.strictEqual(_.isArray(slice), false); + assert.strictEqual(_.isArray({ '0': 1, 'length': 1 }), false); + assert.strictEqual(_.isArray(1), false); + assert.strictEqual(_.isArray(NaN), false); + assert.strictEqual(_.isArray(/x/), false); + assert.strictEqual(_.isArray('a'), false); }); - test('should work with an array from another realm', 1, function() { + QUnit.test('should work with an array from another realm', function(assert) { + assert.expect(1); + if (_._object) { - strictEqual(_.isArray(_._array), true); + assert.strictEqual(_.isArray(_._array), true); } else { - skipTest(); + skipTest(assert); } }); }(1, 2, 3)); @@ -6174,44 +7053,50 @@ (function() { var args = arguments; - test('should return `true` for array-like values', 1, function() { + QUnit.test('should return `true` for array-like values', function(assert) { + assert.expect(1); + var values = [args, [1, 2, 3], { '0': 1, 'length': 1 }, 'a'], expected = _.map(values, _.constant(true)), actual = _.map(values, _.isArrayLike); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return `false` for non-arrays', 10, function() { + QUnit.test('should return `false` for non-arrays', function(assert) { + assert.expect(10); + var expected = _.map(falsey, function(value) { return value === ''; }); var actual = _.map(falsey, function(value, index) { return index ? _.isArrayLike(value) : _.isArrayLike(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); - strictEqual(_.isArrayLike(true), false); - strictEqual(_.isArrayLike(new Date), false); - strictEqual(_.isArrayLike(new Error), false); - strictEqual(_.isArrayLike(_), false); - strictEqual(_.isArrayLike(slice), false); - strictEqual(_.isArrayLike(), false); - strictEqual(_.isArrayLike(1), false); - strictEqual(_.isArrayLike(NaN), false); - strictEqual(_.isArrayLike(/x/), false); + assert.strictEqual(_.isArrayLike(true), false); + assert.strictEqual(_.isArrayLike(new Date), false); + assert.strictEqual(_.isArrayLike(new Error), false); + assert.strictEqual(_.isArrayLike(_), false); + assert.strictEqual(_.isArrayLike(slice), false); + assert.strictEqual(_.isArrayLike(), false); + assert.strictEqual(_.isArrayLike(1), false); + assert.strictEqual(_.isArrayLike(NaN), false); + assert.strictEqual(_.isArrayLike(/x/), false); }); - test('should work with an array from another realm', 1, function() { + QUnit.test('should work with an array from another realm', function(assert) { + assert.expect(1); + if (_._object) { var values = [_._arguments, _._array, _._string], expected = _.map(values, _.constant(true)), actual = _.map(values, _.isArrayLike); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); } else { - skipTest(); + skipTest(assert); } }); }(1, 2, 3)); @@ -6223,41 +7108,47 @@ (function() { var args = arguments; - test('should return `true` for booleans', 4, function() { - strictEqual(_.isBoolean(true), true); - strictEqual(_.isBoolean(false), true); - strictEqual(_.isBoolean(Object(true)), true); - strictEqual(_.isBoolean(Object(false)), true); + QUnit.test('should return `true` for booleans', function(assert) { + assert.expect(4); + + assert.strictEqual(_.isBoolean(true), true); + assert.strictEqual(_.isBoolean(false), true); + assert.strictEqual(_.isBoolean(Object(true)), true); + assert.strictEqual(_.isBoolean(Object(false)), true); }); - test('should return `false` for non-booleans', 12, function() { + QUnit.test('should return `false` for non-booleans', function(assert) { + assert.expect(12); + var expected = _.map(falsey, function(value) { return value === false; }); var actual = _.map(falsey, function(value, index) { return index ? _.isBoolean(value) : _.isBoolean(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); - strictEqual(_.isBoolean(args), false); - strictEqual(_.isBoolean([1, 2, 3]), false); - strictEqual(_.isBoolean(new Date), false); - strictEqual(_.isBoolean(new Error), false); - strictEqual(_.isBoolean(_), false); - strictEqual(_.isBoolean(slice), false); - strictEqual(_.isBoolean({ 'a': 1 }), false); - strictEqual(_.isBoolean(1), false); - strictEqual(_.isBoolean(NaN), false); - strictEqual(_.isBoolean(/x/), false); - strictEqual(_.isBoolean('a'), false); + assert.strictEqual(_.isBoolean(args), false); + assert.strictEqual(_.isBoolean([1, 2, 3]), false); + assert.strictEqual(_.isBoolean(new Date), false); + assert.strictEqual(_.isBoolean(new Error), false); + assert.strictEqual(_.isBoolean(_), false); + assert.strictEqual(_.isBoolean(slice), false); + assert.strictEqual(_.isBoolean({ 'a': 1 }), false); + assert.strictEqual(_.isBoolean(1), false); + assert.strictEqual(_.isBoolean(NaN), false); + assert.strictEqual(_.isBoolean(/x/), false); + assert.strictEqual(_.isBoolean('a'), false); }); - test('should work with a boolean from another realm', 1, function() { + QUnit.test('should work with a boolean from another realm', function(assert) { + assert.expect(1); + if (_._object) { - strictEqual(_.isBoolean(_._boolean), true); + assert.strictEqual(_.isBoolean(_._boolean), true); } else { - skipTest(); + skipTest(assert); } }); }(1, 2, 3)); @@ -6269,38 +7160,44 @@ (function() { var args = arguments; - test('should return `true` for dates', 1, function() { - strictEqual(_.isDate(new Date), true); + QUnit.test('should return `true` for dates', function(assert) { + assert.expect(1); + + assert.strictEqual(_.isDate(new Date), true); }); - test('should return `false` for non-dates', 12, function() { + QUnit.test('should return `false` for non-dates', function(assert) { + assert.expect(12); + var expected = _.map(falsey, _.constant(false)); var actual = _.map(falsey, function(value, index) { return index ? _.isDate(value) : _.isDate(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); - strictEqual(_.isDate(args), false); - strictEqual(_.isDate([1, 2, 3]), false); - strictEqual(_.isDate(true), false); - strictEqual(_.isDate(new Error), false); - strictEqual(_.isDate(_), false); - strictEqual(_.isDate(slice), false); - strictEqual(_.isDate({ 'a': 1 }), false); - strictEqual(_.isDate(1), false); - strictEqual(_.isDate(NaN), false); - strictEqual(_.isDate(/x/), false); - strictEqual(_.isDate('a'), false); + assert.strictEqual(_.isDate(args), false); + assert.strictEqual(_.isDate([1, 2, 3]), false); + assert.strictEqual(_.isDate(true), false); + assert.strictEqual(_.isDate(new Error), false); + assert.strictEqual(_.isDate(_), false); + assert.strictEqual(_.isDate(slice), false); + assert.strictEqual(_.isDate({ 'a': 1 }), false); + assert.strictEqual(_.isDate(1), false); + assert.strictEqual(_.isDate(NaN), false); + assert.strictEqual(_.isDate(/x/), false); + assert.strictEqual(_.isDate('a'), false); }); - test('should work with a date object from another realm', 1, function() { + QUnit.test('should work with a date object from another realm', function(assert) { + assert.expect(1); + if (_._object) { - strictEqual(_.isDate(_._date), true); + assert.strictEqual(_.isDate(_._date), true); } else { - skipTest(); + skipTest(assert); } }); }(1, 2, 3)); @@ -6316,47 +7213,53 @@ this.nodeType = 1; } - test('should return `false` for plain objects', 7, function() { + QUnit.test('should return `false` for plain objects', function(assert) { + assert.expect(7); + var element = body || new Element; - strictEqual(_.isElement(element), true); - strictEqual(_.isElement({ 'nodeType': 1 }), false); - strictEqual(_.isElement({ 'nodeType': Object(1) }), false); - strictEqual(_.isElement({ 'nodeType': true }), false); - strictEqual(_.isElement({ 'nodeType': [1] }), false); - strictEqual(_.isElement({ 'nodeType': '1' }), false); - strictEqual(_.isElement({ 'nodeType': '001' }), false); + assert.strictEqual(_.isElement(element), true); + assert.strictEqual(_.isElement({ 'nodeType': 1 }), false); + assert.strictEqual(_.isElement({ 'nodeType': Object(1) }), false); + assert.strictEqual(_.isElement({ 'nodeType': true }), false); + assert.strictEqual(_.isElement({ 'nodeType': [1] }), false); + assert.strictEqual(_.isElement({ 'nodeType': '1' }), false); + assert.strictEqual(_.isElement({ 'nodeType': '001' }), false); }); - test('should return `false` for non DOM elements', 13, function() { + QUnit.test('should return `false` for non DOM elements', function(assert) { + assert.expect(13); + var expected = _.map(falsey, _.constant(false)); var actual = _.map(falsey, function(value, index) { return index ? _.isElement(value) : _.isElement(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); - strictEqual(_.isElement(args), false); - strictEqual(_.isElement([1, 2, 3]), false); - strictEqual(_.isElement(true), false); - strictEqual(_.isElement(new Date), false); - strictEqual(_.isElement(new Error), false); - strictEqual(_.isElement(_), false); - strictEqual(_.isElement(slice), false); - strictEqual(_.isElement({ 'a': 1 }), false); - strictEqual(_.isElement(1), false); - strictEqual(_.isElement(NaN), false); - strictEqual(_.isElement(/x/), false); - strictEqual(_.isElement('a'), false); + assert.strictEqual(_.isElement(args), false); + assert.strictEqual(_.isElement([1, 2, 3]), false); + assert.strictEqual(_.isElement(true), false); + assert.strictEqual(_.isElement(new Date), false); + assert.strictEqual(_.isElement(new Error), false); + assert.strictEqual(_.isElement(_), false); + assert.strictEqual(_.isElement(slice), false); + assert.strictEqual(_.isElement({ 'a': 1 }), false); + assert.strictEqual(_.isElement(1), false); + assert.strictEqual(_.isElement(NaN), false); + assert.strictEqual(_.isElement(/x/), false); + assert.strictEqual(_.isElement('a'), false); }); - test('should work with a DOM element from another realm', 1, function() { + QUnit.test('should work with a DOM element from another realm', function(assert) { + assert.expect(1); + if (_._element) { - strictEqual(_.isElement(_._element), true); + assert.strictEqual(_.isElement(_._element), true); } else { - skipTest(); + skipTest(assert); } }); }(1, 2, 3)); @@ -6368,77 +7271,97 @@ (function() { var args = arguments; - test('should return `true` for empty values', 7, function() { + QUnit.test('should return `true` for empty values', function(assert) { + assert.expect(7); + var expected = _.map(empties, _.constant(true)); var actual = _.map(empties, function(value) { return _.isEmpty(value); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); - strictEqual(_.isEmpty(true), true); - strictEqual(_.isEmpty(slice), true); - strictEqual(_.isEmpty(1), true); - strictEqual(_.isEmpty(NaN), true); - strictEqual(_.isEmpty(/x/), true); - strictEqual(_.isEmpty(), true); + assert.strictEqual(_.isEmpty(true), true); + assert.strictEqual(_.isEmpty(slice), true); + assert.strictEqual(_.isEmpty(1), true); + assert.strictEqual(_.isEmpty(NaN), true); + assert.strictEqual(_.isEmpty(/x/), true); + assert.strictEqual(_.isEmpty(), true); }); - test('should return `false` for non-empty values', 3, function() { - strictEqual(_.isEmpty([0]), false); - strictEqual(_.isEmpty({ 'a': 0 }), false); - strictEqual(_.isEmpty('a'), false); + QUnit.test('should return `false` for non-empty values', function(assert) { + assert.expect(3); + + assert.strictEqual(_.isEmpty([0]), false); + assert.strictEqual(_.isEmpty({ 'a': 0 }), false); + assert.strictEqual(_.isEmpty('a'), false); }); - test('should work with an object that has a `length` property', 1, function() { - strictEqual(_.isEmpty({ 'length': 0 }), false); + QUnit.test('should work with an object that has a `length` property', function(assert) { + assert.expect(1); + + assert.strictEqual(_.isEmpty({ 'length': 0 }), false); }); - test('should work with `arguments` objects', 1, function() { - strictEqual(_.isEmpty(args), false); + QUnit.test('should work with `arguments` objects', function(assert) { + assert.expect(1); + + assert.strictEqual(_.isEmpty(args), false); }); - test('should work with jQuery/MooTools DOM query collections', 1, function() { + QUnit.test('should work with jQuery/MooTools DOM query collections', function(assert) { + assert.expect(1); + function Foo(elements) { push.apply(this, elements); } Foo.prototype = { 'length': 0, 'splice': arrayProto.splice }; - strictEqual(_.isEmpty(new Foo([])), true); + assert.strictEqual(_.isEmpty(new Foo([])), true); }); - test('should not treat objects with negative lengths as array-like', 1, function() { + QUnit.test('should not treat objects with negative lengths as array-like', function(assert) { + assert.expect(1); + function Foo() {} Foo.prototype.length = -1; - strictEqual(_.isEmpty(new Foo), true); + assert.strictEqual(_.isEmpty(new Foo), true); }); - test('should not treat objects with lengths larger than `MAX_SAFE_INTEGER` as array-like', 1, function() { + QUnit.test('should not treat objects with lengths larger than `MAX_SAFE_INTEGER` as array-like', function(assert) { + assert.expect(1); + function Foo() {} Foo.prototype.length = MAX_SAFE_INTEGER + 1; - strictEqual(_.isEmpty(new Foo), true); + assert.strictEqual(_.isEmpty(new Foo), true); }); - test('should not treat objects with non-number lengths as array-like', 1, function() { - strictEqual(_.isEmpty({ 'length': '0' }), false); + QUnit.test('should not treat objects with non-number lengths as array-like', function(assert) { + assert.expect(1); + + assert.strictEqual(_.isEmpty({ 'length': '0' }), false); }); - test('should return an unwrapped value when implicitly chaining', 1, function() { + QUnit.test('should return an unwrapped value when implicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - strictEqual(_({}).isEmpty(), true); + assert.strictEqual(_({}).isEmpty(), true); } else { - skipTest(); + skipTest(assert); } }); - test('should return a wrapped value when explicitly chaining', 1, function() { + QUnit.test('should return a wrapped value when explicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - ok(_({}).chain().isEmpty() instanceof _); + assert.ok(_({}).chain().isEmpty() instanceof _); } else { - skipTest(); + skipTest(assert); } }); }(1, 2, 3)); @@ -6448,7 +7371,9 @@ QUnit.module('lodash.isEqual'); (function() { - test('should compare primitives', 1, function() { + QUnit.test('should compare primitives', function(assert) { + assert.expect(1); + var pairs = [ [1, 1, true], [1, Object(1), true], [1, '1', false], [1, 2, false], [-0, -0, true], [0, 0, true], [0, Object(0), true], [Object(0), Object(0), true], [-0, 0, true], [0, '0', false], [0, null, false], @@ -6468,19 +7393,21 @@ return _.isEqual(pair[0], pair[1]); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should compare arrays', 6, function() { + QUnit.test('should compare arrays', function(assert) { + assert.expect(6); + var array1 = [true, null, 1, 'a', undefined], array2 = [true, null, 1, 'a', undefined]; - strictEqual(_.isEqual(array1, array2), true); + assert.strictEqual(_.isEqual(array1, array2), true); array1 = [[1, 2, 3], new Date(2012, 4, 23), /x/, { 'e': 1 }]; array2 = [[1, 2, 3], new Date(2012, 4, 23), /x/, { 'e': 1 }]; - strictEqual(_.isEqual(array1, array2), true); + assert.strictEqual(_.isEqual(array1, array2), true); array1 = [1]; array1[2] = 3; @@ -6489,25 +7416,27 @@ array2[1] = undefined; array2[2] = 3; - strictEqual(_.isEqual(array1, array2), true); + assert.strictEqual(_.isEqual(array1, array2), true); array1 = [Object(1), false, Object('a'), /x/, new Date(2012, 4, 23), ['a', 'b', [Object('c')]], { 'a': 1 }]; array2 = [1, Object(false), 'a', /x/, new Date(2012, 4, 23), ['a', Object('b'), ['c']], { 'a': 1 }]; - strictEqual(_.isEqual(array1, array2), true); + assert.strictEqual(_.isEqual(array1, array2), true); array1 = [1, 2, 3]; array2 = [3, 2, 1]; - strictEqual(_.isEqual(array1, array2), false); + assert.strictEqual(_.isEqual(array1, array2), false); array1 = [1, 2]; array2 = [1, 2, 3]; - strictEqual(_.isEqual(array1, array2), false); + assert.strictEqual(_.isEqual(array1, array2), false); }); - test('should treat arrays with identical values but different non-index properties as equal', 3, function() { + QUnit.test('should treat arrays with identical values but different non-index properties as equal', function(assert) { + assert.expect(3); + var array1 = [1, 2, 3], array2 = [1, 2, 3]; @@ -6519,7 +7448,7 @@ array2.reverse = array2.shift = array2.slice = array2.sort = array2.splice = array2.unshift = null; - strictEqual(_.isEqual(array1, array2), true); + assert.strictEqual(_.isEqual(array1, array2), true); array1 = [1, 2, 3]; array1.a = 1; @@ -6527,50 +7456,56 @@ array2 = [1, 2, 3]; array2.b = 1; - strictEqual(_.isEqual(array1, array2), true); + assert.strictEqual(_.isEqual(array1, array2), true); array1 = /x/.exec('vwxyz'); array2 = ['x']; - strictEqual(_.isEqual(array1, array2), true); + assert.strictEqual(_.isEqual(array1, array2), true); }); - test('should compare sparse arrays', 3, function() { + QUnit.test('should compare sparse arrays', function(assert) { + assert.expect(3); + var array = Array(1); - strictEqual(_.isEqual(array, Array(1)), true); - strictEqual(_.isEqual(array, [undefined]), true); - strictEqual(_.isEqual(array, Array(2)), false); + assert.strictEqual(_.isEqual(array, Array(1)), true); + assert.strictEqual(_.isEqual(array, [undefined]), true); + assert.strictEqual(_.isEqual(array, Array(2)), false); }); - test('should compare plain objects', 5, function() { + QUnit.test('should compare plain objects', function(assert) { + assert.expect(5); + var object1 = { 'a': true, 'b': null, 'c': 1, 'd': 'a', 'e': undefined }, object2 = { 'a': true, 'b': null, 'c': 1, 'd': 'a', 'e': undefined }; - strictEqual(_.isEqual(object1, object2), true); + assert.strictEqual(_.isEqual(object1, object2), true); object1 = { 'a': [1, 2, 3], 'b': new Date(2012, 4, 23), 'c': /x/, 'd': { 'e': 1 } }; object2 = { 'a': [1, 2, 3], 'b': new Date(2012, 4, 23), 'c': /x/, 'd': { 'e': 1 } }; - strictEqual(_.isEqual(object1, object2), true); + assert.strictEqual(_.isEqual(object1, object2), true); object1 = { 'a': 1, 'b': 2, 'c': 3 }; object2 = { 'a': 3, 'b': 2, 'c': 1 }; - strictEqual(_.isEqual(object1, object2), false); + assert.strictEqual(_.isEqual(object1, object2), false); object1 = { 'a': 1, 'b': 2, 'c': 3 }; object2 = { 'd': 1, 'e': 2, 'f': 3 }; - strictEqual(_.isEqual(object1, object2), false); + assert.strictEqual(_.isEqual(object1, object2), false); object1 = { 'a': 1, 'b': 2 }; object2 = { 'a': 1, 'b': 2, 'c': 3 }; - strictEqual(_.isEqual(object1, object2), false); + assert.strictEqual(_.isEqual(object1, object2), false); }); - test('should compare nested objects', 1, function() { + QUnit.test('should compare nested objects', function(assert) { + assert.expect(1); + var object1 = { 'a': [1, 2, 3], 'b': true, @@ -6599,103 +7534,115 @@ } }; - strictEqual(_.isEqual(object1, object2), true); + assert.strictEqual(_.isEqual(object1, object2), true); }); - test('should compare object instances', 4, function() { + QUnit.test('should compare object instances', function(assert) { + assert.expect(4); + function Foo() { this.a = 1; } Foo.prototype.a = 1; function Bar() { this.a = 1; } Bar.prototype.a = 2; - strictEqual(_.isEqual(new Foo, new Foo), true); - strictEqual(_.isEqual(new Foo, new Bar), false); - strictEqual(_.isEqual({ 'a': 1 }, new Foo), false); - strictEqual(_.isEqual({ 'a': 2 }, new Bar), false); + assert.strictEqual(_.isEqual(new Foo, new Foo), true); + assert.strictEqual(_.isEqual(new Foo, new Bar), false); + assert.strictEqual(_.isEqual({ 'a': 1 }, new Foo), false); + assert.strictEqual(_.isEqual({ 'a': 2 }, new Bar), false); }); - test('should compare objects with constructor properties', 5, function() { - strictEqual(_.isEqual({ 'constructor': 1 }, { 'constructor': 1 }), true); - strictEqual(_.isEqual({ 'constructor': 1 }, { 'constructor': '1' }), false); - strictEqual(_.isEqual({ 'constructor': [1] }, { 'constructor': [1] }), true); - strictEqual(_.isEqual({ 'constructor': [1] }, { 'constructor': ['1'] }), false); - strictEqual(_.isEqual({ 'constructor': Object }, {}), false); + QUnit.test('should compare objects with constructor properties', function(assert) { + assert.expect(5); + + assert.strictEqual(_.isEqual({ 'constructor': 1 }, { 'constructor': 1 }), true); + assert.strictEqual(_.isEqual({ 'constructor': 1 }, { 'constructor': '1' }), false); + assert.strictEqual(_.isEqual({ 'constructor': [1] }, { 'constructor': [1] }), true); + assert.strictEqual(_.isEqual({ 'constructor': [1] }, { 'constructor': ['1'] }), false); + assert.strictEqual(_.isEqual({ 'constructor': Object }, {}), false); }); - test('should compare arrays with circular references', 4, function() { + QUnit.test('should compare arrays with circular references', function(assert) { + assert.expect(4); + var array1 = [], array2 = []; array1.push(array1); array2.push(array2); - strictEqual(_.isEqual(array1, array2), true); + assert.strictEqual(_.isEqual(array1, array2), true); array1.push('b'); array2.push('b'); - strictEqual(_.isEqual(array1, array2), true); + assert.strictEqual(_.isEqual(array1, array2), true); array1.push('c'); array2.push('d'); - strictEqual(_.isEqual(array1, array2), false); + assert.strictEqual(_.isEqual(array1, array2), false); array1 = ['a', 'b', 'c']; array1[1] = array1; array2 = ['a', ['a', 'b', 'c'], 'c']; - strictEqual(_.isEqual(array1, array2), false); + assert.strictEqual(_.isEqual(array1, array2), false); }); - test('should compare objects with circular references', 4, function() { + QUnit.test('should compare objects with circular references', function(assert) { + assert.expect(4); + var object1 = {}, object2 = {}; object1.a = object1; object2.a = object2; - strictEqual(_.isEqual(object1, object2), true); + assert.strictEqual(_.isEqual(object1, object2), true); object1.b = 0; object2.b = Object(0); - strictEqual(_.isEqual(object1, object2), true); + assert.strictEqual(_.isEqual(object1, object2), true); object1.c = Object(1); object2.c = Object(2); - strictEqual(_.isEqual(object1, object2), false); + assert.strictEqual(_.isEqual(object1, object2), false); object1 = { 'a': 1, 'b': 2, 'c': 3 }; object1.b = object1; object2 = { 'a': 1, 'b': { 'a': 1, 'b': 2, 'c': 3 }, 'c': 3 }; - strictEqual(_.isEqual(object1, object2), false); + assert.strictEqual(_.isEqual(object1, object2), false); }); - test('should compare objects with multiple circular references', 3, function() { + QUnit.test('should compare objects with multiple circular references', function(assert) { + assert.expect(3); + var array1 = [{}], array2 = [{}]; (array1[0].a = array1).push(array1); (array2[0].a = array2).push(array2); - strictEqual(_.isEqual(array1, array2), true); + assert.strictEqual(_.isEqual(array1, array2), true); array1[0].b = 0; array2[0].b = Object(0); - strictEqual(_.isEqual(array1, array2), true); + assert.strictEqual(_.isEqual(array1, array2), true); array1[0].c = Object(1); array2[0].c = Object(2); - strictEqual(_.isEqual(array1, array2), false); + assert.strictEqual(_.isEqual(array1, array2), false); }); - test('should compare objects with complex circular references', 1, function() { + QUnit.test('should compare objects with complex circular references', function(assert) { + assert.expect(1); + var object1 = { 'foo': { 'b': { 'c': { 'd': {} } } }, 'bar': { 'a': 2 } @@ -6712,10 +7659,12 @@ object2.foo.b.c.d = object2; object2.bar.b = object2.foo.b; - strictEqual(_.isEqual(object1, object2), true); + assert.strictEqual(_.isEqual(object1, object2), true); }); - test('should compare objects with shared property values', 1, function() { + QUnit.test('should compare objects with shared property values', function(assert) { + assert.expect(1); + var object1 = { 'a': [1, 2] }; @@ -6727,27 +7676,31 @@ object1.b = object1.a; - strictEqual(_.isEqual(object1, object2), true); + assert.strictEqual(_.isEqual(object1, object2), true); }); - test('should treat objects created by `Object.create(null)` like a plain object', 2, function() { + QUnit.test('should treat objects created by `Object.create(null)` like a plain object', function(assert) { + assert.expect(2); + function Foo() { this.a = 1; } Foo.prototype.constructor = null; var object2 = { 'a': 1 }; - strictEqual(_.isEqual(new Foo, object2), false); + assert.strictEqual(_.isEqual(new Foo, object2), false); if (create) { var object1 = create(null); object1.a = 1; - strictEqual(_.isEqual(object1, object2), true); + assert.strictEqual(_.isEqual(object1, object2), true); } else { - skipTest(); + skipTest(assert); } }); - test('should return `false` for objects with custom `toString` methods', 1, function() { + QUnit.test('should return `false` for objects with custom `toString` methods', function(assert) { + assert.expect(1); + var primitive, object = { 'toString': function() { return primitive; } }, values = [true, null, 1, 'a', undefined], @@ -6758,52 +7711,62 @@ return _.isEqual(object, value); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should avoid common type coercions', 9, function() { - strictEqual(_.isEqual(true, Object(false)), false); - strictEqual(_.isEqual(Object(false), Object(0)), false); - strictEqual(_.isEqual(false, Object('')), false); - strictEqual(_.isEqual(Object(36), Object('36')), false); - strictEqual(_.isEqual(0, ''), false); - strictEqual(_.isEqual(1, true), false); - strictEqual(_.isEqual(1337756400000, new Date(2012, 4, 23)), false); - strictEqual(_.isEqual('36', 36), false); - strictEqual(_.isEqual(36, '36'), false); + QUnit.test('should avoid common type coercions', function(assert) { + assert.expect(9); + + assert.strictEqual(_.isEqual(true, Object(false)), false); + assert.strictEqual(_.isEqual(Object(false), Object(0)), false); + assert.strictEqual(_.isEqual(false, Object('')), false); + assert.strictEqual(_.isEqual(Object(36), Object('36')), false); + assert.strictEqual(_.isEqual(0, ''), false); + assert.strictEqual(_.isEqual(1, true), false); + assert.strictEqual(_.isEqual(1337756400000, new Date(2012, 4, 23)), false); + assert.strictEqual(_.isEqual('36', 36), false); + assert.strictEqual(_.isEqual(36, '36'), false); }); - test('should compare `arguments` objects', 2, function() { + QUnit.test('should compare `arguments` objects', function(assert) { + assert.expect(2); + var args1 = (function() { return arguments; }(1, 2, 3)), args2 = (function() { return arguments; }(1, 2, 3)), args3 = (function() { return arguments; }(1, 2)); - strictEqual(_.isEqual(args1, args2), true); - strictEqual(_.isEqual(args1, args3), false); + assert.strictEqual(_.isEqual(args1, args2), true); + assert.strictEqual(_.isEqual(args1, args3), false); }); - test('should treat `arguments` objects like `Object` objects', 4, function() { + QUnit.test('should treat `arguments` objects like `Object` objects', function(assert) { + assert.expect(4); + var args = (function() { return arguments; }(1, 2, 3)), object = { '0': 1, '1': 2, '2': 3 }; function Foo() {} Foo.prototype = object; - strictEqual(_.isEqual(args, object), true); - strictEqual(_.isEqual(object, args), true); + assert.strictEqual(_.isEqual(args, object), true); + assert.strictEqual(_.isEqual(object, args), true); - strictEqual(_.isEqual(args, new Foo), false); - strictEqual(_.isEqual(new Foo, args), false); + assert.strictEqual(_.isEqual(args, new Foo), false); + assert.strictEqual(_.isEqual(new Foo, args), false); }); - test('should compare date objects', 4, function() { - strictEqual(_.isEqual(new Date(2012, 4, 23), new Date(2012, 4, 23)), true); - strictEqual(_.isEqual(new Date(2012, 4, 23), new Date(2013, 3, 25)), false); - strictEqual(_.isEqual(new Date(2012, 4, 23), { 'getTime': _.constant(1337756400000) }), false); - strictEqual(_.isEqual(new Date('a'), new Date('a')), false); + QUnit.test('should compare date objects', function(assert) { + assert.expect(4); + + assert.strictEqual(_.isEqual(new Date(2012, 4, 23), new Date(2012, 4, 23)), true); + assert.strictEqual(_.isEqual(new Date(2012, 4, 23), new Date(2013, 3, 25)), false); + assert.strictEqual(_.isEqual(new Date(2012, 4, 23), { 'getTime': _.constant(1337756400000) }), false); + assert.strictEqual(_.isEqual(new Date('a'), new Date('a')), false); }); - test('should compare error objects', 1, function() { + QUnit.test('should compare error objects', function(assert) { + assert.expect(1); + var pairs = _.map([ 'Error', 'EvalError', @@ -6826,76 +7789,86 @@ return [_.isEqual(pair[0], pair[1]), _.isEqual(pair[0], pair[2]), _.isEqual(pair[2], pair[3])]; }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should compare functions', 2, function() { + QUnit.test('should compare functions', function(assert) { + assert.expect(2); + function a() { return 1 + 2; } function b() { return 1 + 2; } - strictEqual(_.isEqual(a, a), true); - strictEqual(_.isEqual(a, b), false); + assert.strictEqual(_.isEqual(a, a), true); + assert.strictEqual(_.isEqual(a, b), false); }); - test('should compare maps', 4, function() { + QUnit.test('should compare maps', function(assert) { + assert.expect(4); + if (Map) { var map1 = new Map, map2 = new Map; map1.set('a', 1); map2.set('b', 2); - strictEqual(_.isEqual(map1, map2), false); + assert.strictEqual(_.isEqual(map1, map2), false); map1.set('b', 2); map2.set('a', 1); - strictEqual(_.isEqual(map1, map2), true); + assert.strictEqual(_.isEqual(map1, map2), true); map1['delete']('a'); map1.set('a', 1); - strictEqual(_.isEqual(map1, map2), true); + assert.strictEqual(_.isEqual(map1, map2), true); map2['delete']('a'); - strictEqual(_.isEqual(map1, map2), false); + assert.strictEqual(_.isEqual(map1, map2), false); } else { - skipTest(4); + skipTest(assert, 4); } }); - test('should compare regexes', 5, function() { - strictEqual(_.isEqual(/x/gim, /x/gim), true); - strictEqual(_.isEqual(/x/gim, /x/mgi), true); - strictEqual(_.isEqual(/x/gi, /x/g), false); - strictEqual(_.isEqual(/x/, /y/), false); - strictEqual(_.isEqual(/x/g, { 'global': true, 'ignoreCase': false, 'multiline': false, 'source': 'x' }), false); + QUnit.test('should compare regexes', function(assert) { + assert.expect(5); + + assert.strictEqual(_.isEqual(/x/gim, /x/gim), true); + assert.strictEqual(_.isEqual(/x/gim, /x/mgi), true); + assert.strictEqual(_.isEqual(/x/gi, /x/g), false); + assert.strictEqual(_.isEqual(/x/, /y/), false); + assert.strictEqual(_.isEqual(/x/g, { 'global': true, 'ignoreCase': false, 'multiline': false, 'source': 'x' }), false); }); - test('should compare sets', 4, function() { + QUnit.test('should compare sets', function(assert) { + assert.expect(4); + if (Set) { var set1 = new Set, set2 = new Set; set1.add(1); set2.add(2); - strictEqual(_.isEqual(set1, set2), false); + assert.strictEqual(_.isEqual(set1, set2), false); set1.add(2); set2.add(1); - strictEqual(_.isEqual(set1, set2), true); + assert.strictEqual(_.isEqual(set1, set2), true); set1['delete'](1); set1.add(1); - strictEqual(_.isEqual(set1, set2), true); + assert.strictEqual(_.isEqual(set1, set2), true); set2['delete'](1); - strictEqual(_.isEqual(set1, set2), false); + assert.strictEqual(_.isEqual(set1, set2), false); } else { - skipTest(4); + skipTest(assert, 4); } }); - test('should compare typed arrays', 1, function() { + QUnit.test('should compare typed arrays', function(assert) { + assert.expect(1); + var pairs = _.map(typedArrays, function(type, index) { var otherType = typedArrays[(index + 1) % typedArrays.length], CtorA = root[type] || function(n) { this.n = n; }, @@ -6913,43 +7886,51 @@ return [_.isEqual(pair[0], pair[1]), _.isEqual(pair[0], pair[2]), _.isEqual(pair[2], pair[3])]; }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work as an iteratee for `_.every`', 1, function() { + QUnit.test('should work as an iteratee for `_.every`', function(assert) { + assert.expect(1); + var actual = _.every([1, 1, 1], _.partial(_.isEqual, 1)); - ok(actual); + assert.ok(actual); }); - test('should return `true` for like-objects from different documents', 4, function() { + QUnit.test('should return `true` for like-objects from different documents', function(assert) { + assert.expect(4); + if (_._object) { - strictEqual(_.isEqual({ 'a': 1, 'b': 2, 'c': 3 }, _._object), true); - strictEqual(_.isEqual({ 'a': 1, 'b': 2, 'c': 2 }, _._object), false); - strictEqual(_.isEqual([1, 2, 3], _._array), true); - strictEqual(_.isEqual([1, 2, 2], _._array), false); + assert.strictEqual(_.isEqual({ 'a': 1, 'b': 2, 'c': 3 }, _._object), true); + assert.strictEqual(_.isEqual({ 'a': 1, 'b': 2, 'c': 2 }, _._object), false); + assert.strictEqual(_.isEqual([1, 2, 3], _._array), true); + assert.strictEqual(_.isEqual([1, 2, 2], _._array), false); } else { - skipTest(4); + skipTest(assert, 4); } }); - test('should not error on DOM elements', 1, function() { + QUnit.test('should not error on DOM elements', function(assert) { + assert.expect(1); + if (document) { var element1 = document.createElement('div'), element2 = element1.cloneNode(true); try { - strictEqual(_.isEqual(element1, element2), false); + assert.strictEqual(_.isEqual(element1, element2), false); } catch (e) { - ok(false, e.message); + assert.ok(false, e.message); } } else { - skipTest(); + skipTest(assert); } }); - test('should compare wrapped values', 32, function() { + QUnit.test('should compare wrapped values', function(assert) { + assert.expect(32); + var stamp = +new Date; var values = [ @@ -6969,56 +7950,62 @@ wrapped2 = _(vals[1]), actual = wrapped1.isEqual(wrapped2); - strictEqual(actual, true); - strictEqual(_.isEqual(_(actual), _(true)), true); + assert.strictEqual(actual, true); + assert.strictEqual(_.isEqual(_(actual), _(true)), true); wrapped1 = _(vals[0]); wrapped2 = _(vals[2]); actual = wrapped1.isEqual(wrapped2); - strictEqual(actual, false); - strictEqual(_.isEqual(_(actual), _(false)), true); + assert.strictEqual(actual, false); + assert.strictEqual(_.isEqual(_(actual), _(false)), true); } else { - skipTest(4); + skipTest(assert, 4); } }); }); - test('should compare wrapped and non-wrapped values', 4, function() { + QUnit.test('should compare wrapped and non-wrapped values', function(assert) { + assert.expect(4); + if (!isNpm) { var object1 = _({ 'a': 1, 'b': 2 }), object2 = { 'a': 1, 'b': 2 }; - strictEqual(object1.isEqual(object2), true); - strictEqual(_.isEqual(object1, object2), true); + assert.strictEqual(object1.isEqual(object2), true); + assert.strictEqual(_.isEqual(object1, object2), true); object1 = _({ 'a': 1, 'b': 2 }); object2 = { 'a': 1, 'b': 1 }; - strictEqual(object1.isEqual(object2), false); - strictEqual(_.isEqual(object1, object2), false); + assert.strictEqual(object1.isEqual(object2), false); + assert.strictEqual(_.isEqual(object1, object2), false); } else { - skipTest(4); + skipTest(assert, 4); } }); - test('should return an unwrapped value when implicitly chaining', 1, function() { + QUnit.test('should return an unwrapped value when implicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - strictEqual(_('a').isEqual('a'), true); + assert.strictEqual(_('a').isEqual('a'), true); } else { - skipTest(); + skipTest(assert); } }); - test('should return a wrapped value when explicitly chaining', 1, function() { + QUnit.test('should return a wrapped value when explicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - ok(_('a').chain().isEqual('a') instanceof _); + assert.ok(_('a').chain().isEqual('a') instanceof _); } else { - skipTest(); + skipTest(assert); } }); }()); @@ -7028,7 +8015,9 @@ QUnit.module('lodash.isEqualWith'); (function() { - test('should provide the correct `customizer` arguments', 1, function() { + QUnit.test('should provide the correct `customizer` arguments', function(assert) { + assert.expect(1); + var argsList = [], object1 = { 'a': [1, 2], 'b': null }, object2 = { 'a': [1, 2], 'b': null }; @@ -7048,42 +8037,50 @@ [object1.b.b, object2.b.b, 'b', object1.b.b, object2.b.b, [], []] ]; - _.isEqualWith(object1, object2, function() { + _.isEqualWith(object1, object2, function(assert) { argsList.push(slice.call(arguments)); }); - deepEqual(argsList, expected); + assert.deepEqual(argsList, expected); }); - test('should handle comparisons if `customizer` returns `undefined`', 3, function() { - strictEqual(_.isEqualWith('a', 'a', _.noop), true); - strictEqual(_.isEqualWith(['a'], ['a'], _.noop), true); - strictEqual(_.isEqualWith({ '0': 'a' }, { '0': 'a' }, _.noop), true); + QUnit.test('should handle comparisons if `customizer` returns `undefined`', function(assert) { + assert.expect(3); + + assert.strictEqual(_.isEqualWith('a', 'a', _.noop), true); + assert.strictEqual(_.isEqualWith(['a'], ['a'], _.noop), true); + assert.strictEqual(_.isEqualWith({ '0': 'a' }, { '0': 'a' }, _.noop), true); }); - test('should not handle comparisons if `customizer` returns `true`', 3, function() { + QUnit.test('should not handle comparisons if `customizer` returns `true`', function(assert) { + assert.expect(3); + var customizer = function(value) { return _.isString(value) || undefined; }; - strictEqual(_.isEqualWith('a', 'b', customizer), true); - strictEqual(_.isEqualWith(['a'], ['b'], customizer), true); - strictEqual(_.isEqualWith({ '0': 'a' }, { '0': 'b' }, customizer), true); + assert.strictEqual(_.isEqualWith('a', 'b', customizer), true); + assert.strictEqual(_.isEqualWith(['a'], ['b'], customizer), true); + assert.strictEqual(_.isEqualWith({ '0': 'a' }, { '0': 'b' }, customizer), true); }); - test('should not handle comparisons if `customizer` returns `false`', 3, function() { + QUnit.test('should not handle comparisons if `customizer` returns `false`', function(assert) { + assert.expect(3); + var customizer = function(value) { return _.isString(value) ? false : undefined; }; - strictEqual(_.isEqualWith('a', 'a', customizer), false); - strictEqual(_.isEqualWith(['a'], ['a'], customizer), false); - strictEqual(_.isEqualWith({ '0': 'a' }, { '0': 'a' }, customizer), false); + assert.strictEqual(_.isEqualWith('a', 'a', customizer), false); + assert.strictEqual(_.isEqualWith(['a'], ['a'], customizer), false); + assert.strictEqual(_.isEqualWith({ '0': 'a' }, { '0': 'a' }, customizer), false); }); - test('should return a boolean value even if `customizer` does not', 2, function() { + QUnit.test('should return a boolean value even if `customizer` does not', function(assert) { + assert.expect(2); + var actual = _.isEqualWith('a', 'b', _.constant('c')); - strictEqual(actual, true); + assert.strictEqual(actual, true); var values = _.without(falsey, undefined), expected = _.map(values, _.constant(false)); @@ -7093,18 +8090,22 @@ actual.push(_.isEqualWith('a', 'a', _.constant(value))); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should ensure `customizer` is a function', 1, function() { + QUnit.test('should ensure `customizer` is a function', function(assert) { + assert.expect(1); + var array = [1, 2, 3], eq = _.partial(_.isEqualWith, array), actual = _.map([array, [1, 0, 3]], eq); - deepEqual(actual, [true, false]); + assert.deepEqual(actual, [true, false]); }); - test('should call `customizer` for values maps and sets', 2, function() { + QUnit.test('should call `customizer` for values maps and sets', function(assert) { + assert.expect(2); + var value = { 'a': { 'b': 2 } }; if (Map) { @@ -7140,10 +8141,10 @@ argsList.push(slice.call(arguments)); }); - deepEqual(argsList, expected, index ? 'Set' : 'Map'); + assert.deepEqual(argsList, expected, index ? 'Set' : 'Map'); } else { - skipTest(); + skipTest(assert); } }); }); @@ -7156,39 +8157,45 @@ (function() { var args = arguments; - test('should return `true` for error objects', 1, function() { + QUnit.test('should return `true` for error objects', function(assert) { + assert.expect(1); + var expected = _.map(errors, _.constant(true)); var actual = _.map(errors, function(error) { return _.isError(error) === true; }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return `false` for non error objects', 12, function() { + QUnit.test('should return `false` for non error objects', function(assert) { + assert.expect(12); + var expected = _.map(falsey, _.constant(false)); var actual = _.map(falsey, function(value, index) { return index ? _.isError(value) : _.isError(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); - strictEqual(_.isError(args), false); - strictEqual(_.isError([1, 2, 3]), false); - strictEqual(_.isError(true), false); - strictEqual(_.isError(new Date), false); - strictEqual(_.isError(_), false); - strictEqual(_.isError(slice), false); - strictEqual(_.isError({ 'a': 1 }), false); - strictEqual(_.isError(1), false); - strictEqual(_.isError(NaN), false); - strictEqual(_.isError(/x/), false); - strictEqual(_.isError('a'), false); + assert.strictEqual(_.isError(args), false); + assert.strictEqual(_.isError([1, 2, 3]), false); + assert.strictEqual(_.isError(true), false); + assert.strictEqual(_.isError(new Date), false); + assert.strictEqual(_.isError(_), false); + assert.strictEqual(_.isError(slice), false); + assert.strictEqual(_.isError({ 'a': 1 }), false); + assert.strictEqual(_.isError(1), false); + assert.strictEqual(_.isError(NaN), false); + assert.strictEqual(_.isError(/x/), false); + assert.strictEqual(_.isError('a'), false); }); - test('should work with an error object from another realm', 1, function() { + QUnit.test('should work with an error object from another realm', function(assert) { + assert.expect(1); + if (_._object) { var expected = _.map(_._errors, _.constant(true)); @@ -7196,10 +8203,10 @@ return _.isError(error) === true; }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); } else { - skipTest(); + skipTest(assert); } }); }(1, 2, 3)); @@ -7211,7 +8218,9 @@ (function() { var args = arguments; - test('should return `true` for finite values', 1, function() { + QUnit.test('should return `true` for finite values', function(assert) { + assert.expect(1); + var values = [0, 1, 3.14, -1], expected = _.map(values, _.constant(true)); @@ -7219,10 +8228,12 @@ return _.isFinite(value); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return `false` for non-finite values', 9, function() { + QUnit.test('should return `false` for non-finite values', function(assert) { + assert.expect(9); + var values = [NaN, Infinity, -Infinity, Object(1)], expected = _.map(values, _.constant(false)); @@ -7230,19 +8241,21 @@ return _.isFinite(value); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); - strictEqual(_.isFinite(args), false); - strictEqual(_.isFinite([1, 2, 3]), false); - strictEqual(_.isFinite(true), false); - strictEqual(_.isFinite(new Date), false); - strictEqual(_.isFinite(new Error), false); - strictEqual(_.isFinite({ 'a': 1 }), false); - strictEqual(_.isFinite(/x/), false); - strictEqual(_.isFinite('a'), false); + assert.strictEqual(_.isFinite(args), false); + assert.strictEqual(_.isFinite([1, 2, 3]), false); + assert.strictEqual(_.isFinite(true), false); + assert.strictEqual(_.isFinite(new Date), false); + assert.strictEqual(_.isFinite(new Error), false); + assert.strictEqual(_.isFinite({ 'a': 1 }), false); + assert.strictEqual(_.isFinite(/x/), false); + assert.strictEqual(_.isFinite('a'), false); }); - test('should return `false` for non-numeric values', 1, function() { + QUnit.test('should return `false` for non-numeric values', function(assert) { + assert.expect(1); + var values = [undefined, [], true, new Date, new Error, '', ' ', '2px'], expected = _.map(values, _.constant(false)); @@ -7250,10 +8263,12 @@ return _.isFinite(value); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return `false` for numeric string values', 1, function() { + QUnit.test('should return `false` for numeric string values', function(assert) { + assert.expect(1); + var values = ['2', '0', '08'], expected = _.map(values, _.constant(false)); @@ -7261,7 +8276,7 @@ return _.isFinite(value); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }(1, 2, 3)); @@ -7272,12 +8287,16 @@ (function() { var args = arguments; - test('should return `true` for functions', 2, function() { - strictEqual(_.isFunction(_), true); - strictEqual(_.isFunction(slice), true); + QUnit.test('should return `true` for functions', function(assert) { + assert.expect(2); + + assert.strictEqual(_.isFunction(_), true); + assert.strictEqual(_.isFunction(slice), true); }); - test('should return `true` for typed array constructors', 1, function() { + QUnit.test('should return `true` for typed array constructors', function(assert) { + assert.expect(1); + var expected = _.map(typedArrays, function(type) { return objToString.call(root[type]) == funcTag; }); @@ -7286,56 +8305,62 @@ return _.isFunction(root[type]); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return `false` for non-functions', 12, function() { + QUnit.test('should return `false` for non-functions', function(assert) { + assert.expect(12); + var expected = _.map(falsey, _.constant(false)); var actual = _.map(falsey, function(value, index) { return index ? _.isFunction(value) : _.isFunction(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); - strictEqual(_.isFunction(args), false); - strictEqual(_.isFunction([1, 2, 3]), false); - strictEqual(_.isFunction(true), false); - strictEqual(_.isFunction(new Date), false); - strictEqual(_.isFunction(new Error), false); - strictEqual(_.isFunction({ 'a': 1 }), false); - strictEqual(_.isFunction(1), false); - strictEqual(_.isFunction(NaN), false); - strictEqual(_.isFunction(/x/), false); - strictEqual(_.isFunction('a'), false); + assert.strictEqual(_.isFunction(args), false); + assert.strictEqual(_.isFunction([1, 2, 3]), false); + assert.strictEqual(_.isFunction(true), false); + assert.strictEqual(_.isFunction(new Date), false); + assert.strictEqual(_.isFunction(new Error), false); + assert.strictEqual(_.isFunction({ 'a': 1 }), false); + assert.strictEqual(_.isFunction(1), false); + assert.strictEqual(_.isFunction(NaN), false); + assert.strictEqual(_.isFunction(/x/), false); + assert.strictEqual(_.isFunction('a'), false); if (document) { - strictEqual(_.isFunction(document.getElementsByTagName('body')), false); + assert.strictEqual(_.isFunction(document.getElementsByTagName('body')), false); } else { - skipTest(); + skipTest(assert); } }); - test('should work with host objects in IE 8 document mode (test in IE 11)', 2, function() { + QUnit.test('should work with host objects in IE 8 document mode (test in IE 11)', function(assert) { + assert.expect(2); + // Trigger a Chakra JIT bug. // See https://github.com/jashkenas/underscore/issues/1621. _.each([body, xml], function(object) { if (object) { _.times(100, _.isFunction); - strictEqual(_.isFunction(object), false); + assert.strictEqual(_.isFunction(object), false); } else { - skipTest(); + skipTest(assert); } }); }); - test('should work with a function from another realm', 1, function() { + QUnit.test('should work with a function from another realm', function(assert) { + assert.expect(1); + if (_._object) { - strictEqual(_.isFunction(_._function), true); + assert.strictEqual(_.isFunction(_._function), true); } else { - skipTest(); + skipTest(assert); } }); }(1, 2, 3)); @@ -7345,25 +8370,31 @@ QUnit.module('lodash.isMatch'); (function() { - test('should perform a deep comparison between `object` and `source`', 5, function() { + QUnit.test('should perform a deep comparison between `object` and `source`', function(assert) { + assert.expect(5); + var object = { 'a': 1, 'b': 2, 'c': 3 }; - strictEqual(_.isMatch(object, { 'a': 1 }), true); - strictEqual(_.isMatch(object, { 'b': 1 }), false); - strictEqual(_.isMatch(object, { 'a': 1, 'c': 3 }), true); - strictEqual(_.isMatch(object, { 'c': 3, 'd': 4 }), false); + assert.strictEqual(_.isMatch(object, { 'a': 1 }), true); + assert.strictEqual(_.isMatch(object, { 'b': 1 }), false); + assert.strictEqual(_.isMatch(object, { 'a': 1, 'c': 3 }), true); + assert.strictEqual(_.isMatch(object, { 'c': 3, 'd': 4 }), false); object = { 'a': { 'b': { 'c': 1, 'd': 2 }, 'e': 3 }, 'f': 4 }; - strictEqual(_.isMatch(object, { 'a': { 'b': { 'c': 1 } } }), true); + assert.strictEqual(_.isMatch(object, { 'a': { 'b': { 'c': 1 } } }), true); }); - test('should match inherited `object` properties', 1, function() { + QUnit.test('should match inherited `object` properties', function(assert) { + assert.expect(1); + function Foo() { this.a = 1; } Foo.prototype.b = 2; - strictEqual(_.isMatch({ 'a': new Foo }, { 'a': { 'b': 2 } }), true); + assert.strictEqual(_.isMatch({ 'a': new Foo }, { 'a': { 'b': 2 } }), true); }); - test('should not match by inherited `source` properties', 1, function() { + QUnit.test('should not match by inherited `source` properties', function(assert) { + assert.expect(1); + function Foo() { this.a = 1; } Foo.prototype.b = 2; @@ -7375,43 +8406,53 @@ return _.isMatch(object, source); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should compare a variety of `source` property values', 2, function() { + QUnit.test('should compare a variety of `source` property values', function(assert) { + assert.expect(2); + var object1 = { 'a': false, 'b': true, 'c': '3', 'd': 4, 'e': [5], 'f': { 'g': 6 } }, object2 = { 'a': 0, 'b': 1, 'c': 3, 'd': '4', 'e': ['5'], 'f': { 'g': '6' } }; - strictEqual(_.isMatch(object1, object1), true); - strictEqual(_.isMatch(object1, object2), false); + assert.strictEqual(_.isMatch(object1, object1), true); + assert.strictEqual(_.isMatch(object1, object2), false); }); - test('should match `-0` as `0`', 2, function() { + QUnit.test('should match `-0` as `0`', function(assert) { + assert.expect(2); + var object1 = { 'a': -0 }, object2 = { 'a': 0 }; - strictEqual(_.isMatch(object1, object2), true); - strictEqual(_.isMatch(object2, object1), true); + assert.strictEqual(_.isMatch(object1, object2), true); + assert.strictEqual(_.isMatch(object2, object1), true); }); - test('should compare functions by reference', 3, function() { + QUnit.test('should compare functions by reference', function(assert) { + assert.expect(3); + var object1 = { 'a': _.noop }, object2 = { 'a': noop }, object3 = { 'a': {} }; - strictEqual(_.isMatch(object1, object1), true); - strictEqual(_.isMatch(object2, object1), false); - strictEqual(_.isMatch(object3, object1), false); + assert.strictEqual(_.isMatch(object1, object1), true); + assert.strictEqual(_.isMatch(object2, object1), false); + assert.strictEqual(_.isMatch(object3, object1), false); }); - test('should work with a function for `object`', 1, function() { + QUnit.test('should work with a function for `object`', function(assert) { + assert.expect(1); + function Foo() {} Foo.a = { 'b': 1, 'c': 2 }; - strictEqual(_.isMatch(Foo, { 'a': { 'b': 1 } }), true); + assert.strictEqual(_.isMatch(Foo, { 'a': { 'b': 1 } }), true); }); - test('should work with a function for `source`', 1, function() { + QUnit.test('should work with a function for `source`', function(assert) { + assert.expect(1); + function Foo() {} Foo.a = 1; Foo.b = function() {}; @@ -7423,28 +8464,32 @@ return _.isMatch(object, Foo); }); - deepEqual(actual, [false, true]); + assert.deepEqual(actual, [false, true]); }); - test('should partial match arrays', 3, function() { + QUnit.test('should partial match arrays', function(assert) { + assert.expect(3); + var objects = [{ 'a': ['b'] }, { 'a': ['c', 'd'] }], source = { 'a': ['d'] }, predicate = function(object) { return _.isMatch(object, source); }, actual = _.filter(objects, predicate); - deepEqual(actual, [objects[1]]); + assert.deepEqual(actual, [objects[1]]); source = { 'a': ['b', 'd'] }; actual = _.filter(objects, predicate); - deepEqual(actual, []); + assert.deepEqual(actual, []); source = { 'a': ['d', 'b'] }; actual = _.filter(objects, predicate); - deepEqual(actual, []); + assert.deepEqual(actual, []); }); - test('should partial match arrays of objects', 1, function() { + QUnit.test('should partial match arrays of objects', function(assert) { + assert.expect(1); + var source = { 'a': [{ 'b': 1 }, { 'b': 4, 'c': 5 }] }; var objects = [ @@ -7456,10 +8501,12 @@ return _.isMatch(object, source); }); - deepEqual(actual, [objects[0]]); + assert.deepEqual(actual, [objects[0]]); }); - test('should partial match maps', 3, function() { + QUnit.test('should partial match maps', function(assert) { + assert.expect(3); + if (Map) { var objects = [{ 'a': new Map }, { 'a': new Map }]; objects[0].a.set('a', 1); @@ -7473,24 +8520,26 @@ predicate = function(object) { return _.isMatch(object, source); }, actual = _.filter(objects, predicate); - deepEqual(actual, [objects[1]]); + assert.deepEqual(actual, [objects[1]]); map['delete']('b'); actual = _.filter(objects, predicate); - deepEqual(actual, objects); + assert.deepEqual(actual, objects); map.set('c', 3); actual = _.filter(objects, predicate); - deepEqual(actual, []); + assert.deepEqual(actual, []); } else { - skipTest(3); + skipTest(assert, 3); } }); - test('should partial match sets', 3, function() { + QUnit.test('should partial match sets', function(assert) { + assert.expect(3); + if (Set) { var objects = [{ 'a': new Set }, { 'a': new Set }]; objects[0].a.add(1); @@ -7504,76 +8553,84 @@ predicate = function(object) { return _.isMatch(object, source); }, actual = _.filter(objects, predicate); - deepEqual(actual, [objects[1]]); + assert.deepEqual(actual, [objects[1]]); set['delete'](2); actual = _.filter(objects, predicate); - deepEqual(actual, objects); + assert.deepEqual(actual, objects); set.add(3); actual = _.filter(objects, predicate); - deepEqual(actual, []); + assert.deepEqual(actual, []); } else { - skipTest(3); + skipTest(assert, 3); } }); - test('should match properties when `object` is not a plain object', 1, function() { + QUnit.test('should match properties when `object` is not a plain object', function(assert) { + assert.expect(1); + function Foo(object) { _.assign(this, object); } var object = new Foo({ 'a': new Foo({ 'b': 1, 'c': 2 }) }); - strictEqual(_.isMatch(object, { 'a': { 'b': 1 } }), true); + assert.strictEqual(_.isMatch(object, { 'a': { 'b': 1 } }), true); }); - test('should match `undefined` values', 3, function() { + QUnit.test('should match `undefined` values', function(assert) { + assert.expect(3); + var objects = [{ 'a': 1 }, { 'a': 1, 'b': 1 }, { 'a': 1, 'b': undefined }], source = { 'b': undefined }, predicate = function(object) { return _.isMatch(object, source); }, actual = _.map(objects, predicate), expected = [false, false, true]; - deepEqual(actual, expected); + assert.deepEqual(actual, expected); source = { 'a': 1, 'b': undefined }; actual = _.map(objects, predicate); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); objects = [{ 'a': { 'b': 1 } }, { 'a':{ 'b': 1, 'c': 1 } }, { 'a': { 'b': 1, 'c': undefined } }]; source = { 'a': { 'c': undefined } }; actual = _.map(objects, predicate); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should match `undefined` values on primitives', 3, function() { + QUnit.test('should match `undefined` values on primitives', function(assert) { + assert.expect(3); + numberProto.a = 1; numberProto.b = undefined; try { - strictEqual(_.isMatch(1, { 'b': undefined }), true); + assert.strictEqual(_.isMatch(1, { 'b': undefined }), true); } catch (e) { - ok(false, e.message); + assert.ok(false, e.message); } try { - strictEqual(_.isMatch(1, { 'a': 1, 'b': undefined }), true); + assert.strictEqual(_.isMatch(1, { 'a': 1, 'b': undefined }), true); } catch (e) { - ok(false, e.message); + assert.ok(false, e.message); } numberProto.a = { 'b': 1, 'c': undefined }; try { - strictEqual(_.isMatch(1, { 'a': { 'c': undefined } }), true); + assert.strictEqual(_.isMatch(1, { 'a': { 'c': undefined } }), true); } catch (e) { - ok(false, e.message); + assert.ok(false, e.message); } delete numberProto.a; delete numberProto.b; }); - test('should return `false` when `object` is nullish', 1, function() { + QUnit.test('should return `false` when `object` is nullish', function(assert) { + assert.expect(1); + var values = [null, undefined], expected = _.map(values, _.constant(false)), source = { 'a': 1 }; @@ -7584,10 +8641,12 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return `true` when comparing an empty `source` to a nullish `object`', 1, function() { + QUnit.test('should return `true` when comparing an empty `source` to a nullish `object`', function(assert) { + assert.expect(1); + var values = [null, undefined], expected = _.map(values, _.constant(true)), source = {}; @@ -7598,10 +8657,12 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return `true` when comparing an empty `source`', 1, function() { + QUnit.test('should return `true` when comparing an empty `source`', function(assert) { + assert.expect(1); + var object = { 'a': 1 }, expected = _.map(empties, _.constant(true)); @@ -7609,10 +8670,12 @@ return _.isMatch(object, value); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return `true` when comparing a `source` of empty arrays and objects', 1, function() { + QUnit.test('should return `true` when comparing a `source` of empty arrays and objects', function(assert) { + assert.expect(1); + var objects = [{ 'a': [1], 'b': { 'c': 1 } }, { 'a': [2, 3], 'b': { 'd': 2 } }], source = { 'a': [], 'b': {} }; @@ -7620,7 +8683,7 @@ return _.isMatch(object, source); }); - deepEqual(actual, objects); + assert.deepEqual(actual, objects); }); }()); @@ -7629,7 +8692,9 @@ QUnit.module('lodash.isMatchWith'); (function() { - test('should provide the correct `customizer` arguments', 1, function() { + QUnit.test('should provide the correct `customizer` arguments', function(assert) { + assert.expect(1); + var argsList = [], object1 = { 'a': [1, 2], 'b': null }, object2 = { 'a': [1, 2], 'b': null }; @@ -7652,40 +8717,48 @@ [object1.b.b.b, object2.b.b.b, 'b', object1.b.b, object2.b.b, [], []] ]; - _.isMatchWith(object1, object2, function() { + _.isMatchWith(object1, object2, function(assert) { argsList.push(slice.call(arguments)); }); - deepEqual(argsList, expected); + assert.deepEqual(argsList, expected); }); - test('should handle comparisons if `customizer` returns `undefined`', 1, function() { - strictEqual(_.isMatchWith({ 'a': 1 }, { 'a': 1 }, _.noop), true); + QUnit.test('should handle comparisons if `customizer` returns `undefined`', function(assert) { + assert.expect(1); + + assert.strictEqual(_.isMatchWith({ 'a': 1 }, { 'a': 1 }, _.noop), true); }); - test('should not handle comparisons if `customizer` returns `true`', 2, function() { + QUnit.test('should not handle comparisons if `customizer` returns `true`', function(assert) { + assert.expect(2); + var customizer = function(value) { return _.isString(value) || undefined; }; - strictEqual(_.isMatchWith(['a'], ['b'], customizer), true); - strictEqual(_.isMatchWith({ '0': 'a' }, { '0': 'b' }, customizer), true); + assert.strictEqual(_.isMatchWith(['a'], ['b'], customizer), true); + assert.strictEqual(_.isMatchWith({ '0': 'a' }, { '0': 'b' }, customizer), true); }); - test('should not handle comparisons if `customizer` returns `false`', 2, function() { + QUnit.test('should not handle comparisons if `customizer` returns `false`', function(assert) { + assert.expect(2); + var customizer = function(value) { return _.isString(value) ? false : undefined; }; - strictEqual(_.isMatchWith(['a'], ['a'], customizer), false); - strictEqual(_.isMatchWith({ '0': 'a' }, { '0': 'a' }, customizer), false); + assert.strictEqual(_.isMatchWith(['a'], ['a'], customizer), false); + assert.strictEqual(_.isMatchWith({ '0': 'a' }, { '0': 'a' }, customizer), false); }); - test('should return a boolean value even if `customizer` does not', 2, function() { + QUnit.test('should return a boolean value even if `customizer` does not', function(assert) { + assert.expect(2); + var object = { 'a': 1 }, actual = _.isMatchWith(object, { 'a': 1 }, _.constant('a')); - strictEqual(actual, true); + assert.strictEqual(actual, true); var expected = _.map(falsey, _.constant(false)); @@ -7694,18 +8767,22 @@ actual.push(_.isMatchWith(object, { 'a': 2 }, _.constant(value))); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should ensure `customizer` is a function', 1, function() { + QUnit.test('should ensure `customizer` is a function', function(assert) { + assert.expect(1); + var object = { 'a': 1 }, matches = _.partial(_.isMatchWith, object), actual = _.map([object, { 'a': 2 }], matches); - deepEqual(actual, [true, false]); + assert.deepEqual(actual, [true, false]); }); - test('should call `customizer` for values maps and sets', 2, function() { + QUnit.test('should call `customizer` for values maps and sets', function(assert) { + assert.expect(2); + var value = { 'a': { 'b': 2 } }; if (Map) { @@ -7743,10 +8820,10 @@ argsList.push(slice.call(arguments)); }); - deepEqual(argsList, expected, index ? 'Set' : 'Map'); + assert.deepEqual(argsList, expected, index ? 'Set' : 'Map'); } else { - skipTest(); + skipTest(assert); } }); }); @@ -7759,40 +8836,46 @@ (function() { var args = arguments; - test('should return `true` for NaNs', 2, function() { - strictEqual(_.isNaN(NaN), true); - strictEqual(_.isNaN(Object(NaN)), true); + QUnit.test('should return `true` for NaNs', function(assert) { + assert.expect(2); + + assert.strictEqual(_.isNaN(NaN), true); + assert.strictEqual(_.isNaN(Object(NaN)), true); }); - test('should return `false` for non-NaNs', 13, function() { + QUnit.test('should return `false` for non-NaNs', function(assert) { + assert.expect(13); + var expected = _.map(falsey, function(value) { return value !== value; }); var actual = _.map(falsey, function(value, index) { return index ? _.isNaN(value) : _.isNaN(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); - strictEqual(_.isNaN(args), false); - strictEqual(_.isNaN([1, 2, 3]), false); - strictEqual(_.isNaN(true), false); - strictEqual(_.isNaN(new Date), false); - strictEqual(_.isNaN(new Error), false); - strictEqual(_.isNaN(_), false); - strictEqual(_.isNaN(slice), false); - strictEqual(_.isNaN({ 'a': 1 }), false); - strictEqual(_.isNaN(1), false); - strictEqual(_.isNaN(Object(1)), false); - strictEqual(_.isNaN(/x/), false); - strictEqual(_.isNaN('a'), false); + assert.strictEqual(_.isNaN(args), false); + assert.strictEqual(_.isNaN([1, 2, 3]), false); + assert.strictEqual(_.isNaN(true), false); + assert.strictEqual(_.isNaN(new Date), false); + assert.strictEqual(_.isNaN(new Error), false); + assert.strictEqual(_.isNaN(_), false); + assert.strictEqual(_.isNaN(slice), false); + assert.strictEqual(_.isNaN({ 'a': 1 }), false); + assert.strictEqual(_.isNaN(1), false); + assert.strictEqual(_.isNaN(Object(1)), false); + assert.strictEqual(_.isNaN(/x/), false); + assert.strictEqual(_.isNaN('a'), false); }); - test('should work with `NaN` from another realm', 1, function() { + QUnit.test('should work with `NaN` from another realm', function(assert) { + assert.expect(1); + if (_._object) { - strictEqual(_.isNaN(_._nan), true); + assert.strictEqual(_.isNaN(_._nan), true); } else { - skipTest(); + skipTest(assert); } }); }(1, 2, 3)); @@ -7804,58 +8887,64 @@ (function() { var args = arguments; - test('should return `true` for native methods', 6, function() { + QUnit.test('should return `true` for native methods', function(assert) { + assert.expect(6); + _.each([Array, create, root.encodeURI, slice, Uint8Array], function(func) { if (func) { - strictEqual(_.isNative(func), true); + assert.strictEqual(_.isNative(func), true); } else { - skipTest(); + skipTest(assert); } }); if (body) { - strictEqual(_.isNative(body.cloneNode), true); + assert.strictEqual(_.isNative(body.cloneNode), true); } else { - skipTest(); + skipTest(assert); } }); - test('should return `false` for non-native methods', 12, function() { + QUnit.test('should return `false` for non-native methods', function(assert) { + assert.expect(12); + var expected = _.map(falsey, _.constant(false)); var actual = _.map(falsey, function(value, index) { return index ? _.isNative(value) : _.isNative(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); - strictEqual(_.isNative(args), false); - strictEqual(_.isNative([1, 2, 3]), false); - strictEqual(_.isNative(true), false); - strictEqual(_.isNative(new Date), false); - strictEqual(_.isNative(new Error), false); - strictEqual(_.isNative(_), false); - strictEqual(_.isNative({ 'a': 1 }), false); - strictEqual(_.isNative(1), false); - strictEqual(_.isNative(NaN), false); - strictEqual(_.isNative(/x/), false); - strictEqual(_.isNative('a'), false); + assert.strictEqual(_.isNative(args), false); + assert.strictEqual(_.isNative([1, 2, 3]), false); + assert.strictEqual(_.isNative(true), false); + assert.strictEqual(_.isNative(new Date), false); + assert.strictEqual(_.isNative(new Error), false); + assert.strictEqual(_.isNative(_), false); + assert.strictEqual(_.isNative({ 'a': 1 }), false); + assert.strictEqual(_.isNative(1), false); + assert.strictEqual(_.isNative(NaN), false); + assert.strictEqual(_.isNative(/x/), false); + assert.strictEqual(_.isNative('a'), false); }); - test('should work with native functions from another realm', 2, function() { + QUnit.test('should work with native functions from another realm', function(assert) { + assert.expect(2); + if (_._element) { - strictEqual(_.isNative(_._element.cloneNode), true); + assert.strictEqual(_.isNative(_._element.cloneNode), true); } else { - skipTest(); + skipTest(assert); } if (_._object) { - strictEqual(_.isNative(_._object.valueOf), true); + assert.strictEqual(_.isNative(_._object.valueOf), true); } else { - skipTest(); + skipTest(assert); } }); }(1, 2, 3)); @@ -7867,39 +8956,45 @@ (function() { var args = arguments; - test('should return `true` for `null` values', 1, function() { - strictEqual(_.isNull(null), true); + QUnit.test('should return `true` for `null` values', function(assert) { + assert.expect(1); + + assert.strictEqual(_.isNull(null), true); }); - test('should return `false` for non `null` values', 13, function() { + QUnit.test('should return `false` for non `null` values', function(assert) { + assert.expect(13); + var expected = _.map(falsey, function(value) { return value === null; }); var actual = _.map(falsey, function(value, index) { return index ? _.isNull(value) : _.isNull(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); - strictEqual(_.isNull(args), false); - strictEqual(_.isNull([1, 2, 3]), false); - strictEqual(_.isNull(true), false); - strictEqual(_.isNull(new Date), false); - strictEqual(_.isNull(new Error), false); - strictEqual(_.isNull(_), false); - strictEqual(_.isNull(slice), false); - strictEqual(_.isNull({ 'a': 1 }), false); - strictEqual(_.isNull(1), false); - strictEqual(_.isNull(NaN), false); - strictEqual(_.isNull(/x/), false); - strictEqual(_.isNull('a'), false); + assert.strictEqual(_.isNull(args), false); + assert.strictEqual(_.isNull([1, 2, 3]), false); + assert.strictEqual(_.isNull(true), false); + assert.strictEqual(_.isNull(new Date), false); + assert.strictEqual(_.isNull(new Error), false); + assert.strictEqual(_.isNull(_), false); + assert.strictEqual(_.isNull(slice), false); + assert.strictEqual(_.isNull({ 'a': 1 }), false); + assert.strictEqual(_.isNull(1), false); + assert.strictEqual(_.isNull(NaN), false); + assert.strictEqual(_.isNull(/x/), false); + assert.strictEqual(_.isNull('a'), false); }); - test('should work with nulls from another realm', 1, function() { + QUnit.test('should work with nulls from another realm', function(assert) { + assert.expect(1); + if (_._object) { - strictEqual(_.isNull(_._null), true); + assert.strictEqual(_.isNull(_._null), true); } else { - skipTest(); + skipTest(assert); } }); }(1, 2, 3)); @@ -7911,13 +9006,17 @@ (function() { var args = arguments; - test('should return `true` for nullish values', 3, function() { - strictEqual(_.isNil(null), true); - strictEqual(_.isNil(), true); - strictEqual(_.isNil(undefined), true); + QUnit.test('should return `true` for nullish values', function(assert) { + assert.expect(3); + + assert.strictEqual(_.isNil(null), true); + assert.strictEqual(_.isNil(), true); + assert.strictEqual(_.isNil(undefined), true); }); - test('should return `false` for non-nullish values', 13, function() { + QUnit.test('should return `false` for non-nullish values', function(assert) { + assert.expect(13); + var expected = _.map(falsey, function(value) { return value == null; }); @@ -7926,29 +9025,31 @@ return index ? _.isNil(value) : _.isNil(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); - strictEqual(_.isNil(args), false); - strictEqual(_.isNil([1, 2, 3]), false); - strictEqual(_.isNil(true), false); - strictEqual(_.isNil(new Date), false); - strictEqual(_.isNil(new Error), false); - strictEqual(_.isNil(_), false); - strictEqual(_.isNil(slice), false); - strictEqual(_.isNil({ 'a': 1 }), false); - strictEqual(_.isNil(1), false); - strictEqual(_.isNil(NaN), false); - strictEqual(_.isNil(/x/), false); - strictEqual(_.isNil('a'), false); + assert.strictEqual(_.isNil(args), false); + assert.strictEqual(_.isNil([1, 2, 3]), false); + assert.strictEqual(_.isNil(true), false); + assert.strictEqual(_.isNil(new Date), false); + assert.strictEqual(_.isNil(new Error), false); + assert.strictEqual(_.isNil(_), false); + assert.strictEqual(_.isNil(slice), false); + assert.strictEqual(_.isNil({ 'a': 1 }), false); + assert.strictEqual(_.isNil(1), false); + assert.strictEqual(_.isNil(NaN), false); + assert.strictEqual(_.isNil(/x/), false); + assert.strictEqual(_.isNil('a'), false); }); - test('should work with nulls from another realm', 2, function() { + QUnit.test('should work with nulls from another realm', function(assert) { + assert.expect(2); + if (_._object) { - strictEqual(_.isNil(_._null), true); - strictEqual(_.isNil(_._undefined), true); + assert.strictEqual(_.isNil(_._null), true); + assert.strictEqual(_.isNil(_._undefined), true); } else { - skipTest(2); + skipTest(assert, 2); } }); }(1, 2, 3)); @@ -7960,44 +9061,52 @@ (function() { var args = arguments; - test('should return `true` for numbers', 3, function() { - strictEqual(_.isNumber(0), true); - strictEqual(_.isNumber(Object(0)), true); - strictEqual(_.isNumber(NaN), true); + QUnit.test('should return `true` for numbers', function(assert) { + assert.expect(3); + + assert.strictEqual(_.isNumber(0), true); + assert.strictEqual(_.isNumber(Object(0)), true); + assert.strictEqual(_.isNumber(NaN), true); }); - test('should return `false` for non-numbers', 11, function() { + QUnit.test('should return `false` for non-numbers', function(assert) { + assert.expect(11); + var expected = _.map(falsey, function(value) { return typeof value == 'number'; }); var actual = _.map(falsey, function(value, index) { return index ? _.isNumber(value) : _.isNumber(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); - strictEqual(_.isNumber(args), false); - strictEqual(_.isNumber([1, 2, 3]), false); - strictEqual(_.isNumber(true), false); - strictEqual(_.isNumber(new Date), false); - strictEqual(_.isNumber(new Error), false); - strictEqual(_.isNumber(_), false); - strictEqual(_.isNumber(slice), false); - strictEqual(_.isNumber({ 'a': 1 }), false); - strictEqual(_.isNumber(/x/), false); - strictEqual(_.isNumber('a'), false); + assert.strictEqual(_.isNumber(args), false); + assert.strictEqual(_.isNumber([1, 2, 3]), false); + assert.strictEqual(_.isNumber(true), false); + assert.strictEqual(_.isNumber(new Date), false); + assert.strictEqual(_.isNumber(new Error), false); + assert.strictEqual(_.isNumber(_), false); + assert.strictEqual(_.isNumber(slice), false); + assert.strictEqual(_.isNumber({ 'a': 1 }), false); + assert.strictEqual(_.isNumber(/x/), false); + assert.strictEqual(_.isNumber('a'), false); }); - test('should work with numbers from another realm', 1, function() { + QUnit.test('should work with numbers from another realm', function(assert) { + assert.expect(1); + if (_._object) { - strictEqual(_.isNumber(_._number), true); + assert.strictEqual(_.isNumber(_._number), true); } else { - skipTest(); + skipTest(assert); } }); - test('should avoid `[xpconnect wrapped native prototype]` in Firefox', 1, function() { - strictEqual(_.isNumber(+'2'), true); + QUnit.test('should avoid `[xpconnect wrapped native prototype]` in Firefox', function(assert) { + assert.expect(1); + + assert.strictEqual(_.isNumber(+'2'), true); }); }(1, 2, 3)); @@ -8008,27 +9117,31 @@ (function() { var args = arguments; - test('should return `true` for objects', 12, function() { - strictEqual(_.isObject(args), true); - strictEqual(_.isObject([1, 2, 3]), true); - strictEqual(_.isObject(Object(false)), true); - strictEqual(_.isObject(new Date), true); - strictEqual(_.isObject(new Error), true); - strictEqual(_.isObject(_), true); - strictEqual(_.isObject(slice), true); - strictEqual(_.isObject({ 'a': 1 }), true); - strictEqual(_.isObject(Object(0)), true); - strictEqual(_.isObject(/x/), true); - strictEqual(_.isObject(Object('a')), true); + QUnit.test('should return `true` for objects', function(assert) { + assert.expect(12); + + assert.strictEqual(_.isObject(args), true); + assert.strictEqual(_.isObject([1, 2, 3]), true); + assert.strictEqual(_.isObject(Object(false)), true); + assert.strictEqual(_.isObject(new Date), true); + assert.strictEqual(_.isObject(new Error), true); + assert.strictEqual(_.isObject(_), true); + assert.strictEqual(_.isObject(slice), true); + assert.strictEqual(_.isObject({ 'a': 1 }), true); + assert.strictEqual(_.isObject(Object(0)), true); + assert.strictEqual(_.isObject(/x/), true); + assert.strictEqual(_.isObject(Object('a')), true); if (document) { - strictEqual(_.isObject(body), true); + assert.strictEqual(_.isObject(body), true); } else { - skipTest(); + skipTest(assert); } }); - test('should return `false` for non-objects', 1, function() { + QUnit.test('should return `false` for non-objects', function(assert) { + assert.expect(1); + var symbol = (Symbol || noop)(), values = falsey.concat(true, 1, 'a', symbol), expected = _.map(values, _.constant(false)); @@ -8037,31 +9150,35 @@ return index ? _.isObject(value) : _.isObject(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work with objects from another realm', 8, function() { + QUnit.test('should work with objects from another realm', function(assert) { + assert.expect(8); + if (_._element) { - strictEqual(_.isObject(_._element), true); + assert.strictEqual(_.isObject(_._element), true); } else { - skipTest(); + skipTest(assert); } if (_._object) { - strictEqual(_.isObject(_._object), true); - strictEqual(_.isObject(_._boolean), true); - strictEqual(_.isObject(_._date), true); - strictEqual(_.isObject(_._function), true); - strictEqual(_.isObject(_._number), true); - strictEqual(_.isObject(_._regexp), true); - strictEqual(_.isObject(_._string), true); + assert.strictEqual(_.isObject(_._object), true); + assert.strictEqual(_.isObject(_._boolean), true); + assert.strictEqual(_.isObject(_._date), true); + assert.strictEqual(_.isObject(_._function), true); + assert.strictEqual(_.isObject(_._number), true); + assert.strictEqual(_.isObject(_._regexp), true); + assert.strictEqual(_.isObject(_._string), true); } else { - skipTest(7); + skipTest(assert, 7); } }); - test('should avoid V8 bug #2291 (test in Chrome 19-20)', 1, function() { + QUnit.test('should avoid V8 bug #2291 (test in Chrome 19-20)', function(assert) { + assert.expect(1); + // Trigger a V8 JIT bug. // See https://code.google.com/p/v8/issues/detail?id=2291. var object = {}; @@ -8072,7 +9189,7 @@ // 2: Initial check with object, this is the other half of the trigger. _.isObject(object); - strictEqual(_.isObject('x'), false); + assert.strictEqual(_.isObject('x'), false); }); }(1, 2, 3)); @@ -8083,19 +9200,23 @@ (function() { var args = arguments; - test('should return `true` for objects', 9, function() { - strictEqual(_.isObjectLike(args), true); - strictEqual(_.isObjectLike([1, 2, 3]), true); - strictEqual(_.isObjectLike(Object(false)), true); - strictEqual(_.isObjectLike(new Date), true); - strictEqual(_.isObjectLike(new Error), true); - strictEqual(_.isObjectLike({ 'a': 1 }), true); - strictEqual(_.isObjectLike(Object(0)), true); - strictEqual(_.isObjectLike(/x/), true); - strictEqual(_.isObjectLike(Object('a')), true); + QUnit.test('should return `true` for objects', function(assert) { + assert.expect(9); + + assert.strictEqual(_.isObjectLike(args), true); + assert.strictEqual(_.isObjectLike([1, 2, 3]), true); + assert.strictEqual(_.isObjectLike(Object(false)), true); + assert.strictEqual(_.isObjectLike(new Date), true); + assert.strictEqual(_.isObjectLike(new Error), true); + assert.strictEqual(_.isObjectLike({ 'a': 1 }), true); + assert.strictEqual(_.isObjectLike(Object(0)), true); + assert.strictEqual(_.isObjectLike(/x/), true); + assert.strictEqual(_.isObjectLike(Object('a')), true); }); - test('should return `false` for non-objects', 1, function() { + QUnit.test('should return `false` for non-objects', function(assert) { + assert.expect(1); + var symbol = (Symbol || noop)(), values = falsey.concat(true, _, slice, 1, 'a', symbol), expected = _.map(values, _.constant(false)); @@ -8104,20 +9225,22 @@ return index ? _.isObjectLike(value) : _.isObjectLike(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work with objects from another realm', 6, function() { + QUnit.test('should work with objects from another realm', function(assert) { + assert.expect(6); + if (_._object) { - strictEqual(_.isObjectLike(_._object), true); - strictEqual(_.isObjectLike(_._boolean), true); - strictEqual(_.isObjectLike(_._date), true); - strictEqual(_.isObjectLike(_._number), true); - strictEqual(_.isObjectLike(_._regexp), true); - strictEqual(_.isObjectLike(_._string), true); + assert.strictEqual(_.isObjectLike(_._object), true); + assert.strictEqual(_.isObjectLike(_._boolean), true); + assert.strictEqual(_.isObjectLike(_._date), true); + assert.strictEqual(_.isObjectLike(_._number), true); + assert.strictEqual(_.isObjectLike(_._regexp), true); + assert.strictEqual(_.isObjectLike(_._string), true); } else { - skipTest(6); + skipTest(assert, 6); } }); }(1, 2, 3)); @@ -8129,79 +9252,93 @@ (function() { var element = document && document.createElement('div'); - test('should detect plain objects', 5, function() { + QUnit.test('should detect plain objects', function(assert) { + assert.expect(5); + function Foo(a) { this.a = 1; } - strictEqual(_.isPlainObject({}), true); - strictEqual(_.isPlainObject({ 'a': 1 }), true); - strictEqual(_.isPlainObject({ 'constructor': Foo }), true); - strictEqual(_.isPlainObject([1, 2, 3]), false); - strictEqual(_.isPlainObject(new Foo(1)), false); + assert.strictEqual(_.isPlainObject({}), true); + assert.strictEqual(_.isPlainObject({ 'a': 1 }), true); + assert.strictEqual(_.isPlainObject({ 'constructor': Foo }), true); + assert.strictEqual(_.isPlainObject([1, 2, 3]), false); + assert.strictEqual(_.isPlainObject(new Foo(1)), false); }); - test('should return `true` for objects with a `[[Prototype]]` of `null`', 2, function() { + QUnit.test('should return `true` for objects with a `[[Prototype]]` of `null`', function(assert) { + assert.expect(2); + if (create) { var object = create(null); - strictEqual(_.isPlainObject(object), true); + assert.strictEqual(_.isPlainObject(object), true); object.constructor = objectProto.constructor; - strictEqual(_.isPlainObject(object), true); + assert.strictEqual(_.isPlainObject(object), true); } else { - skipTest(2); + skipTest(assert, 2); } }); - test('should return `true` for plain objects with a custom `valueOf` property', 2, function() { - strictEqual(_.isPlainObject({ 'valueOf': 0 }), true); + QUnit.test('should return `true` for plain objects with a custom `valueOf` property', function(assert) { + assert.expect(2); + + assert.strictEqual(_.isPlainObject({ 'valueOf': 0 }), true); if (element) { var valueOf = element.valueOf; element.valueOf = 0; - strictEqual(_.isPlainObject(element), false); + assert.strictEqual(_.isPlainObject(element), false); element.valueOf = valueOf; } else { - skipTest(); + skipTest(assert); } }); - test('should return `false` for DOM elements', 1, function() { + QUnit.test('should return `false` for DOM elements', function(assert) { + assert.expect(1); + if (element) { - strictEqual(_.isPlainObject(element), false); + assert.strictEqual(_.isPlainObject(element), false); } else { - skipTest(); + skipTest(assert); } }); - test('should return `false` for Object objects without a `toStringTag` of "Object"', 3, function() { - strictEqual(_.isPlainObject(arguments), false); - strictEqual(_.isPlainObject(Error), false); - strictEqual(_.isPlainObject(Math), false); + QUnit.test('should return `false` for Object objects without a `toStringTag` of "Object"', function(assert) { + assert.expect(3); + + assert.strictEqual(_.isPlainObject(arguments), false); + assert.strictEqual(_.isPlainObject(Error), false); + assert.strictEqual(_.isPlainObject(Math), false); }); - test('should return `false` for non-objects', 3, function() { + QUnit.test('should return `false` for non-objects', function(assert) { + assert.expect(3); + var expected = _.map(falsey, _.constant(false)); var actual = _.map(falsey, function(value, index) { return index ? _.isPlainObject(value) : _.isPlainObject(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); - strictEqual(_.isPlainObject(true), false); - strictEqual(_.isPlainObject('a'), false); + assert.strictEqual(_.isPlainObject(true), false); + assert.strictEqual(_.isPlainObject('a'), false); }); - test('should work with objects from another realm', 1, function() { + QUnit.test('should work with objects from another realm', function(assert) { + assert.expect(1); + if (_._object) { - strictEqual(_.isPlainObject(_._object), true); + assert.strictEqual(_.isPlainObject(_._object), true); } else { - skipTest(); + skipTest(assert); } }); }()); @@ -8213,39 +9350,45 @@ (function() { var args = arguments; - test('should return `true` for regexes', 2, function() { - strictEqual(_.isRegExp(/x/), true); - strictEqual(_.isRegExp(RegExp('x')), true); + QUnit.test('should return `true` for regexes', function(assert) { + assert.expect(2); + + assert.strictEqual(_.isRegExp(/x/), true); + assert.strictEqual(_.isRegExp(RegExp('x')), true); }); - test('should return `false` for non-regexes', 12, function() { + QUnit.test('should return `false` for non-regexes', function(assert) { + assert.expect(12); + var expected = _.map(falsey, _.constant(false)); var actual = _.map(falsey, function(value, index) { return index ? _.isRegExp(value) : _.isRegExp(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); - strictEqual(_.isRegExp(args), false); - strictEqual(_.isRegExp([1, 2, 3]), false); - strictEqual(_.isRegExp(true), false); - strictEqual(_.isRegExp(new Date), false); - strictEqual(_.isRegExp(new Error), false); - strictEqual(_.isRegExp(_), false); - strictEqual(_.isRegExp(slice), false); - strictEqual(_.isRegExp({ 'a': 1 }), false); - strictEqual(_.isRegExp(1), false); - strictEqual(_.isRegExp(NaN), false); - strictEqual(_.isRegExp('a'), false); + assert.strictEqual(_.isRegExp(args), false); + assert.strictEqual(_.isRegExp([1, 2, 3]), false); + assert.strictEqual(_.isRegExp(true), false); + assert.strictEqual(_.isRegExp(new Date), false); + assert.strictEqual(_.isRegExp(new Error), false); + assert.strictEqual(_.isRegExp(_), false); + assert.strictEqual(_.isRegExp(slice), false); + assert.strictEqual(_.isRegExp({ 'a': 1 }), false); + assert.strictEqual(_.isRegExp(1), false); + assert.strictEqual(_.isRegExp(NaN), false); + assert.strictEqual(_.isRegExp('a'), false); }); - test('should work with regexes from another realm', 1, function() { + QUnit.test('should work with regexes from another realm', function(assert) { + assert.expect(1); + if (_._object) { - strictEqual(_.isRegExp(_._regexp), true); + assert.strictEqual(_.isRegExp(_._regexp), true); } else { - skipTest(); + skipTest(assert); } }); }(1, 2, 3)); @@ -8257,39 +9400,45 @@ (function() { var args = arguments; - test('should return `true` for strings', 2, function() { - strictEqual(_.isString('a'), true); - strictEqual(_.isString(Object('a')), true); + QUnit.test('should return `true` for strings', function(assert) { + assert.expect(2); + + assert.strictEqual(_.isString('a'), true); + assert.strictEqual(_.isString(Object('a')), true); }); - test('should return `false` for non-strings', 12, function() { + QUnit.test('should return `false` for non-strings', function(assert) { + assert.expect(12); + var expected = _.map(falsey, function(value) { return value === ''; }); var actual = _.map(falsey, function(value, index) { return index ? _.isString(value) : _.isString(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); - strictEqual(_.isString(args), false); - strictEqual(_.isString([1, 2, 3]), false); - strictEqual(_.isString(true), false); - strictEqual(_.isString(new Date), false); - strictEqual(_.isString(new Error), false); - strictEqual(_.isString(_), false); - strictEqual(_.isString(slice), false); - strictEqual(_.isString({ '0': 1, 'length': 1 }), false); - strictEqual(_.isString(1), false); - strictEqual(_.isString(NaN), false); - strictEqual(_.isString(/x/), false); + assert.strictEqual(_.isString(args), false); + assert.strictEqual(_.isString([1, 2, 3]), false); + assert.strictEqual(_.isString(true), false); + assert.strictEqual(_.isString(new Date), false); + assert.strictEqual(_.isString(new Error), false); + assert.strictEqual(_.isString(_), false); + assert.strictEqual(_.isString(slice), false); + assert.strictEqual(_.isString({ '0': 1, 'length': 1 }), false); + assert.strictEqual(_.isString(1), false); + assert.strictEqual(_.isString(NaN), false); + assert.strictEqual(_.isString(/x/), false); }); - test('should work with strings from another realm', 1, function() { + QUnit.test('should work with strings from another realm', function(assert) { + assert.expect(1); + if (_._object) { - strictEqual(_.isString(_._string), true); + assert.strictEqual(_.isString(_._string), true); } else { - skipTest(); + skipTest(assert); } }); }(1, 2, 3)); @@ -8301,7 +9450,9 @@ (function() { var args = arguments; - test('should return `true` for typed arrays', 1, function() { + QUnit.test('should return `true` for typed arrays', function(assert) { + assert.expect(1); + var expected = _.map(typedArrays, function(type) { return type in root; }); @@ -8311,33 +9462,37 @@ return Ctor ? _.isTypedArray(new Ctor(new ArrayBuffer(8))) : false; }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return `false` for non typed arrays', 13, function() { + QUnit.test('should return `false` for non typed arrays', function(assert) { + assert.expect(13); + var expected = _.map(falsey, _.constant(false)); var actual = _.map(falsey, function(value, index) { return index ? _.isTypedArray(value) : _.isTypedArray(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); - strictEqual(_.isTypedArray(args), false); - strictEqual(_.isTypedArray([1, 2, 3]), false); - strictEqual(_.isTypedArray(true), false); - strictEqual(_.isTypedArray(new Date), false); - strictEqual(_.isTypedArray(new Error), false); - strictEqual(_.isTypedArray(_), false); - strictEqual(_.isTypedArray(slice), false); - strictEqual(_.isTypedArray({ 'a': 1 }), false); - strictEqual(_.isTypedArray(1), false); - strictEqual(_.isTypedArray(NaN), false); - strictEqual(_.isTypedArray(/x/), false); - strictEqual(_.isTypedArray('a'), false); + assert.strictEqual(_.isTypedArray(args), false); + assert.strictEqual(_.isTypedArray([1, 2, 3]), false); + assert.strictEqual(_.isTypedArray(true), false); + assert.strictEqual(_.isTypedArray(new Date), false); + assert.strictEqual(_.isTypedArray(new Error), false); + assert.strictEqual(_.isTypedArray(_), false); + assert.strictEqual(_.isTypedArray(slice), false); + assert.strictEqual(_.isTypedArray({ 'a': 1 }), false); + assert.strictEqual(_.isTypedArray(1), false); + assert.strictEqual(_.isTypedArray(NaN), false); + assert.strictEqual(_.isTypedArray(/x/), false); + assert.strictEqual(_.isTypedArray('a'), false); }); - test('should work with typed arrays from another realm', 1, function() { + QUnit.test('should work with typed arrays from another realm', function(assert) { + assert.expect(1); + if (_._object) { var props = _.map(typedArrays, function(type) { return '_' + type.toLowerCase(); @@ -8352,10 +9507,10 @@ return value ? _.isTypedArray(value) : false; }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); } else { - skipTest(); + skipTest(assert); } }); }(1, 2, 3)); @@ -8367,40 +9522,46 @@ (function() { var args = arguments; - test('should return `true` for `undefined` values', 2, function() { - strictEqual(_.isUndefined(), true); - strictEqual(_.isUndefined(undefined), true); + QUnit.test('should return `true` for `undefined` values', function(assert) { + assert.expect(2); + + assert.strictEqual(_.isUndefined(), true); + assert.strictEqual(_.isUndefined(undefined), true); }); - test('should return `false` for non `undefined` values', 13, function() { + QUnit.test('should return `false` for non `undefined` values', function(assert) { + assert.expect(13); + var expected = _.map(falsey, function(value) { return value === undefined; }); var actual = _.map(falsey, function(value, index) { return index ? _.isUndefined(value) : _.isUndefined(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); - strictEqual(_.isUndefined(args), false); - strictEqual(_.isUndefined([1, 2, 3]), false); - strictEqual(_.isUndefined(true), false); - strictEqual(_.isUndefined(new Date), false); - strictEqual(_.isUndefined(new Error), false); - strictEqual(_.isUndefined(_), false); - strictEqual(_.isUndefined(slice), false); - strictEqual(_.isUndefined({ 'a': 1 }), false); - strictEqual(_.isUndefined(1), false); - strictEqual(_.isUndefined(NaN), false); - strictEqual(_.isUndefined(/x/), false); - strictEqual(_.isUndefined('a'), false); + assert.strictEqual(_.isUndefined(args), false); + assert.strictEqual(_.isUndefined([1, 2, 3]), false); + assert.strictEqual(_.isUndefined(true), false); + assert.strictEqual(_.isUndefined(new Date), false); + assert.strictEqual(_.isUndefined(new Error), false); + assert.strictEqual(_.isUndefined(_), false); + assert.strictEqual(_.isUndefined(slice), false); + assert.strictEqual(_.isUndefined({ 'a': 1 }), false); + assert.strictEqual(_.isUndefined(1), false); + assert.strictEqual(_.isUndefined(NaN), false); + assert.strictEqual(_.isUndefined(/x/), false); + assert.strictEqual(_.isUndefined('a'), false); }); - test('should work with `undefined` from another realm', 1, function() { + QUnit.test('should work with `undefined` from another realm', function(assert) { + assert.expect(1); + if (_._object) { - strictEqual(_.isUndefined(_._undefined), true); + assert.strictEqual(_.isUndefined(_._undefined), true); } else { - skipTest(); + skipTest(assert); } }); }(1, 2, 3)); @@ -8410,7 +9571,9 @@ QUnit.module('isType checks'); (function() { - test('should return `false` for subclassed values', 8, function() { + QUnit.test('should return `false` for subclassed values', function(assert) { + assert.expect(8); + var funcs = [ 'isArray', 'isBoolean', 'isDate', 'isError', 'isFunction', 'isNumber', 'isRegExp', 'isString' @@ -8422,14 +9585,16 @@ var object = new Foo; if (objToString.call(object) == objectTag) { - strictEqual(_[methodName](object), false, '`_.' + methodName + '` returns `false`'); + assert.strictEqual(_[methodName](object), false, '`_.' + methodName + '` returns `false`'); } else { - skipTest(); + skipTest(assert); } }); }); - test('should not error on host objects (test in IE)', 18, function() { + QUnit.test('should not error on host objects (test in IE)', function(assert) { + assert.expect(18); + var funcs = [ 'isArguments', 'isArray', 'isArrayLike', 'isBoolean', 'isDate', 'isElement', 'isError', 'isFinite', 'isFunction', 'isNaN', 'isNil', 'isNull', 'isNumber', @@ -8445,10 +9610,10 @@ } catch (e) { pass = false; } - ok(pass, '`_.' + methodName + '` should not error'); + assert.ok(pass, '`_.' + methodName + '` should not error'); } else { - skipTest(); + skipTest(assert); } }); }); @@ -8459,15 +9624,19 @@ QUnit.module('lodash.iteratee'); (function() { - test('should provide arguments to `func`', 1, function() { + QUnit.test('should provide arguments to `func`', function(assert) { + assert.expect(1); + var fn = function() { return slice.call(arguments); }, iteratee = _.iteratee(fn), actual = iteratee('a', 'b', 'c', 'd', 'e', 'f'); - deepEqual(actual, ['a', 'b', 'c', 'd', 'e', 'f']); + assert.deepEqual(actual, ['a', 'b', 'c', 'd', 'e', 'f']); }); - test('should return `_.identity` when `func` is nullish', 1, function() { + QUnit.test('should return `_.identity` when `func` is nullish', function(assert) { + assert.expect(1); + var object = {}, values = [, null, undefined], expected = _.map(values, _.constant([!isNpm && _.identity, object])); @@ -8477,16 +9646,20 @@ return [!isNpm && identity, identity(object)]; }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return an iteratee created by `_.matches` when `func` is an object', 2, function() { + QUnit.test('should return an iteratee created by `_.matches` when `func` is an object', function(assert) { + assert.expect(2); + var matches = _.iteratee({ 'a': 1, 'b': 2 }); - strictEqual(matches({ 'a': 1, 'b': 2, 'c': 3 }), true); - strictEqual(matches({ 'b': 2 }), false); + assert.strictEqual(matches({ 'a': 1, 'b': 2, 'c': 3 }), true); + assert.strictEqual(matches({ 'b': 2 }), false); }); - test('should not change match behavior if `source` is modified', 9, function() { + QUnit.test('should not change match behavior if `source` is modified', function(assert) { + assert.expect(9); + var sources = [ { 'a': { 'b': 2, 'c': 3 } }, { 'a': 1, 'b': 2 }, @@ -8497,7 +9670,7 @@ var object = _.cloneDeep(source), matches = _.iteratee(source); - strictEqual(matches(object), true); + assert.strictEqual(matches(object), true); if (index) { source.a = 2; @@ -8508,49 +9681,59 @@ source.a.c = 2; source.a.d = 3; } - strictEqual(matches(object), true); - strictEqual(matches(source), false); + assert.strictEqual(matches(object), true); + assert.strictEqual(matches(source), false); }); }); - test('should return an iteratee created by `_.matchesProperty` when `func` is a number or string and a value is provided', 3, function() { + QUnit.test('should return an iteratee created by `_.matchesProperty` when `func` is a number or string and a value is provided', function(assert) { + assert.expect(3); + var array = ['a', undefined], matches = _.iteratee([0, 'a']); - strictEqual(matches(array), true); + assert.strictEqual(matches(array), true); matches = _.iteratee(['0', 'a']); - strictEqual(matches(array), true); + assert.strictEqual(matches(array), true); matches = _.iteratee([1, undefined]); - strictEqual(matches(array), true); + assert.strictEqual(matches(array), true); }); - test('should support deep paths for "_.matchesProperty" shorthands', 1, function() { + QUnit.test('should support deep paths for "_.matchesProperty" shorthands', function(assert) { + assert.expect(1); + var object = { 'a': { 'b': { 'c': { 'd': 1, 'e': 2 } } } }, matches = _.iteratee(['a.b.c', { 'e': 2 }]); - strictEqual(matches(object), true); + assert.strictEqual(matches(object), true); }); - test('should return an iteratee created by `_.property` when `func` is a number or string', 2, function() { + QUnit.test('should return an iteratee created by `_.property` when `func` is a number or string', function(assert) { + assert.expect(2); + var array = ['a'], prop = _.iteratee(0); - strictEqual(prop(array), 'a'); + assert.strictEqual(prop(array), 'a'); prop = _.iteratee('0'); - strictEqual(prop(array), 'a'); + assert.strictEqual(prop(array), 'a'); }); - test('should support deep paths for "_.property" shorthands', 1, function() { + QUnit.test('should support deep paths for "_.property" shorthands', function(assert) { + assert.expect(1); + var object = { 'a': { 'b': { 'c': 3 } } }, prop = _.iteratee('a.b.c'); - strictEqual(prop(object), 3); + assert.strictEqual(prop(object), 3); }); - test('should work with functions created by `_.partial` and `_.partialRight`', 2, function() { + QUnit.test('should work with functions created by `_.partial` and `_.partialRight`', function(assert) { + assert.expect(2); + var fn = function() { var result = [this.a]; push.apply(result, arguments); @@ -8560,13 +9743,15 @@ var expected = [1, 2, 3], object = { 'a': 1 , 'iteratee': _.iteratee(_.partial(fn, 2)) }; - deepEqual(object.iteratee(3), expected); + assert.deepEqual(object.iteratee(3), expected); object.iteratee = _.iteratee(_.partialRight(fn, 3)); - deepEqual(object.iteratee(2), expected); + assert.deepEqual(object.iteratee(2), expected); }); - test('should work as an iteratee for methods like `_.map`', 1, function() { + QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { + assert.expect(1); + var fn = function() { return this instanceof Number; }, array = [fn, fn, fn], iteratees = _.map(array, _.iteratee), @@ -8576,7 +9761,7 @@ return iteratee(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }()); @@ -8603,350 +9788,412 @@ { 'a': 1, 'b': 1 } ]; - test('`_.countBy` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.countBy` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { _.iteratee = getLength; - deepEqual(_.countBy(array), { '3': 2, '5': 1 }); + assert.deepEqual(_.countBy(array), { '3': 2, '5': 1 }); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.dropRightWhile` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.dropRightWhile` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { _.iteratee = getPropB; - deepEqual(_.dropRightWhile(objects), objects.slice(0, 2)); + assert.deepEqual(_.dropRightWhile(objects), objects.slice(0, 2)); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.dropWhile` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.dropWhile` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { _.iteratee = getPropB; - deepEqual(_.dropWhile(objects.reverse()).reverse(), objects.reverse().slice(0, 2)); + assert.deepEqual(_.dropWhile(objects.reverse()).reverse(), objects.reverse().slice(0, 2)); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.every` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.every` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { _.iteratee = getPropA; - strictEqual(_.every(objects.slice(1)), true); + assert.strictEqual(_.every(objects.slice(1)), true); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.filter` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.filter` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { var objects = [{ 'a': 0 }, { 'a': 1 }]; _.iteratee = getPropA; - deepEqual(_.filter(objects), [objects[1]]); + assert.deepEqual(_.filter(objects), [objects[1]]); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.find` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.find` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { _.iteratee = getPropA; - strictEqual(_.find(objects), objects[1]); + assert.strictEqual(_.find(objects), objects[1]); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.findIndex` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.findIndex` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { _.iteratee = getPropA; - strictEqual(_.findIndex(objects), 1); + assert.strictEqual(_.findIndex(objects), 1); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.findLast` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.findLast` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { _.iteratee = getPropA; - strictEqual(_.findLast(objects), objects[2]); + assert.strictEqual(_.findLast(objects), objects[2]); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.findLastIndex` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.findLastIndex` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { _.iteratee = getPropA; - strictEqual(_.findLastIndex(objects), 2); + assert.strictEqual(_.findLastIndex(objects), 2); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.findLastKey` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.findLastKey` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { _.iteratee = getPropB; - strictEqual(_.findKey(objects), '2'); + assert.strictEqual(_.findKey(objects), '2'); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.findKey` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.findKey` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { _.iteratee = getPropB; - strictEqual(_.findLastKey(objects), '2'); + assert.strictEqual(_.findLastKey(objects), '2'); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.groupBy` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.groupBy` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { _.iteratee = getLength; - deepEqual(_.groupBy(array), { '3': ['one', 'two'], '5': ['three'] }); + assert.deepEqual(_.groupBy(array), { '3': ['one', 'two'], '5': ['three'] }); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.keyBy` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.keyBy` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { _.iteratee = getLength; - deepEqual(_.keyBy(array), { '3': 'two', '5': 'three' }); + assert.deepEqual(_.keyBy(array), { '3': 'two', '5': 'three' }); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.map` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.map` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { _.iteratee = getPropA; - deepEqual(_.map(objects), [0, 1, 1]); + assert.deepEqual(_.map(objects), [0, 1, 1]); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.mapKeys` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.mapKeys` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { _.iteratee = getPropB; - deepEqual(_.mapKeys({ 'a': { 'b': 1 } }), { '1': { 'b': 1 } }); + assert.deepEqual(_.mapKeys({ 'a': { 'b': 1 } }), { '1': { 'b': 1 } }); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.mapValues` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.mapValues` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { _.iteratee = getPropB; - deepEqual(_.mapValues({ 'a': { 'b': 1 } }), { 'a': 1 }); + assert.deepEqual(_.mapValues({ 'a': { 'b': 1 } }), { 'a': 1 }); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.maxBy` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.maxBy` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { _.iteratee = getPropB; - deepEqual(_.maxBy(objects), objects[2]); + assert.deepEqual(_.maxBy(objects), objects[2]); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.minBy` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.minBy` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { _.iteratee = getPropB; - deepEqual(_.minBy(objects), objects[0]); + assert.deepEqual(_.minBy(objects), objects[0]); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.partition` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.partition` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { var objects = [{ 'a': 1 }, { 'a': 1 }, { 'b': 2 }]; _.iteratee = getPropA; - deepEqual(_.partition(objects), [objects.slice(0, 2), objects.slice(2)]); + assert.deepEqual(_.partition(objects), [objects.slice(0, 2), objects.slice(2)]); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.reduce` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.reduce` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { _.iteratee = getSum; - strictEqual(_.reduce(objects, undefined, 0), 2); + assert.strictEqual(_.reduce(objects, undefined, 0), 2); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.reduceRight` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.reduceRight` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { _.iteratee = getSum; - strictEqual(_.reduceRight(objects, undefined, 0), 2); + assert.strictEqual(_.reduceRight(objects, undefined, 0), 2); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.reject` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.reject` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { var objects = [{ 'a': 0 }, { 'a': 1 }]; _.iteratee = getPropA; - deepEqual(_.reject(objects), [objects[0]]); + assert.deepEqual(_.reject(objects), [objects[0]]); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.remove` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.remove` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { var objects = [{ 'a': 0 }, { 'a': 1 }]; _.iteratee = getPropA; _.remove(objects); - deepEqual(objects, [{ 'a': 0 }]); + assert.deepEqual(objects, [{ 'a': 0 }]); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.some` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.some` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { _.iteratee = getPropB; - strictEqual(_.some(objects), true); + assert.strictEqual(_.some(objects), true); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.sortBy` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.sortBy` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { _.iteratee = getPropA; - deepEqual(_.sortBy(objects.slice().reverse()), [objects[0], objects[2], objects[1]]); + assert.deepEqual(_.sortBy(objects.slice().reverse()), [objects[0], objects[2], objects[1]]); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.sortedIndexBy` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.sortedIndexBy` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { var objects = [{ 'a': 30 }, { 'a': 50 }]; _.iteratee = getPropA; - strictEqual(_.sortedIndexBy(objects, { 'a': 40 }), 1); + assert.strictEqual(_.sortedIndexBy(objects, { 'a': 40 }), 1); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.sortedLastIndexBy` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.sortedLastIndexBy` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { var objects = [{ 'a': 30 }, { 'a': 50 }]; _.iteratee = getPropA; - strictEqual(_.sortedLastIndexBy(objects, { 'a': 40 }), 1); + assert.strictEqual(_.sortedLastIndexBy(objects, { 'a': 40 }), 1); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.sumBy` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.sumBy` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { _.iteratee = getPropB; - strictEqual(_.sumBy(objects), 1); + assert.strictEqual(_.sumBy(objects), 1); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.takeRightWhile` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.takeRightWhile` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { _.iteratee = getPropB; - deepEqual(_.takeRightWhile(objects), objects.slice(2)); + assert.deepEqual(_.takeRightWhile(objects), objects.slice(2)); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.takeWhile` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.takeWhile` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { _.iteratee = getPropB; - deepEqual(_.takeWhile(objects.reverse()), objects.reverse().slice(2)); + assert.deepEqual(_.takeWhile(objects.reverse()), objects.reverse().slice(2)); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.transform` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.transform` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { _.iteratee = function() { return function(result, object) { @@ -8954,22 +10201,24 @@ }; }; - deepEqual(_.transform(objects, undefined, { 'sum': 0 }), { 'sum': 2 }); + assert.deepEqual(_.transform(objects, undefined, { 'sum': 0 }), { 'sum': 2 }); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); - test('`_.uniqBy` should use `_.iteratee` internally', 1, function() { + QUnit.test('`_.uniqBy` should use `_.iteratee` internally', function(assert) { + assert.expect(1); + if (!isModularize) { _.iteratee = getPropB; - deepEqual(_.uniqBy(objects), [objects[0], objects[2]]); + assert.deepEqual(_.uniqBy(objects), [objects[0], objects[2]]); _.iteratee = iteratee; } else { - skipTest(); + skipTest(assert); } }); }()); @@ -8979,7 +10228,9 @@ QUnit.module('lodash.keyBy'); (function() { - test('should use `_.identity` when `iteratee` is nullish', 1, function() { + QUnit.test('should use `_.identity` when `iteratee` is nullish', function(assert) { + assert.expect(1); + var array = [4, 6, 6], values = [, null, undefined], expected = _.map(values, _.constant({ '4': 4, '6': 6 })); @@ -8988,43 +10239,53 @@ return index ? _.keyBy(array, value) : _.keyBy(array); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work with a "_.property" style `iteratee`', 1, function() { + QUnit.test('should work with a "_.property" style `iteratee`', function(assert) { + assert.expect(1); + var actual = _.keyBy(['one', 'two', 'three'], 'length'); - deepEqual(actual, { '3': 'two', '5': 'three' }); + assert.deepEqual(actual, { '3': 'two', '5': 'three' }); }); - test('should only add values to own, not inherited, properties', 2, function() { + QUnit.test('should only add values to own, not inherited, properties', function(assert) { + assert.expect(2); + var actual = _.keyBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num) > 4 ? 'hasOwnProperty' : 'constructor'; }); - deepEqual(actual.constructor, 4.2); - deepEqual(actual.hasOwnProperty, 6.4); + assert.deepEqual(actual.constructor, 4.2); + assert.deepEqual(actual.hasOwnProperty, 6.4); }); - test('should work with a number for `iteratee`', 2, function() { + QUnit.test('should work with a number for `iteratee`', function(assert) { + assert.expect(2); + var array = [ [1, 'a'], [2, 'a'], [2, 'b'] ]; - deepEqual(_.keyBy(array, 0), { '1': [1, 'a'], '2': [2, 'b'] }); - deepEqual(_.keyBy(array, 1), { 'a': [2, 'a'], 'b': [2, 'b'] }); + assert.deepEqual(_.keyBy(array, 0), { '1': [1, 'a'], '2': [2, 'b'] }); + assert.deepEqual(_.keyBy(array, 1), { 'a': [2, 'a'], 'b': [2, 'b'] }); }); - test('should work with an object for `collection`', 1, function() { + QUnit.test('should work with an object for `collection`', function(assert) { + assert.expect(1); + var actual = _.keyBy({ 'a': 4.2, 'b': 6.1, 'c': 6.4 }, function(num) { return Math.floor(num); }); - deepEqual(actual, { '4': 4.2, '6': 6.4 }); + assert.deepEqual(actual, { '4': 4.2, '6': 6.4 }); }); - test('should work in a lazy chain sequence', 1, function() { + QUnit.test('should work in a lazy chain sequence', function(assert) { + assert.expect(1); + if (!isNpm) { var array = _.range(LARGE_ARRAY_SIZE).concat( _.range(Math.floor(LARGE_ARRAY_SIZE / 2), LARGE_ARRAY_SIZE), @@ -9033,10 +10294,10 @@ var actual = _(array).keyBy().map(square).filter(isEven).take().value(); - deepEqual(actual, _.take(_.filter(_.map(_.keyBy(array), square), isEven))); + assert.deepEqual(actual, _.take(_.filter(_.map(_.keyBy(array), square), isEven))); } else { - skipTest(); + skipTest(assert); } }); }()); @@ -9050,107 +10311,135 @@ func = _[methodName], isKeys = methodName == 'keys'; - test('`_.' + methodName + '` should return the keys of an object', 1, function() { - deepEqual(func({ 'a': 1, 'b': 1 }).sort(), ['a', 'b']); + QUnit.test('`_.' + methodName + '` should return the keys of an object', function(assert) { + assert.expect(1); + + assert.deepEqual(func({ 'a': 1, 'b': 1 }).sort(), ['a', 'b']); }); - test('`_.' + methodName + '` should coerce primitives to objects (test in IE 9)', 2, function() { - deepEqual(func('abc').sort(), ['0', '1', '2']); + QUnit.test('`_.' + methodName + '` should coerce primitives to objects (test in IE 9)', function(assert) { + assert.expect(2); + + assert.deepEqual(func('abc').sort(), ['0', '1', '2']); // IE 9 doesn't box numbers in for-in loops. numberProto.a = 1; - deepEqual(func(0), isKeys ? [] : ['a']); + assert.deepEqual(func(0), isKeys ? [] : ['a']); delete numberProto.a; }); - test('`_.' + methodName + '` should treat sparse arrays as dense', 1, function() { + QUnit.test('`_.' + methodName + '` should treat sparse arrays as dense', function(assert) { + assert.expect(1); + var array = [1]; array[2] = 3; - deepEqual(func(array).sort(), ['0', '1', '2']); + assert.deepEqual(func(array).sort(), ['0', '1', '2']); }); - test('`_.' + methodName + '` should not coerce nullish values to objects', 2, function() { + QUnit.test('`_.' + methodName + '` should not coerce nullish values to objects', function(assert) { + assert.expect(2); + objectProto.a = 1; _.each([null, undefined], function(value) { - deepEqual(func(value), []); + assert.deepEqual(func(value), []); }); delete objectProto.a; }); - test('`_.' + methodName + '` should return keys for custom properties on arrays', 1, function() { + QUnit.test('`_.' + methodName + '` should return keys for custom properties on arrays', function(assert) { + assert.expect(1); + var array = [1]; array.a = 1; - deepEqual(func(array).sort(), ['0', 'a']); + assert.deepEqual(func(array).sort(), ['0', 'a']); }); - test('`_.' + methodName + '` should ' + (isKeys ? 'not' : '') + ' include inherited properties of arrays', 1, function() { + QUnit.test('`_.' + methodName + '` should ' + (isKeys ? 'not' : '') + ' include inherited properties of arrays', function(assert) { + assert.expect(1); + var expected = isKeys ? ['0'] : ['0', 'a']; arrayProto.a = 1; - deepEqual(func([1]).sort(), expected); + assert.deepEqual(func([1]).sort(), expected); delete arrayProto.a; }); - test('`_.' + methodName + '` should work with `arguments` objects', 1, function() { - deepEqual(func(args).sort(), ['0', '1', '2']); + QUnit.test('`_.' + methodName + '` should work with `arguments` objects', function(assert) { + assert.expect(1); + + assert.deepEqual(func(args).sort(), ['0', '1', '2']); }); - test('`_.' + methodName + '` should return keys for custom properties on `arguments` objects', 1, function() { + QUnit.test('`_.' + methodName + '` should return keys for custom properties on `arguments` objects', function(assert) { + assert.expect(1); + args.a = 1; - deepEqual(func(args).sort(), ['0', '1', '2', 'a']); + assert.deepEqual(func(args).sort(), ['0', '1', '2', 'a']); delete args.a; }); - test('`_.' + methodName + '` should ' + (isKeys ? 'not' : '') + ' include inherited properties of `arguments` objects', 1, function() { + QUnit.test('`_.' + methodName + '` should ' + (isKeys ? 'not' : '') + ' include inherited properties of `arguments` objects', function(assert) { + assert.expect(1); + var expected = isKeys ? ['0', '1', '2'] : ['0', '1', '2', 'a']; objectProto.a = 1; - deepEqual(func(args).sort(), expected); + assert.deepEqual(func(args).sort(), expected); delete objectProto.a; }); - test('`_.' + methodName + '` should work with string objects', 1, function() { - deepEqual(func(Object('abc')).sort(), ['0', '1', '2']); + QUnit.test('`_.' + methodName + '` should work with string objects', function(assert) { + assert.expect(1); + + assert.deepEqual(func(Object('abc')).sort(), ['0', '1', '2']); }); - test('`_.' + methodName + '` should return keys for custom properties on string objects', 1, function() { + QUnit.test('`_.' + methodName + '` should return keys for custom properties on string objects', function(assert) { + assert.expect(1); + var object = Object('a'); object.a = 1; - deepEqual(func(object).sort(), ['0', 'a']); + assert.deepEqual(func(object).sort(), ['0', 'a']); }); - test('`_.' + methodName + '` should ' + (isKeys ? 'not' : '') + ' include inherited properties of string objects', 1, function() { + QUnit.test('`_.' + methodName + '` should ' + (isKeys ? 'not' : '') + ' include inherited properties of string objects', function(assert) { + assert.expect(1); + var expected = isKeys ? ['0'] : ['0', 'a']; stringProto.a = 1; - deepEqual(func(Object('a')).sort(), expected); + assert.deepEqual(func(Object('a')).sort(), expected); delete stringProto.a; }); - test('`_.' + methodName + '` skips the `constructor` property on prototype objects', 3, function() { + QUnit.test('`_.' + methodName + '` skips the `constructor` property on prototype objects', function(assert) { + assert.expect(3); + function Foo() {} Foo.prototype.a = 1; var expected = ['a']; - deepEqual(func(Foo.prototype), expected); + assert.deepEqual(func(Foo.prototype), expected); Foo.prototype = { 'constructor': Foo, 'a': 1 }; - deepEqual(func(Foo.prototype), expected); + assert.deepEqual(func(Foo.prototype), expected); var Fake = { 'prototype': {} }; Fake.prototype.constructor = Fake; - deepEqual(func(Fake.prototype), ['constructor']); + assert.deepEqual(func(Fake.prototype), ['constructor']); }); - test('`_.' + methodName + '` should ' + (isKeys ? 'not' : '') + ' include inherited properties', 1, function() { + QUnit.test('`_.' + methodName + '` should ' + (isKeys ? 'not' : '') + ' include inherited properties', function(assert) { + assert.expect(1); + function Foo() { this.a = 1; } Foo.prototype.b = 2; var expected = isKeys ? ['a'] : ['a', 'b']; - deepEqual(func(new Foo).sort(), expected); + assert.deepEqual(func(new Foo).sort(), expected); }); }); @@ -9161,53 +10450,67 @@ (function() { var array = [1, 2, 3, 4]; - test('should return the last element', 1, function() { - strictEqual(_.last(array), 4); + QUnit.test('should return the last element', function(assert) { + assert.expect(1); + + assert.strictEqual(_.last(array), 4); }); - test('should return `undefined` when querying empty arrays', 1, function() { + QUnit.test('should return `undefined` when querying empty arrays', function(assert) { + assert.expect(1); + var array = []; array['-1'] = 1; - strictEqual(_.last([]), undefined); + assert.strictEqual(_.last([]), undefined); }); - test('should work as an iteratee for methods like `_.map`', 1, function() { + 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, _.last); - deepEqual(actual, [3, 6, 9]); + assert.deepEqual(actual, [3, 6, 9]); }); - test('should return an unwrapped value when implicitly chaining', 1, function() { + QUnit.test('should return an unwrapped value when implicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - strictEqual(_(array).last(), 4); + assert.strictEqual(_(array).last(), 4); } else { - skipTest(); + skipTest(assert); } }); - test('should return a wrapped value when explicitly chaining', 1, function() { + QUnit.test('should return a wrapped value when explicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - ok(_(array).chain().last() instanceof _); + assert.ok(_(array).chain().last() instanceof _); } else { - skipTest(); + skipTest(assert); } }); - test('should not execute immediately when explicitly chaining', 1, function() { + QUnit.test('should not execute immediately when explicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { var wrapped = _(array).chain().last(); - strictEqual(wrapped.__wrapped__, array); + assert.strictEqual(wrapped.__wrapped__, array); } else { - skipTest(); + skipTest(assert); } }); - test('should work in a lazy chain sequence', 2, function() { + QUnit.test('should work in a lazy chain sequence', function(assert) { + assert.expect(2); + if (!isNpm) { var largeArray = _.range(LARGE_ARRAY_SIZE), smallArray = array; @@ -9216,11 +10519,11 @@ var array = index ? largeArray : smallArray, wrapped = _(array).filter(isEven); - strictEqual(wrapped.last(), _.last(_.filter(array, isEven))); + assert.strictEqual(wrapped.last(), _.last(_.filter(array, isEven))); }); } else { - skipTest(2); + skipTest(assert, 2); } }); }()); @@ -9230,16 +10533,20 @@ QUnit.module('lodash.lt'); (function() { - test('should return `true` if `value` is less than `other`', 2, function() { - strictEqual(_.lt(1, 3), true); - strictEqual(_.lt('abc', 'def'), true); + QUnit.test('should return `true` if `value` is less than `other`', function(assert) { + assert.expect(2); + + assert.strictEqual(_.lt(1, 3), true); + assert.strictEqual(_.lt('abc', 'def'), true); }); - test('should return `false` if `value` is greater than or equal to `other`', 4, function() { - strictEqual(_.lt(3, 1), false); - strictEqual(_.lt(3, 3), false); - strictEqual(_.lt('def', 'abc'), false); - strictEqual(_.lt('def', 'def'), false); + QUnit.test('should return `false` if `value` is greater than or equal to `other`', function(assert) { + assert.expect(4); + + assert.strictEqual(_.lt(3, 1), false); + assert.strictEqual(_.lt(3, 3), false); + assert.strictEqual(_.lt('def', 'abc'), false); + assert.strictEqual(_.lt('def', 'def'), false); }); }()); @@ -9248,16 +10555,20 @@ QUnit.module('lodash.lte'); (function() { - test('should return `true` if `value` is less than or equal to `other`', 4, function() { - strictEqual(_.lte(1, 3), true); - strictEqual(_.lte(3, 3), true); - strictEqual(_.lte('abc', 'def'), true); - strictEqual(_.lte('def', 'def'), true); + QUnit.test('should return `true` if `value` is less than or equal to `other`', function(assert) { + assert.expect(4); + + assert.strictEqual(_.lte(1, 3), true); + assert.strictEqual(_.lte(3, 3), true); + assert.strictEqual(_.lte('abc', 'def'), true); + assert.strictEqual(_.lte('def', 'def'), true); }); - test('should return `false` if `value` is greater than `other`', 2, function() { - strictEqual(_.lt(3, 1), false); - strictEqual(_.lt('def', 'abc'), false); + QUnit.test('should return `false` if `value` is greater than `other`', function(assert) { + assert.expect(2); + + assert.strictEqual(_.lt(3, 1), false); + assert.strictEqual(_.lt('def', 'abc'), false); }); }()); @@ -9268,15 +10579,21 @@ (function() { var array = [1, 2, 3, 1, 2, 3]; - test('should return the index of the last matched value', 1, function() { - strictEqual(_.lastIndexOf(array, 3), 5); + QUnit.test('should return the index of the last matched value', function(assert) { + assert.expect(1); + + assert.strictEqual(_.lastIndexOf(array, 3), 5); }); - test('should work with a positive `fromIndex`', 1, function() { - strictEqual(_.lastIndexOf(array, 1, 2), 0); + QUnit.test('should work with a positive `fromIndex`', function(assert) { + assert.expect(1); + + assert.strictEqual(_.lastIndexOf(array, 1, 2), 0); }); - test('should work with `fromIndex` >= `array.length`', 1, function() { + QUnit.test('should work with `fromIndex` >= `array.length`', function(assert) { + assert.expect(1); + var values = [6, 8, Math.pow(2, 32), Infinity], expected = _.map(values, _.constant([-1, 3, -1])); @@ -9288,14 +10605,18 @@ ]; }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work with a negative `fromIndex`', 1, function() { - strictEqual(_.lastIndexOf(array, 2, -3), 1); + QUnit.test('should work with a negative `fromIndex`', function(assert) { + assert.expect(1); + + assert.strictEqual(_.lastIndexOf(array, 2, -3), 1); }); - test('should work with a negative `fromIndex` <= `-array.length`', 1, function() { + QUnit.test('should work with a negative `fromIndex` <= `-array.length`', function(assert) { + assert.expect(1); + var values = [-6, -8, -Infinity], expected = _.map(values, _.constant(0)); @@ -9303,10 +10624,12 @@ return _.lastIndexOf(array, 1, fromIndex); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should treat falsey `fromIndex` values correctly', 1, function() { + QUnit.test('should treat falsey `fromIndex` values correctly', function(assert) { + assert.expect(1); + var expected = _.map(falsey, function(value) { return value === undefined ? 5 : -1; }); @@ -9315,11 +10638,13 @@ return _.lastIndexOf(array, 3, fromIndex); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should coerce `fromIndex` to an integer', 1, function() { - strictEqual(_.lastIndexOf(array, 2, 4.2), 4); + QUnit.test('should coerce `fromIndex` to an integer', function(assert) { + assert.expect(1); + + assert.strictEqual(_.lastIndexOf(array, 2, 4.2), 4); }); }()); @@ -9332,7 +10657,9 @@ isIndexOf = !/last/i.test(methodName), isSorted = /^sorted/.test(methodName); - test('`_.' + methodName + '` should accept a falsey `array` argument', 1, function() { + QUnit.test('`_.' + methodName + '` should accept a falsey `array` argument', function(assert) { + assert.expect(1); + var expected = _.map(falsey, _.constant(-1)); var actual = _.map(falsey, function(array, index) { @@ -9341,49 +10668,57 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('`_.' + methodName + '` should return `-1` for an unmatched value', 5, function() { + QUnit.test('`_.' + methodName + '` should return `-1` for an unmatched value', function(assert) { + assert.expect(5); + var array = [1, 2, 3], empty = []; - strictEqual(func(array, 4), -1); - strictEqual(func(array, 4, true), -1); - strictEqual(func(array, undefined, true), -1); + assert.strictEqual(func(array, 4), -1); + assert.strictEqual(func(array, 4, true), -1); + assert.strictEqual(func(array, undefined, true), -1); - strictEqual(func(empty, undefined), -1); - strictEqual(func(empty, undefined, true), -1); + assert.strictEqual(func(empty, undefined), -1); + assert.strictEqual(func(empty, undefined, true), -1); }); - test('`_.' + methodName + '` should not match values on empty arrays', 2, function() { + QUnit.test('`_.' + methodName + '` should not match values on empty arrays', function(assert) { + assert.expect(2); + var array = []; array[-1] = 0; - strictEqual(func(array, undefined), -1); - strictEqual(func(array, 0, true), -1); + assert.strictEqual(func(array, undefined), -1); + assert.strictEqual(func(array, 0, true), -1); }); - test('`_.' + methodName + '` should match `NaN`', 4, function() { + QUnit.test('`_.' + methodName + '` should match `NaN`', function(assert) { + assert.expect(4); + var array = isSorted ? [1, 2, NaN, NaN] : [1, NaN, 3, NaN, 5, NaN]; if (isSorted) { - strictEqual(func(array, NaN, true), isIndexOf ? 2 : 3); - skipTest(3); + assert.strictEqual(func(array, NaN, true), isIndexOf ? 2 : 3); + skipTest(assert, 3); } else { - strictEqual(func(array, NaN), isIndexOf ? 1 : 5); - strictEqual(func(array, NaN, 2), isIndexOf ? 3 : 1); - strictEqual(func(array, NaN, -2), isIndexOf ? 5 : 3); - skipTest(); + assert.strictEqual(func(array, NaN), isIndexOf ? 1 : 5); + assert.strictEqual(func(array, NaN, 2), isIndexOf ? 3 : 1); + assert.strictEqual(func(array, NaN, -2), isIndexOf ? 5 : 3); + skipTest(assert); } }); - test('`_.' + methodName + '` should match `-0` as `0`', 2, function() { - strictEqual(func([-0], 0), 0); - strictEqual(func([0], -0), 0); + QUnit.test('`_.' + methodName + '` should match `-0` as `0`', function(assert) { + assert.expect(2); + + assert.strictEqual(func([-0], 0), 0); + assert.strictEqual(func([0], -0), 0); }); }); @@ -9394,53 +10729,67 @@ (function() { var array = [1, 2, 3]; - test('should map values in `collection` to a new array', 2, function() { + QUnit.test('should map values in `collection` to a new array', function(assert) { + assert.expect(2); + var object = { 'a': 1, 'b': 2, 'c': 3 }, expected = ['1', '2', '3']; - deepEqual(_.map(array, String), expected); - deepEqual(_.map(object, String), expected); + assert.deepEqual(_.map(array, String), expected); + assert.deepEqual(_.map(object, String), expected); }); - test('should work with a "_.property" style `iteratee`', 1, function() { + QUnit.test('should work with a "_.property" style `iteratee`', function(assert) { + assert.expect(1); + var objects = [{ 'a': 'x' }, { 'a': 'y' }]; - deepEqual(_.map(objects, 'a'), ['x', 'y']); + assert.deepEqual(_.map(objects, 'a'), ['x', 'y']); }); - test('should iterate over own properties of objects', 1, function() { + QUnit.test('should iterate over own properties of objects', function(assert) { + assert.expect(1); + function Foo() { this.a = 1; } Foo.prototype.b = 2; var actual = _.map(new Foo, function(value, key) { return key; }); - deepEqual(actual, ['a']); + assert.deepEqual(actual, ['a']); }); - test('should work on an object with no `iteratee`', 1, function() { + QUnit.test('should work on an object with no `iteratee`', function(assert) { + assert.expect(1); + var actual = _.map({ 'a': 1, 'b': 2, 'c': 3 }); - deepEqual(actual, array); + assert.deepEqual(actual, array); }); - test('should handle object arguments with non-number length properties', 1, function() { + QUnit.test('should handle object arguments with non-number length properties', function(assert) { + assert.expect(1); + var value = { 'value': 'x' }, object = { 'length': { 'value': 'x' } }; - deepEqual(_.map(object, _.identity), [value]); + assert.deepEqual(_.map(object, _.identity), [value]); }); - test('should treat a nodelist as an array-like object', 1, function() { + QUnit.test('should treat a nodelist as an array-like object', function(assert) { + assert.expect(1); + if (document) { var actual = _.map(document.getElementsByTagName('body'), function(element) { return element.nodeName.toLowerCase(); }); - deepEqual(actual, ['body']); + assert.deepEqual(actual, ['body']); } else { - skipTest(); + skipTest(assert); } }); - test('should accept a falsey `collection` argument', 1, function() { + QUnit.test('should accept a falsey `collection` argument', function(assert) { + assert.expect(1); + var expected = _.map(falsey, _.constant([])); var actual = _.map(falsey, function(collection, index) { @@ -9449,23 +10798,29 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should treat number values for `collection` as empty', 1, function() { - deepEqual(_.map(1), []); + QUnit.test('should treat number values for `collection` as empty', function(assert) { + assert.expect(1); + + assert.deepEqual(_.map(1), []); }); - test('should return a wrapped value when chaining', 1, function() { + QUnit.test('should return a wrapped value when chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - ok(_(array).map(_.noop) instanceof _); + assert.ok(_(array).map(_.noop) instanceof _); } else { - skipTest(); + skipTest(assert); } }); - test('should provide the correct `predicate` arguments in a lazy chain sequence', 5, function() { + 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), @@ -9475,38 +10830,38 @@ args || (args = slice.call(arguments)); }).value(); - deepEqual(args, [1, 0, array.slice(1)]); + assert.deepEqual(args, [1, 0, array.slice(1)]); args = null; _(array).slice(1).map(square).map(function(value, index, array) { args || (args = slice.call(arguments)); }).value(); - deepEqual(args, expected); + assert.deepEqual(args, expected); args = null; _(array).slice(1).map(square).map(function(value, index) { args || (args = slice.call(arguments)); }).value(); - deepEqual(args, expected); + assert.deepEqual(args, expected); args = null; _(array).slice(1).map(square).map(function(value) { args || (args = slice.call(arguments)); }).value(); - deepEqual(args, [1]); + assert.deepEqual(args, [1]); args = null; _(array).slice(1).map(square).map(function() { args || (args = slice.call(arguments)); }).value(); - deepEqual(args, expected); + assert.deepEqual(args, expected); } else { - skipTest(5); + skipTest(assert, 5); } }); }()); @@ -9518,24 +10873,32 @@ var array = [1, 2], object = { 'a': 1, 'b': 2, 'c': 3 }; - test('should map keys in `object` to a new object', 1, function() { + QUnit.test('should map keys in `object` to a new object', function(assert) { + assert.expect(1); + var actual = _.mapKeys(object, String); - deepEqual(actual, { '1': 1, '2': 2, '3': 3 }); + assert.deepEqual(actual, { '1': 1, '2': 2, '3': 3 }); }); - test('should treat arrays like objects', 1, function() { + QUnit.test('should treat arrays like objects', function(assert) { + assert.expect(1); + var actual = _.mapKeys(array, String); - deepEqual(actual, { '1': 1, '2': 2 }); + assert.deepEqual(actual, { '1': 1, '2': 2 }); }); - test('should work with a "_.property" style `iteratee`', 1, function() { + QUnit.test('should work with a "_.property" style `iteratee`', function(assert) { + assert.expect(1); + var actual = _.mapKeys({ 'a': { 'b': 'c' } }, 'b'); - deepEqual(actual, { 'c': { 'b': 'c' } }); + assert.deepEqual(actual, { 'c': { 'b': 'c' } }); }); - test('should work on an object with no `iteratee`', 1, function() { + QUnit.test('should work on an object with no `iteratee`', function(assert) { + assert.expect(1); + var actual = _.mapKeys({ 'a': 1, 'b': 2, 'c': 3 }); - deepEqual(actual, { '1': 1, '2': 2, '3': 3 }); + assert.deepEqual(actual, { '1': 1, '2': 2, '3': 3 }); }); }()); @@ -9547,25 +10910,33 @@ var array = [1, 2], object = { 'a': 1, 'b': 2, 'c': 3 }; - test('should map values in `object` to a new object', 1, function() { + QUnit.test('should map values in `object` to a new object', function(assert) { + assert.expect(1); + var actual = _.mapValues(object, String); - deepEqual(actual, { 'a': '1', 'b': '2', 'c': '3' }); + assert.deepEqual(actual, { 'a': '1', 'b': '2', 'c': '3' }); }); - test('should treat arrays like objects', 1, function() { + QUnit.test('should treat arrays like objects', function(assert) { + assert.expect(1); + var actual = _.mapValues(array, String); - deepEqual(actual, { '0': '1', '1': '2' }); + assert.deepEqual(actual, { '0': '1', '1': '2' }); }); - test('should work with a "_.property" style `iteratee`', 1, function() { + QUnit.test('should work with a "_.property" style `iteratee`', function(assert) { + assert.expect(1); + var actual = _.mapValues({ 'a': { 'b': 1 } }, 'b'); - deepEqual(actual, { 'a': 1 }); + assert.deepEqual(actual, { 'a': 1 }); }); - test('should work on an object with no `iteratee`', 2, function() { + QUnit.test('should work on an object with no `iteratee`', function(assert) { + assert.expect(2); + var actual = _.mapValues({ 'a': 1, 'b': 2, 'c': 3 }); - deepEqual(actual, object); - notStrictEqual(actual, object); + assert.deepEqual(actual, object); + assert.notStrictEqual(actual, object); }); }()); @@ -9578,15 +10949,19 @@ func = _[methodName], object = { 'a': 1, 'b': 2, 'c': 3 }; - test('should iterate over own properties of objects', 1, function() { + QUnit.test('should iterate over own properties of objects', function(assert) { + assert.expect(1); + function Foo() { this.a = 'a'; } Foo.prototype.b = 'b'; var actual = func(new Foo, function(value, key) { return key; }); - deepEqual(actual, { 'a': 'a' }); + assert.deepEqual(actual, { 'a': 'a' }); }); - test('should accept a falsey `object` argument', 1, function() { + QUnit.test('should accept a falsey `object` argument', function(assert) { + assert.expect(1); + var expected = _.map(falsey, _.constant({})); var actual = _.map(falsey, function(object, index) { @@ -9595,15 +10970,17 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return a wrapped value when chaining', 1, function() { + QUnit.test('should return a wrapped value when chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - ok(_(object)[methodName](_.noop) instanceof _); + assert.ok(_(object)[methodName](_.noop) instanceof _); } else { - skipTest(); + skipTest(assert); } }); }); @@ -9613,39 +10990,45 @@ QUnit.module('lodash.matches'); (function() { - test('should create a function that performs a deep comparison between a given object and `source`', 6, function() { + QUnit.test('should create a function that performs a deep comparison between a given object and `source`', function(assert) { + assert.expect(6); + var object = { 'a': 1, 'b': 2, 'c': 3 }, matches = _.matches({ 'a': 1 }); - strictEqual(matches.length, 1); - strictEqual(matches(object), true); + assert.strictEqual(matches.length, 1); + assert.strictEqual(matches(object), true); matches = _.matches({ 'b': 1 }); - strictEqual(matches(object), false); + assert.strictEqual(matches(object), false); matches = _.matches({ 'a': 1, 'c': 3 }); - strictEqual(matches(object), true); + assert.strictEqual(matches(object), true); matches = _.matches({ 'c': 3, 'd': 4 }); - strictEqual(matches(object), false); + assert.strictEqual(matches(object), false); object = { 'a': { 'b': { 'c': 1, 'd': 2 }, 'e': 3 }, 'f': 4 }; matches = _.matches({ 'a': { 'b': { 'c': 1 } } }); - strictEqual(matches(object), true); + assert.strictEqual(matches(object), true); }); - test('should match inherited `object` properties', 1, function() { + QUnit.test('should match inherited `object` properties', function(assert) { + assert.expect(1); + function Foo() { this.a = 1; } Foo.prototype.b = 2; var object = { 'a': new Foo }, matches = _.matches({ 'a': { 'b': 2 } }); - strictEqual(matches(object), true); + assert.strictEqual(matches(object), true); }); - test('should not match by inherited `source` properties', 1, function() { + QUnit.test('should not match by inherited `source` properties', function(assert) { + assert.expect(1); + function Foo() { this.a = 1; } Foo.prototype.b = 2; @@ -9654,49 +11037,59 @@ actual = _.map(objects, _.matches(source)), expected = _.map(objects, _.constant(true)); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should compare a variety of `source` property values', 2, function() { + QUnit.test('should compare a variety of `source` property values', function(assert) { + assert.expect(2); + var object1 = { 'a': false, 'b': true, 'c': '3', 'd': 4, 'e': [5], 'f': { 'g': 6 } }, object2 = { 'a': 0, 'b': 1, 'c': 3, 'd': '4', 'e': ['5'], 'f': { 'g': '6' } }, matches = _.matches(object1); - strictEqual(matches(object1), true); - strictEqual(matches(object2), false); + assert.strictEqual(matches(object1), true); + assert.strictEqual(matches(object2), false); }); - test('should match `-0` as `0`', 2, function() { + QUnit.test('should match `-0` as `0`', function(assert) { + assert.expect(2); + var object1 = { 'a': -0 }, object2 = { 'a': 0 }, matches = _.matches(object1); - strictEqual(matches(object2), true); + assert.strictEqual(matches(object2), true); matches = _.matches(object2); - strictEqual(matches(object1), true); + assert.strictEqual(matches(object1), true); }); - test('should compare functions by reference', 3, function() { + QUnit.test('should compare functions by reference', function(assert) { + assert.expect(3); + var object1 = { 'a': _.noop }, object2 = { 'a': noop }, object3 = { 'a': {} }, matches = _.matches(object1); - strictEqual(matches(object1), true); - strictEqual(matches(object2), false); - strictEqual(matches(object3), false); + assert.strictEqual(matches(object1), true); + assert.strictEqual(matches(object2), false); + assert.strictEqual(matches(object3), false); }); - test('should work with a function for `object`', 1, function() { + QUnit.test('should work with a function for `object`', function(assert) { + assert.expect(1); + function Foo() {} Foo.a = { 'b': 1, 'c': 2 }; var matches = _.matches({ 'a': { 'b': 1 } }); - strictEqual(matches(Foo), true); + assert.strictEqual(matches(Foo), true); }); - test('should work with a function for `source`', 1, function() { + QUnit.test('should work with a function for `source`', function(assert) { + assert.expect(1); + function Foo() {} Foo.a = 1; Foo.b = function() {}; @@ -9705,33 +11098,39 @@ var objects = [{ 'a': 1 }, { 'a': 1, 'b': Foo.b, 'c': 3 }], actual = _.map(objects, _.matches(Foo)); - deepEqual(actual, [false, true]); + assert.deepEqual(actual, [false, true]); }); - test('should partial match arrays', 3, function() { + QUnit.test('should partial match arrays', function(assert) { + assert.expect(3); + var objects = [{ 'a': ['b'] }, { 'a': ['c', 'd'] }], actual = _.filter(objects, _.matches({ 'a': ['d'] })); - deepEqual(actual, [objects[1]]); + assert.deepEqual(actual, [objects[1]]); actual = _.filter(objects, _.matches({ 'a': ['b', 'd'] })); - deepEqual(actual, []); + assert.deepEqual(actual, []); actual = _.filter(objects, _.matches({ 'a': ['d', 'b'] })); - deepEqual(actual, []); + assert.deepEqual(actual, []); }); - test('should partial match arrays of objects', 1, function() { + QUnit.test('should partial match arrays of objects', function(assert) { + assert.expect(1); + var objects = [ { 'a': [{ 'b': 1, 'c': 2 }, { 'b': 4, 'c': 5, 'd': 6 }] }, { 'a': [{ 'b': 1, 'c': 2 }, { 'b': 4, 'c': 6, 'd': 7 }] } ]; var actual = _.filter(objects, _.matches({ 'a': [{ 'b': 1 }, { 'b': 4, 'c': 5 }] })); - deepEqual(actual, [objects[0]]); + assert.deepEqual(actual, [objects[0]]); }); - test('should partial match maps', 3, function() { + QUnit.test('should partial match maps', function(assert) { + assert.expect(3); + if (Map) { var objects = [{ 'a': new Map }, { 'a': new Map }]; objects[0].a.set('a', 1); @@ -9742,24 +11141,26 @@ map.set('b', 2); var actual = _.filter(objects, _.matches({ 'a': map })); - deepEqual(actual, [objects[1]]); + assert.deepEqual(actual, [objects[1]]); map['delete']('b'); actual = _.filter(objects, _.matches({ 'a': map })); - deepEqual(actual, objects); + assert.deepEqual(actual, objects); map.set('c', 3); actual = _.filter(objects, _.matches({ 'a': map })); - deepEqual(actual, []); + assert.deepEqual(actual, []); } else { - skipTest(3); + skipTest(assert, 3); } }); - test('should partial match sets', 3, function() { + QUnit.test('should partial match sets', function(assert) { + assert.expect(3); + if (Set) { var objects = [{ 'a': new Set }, { 'a': new Set }]; objects[0].a.add(1); @@ -9770,77 +11171,85 @@ set.add(2); var actual = _.filter(objects, _.matches({ 'a': set })); - deepEqual(actual, [objects[1]]); + assert.deepEqual(actual, [objects[1]]); set['delete'](2); actual = _.filter(objects, _.matches({ 'a': set })); - deepEqual(actual, objects); + assert.deepEqual(actual, objects); set.add(3); actual = _.filter(objects, _.matches({ 'a': set })); - deepEqual(actual, []); + assert.deepEqual(actual, []); } else { - skipTest(3); + skipTest(assert, 3); } }); - test('should match properties when `object` is not a plain object', 1, function() { + QUnit.test('should match properties when `object` is not a plain object', function(assert) { + assert.expect(1); + function Foo(object) { _.assign(this, object); } var object = new Foo({ 'a': new Foo({ 'b': 1, 'c': 2 }) }), matches = _.matches({ 'a': { 'b': 1 } }); - strictEqual(matches(object), true); + assert.strictEqual(matches(object), true); }); - test('should match `undefined` values', 3, function() { + QUnit.test('should match `undefined` values', function(assert) { + assert.expect(3); + var objects = [{ 'a': 1 }, { 'a': 1, 'b': 1 }, { 'a': 1, 'b': undefined }], actual = _.map(objects, _.matches({ 'b': undefined })), expected = [false, false, true]; - deepEqual(actual, expected); + assert.deepEqual(actual, expected); actual = _.map(objects, _.matches({ 'a': 1, 'b': undefined })); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); objects = [{ 'a': { 'b': 1 } }, { 'a': { 'b': 1, 'c': 1 } }, { 'a': { 'b': 1, 'c': undefined } }]; actual = _.map(objects, _.matches({ 'a': { 'c': undefined } })); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should match `undefined` values on primitives', 3, function() { + QUnit.test('should match `undefined` values on primitives', function(assert) { + assert.expect(3); + numberProto.a = 1; numberProto.b = undefined; try { var matches = _.matches({ 'b': undefined }); - strictEqual(matches(1), true); + assert.strictEqual(matches(1), true); } catch (e) { - ok(false, e.message); + assert.ok(false, e.message); } try { matches = _.matches({ 'a': 1, 'b': undefined }); - strictEqual(matches(1), true); + assert.strictEqual(matches(1), true); } catch (e) { - ok(false, e.message); + assert.ok(false, e.message); } numberProto.a = { 'b': 1, 'c': undefined }; try { matches = _.matches({ 'a': { 'c': undefined } }); - strictEqual(matches(1), true); + assert.strictEqual(matches(1), true); } catch (e) { - ok(false, e.message); + assert.ok(false, e.message); } delete numberProto.a; delete numberProto.b; }); - test('should return `false` when `object` is nullish', 1, function() { + QUnit.test('should return `false` when `object` is nullish', function(assert) { + assert.expect(1); + var values = [, null, undefined], expected = _.map(values, _.constant(false)), matches = _.matches({ 'a': 1 }); @@ -9851,10 +11260,12 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return `true` when comparing an empty `source` to a nullish `object`', 1, function() { + QUnit.test('should return `true` when comparing an empty `source` to a nullish `object`', function(assert) { + assert.expect(1); + var values = [, null, undefined], expected = _.map(values, _.constant(true)), matches = _.matches({}); @@ -9865,10 +11276,12 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return `true` when comparing an empty `source`', 1, function() { + QUnit.test('should return `true` when comparing an empty `source`', function(assert) { + assert.expect(1); + var object = { 'a': 1 }, expected = _.map(empties, _.constant(true)); @@ -9877,17 +11290,21 @@ return matches(object); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return `true` when comparing a `source` of empty arrays and objects', 1, function() { + QUnit.test('should return `true` when comparing a `source` of empty arrays and objects', function(assert) { + assert.expect(1); + var objects = [{ 'a': [1], 'b': { 'c': 1 } }, { 'a': [2, 3], 'b': { 'd': 2 } }], actual = _.filter(objects, _.matches({ 'a': [], 'b': {} })); - deepEqual(actual, objects); + assert.deepEqual(actual, objects); }); - test('should not change match behavior if `source` is modified', 9, function() { + QUnit.test('should not change match behavior if `source` is modified', function(assert) { + assert.expect(9); + var sources = [ { 'a': { 'b': 2, 'c': 3 } }, { 'a': 1, 'b': 2 }, @@ -9898,7 +11315,7 @@ var object = _.cloneDeep(source), matches = _.matches(source); - strictEqual(matches(object), true); + assert.strictEqual(matches(object), true); if (index) { source.a = 2; @@ -9909,8 +11326,8 @@ source.a.c = 2; source.a.d = 3; } - strictEqual(matches(object), true); - strictEqual(matches(source), false); + assert.strictEqual(matches(object), true); + assert.strictEqual(matches(source), false); }); }); }()); @@ -9920,38 +11337,44 @@ QUnit.module('lodash.matchesProperty'); (function() { - test('should create a function that performs a deep comparison between a property value and `srcValue`', 6, function() { + QUnit.test('should create a function that performs a deep comparison between a property value and `srcValue`', function(assert) { + assert.expect(6); + var object = { 'a': 1, 'b': 2, 'c': 3 }, matches = _.matchesProperty('a', 1); - strictEqual(matches.length, 1); - strictEqual(matches(object), true); + assert.strictEqual(matches.length, 1); + assert.strictEqual(matches(object), true); matches = _.matchesProperty('b', 3); - strictEqual(matches(object), false); + assert.strictEqual(matches(object), false); matches = _.matchesProperty('a', { 'a': 1, 'c': 3 }); - strictEqual(matches({ 'a': object }), true); + assert.strictEqual(matches({ 'a': object }), true); matches = _.matchesProperty('a', { 'c': 3, 'd': 4 }); - strictEqual(matches(object), false); + assert.strictEqual(matches(object), false); object = { 'a': { 'b': { 'c': 1, 'd': 2 }, 'e': 3 }, 'f': 4 }; matches = _.matchesProperty('a', { 'b': { 'c': 1 } }); - strictEqual(matches(object), true); + assert.strictEqual(matches(object), true); }); - test('should support deep paths', 2, function() { + QUnit.test('should support deep paths', function(assert) { + assert.expect(2); + var object = { 'a': { 'b': { 'c': 3 } } }; _.each(['a.b.c', ['a', 'b', 'c']], function(path) { var matches = _.matchesProperty(path, 3); - strictEqual(matches(object), true); + assert.strictEqual(matches(object), true); }); }); - test('should coerce key to a string', 1, function() { + QUnit.test('should coerce key to a string', function(assert) { + assert.expect(1); + function fn() {} fn.toString = _.constant('fn'); @@ -9970,37 +11393,45 @@ }); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should match a key over a path', 2, function() { + QUnit.test('should match a key over a path', function(assert) { + assert.expect(2); + var object = { 'a.b.c': 3, 'a': { 'b': { 'c': 4 } } }; _.each(['a.b.c', ['a.b.c']], function(path) { var matches = _.matchesProperty(path, 3); - strictEqual(matches(object), true); + assert.strictEqual(matches(object), true); }); }); - test('should work with non-string `path` arguments', 2, function() { + QUnit.test('should work with non-string `path` arguments', function(assert) { + assert.expect(2); + var array = [1, 2, 3]; _.each([1, [1]], function(path) { var matches = _.matchesProperty(path, 2); - strictEqual(matches(array), true); + assert.strictEqual(matches(array), true); }); }); - test('should return `false` if parts of `path` are missing', 4, function() { + QUnit.test('should return `false` if parts of `path` are missing', function(assert) { + assert.expect(4); + var object = {}; _.each(['a', 'a[1].b.c', ['a'], ['a', '1', 'b', 'c']], function(path) { var matches = _.matchesProperty(path, 1); - strictEqual(matches(object), false); + assert.strictEqual(matches(object), false); }); }); - test('should return `false` with deep paths when `object` is nullish', 2, function() { + QUnit.test('should return `false` with deep paths when `object` is nullish', function(assert) { + assert.expect(2); + var values = [, null, undefined], expected = _.map(values, _.constant(false)); @@ -10013,11 +11444,13 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }); - test('should match inherited `srcValue` properties', 2, function() { + QUnit.test('should match inherited `srcValue` properties', function(assert) { + assert.expect(2); + function Foo() {} Foo.prototype.b = 2; @@ -10025,11 +11458,13 @@ _.each(['a', ['a']], function(path) { var matches = _.matchesProperty(path, { 'b': 2 }); - strictEqual(matches(object), true); + assert.strictEqual(matches(object), true); }); }); - test('should not match by inherited `srcValue` properties', 2, function() { + QUnit.test('should not match by inherited `srcValue` properties', function(assert) { + assert.expect(2); + function Foo() { this.a = 1; } Foo.prototype.b = 2; @@ -10037,39 +11472,47 @@ expected = _.map(objects, _.constant(true)); _.each(['a', ['a']], function(path) { - deepEqual(_.map(objects, _.matchesProperty(path, new Foo)), expected); + assert.deepEqual(_.map(objects, _.matchesProperty(path, new Foo)), expected); }); }); - test('should compare a variety of values', 2, function() { + QUnit.test('should compare a variety of values', function(assert) { + assert.expect(2); + var object1 = { 'a': false, 'b': true, 'c': '3', 'd': 4, 'e': [5], 'f': { 'g': 6 } }, object2 = { 'a': 0, 'b': 1, 'c': 3, 'd': '4', 'e': ['5'], 'f': { 'g': '6' } }, matches = _.matchesProperty('a', object1); - strictEqual(matches({ 'a': object1 }), true); - strictEqual(matches({ 'a': object2 }), false); + assert.strictEqual(matches({ 'a': object1 }), true); + assert.strictEqual(matches({ 'a': object2 }), false); }); - test('should match `-0` as `0`', 2, function() { + QUnit.test('should match `-0` as `0`', function(assert) { + assert.expect(2); + var matches = _.matchesProperty('a', -0); - strictEqual(matches({ 'a': 0 }), true); + assert.strictEqual(matches({ 'a': 0 }), true); matches = _.matchesProperty('a', 0); - strictEqual(matches({ 'a': -0 }), true); + assert.strictEqual(matches({ 'a': -0 }), true); }); - test('should compare functions by reference', 3, function() { + QUnit.test('should compare functions by reference', function(assert) { + assert.expect(3); + var object1 = { 'a': _.noop }, object2 = { 'a': noop }, object3 = { 'a': {} }, matches = _.matchesProperty('a', object1); - strictEqual(matches({ 'a': object1 }), true); - strictEqual(matches({ 'a': object2 }), false); - strictEqual(matches({ 'a': object3 }), false); + assert.strictEqual(matches({ 'a': object1 }), true); + assert.strictEqual(matches({ 'a': object2 }), false); + assert.strictEqual(matches({ 'a': object3 }), false); }); - test('should work with a function for `srcValue`', 1, function() { + QUnit.test('should work with a function for `srcValue`', function(assert) { + assert.expect(1); + function Foo() {} Foo.a = 1; Foo.b = function() {}; @@ -10078,32 +11521,38 @@ var objects = [{ 'a': { 'a': 1 } }, { 'a': { 'a': 1, 'b': Foo.b, 'c': 3 } }], actual = _.map(objects, _.matchesProperty('a', Foo)); - deepEqual(actual, [false, true]); + assert.deepEqual(actual, [false, true]); }); - test('should partial match arrays', 3, function() { + QUnit.test('should partial match arrays', function(assert) { + assert.expect(3); + var objects = [{ 'a': ['b'] }, { 'a': ['c', 'd'] }], actual = _.filter(objects, _.matchesProperty('a', ['d'])); - deepEqual(actual, [objects[1]]); + assert.deepEqual(actual, [objects[1]]); actual = _.filter(objects, _.matchesProperty('a', ['b', 'd'])); - deepEqual(actual, []); + assert.deepEqual(actual, []); actual = _.filter(objects, _.matchesProperty('a', ['d', 'b'])); - deepEqual(actual, []); + assert.deepEqual(actual, []); }); - test('should partial match arrays of objects', 1, function() { + QUnit.test('should partial match arrays of objects', function(assert) { + assert.expect(1); + var objects = [ { 'a': [{ 'a': 1, 'b': 2 }, { 'a': 4, 'b': 5, 'c': 6 }] }, { 'a': [{ 'a': 1, 'b': 2 }, { 'a': 4, 'b': 6, 'c': 7 }] } ]; var actual = _.filter(objects, _.matchesProperty('a', [{ 'a': 1 }, { 'a': 4, 'b': 5 }])); - deepEqual(actual, [objects[0]]); + assert.deepEqual(actual, [objects[0]]); }); - test('should partial match maps', 3, function() { + QUnit.test('should partial match maps', function(assert) { + assert.expect(3); + if (Map) { var objects = [{ 'a': new Map }, { 'a': new Map }]; objects[0].a.set('a', 1); @@ -10114,24 +11563,26 @@ map.set('b', 2); var actual = _.filter(objects, _.matchesProperty('a', map)); - deepEqual(actual, [objects[1]]); + assert.deepEqual(actual, [objects[1]]); map['delete']('b'); actual = _.filter(objects, _.matchesProperty('a', map)); - deepEqual(actual, objects); + assert.deepEqual(actual, objects); map.set('c', 3); actual = _.filter(objects, _.matchesProperty('a', map)); - deepEqual(actual, []); + assert.deepEqual(actual, []); } else { - skipTest(3); + skipTest(assert, 3); } }); - test('should partial match sets', 3, function() { + QUnit.test('should partial match sets', function(assert) { + assert.expect(3); + if (Set) { var objects = [{ 'a': new Set }, { 'a': new Set }]; objects[0].a.add(1); @@ -10142,46 +11593,52 @@ set.add(2); var actual = _.filter(objects, _.matchesProperty('a', set)); - deepEqual(actual, [objects[1]]); + assert.deepEqual(actual, [objects[1]]); set['delete'](2); actual = _.filter(objects, _.matchesProperty('a', set)); - deepEqual(actual, objects); + assert.deepEqual(actual, objects); set.add(3); actual = _.filter(objects, _.matchesProperty('a', set)); - deepEqual(actual, []); + assert.deepEqual(actual, []); } else { - skipTest(3); + skipTest(assert, 3); } }); - test('should match properties when `srcValue` is not a plain object', 1, function() { + QUnit.test('should match properties when `srcValue` is not a plain object', function(assert) { + assert.expect(1); + function Foo(object) { _.assign(this, object); } var object = new Foo({ 'a': new Foo({ 'b': 1, 'c': 2 }) }), matches = _.matchesProperty('a', { 'b': 1 }); - strictEqual(matches(object), true); + assert.strictEqual(matches(object), true); }); - test('should match `undefined` values', 2, function() { + QUnit.test('should match `undefined` values', function(assert) { + assert.expect(2); + var objects = [{ 'a': 1 }, { 'a': 1, 'b': 1 }, { 'a': 1, 'b': undefined }], actual = _.map(objects, _.matchesProperty('b', undefined)), expected = [false, false, true]; - deepEqual(actual, expected); + assert.deepEqual(actual, expected); objects = [{ 'a': { 'a': 1 } }, { 'a': { 'a': 1, 'b': 1 } }, { 'a': { 'a': 1, 'b': undefined } }]; actual = _.map(objects, _.matchesProperty('a', { 'b': undefined })); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return `false` when `object` is nullish', 2, function() { + QUnit.test('should return `false` when `object` is nullish', function(assert) { + assert.expect(2); + var values = [, null, undefined], expected = _.map(values, _.constant(false)); @@ -10194,32 +11651,36 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }); - test('should match `undefined` values on primitives', 2, function() { + QUnit.test('should match `undefined` values on primitives', function(assert) { + assert.expect(2); + numberProto.a = 1; numberProto.b = undefined; try { var matches = _.matchesProperty('b', undefined); - strictEqual(matches(1), true); + assert.strictEqual(matches(1), true); } catch (e) { - ok(false, e.message); + assert.ok(false, e.message); } numberProto.a = { 'b': 1, 'c': undefined }; try { matches = _.matchesProperty('a', { 'c': undefined }); - strictEqual(matches(1), true); + assert.strictEqual(matches(1), true); } catch (e) { - ok(false, e.message); + assert.ok(false, e.message); } delete numberProto.a; delete numberProto.b; }); - test('should return `true` when comparing a `srcValue` of empty arrays and objects', 1, function() { + QUnit.test('should return `true` when comparing a `srcValue` of empty arrays and objects', function(assert) { + assert.expect(1); + var objects = [{ 'a': [1], 'b': { 'c': 1 } }, { 'a': [2, 3], 'b': { 'd': 2 } }], matches = _.matchesProperty('a', { 'a': [], 'b': {} }); @@ -10227,15 +11688,17 @@ return matches({ 'a': object }); }); - deepEqual(actual, objects); + assert.deepEqual(actual, objects); }); - test('should not change match behavior if `srcValue` is modified', 9, function() { + QUnit.test('should not change match behavior if `srcValue` is modified', function(assert) { + assert.expect(9); + _.each([{ 'a': { 'b': 2, 'c': 3 } }, { 'a': 1, 'b': 2 }, { 'a': 1 }], function(source, index) { var object = _.cloneDeep(source), matches = _.matchesProperty('a', source); - strictEqual(matches({ 'a': object }), true); + assert.strictEqual(matches({ 'a': object }), true); if (index) { source.a = 2; @@ -10246,8 +11709,8 @@ source.a.c = 2; source.a.d = 3; } - strictEqual(matches({ 'a': object }), true); - strictEqual(matches({ 'a': source }), false); + assert.strictEqual(matches({ 'a': object }), true); + assert.strictEqual(matches({ 'a': source }), false); }); }); }()); @@ -10257,11 +11720,15 @@ QUnit.module('lodash.max'); (function() { - test('should return the largest value from a collection', 1, function() { - strictEqual(_.max([1, 2, 3]), 3); + QUnit.test('should return the largest value from a collection', function(assert) { + assert.expect(1); + + assert.strictEqual(_.max([1, 2, 3]), 3); }); - test('should return `-Infinity` for empty collections', 1, function() { + QUnit.test('should return `-Infinity` for empty collections', function(assert) { + assert.expect(1); + var values = falsey.concat([[]]), expected = _.map(values, _.constant(-Infinity)); @@ -10271,11 +11738,13 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return `-Infinity` for non-numeric collection values', 1, function() { - strictEqual(_.max(['a', 'b']), -Infinity); + QUnit.test('should return `-Infinity` for non-numeric collection values', function(assert) { + assert.expect(1); + + assert.strictEqual(_.max(['a', 'b']), -Infinity); }); }()); @@ -10284,40 +11753,50 @@ QUnit.module('lodash.memoize'); (function() { - test('should memoize results based on the first argument provided', 2, function() { + QUnit.test('should memoize results based on the first argument provided', function(assert) { + assert.expect(2); + var memoized = _.memoize(function(a, b, c) { return a + b + c; }); - strictEqual(memoized(1, 2, 3), 6); - strictEqual(memoized(1, 3, 5), 6); + assert.strictEqual(memoized(1, 2, 3), 6); + assert.strictEqual(memoized(1, 3, 5), 6); }); - test('should support a `resolver` argument', 2, function() { + QUnit.test('should support a `resolver` argument', function(assert) { + assert.expect(2); + var fn = function(a, b, c) { return a + b + c; }, memoized = _.memoize(fn, fn); - strictEqual(memoized(1, 2, 3), 6); - strictEqual(memoized(1, 3, 5), 9); + assert.strictEqual(memoized(1, 2, 3), 6); + assert.strictEqual(memoized(1, 3, 5), 9); }); - test('should use `this` binding of function for `resolver`', 2, function() { + QUnit.test('should use `this` binding of function for `resolver`', function(assert) { + assert.expect(2); + var fn = function(a, b, c) { return a + this.b + this.c; }, memoized = _.memoize(fn, fn); var object = { 'b': 2, 'c': 3, 'memoized': memoized }; - strictEqual(object.memoized(1), 6); + assert.strictEqual(object.memoized(1), 6); object.b = 3; object.c = 5; - strictEqual(object.memoized(1), 9); + assert.strictEqual(object.memoized(1), 9); }); - test('should throw a TypeError if `resolve` is truthy and not a function', function() { - raises(function() { _.memoize(_.noop, {}); }, TypeError); + QUnit.test('should throw a TypeError if `resolve` is truthy and not a function', function(assert) { + assert.expect(1); + + assert.raises(function() { _.memoize(_.noop, {}); }, TypeError); }); - test('should not error if `resolver` is falsey', function() { + QUnit.test('should not error if `resolver` is falsey', function(assert) { + assert.expect(1); + var expected = _.map(falsey, _.constant(true)); var actual = _.map(falsey, function(resolver, index) { @@ -10326,20 +11805,24 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should not set a `this` binding', 2, function() { + QUnit.test('should not set a `this` binding', function(assert) { + assert.expect(2); + var memoized = _.memoize(function(a, b, c) { return a + this.b + this.c; }); var object = { 'b': 2, 'c': 3, 'memoized': memoized }; - strictEqual(object.memoized(1), 6); - strictEqual(object.memoized(2), 7); + assert.strictEqual(object.memoized(1), 6); + assert.strictEqual(object.memoized(2), 7); }); - test('should check cache for own properties', 1, function() { + QUnit.test('should check cache for own properties', function(assert) { + assert.expect(1); + var props = [ 'constructor', 'hasOwnProperty', @@ -10356,10 +11839,12 @@ return memoized(value); }); - deepEqual(actual, props); + assert.deepEqual(actual, props); }); - test('should expose a `cache` object on the `memoized` function which implements `Map` interface', 18, function() { + QUnit.test('should expose a `cache` object on the `memoized` function which implements `Map` interface', function(assert) { + assert.expect(18); + _.times(2, function(index) { var resolver = index ? _.identity : null; @@ -10371,20 +11856,22 @@ memoized('a'); - strictEqual(cache.has('a'), true); - strictEqual(cache.get('a'), 'value:a'); - strictEqual(cache['delete']('a'), true); - strictEqual(cache['delete']('b'), false); + assert.strictEqual(cache.has('a'), true); + assert.strictEqual(cache.get('a'), 'value:a'); + assert.strictEqual(cache['delete']('a'), true); + assert.strictEqual(cache['delete']('b'), false); - strictEqual(cache.set('b', 'value:b'), cache); - strictEqual(cache.has('b'), true); - strictEqual(cache.get('b'), 'value:b'); - strictEqual(cache['delete']('b'), true); - strictEqual(cache['delete']('a'), false); + assert.strictEqual(cache.set('b', 'value:b'), cache); + assert.strictEqual(cache.has('b'), true); + assert.strictEqual(cache.get('b'), 'value:b'); + assert.strictEqual(cache['delete']('b'), true); + assert.strictEqual(cache['delete']('a'), false); }); }); - test('should skip the `__proto__` key', 8, function() { + QUnit.test('should skip the `__proto__` key', function(assert) { + assert.expect(8); + _.times(2, function(index) { var count = 0, key = '__proto__', @@ -10400,14 +11887,16 @@ memoized(key); memoized(key); - strictEqual(count, 2); - strictEqual(cache.get(key), undefined); - strictEqual(cache['delete'](key), false); - ok(!(cache.__data__ instanceof Array)); + assert.strictEqual(count, 2); + assert.strictEqual(cache.get(key), undefined); + assert.strictEqual(cache['delete'](key), false); + assert.notOk(cache.__data__ instanceof Array); }); }); - test('should allow `_.memoize.Cache` to be customized', 5, function() { + QUnit.test('should allow `_.memoize.Cache` to be customized', function(assert) { + assert.expect(5); + var oldCache = _.memoize.Cache; function Cache() { @@ -10454,19 +11943,21 @@ key1 = { 'id': 'a' }, key2 = { 'id': 'b' }; - strictEqual(memoized(key1), 'value:a'); - strictEqual(cache.has(key1), true); + assert.strictEqual(memoized(key1), 'value:a'); + assert.strictEqual(cache.has(key1), true); - strictEqual(memoized(key2), 'value:b'); - strictEqual(cache.has(key2), true); + assert.strictEqual(memoized(key2), 'value:b'); + assert.strictEqual(cache.has(key2), true); cache['delete'](key2); - strictEqual(cache.has(key2), false); + assert.strictEqual(cache.has(key2), false); _.memoize.Cache = oldCache; }); - test('should works with an immutable `_.memoize.Cache` ', 2, function() { + QUnit.test('should works with an immutable `_.memoize.Cache` ', function(assert) { + assert.expect(2); + var oldCache = _.memoize.Cache; function Cache() { @@ -10504,8 +11995,8 @@ memoized(key2); var cache = memoized.cache; - strictEqual(cache.has(key1), true); - strictEqual(cache.has(key2), true); + assert.strictEqual(cache.has(key1), true); + assert.strictEqual(cache.has(key2), true); _.memoize.Cache = oldCache; }); @@ -10518,7 +12009,9 @@ (function() { var args = arguments; - test('should merge `source` into the destination object', 1, function() { + QUnit.test('should merge `source` into the destination object', function(assert) { + assert.expect(1); + var names = { 'characters': [ { 'name': 'barney' }, @@ -10547,10 +12040,12 @@ ] }; - deepEqual(_.merge(names, ages, heights), expected); + assert.deepEqual(_.merge(names, ages, heights), expected); }); - test('should merge sources containing circular references', 1, function() { + QUnit.test('should merge sources containing circular references', function(assert) { + assert.expect(1); + var object = { 'foo': { 'a': 1 }, 'bar': { 'a': 2 } @@ -10565,10 +12060,12 @@ source.bar.b = source.foo.b; var actual = _.merge(object, source); - ok(actual.bar.b === actual.foo.b && actual.foo.b.c.d === actual.foo.b.c.d.foo.b.c.d); + assert.ok(actual.bar.b === actual.foo.b && actual.foo.b.c.d === actual.foo.b.c.d.foo.b.c.d); }); - test('should treat sources that are sparse arrays as dense', 2, function() { + QUnit.test('should treat sources that are sparse arrays as dense', function(assert) { + assert.expect(2); + var array = Array(3); array[0] = 1; array[2] = 3; @@ -10578,11 +12075,13 @@ expected[1] = undefined; - ok('1' in actual); - deepEqual(actual, expected); + assert.ok('1' in actual); + assert.deepEqual(actual, expected); }); - test('should skip `undefined` values in arrays if a destination value exists', 2, function() { + QUnit.test('should skip `undefined` values in arrays if a destination value exists', function(assert) { + assert.expect(2); + var array = Array(3); array[0] = 1; array[2] = 3; @@ -10590,30 +12089,34 @@ var actual = _.merge([4, 5, 6], array), expected = [1, 5, 3]; - deepEqual(actual, expected); + assert.deepEqual(actual, expected); array = [1, , 3]; array[1] = undefined; actual = _.merge([4, 5, 6], array); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should merge `arguments` objects', 3, function() { + QUnit.test('should merge `arguments` objects', function(assert) { + assert.expect(3); + var object1 = { 'value': args }, object2 = { 'value': { '3': 4 } }, expected = { '0': 1, '1': 2, '2': 3, '3': 4 }, actual = _.merge(object1, object2); - ok(!_.isArguments(actual.value)); - deepEqual(actual.value, expected); + assert.notOk(_.isArguments(actual.value)); + assert.deepEqual(actual.value, expected); delete object1.value[3]; actual = _.merge(object2, object1); - deepEqual(actual.value, expected); + assert.deepEqual(actual.value, expected); }); - test('should merge typed arrays', 4, function() { + QUnit.test('should merge typed arrays', function(assert) { + assert.expect(4); + var array1 = [0], array2 = [0, 0], array3 = [0, 0, 0, 0], @@ -10637,8 +12140,8 @@ return Ctor ? _.merge({ 'value': new Ctor(buffer) }, { 'value': [1] }) : false; }); - ok(_.isArray(actual)); - deepEqual(actual, expected); + assert.ok(_.isArray(actual)); + assert.deepEqual(actual, expected); expected = _.map(typedArrays, function(type, index) { var array = arrays[index].slice(); @@ -10654,28 +12157,36 @@ return Ctor ? _.merge({ 'value': array }, { 'value': new Ctor(buffer) }) : false; }); - ok(_.isArray(actual)); - deepEqual(actual, expected); + assert.ok(_.isArray(actual)); + assert.deepEqual(actual, expected); }); - test('should work with four arguments', 1, function() { + QUnit.test('should work with four arguments', function(assert) { + assert.expect(1); + var expected = { 'a': 4 }, actual = _.merge({ 'a': 1 }, { 'a': 2 }, { 'a': 3 }, expected); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should assign `null` values', 1, function() { + QUnit.test('should assign `null` values', function(assert) { + assert.expect(1); + var actual = _.merge({ 'a': 1 }, { 'a': null }); - strictEqual(actual.a, null); + assert.strictEqual(actual.a, null); }); - test('should not assign `undefined` values', 1, function() { + QUnit.test('should not assign `undefined` values', function(assert) { + assert.expect(1); + var actual = _.merge({ 'a': 1 }, { 'a': undefined, 'b': undefined }); - deepEqual(actual, { 'a': 1 }); + assert.deepEqual(actual, { 'a': 1 }); }); - test('should not error on DOM elements', 1, function() { + QUnit.test('should not error on DOM elements', function(assert) { + assert.expect(1); + var object1 = { 'el': document && document.createElement('div') }, object2 = { 'el': document && document.createElement('div') }, pairs = [[{}, object1], [object1, object2]], @@ -10687,10 +12198,12 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should assign non array/plain-object values directly', 1, function() { + QUnit.test('should assign non array/plain-object values directly', function(assert) { + assert.expect(1); + function Foo() {} var values = [new Foo, new Boolean, new Date, Foo, new Number, new String, new RegExp], @@ -10701,10 +12214,12 @@ return object.a === value; }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should merge plain-objects onto non plain-objects', 4, function() { + QUnit.test('should merge plain-objects onto non plain-objects', function(assert) { + assert.expect(4); + function Foo(object) { _.assign(this, object); } @@ -10712,61 +12227,71 @@ var object = { 'a': 1 }, actual = _.merge(new Foo, object); - ok(actual instanceof Foo); - deepEqual(actual, new Foo(object)); + assert.ok(actual instanceof Foo); + assert.deepEqual(actual, new Foo(object)); actual = _.merge([new Foo], [object]); - ok(actual[0] instanceof Foo); - deepEqual(actual, [new Foo(object)]); + assert.ok(actual[0] instanceof Foo); + assert.deepEqual(actual, [new Foo(object)]); }); - test('should convert values to arrays when merging with arrays of `source`', 2, function() { + QUnit.test('should convert values to arrays when merging with arrays of `source`', function(assert) { + assert.expect(2); + var object = { 'a': { '1': 'y', 'b': 'z', 'length': 2 } }, actual = _.merge(object, { 'a': ['x'] }); - deepEqual(actual, { 'a': ['x', 'y'] }); + assert.deepEqual(actual, { 'a': ['x', 'y'] }); actual = _.merge({ 'a': {} }, { 'a': [] }); - deepEqual(actual, { 'a': [] }); + assert.deepEqual(actual, { 'a': [] }); }); - test('should not convert strings to arrays when merging with arrays of `source`', 1, function() { + QUnit.test('should not convert strings to arrays when merging with arrays of `source`', function(assert) { + assert.expect(1); + var object = { 'a': 'abcdef' }, actual = _.merge(object, { 'a': ['x', 'y', 'z'] }); - deepEqual(actual, { 'a': ['x', 'y', 'z'] }); + assert.deepEqual(actual, { 'a': ['x', 'y', 'z'] }); }); - test('should work with a function for `object`', 2, function() { + QUnit.test('should work with a function for `object`', function(assert) { + assert.expect(2); + function Foo() {} var source = { 'a': 1 }, actual = _.merge(Foo, source); - strictEqual(actual, Foo); - strictEqual(Foo.a, 1); + assert.strictEqual(actual, Foo); + assert.strictEqual(Foo.a, 1); }); - test('should work with a non-plain `object` value', 2, function() { + QUnit.test('should work with a non-plain `object` value', function(assert) { + assert.expect(2); + function Foo() {} var object = new Foo, source = { 'a': 1 }, actual = _.merge(object, source); - strictEqual(actual, object); - strictEqual(object.a, 1); + assert.strictEqual(actual, object); + assert.strictEqual(object.a, 1); }); - test('should pass thru primitive `object` values', 1, function() { + QUnit.test('should pass thru primitive `object` values', function(assert) { + assert.expect(1); + var values = [true, 1, '1']; var actual = _.map(values, function(value) { return _.merge(value, { 'a': 1 }); }); - deepEqual(actual, values); + assert.deepEqual(actual, values); }); }(1, 2, 3)); @@ -10775,20 +12300,24 @@ QUnit.module('lodash.mergeWith'); (function() { - test('should handle merging if `customizer` returns `undefined`', 2, function() { + QUnit.test('should handle merging if `customizer` returns `undefined`', function(assert) { + assert.expect(2); + var actual = _.mergeWith({ 'a': { 'b': [1, 1] } }, { 'a': { 'b': [0] } }, _.noop); - deepEqual(actual, { 'a': { 'b': [0, 1] } }); + assert.deepEqual(actual, { 'a': { 'b': [0, 1] } }); actual = _.mergeWith([], [undefined], _.identity); - deepEqual(actual, [undefined]); + assert.deepEqual(actual, [undefined]); }); - test('should defer to `customizer` when it returns a value other than `undefined`', 1, function() { + QUnit.test('should defer to `customizer` when it returns a value other than `undefined`', function(assert) { + assert.expect(1); + var actual = _.mergeWith({ 'a': { 'b': [0, 1] } }, { 'a': { 'b': [2] } }, function(a, b) { return _.isArray(a) ? a.concat(b) : undefined; }); - deepEqual(actual, { 'a': { 'b': [0, 1, 2] } }); + assert.deepEqual(actual, { 'a': { 'b': [0, 1, 2] } }); }); }()); @@ -10797,35 +12326,43 @@ QUnit.module('lodash.method'); (function() { - test('should create a function that calls a method of a given object', 4, function() { + QUnit.test('should create a function that calls a method of a given object', function(assert) { + assert.expect(4); + var object = { 'a': _.constant(1) }; _.each(['a', ['a']], function(path) { var method = _.method(path); - strictEqual(method.length, 1); - strictEqual(method(object), 1); + assert.strictEqual(method.length, 1); + assert.strictEqual(method(object), 1); }); }); - test('should work with deep property values', 2, function() { + QUnit.test('should work with deep property values', function(assert) { + assert.expect(2); + var object = { 'a': { 'b': { 'c': _.constant(3) } } }; _.each(['a.b.c', ['a', 'b', 'c']], function(path) { var method = _.method(path); - strictEqual(method(object), 3); + assert.strictEqual(method(object), 3); }); }); - test('should work with non-string `path` arguments', 2, function() { + QUnit.test('should work with non-string `path` arguments', function(assert) { + assert.expect(2); + var array = _.times(3, _.constant); _.each([1, [1]], function(path) { var method = _.method(path); - strictEqual(method(array), 1); + assert.strictEqual(method(array), 1); }); }); - test('should coerce key to a string', 1, function() { + QUnit.test('should coerce key to a string', function(assert) { + assert.expect(1); + function fn() {} fn.toString = _.constant('fn'); @@ -10841,29 +12378,35 @@ }); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work with inherited property values', 2, function() { + QUnit.test('should work with inherited property values', function(assert) { + assert.expect(2); + function Foo() {} Foo.prototype.a = _.constant(1); _.each(['a', ['a']], function(path) { var method = _.method(path); - strictEqual(method(new Foo), 1); + assert.strictEqual(method(new Foo), 1); }); }); - test('should use a key over a path', 2, function() { + QUnit.test('should use a key over a path', function(assert) { + assert.expect(2); + var object = { 'a.b.c': _.constant(3), 'a': { 'b': { 'c': _.constant(4) } } }; _.each(['a.b.c', ['a.b.c']], function(path) { var method = _.method(path); - strictEqual(method(object), 3); + assert.strictEqual(method(object), 3); }); }); - test('should return `undefined` when `object` is nullish', 2, function() { + QUnit.test('should return `undefined` when `object` is nullish', function(assert) { + assert.expect(2); + var values = [, null, undefined], expected = _.map(values, _.constant(undefined)); @@ -10874,11 +12417,13 @@ return index ? method(value) : method(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }); - test('should return `undefined` with deep paths when `object` is nullish', 2, function() { + QUnit.test('should return `undefined` with deep paths when `object` is nullish', function(assert) { + assert.expect(2); + var values = [, null, undefined], expected = _.map(values, _.constant(undefined)); @@ -10889,20 +12434,24 @@ return index ? method(value) : method(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }); - test('should return `undefined` if parts of `path` are missing', 4, function() { + QUnit.test('should return `undefined` if parts of `path` are missing', function(assert) { + assert.expect(4); + var object = {}; _.each(['a', 'a[1].b.c', ['a'], ['a', '1', 'b', 'c']], function(path) { var method = _.method(path); - strictEqual(method(object), undefined); + assert.strictEqual(method(object), undefined); }); }); - test('should apply partial arguments to function', 2, function() { + QUnit.test('should apply partial arguments to function', function(assert) { + assert.expect(2); + var object = { 'fn': function() { return slice.call(arguments); @@ -10911,16 +12460,18 @@ _.each(['fn', ['fn']], function(path) { var method = _.method(path, 1, 2, 3); - deepEqual(method(object), [1, 2, 3]); + assert.deepEqual(method(object), [1, 2, 3]); }); }); - test('should invoke deep property methods with the correct `this` binding', 2, function() { + QUnit.test('should invoke deep property methods with the correct `this` binding', function(assert) { + assert.expect(2); + var object = { 'a': { 'b': function() { return this.c; }, 'c': 1 } }; _.each(['a.b', ['a', 'b']], function(path) { var method = _.method(path); - strictEqual(method(object), 1); + assert.strictEqual(method(object), 1); }); }); }()); @@ -10930,35 +12481,43 @@ QUnit.module('lodash.methodOf'); (function() { - test('should create a function that calls a method of a given key', 4, function() { + QUnit.test('should create a function that calls a method of a given key', function(assert) { + assert.expect(4); + var object = { 'a': _.constant(1) }; _.each(['a', ['a']], function(path) { var methodOf = _.methodOf(object); - strictEqual(methodOf.length, 1); - strictEqual(methodOf(path), 1); + assert.strictEqual(methodOf.length, 1); + assert.strictEqual(methodOf(path), 1); }); }); - test('should work with deep property values', 2, function() { + QUnit.test('should work with deep property values', function(assert) { + assert.expect(2); + var object = { 'a': { 'b': { 'c': _.constant(3) } } }; _.each(['a.b.c', ['a', 'b', 'c']], function(path) { var methodOf = _.methodOf(object); - strictEqual(methodOf(path), 3); + assert.strictEqual(methodOf(path), 3); }); }); - test('should work with non-string `path` arguments', 2, function() { + QUnit.test('should work with non-string `path` arguments', function(assert) { + assert.expect(2); + var array = _.times(3, _.constant); _.each([1, [1]], function(path) { var methodOf = _.methodOf(array); - strictEqual(methodOf(path), 1); + assert.strictEqual(methodOf(path), 1); }); }); - test('should coerce key to a string', 1, function() { + QUnit.test('should coerce key to a string', function(assert) { + assert.expect(1); + function fn() {} fn.toString = _.constant('fn'); @@ -10974,29 +12533,35 @@ }); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work with inherited property values', 2, function() { + QUnit.test('should work with inherited property values', function(assert) { + assert.expect(2); + function Foo() {} Foo.prototype.a = _.constant(1); _.each(['a', ['a']], function(path) { var methodOf = _.methodOf(new Foo); - strictEqual(methodOf(path), 1); + assert.strictEqual(methodOf(path), 1); }); }); - test('should use a key over a path', 2, function() { + QUnit.test('should use a key over a path', function(assert) { + assert.expect(2); + var object = { 'a.b.c': _.constant(3), 'a': { 'b': { 'c': _.constant(4) } } }; _.each(['a.b.c', ['a.b.c']], function(path) { var methodOf = _.methodOf(object); - strictEqual(methodOf(path), 3); + assert.strictEqual(methodOf(path), 3); }); }); - test('should return `undefined` when `object` is nullish', 2, function() { + QUnit.test('should return `undefined` when `object` is nullish', function(assert) { + assert.expect(2); + var values = [, null, undefined], expected = _.map(values, _.constant(undefined)); @@ -11006,11 +12571,13 @@ return methodOf(path); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }); - test('should return `undefined` with deep paths when `object` is nullish', 2, function() { + QUnit.test('should return `undefined` with deep paths when `object` is nullish', function(assert) { + assert.expect(2); + var values = [, null, undefined], expected = _.map(values, _.constant(undefined)); @@ -11020,20 +12587,24 @@ return methodOf(path); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }); - test('should return `undefined` if parts of `path` are missing', 4, function() { + QUnit.test('should return `undefined` if parts of `path` are missing', function(assert) { + assert.expect(4); + var object = {}, methodOf = _.methodOf(object); _.each(['a', 'a[1].b.c', ['a'], ['a', '1', 'b', 'c']], function(path) { - strictEqual(methodOf(path), undefined); + assert.strictEqual(methodOf(path), undefined); }); }); - test('should apply partial arguments to function', 2, function() { + QUnit.test('should apply partial arguments to function', function(assert) { + assert.expect(2); + var object = { 'fn': function() { return slice.call(arguments); @@ -11043,16 +12614,18 @@ var methodOf = _.methodOf(object, 1, 2, 3); _.each(['fn', ['fn']], function(path) { - deepEqual(methodOf(path), [1, 2, 3]); + assert.deepEqual(methodOf(path), [1, 2, 3]); }); }); - test('should invoke deep property methods with the correct `this` binding', 2, function() { + QUnit.test('should invoke deep property methods with the correct `this` binding', function(assert) { + assert.expect(2); + var object = { 'a': { 'b': function() { return this.c; }, 'c': 1 } }, methodOf = _.methodOf(object); _.each(['a.b', ['a', 'b']], function(path) { - strictEqual(methodOf(path), 1); + assert.strictEqual(methodOf(path), 1); }); }); }()); @@ -11062,11 +12635,15 @@ QUnit.module('lodash.min'); (function() { - test('should return the smallest value from a collection', 1, function() { - strictEqual(_.min([1, 2, 3]), 1); + QUnit.test('should return the smallest value from a collection', function(assert) { + assert.expect(1); + + assert.strictEqual(_.min([1, 2, 3]), 1); }); - test('should return `Infinity` for empty collections', 1, function() { + QUnit.test('should return `Infinity` for empty collections', function(assert) { + assert.expect(1); + var values = falsey.concat([[]]), expected = _.map(values, _.constant(Infinity)); @@ -11076,11 +12653,13 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return `Infinity` for non-numeric collection values', 1, function() { - strictEqual(_.min(['a', 'b']), Infinity); + QUnit.test('should return `Infinity` for non-numeric collection values', function(assert) { + assert.expect(1); + + assert.strictEqual(_.min(['a', 'b']), Infinity); }); }()); @@ -11093,25 +12672,31 @@ func = _[methodName], isMax = /^max/.test(methodName); - test('`_.' + methodName + '` should work with Date objects', 1, function() { + QUnit.test('`_.' + methodName + '` should work with Date objects', function(assert) { + assert.expect(1); + var curr = new Date, past = new Date(0); - strictEqual(func([curr, past]), isMax ? curr : past); + assert.strictEqual(func([curr, past]), isMax ? curr : past); }); - test('`_.' + methodName + '` should work with extremely large arrays', 1, function() { + QUnit.test('`_.' + methodName + '` should work with extremely large arrays', function(assert) { + assert.expect(1); + var array = _.range(0, 5e5); - strictEqual(func(array), isMax ? 499999 : 0); + assert.strictEqual(func(array), isMax ? 499999 : 0); }); - test('`_.' + methodName + '` should work when chaining on an array with only one value', 1, function() { + QUnit.test('`_.' + methodName + '` should work when chaining on an array with only one value', function(assert) { + assert.expect(1); + if (!isNpm) { var actual = _([40])[methodName](); - strictEqual(actual, 40); + assert.strictEqual(actual, 40); } else { - skipTest(); + skipTest(assert); } }); }); @@ -11121,27 +12706,33 @@ func = _[methodName], isMax = methodName == 'maxBy'; - test('`_.' + methodName + '` should work with an `iteratee` argument', 1, function() { + QUnit.test('`_.' + methodName + '` should work with an `iteratee` argument', function(assert) { + assert.expect(1); + var actual = func(array, function(num) { return -num; }); - strictEqual(actual, isMax ? 1 : 3); + assert.strictEqual(actual, isMax ? 1 : 3); }); - test('should work with a "_.property" style `iteratee`', 2, function() { + QUnit.test('should work with a "_.property" style `iteratee`', function(assert) { + assert.expect(2); + var objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }], actual = func(objects, 'a'); - deepEqual(actual, objects[isMax ? 1 : 2]); + assert.deepEqual(actual, objects[isMax ? 1 : 2]); var arrays = [[2], [3], [1]]; actual = func(arrays, 0); - deepEqual(actual, arrays[isMax ? 1 : 2]); + assert.deepEqual(actual, arrays[isMax ? 1 : 2]); }); - test('`_.' + methodName + '` should work when `iteratee` returns +/-Infinity', 1, function() { + QUnit.test('`_.' + methodName + '` should work when `iteratee` returns +/-Infinity', function(assert) { + assert.expect(1); + var value = isMax ? -Infinity : Infinity, object = { 'a': value }; @@ -11149,7 +12740,7 @@ return object.a; }); - strictEqual(actual, object); + assert.strictEqual(actual, object); }); }); @@ -11180,51 +12771,57 @@ var array = ['a'], source = { 'a': function(array) { return array[0]; }, 'b': 'B' }; - test('should mixin `source` methods into lodash', 4, function() { + QUnit.test('should mixin `source` methods into lodash', function(assert) { + assert.expect(4); + if (!isNpm) { _.mixin(source); - strictEqual(_.a(array), 'a'); - strictEqual(_(array).a().value(), 'a'); + assert.strictEqual(_.a(array), 'a'); + assert.strictEqual(_(array).a().value(), 'a'); delete _.a; delete _.prototype.a; - ok(!('b' in _)); - ok(!('b' in _.prototype)); + assert.notOk('b' in _); + assert.notOk('b' in _.prototype); delete _.b; delete _.prototype.b; } else { - skipTest(4); + skipTest(assert, 4); } }); - test('should mixin chaining methods by reference', 2, function() { + QUnit.test('should mixin chaining methods by reference', function(assert) { + assert.expect(2); + if (!isNpm) { _.mixin(source); _.a = _.constant('b'); - strictEqual(_.a(array), 'b'); - strictEqual(_(array).a().value(), 'a'); + assert.strictEqual(_.a(array), 'b'); + assert.strictEqual(_(array).a().value(), 'a'); delete _.a; delete _.prototype.a; } else { - skipTest(2); + skipTest(assert, 2); } }); - test('should use `this` as the default `object` value', 3, function() { + QUnit.test('should use `this` as the default `object` value', function(assert) { + assert.expect(3); + var object = _.create(_); object.mixin(source); - strictEqual(object.a(array), 'a'); + assert.strictEqual(object.a(array), 'a'); - ok(!('a' in _)); - ok(!('a' in _.prototype)); + assert.notOk('a' in _); + assert.notOk('a' in _.prototype); delete Wrapper.a; delete Wrapper.prototype.a; @@ -11232,26 +12829,32 @@ delete Wrapper.prototype.b; }); - test('should accept an `object` argument', 1, function() { + QUnit.test('should accept an `object` argument', function(assert) { + assert.expect(1); + var object = {}; _.mixin(object, source); - strictEqual(object.a(array), 'a'); + assert.strictEqual(object.a(array), 'a'); }); - test('should return `object`', 2, function() { + QUnit.test('should return `object`', function(assert) { + assert.expect(2); + var object = {}; - strictEqual(_.mixin(object, source), object); - strictEqual(_.mixin(), _); + assert.strictEqual(_.mixin(object, source), object); + assert.strictEqual(_.mixin(), _); }); - test('should work with a function for `object`', 2, function() { + QUnit.test('should work with a function for `object`', function(assert) { + assert.expect(2); + _.mixin(Wrapper, source); var wrapped = Wrapper(array), actual = wrapped.a(); - strictEqual(actual.value(), 'a'); - ok(actual instanceof Wrapper); + assert.strictEqual(actual.value(), 'a'); + assert.ok(actual instanceof Wrapper); delete Wrapper.a; delete Wrapper.prototype.a; @@ -11259,15 +12862,19 @@ delete Wrapper.prototype.b; }); - test('should not assign inherited `source` methods', 1, function() { + QUnit.test('should not assign inherited `source` methods', function(assert) { + assert.expect(1); + function Foo() {} Foo.prototype.a = _.noop; var object = {}; - strictEqual(_.mixin(object, new Foo), object); + assert.strictEqual(_.mixin(object, new Foo), object); }); - test('should accept an `options` argument', 8, function() { + QUnit.test('should accept an `options` argument', function(assert) { + assert.expect(8); + function message(func, chain) { return (func === _ ? 'lodash' : 'provided') + ' function should ' + (chain ? '' : 'not ') + 'chain'; } @@ -11284,11 +12891,11 @@ actual = wrapped.a(); if (options.chain) { - strictEqual(actual.value(), 'a', message(func, true)); - ok(actual instanceof func, message(func, true)); + assert.strictEqual(actual.value(), 'a', message(func, true)); + assert.ok(actual instanceof func, message(func, true)); } else { - strictEqual(actual, 'a', message(func, false)); - ok(!(actual instanceof func), message(func, false)); + assert.strictEqual(actual, 'a', message(func, false)); + assert.notOk(actual instanceof func, message(func, false)); } delete func.a; delete func.prototype.a; @@ -11296,19 +12903,23 @@ delete func.prototype.b; } else { - skipTest(2); + skipTest(assert, 2); } }); }); }); - test('should not extend lodash when an `object` is provided with an empty `options` object', 1, function() { + QUnit.test('should not extend lodash when an `object` is provided with an empty `options` object', function(assert) { + assert.expect(1); + _.mixin({ 'a': _.noop }, {}); - ok(!('a' in _)); + assert.notOk('a' in _); delete _.a; }); - test('should not error for non-object `options` values', 2, function() { + QUnit.test('should not error for non-object `options` values', function(assert) { + assert.expect(2); + var pass = true; try { @@ -11316,7 +12927,7 @@ } catch (e) { pass = false; } - ok(pass); + assert.ok(pass); pass = true; @@ -11330,22 +12941,24 @@ delete _.b; delete _.prototype.b; - ok(pass); + assert.ok(pass); }); - test('should not return the existing wrapped value when chaining', 2, function() { + QUnit.test('should not return the existing wrapped value when chaining', function(assert) { + assert.expect(2); + _.each([_, Wrapper], function(func) { if (!isNpm) { if (func === _) { var wrapped = _(source), actual = wrapped.mixin(); - strictEqual(actual.value(), _); + assert.strictEqual(actual.value(), _); } else { wrapped = _(func); actual = wrapped.mixin(source); - notStrictEqual(actual, wrapped); + assert.notStrictEqual(actual, wrapped); } delete func.a; delete func.prototype.a; @@ -11353,19 +12966,21 @@ delete func.prototype.b; } else { - skipTest(); + skipTest(assert); } }); }); - test('should produce methods that work in a lazy chain sequence', 1, function() { + QUnit.test('should produce methods that work in a lazy chain sequence', function(assert) { + assert.expect(1); + if (!isNpm) { _.mixin({ 'a': _.countBy, 'b': _.filter }); var array = _.range(LARGE_ARRAY_SIZE), actual = _(array).a().map(square).b(isEven).take().value(); - deepEqual(actual, _.take(_.b(_.map(_.a(array), square), isEven))); + assert.deepEqual(actual, _.take(_.b(_.map(_.a(array), square), isEven))); delete _.a; delete _.prototype.a; @@ -11373,7 +12988,7 @@ delete _.prototype.b; } else { - skipTest(); + skipTest(assert); } }); }()); @@ -11387,41 +13002,55 @@ return slice.call(arguments); } - test('should transform each argument', 1, function() { + QUnit.test('should transform each argument', function(assert) { + assert.expect(1); + var modded = _.modArgs(fn, doubled, square); - deepEqual(modded(5, 10), [10, 100]); + assert.deepEqual(modded(5, 10), [10, 100]); }); - test('should flatten `transforms`', 1, function() { + QUnit.test('should flatten `transforms`', function(assert) { + assert.expect(1); + var modded = _.modArgs(fn, [doubled, square], String); - deepEqual(modded(5, 10, 15), [10, 100, '15']); + assert.deepEqual(modded(5, 10, 15), [10, 100, '15']); }); - test('should not transform any argument greater than the number of transforms', 1, function() { + QUnit.test('should not transform any argument greater than the number of transforms', function(assert) { + assert.expect(1); + var modded = _.modArgs(fn, doubled, square); - deepEqual(modded(5, 10, 18), [10, 100, 18]); + assert.deepEqual(modded(5, 10, 18), [10, 100, 18]); }); - test('should not transform any arguments if no transforms are provided', 1, function() { + QUnit.test('should not transform any arguments if no transforms are provided', function(assert) { + assert.expect(1); + var modded = _.modArgs(fn); - deepEqual(modded(5, 10, 18), [5, 10, 18]); + assert.deepEqual(modded(5, 10, 18), [5, 10, 18]); }); - test('should not pass `undefined` if there are more transforms than arguments', 1, function() { + QUnit.test('should not pass `undefined` if there are more transforms than arguments', function(assert) { + assert.expect(1); + var modded = _.modArgs(fn, doubled, _.identity); - deepEqual(modded(5), [10]); + assert.deepEqual(modded(5), [10]); }); - test('should provide the correct argument to each transform', 1, function() { + QUnit.test('should provide the correct argument to each transform', function(assert) { + assert.expect(1); + var argsList = [], transform = function() { argsList.push(slice.call(arguments)); }, modded = _.modArgs(_.noop, transform, transform, transform); modded('a', 'b', 'c'); - deepEqual(argsList, [['a'], ['b'], ['c']]); + assert.deepEqual(argsList, [['a'], ['b'], ['c']]); }); - test('should use `this` binding of function for transforms', 1, function() { + QUnit.test('should use `this` binding of function for transforms', function(assert) { + assert.expect(1); + var modded = _.modArgs(function(x) { return this[x]; }, function(x) { @@ -11429,7 +13058,7 @@ }); var object = { 'modded': modded, 'true': 1 }; - strictEqual(object.modded(object), 1); + assert.strictEqual(object.modded(object), 1); }); }()); @@ -11438,11 +13067,13 @@ QUnit.module('lodash.negate'); (function() { - test('should create a function that negates the result of `func`', 2, function() { + QUnit.test('should create a function that negates the result of `func`', function(assert) { + assert.expect(2); + var negate = _.negate(isEven); - strictEqual(negate(1), true); - strictEqual(negate(2), false); + assert.strictEqual(negate(1), true); + assert.strictEqual(negate(2), false); }); }()); @@ -11451,7 +13082,9 @@ QUnit.module('lodash.noop'); (function() { - test('should return `undefined`', 1, function() { + QUnit.test('should return `undefined`', function(assert) { + assert.expect(1); + var values = empties.concat(true, new Date, _, 1, /x/, 'a'), expected = _.map(values, _.constant()); @@ -11459,7 +13092,7 @@ return index ? _.noop(value) : _.noop(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }()); @@ -11468,24 +13101,28 @@ QUnit.module('lodash.noConflict'); (function() { - test('should return the `lodash` function', 2, function() { + QUnit.test('should return the `lodash` function', function(assert) { + assert.expect(2); + if (!isModularize) { - strictEqual(_.noConflict(), oldDash); + assert.strictEqual(_.noConflict(), oldDash); if (!(isRhino && typeof require == 'function')) { - notStrictEqual(root._, oldDash); + assert.notStrictEqual(root._, oldDash); } else { - skipTest(); + skipTest(assert); } root._ = oldDash; } else { - skipTest(2); + skipTest(assert, 2); } }); - test('should work with a `root` of `this`', 2, function() { + QUnit.test('should work with a `root` of `this`', function(assert) { + assert.expect(2); + if (!isModularize && !document && _._object) { var fs = require('fs'), vm = require('vm'), @@ -11495,11 +13132,11 @@ vm.runInContext(source + '\nthis.lodash = this._.noConflict()', context); - strictEqual(context._, expected); - ok(!!context.lodash); + assert.strictEqual(context._, expected); + assert.ok(!!context.lodash); } else { - skipTest(2); + skipTest(assert, 2); } }); }()); @@ -11509,20 +13146,22 @@ QUnit.module('lodash.now'); (function() { - asyncTest('should return the number of milliseconds that have elapsed since the Unix epoch', 2, function() { + QUnit.asyncTest('should return the number of milliseconds that have elapsed since the Unix epoch', function(assert) { + assert.expect(2); + var stamp = +new Date, actual = _.now(); - ok(actual >= stamp); + assert.ok(actual >= stamp); if (!(isRhino && isModularize)) { setTimeout(function() { - ok(_.now() > actual); + assert.ok(_.now() > actual); QUnit.start(); }, 32); } else { - skipTest(); + skipTest(assert); QUnit.start(); } }); @@ -11536,35 +13175,45 @@ var args = arguments, object = { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }; - test('should flatten `props`', 2, function() { - deepEqual(_.omit(object, 'a', 'c'), { 'b': 2, 'd': 4 }); - deepEqual(_.omit(object, ['a', 'd'], 'c'), { 'b': 2 }); + QUnit.test('should flatten `props`', function(assert) { + assert.expect(2); + + assert.deepEqual(_.omit(object, 'a', 'c'), { 'b': 2, 'd': 4 }); + assert.deepEqual(_.omit(object, ['a', 'd'], 'c'), { 'b': 2 }); }); - test('should work with a primitive `object` argument', 1, function() { + QUnit.test('should work with a primitive `object` argument', function(assert) { + assert.expect(1); + stringProto.a = 1; stringProto.b = 2; - deepEqual(_.omit('', 'b'), { 'a': 1 }); + assert.deepEqual(_.omit('', 'b'), { 'a': 1 }); delete stringProto.a; delete stringProto.b; }); - test('should return an empty object when `object` is nullish', 2, function() { + QUnit.test('should return an empty object when `object` is nullish', function(assert) { + assert.expect(2); + objectProto.a = 1; _.each([null, undefined], function(value) { - deepEqual(_.omit(value, 'valueOf'), {}); + assert.deepEqual(_.omit(value, 'valueOf'), {}); }); delete objectProto.a; }); - test('should work with `arguments` objects as secondary arguments', 1, function() { - deepEqual(_.omit(object, args), { 'b': 2, 'd': 4 }); + QUnit.test('should work with `arguments` objects as secondary arguments', function(assert) { + assert.expect(1); + + assert.deepEqual(_.omit(object, args), { 'b': 2, 'd': 4 }); }); - test('should coerce property names to strings', 1, function() { - deepEqual(_.omit({ '0': 'a' }, 0), {}); + QUnit.test('should coerce property names to strings', function(assert) { + assert.expect(1); + + assert.deepEqual(_.omit({ '0': 'a' }, 0), {}); }); }('a', 'c')); @@ -11573,14 +13222,16 @@ QUnit.module('lodash.omitBy'); (function() { - test('should work with a predicate argument', 1, function() { + QUnit.test('should work with a predicate argument', function(assert) { + assert.expect(1); + var object = { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }; var actual = _.omitBy(object, function(num) { return num != 2 && num != 4; }); - deepEqual(actual, { 'b': 2, 'd': 4 }); + assert.deepEqual(actual, { 'b': 2, 'd': 4 }); }); }()); @@ -11602,22 +13253,28 @@ }; }; } - test('`_.' + methodName + '` should create an object with omitted properties', 2, function() { - deepEqual(func(object, prop(object, 'a')), { 'b': 2, 'c': 3, 'd': 4 }); - deepEqual(func(object, prop(object, ['a', 'c'])), expected); + QUnit.test('`_.' + methodName + '` should create an object with omitted properties', function(assert) { + assert.expect(2); + + assert.deepEqual(func(object, prop(object, 'a')), { 'b': 2, 'c': 3, 'd': 4 }); + assert.deepEqual(func(object, prop(object, ['a', 'c'])), expected); }); - test('`_.' + methodName + '` should iterate over inherited properties', 1, function() { + QUnit.test('`_.' + methodName + '` should iterate over inherited properties', function(assert) { + assert.expect(1); + function Foo() {} Foo.prototype = object; var foo = new Foo; - deepEqual(func(foo, prop(object, ['a', 'c'])), expected); + assert.deepEqual(func(foo, prop(object, ['a', 'c'])), expected); }); - test('`_.' + methodName + '` should work with an array `object` argument', 1, function() { + QUnit.test('`_.' + methodName + '` should work with an array `object` argument', function(assert) { + assert.expect(1); + var array = [1, 2, 3]; - deepEqual(func(array, prop(array, ['0', '2'])), { '1': 2 }); + assert.deepEqual(func(array, prop(array, ['0', '2'])), { '1': 2 }); }); }); @@ -11626,25 +13283,31 @@ QUnit.module('lodash.once'); (function() { - test('should invoke `func` once', 2, function() { + QUnit.test('should invoke `func` once', function(assert) { + assert.expect(2); + var count = 0, once = _.once(function() { return ++count; }); once(); - strictEqual(once(), 1); - strictEqual(count, 1); + assert.strictEqual(once(), 1); + assert.strictEqual(count, 1); }); - test('should not set a `this` binding', 2, function() { + QUnit.test('should not set a `this` binding', function(assert) { + assert.expect(2); + var once = _.once(function() { return ++this.count; }), object = { 'count': 0, 'once': once }; object.once(); - strictEqual(object.once(), 1); - strictEqual(object.count, 1); + assert.strictEqual(object.once(), 1); + assert.strictEqual(object.count, 1); }); - test('should ignore recursive calls', 2, function() { + QUnit.test('should ignore recursive calls', function(assert) { + assert.expect(2); + var count = 0; var once = _.once(function() { @@ -11652,25 +13315,27 @@ return ++count; }); - strictEqual(once(), 1); - strictEqual(count, 1); + assert.strictEqual(once(), 1); + assert.strictEqual(count, 1); }); - test('should not throw more than once', 2, function() { + QUnit.test('should not throw more than once', function(assert) { + assert.expect(2); + var pass = true; var once = _.once(function() { throw new Error; }); - raises(function() { once(); }, Error); + assert.raises(function() { once(); }, Error); try { once(); } catch (e) { pass = false; } - ok(pass); + assert.ok(pass); }); }()); @@ -11679,18 +13344,24 @@ QUnit.module('lodash.pad'); (function() { - test('should pad a string to a given length', 1, function() { - strictEqual(_.pad('abc', 9), ' abc '); + QUnit.test('should pad a string to a given length', function(assert) { + assert.expect(1); + + assert.strictEqual(_.pad('abc', 9), ' abc '); }); - test('should truncate pad characters to fit the pad length', 2, function() { - strictEqual(_.pad('abc', 8), ' abc '); - strictEqual(_.pad('abc', 8, '_-'), '_-abc_-_'); + QUnit.test('should truncate pad characters to fit the pad length', function(assert) { + assert.expect(2); + + assert.strictEqual(_.pad('abc', 8), ' abc '); + assert.strictEqual(_.pad('abc', 8, '_-'), '_-abc_-_'); }); - test('should coerce `string` to a string', 2, function() { - strictEqual(_.pad(Object('abc'), 4), 'abc '); - strictEqual(_.pad({ 'toString': _.constant('abc') }, 5), ' abc '); + QUnit.test('should coerce `string` to a string', function(assert) { + assert.expect(2); + + assert.strictEqual(_.pad(Object('abc'), 4), 'abc '); + assert.strictEqual(_.pad({ 'toString': _.constant('abc') }, 5), ' abc '); }); }()); @@ -11699,17 +13370,23 @@ QUnit.module('lodash.padLeft'); (function() { - test('should pad a string to a given length', 1, function() { - strictEqual(_.padLeft('abc', 6), ' abc'); + QUnit.test('should pad a string to a given length', function(assert) { + assert.expect(1); + + assert.strictEqual(_.padLeft('abc', 6), ' abc'); }); - test('should truncate pad characters to fit the pad length', 1, function() { - strictEqual(_.padLeft('abc', 6, '_-'), '_-_abc'); + QUnit.test('should truncate pad characters to fit the pad length', function(assert) { + assert.expect(1); + + assert.strictEqual(_.padLeft('abc', 6, '_-'), '_-_abc'); }); - test('should coerce `string` to a string', 2, function() { - strictEqual(_.padLeft(Object('abc'), 4), ' abc'); - strictEqual(_.padLeft({ 'toString': _.constant('abc') }, 5), ' abc'); + QUnit.test('should coerce `string` to a string', function(assert) { + assert.expect(2); + + assert.strictEqual(_.padLeft(Object('abc'), 4), ' abc'); + assert.strictEqual(_.padLeft({ 'toString': _.constant('abc') }, 5), ' abc'); }); }()); @@ -11718,17 +13395,23 @@ QUnit.module('lodash.padRight'); (function() { - test('should pad a string to a given length', 1, function() { - strictEqual(_.padRight('abc', 6), 'abc '); + QUnit.test('should pad a string to a given length', function(assert) { + assert.expect(1); + + assert.strictEqual(_.padRight('abc', 6), 'abc '); }); - test('should truncate pad characters to fit the pad length', 1, function() { - strictEqual(_.padRight('abc', 6, '_-'), 'abc_-_'); + QUnit.test('should truncate pad characters to fit the pad length', function(assert) { + assert.expect(1); + + assert.strictEqual(_.padRight('abc', 6, '_-'), 'abc_-_'); }); - test('should coerce `string` to a string', 2, function() { - strictEqual(_.padRight(Object('abc'), 4), 'abc '); - strictEqual(_.padRight({ 'toString': _.constant('abc') }, 5), 'abc '); + QUnit.test('should coerce `string` to a string', function(assert) { + assert.expect(2); + + assert.strictEqual(_.padRight(Object('abc'), 4), 'abc '); + assert.strictEqual(_.padRight({ 'toString': _.constant('abc') }, 5), 'abc '); }); }()); @@ -11741,37 +13424,47 @@ isPad = methodName == 'pad', isPadLeft = methodName == 'padLeft'; - test('`_.' + methodName + '` should not pad is string is >= `length`', 2, function() { - strictEqual(func('abc', 2), 'abc'); - strictEqual(func('abc', 3), 'abc'); + QUnit.test('`_.' + methodName + '` should not pad is string is >= `length`', function(assert) { + assert.expect(2); + + assert.strictEqual(func('abc', 2), 'abc'); + assert.strictEqual(func('abc', 3), 'abc'); }); - test('`_.' + methodName + '` should treat negative `length` as `0`', 2, function() { + QUnit.test('`_.' + methodName + '` should treat negative `length` as `0`', function(assert) { + assert.expect(2); + _.each([0, -2], function(length) { - strictEqual(func('abc', length), 'abc'); + assert.strictEqual(func('abc', length), 'abc'); }); }); - test('`_.' + methodName + '` should coerce `length` to a number', 2, function() { + QUnit.test('`_.' + methodName + '` should coerce `length` to a number', function(assert) { + assert.expect(2); + _.each(['', '4'], function(length) { var actual = length ? (isPadLeft ? ' abc' : 'abc ') : 'abc'; - strictEqual(func('abc', length), actual); + assert.strictEqual(func('abc', length), actual); }); }); - test('`_.' + methodName + '` should treat nullish values as empty strings', 6, function() { + QUnit.test('`_.' + methodName + '` should treat nullish values as empty strings', function(assert) { + assert.expect(6); + _.each([undefined, '_-'], function(chars) { var expected = chars ? (isPad ? '__' : chars) : ' '; - strictEqual(func(null, 2, chars), expected); - strictEqual(func(undefined, 2, chars), expected); - strictEqual(func('', 2, chars), expected); + assert.strictEqual(func(null, 2, chars), expected); + assert.strictEqual(func(undefined, 2, chars), expected); + assert.strictEqual(func('', 2, chars), expected); }); }); - test('`_.' + methodName + '` should work with nullish or empty string values for `chars`', 3, function() { - notStrictEqual(func('abc', 6, null), 'abc'); - notStrictEqual(func('abc', 6, undefined), 'abc'); - strictEqual(func('abc', 6, ''), 'abc'); + QUnit.test('`_.' + methodName + '` should work with nullish or empty string values for `chars`', function(assert) { + assert.expect(3); + + assert.notStrictEqual(func('abc', 6, null), 'abc'); + assert.notStrictEqual(func('abc', 6, undefined), 'abc'); + assert.strictEqual(func('abc', 6, ''), 'abc'); }); }); @@ -11780,19 +13473,25 @@ QUnit.module('lodash.pairs'); (function() { - test('should create a two dimensional array of key-value pairs', 1, function() { + QUnit.test('should create a two dimensional array of key-value pairs', function(assert) { + assert.expect(1); + var object = { 'a': 1, 'b': 2 }; - deepEqual(_.pairs(object), [['a', 1], ['b', 2]]); + assert.deepEqual(_.pairs(object), [['a', 1], ['b', 2]]); }); - test('should work with an object that has a `length` property', 1, function() { + QUnit.test('should work with an object that has a `length` property', function(assert) { + assert.expect(1); + var object = { '0': 'a', '1': 'b', 'length': 2 }; - deepEqual(_.pairs(object), [['0', 'a'], ['1', 'b'], ['length', 2]]); + assert.deepEqual(_.pairs(object), [['0', 'a'], ['1', 'b'], ['length', 2]]); }); - test('should work with strings', 2, function() { + QUnit.test('should work with strings', function(assert) { + assert.expect(2); + _.each(['xo', Object('xo')], function(string) { - deepEqual(_.pairs(string), [['0', 'x'], ['1', 'o']]); + assert.deepEqual(_.pairs(string), [['0', 'x'], ['1', 'o']]); }); }); }()); @@ -11802,38 +13501,48 @@ QUnit.module('lodash.parseInt'); (function() { - test('should accept a `radix` argument', 1, function() { + QUnit.test('should accept a `radix` argument', function(assert) { + assert.expect(1); + var expected = _.range(2, 37); var actual = _.map(expected, function(radix) { return _.parseInt('10', radix); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should use a radix of `10`, for non-hexadecimals, if `radix` is `undefined` or `0`', 4, function() { - strictEqual(_.parseInt('10'), 10); - strictEqual(_.parseInt('10', 0), 10); - strictEqual(_.parseInt('10', 10), 10); - strictEqual(_.parseInt('10', undefined), 10); + QUnit.test('should use a radix of `10`, for non-hexadecimals, if `radix` is `undefined` or `0`', function(assert) { + assert.expect(4); + + assert.strictEqual(_.parseInt('10'), 10); + assert.strictEqual(_.parseInt('10', 0), 10); + assert.strictEqual(_.parseInt('10', 10), 10); + assert.strictEqual(_.parseInt('10', undefined), 10); }); - test('should use a radix of `16`, for hexadecimals, if `radix` is `undefined` or `0`', 8, function() { + QUnit.test('should use a radix of `16`, for hexadecimals, if `radix` is `undefined` or `0`', function(assert) { + assert.expect(8); + _.each(['0x20', '0X20'], function(string) { - strictEqual(_.parseInt(string), 32); - strictEqual(_.parseInt(string, 0), 32); - strictEqual(_.parseInt(string, 16), 32); - strictEqual(_.parseInt(string, undefined), 32); + assert.strictEqual(_.parseInt(string), 32); + assert.strictEqual(_.parseInt(string, 0), 32); + assert.strictEqual(_.parseInt(string, 16), 32); + assert.strictEqual(_.parseInt(string, undefined), 32); }); }); - test('should use a radix of `10` for string with leading zeros', 2, function() { - strictEqual(_.parseInt('08'), 8); - strictEqual(_.parseInt('08', 10), 8); + QUnit.test('should use a radix of `10` for string with leading zeros', function(assert) { + assert.expect(2); + + assert.strictEqual(_.parseInt('08'), 8); + assert.strictEqual(_.parseInt('08', 10), 8); }); - test('should parse strings with leading whitespace (test in Chrome, Firefox, and Opera)', 2, function() { + QUnit.test('should parse strings with leading whitespace (test in Chrome, Firefox, and Opera)', function(assert) { + assert.expect(2); + var expected = [8, 8, 10, 10, 32, 32, 32, 32]; _.times(2, function(index) { @@ -11856,28 +13565,32 @@ ); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); } else { - skipTest(); + skipTest(assert); } }); }); - test('should coerce `radix` to a number', 2, function() { + QUnit.test('should coerce `radix` to a number', function(assert) { + assert.expect(2); + var object = { 'valueOf': _.constant(0) }; - strictEqual(_.parseInt('08', object), 8); - strictEqual(_.parseInt('0x20', object), 32); + assert.strictEqual(_.parseInt('08', object), 8); + assert.strictEqual(_.parseInt('0x20', object), 32); }); - test('should work as an iteratee for methods like `_.map`', 2, function() { + QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { + assert.expect(2); + var strings = _.map(['6', '08', '10'], Object), actual = _.map(strings, _.parseInt); - deepEqual(actual, [6, 8, 10]); + assert.deepEqual(actual, [6, 8, 10]); actual = _.map('123', _.parseInt); - deepEqual(actual, [1, 2, 3]); + assert.deepEqual(actual, [1, 2, 3]); }); }()); @@ -11890,69 +13603,85 @@ isPartial = methodName == 'partial', ph = func.placeholder; - test('`_.' + methodName + '` partially applies arguments', 1, function() { + QUnit.test('`_.' + methodName + '` partially applies arguments', function(assert) { + assert.expect(1); + var par = func(_.identity, 'a'); - strictEqual(par(), 'a'); + assert.strictEqual(par(), 'a'); }); - test('`_.' + methodName + '` creates a function that can be invoked with additional arguments', 1, function() { + QUnit.test('`_.' + methodName + '` creates a function that can be invoked with additional arguments', function(assert) { + assert.expect(1); + var fn = function(a, b) { return [a, b]; }, par = func(fn, 'a'), expected = ['a', 'b']; - deepEqual(par('b'), isPartial ? expected : expected.reverse()); + assert.deepEqual(par('b'), isPartial ? expected : expected.reverse()); }); - test('`_.' + methodName + '` works when there are no partially applied arguments and the created function is invoked without additional arguments', 1, function() { + QUnit.test('`_.' + methodName + '` works when there are no partially applied arguments and the created function is invoked without additional arguments', function(assert) { + assert.expect(1); + var fn = function() { return arguments.length; }, par = func(fn); - strictEqual(par(), 0); + assert.strictEqual(par(), 0); }); - test('`_.' + methodName + '` works when there are no partially applied arguments and the created function is invoked with additional arguments', 1, function() { + QUnit.test('`_.' + methodName + '` works when there are no partially applied arguments and the created function is invoked with additional arguments', function(assert) { + assert.expect(1); + var par = func(_.identity); - strictEqual(par('a'), 'a'); + assert.strictEqual(par('a'), 'a'); }); - test('`_.' + methodName + '` should support placeholders', 4, function() { + QUnit.test('`_.' + methodName + '` should support placeholders', function(assert) { + assert.expect(4); + var fn = function() { return slice.call(arguments); }, par = func(fn, ph, 'b', ph); - deepEqual(par('a', 'c'), ['a', 'b', 'c']); - deepEqual(par('a'), ['a', 'b', undefined]); - deepEqual(par(), [undefined, 'b', undefined]); + assert.deepEqual(par('a', 'c'), ['a', 'b', 'c']); + assert.deepEqual(par('a'), ['a', 'b', undefined]); + assert.deepEqual(par(), [undefined, 'b', undefined]); if (isPartial) { - deepEqual(par('a', 'c', 'd'), ['a', 'b', 'c', 'd']); + assert.deepEqual(par('a', 'c', 'd'), ['a', 'b', 'c', 'd']); } else { par = func(fn, ph, 'c', ph); - deepEqual(par('a', 'b', 'd'), ['a', 'b', 'c', 'd']); + assert.deepEqual(par('a', 'b', 'd'), ['a', 'b', 'c', 'd']); } }); - test('`_.' + methodName + '` should not set a `this` binding', 3, function() { + QUnit.test('`_.' + methodName + '` should not set a `this` binding', function(assert) { + assert.expect(3); + var fn = function() { return this.a; }, object = { 'a': 1 }; var par = func(_.bind(fn, object)); - strictEqual(par(), object.a); + assert.strictEqual(par(), object.a); par = _.bind(func(fn), object); - strictEqual(par(), object.a); + assert.strictEqual(par(), object.a); object.par = func(fn); - strictEqual(object.par(), object.a); + assert.strictEqual(object.par(), object.a); }); - test('`_.' + methodName + '` creates a function with a `length` of `0`', 1, function() { + QUnit.test('`_.' + methodName + '` creates a function with a `length` of `0`', function(assert) { + assert.expect(1); + var fn = function(a, b, c) {}, par = func(fn, 'a'); - strictEqual(par.length, 0); + assert.strictEqual(par.length, 0); }); - test('`_.' + methodName + '` ensure `new partialed` is an instance of `func`', 2, function() { + QUnit.test('`_.' + methodName + '` ensure `new partialed` is an instance of `func`', function(assert) { + assert.expect(2); + function Foo(value) { return value && object; } @@ -11960,11 +13689,13 @@ var object = {}, par = func(Foo); - ok(new par instanceof Foo); - strictEqual(new par(true), object); + assert.ok(new par instanceof Foo); + assert.strictEqual(new par(true), object); }); - test('`_.' + methodName + '` should clone metadata for created functions', 3, function() { + QUnit.test('`_.' + methodName + '` should clone metadata for created functions', function(assert) { + assert.expect(3); + function greet(greeting, name) { return greeting + ' ' + name; } @@ -11973,25 +13704,29 @@ par2 = func(par1, 'barney'), par3 = func(par1, 'pebbles'); - strictEqual(par1('fred'), isPartial ? 'hi fred' : 'fred hi'); - strictEqual(par2(), isPartial ? 'hi barney' : 'barney hi'); - strictEqual(par3(), isPartial ? 'hi pebbles' : 'pebbles hi'); + assert.strictEqual(par1('fred'), isPartial ? 'hi fred' : 'fred hi'); + assert.strictEqual(par2(), isPartial ? 'hi barney' : 'barney hi'); + assert.strictEqual(par3(), isPartial ? 'hi pebbles' : 'pebbles hi'); }); - test('`_.' + methodName + '` should work with curried functions', 2, function() { + QUnit.test('`_.' + methodName + '` should work with curried functions', function(assert) { + assert.expect(2); + var fn = function(a, b, c) { return a + b + c; }, curried = _.curry(func(fn, 1), 2); - strictEqual(curried(2, 3), 6); - strictEqual(curried(2)(3), 6); + assert.strictEqual(curried(2, 3), 6); + assert.strictEqual(curried(2)(3), 6); }); - test('should work with placeholders and curried functions', 1, function() { + QUnit.test('should work with placeholders and curried functions', function(assert) { + assert.expect(1); + var fn = function() { return slice.call(arguments); }, curried = _.curry(fn), par = func(curried, ph, 'b', ph, 'd'); - deepEqual(par('a', 'c'), ['a', 'b', 'c', 'd']); + assert.deepEqual(par('a', 'c'), ['a', 'b', 'c', 'd']); }); }); @@ -12000,7 +13735,9 @@ QUnit.module('lodash.partialRight'); (function() { - test('should work as a deep `_.defaults`', 1, function() { + QUnit.test('should work as a deep `_.defaults`', function(assert) { + assert.expect(1); + var object = { 'a': { 'b': 1 } }, source = { 'a': { 'b': 2, 'c': 3 } }, expected = { 'a': { 'b': 1, 'c': 3 } }; @@ -12009,7 +13746,7 @@ return _.isObject(value) ? _.mergeWith(value, other, deep) : value; }); - deepEqual(defaultsDeep(object, source), expected); + assert.deepEqual(defaultsDeep(object, source), expected); }); }()); @@ -12027,15 +13764,19 @@ ph3 = _.partial.placeholder, ph4 = _.partialRight.placeholder; - test('should work with combinations of partial functions', 1, function() { + QUnit.test('should work with combinations of partial functions', function(assert) { + assert.expect(1); + var a = _.partial(fn), b = _.partialRight(a, 3), c = _.partial(b, 1); - deepEqual(c(2), [1, 2, 3]); + assert.deepEqual(c(2), [1, 2, 3]); }); - test('should work with combinations of bound and partial functions', 3, function() { + QUnit.test('should work with combinations of bound and partial functions', function(assert) { + assert.expect(3); + var fn = function() { var result = [this.a]; push.apply(result, arguments); @@ -12049,22 +13790,24 @@ b = _.partialRight(a, 4), c = _.partial(b, 2); - deepEqual(c(3), expected); + assert.deepEqual(c(3), expected); a = _.bind(fn, object); b = _.partialRight(a, 4); c = _.partial(b, 2); - deepEqual(c(3), expected); + assert.deepEqual(c(3), expected); a = _.partial(fn, 2); b = _.bind(a, object); c = _.partialRight(b, 4); - deepEqual(c(3), expected); + assert.deepEqual(c(3), expected); }); - test('should work with combinations of functions with placeholders', 3, function() { + QUnit.test('should work with combinations of functions with placeholders', function(assert) { + assert.expect(3); + var expected = [1, 2, 3, 4, 5, 6], object = { 'fn': fn }; @@ -12072,22 +13815,24 @@ b = _.partialRight(a, ph4, 6), c = _.partial(b, 1, ph3, 4); - deepEqual(c(3, 5), expected); + assert.deepEqual(c(3, 5), expected); a = _.bind(fn, object, ph1, 2); b = _.partialRight(a, ph4, 6); c = _.partial(b, 1, ph3, 4); - deepEqual(c(3, 5), expected); + assert.deepEqual(c(3, 5), expected); a = _.partial(fn, ph3, 2); b = _.bind(a, object, 1, ph1, 4); c = _.partialRight(b, ph4, 6); - deepEqual(c(3, 5), expected); + assert.deepEqual(c(3, 5), expected); }); - test('should work with combinations of functions with overlaping placeholders', 3, function() { + QUnit.test('should work with combinations of functions with overlaping placeholders', function(assert) { + assert.expect(3); + var expected = [1, 2, 3, 4], object = { 'fn': fn }; @@ -12095,22 +13840,24 @@ b = _.partialRight(a, ph4, 4), c = _.partial(b, ph3, 3); - deepEqual(c(1), expected); + assert.deepEqual(c(1), expected); a = _.bind(fn, object, ph1, 2); b = _.partialRight(a, ph4, 4); c = _.partial(b, ph3, 3); - deepEqual(c(1), expected); + assert.deepEqual(c(1), expected); a = _.partial(fn, ph3, 2); b = _.bind(a, object, ph1, 3); c = _.partialRight(b, ph4, 4); - deepEqual(c(1), expected); + assert.deepEqual(c(1), expected); }); - test('should work with recursively bound functions', 1, function() { + QUnit.test('should work with recursively bound functions', function(assert) { + assert.expect(1); + var fn = function() { return this.a; }; @@ -12119,10 +13866,12 @@ b = _.bind(a, { 'a': 2 }), c = _.bind(b, { 'a': 3 }); - strictEqual(c(), 1); + assert.strictEqual(c(), 1); }); - test('should work when hot', 12, function() { + QUnit.test('should work when hot', function(assert) { + assert.expect(12); + _.times(2, function(index) { var fn = function() { var result = [this]; @@ -12139,7 +13888,7 @@ return index ? bound2(3) : bound2(1, 2, 3); })); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); actual = _.last(_.times(HOT_COUNT, function() { var bound1 = index ? _.bind(fn, object, 1) : _.bind(fn, object), @@ -12148,7 +13897,7 @@ return index ? bound2(3) : bound2(1, 2, 3); })); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); _.each(['curry', 'curryRight'], function(methodName, index) { @@ -12160,14 +13909,14 @@ return curried(1)(2)(3); })); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); actual = _.last(_.times(HOT_COUNT, function() { var curried = _[methodName](fn); return curried(1)(2)(3); })); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); _.each(['partial', 'partialRight'], function(methodName, index) { @@ -12181,7 +13930,7 @@ return par2(3); })); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); actual = _.last(_.times(HOT_COUNT, function() { var par1 = func(fn, 1), @@ -12190,7 +13939,7 @@ return par2(3); })); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }); }()); @@ -12202,13 +13951,17 @@ (function() { var array = [1, 0, 1]; - test('should return two groups of elements', 3, function() { - deepEqual(_.partition([], _.identity), [[], []]); - deepEqual(_.partition(array, _.constant(true)), [array, []]); - deepEqual(_.partition(array, _.constant(false)), [[], array]); + QUnit.test('should return two groups of elements', function(assert) { + assert.expect(3); + + assert.deepEqual(_.partition([], _.identity), [[], []]); + assert.deepEqual(_.partition(array, _.constant(true)), [array, []]); + assert.deepEqual(_.partition(array, _.constant(false)), [[], array]); }); - test('should use `_.identity` when `predicate` is nullish', 1, function() { + QUnit.test('should use `_.identity` when `predicate` is nullish', function(assert) { + assert.expect(1); + var values = [, null, undefined], expected = _.map(values, _.constant([[1, 1], [0]])); @@ -12216,33 +13969,39 @@ return index ? _.partition(array, value) : _.partition(array); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work with a "_.property" style `predicate`', 1, function() { + QUnit.test('should work with a "_.property" style `predicate`', function(assert) { + assert.expect(1); + var objects = [{ 'a': 1 }, { 'a': 1 }, { 'b': 2 }], actual = _.partition(objects, 'a'); - deepEqual(actual, [objects.slice(0, 2), objects.slice(2)]); + assert.deepEqual(actual, [objects.slice(0, 2), objects.slice(2)]); }); - test('should work with a number for `predicate`', 2, function() { + QUnit.test('should work with a number for `predicate`', function(assert) { + assert.expect(2); + var array = [ [1, 0], [0, 1], [1, 0] ]; - deepEqual(_.partition(array, 0), [[array[0], array[2]], [array[1]]]); - deepEqual(_.partition(array, 1), [[array[1]], [array[0], array[2]]]); + assert.deepEqual(_.partition(array, 0), [[array[0], array[2]], [array[1]]]); + assert.deepEqual(_.partition(array, 1), [[array[1]], [array[0], array[2]]]); }); - test('should work with an object for `collection`', 1, function() { + QUnit.test('should work with an object for `collection`', function(assert) { + assert.expect(1); + var actual = _.partition({ 'a': 1.1, 'b': 0.2, 'c': 1.3 }, function(num) { return Math.floor(num); }); - deepEqual(actual, [[1.1, 1.3], [0.2]]); + assert.deepEqual(actual, [[1.1, 1.3], [0.2]]); }); }()); @@ -12254,27 +14013,37 @@ var args = arguments, object = { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }; - test('should flatten `props`', 2, function() { - deepEqual(_.pick(object, 'a', 'c'), { 'a': 1, 'c': 3 }); - deepEqual(_.pick(object, ['a', 'd'], 'c'), { 'a': 1, 'c': 3, 'd': 4 }); + QUnit.test('should flatten `props`', function(assert) { + assert.expect(2); + + assert.deepEqual(_.pick(object, 'a', 'c'), { 'a': 1, 'c': 3 }); + assert.deepEqual(_.pick(object, ['a', 'd'], 'c'), { 'a': 1, 'c': 3, 'd': 4 }); }); - test('should work with a primitive `object` argument', 1, function() { - deepEqual(_.pick('', 'slice'), { 'slice': ''.slice }); + QUnit.test('should work with a primitive `object` argument', function(assert) { + assert.expect(1); + + assert.deepEqual(_.pick('', 'slice'), { 'slice': ''.slice }); }); - test('should return an empty object when `object` is nullish', 2, function() { + QUnit.test('should return an empty object when `object` is nullish', function(assert) { + assert.expect(2); + _.each([null, undefined], function(value) { - deepEqual(_.pick(value, 'valueOf'), {}); + assert.deepEqual(_.pick(value, 'valueOf'), {}); }); }); - test('should work with `arguments` objects as secondary arguments', 1, function() { - deepEqual(_.pick(object, args), { 'a': 1, 'c': 3 }); + QUnit.test('should work with `arguments` objects as secondary arguments', function(assert) { + assert.expect(1); + + assert.deepEqual(_.pick(object, args), { 'a': 1, 'c': 3 }); }); - test('should coerce property names to strings', 1, function() { - deepEqual(_.pick({ '0': 'a', '1': 'b' }, 0), { '0': 'a' }); + QUnit.test('should coerce property names to strings', function(assert) { + assert.expect(1); + + assert.deepEqual(_.pick({ '0': 'a', '1': 'b' }, 0), { '0': 'a' }); }); }('a', 'c')); @@ -12283,14 +14052,16 @@ QUnit.module('lodash.pickBy'); (function() { - test('should work with a predicate argument', 1, function() { + QUnit.test('should work with a predicate argument', function(assert) { + assert.expect(1); + var object = { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }; var actual = _.pickBy(object, function(num) { return num == 1 || num == 3; }); - deepEqual(actual, { 'a': 1, 'c': 3 }); + assert.deepEqual(actual, { 'a': 1, 'c': 3 }); }); }()); @@ -12312,22 +14083,28 @@ }; }; } - test('`_.' + methodName + '` should create an object of picked properties', 2, function() { - deepEqual(func(object, prop(object, 'a')), { 'a': 1 }); - deepEqual(func(object, prop(object, ['a', 'c'])), expected); + QUnit.test('`_.' + methodName + '` should create an object of picked properties', function(assert) { + assert.expect(2); + + assert.deepEqual(func(object, prop(object, 'a')), { 'a': 1 }); + assert.deepEqual(func(object, prop(object, ['a', 'c'])), expected); }); - test('`_.' + methodName + '` should iterate over inherited properties', 1, function() { + QUnit.test('`_.' + methodName + '` should iterate over inherited properties', function(assert) { + assert.expect(1); + function Foo() {} Foo.prototype = object; var foo = new Foo; - deepEqual(func(foo, prop(foo, ['a', 'c'])), expected); + assert.deepEqual(func(foo, prop(foo, ['a', 'c'])), expected); }); - test('`_.' + methodName + '` should work with an array `object` argument', 1, function() { + QUnit.test('`_.' + methodName + '` should work with an array `object` argument', function(assert) { + assert.expect(1); + var array = [1, 2, 3]; - deepEqual(func(array, prop(array, '1')), { '1': 2 }); + assert.deepEqual(func(array, prop(array, '1')), { '1': 2 }); }); }); @@ -12336,35 +14113,43 @@ QUnit.module('lodash.property'); (function() { - test('should create a function that plucks a property value of a given object', 4, function() { + QUnit.test('should create a function that plucks a property value of a given object', function(assert) { + assert.expect(4); + var object = { 'a': 1 }; _.each(['a', ['a']], function(path) { var prop = _.property(path); - strictEqual(prop.length, 1); - strictEqual(prop(object), 1); + assert.strictEqual(prop.length, 1); + assert.strictEqual(prop(object), 1); }); }); - test('should pluck deep property values', 2, function() { + QUnit.test('should pluck deep property values', function(assert) { + assert.expect(2); + var object = { 'a': { 'b': { 'c': 3 } } }; _.each(['a.b.c', ['a', 'b', 'c']], function(path) { var prop = _.property(path); - strictEqual(prop(object), 3); + assert.strictEqual(prop(object), 3); }); }); - test('should work with non-string `path` arguments', 2, function() { + QUnit.test('should work with non-string `path` arguments', function(assert) { + assert.expect(2); + var array = [1, 2, 3]; _.each([1, [1]], function(path) { var prop = _.property(path); - strictEqual(prop(array), 2); + assert.strictEqual(prop(array), 2); }); }); - test('should coerce key to a string', 1, function() { + QUnit.test('should coerce key to a string', function(assert) { + assert.expect(1); + function fn() {} fn.toString = _.constant('fn'); @@ -12380,29 +14165,35 @@ }); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should pluck inherited property values', 2, function() { + QUnit.test('should pluck inherited property values', function(assert) { + assert.expect(2); + function Foo() {} Foo.prototype.a = 1; _.each(['a', ['a']], function(path) { var prop = _.property(path); - strictEqual(prop(new Foo), 1); + assert.strictEqual(prop(new Foo), 1); }); }); - test('should pluck a key over a path', 2, function() { + QUnit.test('should pluck a key over a path', function(assert) { + assert.expect(2); + var object = { 'a.b.c': 3, 'a': { 'b': { 'c': 4 } } }; _.each(['a.b.c', ['a.b.c']], function(path) { var prop = _.property(path); - strictEqual(prop(object), 3); + assert.strictEqual(prop(object), 3); }); }); - test('should return `undefined` when `object` is nullish', 2, function() { + QUnit.test('should return `undefined` when `object` is nullish', function(assert) { + assert.expect(2); + var values = [, null, undefined], expected = _.map(values, _.constant(undefined)); @@ -12413,11 +14204,13 @@ return index ? prop(value) : prop(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }); - test('should return `undefined` with deep paths when `object` is nullish', 2, function() { + QUnit.test('should return `undefined` with deep paths when `object` is nullish', function(assert) { + assert.expect(2); + var values = [, null, undefined], expected = _.map(values, _.constant(undefined)); @@ -12428,16 +14221,18 @@ return index ? prop(value) : prop(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }); - test('should return `undefined` if parts of `path` are missing', 4, function() { + QUnit.test('should return `undefined` if parts of `path` are missing', function(assert) { + assert.expect(4); + var object = {}; _.each(['a', 'a[1].b.c', ['a'], ['a', '1', 'b', 'c']], function(path) { var prop = _.property(path); - strictEqual(prop(object), undefined); + assert.strictEqual(prop(object), undefined); }); }); }()); @@ -12447,35 +14242,43 @@ QUnit.module('lodash.propertyOf'); (function() { - test('should create a function that plucks a property value of a given key', 3, function() { + QUnit.test('should create a function that plucks a property value of a given key', function(assert) { + assert.expect(3); + var object = { 'a': 1 }, propOf = _.propertyOf(object); - strictEqual(propOf.length, 1); + assert.strictEqual(propOf.length, 1); _.each(['a', ['a']], function(path) { - strictEqual(propOf(path), 1); + assert.strictEqual(propOf(path), 1); }); }); - test('should pluck deep property values', 2, function() { + QUnit.test('should pluck deep property values', function(assert) { + assert.expect(2); + var object = { 'a': { 'b': { 'c': 3 } } }, propOf = _.propertyOf(object); _.each(['a.b.c', ['a', 'b', 'c']], function(path) { - strictEqual(propOf(path), 3); + assert.strictEqual(propOf(path), 3); }); }); - test('should work with non-string `path` arguments', 2, function() { + QUnit.test('should work with non-string `path` arguments', function(assert) { + assert.expect(2); + var array = [1, 2, 3], propOf = _.propertyOf(array); _.each([1, [1]], function(path) { - strictEqual(propOf(path), 2); + assert.strictEqual(propOf(path), 2); }); }); - test('should coerce key to a string', 1, function() { + QUnit.test('should coerce key to a string', function(assert) { + assert.expect(1); + function fn() {} fn.toString = _.constant('fn'); @@ -12491,30 +14294,36 @@ }); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should pluck inherited property values', 2, function() { + QUnit.test('should pluck inherited property values', function(assert) { + assert.expect(2); + function Foo() { this.a = 1; } Foo.prototype.b = 2; var propOf = _.propertyOf(new Foo); _.each(['b', ['b']], function(path) { - strictEqual(propOf(path), 2); + assert.strictEqual(propOf(path), 2); }); }); - test('should pluck a key over a path', 2, function() { + QUnit.test('should pluck a key over a path', function(assert) { + assert.expect(2); + var object = { 'a.b.c': 3, 'a': { 'b': { 'c': 4 } } }, propOf = _.propertyOf(object); _.each(['a.b.c', ['a.b.c']], function(path) { - strictEqual(propOf(path), 3); + assert.strictEqual(propOf(path), 3); }); }); - test('should return `undefined` when `object` is nullish', 2, function() { + QUnit.test('should return `undefined` when `object` is nullish', function(assert) { + assert.expect(2); + var values = [, null, undefined], expected = _.map(values, _.constant(undefined)); @@ -12524,11 +14333,13 @@ return propOf(path); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }); - test('should return `undefined` with deep paths when `object` is nullish', 2, function() { + QUnit.test('should return `undefined` with deep paths when `object` is nullish', function(assert) { + assert.expect(2); + var values = [, null, undefined], expected = _.map(values, _.constant(undefined)); @@ -12538,15 +14349,17 @@ return propOf(path); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }); - test('should return `undefined` if parts of `path` are missing', 4, function() { + QUnit.test('should return `undefined` if parts of `path` are missing', function(assert) { + assert.expect(4); + var propOf = _.propertyOf({}); _.each(['a', 'a[1].b.c', ['a'], ['a', '1', 'b', 'c']], function(path) { - strictEqual(propOf(path), undefined); + assert.strictEqual(propOf(path), undefined); }); }); }()); @@ -12556,37 +14369,45 @@ QUnit.module('lodash.pull'); (function() { - test('should modify and return the array', 2, function() { + QUnit.test('should modify and return the array', function(assert) { + assert.expect(2); + var array = [1, 2, 3], actual = _.pull(array, 1, 3); - deepEqual(array, [2]); - ok(actual === array); + assert.deepEqual(array, [2]); + assert.ok(actual === array); }); - test('should preserve holes in arrays', 2, function() { + QUnit.test('should preserve holes in arrays', function(assert) { + assert.expect(2); + var array = [1, 2, 3, 4]; delete array[1]; delete array[3]; _.pull(array, 1); - ok(!('0' in array)); - ok(!('2' in array)); + assert.notOk('0' in array); + assert.notOk('2' in array); }); - test('should treat holes as `undefined`', 1, function() { + QUnit.test('should treat holes as `undefined`', function(assert) { + assert.expect(1); + var array = [1, 2, 3]; delete array[1]; _.pull(array, undefined); - deepEqual(array, [1, 3]); + assert.deepEqual(array, [1, 3]); }); - test('should match `NaN`', 1, function() { + QUnit.test('should match `NaN`', function(assert) { + assert.expect(1); + var array = [1, NaN, 3, NaN]; _.pull(array, NaN); - deepEqual(array, [1, 3]); + assert.deepEqual(array, [1, 3]); }); }()); @@ -12595,62 +14416,76 @@ QUnit.module('lodash.pullAt'); (function() { - test('should modify the array and return removed elements', 2, function() { + QUnit.test('should modify the array and return removed elements', function(assert) { + assert.expect(2); + var array = [1, 2, 3], actual = _.pullAt(array, [0, 1]); - deepEqual(array, [3]); - deepEqual(actual, [1, 2]); + assert.deepEqual(array, [3]); + assert.deepEqual(actual, [1, 2]); }); - test('should work with unsorted indexes', 2, function() { + QUnit.test('should work with unsorted indexes', function(assert) { + assert.expect(2); + var array = [1, 2, 3, 4], actual = _.pullAt(array, [1, 3, 0]); - deepEqual(array, [3]); - deepEqual(actual, [2, 4, 1]); + assert.deepEqual(array, [3]); + assert.deepEqual(actual, [2, 4, 1]); }); - test('should work with repeated indexes', 2, function() { + QUnit.test('should work with repeated indexes', function(assert) { + assert.expect(2); + var array = [1, 2, 3, 4], actual = _.pullAt(array, [0, 2, 0, 1, 0, 2]); - deepEqual(array, [4]); - deepEqual(actual, [1, 3, 1, 2, 1, 3]); + assert.deepEqual(array, [4]); + assert.deepEqual(actual, [1, 3, 1, 2, 1, 3]); }); - test('should use `undefined` for nonexistent indexes', 2, function() { + QUnit.test('should use `undefined` for nonexistent indexes', function(assert) { + assert.expect(2); + var array = ['a', 'b', 'c'], actual = _.pullAt(array, [2, 4, 0]); - deepEqual(array, ['b']); - deepEqual(actual, ['c', undefined, 'a']); + assert.deepEqual(array, ['b']); + assert.deepEqual(actual, ['c', undefined, 'a']); }); - test('should flatten `indexes`', 4, function() { + QUnit.test('should flatten `indexes`', function(assert) { + assert.expect(4); + var array = ['a', 'b', 'c']; - deepEqual(_.pullAt(array, 2, 0), ['c', 'a']); - deepEqual(array, ['b']); + assert.deepEqual(_.pullAt(array, 2, 0), ['c', 'a']); + assert.deepEqual(array, ['b']); array = ['a', 'b', 'c', 'd']; - deepEqual(_.pullAt(array, [3, 0], 2), ['d', 'a', 'c']); - deepEqual(array, ['b']); + assert.deepEqual(_.pullAt(array, [3, 0], 2), ['d', 'a', 'c']); + assert.deepEqual(array, ['b']); }); - test('should return an empty array when no indexes are provided', 4, function() { + QUnit.test('should return an empty array when no indexes are provided', function(assert) { + assert.expect(4); + var array = ['a', 'b', 'c'], actual = _.pullAt(array); - deepEqual(array, ['a', 'b', 'c']); - deepEqual(actual, []); + assert.deepEqual(array, ['a', 'b', 'c']); + assert.deepEqual(actual, []); actual = _.pullAt(array, [], []); - deepEqual(array, ['a', 'b', 'c']); - deepEqual(actual, []); + assert.deepEqual(array, ['a', 'b', 'c']); + assert.deepEqual(actual, []); }); - test('should work with non-index paths', 2, function() { + QUnit.test('should work with non-index paths', function(assert) { + assert.expect(2); + var values = _.reject(empties, function(value) { return value === 0 || _.isArray(value); }).concat(-1, 1.1); @@ -12662,25 +14497,29 @@ var expected = _.map(values, _.constant(1)), actual = _.pullAt(array, values); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); expected = _.map(values, _.constant(undefined)), actual = _.at(array, values); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work with deep paths', 2, function() { + QUnit.test('should work with deep paths', function(assert) { + assert.expect(2); + var array = []; array.a = { 'b': { 'c': 3 } }; var actual = _.pullAt(array, 'a.b.c'); - deepEqual(actual, [3]); - deepEqual(array.a, { 'b': {} }); + assert.deepEqual(actual, [3]); + assert.deepEqual(array.a, { 'b': {} }); }); - test('should work with a falsey `array` argument when keys are provided', 1, function() { + QUnit.test('should work with a falsey `array` argument when keys are provided', function(assert) { + assert.expect(1); + var values = falsey.slice(), expected = _.map(values, _.constant(Array(4))); @@ -12690,7 +14529,7 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }()); @@ -12701,73 +14540,89 @@ (function() { var array = Array(1000); - test('should return `0` or `1` when arguments are not provided', 1, function() { + QUnit.test('should return `0` or `1` when arguments are not provided', function(assert) { + assert.expect(1); + var actual = _.map(array, function() { return _.random(); }); - deepEqual(_.uniq(actual).sort(), [0, 1]); + assert.deepEqual(_.uniq(actual).sort(), [0, 1]); }); - test('should support a `min` and `max` argument', 1, function() { + QUnit.test('should support a `min` and `max` argument', function(assert) { + assert.expect(1); + var min = 5, max = 10; - ok(_.some(array, function() { + assert.ok(_.some(array, function() { var result = _.random(min, max); return result >= min && result <= max; })); }); - test('should support not providing a `max` argument', 1, function() { + QUnit.test('should support not providing a `max` argument', function(assert) { + assert.expect(1); + var min = 0, max = 5; - ok(_.some(array, function() { + assert.ok(_.some(array, function() { var result = _.random(max); return result >= min && result <= max; })); }); - test('should support large integer values', 2, function() { + QUnit.test('should support large integer values', function(assert) { + assert.expect(2); + var min = Math.pow(2, 31), max = Math.pow(2, 62); - ok(_.every(array, function() { + assert.ok(_.every(array, function() { var result = _.random(min, max); return result >= min && result <= max; })); - ok(_.some(array, function() { + assert.ok(_.some(array, function() { return _.random(Number.MAX_VALUE) > 0; })); }); - test('should coerce arguments to numbers', 1, function() { - strictEqual(_.random('1', '1'), 1); + QUnit.test('should coerce arguments to numbers', function(assert) { + assert.expect(1); + + assert.strictEqual(_.random('1', '1'), 1); }); - test('should support floats', 2, function() { + QUnit.test('should support floats', function(assert) { + assert.expect(2); + var min = 1.5, max = 1.6, actual = _.random(min, max); - ok(actual % 1); - ok(actual >= min && actual <= max); + assert.ok(actual % 1); + assert.ok(actual >= min && actual <= max); }); - test('should support providing a `floating` argument', 3, function() { + QUnit.test('should support providing a `floating` argument', function(assert) { + assert.expect(3); + var actual = _.random(true); - ok(actual % 1 && actual >= 0 && actual <= 1); + assert.ok(actual % 1 && actual >= 0 && actual <= 1); actual = _.random(2, true); - ok(actual % 1 && actual >= 0 && actual <= 2); + assert.ok(actual % 1 && actual >= 0 && actual <= 2); actual = _.random(2, 4, true); - ok(actual % 1 && actual >= 2 && actual <= 4); + assert.ok(actual % 1 && actual >= 2 && actual <= 4); }); - test('should work as an iteratee for methods like `_.map`', 1, function() { + QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { + assert.expect(1); + var array = [1, 2, 3], expected = _.map(array, _.constant(true)), randoms = _.map(array, _.random); @@ -12776,7 +14631,7 @@ return result >= 0 && result <= array[index] && (result % 1) == 0; }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }()); @@ -12785,55 +14640,73 @@ QUnit.module('lodash.range'); (function() { - test('should work with an `end` argument', 1, function() { - deepEqual(_.range(4), [0, 1, 2, 3]); + QUnit.test('should work with an `end` argument', function(assert) { + assert.expect(1); + + assert.deepEqual(_.range(4), [0, 1, 2, 3]); }); - test('should work with `start` and `end` arguments', 1, function() { - deepEqual(_.range(1, 5), [1, 2, 3, 4]); + QUnit.test('should work with `start` and `end` arguments', function(assert) { + assert.expect(1); + + assert.deepEqual(_.range(1, 5), [1, 2, 3, 4]); }); - test('should work with `start`, `end`, and `step` arguments', 1, function() { - deepEqual(_.range(0, 20, 5), [0, 5, 10, 15]); + QUnit.test('should work with `start`, `end`, and `step` arguments', function(assert) { + assert.expect(1); + + assert.deepEqual(_.range(0, 20, 5), [0, 5, 10, 15]); }); - test('should support a `step` of `0`', 1, function() { - deepEqual(_.range(1, 4, 0), [1, 1, 1]); + QUnit.test('should support a `step` of `0`', function(assert) { + assert.expect(1); + + assert.deepEqual(_.range(1, 4, 0), [1, 1, 1]); }); - test('should work with a `step` larger than `end`', 1, function() { - deepEqual(_.range(1, 5, 20), [1]); + QUnit.test('should work with a `step` larger than `end`', function(assert) { + assert.expect(1); + + assert.deepEqual(_.range(1, 5, 20), [1]); }); - test('should work with a negative `step` argument', 2, function() { - deepEqual(_.range(0, -4, -1), [0, -1, -2, -3]); - deepEqual(_.range(21, 10, -3), [21, 18, 15, 12]); + QUnit.test('should work with a negative `step` argument', function(assert) { + assert.expect(2); + + assert.deepEqual(_.range(0, -4, -1), [0, -1, -2, -3]); + assert.deepEqual(_.range(21, 10, -3), [21, 18, 15, 12]); }); - test('should treat falsey `start` arguments as `0`', 13, function() { + QUnit.test('should treat falsey `start` arguments as `0`', function(assert) { + assert.expect(13); + _.each(falsey, function(value, index) { if (index) { - deepEqual(_.range(value), []); - deepEqual(_.range(value, 1), [0]); + assert.deepEqual(_.range(value), []); + assert.deepEqual(_.range(value, 1), [0]); } else { - deepEqual(_.range(), []); + assert.deepEqual(_.range(), []); } }); }); - test('should coerce arguments to finite numbers', 1, function() { + QUnit.test('should coerce arguments to finite numbers', function(assert) { + assert.expect(1); + var actual = [_.range('0', 1), _.range('1'), _.range(0, 1, '1'), _.range(NaN), _.range(NaN, NaN)]; - deepEqual(actual, [[0], [0], [0], [], []]); + assert.deepEqual(actual, [[0], [0], [0], [], []]); }); - test('should work as an iteratee for methods like `_.map`', 2, function() { + QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { + assert.expect(2); + var array = [1, 2, 3], object = { 'a': 1, 'b': 2, 'c': 3 }, expected = [[0], [0, 1], [0, 1, 2]]; _.each([array, object], function(collection) { var actual = _.map(collection, _.range); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }); }()); @@ -12847,22 +14720,30 @@ return slice.call(arguments); } - test('should reorder arguments provided to `func`', 1, function() { + QUnit.test('should reorder arguments provided to `func`', function(assert) { + assert.expect(1); + var rearged = _.rearg(fn, [2, 0, 1]); - deepEqual(rearged('b', 'c', 'a'), ['a', 'b', 'c']); + assert.deepEqual(rearged('b', 'c', 'a'), ['a', 'b', 'c']); }); - test('should work with repeated indexes', 1, function() { + QUnit.test('should work with repeated indexes', function(assert) { + assert.expect(1); + var rearged = _.rearg(fn, [1, 1, 1]); - deepEqual(rearged('c', 'a', 'b'), ['a', 'a', 'a']); + assert.deepEqual(rearged('c', 'a', 'b'), ['a', 'a', 'a']); }); - test('should use `undefined` for nonexistent indexes', 1, function() { + QUnit.test('should use `undefined` for nonexistent indexes', function(assert) { + assert.expect(1); + var rearged = _.rearg(fn, [1, 4]); - deepEqual(rearged('b', 'a', 'c'), ['a', undefined, 'c']); + assert.deepEqual(rearged('b', 'a', 'c'), ['a', undefined, 'c']); }); - test('should use `undefined` for non-index values', 1, function() { + QUnit.test('should use `undefined` for non-index values', function(assert) { + assert.expect(1); + var values = _.reject(empties, function(value) { return value === 0 || _.isArray(value); }).concat(-1, 1.1); @@ -12874,37 +14755,47 @@ return rearged('a', 'b', 'c'); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should not rearrange arguments when no indexes are provided', 2, function() { + QUnit.test('should not rearrange arguments when no indexes are provided', function(assert) { + assert.expect(2); + var rearged = _.rearg(fn); - deepEqual(rearged('a', 'b', 'c'), ['a', 'b', 'c']); + assert.deepEqual(rearged('a', 'b', 'c'), ['a', 'b', 'c']); rearged = _.rearg(fn, [], []); - deepEqual(rearged('a', 'b', 'c'), ['a', 'b', 'c']); + assert.deepEqual(rearged('a', 'b', 'c'), ['a', 'b', 'c']); }); - test('should accept multiple index arguments', 1, function() { + QUnit.test('should accept multiple index arguments', function(assert) { + assert.expect(1); + var rearged = _.rearg(fn, 2, 0, 1); - deepEqual(rearged('b', 'c', 'a'), ['a', 'b', 'c']); + assert.deepEqual(rearged('b', 'c', 'a'), ['a', 'b', 'c']); }); - test('should accept multiple arrays of indexes', 1, function() { + QUnit.test('should accept multiple arrays of indexes', function(assert) { + assert.expect(1); + var rearged = _.rearg(fn, [2], [0, 1]); - deepEqual(rearged('b', 'c', 'a'), ['a', 'b', 'c']); + assert.deepEqual(rearged('b', 'c', 'a'), ['a', 'b', 'c']); }); - test('should work with fewer indexes than arguments', 1, function() { + QUnit.test('should work with fewer indexes than arguments', function(assert) { + assert.expect(1); + var rearged = _.rearg(fn, [1, 0]); - deepEqual(rearged('b', 'a', 'c'), ['a', 'b', 'c']); + assert.deepEqual(rearged('b', 'a', 'c'), ['a', 'b', 'c']); }); - test('should work on functions that have been rearged', 1, function() { + QUnit.test('should work on functions that have been rearged', function(assert) { + assert.expect(1); + var rearged1 = _.rearg(fn, 2, 1, 0), rearged2 = _.rearg(rearged1, 1, 0, 2); - deepEqual(rearged2('b', 'c', 'a'), ['a', 'b', 'c']); + assert.deepEqual(rearged2('b', 'c', 'a'), ['a', 'b', 'c']); }); }()); @@ -12915,28 +14806,34 @@ (function() { var array = [1, 2, 3]; - test('should use the first element of a collection as the default `accumulator`', 1, function() { - strictEqual(_.reduce(array), 1); + QUnit.test('should use the first element of a collection as the default `accumulator`', function(assert) { + assert.expect(1); + + assert.strictEqual(_.reduce(array), 1); }); - test('should provide the correct `iteratee` arguments when iterating an array', 2, function() { + QUnit.test('should provide the correct `iteratee` arguments when iterating an array', function(assert) { + assert.expect(2); + var args; _.reduce(array, function() { args || (args = slice.call(arguments)); }, 0); - deepEqual(args, [0, 1, 0, array]); + assert.deepEqual(args, [0, 1, 0, array]); args = null; _.reduce(array, function() { args || (args = slice.call(arguments)); }); - deepEqual(args, [1, 2, 1, array]); + assert.deepEqual(args, [1, 2, 1, array]); }); - test('should provide the correct `iteratee` arguments when iterating an object', 2, function() { + QUnit.test('should provide the correct `iteratee` arguments when iterating an object', function(assert) { + assert.expect(2); + var args, object = { 'a': 1, 'b': 2 }, firstKey = _.first(_.keys(object)); @@ -12949,7 +14846,7 @@ args || (args = slice.call(arguments)); }, 0); - deepEqual(args, expected); + assert.deepEqual(args, expected); args = null; expected = firstKey == 'a' @@ -12960,7 +14857,7 @@ args || (args = slice.call(arguments)); }); - deepEqual(args, expected); + assert.deepEqual(args, expected); }); }()); @@ -12971,28 +14868,34 @@ (function() { var array = [1, 2, 3]; - test('should use the last element of a collection as the default `accumulator`', 1, function() { - strictEqual(_.reduceRight(array), 3); + QUnit.test('should use the last element of a collection as the default `accumulator`', function(assert) { + assert.expect(1); + + assert.strictEqual(_.reduceRight(array), 3); }); - test('should provide the correct `iteratee` arguments when iterating an array', 2, function() { + QUnit.test('should provide the correct `iteratee` arguments when iterating an array', function(assert) { + assert.expect(2); + var args; _.reduceRight(array, function() { args || (args = slice.call(arguments)); }, 0); - deepEqual(args, [0, 3, 2, array]); + assert.deepEqual(args, [0, 3, 2, array]); args = null; _.reduceRight(array, function() { args || (args = slice.call(arguments)); }); - deepEqual(args, [3, 2, 1, array]); + assert.deepEqual(args, [3, 2, 1, array]); }); - test('should provide the correct `iteratee` arguments when iterating an object', 2, function() { + QUnit.test('should provide the correct `iteratee` arguments when iterating an object', function(assert) { + assert.expect(2); + var args, object = { 'a': 1, 'b': 2 }, lastKey = _.last(_.keys(object)); @@ -13005,7 +14908,7 @@ args || (args = slice.call(arguments)); }, 0); - deepEqual(args, expected); + assert.deepEqual(args, expected); args = null; expected = lastKey == 'b' @@ -13016,7 +14919,7 @@ args || (args = slice.call(arguments)); }); - deepEqual(args, expected); + assert.deepEqual(args, expected); }); }()); @@ -13029,15 +14932,19 @@ array = [1, 2, 3], isReduce = methodName == 'reduce'; - test('`_.' + methodName + '` should reduce a collection to a single value', 1, function() { + QUnit.test('`_.' + methodName + '` should reduce a collection to a single value', function(assert) { + assert.expect(1); + var actual = func(['a', 'b', 'c'], function(accumulator, value) { return accumulator + value; }, ''); - strictEqual(actual, isReduce ? 'abc' : 'cba'); + assert.strictEqual(actual, isReduce ? 'abc' : 'cba'); }); - test('`_.' + methodName + '` should support empty collections without an initial `accumulator` value', 1, function() { + QUnit.test('`_.' + methodName + '` should support empty collections without an initial `accumulator` value', function(assert) { + assert.expect(1); + var actual = [], expected = _.map(empties, _.constant()); @@ -13047,10 +14954,12 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('`_.' + methodName + '` should support empty collections with an initial `accumulator` value', 1, function() { + QUnit.test('`_.' + methodName + '` should support empty collections with an initial `accumulator` value', function(assert) { + assert.expect(1); + var expected = _.map(empties, _.constant('x')); var actual = _.map(empties, function(value) { @@ -13059,43 +14968,51 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('`_.' + methodName + '` should handle an initial `accumulator` value of `undefined`', 1, function() { + QUnit.test('`_.' + methodName + '` should handle an initial `accumulator` value of `undefined`', function(assert) { + assert.expect(1); + var actual = func([], _.noop, undefined); - strictEqual(actual, undefined); + assert.strictEqual(actual, undefined); }); - test('`_.' + methodName + '` should return `undefined` for empty collections when no `accumulator` is provided (test in IE > 9 and modern browsers)', 2, function() { + QUnit.test('`_.' + methodName + '` should return `undefined` for empty collections when no `accumulator` is provided (test in IE > 9 and modern browsers)', function(assert) { + assert.expect(2); + var array = [], object = { '0': 1, 'length': 0 }; if ('__proto__' in array) { array.__proto__ = object; - strictEqual(_.reduce(array, _.noop), undefined); + assert.strictEqual(_.reduce(array, _.noop), undefined); } else { - skipTest(); + skipTest(assert); } - strictEqual(_.reduce(object, _.noop), undefined); + assert.strictEqual(_.reduce(object, _.noop), undefined); }); - test('`_.' + methodName + '` should return an unwrapped value when implicityly chaining', 1, function() { + QUnit.test('`_.' + methodName + '` should return an unwrapped value when implicityly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - strictEqual(_(array)[methodName](add), 6); + assert.strictEqual(_(array)[methodName](add), 6); } else { - skipTest(); + skipTest(assert); } }); - test('`_.' + methodName + '` should return a wrapped value when explicitly chaining', 1, function() { + QUnit.test('`_.' + methodName + '` should return a wrapped value when explicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - ok(_(array).chain()[methodName](add) instanceof _); + assert.ok(_(array).chain()[methodName](add) instanceof _); } else { - skipTest(); + skipTest(assert); } }); }); @@ -13107,8 +15024,10 @@ (function() { var array = [1, 2, 3]; - test('should return elements the `predicate` returns falsey for', 1, function() { - deepEqual(_.reject(array, isEven), [1, 3]); + QUnit.test('should return elements the `predicate` returns falsey for', function(assert) { + assert.expect(1); + + assert.deepEqual(_.reject(array, isEven), [1, 3]); }); }()); @@ -13122,24 +15041,32 @@ isFilter = methodName == 'filter', objects = [{ 'a': 0 }, { 'a': 1 }]; - test('`_.' + methodName + '` should not modify the resulting value from within `predicate`', 1, function() { + QUnit.test('`_.' + methodName + '` should not modify the resulting value from within `predicate`', function(assert) { + assert.expect(1); + var actual = func([0], function(num, index, array) { array[index] = 1; return isFilter; }); - deepEqual(actual, [0]); + assert.deepEqual(actual, [0]); }); - test('`_.' + methodName + '` should work with a "_.property" style `predicate`', 1, function() { - deepEqual(func(objects, 'a'), [objects[isFilter ? 1 : 0]]); + QUnit.test('`_.' + methodName + '` should work with a "_.property" style `predicate`', function(assert) { + assert.expect(1); + + assert.deepEqual(func(objects, 'a'), [objects[isFilter ? 1 : 0]]); }); - test('`_.' + methodName + '` should work with a "_.matches" style `predicate`', 1, function() { - deepEqual(func(objects, objects[1]), [objects[isFilter ? 1 : 0]]); + QUnit.test('`_.' + methodName + '` should work with a "_.matches" style `predicate`', function(assert) { + assert.expect(1); + + assert.deepEqual(func(objects, objects[1]), [objects[isFilter ? 1 : 0]]); }); - test('`_.' + methodName + '` should not modify wrapped values', 2, function() { + QUnit.test('`_.' + methodName + '` should not modify wrapped values', function(assert) { + assert.expect(2); + if (!isNpm) { var wrapped = _(array); @@ -13147,40 +15074,44 @@ return num < 3; }); - deepEqual(actual.value(), isFilter ? [1, 2] : [3, 4]); + assert.deepEqual(actual.value(), isFilter ? [1, 2] : [3, 4]); actual = wrapped[methodName](function(num) { return num > 2; }); - deepEqual(actual.value(), isFilter ? [3, 4] : [1, 2]); + assert.deepEqual(actual.value(), isFilter ? [3, 4] : [1, 2]); } else { - skipTest(2); + skipTest(assert, 2); } }); - test('`_.' + methodName + '` should work in a lazy chain sequence', 2, function() { + QUnit.test('`_.' + methodName + '` should work in a lazy chain sequence', function(assert) { + assert.expect(2); + if (!isNpm) { var array = _.range(LARGE_ARRAY_SIZE + 1), predicate = function(value) { return isFilter ? isEven(value) : !isEven(value); }, actual = _(array).slice(1).map(square)[methodName](predicate).value(); - deepEqual(actual, _[methodName](_.map(array.slice(1), square), predicate)); + assert.deepEqual(actual, _[methodName](_.map(array.slice(1), square), predicate)); var object = _.zipObject(_.times(LARGE_ARRAY_SIZE, function(index) { return ['key' + index, index]; })); actual = _(object).mapValues(square)[methodName](predicate).value(); - deepEqual(actual, _[methodName](_.mapValues(object, square), predicate)); + assert.deepEqual(actual, _[methodName](_.mapValues(object, square), predicate)); } else { - skipTest(2); + skipTest(assert, 2); } }); - test('`_.' + methodName + '` should provide the correct `predicate` arguments in a lazy chain sequence', 5, function() { + QUnit.test('`_.' + methodName + '` 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), @@ -13190,38 +15121,38 @@ args || (args = slice.call(arguments)); }).value(); - deepEqual(args, [1, 0, array.slice(1)]); + assert.deepEqual(args, [1, 0, array.slice(1)]); args = null; _(array).slice(1).map(square)[methodName](function(value, index, array) { args || (args = slice.call(arguments)); }).value(); - deepEqual(args, expected); + assert.deepEqual(args, expected); args = null; _(array).slice(1).map(square)[methodName](function(value, index) { args || (args = slice.call(arguments)); }).value(); - deepEqual(args, expected); + assert.deepEqual(args, expected); args = null; _(array).slice(1).map(square)[methodName](function(value) { args || (args = slice.call(arguments)); }).value(); - deepEqual(args, [1]); + assert.deepEqual(args, [1]); args = null; _(array).slice(1).map(square)[methodName](function() { args || (args = slice.call(arguments)); }).value(); - deepEqual(args, expected); + assert.deepEqual(args, expected); } else { - skipTest(5); + skipTest(assert, 5); } }); }); @@ -13231,18 +15162,22 @@ QUnit.module('lodash.remove'); (function() { - test('should modify the array and return removed elements', 2, function() { + QUnit.test('should modify the array and return removed elements', function(assert) { + assert.expect(2); + var array = [1, 2, 3]; var actual = _.remove(array, function(num) { return num < 3; }); - deepEqual(array, [3]); - deepEqual(actual, [1, 2]); + assert.deepEqual(array, [3]); + assert.deepEqual(actual, [1, 2]); }); - test('should provide the correct `predicate` arguments', 1, function() { + QUnit.test('should provide the correct `predicate` arguments', function(assert) { + assert.expect(1); + var argsList = [], array = [1, 2, 3], clone = array.slice(); @@ -13254,49 +15189,61 @@ return isEven(index); }); - deepEqual(argsList, [[1, 0, clone], [2, 1, clone], [3, 2, clone]]); + assert.deepEqual(argsList, [[1, 0, clone], [2, 1, clone], [3, 2, clone]]); }); - test('should work with a "_.matches" style `predicate`', 1, function() { + QUnit.test('should work with a "_.matches" style `predicate`', function(assert) { + assert.expect(1); + var objects = [{ 'a': 0, 'b': 1 }, { 'a': 1, 'b': 2 }]; _.remove(objects, { 'a': 1 }); - deepEqual(objects, [{ 'a': 0, 'b': 1 }]); + assert.deepEqual(objects, [{ 'a': 0, 'b': 1 }]); }); - test('should work with a "_.matchesProperty" style `predicate`', 1, function() { + QUnit.test('should work with a "_.matchesProperty" style `predicate`', function(assert) { + assert.expect(1); + var objects = [{ 'a': 0, 'b': 1 }, { 'a': 1, 'b': 2 }]; _.remove(objects, ['a', 1]); - deepEqual(objects, [{ 'a': 0, 'b': 1 }]); + assert.deepEqual(objects, [{ 'a': 0, 'b': 1 }]); }); - test('should work with a "_.property" style `predicate`', 1, function() { + QUnit.test('should work with a "_.property" style `predicate`', function(assert) { + assert.expect(1); + var objects = [{ 'a': 0 }, { 'a': 1 }]; _.remove(objects, 'a'); - deepEqual(objects, [{ 'a': 0 }]); + assert.deepEqual(objects, [{ 'a': 0 }]); }); - test('should preserve holes in arrays', 2, function() { + QUnit.test('should preserve holes in arrays', function(assert) { + assert.expect(2); + var array = [1, 2, 3, 4]; delete array[1]; delete array[3]; _.remove(array, function(num) { return num === 1; }); - ok(!('0' in array)); - ok(!('2' in array)); + assert.notOk('0' in array); + assert.notOk('2' in array); }); - test('should treat holes as `undefined`', 1, function() { + QUnit.test('should treat holes as `undefined`', function(assert) { + assert.expect(1); + var array = [1, 2, 3]; delete array[1]; _.remove(array, function(num) { return num == null; }); - deepEqual(array, [1, 3]); + assert.deepEqual(array, [1, 3]); }); - test('should not mutate the array until all elements to remove are determined', 1, function() { + QUnit.test('should not mutate the array until all elements to remove are determined', function(assert) { + assert.expect(1); + var array = [1, 2, 3]; _.remove(array, function(num, index) { return isEven(index); }); - deepEqual(array, [2]); + assert.deepEqual(array, [2]); }); }()); @@ -13305,25 +15252,33 @@ QUnit.module('lodash.repeat'); (function() { - test('should repeat a string `n` times', 2, function() { - strictEqual(_.repeat('*', 3), '***'); - strictEqual(_.repeat('abc', 2), 'abcabc'); + QUnit.test('should repeat a string `n` times', function(assert) { + assert.expect(2); + + assert.strictEqual(_.repeat('*', 3), '***'); + assert.strictEqual(_.repeat('abc', 2), 'abcabc'); }); - test('should return an empty string for negative `n` or `n` of `0`', 2, function() { - strictEqual(_.repeat('abc', 0), ''); - strictEqual(_.repeat('abc', -2), ''); + QUnit.test('should return an empty string for negative `n` or `n` of `0`', function(assert) { + assert.expect(2); + + assert.strictEqual(_.repeat('abc', 0), ''); + assert.strictEqual(_.repeat('abc', -2), ''); }); - test('should coerce `n` to a number', 3, function() { - strictEqual(_.repeat('abc'), ''); - strictEqual(_.repeat('abc', '2'), 'abcabc'); - strictEqual(_.repeat('*', { 'valueOf': _.constant(3) }), '***'); + QUnit.test('should coerce `n` to a number', function(assert) { + assert.expect(3); + + assert.strictEqual(_.repeat('abc'), ''); + assert.strictEqual(_.repeat('abc', '2'), 'abcabc'); + assert.strictEqual(_.repeat('*', { 'valueOf': _.constant(3) }), '***'); }); - test('should coerce `string` to a string', 2, function() { - strictEqual(_.repeat(Object('abc'), 2), 'abcabc'); - strictEqual(_.repeat({ 'toString': _.constant('*') }, 3), '***'); + QUnit.test('should coerce `string` to a string', function(assert) { + assert.expect(2); + + assert.strictEqual(_.repeat(Object('abc'), 2), 'abcabc'); + assert.strictEqual(_.repeat({ 'toString': _.constant('*') }, 3), '***'); }); }()); @@ -13337,20 +15292,26 @@ 'b': function() { return this.a; } }; - test('should invoke function values', 1, function() { - strictEqual(_.result(object, 'b'), 1); + QUnit.test('should invoke function values', function(assert) { + assert.expect(1); + + assert.strictEqual(_.result(object, 'b'), 1); }); - test('should invoke default function values', 1, function() { + QUnit.test('should invoke default function values', function(assert) { + assert.expect(1); + var actual = _.result(object, 'c', object.b); - strictEqual(actual, 1); + assert.strictEqual(actual, 1); }); - test('should invoke deep property methods with the correct `this` binding', 2, function() { + QUnit.test('should invoke deep property methods with the correct `this` binding', function(assert) { + assert.expect(2); + var value = { 'a': object }; _.each(['a.b', ['a', 'b']], function(path) { - strictEqual(_.result(value, path), 1); + assert.strictEqual(_.result(value, path), 1); }); }); }()); @@ -13362,48 +15323,62 @@ _.each(['get', 'result'], function(methodName) { var func = _[methodName]; - test('`_.' + methodName + '` should get property values', 2, function() { + QUnit.test('`_.' + methodName + '` should get property values', function(assert) { + assert.expect(2); + var object = { 'a': 1 }; _.each(['a', ['a']], function(path) { - strictEqual(func(object, path), 1); + assert.strictEqual(func(object, path), 1); }); }); - test('`_.' + methodName + '` should get deep property values', 2, function() { + QUnit.test('`_.' + methodName + '` should get deep property values', function(assert) { + assert.expect(2); + var object = { 'a': { 'b': { 'c': 3 } } }; _.each(['a.b.c', ['a', 'b', 'c']], function(path) { - strictEqual(func(object, path), 3); + assert.strictEqual(func(object, path), 3); }); }); - test('`_.' + methodName + '` should get a key over a path', 2, function() { + QUnit.test('`_.' + methodName + '` should get a key over a path', function(assert) { + assert.expect(2); + var object = { 'a.b.c': 3, 'a': { 'b': { 'c': 4 } } }; _.each(['a.b.c', ['a.b.c']], function(path) { - strictEqual(func(object, path), 3); + assert.strictEqual(func(object, path), 3); }); }); - test('`_.' + methodName + '` should not coerce array paths to strings', 1, function() { + QUnit.test('`_.' + methodName + '` should not coerce array paths to strings', function(assert) { + assert.expect(1); + var object = { 'a,b,c': 3, 'a': { 'b': { 'c': 4 } } }; - strictEqual(func(object, ['a', 'b', 'c']), 4); + assert.strictEqual(func(object, ['a', 'b', 'c']), 4); }); - test('`_.' + methodName + '` should ignore empty brackets', 1, function() { + QUnit.test('`_.' + methodName + '` should ignore empty brackets', function(assert) { + assert.expect(1); + var object = { 'a': 1 }; - strictEqual(func(object, 'a[]'), 1); + assert.strictEqual(func(object, 'a[]'), 1); }); - test('`_.' + methodName + '` should handle empty paths', 4, function() { + QUnit.test('`_.' + methodName + '` should handle empty paths', function(assert) { + assert.expect(4); + _.each([['', ''], [[], ['']]], function(pair) { - strictEqual(func({}, pair[0]), undefined); - strictEqual(func({ '': 3 }, pair[1]), 3); + assert.strictEqual(func({}, pair[0]), undefined); + assert.strictEqual(func({ '': 3 }, pair[1]), 3); }); }); - test('`_.' + methodName + '` should handle complex paths', 2, function() { + QUnit.test('`_.' + methodName + '` should handle complex paths', function(assert) { + assert.expect(2); + var object = { 'a': { '-1.23': { '["b"]': { 'c': { "['d']": { '\ne\n': { 'f': { 'g': 8 } } } } } } } }; var paths = [ @@ -13412,18 +15387,22 @@ ]; _.each(paths, function(path) { - strictEqual(func(object, path), 8); + assert.strictEqual(func(object, path), 8); }); }); - test('`_.' + methodName + '` should return `undefined` when `object` is nullish', 4, function() { + QUnit.test('`_.' + methodName + '` should return `undefined` when `object` is nullish', function(assert) { + assert.expect(4); + _.each(['constructor', ['constructor']], function(path) { - strictEqual(func(null, path), undefined); - strictEqual(func(undefined, path), undefined); + assert.strictEqual(func(null, path), undefined); + assert.strictEqual(func(undefined, path), undefined); }); }); - test('`_.' + methodName + '` should return `undefined` with deep paths when `object` is nullish', 2, function() { + QUnit.test('`_.' + methodName + '` should return `undefined` with deep paths when `object` is nullish', function(assert) { + assert.expect(2); + var values = [null, undefined], expected = _.map(values, _.constant(undefined)), paths = ['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']]; @@ -13433,27 +15412,33 @@ return func(value, path); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }); - test('`_.' + methodName + '` should return `undefined` if parts of `path` are missing', 2, function() { + QUnit.test('`_.' + methodName + '` should return `undefined` if parts of `path` are missing', function(assert) { + assert.expect(2); + var object = { 'a': [, null] }; _.each(['a[1].b.c', ['a', '1', 'b', 'c']], function(path) { - strictEqual(func(object, path), undefined); + assert.strictEqual(func(object, path), undefined); }); }); - test('`_.' + methodName + '` should be able to return `null` values', 2, function() { + QUnit.test('`_.' + methodName + '` should be able to return `null` values', function(assert) { + assert.expect(2); + var object = { 'a': { 'b': null } }; _.each(['a.b', ['a', 'b']], function(path) { - strictEqual(func(object, path), null); + assert.strictEqual(func(object, path), null); }); }); - test('`_.' + methodName + '` should follow `path` over non-plain objects', 4, function() { + QUnit.test('`_.' + methodName + '` should follow `path` over non-plain objects', function(assert) { + assert.expect(4); + var object = { 'a': '' }, paths = ['constructor.prototype.a', ['constructor', 'prototype', 'a']]; @@ -13461,7 +15446,7 @@ numberProto.a = 1; var actual = func(0, path); - strictEqual(actual, 1); + assert.strictEqual(actual, 1); delete numberProto.a; }); @@ -13470,13 +15455,15 @@ stringProto.replace.b = 1; var actual = func(object, path); - strictEqual(actual, 1); + assert.strictEqual(actual, 1); delete stringProto.replace.b; }); }); - test('`_.' + methodName + '` should return the specified default value for `undefined` values', 1, function() { + QUnit.test('`_.' + methodName + '` should return the specified default value for `undefined` values', function(assert) { + assert.expect(1); + var object = { 'a': {} }, values = empties.concat(true, new Date, 1, /x/, 'a'); @@ -13493,7 +15480,7 @@ }); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }); @@ -13504,7 +15491,9 @@ (function() { var array = [1, 2, 3]; - test('should accept a falsey `array` argument', 1, function() { + 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) { @@ -13513,25 +15502,33 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should exclude the first element', 1, function() { - deepEqual(_.rest(array), [2, 3]); + QUnit.test('should exclude the first element', function(assert) { + assert.expect(1); + + assert.deepEqual(_.rest(array), [2, 3]); }); - test('should return an empty when querying empty arrays', 1, function() { - deepEqual(_.rest([]), []); + QUnit.test('should return an empty when querying empty arrays', function(assert) { + assert.expect(1); + + assert.deepEqual(_.rest([]), []); }); - test('should work as an iteratee for methods like `_.map`', 1, function() { + 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); - deepEqual(actual, [[2, 3], [5, 6], [8, 9]]); + assert.deepEqual(actual, [[2, 3], [5, 6], [8, 9]]); }); - test('should work in a lazy chain sequence', 4, function() { + QUnit.test('should work in a lazy chain sequence', function(assert) { + assert.expect(4); + if (!isNpm) { var array = _.range(LARGE_ARRAY_SIZE), values = []; @@ -13542,8 +15539,8 @@ }) .value(); - deepEqual(actual, []); - deepEqual(values, array.slice(1)); + assert.deepEqual(actual, []); + assert.deepEqual(values, array.slice(1)); values = []; @@ -13554,32 +15551,34 @@ .rest() .value(); - deepEqual(actual, _.rest(_.filter(array, isEven))); - deepEqual(values, array); + assert.deepEqual(actual, _.rest(_.filter(array, isEven))); + assert.deepEqual(values, array); } else { - skipTest(4); + skipTest(assert, 4); } }); - test('should not execute subsequent iteratees on an empty array in a lazy chain sequence', 4, function() { + 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(); - ok(pass); - deepEqual(actual, []); + assert.ok(pass); + assert.deepEqual(actual, []); pass = true; actual = _(array).filter().slice(0, 1).rest().map(iteratee).value(); - ok(pass); - deepEqual(actual, []); + assert.ok(pass); + assert.deepEqual(actual, []); } else { - skipTest(4); + skipTest(assert, 4); } }); }()); @@ -13593,17 +15592,23 @@ return slice.call(arguments); } - test('should apply a rest parameter to `func`', 1, function() { + QUnit.test('should apply a rest parameter to `func`', function(assert) { + assert.expect(1); + var rp = _.restParam(fn); - deepEqual(rp(1, 2, 3, 4), [1, 2, [3, 4]]); + assert.deepEqual(rp(1, 2, 3, 4), [1, 2, [3, 4]]); }); - test('should work with `start`', 1, function() { + QUnit.test('should work with `start`', function(assert) { + assert.expect(1); + var rp = _.restParam(fn, 1); - deepEqual(rp(1, 2, 3, 4), [1, [2, 3, 4]]); + assert.deepEqual(rp(1, 2, 3, 4), [1, [2, 3, 4]]); }); - test('should treat `start` as `0` for negative or `NaN` values', 1, function() { + QUnit.test('should treat `start` as `0` for negative or `NaN` values', function(assert) { + assert.expect(1); + var values = [-1, NaN, 'x'], expected = _.map(values, _.constant([[1, 2, 3, 4]])); @@ -13612,34 +15617,42 @@ return rp(1, 2, 3, 4); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should coerce `start` to an integer', 1, function() { + QUnit.test('should coerce `start` to an integer', function(assert) { + assert.expect(1); + var rp = _.restParam(fn, 1.6); - deepEqual(rp(1, 2, 3), [1, [2, 3]]); + assert.deepEqual(rp(1, 2, 3), [1, [2, 3]]); }); - test('should use an empty array when `start` is not reached', 1, function() { + QUnit.test('should use an empty array when `start` is not reached', function(assert) { + assert.expect(1); + var rp = _.restParam(fn); - deepEqual(rp(1), [1, undefined, []]); + assert.deepEqual(rp(1), [1, undefined, []]); }); - test('should work on functions with more than three params', 1, function() { + QUnit.test('should work on functions with more than three params', function(assert) { + assert.expect(1); + var rp = _.restParam(function(a, b, c, d) { return slice.call(arguments); }); - deepEqual(rp(1, 2, 3, 4, 5), [1, 2, 3, [4, 5]]); + assert.deepEqual(rp(1, 2, 3, 4, 5), [1, 2, 3, [4, 5]]); }); - test('should not set a `this` binding', 1, function() { + QUnit.test('should not set a `this` binding', function(assert) { + assert.expect(1); + var rp = _.restParam(function(x, y) { return this[x] + this[y[0]]; }); var object = { 'rp': rp, 'x': 4, 'y': 2 }; - strictEqual(object.rp('x', 'y'), 6); + assert.strictEqual(object.rp('x', 'y'), 6); }); }()); @@ -13652,37 +15665,47 @@ isCeil = methodName == 'ceil', isFloor = methodName == 'floor'; - test('`_.' + methodName + '` should return a rounded number without a precision', 1, function() { + QUnit.test('`_.' + methodName + '` should return a rounded number without a precision', function(assert) { + assert.expect(1); + var actual = func(4.006); - strictEqual(actual, isCeil ? 5 : 4); + assert.strictEqual(actual, isCeil ? 5 : 4); }); - test('`_.' + methodName + '` should return a rounded number with a precision of `0`', 1, function() { + QUnit.test('`_.' + methodName + '` should return a rounded number with a precision of `0`', function(assert) { + assert.expect(1); + var actual = func(4.006, 0); - strictEqual(actual, isCeil ? 5 : 4); + assert.strictEqual(actual, isCeil ? 5 : 4); }); - test('`_.' + methodName + '` should coerce `precision` to an integer', 3, function() { + QUnit.test('`_.' + methodName + '` should coerce `precision` to an integer', function(assert) { + assert.expect(3); + var actual = func(4.006, NaN); - strictEqual(actual, isCeil ? 5 : 4); + assert.strictEqual(actual, isCeil ? 5 : 4); var expected = isFloor ? 4.01 : 4.02; actual = func(4.016, 2.6); - strictEqual(actual, expected); + assert.strictEqual(actual, expected); actual = func(4.016, '+2'); - strictEqual(actual, expected); + assert.strictEqual(actual, expected); }); - test('`_.' + methodName + '` should return a rounded number with a positive precision', 1, function() { + QUnit.test('`_.' + methodName + '` should return a rounded number with a positive precision', function(assert) { + assert.expect(1); + var actual = func(4.016, 2); - strictEqual(actual, isFloor ? 4.01 : 4.02); + assert.strictEqual(actual, isFloor ? 4.01 : 4.02); }); - test('`_.' + methodName + '` should return a rounded number with a negative precision', 1, function() { + QUnit.test('`_.' + methodName + '` should return a rounded number with a negative precision', function(assert) { + assert.expect(1); + var actual = func(4160, -2); - strictEqual(actual, isFloor ? 4100 : 4200); + assert.strictEqual(actual, isFloor ? 4100 : 4200); }); }); @@ -13691,7 +15714,9 @@ QUnit.module('lodash.runInContext'); (function() { - test('should not require a fully populated `context` object', 1, function() { + QUnit.test('should not require a fully populated `context` object', function(assert) { + assert.expect(1); + if (!isModularize) { var lodash = _.runInContext({ 'setTimeout': function(callback) { @@ -13701,28 +15726,30 @@ var pass = false; lodash.delay(function() { pass = true; }, 32); - ok(pass); + assert.ok(pass); } else { - skipTest(); + skipTest(assert); } }); - test('should use a zeroed `_.uniqueId` counter', 3, function() { + QUnit.test('should use a zeroed `_.uniqueId` counter', function(assert) { + assert.expect(3); + if (!isModularize) { _.times(2, _.uniqueId); var oldId = Number(_.uniqueId()), lodash = _.runInContext(); - ok(_.uniqueId() > oldId); + assert.ok(_.uniqueId() > oldId); var id = lodash.uniqueId(); - strictEqual(id, '1'); - ok(id < oldId); + assert.strictEqual(id, '1'); + assert.ok(id < oldId); } else { - skipTest(3); + skipTest(assert, 3); } }); }()); @@ -13734,22 +15761,30 @@ (function() { var array = [1, 2, 3]; - test('should return a random element', 1, function() { + QUnit.test('should return a random element', function(assert) { + assert.expect(1); + var actual = _.sample(array); - ok(_.includes(array, actual)); + assert.ok(_.includes(array, actual)); }); - test('should return two random elements', 1, function() { + QUnit.test('should return two random elements', function(assert) { + assert.expect(1); + var actual = _.sample(array, 2); - ok(actual.length == 2 && actual[0] !== actual[1] && _.includes(array, actual[0]) && _.includes(array, actual[1])); + assert.ok(actual.length == 2 && actual[0] !== actual[1] && _.includes(array, actual[0]) && _.includes(array, actual[1])); }); - test('should contain elements of the collection', 1, function() { + QUnit.test('should contain elements of the collection', function(assert) { + assert.expect(1); + var actual = _.sample(array, array.length); - deepEqual(actual.sort(), array); + assert.deepEqual(actual.sort(), array); }); - test('should treat falsey `n` values, except nullish, as `0`', 1, function() { + QUnit.test('should treat falsey `n` values, except nullish, as `0`', function(assert) { + assert.expect(1); + var expected = _.map(falsey, function(value) { return value == null ? 1 : []; }); @@ -13758,31 +15793,41 @@ return _.sample([1], n); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return an empty array when `n` < `1` or `NaN`', 3, function() { + QUnit.test('should return an empty array when `n` < `1` or `NaN`', function(assert) { + assert.expect(3); + _.each([0, -1, -Infinity], function(n) { - deepEqual(_.sample(array, n), []); + assert.deepEqual(_.sample(array, n), []); }); }); - test('should return all elements when `n` >= `array.length`', 4, function() { + 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) { - deepEqual(_.sample(array, n).sort(), array); + assert.deepEqual(_.sample(array, n).sort(), array); }); }); - test('should coerce `n` to an integer', 1, function() { + QUnit.test('should coerce `n` to an integer', function(assert) { + assert.expect(1); + var actual = _.sample(array, 1.6); - strictEqual(actual.length, 1); + assert.strictEqual(actual.length, 1); }); - test('should return `undefined` when sampling an empty array', 1, function() { - strictEqual(_.sample([]), undefined); + QUnit.test('should return `undefined` when sampling an empty array', function(assert) { + assert.expect(1); + + assert.strictEqual(_.sample([]), undefined); }); - test('should return an empty array for empty collections', 1, function() { + QUnit.test('should return an empty array for empty collections', function(assert) { + assert.expect(1); + var expected = _.transform(empties, function(result) { result.push(undefined, []); }); @@ -13794,20 +15839,24 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should sample an object', 2, function() { + QUnit.test('should sample an object', function(assert) { + assert.expect(2); + var object = { 'a': 1, 'b': 2, 'c': 3 }, actual = _.sample(object); - ok(_.includes(array, actual)); + assert.ok(_.includes(array, actual)); actual = _.sample(object, 2); - ok(actual.length == 2 && actual[0] !== actual[1] && _.includes(array, actual[0]) && _.includes(array, actual[1])); + assert.ok(actual.length == 2 && actual[0] !== actual[1] && _.includes(array, actual[0]) && _.includes(array, actual[1])); }); - test('should work as an iteratee for methods like `_.map`', 2, function() { + QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { + assert.expect(2); + var array1 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], array2 = ['abc', 'def', 'ghi']; @@ -13817,54 +15866,62 @@ c = values[2], actual = _.map(values, _.sample); - ok(_.includes(a, actual[0]) && _.includes(b, actual[1]) && _.includes(c, actual[2])); + assert.ok(_.includes(a, actual[0]) && _.includes(b, actual[1]) && _.includes(c, actual[2])); }); }); - test('should return a wrapped value when chaining and `n` is provided', 2, function() { + QUnit.test('should return a wrapped value when chaining and `n` is provided', function(assert) { + assert.expect(2); + if (!isNpm) { var wrapped = _(array).sample(2), actual = wrapped.value(); - ok(wrapped instanceof _); - ok(actual.length == 2 && actual[0] !== actual[1] && _.includes(array, actual[0]) && _.includes(array, actual[1])); + assert.ok(wrapped instanceof _); + assert.ok(actual.length == 2 && actual[0] !== actual[1] && _.includes(array, actual[0]) && _.includes(array, actual[1])); } else { - skipTest(2); + skipTest(assert, 2); } }); - test('should return an unwrapped value when chaining and `n` is not provided', 1, function() { + QUnit.test('should return an unwrapped value when chaining and `n` is not provided', function(assert) { + assert.expect(1); + if (!isNpm) { var actual = _(array).sample(); - ok(_.includes(array, actual)); + assert.ok(_.includes(array, actual)); } else { - skipTest(); + skipTest(assert); } }); - test('should return a wrapped value when explicitly chaining', 1, function() { + QUnit.test('should return a wrapped value when explicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - ok(_(array).chain().sample() instanceof _); + assert.ok(_(array).chain().sample() instanceof _); } else { - skipTest(); + skipTest(assert); } }); - test('should use a stored reference to `_.sample` when chaining', 2, function() { + QUnit.test('should use a stored reference to `_.sample` when chaining', function(assert) { + assert.expect(2); + if (!isNpm) { var sample = _.sample; _.sample = _.noop; var wrapped = _(array); - notStrictEqual(wrapped.sample(), undefined); - notStrictEqual(wrapped.sample(2).value(), undefined); + assert.notStrictEqual(wrapped.sample(), undefined); + assert.notStrictEqual(wrapped.sample(2).value(), undefined); _.sample = sample; } else { - skipTest(2); + skipTest(assert, 2); } }); }()); @@ -13874,19 +15931,23 @@ QUnit.module('lodash.setWith'); (function() { - test('should work with a `customizer` callback', 1, function() { + QUnit.test('should work with a `customizer` callback', function(assert) { + assert.expect(1); + var actual = _.setWith({ '0': { 'length': 2 } }, '[0][1][2]', 3, function(value) { if (!_.isObject(value)) { return {}; } }); - deepEqual(actual, { '0': { '1': { '2': 3 }, 'length': 2 } }); + assert.deepEqual(actual, { '0': { '1': { '2': 3 }, 'length': 2 } }); }); - test('should work with a `customizer` that returns `undefined`', 1, function() { + QUnit.test('should work with a `customizer` that returns `undefined`', function(assert) { + assert.expect(1); + var actual = _.setWith({}, 'a[0].b.c', 4, _.constant(undefined)); - deepEqual(actual, { 'a': [{ 'b': { 'c': 4 } }] }); + assert.deepEqual(actual, { 'a': [{ 'b': { 'c': 4 } }] }); }); }()); @@ -13897,70 +15958,84 @@ _.each(['set', 'setWith'], function(methodName) { var func = _[methodName]; - test('`_.' + methodName + '` should set property values', 4, function() { + QUnit.test('`_.' + methodName + '` should set property values', function(assert) { + assert.expect(4); + var object = { 'a': 1 }; _.each(['a', ['a']], function(path) { var actual = func(object, path, 2); - strictEqual(actual, object); - strictEqual(object.a, 2); + assert.strictEqual(actual, object); + assert.strictEqual(object.a, 2); object.a = 1; }); }); - test('`_.' + methodName + '` should set deep property values', 4, function() { + QUnit.test('`_.' + methodName + '` should set deep property values', function(assert) { + assert.expect(4); + var object = { 'a': { 'b': { 'c': 3 } } }; _.each(['a.b.c', ['a', 'b', 'c']], function(path) { var actual = func(object, path, 4); - strictEqual(actual, object); - strictEqual(object.a.b.c, 4); + assert.strictEqual(actual, object); + assert.strictEqual(object.a.b.c, 4); object.a.b.c = 3; }); }); - test('`_.' + methodName + '` should set a key over a path', 4, function() { + QUnit.test('`_.' + methodName + '` should set a key over a path', function(assert) { + assert.expect(4); + var object = { 'a.b.c': 3 }; _.each(['a.b.c', ['a.b.c']], function(path) { var actual = func(object, path, 4); - strictEqual(actual, object); - deepEqual(object, { 'a.b.c': 4 }); + assert.strictEqual(actual, object); + assert.deepEqual(object, { 'a.b.c': 4 }); object['a.b.c'] = 3; }); }); - test('`_.' + methodName + '` should not coerce array paths to strings', 1, function() { + QUnit.test('`_.' + methodName + '` should not coerce array paths to strings', function(assert) { + assert.expect(1); + var object = { 'a,b,c': 3, 'a': { 'b': { 'c': 3 } } }; func(object, ['a', 'b', 'c'], 4); - strictEqual(object.a.b.c, 4); + assert.strictEqual(object.a.b.c, 4); }); - test('`_.' + methodName + '` should ignore empty brackets', 1, function() { + QUnit.test('`_.' + methodName + '` should ignore empty brackets', function(assert) { + assert.expect(1); + var object = {}; func(object, 'a[]', 1); - deepEqual(object, { 'a': 1 }); + assert.deepEqual(object, { 'a': 1 }); }); - test('`_.' + methodName + '` should handle empty paths', 4, function() { + QUnit.test('`_.' + methodName + '` should handle empty paths', function(assert) { + assert.expect(4); + _.each([['', ''], [[], ['']]], function(pair, index) { var object = {}; func(object, pair[0], 1); - deepEqual(object, index ? {} : { '': 1 }); + assert.deepEqual(object, index ? {} : { '': 1 }); func(object, pair[1], 2); - deepEqual(object, { '': 2 }); + assert.deepEqual(object, { '': 2 }); }); }); - test('`_.' + methodName + '` should handle complex paths', 2, function() { + QUnit.test('`_.' + methodName + '` should handle complex paths', function(assert) { + assert.expect(2); + var object = { 'a': { '1.23': { '["b"]': { 'c': { "['d']": { '\ne\n': { 'f': { 'g': 8 } } } } } } } }; var paths = [ @@ -13970,26 +16045,30 @@ _.each(paths, function(path) { func(object, path, 10); - strictEqual(object.a[-1.23]['["b"]'].c["['d']"]['\ne\n'].f.g, 10); + assert.strictEqual(object.a[-1.23]['["b"]'].c["['d']"]['\ne\n'].f.g, 10); object.a[-1.23]['["b"]'].c["['d']"]['\ne\n'].f.g = 8; }); }); - test('`_.' + methodName + '` should create parts of `path` that are missing', 6, function() { + QUnit.test('`_.' + methodName + '` should create parts of `path` that are missing', function(assert) { + assert.expect(6); + var object = {}; _.each(['a[1].b.c', ['a', '1', 'b', 'c']], function(path) { var actual = func(object, path, 4); - strictEqual(actual, object); - deepEqual(actual, { 'a': [undefined, { 'b': { 'c': 4 } }] }); - ok(!(0 in object.a)); + assert.strictEqual(actual, object); + assert.deepEqual(actual, { 'a': [undefined, { 'b': { 'c': 4 } }] }); + assert.notOk('0' in object.a); delete object.a; }); }); - test('`_.' + methodName + '` should not error when `object` is nullish', 1, function() { + QUnit.test('`_.' + methodName + '` should not error when `object` is nullish', function(assert) { + assert.expect(1); + var values = [null, undefined], expected = [[null, null], [undefined, undefined]]; @@ -14001,35 +16080,39 @@ } }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('`_.' + methodName + '` should follow `path` over non-plain objects', 4, function() { + QUnit.test('`_.' + methodName + '` should follow `path` over non-plain objects', function(assert) { + assert.expect(4); + var object = { 'a': '' }, paths = ['constructor.prototype.a', ['constructor', 'prototype', 'a']]; _.each(paths, function(path) { func(0, path, 1); - strictEqual(0..a, 1); + assert.strictEqual(0..a, 1); delete numberProto.a; }); _.each(['a.replace.b', ['a', 'replace', 'b']], function(path) { func(object, path, 1); - strictEqual(stringProto.replace.b, 1); + assert.strictEqual(stringProto.replace.b, 1); delete stringProto.replace.b; }); }); - test('`_.' + methodName + '` should not error on paths over primitives in strict mode', 2, function() { + QUnit.test('`_.' + methodName + '` should not error on paths over primitives in strict mode', function(assert) { + assert.expect(2); + numberProto.a = 0; _.each(['a', 'a.a.a'], function(path) { try { func(0, path, 1); - strictEqual(0..a, 0); + assert.strictEqual(0..a, 0); } catch (e) { - ok(false, e.message); + assert.ok(false, e.message); } numberProto.a = 0; }); @@ -14037,14 +16120,18 @@ delete numberProto.a; }); - test('`_.' + methodName + '` should not create an array for missing non-index property names that start with numbers', 1, function() { + QUnit.test('`_.' + methodName + '` should not create an array for missing non-index property names that start with numbers', function(assert) { + assert.expect(1); + var object = {}; func(object, ['1a', '2b', '3c'], 1); - deepEqual(object, { '1a': { '2b': { '3c': 1 } } }); + assert.deepEqual(object, { '1a': { '2b': { '3c': 1 } } }); }); - test('`_.' + methodName + '` should not assign values that are the same as their destinations', 4, function() { + QUnit.test('`_.' + methodName + '` should not assign values that are the same as their destinations', function(assert) { + assert.expect(4); + _.each(['a', ['a'], { 'a': 1 }, NaN], function(value) { if (defineProperty) { var object = {}, @@ -14056,10 +16143,10 @@ }); func(object, 'a', value); - ok(pass, value); + assert.ok(pass, value); } else { - skipTest(); + skipTest(assert); } }); }); @@ -14073,25 +16160,33 @@ var array = [1, 2, 3], object = { 'a': 1, 'b': 2, 'c': 3 }; - test('should return a new array', 1, function() { - notStrictEqual(_.shuffle(array), array); + QUnit.test('should return a new array', function(assert) { + assert.expect(1); + + assert.notStrictEqual(_.shuffle(array), array); }); - test('should contain the same elements after a collection is shuffled', 2, function() { - deepEqual(_.shuffle(array).sort(), array); - deepEqual(_.shuffle(object).sort(), array); + QUnit.test('should contain the same elements after a collection is shuffled', function(assert) { + assert.expect(2); + + assert.deepEqual(_.shuffle(array).sort(), array); + assert.deepEqual(_.shuffle(object).sort(), array); }); - test('should shuffle small collections', 1, function() { - var actual = _.times(1000, function() { + QUnit.test('should shuffle small collections', function(assert) { + assert.expect(1); + + var actual = _.times(1000, function(assert) { return _.shuffle([1, 2]); }); - deepEqual(_.sortBy(_.uniqBy(actual, String), '0'), [[1, 2], [2, 1]]); + assert.deepEqual(_.sortBy(_.uniqBy(actual, String), '0'), [[1, 2], [2, 1]]); }); - test('should treat number values for `collection` as empty', 1, function() { - deepEqual(_.shuffle(1), []); + QUnit.test('should treat number values for `collection` as empty', function(assert) { + assert.expect(1); + + assert.deepEqual(_.shuffle(1), []); }); }()); @@ -14103,15 +16198,21 @@ var args = arguments, array = [1, 2, 3]; - test('should return the number of own enumerable properties of an object', 1, function() { - strictEqual(_.size({ 'one': 1, 'two': 2, 'three': 3 }), 3); + QUnit.test('should return the number of own enumerable properties of an object', function(assert) { + assert.expect(1); + + assert.strictEqual(_.size({ 'one': 1, 'two': 2, 'three': 3 }), 3); }); - test('should return the length of an array', 1, function() { - strictEqual(_.size(array), 3); + QUnit.test('should return the length of an array', function(assert) { + assert.expect(1); + + assert.strictEqual(_.size(array), 3); }); - test('should accept a falsey `object` argument', 1, function() { + QUnit.test('should accept a falsey `object` argument', function(assert) { + assert.expect(1); + var expected = _.map(falsey, _.constant(0)); var actual = _.map(falsey, function(object, index) { @@ -14120,30 +16221,40 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work with `arguments` objects', 1, function() { - strictEqual(_.size(args), 3); + QUnit.test('should work with `arguments` objects', function(assert) { + assert.expect(1); + + assert.strictEqual(_.size(args), 3); }); - test('should work with jQuery/MooTools DOM query collections', 1, function() { + QUnit.test('should work with jQuery/MooTools DOM query collections', function(assert) { + assert.expect(1); + function Foo(elements) { push.apply(this, elements); } Foo.prototype = { 'length': 0, 'splice': arrayProto.splice }; - strictEqual(_.size(new Foo(array)), 3); + assert.strictEqual(_.size(new Foo(array)), 3); }); - test('should not treat objects with negative lengths as array-like', 1, function() { - strictEqual(_.size({ 'length': -1 }), 1); + QUnit.test('should not treat objects with negative lengths as array-like', function(assert) { + assert.expect(1); + + assert.strictEqual(_.size({ 'length': -1 }), 1); }); - test('should not treat objects with lengths larger than `MAX_SAFE_INTEGER` as array-like', 1, function() { - strictEqual(_.size({ 'length': MAX_SAFE_INTEGER + 1 }), 1); + QUnit.test('should not treat objects with lengths larger than `MAX_SAFE_INTEGER` as array-like', function(assert) { + assert.expect(1); + + assert.strictEqual(_.size({ 'length': MAX_SAFE_INTEGER + 1 }), 1); }); - test('should not treat objects with non-number lengths as array-like', 1, function() { - strictEqual(_.size({ 'length': '0' }), 1); + QUnit.test('should not treat objects with non-number lengths as array-like', function(assert) { + assert.expect(1); + + assert.strictEqual(_.size({ 'length': '0' }), 1); }); }(1, 2, 3)); @@ -14154,60 +16265,80 @@ (function() { var array = [1, 2, 3]; - test('should use a default `start` of `0` and a default `end` of `array.length`', 2, function() { + QUnit.test('should use a default `start` of `0` and a default `end` of `array.length`', function(assert) { + assert.expect(2); + var actual = _.slice(array); - deepEqual(actual, array); - notStrictEqual(actual, array); + assert.deepEqual(actual, array); + assert.notStrictEqual(actual, array); }); - test('should work with a positive `start`', 2, function() { - deepEqual(_.slice(array, 1), [2, 3]); - deepEqual(_.slice(array, 1, 3), [2, 3]); + QUnit.test('should work with a positive `start`', function(assert) { + assert.expect(2); + + assert.deepEqual(_.slice(array, 1), [2, 3]); + assert.deepEqual(_.slice(array, 1, 3), [2, 3]); }); - test('should work with a `start` >= `array.length`', 4, function() { + QUnit.test('should work with a `start` >= `array.length`', function(assert) { + assert.expect(4); + _.each([3, 4, Math.pow(2, 32), Infinity], function(start) { - deepEqual(_.slice(array, start), []); + assert.deepEqual(_.slice(array, start), []); }); }); - test('should treat falsey `start` values as `0`', 1, function() { + QUnit.test('should treat falsey `start` values as `0`', function(assert) { + assert.expect(1); + var expected = _.map(falsey, _.constant(array)); var actual = _.map(falsey, function(start) { return _.slice(array, start); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work with a negative `start`', 1, function() { - deepEqual(_.slice(array, -1), [3]); + QUnit.test('should work with a negative `start`', function(assert) { + assert.expect(1); + + assert.deepEqual(_.slice(array, -1), [3]); }); - test('should work with a negative `start` <= negative `array.length`', 3, function() { + QUnit.test('should work with a negative `start` <= negative `array.length`', function(assert) { + assert.expect(3); + _.each([-3, -4, -Infinity], function(start) { - deepEqual(_.slice(array, start), array); + assert.deepEqual(_.slice(array, start), array); }); }); - test('should work with `start` >= `end`', 2, function() { + QUnit.test('should work with `start` >= `end`', function(assert) { + assert.expect(2); + _.each([2, 3], function(start) { - deepEqual(_.slice(array, start, 2), []); + assert.deepEqual(_.slice(array, start, 2), []); }); }); - test('should work with a positive `end`', 1, function() { - deepEqual(_.slice(array, 0, 1), [1]); + QUnit.test('should work with a positive `end`', function(assert) { + assert.expect(1); + + assert.deepEqual(_.slice(array, 0, 1), [1]); }); - test('should work with a `end` >= `array.length`', 4, function() { + QUnit.test('should work with a `end` >= `array.length`', function(assert) { + assert.expect(4); + _.each([3, 4, Math.pow(2, 32), Infinity], function(end) { - deepEqual(_.slice(array, 0, end), array); + assert.deepEqual(_.slice(array, 0, end), array); }); }); - test('should treat falsey `end` values, except `undefined`, as `0`', 1, function() { + QUnit.test('should treat falsey `end` values, except `undefined`, as `0`', function(assert) { + assert.expect(1); + var expected = _.map(falsey, function(value) { return value === undefined ? array : []; }); @@ -14216,71 +16347,81 @@ return _.slice(array, 0, end); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work with a negative `end`', 1, function() { - deepEqual(_.slice(array, 0, -1), [1, 2]); + QUnit.test('should work with a negative `end`', function(assert) { + assert.expect(1); + + assert.deepEqual(_.slice(array, 0, -1), [1, 2]); }); - test('should work with a negative `end` <= negative `array.length`', 3, function() { + QUnit.test('should work with a negative `end` <= negative `array.length`', function(assert) { + assert.expect(3); + _.each([-3, -4, -Infinity], function(end) { - deepEqual(_.slice(array, 0, end), []); + assert.deepEqual(_.slice(array, 0, end), []); }); }); - test('should coerce `start` and `end` to integers', 1, function() { + QUnit.test('should coerce `start` and `end` to integers', function(assert) { + assert.expect(1); + var positions = [[0.1, 1.6], ['0', 1], [0, '1'], ['1'], [NaN, 1], [1, NaN]]; var actual = _.map(positions, function(pos) { return _.slice.apply(_, [array].concat(pos)); }); - deepEqual(actual, [[1], [1], [1], [2, 3], [1], []]); + assert.deepEqual(actual, [[1], [1], [1], [2, 3], [1], []]); }); - test('should work as an iteratee for methods like `_.map`', 2, function() { + QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { + assert.expect(2); + var array = [[1], [2, 3]], actual = _.map(array, _.slice); - deepEqual(actual, array); - notStrictEqual(actual, array); + assert.deepEqual(actual, array); + assert.notStrictEqual(actual, array); }); - test('should work in a lazy chain sequence', 38, function() { + QUnit.test('should work in a lazy chain sequence', function(assert) { + assert.expect(38); + if (!isNpm) { var array = _.range(1, LARGE_ARRAY_SIZE + 1), length = array.length, wrapped = _(array); _.each(['map', 'filter'], function(methodName) { - deepEqual(wrapped[methodName]().slice(0, -1).value(), array.slice(0, -1)); - deepEqual(wrapped[methodName]().slice(1).value(), array.slice(1)); - deepEqual(wrapped[methodName]().slice(1, 3).value(), array.slice(1, 3)); - deepEqual(wrapped[methodName]().slice(-1).value(), array.slice(-1)); - - deepEqual(wrapped[methodName]().slice(length).value(), array.slice(length)); - deepEqual(wrapped[methodName]().slice(3, 2).value(), array.slice(3, 2)); - deepEqual(wrapped[methodName]().slice(0, -length).value(), array.slice(0, -length)); - deepEqual(wrapped[methodName]().slice(0, null).value(), array.slice(0, null)); - - deepEqual(wrapped[methodName]().slice(0, length).value(), array.slice(0, length)); - deepEqual(wrapped[methodName]().slice(-length).value(), array.slice(-length)); - deepEqual(wrapped[methodName]().slice(null).value(), array.slice(null)); - - deepEqual(wrapped[methodName]().slice(0, 1).value(), array.slice(0, 1)); - deepEqual(wrapped[methodName]().slice(NaN, '1').value(), array.slice(NaN, '1')); - - deepEqual(wrapped[methodName]().slice(0.1, 1.1).value(), array.slice(0.1, 1.1)); - deepEqual(wrapped[methodName]().slice('0', 1).value(), array.slice('0', 1)); - deepEqual(wrapped[methodName]().slice(0, '1').value(), array.slice(0, '1')); - deepEqual(wrapped[methodName]().slice('1').value(), array.slice('1')); - deepEqual(wrapped[methodName]().slice(NaN, 1).value(), array.slice(NaN, 1)); - deepEqual(wrapped[methodName]().slice(1, NaN).value(), array.slice(1, NaN)); + assert.deepEqual(wrapped[methodName]().slice(0, -1).value(), array.slice(0, -1)); + assert.deepEqual(wrapped[methodName]().slice(1).value(), array.slice(1)); + assert.deepEqual(wrapped[methodName]().slice(1, 3).value(), array.slice(1, 3)); + assert.deepEqual(wrapped[methodName]().slice(-1).value(), array.slice(-1)); + + assert.deepEqual(wrapped[methodName]().slice(length).value(), array.slice(length)); + assert.deepEqual(wrapped[methodName]().slice(3, 2).value(), array.slice(3, 2)); + assert.deepEqual(wrapped[methodName]().slice(0, -length).value(), array.slice(0, -length)); + assert.deepEqual(wrapped[methodName]().slice(0, null).value(), array.slice(0, null)); + + assert.deepEqual(wrapped[methodName]().slice(0, length).value(), array.slice(0, length)); + assert.deepEqual(wrapped[methodName]().slice(-length).value(), array.slice(-length)); + assert.deepEqual(wrapped[methodName]().slice(null).value(), array.slice(null)); + + assert.deepEqual(wrapped[methodName]().slice(0, 1).value(), array.slice(0, 1)); + assert.deepEqual(wrapped[methodName]().slice(NaN, '1').value(), array.slice(NaN, '1')); + + assert.deepEqual(wrapped[methodName]().slice(0.1, 1.1).value(), array.slice(0.1, 1.1)); + assert.deepEqual(wrapped[methodName]().slice('0', 1).value(), array.slice('0', 1)); + assert.deepEqual(wrapped[methodName]().slice(0, '1').value(), array.slice(0, '1')); + assert.deepEqual(wrapped[methodName]().slice('1').value(), array.slice('1')); + assert.deepEqual(wrapped[methodName]().slice(NaN, 1).value(), array.slice(NaN, 1)); + assert.deepEqual(wrapped[methodName]().slice(1, NaN).value(), array.slice(1, NaN)); }); } else { - skipTest(38); + skipTest(assert, 38); } }); }()); @@ -14290,7 +16431,9 @@ QUnit.module('lodash.some'); (function() { - test('should return `false` for empty collections', 1, function() { + QUnit.test('should return `false` for empty collections', function(assert) { + assert.expect(1); + var expected = _.map(empties, _.constant(false)); var actual = _.map(empties, function(value) { @@ -14299,36 +16442,48 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return `true` if `predicate` returns truthy for any element in the collection', 2, function() { - strictEqual(_.some([false, 1, ''], _.identity), true); - strictEqual(_.some([null, 'x', 0], _.identity), true); + QUnit.test('should return `true` if `predicate` returns truthy for any element in the collection', function(assert) { + assert.expect(2); + + assert.strictEqual(_.some([false, 1, ''], _.identity), true); + assert.strictEqual(_.some([null, 'x', 0], _.identity), true); }); - test('should return `false` if `predicate` returns falsey for all elements in the collection', 2, function() { - strictEqual(_.some([false, false, false], _.identity), false); - strictEqual(_.some([null, 0, ''], _.identity), false); + QUnit.test('should return `false` if `predicate` returns falsey for all elements in the collection', function(assert) { + assert.expect(2); + + assert.strictEqual(_.some([false, false, false], _.identity), false); + assert.strictEqual(_.some([null, 0, ''], _.identity), false); }); - test('should return `true` as soon as `predicate` returns truthy', 1, function() { - strictEqual(_.some([null, true, null], _.identity), true); + QUnit.test('should return `true` as soon as `predicate` returns truthy', function(assert) { + assert.expect(1); + + assert.strictEqual(_.some([null, true, null], _.identity), true); }); - test('should work with a "_.property" style `predicate`', 2, function() { + QUnit.test('should work with a "_.property" style `predicate`', function(assert) { + assert.expect(2); + var objects = [{ 'a': 0, 'b': 0 }, { 'a': 0, 'b': 1 }]; - strictEqual(_.some(objects, 'a'), false); - strictEqual(_.some(objects, 'b'), true); + assert.strictEqual(_.some(objects, 'a'), false); + assert.strictEqual(_.some(objects, 'b'), true); }); - test('should work with a "_.matches" style `predicate`', 2, function() { + QUnit.test('should work with a "_.matches" style `predicate`', function(assert) { + assert.expect(2); + var objects = [{ 'a': 0, 'b': 0 }, { 'a': 1, 'b': 1}]; - strictEqual(_.some(objects, { 'a': 0 }), true); - strictEqual(_.some(objects, { 'b': 2 }), false); + assert.strictEqual(_.some(objects, { 'a': 0 }), true); + assert.strictEqual(_.some(objects, { 'b': 2 }), false); }); - test('should use `_.identity` when `predicate` is nullish', 2, function() { + QUnit.test('should use `_.identity` when `predicate` is nullish', function(assert) { + assert.expect(2); + var values = [, null, undefined], expected = _.map(values, _.constant(false)); @@ -14337,7 +16492,7 @@ return index ? _.some(array, value) : _.some(array); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); expected = _.map(values, _.constant(true)); actual = _.map(values, function(value, index) { @@ -14345,12 +16500,14 @@ return index ? _.some(array, value) : _.some(array); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work as an iteratee for methods like `_.map`', 1, function() { + QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { + assert.expect(1); + var actual = _.map([[1]], _.some); - deepEqual(actual, [true]); + assert.deepEqual(actual, [true]); }); }()); @@ -14366,15 +16523,19 @@ { 'a': 'y', 'b': 2 } ]; - test('should sort in ascending order', 1, function() { + QUnit.test('should sort in ascending order', function(assert) { + assert.expect(1); + var actual = _.map(_.sortBy(objects, function(object) { return object.b; }), 'b'); - deepEqual(actual, [1, 2, 3, 4]); + assert.deepEqual(actual, [1, 2, 3, 4]); }); - test('should use `_.identity` when `iteratee` is nullish', 1, function() { + QUnit.test('should use `_.identity` when `iteratee` is nullish', function(assert) { + assert.expect(1); + var array = [3, 2, 1], values = [, null, undefined], expected = _.map(values, _.constant([1, 2, 3])); @@ -14383,47 +16544,59 @@ return index ? _.sortBy(array, value) : _.sortBy(array); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work with a "_.property" style `iteratee`', 1, function() { + QUnit.test('should work with a "_.property" style `iteratee`', function(assert) { + assert.expect(1); + var actual = _.map(_.sortBy(objects.concat(undefined), 'b'), 'b'); - deepEqual(actual, [1, 2, 3, 4, undefined]); + assert.deepEqual(actual, [1, 2, 3, 4, undefined]); }); - test('should work with an object for `collection`', 1, function() { + QUnit.test('should work with an object for `collection`', function(assert) { + assert.expect(1); + var actual = _.sortBy({ 'a': 1, 'b': 2, 'c': 3 }, function(num) { return Math.sin(num); }); - deepEqual(actual, [3, 1, 2]); + assert.deepEqual(actual, [3, 1, 2]); }); - test('should move `null`, `undefined`, and `NaN` values to the end', 2, function() { + QUnit.test('should move `null`, `undefined`, and `NaN` values to the end', function(assert) { + assert.expect(2); + var array = [NaN, undefined, null, 4, null, 1, undefined, 3, NaN, 2]; - deepEqual(_.sortBy(array), [1, 2, 3, 4, null, null, undefined, undefined, NaN, NaN]); + assert.deepEqual(_.sortBy(array), [1, 2, 3, 4, null, null, undefined, undefined, NaN, NaN]); array = [NaN, undefined, null, 'd', null, 'a', undefined, 'c', NaN, 'b']; - deepEqual(_.sortBy(array), ['a', 'b', 'c', 'd', null, null, undefined, undefined, NaN, NaN]); + assert.deepEqual(_.sortBy(array), ['a', 'b', 'c', 'd', null, null, undefined, undefined, NaN, NaN]); }); - test('should treat number values for `collection` as empty', 1, function() { - deepEqual(_.sortBy(1), []); + QUnit.test('should treat number values for `collection` as empty', function(assert) { + assert.expect(1); + + assert.deepEqual(_.sortBy(1), []); }); - test('should coerce arrays returned from `iteratee`', 1, function() { + QUnit.test('should coerce arrays returned from `iteratee`', function(assert) { + assert.expect(1); + var actual = _.sortBy(objects, function(object) { var result = [object.a, object.b]; result.toString = function() { return String(this[0]); }; return result; }); - deepEqual(actual, [objects[0], objects[2], objects[1], objects[3]]); + assert.deepEqual(actual, [objects[0], objects[2], objects[1], objects[3]]); }); - test('should work as an iteratee for methods like `_.map`', 1, function() { + QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { + assert.expect(1); + var actual = _.map([[2, 1, 3], [3, 2, 1]], _.sortBy); - deepEqual(actual, [[1, 2, 3], [1, 2, 3]]); + assert.deepEqual(actual, [[1, 2, 3], [1, 2, 3]]); }); }()); @@ -14439,14 +16612,18 @@ { 'a': 'y', 'b': 2 } ]; - test('should sort multiple properties by specified orders', 1, function() { + QUnit.test('should sort multiple properties by specified orders', function(assert) { + assert.expect(1); + var actual = _.sortByOrder(objects, ['a', 'b'], ['desc', 'asc']); - deepEqual(actual, [objects[3], objects[1], objects[2], objects[0]]); + assert.deepEqual(actual, [objects[3], objects[1], objects[2], objects[0]]); }); - test('should sort a property in ascending order when its order is not specified', 1, function() { + QUnit.test('should sort a property in ascending order when its order is not specified', function(assert) { + assert.expect(1); + var actual = _.sortByOrder(objects, ['a', 'b'], ['desc']); - deepEqual(actual, [objects[3], objects[1], objects[2], objects[0]]); + assert.deepEqual(actual, [objects[3], objects[1], objects[2], objects[0]]); }); }()); @@ -14485,32 +16662,42 @@ var stableObject = _.zipObject('abcdefghijklmnopqrst'.split(''), stableArray); - test('`_.' + methodName + '` should sort mutliple properties in ascending order', 1, function() { + QUnit.test('`_.' + methodName + '` should sort mutliple properties in ascending order', function(assert) { + assert.expect(1); + var actual = func(objects, ['a', 'b']); - deepEqual(actual, [objects[2], objects[0], objects[3], objects[1]]); + assert.deepEqual(actual, [objects[2], objects[0], objects[3], objects[1]]); }); - test('`_.' + methodName + '` should support iteratees', 1, function() { + QUnit.test('`_.' + methodName + '` should support iteratees', function(assert) { + assert.expect(1); + var actual = func(objects, ['a', function(object) { return object.b; }]); - deepEqual(actual, [objects[2], objects[0], objects[3], objects[1]]); + assert.deepEqual(actual, [objects[2], objects[0], objects[3], objects[1]]); }); - test('`_.' + methodName + '` should perform a stable sort (test in IE > 8, Opera, and V8)', 2, function() { + QUnit.test('`_.' + methodName + '` should perform a stable sort (test in IE > 8, Opera, and V8)', function(assert) { + assert.expect(2); + _.each([stableArray, stableObject], function(value, index) { var actual = func(value, ['a', 'c']); - deepEqual(actual, stableArray, index ? 'object' : 'array'); + assert.deepEqual(actual, stableArray, index ? 'object' : 'array'); }); }); - test('`_.' + methodName + '` should not error on nullish elements', 1, function() { + QUnit.test('`_.' + methodName + '` should not error on nullish elements', function(assert) { + assert.expect(1); + try { var actual = func(objects.concat(null, undefined), ['a', 'b']); } catch (e) {} - deepEqual(actual, [objects[2], objects[0], objects[3], objects[1], null, undefined]); + assert.deepEqual(actual, [objects[2], objects[0], objects[3], objects[1], null, undefined]); }); - test('`_.' + methodName + '` should work as an iteratee for methods like `_.reduce`', 3, function() { + QUnit.test('`_.' + methodName + '` should work as an iteratee for methods like `_.reduce`', function(assert) { + assert.expect(3); + var objects = [ { 'a': 'x', '0': 3 }, { 'a': 'y', '0': 4 }, @@ -14530,7 +16717,7 @@ return _.reduce([props], func, objects); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }); }); @@ -14543,7 +16730,9 @@ var func = _[methodName], isSortedIndex = methodName == 'sortedIndex'; - test('`_.' + methodName + '` should return the insert index', 1, function() { + QUnit.test('`_.' + methodName + '` should return the insert index', function(assert) { + assert.expect(1); + var array = [30, 50], values = [30, 40, 50], expected = isSortedIndex ? [0, 1, 1] : [1, 1, 2]; @@ -14552,10 +16741,12 @@ return func(array, value); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('`_.' + methodName + '` should work with an array of strings', 1, function() { + QUnit.test('`_.' + methodName + '` should work with an array of strings', function(assert) { + assert.expect(1); + var array = ['a', 'c'], values = ['a', 'b', 'c'], expected = isSortedIndex ? [0, 1, 1] : [1, 1, 2]; @@ -14564,31 +16755,35 @@ return func(array, value); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('`_.' + methodName + '` should accept a falsey `array` argument and a `value`', 1, function() { + QUnit.test('`_.' + methodName + '` should accept a falsey `array` argument and a `value`', function(assert) { + assert.expect(1); + var expected = _.map(falsey, _.constant([0, 0, 0])); var actual = _.map(falsey, function(array) { return [func(array, 1), func(array, undefined), func(array, NaN)]; }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('`_.' + methodName + '` should align with `_.sortBy`', 10, function() { + QUnit.test('`_.' + methodName + '` should align with `_.sortBy`', function(assert) { + assert.expect(10); + var expected = [1, '2', {}, null, undefined, NaN, NaN]; _.each([ [NaN, null, 1, '2', {}, NaN, undefined], ['2', null, 1, NaN, {}, NaN, undefined] ], function(array) { - deepEqual(_.sortBy(array), expected); - strictEqual(func(expected, 3), 2); - strictEqual(func(expected, null), isSortedIndex ? 3 : 4); - strictEqual(func(expected, undefined), isSortedIndex ? 4 : 5); - strictEqual(func(expected, NaN), isSortedIndex ? 5 : 7); + assert.deepEqual(_.sortBy(array), expected); + assert.strictEqual(func(expected, 3), 2); + assert.strictEqual(func(expected, null), isSortedIndex ? 3 : 4); + assert.strictEqual(func(expected, undefined), isSortedIndex ? 4 : 5); + assert.strictEqual(func(expected, NaN), isSortedIndex ? 5 : 7); }); }); }); @@ -14601,24 +16796,30 @@ var func = _[methodName], isSortedIndexBy = methodName == 'sortedIndexBy'; - test('`_.' + methodName + '` should provide the correct `iteratee` arguments', 1, function() { + QUnit.test('`_.' + methodName + '` should provide the correct `iteratee` arguments', function(assert) { + assert.expect(1); + var args; - func([30, 50], 40, function() { + func([30, 50], 40, function(assert) { args || (args = slice.call(arguments)); }); - deepEqual(args, [40]); + assert.deepEqual(args, [40]); }); - test('`_.' + methodName + '` should work with a "_.property" style `iteratee`', 1, function() { + QUnit.test('`_.' + methodName + '` should work with a "_.property" style `iteratee`', function(assert) { + assert.expect(1); + var objects = [{ 'x': 30 }, { 'x': 50 }], actual = func(objects, { 'x': 40 }, 'x'); - strictEqual(actual, 1); + assert.strictEqual(actual, 1); }); - test('`_.' + methodName + '` should support arrays larger than `MAX_ARRAY_LENGTH / 2`', 12, function() { + QUnit.test('`_.' + methodName + '` should support arrays larger than `MAX_ARRAY_LENGTH / 2`', function(assert) { + assert.expect(12); + _.each([Math.ceil(MAX_ARRAY_LENGTH / 2), MAX_ARRAY_LENGTH], function(length) { var array = [], values = [MAX_ARRAY_LENGTH, NaN, undefined]; @@ -14635,11 +16836,11 @@ // Avoid false fails in older Firefox. if (array.length == length) { - ok(steps == 32 || steps == 33); - strictEqual(actual, expected); + assert.ok(steps == 32 || steps == 33); + assert.strictEqual(actual, expected); } else { - skipTest(2); + skipTest(assert, 2); } }); }); @@ -14654,9 +16855,11 @@ var func = _[methodName], isSortedIndexOf = methodName == 'sortedIndexOf'; - test('should perform a binary search', 1, function() { + QUnit.test('should perform a binary search', function(assert) { + assert.expect(1); + var sorted = [4, 4, 5, 5, 6, 6]; - deepEqual(func(sorted, 5), isSortedIndexOf ? 2 : 3); + assert.deepEqual(func(sorted, 5), isSortedIndexOf ? 2 : 3); }); }); @@ -14665,11 +16868,13 @@ QUnit.module('lodash.sortedUniq'); (function() { - test('should return unique values of a sorted array', 3, function() { + QUnit.test('should return unique values of a sorted array', function(assert) { + assert.expect(3); + var expected = [1, 2, 3]; _.each([[1, 2, 3], [1, 1, 2, 2, 3], [1, 2, 3, 3, 3, 3, 3]], function(array) { - deepEqual(_.sortedUniq(array), expected); + assert.deepEqual(_.sortedUniq(array), expected); }); }); }()); @@ -14679,16 +16884,22 @@ QUnit.module('lodash.spread'); (function() { - test('should spread arguments to `func`', 1, function() { + QUnit.test('should spread arguments to `func`', function(assert) { + assert.expect(1); + var spread = _.spread(add); - strictEqual(spread([4, 2]), 6); + assert.strictEqual(spread([4, 2]), 6); }); - test('should throw a TypeError when receiving a non-array `array` argument', 1, function() { - raises(function() { _.spread(4, 2); }, TypeError); + QUnit.test('should throw a TypeError when receiving a non-array `array` argument', function(assert) { + assert.expect(1); + + assert.raises(function() { _.spread(4, 2); }, TypeError); }); - test('should provide the correct `func` arguments', 1, function() { + QUnit.test('should provide the correct `func` arguments', function(assert) { + assert.expect(1); + var args; var spread = _.spread(function() { @@ -14696,16 +16907,18 @@ }); spread([4, 2], 'ignored'); - deepEqual(args, [4, 2]); + assert.deepEqual(args, [4, 2]); }); - test('should not set a `this` binding', 1, function() { + QUnit.test('should not set a `this` binding', function(assert) { + assert.expect(1); + var spread = _.spread(function(x, y) { return this[x] + this[y]; }); var object = { 'spread': spread, 'x': 4, 'y': 2 }; - strictEqual(object.spread(['x', 'y']), 6); + assert.strictEqual(object.spread(['x', 'y']), 6); }); }()); @@ -14716,47 +16929,63 @@ (function() { var string = 'abc'; - test('should return `true` if a string starts with `target`', 1, function() { - strictEqual(_.startsWith(string, 'a'), true); + QUnit.test('should return `true` if a string starts with `target`', function(assert) { + assert.expect(1); + + assert.strictEqual(_.startsWith(string, 'a'), true); }); - test('should return `false` if a string does not start with `target`', 1, function() { - strictEqual(_.startsWith(string, 'b'), false); + QUnit.test('should return `false` if a string does not start with `target`', function(assert) { + assert.expect(1); + + assert.strictEqual(_.startsWith(string, 'b'), false); }); - test('should work with a `position` argument', 1, function() { - strictEqual(_.startsWith(string, 'b', 1), true); + QUnit.test('should work with a `position` argument', function(assert) { + assert.expect(1); + + assert.strictEqual(_.startsWith(string, 'b', 1), true); }); - test('should work with `position` >= `string.length`', 4, function() { + QUnit.test('should work with `position` >= `string.length`', function(assert) { + assert.expect(4); + _.each([3, 5, MAX_SAFE_INTEGER, Infinity], function(position) { - strictEqual(_.startsWith(string, 'a', position), false); + assert.strictEqual(_.startsWith(string, 'a', position), false); }); }); - test('should treat falsey `position` values as `0`', 1, function() { + QUnit.test('should treat falsey `position` values as `0`', function(assert) { + assert.expect(1); + var expected = _.map(falsey, _.constant(true)); var actual = _.map(falsey, function(position) { return _.startsWith(string, 'a', position); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should treat a negative `position` as `0`', 6, function() { + QUnit.test('should treat a negative `position` as `0`', function(assert) { + assert.expect(6); + _.each([-1, -3, -Infinity], function(position) { - strictEqual(_.startsWith(string, 'a', position), true); - strictEqual(_.startsWith(string, 'b', position), false); + assert.strictEqual(_.startsWith(string, 'a', position), true); + assert.strictEqual(_.startsWith(string, 'b', position), false); }); }); - test('should coerce `position` to an integer', 1, function() { - strictEqual(_.startsWith(string, 'bc', 1.2), true); + QUnit.test('should coerce `position` to an integer', function(assert) { + assert.expect(1); + + assert.strictEqual(_.startsWith(string, 'bc', 1.2), true); }); - test('should return `true` when `target` is an empty string regardless of `position`', 1, function() { - ok(_.every([-Infinity, NaN, -3, -1, 0, 1, 2, 3, 5, MAX_SAFE_INTEGER, Infinity], function(position) { + QUnit.test('should return `true` when `target` is an empty string regardless of `position`', function(assert) { + assert.expect(1); + + assert.ok(_.every([-Infinity, NaN, -3, -1, 0, 1, 2, 3, 5, MAX_SAFE_INTEGER, Infinity], function(position) { return _.startsWith(string, '', position, true); })); }); @@ -14773,20 +17002,26 @@ var string = 'abc', chr = isStartsWith ? 'a' : 'c'; - test('`_.' + methodName + '` should coerce `string` to a string', 2, function() { - strictEqual(func(Object(string), chr), true); - strictEqual(func({ 'toString': _.constant(string) }, chr), true); + QUnit.test('`_.' + methodName + '` should coerce `string` to a string', function(assert) { + assert.expect(2); + + assert.strictEqual(func(Object(string), chr), true); + assert.strictEqual(func({ 'toString': _.constant(string) }, chr), true); }); - test('`_.' + methodName + '` should coerce `target` to a string', 2, function() { - strictEqual(func(string, Object(chr)), true); - strictEqual(func(string, { 'toString': _.constant(chr) }), true); + QUnit.test('`_.' + methodName + '` should coerce `target` to a string', function(assert) { + assert.expect(2); + + assert.strictEqual(func(string, Object(chr)), true); + assert.strictEqual(func(string, { 'toString': _.constant(chr) }), true); }); - test('`_.' + methodName + '` should coerce `position` to a number', 2, function() { + QUnit.test('`_.' + methodName + '` should coerce `position` to a number', function(assert) { + assert.expect(2); + var position = isStartsWith ? 1 : 2; - strictEqual(func(string, 'b', Object(position)), true); - strictEqual(func(string, 'b', { 'toString': _.constant(String(position)) }), true); + assert.strictEqual(func(string, 'b', Object(position)), true); + assert.strictEqual(func(string, 'b', { 'toString': _.constant(String(position)) }), true); }); }); @@ -14797,22 +17032,28 @@ (function() { var array = [6, 4, 2]; - test('should return the sum of an array of numbers', 1, function() { - strictEqual(_.sum(array), 12); + QUnit.test('should return the sum of an array of numbers', function(assert) { + assert.expect(1); + + assert.strictEqual(_.sum(array), 12); }); - test('should return `0` when passing empty `array` values', 1, function() { + QUnit.test('should return `0` when passing empty `array` values', function(assert) { + assert.expect(1); + var expected = _.map(empties, _.constant(0)); var actual = _.map(empties, function(value) { return _.sum(value); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should coerce values to numbers and `NaN` to `0`', 1, function() { - strictEqual(_.sum(['1', NaN, '2']), 3); + QUnit.test('should coerce values to numbers and `NaN` to `0`', function(assert) { + assert.expect(1); + + assert.strictEqual(_.sum(['1', NaN, '2']), 3); }); }()); @@ -14824,28 +17065,34 @@ var array = [6, 4, 2], objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }]; - test('should work with an `iteratee` argument', 1, function() { + QUnit.test('should work with an `iteratee` argument', function(assert) { + assert.expect(1); + var actual = _.sumBy(objects, function(object) { return object.a; }); - deepEqual(actual, 6); + assert.deepEqual(actual, 6); }); - test('should provide the correct `iteratee` arguments', 1, function() { + QUnit.test('should provide the correct `iteratee` arguments', function(assert) { + assert.expect(1); + var args; _.sumBy(array, function() { args || (args = slice.call(arguments)); }); - deepEqual(args, [6]); + assert.deepEqual(args, [6]); }); - test('should work with a "_.property" style `iteratee`', 2, function() { + QUnit.test('should work with a "_.property" style `iteratee`', function(assert) { + assert.expect(2); + var arrays = [[2], [3], [1]]; - strictEqual(_.sumBy(arrays, 0), 6); - strictEqual(_.sumBy(objects, 'a'), 6); + assert.strictEqual(_.sumBy(arrays, 0), 6); + assert.strictEqual(_.sumBy(objects, 'a'), 6); }); }()); @@ -14854,7 +17101,9 @@ QUnit.module('lodash.tap'); (function() { - test('should intercept and return the given value', 2, function() { + QUnit.test('should intercept and return the given value', function(assert) { + assert.expect(2); + if (!isNpm) { var intercepted, array = [1, 2, 3]; @@ -14863,15 +17112,17 @@ intercepted = value; }); - strictEqual(actual, array); - strictEqual(intercepted, array); + assert.strictEqual(actual, array); + assert.strictEqual(intercepted, array); } else { - skipTest(2); + skipTest(assert, 2); } }); - test('should intercept unwrapped values and return wrapped values when chaining', 2, function() { + QUnit.test('should intercept unwrapped values and return wrapped values when chaining', function(assert) { + assert.expect(2); + if (!isNpm) { var intercepted, array = [1, 2, 3]; @@ -14881,13 +17132,13 @@ value.pop(); }); - ok(wrapped instanceof _); + assert.ok(wrapped instanceof _); wrapped.value(); - strictEqual(intercepted, array); + assert.strictEqual(intercepted, array); } else { - skipTest(2); + skipTest(assert, 2); } }); }()); @@ -14897,7 +17148,9 @@ QUnit.module('lodash.template'); (function() { - test('should escape values in "escape" delimiters', 1, function() { + QUnit.test('should escape values in "escape" delimiters', function(assert) { + assert.expect(1); + var strings = ['

<%- value %>

', '

<%-value%>

', '

<%-\nvalue\n%>

'], expected = _.map(strings, _.constant('

&<>"'`\/

')), data = { 'value': '&<>"\'`\/' }; @@ -14906,10 +17159,12 @@ return _.template(string)(data); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should evaluate JavaScript in "evaluate" delimiters', 1, function() { + QUnit.test('should evaluate JavaScript in "evaluate" delimiters', function(assert) { + assert.expect(1); + var compiled = _.template( '
    <%\ for (var key in collection) {\ @@ -14920,10 +17175,12 @@ var data = { 'collection': { 'a': 'A', 'b': 'B' } }, actual = compiled(data); - strictEqual(actual, '
    • A
    • B
    '); + assert.strictEqual(actual, '
    • A
    • B
    '); }); - test('should interpolate data object properties', 1, function() { + QUnit.test('should interpolate data object properties', function(assert) { + assert.expect(1); + var strings = ['<%= a %>BC', '<%=a%>BC', '<%=\na\n%>BC'], expected = _.map(strings, _.constant('ABC')), data = { 'a': 'A' }; @@ -14932,34 +17189,42 @@ return _.template(string)(data); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should support escaped values in "interpolation" delimiters', 1, function() { + QUnit.test('should support escaped values in "interpolation" delimiters', function(assert) { + assert.expect(1); + var compiled = _.template('<%= a ? "a=\\"A\\"" : "" %>'), data = { 'a': true }; - strictEqual(compiled(data), 'a="A"'); + assert.strictEqual(compiled(data), 'a="A"'); }); - test('should work with "interpolate" delimiters containing ternary operators', 1, function() { + QUnit.test('should work with "interpolate" delimiters containing ternary operators', function(assert) { + assert.expect(1); + var compiled = _.template('<%= value ? value : "b" %>'), data = { 'value': 'a' }; - strictEqual(compiled(data), 'a'); + assert.strictEqual(compiled(data), 'a'); }); - test('should work with "interpolate" delimiters containing global values', 1, function() { + QUnit.test('should work with "interpolate" delimiters containing global values', function(assert) { + assert.expect(1); + var compiled = _.template('<%= typeof Math.abs %>'); try { var actual = compiled(); } catch (e) {} - strictEqual(actual, 'function'); + assert.strictEqual(actual, 'function'); }); - test('should work with complex "interpolate" delimiters', 22, function() { + QUnit.test('should work with complex "interpolate" delimiters', function(assert) { + assert.expect(22); + _.each({ '<%= a + b %>': '3', '<%= b - a %>': '1', @@ -14988,36 +17253,46 @@ var compiled = _.template(key), data = { 'a': 1, 'b': 2 }; - strictEqual(compiled(data), value, key); + assert.strictEqual(compiled(data), value, key); }); }); - test('should parse ES6 template delimiters', 2, function() { + QUnit.test('should parse ES6 template delimiters', function(assert) { + assert.expect(2); + var data = { 'value': 2 }; - strictEqual(_.template('1${value}3')(data), '123'); - strictEqual(_.template('${"{" + value + "\\}"}')(data), '{2}'); + assert.strictEqual(_.template('1${value}3')(data), '123'); + assert.strictEqual(_.template('${"{" + value + "\\}"}')(data), '{2}'); }); - test('should not reference `_.escape` when "escape" delimiters are not used', 1, function() { + QUnit.test('should not reference `_.escape` when "escape" delimiters are not used', function(assert) { + assert.expect(1); + var compiled = _.template('<%= typeof __e %>'); - strictEqual(compiled({}), 'undefined'); + assert.strictEqual(compiled({}), 'undefined'); }); - test('should allow referencing variables declared in "evaluate" delimiters from other delimiters', 1, function() { + QUnit.test('should allow referencing variables declared in "evaluate" delimiters from other delimiters', function(assert) { + assert.expect(1); + var compiled = _.template('<% var b = a; %><%= b.value %>'), data = { 'a': { 'value': 1 } }; - strictEqual(compiled(data), '1'); + assert.strictEqual(compiled(data), '1'); }); - test('should support single line comments in "evaluate" delimiters (test production builds)', 1, function() { + QUnit.test('should support single line comments in "evaluate" delimiters (test production builds)', function(assert) { + assert.expect(1); + var compiled = _.template('<% // A code comment. %><% if (value) { %>yap<% } else { %>nope<% } %>'), data = { 'value': true }; - strictEqual(compiled(data), 'yap'); + assert.strictEqual(compiled(data), 'yap'); }); - test('should work with custom delimiters', 2, function() { + QUnit.test('should work with custom delimiters', function(assert) { + assert.expect(2); + _.times(2, function(index) { var settingsClone = _.clone(_.templateSettings); @@ -15031,12 +17306,14 @@ expected = '
    • 0: a & A
    • 1: b & B
    ', data = { 'collection': ['a & A', 'b & B'] }; - strictEqual(compiled(data), expected); + assert.strictEqual(compiled(data), expected); _.assign(_.templateSettings, settingsClone); }); }); - test('should work with custom delimiters containing special characters', 2, function() { + QUnit.test('should work with custom delimiters containing special characters', function(assert) { + assert.expect(2); + _.times(2, function(index) { var settingsClone = _.clone(_.templateSettings); @@ -15050,22 +17327,28 @@ expected = '
    • 0: a & A
    • 1: b & B
    ', data = { 'collection': ['a & A', 'b & B'] }; - strictEqual(compiled(data), expected); + assert.strictEqual(compiled(data), expected); _.assign(_.templateSettings, settingsClone); }); }); - test('should work with strings without delimiters', 1, function() { + QUnit.test('should work with strings without delimiters', function(assert) { + assert.expect(1); + var expected = 'abc'; - strictEqual(_.template(expected)({}), expected); + assert.strictEqual(_.template(expected)({}), expected); }); - test('should support the "imports" option', 1, function() { + QUnit.test('should support the "imports" option', function(assert) { + assert.expect(1); + var compiled = _.template('<%= a %>', { 'imports': { 'a': 1 } }); - strictEqual(compiled({}), '1'); + assert.strictEqual(compiled({}), '1'); }); - test('should support the "variable" options', 1, function() { + QUnit.test('should support the "variable" options', function(assert) { + assert.expect(1); + var compiled = _.template( '<% _.each( data.a, function( value ) { %>' + '<%= value.valueOf() %>' + @@ -15075,57 +17358,71 @@ var data = { 'a': [1, 2, 3] }; try { - strictEqual(compiled(data), '123'); + assert.strictEqual(compiled(data), '123'); } catch (e) { - ok(false, e.message); + assert.ok(false, e.message); } }); - test('should support the legacy `options` param signature', 1, function() { + QUnit.test('should support the legacy `options` param signature', function(assert) { + assert.expect(1); + var compiled = _.template('<%= data.a %>', null, { 'variable': 'data' }), data = { 'a': 1 }; - strictEqual(compiled(data), '1'); + assert.strictEqual(compiled(data), '1'); }); - test('should use a `with` statement by default', 1, function() { + QUnit.test('should use a `with` statement by default', function(assert) { + assert.expect(1); + var compiled = _.template('<%= index %><%= collection[index] %><% _.each(collection, function(value, index) { %><%= index %><% }); %>'), actual = compiled({ 'index': 1, 'collection': ['a', 'b', 'c'] }); - strictEqual(actual, '1b012'); + assert.strictEqual(actual, '1b012'); }); - test('should work with `this` references', 2, function() { + QUnit.test('should work with `this` references', function(assert) { + assert.expect(2); + var compiled = _.template('a<%= this.String("b") %>c'); - strictEqual(compiled(), 'abc'); + assert.strictEqual(compiled(), 'abc'); var object = { 'b': 'B' }; object.compiled = _.template('A<%= this.b %>C', { 'variable': 'obj' }); - strictEqual(object.compiled(), 'ABC'); + assert.strictEqual(object.compiled(), 'ABC'); }); - test('should work with backslashes', 1, function() { + QUnit.test('should work with backslashes', function(assert) { + assert.expect(1); + var compiled = _.template('<%= a %> \\b'), data = { 'a': 'A' }; - strictEqual(compiled(data), 'A \\b'); + assert.strictEqual(compiled(data), 'A \\b'); }); - test('should work with escaped characters in string literals', 2, function() { + QUnit.test('should work with escaped characters in string literals', function(assert) { + assert.expect(2); + var compiled = _.template('<% print("\'\\n\\r\\t\\u2028\\u2029\\\\") %>'); - strictEqual(compiled(), "'\n\r\t\u2028\u2029\\"); + assert.strictEqual(compiled(), "'\n\r\t\u2028\u2029\\"); var data = { 'a': 'A' }; compiled = _.template('\'\n\r\t<%= a %>\u2028\u2029\\"'); - strictEqual(compiled(data), '\'\n\r\tA\u2028\u2029\\"'); + assert.strictEqual(compiled(data), '\'\n\r\tA\u2028\u2029\\"'); }); - test('should handle \\u2028 & \\u2029 characters', 1, function() { + QUnit.test('should handle \\u2028 & \\u2029 characters', function(assert) { + assert.expect(1); + var compiled = _.template('\u2028<%= "\\u2028\\u2029" %>\u2029'); - strictEqual(compiled(), '\u2028\u2028\u2029\u2029'); + assert.strictEqual(compiled(), '\u2028\u2028\u2029\u2029'); }); - test('should work with statements containing quotes', 1, function() { + QUnit.test('should work with statements containing quotes', function(assert) { + assert.expect(1); + var compiled = _.template("<%\ if (a == 'A' || a == \"a\") {\ %>'a',\"A\"<%\ @@ -15133,20 +17430,24 @@ ); var data = { 'a': 'A' }; - strictEqual(compiled(data), "'a',\"A\""); + assert.strictEqual(compiled(data), "'a',\"A\""); }); - test('should work with templates containing newlines and comments', 1, function() { + QUnit.test('should work with templates containing newlines and comments', function(assert) { + assert.expect(1); + var compiled = _.template('<%\n\ // A code comment.\n\ if (value) { value += 3; }\n\ %>

    <%= value %>

    ' ); - strictEqual(compiled({ 'value': 3 }), '

    6

    '); + assert.strictEqual(compiled({ 'value': 3 }), '

    6

    '); }); - test('should not error with IE conditional comments enabled (test with development build)', 1, function() { + QUnit.test('should not error with IE conditional comments enabled (test with development build)', function(assert) { + assert.expect(1); + var compiled = _.template(''), pass = true; @@ -15156,83 +17457,103 @@ } catch (e) { pass = false; } - ok(pass); + assert.ok(pass); }); - test('should tokenize delimiters', 1, function() { + QUnit.test('should tokenize delimiters', function(assert) { + assert.expect(1); + var compiled = _.template(''), data = { 'type': 1 }; - strictEqual(compiled(data), ''); + assert.strictEqual(compiled(data), ''); }); - test('should evaluate delimiters once', 1, function() { + QUnit.test('should evaluate delimiters once', function(assert) { + assert.expect(1); + var actual = [], compiled = _.template('<%= func("a") %><%- func("b") %><% func("c") %>'), data = { 'func': function(value) { actual.push(value); } }; compiled(data); - deepEqual(actual, ['a', 'b', 'c']); + assert.deepEqual(actual, ['a', 'b', 'c']); }); - test('should match delimiters before escaping text', 1, function() { + QUnit.test('should match delimiters before escaping text', function(assert) { + assert.expect(1); + var compiled = _.template('<<\n a \n>>', { 'evaluate': /<<(.*?)>>/g }); - strictEqual(compiled(), '<<\n a \n>>'); + assert.strictEqual(compiled(), '<<\n a \n>>'); }); - test('should resolve nullish values to an empty string', 3, function() { + QUnit.test('should resolve nullish values to an empty string', function(assert) { + assert.expect(3); + var compiled = _.template('<%= a %><%- a %>'), data = { 'a': null }; - strictEqual(compiled(data), ''); + assert.strictEqual(compiled(data), ''); data = { 'a': undefined }; - strictEqual(compiled(data), ''); + assert.strictEqual(compiled(data), ''); data = { 'a': {} }; compiled = _.template('<%= a.b %><%- a.b %>'); - strictEqual(compiled(data), ''); + assert.strictEqual(compiled(data), ''); }); - test('should parse delimiters without newlines', 1, function() { + QUnit.test('should parse delimiters without newlines', function(assert) { + assert.expect(1); + var expected = '<<\nprint("

    " + (value ? "yes" : "no") + "

    ")\n>>', compiled = _.template(expected, { 'evaluate': /<<(.+?)>>/g }), data = { 'value': true }; - strictEqual(compiled(data), expected); + assert.strictEqual(compiled(data), expected); }); - test('should support recursive calls', 1, function() { + QUnit.test('should support recursive calls', function(assert) { + assert.expect(1); + var compiled = _.template('<%= a %><% a = _.template(c)(obj) %><%= a %>'), data = { 'a': 'A', 'b': 'B', 'c': '<%= b %>' }; - strictEqual(compiled(data), 'AB'); + assert.strictEqual(compiled(data), 'AB'); }); - test('should coerce `text` argument to a string', 1, function() { + QUnit.test('should coerce `text` argument to a string', function(assert) { + assert.expect(1); + var object = { 'toString': _.constant('<%= a %>') }, data = { 'a': 1 }; - strictEqual(_.template(object)(data), '1'); + assert.strictEqual(_.template(object)(data), '1'); }); - test('should not modify the `options` object', 1, function() { + QUnit.test('should not modify the `options` object', function(assert) { + assert.expect(1); + var options = {}; _.template('', options); - deepEqual(options, {}); + assert.deepEqual(options, {}); }); - test('should not modify `_.templateSettings` when `options` are provided', 2, function() { + QUnit.test('should not modify `_.templateSettings` when `options` are provided', function(assert) { + assert.expect(2); + var data = { 'a': 1 }; - ok(!('a' in _.templateSettings)); + assert.notOk('a' in _.templateSettings); _.template('', {}, data); - ok(!('a' in _.templateSettings)); + assert.notOk('a' in _.templateSettings); delete _.templateSettings.a; }); - test('should not error for non-object `data` and `options` values', 2, function() { + QUnit.test('should not error for non-object `data` and `options` values', function(assert) { + assert.expect(2); + var pass = true; try { @@ -15240,7 +17561,7 @@ } catch (e) { pass = false; } - ok(pass, '`data` value'); + assert.ok(pass, '`data` value'); pass = true; @@ -15249,10 +17570,12 @@ } catch (e) { pass = false; } - ok(pass, '`options` value'); + assert.ok(pass, '`options` value'); }); - test('should expose the source for compiled templates', 1, function() { + QUnit.test('should expose the source for compiled templates', function(assert) { + assert.expect(1); + var compiled = _.template('x'), values = [String(compiled), compiled.source], expected = _.map(values, _.constant(true)); @@ -15261,19 +17584,23 @@ return _.includes(value, '__p'); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should expose the source when a SyntaxError occurs', 1, function() { + QUnit.test('should expose the source when a SyntaxError occurs', function(assert) { + assert.expect(1); + try { _.template('<% if x %>'); } catch (e) { var source = e.source; } - ok(_.includes(source, '__p')); + assert.ok(_.includes(source, '__p')); }); - test('should not include sourceURLs in the source', 1, function() { + QUnit.test('should not include sourceURLs in the source', function(assert) { + assert.expect(1); + var options = { 'sourceURL': '/a/b/c' }, compiled = _.template('x', options), values = [compiled.source, undefined]; @@ -15289,10 +17616,12 @@ return _.includes(value, 'sourceURL'); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work as an iteratee for methods like `_.map`', 1, function() { + QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { + assert.expect(1); + var array = ['<%= a %>', '<%- b %>', '<% print(c) %>'], compiles = _.map(array, _.template), data = { 'a': 'one', 'b': '`two`', 'c': 'three' }; @@ -15301,7 +17630,7 @@ return compiled(data); }); - deepEqual(actual, ['one', '`two`', 'three']); + assert.deepEqual(actual, ['one', '`two`', 'three']); }); }()); @@ -15312,55 +17641,75 @@ (function() { var string = 'hi-diddly-ho there, neighborino'; - test('should truncate to a length of `30` by default', 1, function() { - strictEqual(_.trunc(string), 'hi-diddly-ho there, neighbo...'); + QUnit.test('should truncate to a length of `30` by default', function(assert) { + assert.expect(1); + + assert.strictEqual(_.trunc(string), 'hi-diddly-ho there, neighbo...'); }); - test('should not truncate if `string` is <= `length`', 2, function() { - strictEqual(_.trunc(string, { 'length': string.length }), string); - strictEqual(_.trunc(string, { 'length': string.length + 2 }), string); + QUnit.test('should not truncate if `string` is <= `length`', function(assert) { + assert.expect(2); + + assert.strictEqual(_.trunc(string, { 'length': string.length }), string); + assert.strictEqual(_.trunc(string, { 'length': string.length + 2 }), string); }); - test('should truncate string the given length', 1, function() { - strictEqual(_.trunc(string, { 'length': 24 }), 'hi-diddly-ho there, n...'); + QUnit.test('should truncate string the given length', function(assert) { + assert.expect(1); + + assert.strictEqual(_.trunc(string, { 'length': 24 }), 'hi-diddly-ho there, n...'); }); - test('should support a `omission` option', 1, function() { - strictEqual(_.trunc(string, { 'omission': ' [...]' }), 'hi-diddly-ho there, neig [...]'); + QUnit.test('should support a `omission` option', function(assert) { + assert.expect(1); + + assert.strictEqual(_.trunc(string, { 'omission': ' [...]' }), 'hi-diddly-ho there, neig [...]'); }); - test('should support a `length` option', 1, function() { - strictEqual(_.trunc(string, { 'length': 4 }), 'h...'); + QUnit.test('should support a `length` option', function(assert) { + assert.expect(1); + + assert.strictEqual(_.trunc(string, { 'length': 4 }), 'h...'); }); - test('should support a `separator` option', 2, function() { - strictEqual(_.trunc(string, { 'length': 24, 'separator': ' ' }), 'hi-diddly-ho there,...'); - strictEqual(_.trunc(string, { 'length': 24, 'separator': /,? +/ }), 'hi-diddly-ho there...'); + QUnit.test('should support a `separator` option', function(assert) { + assert.expect(2); + + assert.strictEqual(_.trunc(string, { 'length': 24, 'separator': ' ' }), 'hi-diddly-ho there,...'); + assert.strictEqual(_.trunc(string, { 'length': 24, 'separator': /,? +/ }), 'hi-diddly-ho there...'); }); - test('should treat negative `length` as `0`', 2, function() { + QUnit.test('should treat negative `length` as `0`', function(assert) { + assert.expect(2); + _.each([0, -2], function(length) { - strictEqual(_.trunc(string, { 'length': length }), '...'); + assert.strictEqual(_.trunc(string, { 'length': length }), '...'); }); }); - test('should coerce `length` to an integer', 4, function() { + QUnit.test('should coerce `length` to an integer', function(assert) { + assert.expect(4); + _.each(['', NaN, 4.6, '4'], function(length, index) { var actual = index > 1 ? 'h...' : '...'; - strictEqual(_.trunc(string, { 'length': { 'valueOf': _.constant(length) } }), actual); + assert.strictEqual(_.trunc(string, { 'length': { 'valueOf': _.constant(length) } }), actual); }); }); - test('should coerce `string` to a string', 2, function() { - strictEqual(_.trunc(Object(string), { 'length': 4 }), 'h...'); - strictEqual(_.trunc({ 'toString': _.constant(string) }, { 'length': 5 }), 'hi...'); + QUnit.test('should coerce `string` to a string', function(assert) { + assert.expect(2); + + assert.strictEqual(_.trunc(Object(string), { 'length': 4 }), 'h...'); + assert.strictEqual(_.trunc({ 'toString': _.constant(string) }, { 'length': 5 }), 'hi...'); }); - test('should work as an iteratee for methods like `_.map`', 1, function() { + QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { + assert.expect(1); + var actual = _.map([string, string, string], _.trunc), truncated = 'hi-diddly-ho there, neighbo...'; - deepEqual(actual, [truncated, truncated, truncated]); + assert.deepEqual(actual, [truncated, truncated, truncated]); }); }()); @@ -15369,7 +17718,9 @@ QUnit.module('lodash.throttle'); (function() { - asyncTest('should throttle a function', 2, function() { + QUnit.asyncTest('should throttle a function', function(assert) { + assert.expect(2); + if (!(isRhino && isModularize)) { var callCount = 0, throttled = _.throttle(function() { callCount++; }, 32); @@ -15379,43 +17730,47 @@ throttled(); var lastCount = callCount; - ok(callCount > 0); + assert.ok(callCount > 0); setTimeout(function() { - ok(callCount > lastCount); + assert.ok(callCount > lastCount); QUnit.start(); }, 64); } else { - skipTest(2); + skipTest(assert, 2); QUnit.start(); } }); - asyncTest('subsequent calls should return the result of the first call', 5, function() { + QUnit.asyncTest('subsequent calls should return the result of the first call', function(assert) { + assert.expect(5); + if (!(isRhino && isModularize)) { var throttled = _.throttle(_.identity, 32), result = [throttled('a'), throttled('b')]; - deepEqual(result, ['a', 'a']); + assert.deepEqual(result, ['a', 'a']); setTimeout(function() { var result = [throttled('x'), throttled('y')]; - notEqual(result[0], 'a'); - notStrictEqual(result[0], undefined); + assert.notEqual(result[0], 'a'); + assert.notStrictEqual(result[0], undefined); - notEqual(result[1], 'y'); - notStrictEqual(result[1], undefined); + assert.notEqual(result[1], 'y'); + assert.notStrictEqual(result[1], undefined); QUnit.start(); }, 64); } else { - skipTest(5); + skipTest(assert, 5); QUnit.start(); } }); - asyncTest('should clear timeout when `func` is called', 1, function() { + QUnit.asyncTest('should clear timeout when `func` is called', function(assert) { + assert.expect(1); + if (!isModularize) { var callCount = 0, dateCount = 0; @@ -15441,37 +17796,41 @@ throttled(); setTimeout(function() { - strictEqual(callCount, 2); + assert.strictEqual(callCount, 2); QUnit.start(); }, 64); } else { - skipTest(); + skipTest(assert); QUnit.start(); } }); - asyncTest('should not trigger a trailing call when invoked once', 2, function() { + QUnit.asyncTest('should not trigger a trailing call when invoked once', function(assert) { + assert.expect(2); + if (!(isRhino && isModularize)) { var callCount = 0, throttled = _.throttle(function() { callCount++; }, 32); throttled(); - strictEqual(callCount, 1); + assert.strictEqual(callCount, 1); setTimeout(function() { - strictEqual(callCount, 1); + assert.strictEqual(callCount, 1); QUnit.start(); }, 64); } else { - skipTest(2); + skipTest(assert, 2); QUnit.start(); } }); _.times(2, function(index) { - asyncTest('should trigger a call when invoked repeatedly' + (index ? ' and `leading` is `false`' : ''), 1, function() { + QUnit.asyncTest('should trigger a call when invoked repeatedly' + (index ? ' and `leading` is `false`' : ''), function(assert) { + assert.expect(1); + if (!(isRhino && isModularize)) { var callCount = 0, limit = (argv || isPhantom) ? 1000 : 320, @@ -15488,18 +17847,20 @@ var actual = callCount > 1; setTimeout(function() { - ok(actual); + assert.ok(actual); QUnit.start(); }, 1); } else { - skipTest(); + skipTest(assert); QUnit.start(); } }); }); - asyncTest('should apply default options', 3, function() { + QUnit.asyncTest('should apply default options', function(assert) { + assert.expect(3); + if (!(isRhino && isModularize)) { var callCount = 0; @@ -15508,34 +17869,38 @@ return value; }, 32, {}); - strictEqual(throttled('a'), 'a'); - strictEqual(throttled('b'), 'a'); + assert.strictEqual(throttled('a'), 'a'); + assert.strictEqual(throttled('b'), 'a'); setTimeout(function() { - strictEqual(callCount, 2); + assert.strictEqual(callCount, 2); QUnit.start(); }, 128); } else { - skipTest(3); + skipTest(assert, 3); QUnit.start(); } }); - test('should support a `leading` option', 2, function() { + QUnit.test('should support a `leading` option', function(assert) { + assert.expect(2); + if (!(isRhino && isModularize)) { var withLeading = _.throttle(_.identity, 32, { 'leading': true }); - strictEqual(withLeading('a'), 'a'); + assert.strictEqual(withLeading('a'), 'a'); var withoutLeading = _.throttle(_.identity, 32, { 'leading': false }); - strictEqual(withoutLeading('a'), undefined); + assert.strictEqual(withoutLeading('a'), undefined); } else { - skipTest(2); + skipTest(assert, 2); } }); - asyncTest('should support a `trailing` option', 6, function() { + QUnit.asyncTest('should support a `trailing` option', function(assert) { + assert.expect(6); + if (!(isRhino && isModularize)) { var withCount = 0, withoutCount = 0; @@ -15550,25 +17915,27 @@ return value; }, 64, { 'trailing': false }); - strictEqual(withTrailing('a'), 'a'); - strictEqual(withTrailing('b'), 'a'); + assert.strictEqual(withTrailing('a'), 'a'); + assert.strictEqual(withTrailing('b'), 'a'); - strictEqual(withoutTrailing('a'), 'a'); - strictEqual(withoutTrailing('b'), 'a'); + assert.strictEqual(withoutTrailing('a'), 'a'); + assert.strictEqual(withoutTrailing('b'), 'a'); setTimeout(function() { - strictEqual(withCount, 2); - strictEqual(withoutCount, 1); + assert.strictEqual(withCount, 2); + assert.strictEqual(withoutCount, 1); QUnit.start(); }, 256); } else { - skipTest(6); + skipTest(assert, 6); QUnit.start(); } }); - asyncTest('should not update `lastCalled`, at the end of the timeout, when `trailing` is `false`', 1, function() { + QUnit.asyncTest('should not update `lastCalled`, at the end of the timeout, when `trailing` is `false`', function(assert) { + assert.expect(1); + if (!(isRhino && isModularize)) { var callCount = 0; @@ -15585,12 +17952,12 @@ }, 96); setTimeout(function() { - ok(callCount > 1); + assert.ok(callCount > 1); QUnit.start(); }, 192); } else { - skipTest(); + skipTest(assert); QUnit.start(); } }); @@ -15604,7 +17971,9 @@ var func = _[methodName], isDebounce = methodName == 'debounce'; - test('_.' + methodName + ' should not error for non-object `options` values', 1, function() { + QUnit.test('_.' + methodName + ' should not error for non-object `options` values', function(assert) { + assert.expect(1); + var pass = true; try { @@ -15612,10 +17981,12 @@ } catch (e) { pass = false; } - ok(pass); + assert.ok(pass); }); - asyncTest('_.' + methodName + ' should have a default `wait` of `0`', 1, function() { + QUnit.asyncTest('_.' + methodName + ' should have a default `wait` of `0`', function(assert) { + assert.expect(1); + if (!(isRhino && isModularize)) { var callCount = 0; @@ -15627,17 +17998,19 @@ setTimeout(function() { funced(); - strictEqual(callCount, isDebounce ? 1 : 2); + assert.strictEqual(callCount, isDebounce ? 1 : 2); QUnit.start(); }, 32); } else { - skipTest(); + skipTest(assert); QUnit.start(); } }); - asyncTest('_.' + methodName + ' should invoke `func` with the correct `this` binding', 1, function() { + QUnit.asyncTest('_.' + methodName + ' should invoke `func` with the correct `this` binding', function(assert) { + assert.expect(1); + if (!(isRhino && isModularize)) { var object = { 'funced': func(function() { actual.push(this); }, 32) @@ -15651,17 +18024,19 @@ object.funced(); } setTimeout(function() { - deepEqual(actual, expected); + assert.deepEqual(actual, expected); QUnit.start(); }, 64); } else { - skipTest(); + skipTest(assert); QUnit.start(); } }); - asyncTest('_.' + methodName + ' supports recursive calls', 2, function() { + QUnit.asyncTest('_.' + methodName + ' supports recursive calls', function(assert) { + assert.expect(2); + if (!(isRhino && isModularize)) { var actual = [], args = _.map(['a', 'b', 'c'], function(chr) { return [{}, chr]; }), @@ -15681,20 +18056,22 @@ var next = queue.shift(); funced.call(next[0], next[1]); - deepEqual(actual, expected.slice(0, isDebounce ? 0 : 1)); + assert.deepEqual(actual, expected.slice(0, isDebounce ? 0 : 1)); setTimeout(function() { - deepEqual(actual, expected.slice(0, actual.length)); + assert.deepEqual(actual, expected.slice(0, actual.length)); QUnit.start(); }, 256); } else { - skipTest(2); + skipTest(assert, 2); QUnit.start(); } }); - asyncTest('_.' + methodName + ' should work if the system time is set backwards', 1, function() { + QUnit.asyncTest('_.' + methodName + ' should work if the system time is set backwards', function(assert) { + assert.expect(1); + if (!isModularize) { var callCount = 0, dateCount = 0; @@ -15719,17 +18096,19 @@ setTimeout(function() { funced(); - strictEqual(callCount, isDebounce ? 1 : 2); + assert.strictEqual(callCount, isDebounce ? 1 : 2); QUnit.start(); }, 64); } else { - skipTest(); + skipTest(assert); QUnit.start(); } }); - asyncTest('_.' + methodName + ' should support cancelling delayed calls', 1, function() { + QUnit.asyncTest('_.' + methodName + ' should support cancelling delayed calls', function(assert) { + assert.expect(1); + if (!(isRhino && isModularize)) { var callCount = 0; @@ -15741,17 +18120,19 @@ funced.cancel(); setTimeout(function() { - strictEqual(callCount, 0); + assert.strictEqual(callCount, 0); QUnit.start(); }, 64); } else { - skipTest(); + skipTest(assert); QUnit.start(); } }); - asyncTest('_.' + methodName + ' should reset `lastCalled` after cancelling', 3, function() { + QUnit.asyncTest('_.' + methodName + ' should reset `lastCalled` after cancelling', function(assert) { + assert.expect(3); + if (!(isRhino && isModularize)) { var callCount = 0; @@ -15759,17 +18140,17 @@ return ++callCount; }, 32, { 'leading': true }); - strictEqual(funced(), 1); + assert.strictEqual(funced(), 1); funced.cancel(); - strictEqual(funced(), 2); + assert.strictEqual(funced(), 2); setTimeout(function() { - strictEqual(callCount, 2); + assert.strictEqual(callCount, 2); QUnit.start(); }, 64); } else { - skipTest(3); + skipTest(assert, 3); QUnit.start(); } }); @@ -15780,28 +18161,36 @@ QUnit.module('lodash.times'); (function() { - test('should coerce non-finite `n` values to `0`', 3, function() { + QUnit.test('should coerce non-finite `n` values to `0`', function(assert) { + assert.expect(3); + _.each([-Infinity, NaN, Infinity], function(n) { - deepEqual(_.times(n), []); + assert.deepEqual(_.times(n), []); }); }); - test('should coerce `n` to an integer', 1, function() { + QUnit.test('should coerce `n` to an integer', function(assert) { + assert.expect(1); + var actual = _.times(2.4, _.indentify); - deepEqual(actual, [0, 1]); + assert.deepEqual(actual, [0, 1]); }); - test('should provide the correct `iteratee` arguments', 1, function() { + QUnit.test('should provide the correct `iteratee` arguments', function(assert) { + assert.expect(1); + var args; - _.times(1, function() { + _.times(1, function(assert) { args || (args = slice.call(arguments)); }); - deepEqual(args, [0]); + assert.deepEqual(args, [0]); }); - test('should use `_.identity` when `iteratee` is nullish', 1, function() { + QUnit.test('should use `_.identity` when `iteratee` is nullish', function(assert) { + assert.expect(1); + var values = [, null, undefined], expected = _.map(values, _.constant([0, 1, 2])); @@ -15809,14 +18198,18 @@ return index ? _.times(3, value) : _.times(3); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return an array of the results of each `iteratee` execution', 1, function() { - deepEqual(_.times(3, function(n) { return n * 2; }), [0, 2, 4]); + QUnit.test('should return an array of the results of each `iteratee` execution', function(assert) { + assert.expect(1); + + assert.deepEqual(_.times(3, function(n) { return n * 2; }), [0, 2, 4]); }); - test('should return an empty array for falsey and negative `n` arguments', 1, function() { + QUnit.test('should return an empty array for falsey and negative `n` arguments', function(assert) { + assert.expect(1); + var values = falsey.concat(-1, -Infinity), expected = _.map(values, _.constant([])); @@ -15824,17 +18217,19 @@ return index ? _.times(value) : _.times(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should return a wrapped value when chaining', 2, function() { + QUnit.test('should return a wrapped value when chaining', function(assert) { + assert.expect(2); + if (!isNpm) { var wrapped = _(3).times(); - ok(wrapped instanceof _); - deepEqual(wrapped.value(), [0, 1, 2]); + assert.ok(wrapped instanceof _); + assert.deepEqual(wrapped.value(), [0, 1, 2]); } else { - skipTest(2); + skipTest(assert, 2); } }); }()); @@ -15844,43 +18239,51 @@ QUnit.module('lodash.toArray'); (function() { - test('should convert objects to arrays', 1, function() { - deepEqual(_.toArray({ 'a': 1, 'b': 2 }), [1, 2]); + QUnit.test('should convert objects to arrays', function(assert) { + assert.expect(1); + + assert.deepEqual(_.toArray({ 'a': 1, 'b': 2 }), [1, 2]); }); - test('should convert strings to arrays', 2, function() { - deepEqual(_.toArray('ab'), ['a', 'b']); - deepEqual(_.toArray(Object('ab')), ['a', 'b']); + QUnit.test('should convert strings to arrays', function(assert) { + assert.expect(2); + + assert.deepEqual(_.toArray('ab'), ['a', 'b']); + assert.deepEqual(_.toArray(Object('ab')), ['a', 'b']); }); - test('should convert iterables to arrays', 1, function() { + QUnit.test('should convert iterables to arrays', function(assert) { + assert.expect(1); + if (!isNpm && Symbol && Symbol.iterator) { var object = { '0': 'a', 'length': 1 }; object[Symbol.iterator] = arrayProto[Symbol.iterator]; - deepEqual(_.toArray(object), ['a']); + assert.deepEqual(_.toArray(object), ['a']); } else { - skipTest(); + skipTest(assert); } }); - test('should work in a lazy chain sequence', 2, function() { + QUnit.test('should work in a lazy chain sequence', function(assert) { + assert.expect(2); + if (!isNpm) { var array = _.range(LARGE_ARRAY_SIZE + 1), actual = _(array).slice(1).map(String).toArray().value(); - deepEqual(actual, _.map(array.slice(1), String)); + assert.deepEqual(actual, _.map(array.slice(1), String)); var object = _.zipObject(_.times(LARGE_ARRAY_SIZE, function(index) { return ['key' + index, index]; })); actual = _(object).toArray().slice(1).map(String).value(); - deepEqual(actual, _.map(_.toArray(object).slice(1), String)); + assert.deepEqual(actual, _.map(_.toArray(object).slice(1), String)); } else { - skipTest(2); + skipTest(assert, 2); } }); }()); @@ -15894,39 +18297,47 @@ array = [1, 2, 3], func = _[methodName]; - test('should return a dense array', 3, function() { + QUnit.test('should return a dense array', function(assert) { + assert.expect(3); + var sparse = Array(3); sparse[1] = 2; var actual = func(sparse); - ok('0' in actual); - ok('2' in actual); - deepEqual(actual, sparse); + assert.ok('0' in actual); + assert.ok('2' in actual); + assert.deepEqual(actual, sparse); }); - test('should treat array-like objects like arrays', 2, function() { + QUnit.test('should treat array-like objects like arrays', function(assert) { + assert.expect(2); + var object = { '0': 'a', '1': 'b', '2': 'c', 'length': 3 }; - deepEqual(func(object), ['a', 'b', 'c']); - deepEqual(func(args), array); + assert.deepEqual(func(object), ['a', 'b', 'c']); + assert.deepEqual(func(args), array); }); - test('should return a shallow clone of arrays', 2, function() { + QUnit.test('should return a shallow clone of arrays', function(assert) { + assert.expect(2); + var actual = func(array); - deepEqual(actual, array); - notStrictEqual(actual, array); + assert.deepEqual(actual, array); + assert.notStrictEqual(actual, array); }); - test('should work with a node list for `collection`', 1, function() { + QUnit.test('should work with a node list for `collection`', function(assert) { + assert.expect(1); + if (document) { try { var actual = func(document.getElementsByTagName('body')); } catch (e) {} - deepEqual(actual, [body]); + assert.deepEqual(actual, [body]); } else { - skipTest(); + skipTest(assert); } }); }); @@ -15936,11 +18347,13 @@ QUnit.module('lodash.toInteger'); (function() { - test('should convert values to integers', 4, function() { - strictEqual(_.toInteger('3.14'), 3); - strictEqual(_.toInteger(), 0); - strictEqual(_.toInteger(NaN), 0); - strictEqual(_.toInteger(-Infinity), -Infinity); + QUnit.test('should convert values to integers', function(assert) { + assert.expect(4); + + assert.strictEqual(_.toInteger('3.14'), 3); + assert.strictEqual(_.toInteger(), 0); + assert.strictEqual(_.toInteger(NaN), 0); + assert.strictEqual(_.toInteger(-Infinity), -Infinity); }); }()); @@ -15949,24 +18362,30 @@ QUnit.module('lodash.toPath'); (function() { - test('should convert a string to a path', 2, function() { - deepEqual(_.toPath('a.b.c'), ['a', 'b', 'c']); - deepEqual(_.toPath('a[0].b.c'), ['a', '0', 'b', 'c']); + QUnit.test('should convert a string to a path', function(assert) { + assert.expect(2); + + assert.deepEqual(_.toPath('a.b.c'), ['a', 'b', 'c']); + assert.deepEqual(_.toPath('a[0].b.c'), ['a', '0', 'b', 'c']); }); - test('should coerce array elements to strings', 4, function() { + QUnit.test('should coerce array elements to strings', function(assert) { + assert.expect(4); + var array = ['a', 'b', 'c']; _.each([array, _.map(array, Object)], function(value) { var actual = _.toPath(value); - deepEqual(actual, array); - notStrictEqual(actual, array); + assert.deepEqual(actual, array); + assert.notStrictEqual(actual, array); }); }); - test('should handle complex paths', 1, function() { + QUnit.test('should handle complex paths', function(assert) { + assert.expect(1); + var actual = _.toPath('a[-1.23]["[\\"b\\"]"].c[\'[\\\'d\\\']\'][\ne\n][f].g'); - deepEqual(actual, ['a', '-1.23', '["b"]', 'c', "['d']", '\ne\n', 'f', 'g']); + assert.deepEqual(actual, ['a', '-1.23', '["b"]', 'c', "['d']", '\ne\n', 'f', 'g']); }); }()); @@ -15977,26 +18396,32 @@ (function() { var args = arguments; - test('should flatten inherited properties', 1, function() { + QUnit.test('should flatten inherited properties', function(assert) { + assert.expect(1); + function Foo() { this.b = 2; } Foo.prototype.c = 3; var actual = _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); - deepEqual(actual, { 'a': 1, 'b': 2, 'c': 3 }); + assert.deepEqual(actual, { 'a': 1, 'b': 2, 'c': 3 }); }); - test('should convert `arguments` objects to plain objects', 1, function() { + QUnit.test('should convert `arguments` objects to plain objects', function(assert) { + assert.expect(1); + var actual = _.toPlainObject(args), expected = { '0': 1, '1': 2, '2': 3 }; - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should convert arrays to plain objects', 1, function() { + QUnit.test('should convert arrays to plain objects', function(assert) { + assert.expect(1); + var actual = _.toPlainObject(['a', 'b', 'c']), expected = { '0': 'a', '1': 'b', '2': 'c' }; - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }(1, 2, 3)); @@ -16011,7 +18436,9 @@ this.c = 3; } - test('should create an object with the same `[[Prototype]]` as `object` when `accumulator` is nullish', 4, function() { + QUnit.test('should create an object with the same `[[Prototype]]` as `object` when `accumulator` is nullish', function(assert) { + assert.expect(4); + var accumulators = [, null, undefined], expected = _.map(accumulators, _.constant(true)), object = new Foo; @@ -16030,26 +18457,28 @@ return result instanceof Foo; }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); expected = _.map(accumulators, _.constant({ 'a': 1, 'b': 4, 'c': 9 })); actual = _.map(results, _.clone); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); object = { 'a': 1, 'b': 2, 'c': 3 }; actual = _.map(accumulators, mapper); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); object = [1, 2, 3]; expected = _.map(accumulators, _.constant([1, 4, 9])); actual = _.map(accumulators, mapper); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should support an `accumulator` value', 4, function() { + QUnit.test('should support an `accumulator` value', function(assert) { + assert.expect(4); + var values = [new Foo, [1, 2, 3], { 'a': 1, 'b': 2, 'c': 3 }], expected = _.map(values, _.constant([0, 1, 4, 9])); @@ -16059,7 +18488,7 @@ }, [0]); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); var object = { '_': 0, 'a': 1, 'b': 4, 'c': 9 }; expected = [object, { '_': 0, '0': 1, '1': 4, '2': 9 }, object]; @@ -16069,7 +18498,7 @@ }, { '_': 0 }); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); object = {}; expected = _.map(values, _.constant(object)); @@ -16077,28 +18506,34 @@ return _.transform(value, _.noop, object); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); actual = _.map(values, function(value) { return _.transform(null, null, object); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should treat sparse arrays as dense', 1, function() { + QUnit.test('should treat sparse arrays as dense', function(assert) { + assert.expect(1); + var actual = _.transform(Array(1), function(result, value, index) { result[index] = String(value); }); - deepEqual(actual, ['undefined']); + assert.deepEqual(actual, ['undefined']); }); - test('should work without an `iteratee` argument', 1, function() { - ok(_.transform(new Foo) instanceof Foo); + QUnit.test('should work without an `iteratee` argument', function(assert) { + assert.expect(1); + + assert.ok(_.transform(new Foo) instanceof Foo); }); - test('should check that `object` is an object before using its `[[Prototype]]`', 2, function() { + QUnit.test('should check that `object` is an object before using its `[[Prototype]]`', function(assert) { + assert.expect(2); + var Ctors = [Boolean, Boolean, Number, Number, Number, String, String], values = [true, false, 0, 1, NaN, '', 'a'], expected = _.map(values, _.constant({})); @@ -16107,7 +18542,7 @@ return _.transform(value); }); - deepEqual(results, expected); + assert.deepEqual(results, expected); expected = _.map(values, _.constant(false)); @@ -16115,17 +18550,19 @@ return value instanceof Ctors[index]; }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should create an empty object when provided a falsey `object` argument', 1, function() { + QUnit.test('should create an empty object when provided a falsey `object` argument', function(assert) { + assert.expect(1); + var expected = _.map(falsey, _.constant({})); var actual = _.map(falsey, function(object, index) { return index ? _.transform(object) : _.transform(); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); _.each({ @@ -16133,7 +18570,9 @@ 'object': { 'a': 1, 'b': 2, 'c': 3 } }, function(object, key) { - test('should provide the correct `iteratee` arguments when transforming an ' + key, 2, function() { + QUnit.test('should provide the correct `iteratee` arguments when transforming an ' + key, function(assert) { + assert.expect(2); + var args; _.transform(object, function() { @@ -16142,16 +18581,18 @@ var first = args[0]; if (key == 'array') { - ok(first !== object && _.isArray(first)); - deepEqual(args, [first, 1, 0, object]); + assert.ok(first !== object && _.isArray(first)); + assert.deepEqual(args, [first, 1, 0, object]); } else { - ok(first !== object && _.isPlainObject(first)); - deepEqual(args, [first, 1, 'a', object]); + assert.ok(first !== object && _.isPlainObject(first)); + assert.deepEqual(args, [first, 1, 'a', object]); } }); }); - test('should create an object from the same realm as `object`', 1, function() { + QUnit.test('should create an object from the same realm as `object`', function(assert) { + assert.expect(1); + var objects = _.transform(_, function(result, value, key) { if (_.startsWith(key, '_') && _.isObject(value) && !_.isElement(value)) { result.push(value); @@ -16173,7 +18614,7 @@ return result instanceof Ctor || !(new Ctor instanceof Ctor); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }()); @@ -16193,86 +18634,106 @@ } parts = parts.join(' and '); - test('`_.' + methodName + '` should remove ' + parts + ' whitespace', 1, function() { + QUnit.test('`_.' + methodName + '` should remove ' + parts + ' whitespace', function(assert) { + assert.expect(1); + var string = whitespace + 'a b c' + whitespace, expected = (index == 2 ? whitespace : '') + 'a b c' + (index == 1 ? whitespace : ''); - strictEqual(func(string), expected); + assert.strictEqual(func(string), expected); }); - test('`_.' + methodName + '` should not remove non-whitespace characters', 1, function() { + QUnit.test('`_.' + methodName + '` should not remove non-whitespace characters', function(assert) { + assert.expect(1); + // Zero-width space (zws), next line character (nel), and non-character (bom) are not whitespace. var problemChars = '\x85\u200b\ufffe', string = problemChars + 'a b c' + problemChars; - strictEqual(func(string), string); + assert.strictEqual(func(string), string); }); - test('`_.' + methodName + '` should coerce `string` to a string', 1, function() { + QUnit.test('`_.' + methodName + '` should coerce `string` to a string', function(assert) { + assert.expect(1); + var object = { 'toString': _.constant(whitespace + 'a b c' + whitespace) }, expected = (index == 2 ? whitespace : '') + 'a b c' + (index == 1 ? whitespace : ''); - strictEqual(func(object), expected); + assert.strictEqual(func(object), expected); }); - test('`_.' + methodName + '` should remove ' + parts + ' `chars`', 1, function() { + QUnit.test('`_.' + methodName + '` should remove ' + parts + ' `chars`', function(assert) { + assert.expect(1); + var string = '-_-a-b-c-_-', expected = (index == 2 ? '-_-' : '') + 'a-b-c' + (index == 1 ? '-_-' : ''); - strictEqual(func(string, '_-'), expected); + assert.strictEqual(func(string, '_-'), expected); }); - test('`_.' + methodName + '` should coerce `chars` to a string', 1, function() { + QUnit.test('`_.' + methodName + '` should coerce `chars` to a string', function(assert) { + assert.expect(1); + var object = { 'toString': _.constant('_-') }, string = '-_-a-b-c-_-', expected = (index == 2 ? '-_-' : '') + 'a-b-c' + (index == 1 ? '-_-' : ''); - strictEqual(func(string, object), expected); + assert.strictEqual(func(string, object), expected); }); - test('`_.' + methodName + '` should return an empty string for empty values and `chars`', 6, function() { + QUnit.test('`_.' + methodName + '` should return an empty string for empty values and `chars`', function(assert) { + assert.expect(6); + _.each([null, '_-'], function(chars) { - strictEqual(func(null, chars), ''); - strictEqual(func(undefined, chars), ''); - strictEqual(func('', chars), ''); + assert.strictEqual(func(null, chars), ''); + assert.strictEqual(func(undefined, chars), ''); + assert.strictEqual(func('', chars), ''); }); }); - test('`_.' + methodName + '` should work with `undefined` or empty string values for `chars`', 2, function() { + QUnit.test('`_.' + methodName + '` should work with `undefined` or empty string values for `chars`', function(assert) { + assert.expect(2); + var string = whitespace + 'a b c' + whitespace, expected = (index == 2 ? whitespace : '') + 'a b c' + (index == 1 ? whitespace : ''); - strictEqual(func(string, undefined), expected); - strictEqual(func(string, ''), string); + assert.strictEqual(func(string, undefined), expected); + assert.strictEqual(func(string, ''), string); }); - test('`_.' + methodName + '` should work as an iteratee for methods like `_.map`', 1, function() { + QUnit.test('`_.' + methodName + '` should work as an iteratee for methods like `_.map`', function(assert) { + assert.expect(1); + var string = Object(whitespace + 'a b c' + whitespace), trimmed = (index == 2 ? whitespace : '') + 'a b c' + (index == 1 ? whitespace : ''), actual = _.map([string, string, string], func); - deepEqual(actual, [trimmed, trimmed, trimmed]); + assert.deepEqual(actual, [trimmed, trimmed, trimmed]); }); - test('`_.' + methodName + '` should return an unwrapped value when implicitly chaining', 1, function() { + QUnit.test('`_.' + methodName + '` should return an unwrapped value when implicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { var string = whitespace + 'a b c' + whitespace, expected = (index == 2 ? whitespace : '') + 'a b c' + (index == 1 ? whitespace : ''); - strictEqual(_(string)[methodName](), expected); + assert.strictEqual(_(string)[methodName](), expected); } else { - skipTest(); + skipTest(assert); } }); - test('`_.' + methodName + '` should return a wrapped value when explicitly chaining', 1, function() { + QUnit.test('`_.' + methodName + '` should return a wrapped value when explicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { var string = whitespace + 'a b c' + whitespace; - ok(_(string).chain()[methodName]() instanceof _); + assert.ok(_(string).chain()[methodName]() instanceof _); } else { - skipTest(); + skipTest(assert); } }); }); @@ -16288,24 +18749,34 @@ escaped += escaped; unescaped += unescaped; - test('should unescape entities in order', 1, function() { - strictEqual(_.unescape('&lt;'), '<'); + QUnit.test('should unescape entities in order', function(assert) { + assert.expect(1); + + assert.strictEqual(_.unescape('&lt;'), '<'); }); - test('should unescape the proper entities', 1, function() { - strictEqual(_.unescape(escaped), unescaped); + QUnit.test('should unescape the proper entities', function(assert) { + assert.expect(1); + + assert.strictEqual(_.unescape(escaped), unescaped); }); - test('should not unescape the "/" entity', 1, function() { - strictEqual(_.unescape('/'), '/'); + QUnit.test('should not unescape the "/" entity', function(assert) { + assert.expect(1); + + assert.strictEqual(_.unescape('/'), '/'); }); - test('should handle strings with nothing to unescape', 1, function() { - strictEqual(_.unescape('abc'), 'abc'); + QUnit.test('should handle strings with nothing to unescape', function(assert) { + assert.expect(1); + + assert.strictEqual(_.unescape('abc'), 'abc'); }); - test('should unescape the same characters escaped by `_.escape`', 1, function() { - strictEqual(_.unescape(_.escape(unescaped)), unescaped); + QUnit.test('should unescape the same characters escaped by `_.escape`', function(assert) { + assert.expect(1); + + assert.strictEqual(_.unescape(_.escape(unescaped)), unescaped); }); }()); @@ -16316,21 +18787,27 @@ (function() { var args = arguments; - test('should return the union of the given arrays', 1, function() { + QUnit.test('should return the union of the given arrays', function(assert) { + assert.expect(1); + var actual = _.union([1, 3, 2], [5, 2, 1, 4], [2, 1]); - deepEqual(actual, [1, 3, 2, 5, 4]); + assert.deepEqual(actual, [1, 3, 2, 5, 4]); }); - test('should not flatten nested arrays', 1, function() { + QUnit.test('should not flatten nested arrays', function(assert) { + assert.expect(1); + var actual = _.union([1, 3, 2], [1, [5]], [2, [4]]); - deepEqual(actual, [1, 3, 2, [5], [4]]); + assert.deepEqual(actual, [1, 3, 2, [5], [4]]); }); - test('should ignore values that are not arrays or `arguments` objects', 3, function() { + QUnit.test('should ignore values that are not arrays or `arguments` objects', function(assert) { + assert.expect(3); + var array = [0]; - deepEqual(_.union(array, 3, null, { '0': 1 }), array); - deepEqual(_.union(null, array, null, [2, 1]), [0, 2, 1]); - deepEqual(_.union(array, null, args, null), [0, 1, 2, 3]); + assert.deepEqual(_.union(array, 3, null, { '0': 1 }), array); + assert.deepEqual(_.union(null, array, null, [2, 1]), [0, 2, 1]); + assert.deepEqual(_.union(array, null, args, null), [0, 1, 2, 3]); }); }(1, 2, 3)); @@ -16339,11 +18816,13 @@ QUnit.module('lodash.uniq'); (function() { - test('should perform an unsorted uniq when used as an iteratee for methods like `_.map`', 1, function() { + QUnit.test('should perform an unsorted uniq when used as an iteratee for methods like `_.map`', function(assert) { + assert.expect(1); + var array = [[2, 1, 2], [1, 2, 1]], actual = _.map(array, _.uniq); - deepEqual(actual, [[2, 1], [1, 2]]); + assert.deepEqual(actual, [[2, 1], [1, 2]]); }); }()); @@ -16360,25 +18839,35 @@ objects = _.sortBy(objects, 'a'); } else { - test('`_.' + methodName + '` should return unique values of an unsorted array', 1, function() { + QUnit.test('`_.' + methodName + '` should return unique values of an unsorted array', function(assert) { + assert.expect(1); + var array = [2, 3, 1, 2, 3, 1]; - deepEqual(func(array), [2, 3, 1]); + assert.deepEqual(func(array), [2, 3, 1]); }); } - test('`_.' + methodName + '` should return unique values of a sorted array', 1, function() { + QUnit.test('`_.' + methodName + '` should return unique values of a sorted array', function(assert) { + assert.expect(1); + var array = [1, 1, 2, 2, 3]; - deepEqual(func(array), [1, 2, 3]); + assert.deepEqual(func(array), [1, 2, 3]); }); - test('`_.' + methodName + '` should treat object instances as unique', 1, function() { - deepEqual(func(objects), objects); + QUnit.test('`_.' + methodName + '` should treat object instances as unique', function(assert) { + assert.expect(1); + + assert.deepEqual(func(objects), objects); }); - test('`_.' + methodName + '` should not treat `NaN` as unique', 1, function() { - deepEqual(func([1, 3, NaN, NaN]), [1, 3, NaN]); + QUnit.test('`_.' + methodName + '` should not treat `NaN` as unique', function(assert) { + assert.expect(1); + + assert.deepEqual(func([1, 3, NaN, NaN]), [1, 3, NaN]); }); - test('`_.' + methodName + '` should work with large arrays', 1, function() { + QUnit.test('`_.' + methodName + '` should work with large arrays', function(assert) { + assert.expect(1); + var largeArray = [], expected = [0, {}, 'a'], count = Math.ceil(LARGE_ARRAY_SIZE / expected.length); @@ -16389,10 +18878,12 @@ }); }); - deepEqual(func(largeArray), expected); + assert.deepEqual(func(largeArray), expected); }); - test('`_.' + methodName + '` should work with large arrays of boolean, `NaN`, and nullish values', 1, function() { + QUnit.test('`_.' + methodName + '` should work with large arrays of boolean, `NaN`, and nullish values', function(assert) { + assert.expect(1); + var largeArray = [], expected = [false, true, null, undefined, NaN], count = Math.ceil(LARGE_ARRAY_SIZE / expected.length); @@ -16403,23 +18894,27 @@ }); }); - deepEqual(func(largeArray), expected); + assert.deepEqual(func(largeArray), expected); }); - test('`_.' + methodName + '` should work with large arrays of symbols', 1, function() { + QUnit.test('`_.' + methodName + '` should work with large arrays of symbols', function(assert) { + assert.expect(1); + if (Symbol) { var largeArray = _.times(LARGE_ARRAY_SIZE, function() { return Symbol(); }); - deepEqual(func(largeArray), largeArray); + assert.deepEqual(func(largeArray), largeArray); } else { - skipTest(); + skipTest(assert); } }); - test('`_.' + methodName + '` should work with large arrays of well-known symbols', 1, function() { + QUnit.test('`_.' + methodName + '` should work with large arrays of well-known symbols', function(assert) { + assert.expect(1); + // See http://www.ecma-international.org/ecma-262/6.0/#sec-well-known-symbols. if (Symbol) { var expected = [ @@ -16441,14 +18936,16 @@ }); }); - deepEqual(func(largeArray), expected); + assert.deepEqual(func(largeArray), expected); } else { - skipTest(); + skipTest(assert); } }); - test('`_.' + methodName + '` should distinguish between numbers and numeric strings', 1, function() { + QUnit.test('`_.' + methodName + '` should distinguish between numbers and numeric strings', function(assert) { + assert.expect(1); + var largeArray = [], expected = ['2', 2, Object('2'), Object(2)], count = Math.ceil(LARGE_ARRAY_SIZE / expected.length); @@ -16459,7 +18956,7 @@ }); }); - deepEqual(func(largeArray), expected); + assert.deepEqual(func(largeArray), expected); }); }); @@ -16475,31 +18972,37 @@ if (isSortedUniqBy) { objects = _.sortBy(objects, 'a'); } - test('`_.' + methodName + '` should work with an `iteratee` argument', 1, function() { + QUnit.test('`_.' + methodName + '` should work with an `iteratee` argument', function(assert) { + assert.expect(1); + var expected = isSortedUniqBy ? [{ 'a': 1 }, { 'a': 2 }, { 'a': 3 }] : objects.slice(0, 3); var actual = func(objects, function(object) { return object.a; }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('`_.' + methodName + '` should provide the correct `iteratee` arguments', 1, function() { + QUnit.test('`_.' + methodName + '` should provide the correct `iteratee` arguments', function(assert) { + assert.expect(1); + var args; func(objects, function() { args || (args = slice.call(arguments)); }); - deepEqual(args, [objects[0]]); + assert.deepEqual(args, [objects[0]]); }); - test('`_.' + methodName + '` should work with a "_.property" style `iteratee`', 2, function() { + QUnit.test('`_.' + methodName + '` should work with a "_.property" style `iteratee`', function(assert) { + assert.expect(2); + var expected = isSortedUniqBy ? [{ 'a': 1 }, { 'a': 2 }, { 'a': 3 }] : objects.slice(0, 3), actual = func(objects, 'a'); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); var arrays = [[2], [3], [1], [2], [3], [1]]; if (isSortedUniqBy) { @@ -16508,7 +19011,7 @@ expected = isSortedUniqBy ? [[1], [2], [3]] : arrays.slice(0, 3); actual = func(arrays, 0); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); _.each({ @@ -16518,9 +19021,11 @@ 'a string': '0' }, function(iteratee, key) { - test('`_.' + methodName + '` should work with ' + key + ' for `iteratee`', 1, function() { + QUnit.test('`_.' + methodName + '` should work with ' + key + ' for `iteratee`', function(assert) { + assert.expect(1); + var actual = func([['a'], ['a'], ['b']], iteratee); - deepEqual(actual, [['a'], ['b']]); + assert.deepEqual(actual, [['a'], ['b']]); }); }); }); @@ -16530,21 +19035,27 @@ QUnit.module('lodash.uniqueId'); (function() { - test('should generate unique ids', 1, function() { - var actual = _.times(1000, function() { + QUnit.test('should generate unique ids', function(assert) { + assert.expect(1); + + var actual = _.times(1000, function(assert) { return _.uniqueId(); }); - strictEqual(_.uniq(actual).length, actual.length); + assert.strictEqual(_.uniq(actual).length, actual.length); }); - test('should return a string value when not providing a prefix argument', 1, function() { - strictEqual(typeof _.uniqueId(), 'string'); + QUnit.test('should return a string value when not providing a prefix argument', function(assert) { + assert.expect(1); + + assert.strictEqual(typeof _.uniqueId(), 'string'); }); - test('should coerce the prefix argument to a string', 1, function() { + QUnit.test('should coerce the prefix argument to a string', function(assert) { + assert.expect(1); + var actual = [_.uniqueId(3), _.uniqueId(2), _.uniqueId(1)]; - ok(/3\d+,2\d+,1\d+/.test(actual)); + assert.ok(/3\d+,2\d+,1\d+/.test(actual)); }); }()); @@ -16553,23 +19064,29 @@ QUnit.module('lodash.unset'); (function() { - test('should unset property values', 4, function() { + QUnit.test('should unset property values', function(assert) { + assert.expect(4); + _.each(['a', ['a']], function(path) { var object = { 'a': 1, 'c': 2 }; - strictEqual(_.unset(object, path), true); - deepEqual(object, { 'c': 2 }); + assert.strictEqual(_.unset(object, path), true); + assert.deepEqual(object, { 'c': 2 }); }); }); - test('should unset deep property values', 4, function() { + QUnit.test('should unset deep property values', function(assert) { + assert.expect(4); + _.each(['a.b.c', ['a', 'b', 'c']], function(path) { var object = { 'a': { 'b': { 'c': null } } }; - strictEqual(_.unset(object, path), true); - deepEqual(object, { 'a': { 'b': {} } }); + assert.strictEqual(_.unset(object, path), true); + assert.deepEqual(object, { 'a': { 'b': {} } }); }); }); - test('should handle complex paths', 4, function() { + QUnit.test('should handle complex paths', function(assert) { + assert.expect(4); + var paths = [ 'a[-1.23]["[\\"b\\"]"].c[\'[\\\'d\\\']\'][\ne\n][f].g', ['a', '-1.23', '["b"]', 'c', "['d']", '\ne\n', 'f', 'g'] @@ -16577,22 +19094,26 @@ _.each(paths, function(path) { var object = { 'a': { '-1.23': { '["b"]': { 'c': { "['d']": { '\ne\n': { 'f': { 'g': 8 } } } } } } } }; - strictEqual(_.unset(object, path), true); - ok(!('g' in object.a[-1.23]['["b"]'].c["['d']"]['\ne\n'].f)); + assert.strictEqual(_.unset(object, path), true); + assert.notOk('g' in object.a[-1.23]['["b"]'].c["['d']"]['\ne\n'].f); }); }); - test('should return `true` for nonexistent paths', 5, function() { + QUnit.test('should return `true` for nonexistent paths', function(assert) { + assert.expect(5); + var object = { 'a': { 'b': { 'c': null } } }; _.each(['z', 'a.z', 'a.b.z', 'a.b.c.z'], function(path) { - strictEqual(_.unset(object, path), true); + assert.strictEqual(_.unset(object, path), true); }); - deepEqual(object, { 'a': { 'b': { 'c': null } } }); + assert.deepEqual(object, { 'a': { 'b': { 'c': null } } }); }); - test('should not error when `object` is nullish', 1, function() { + QUnit.test('should not error when `object` is nullish', function(assert) { + assert.expect(1); + var values = [null, undefined], expected = [[true, true], [true, true]]; @@ -16604,10 +19125,12 @@ } }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should follow `path` over non-plain objects', 8, function() { + QUnit.test('should follow `path` over non-plain objects', function(assert) { + assert.expect(8); + var object = { 'a': '' }, paths = ['constructor.prototype.a', ['constructor', 'prototype', 'a']]; @@ -16615,8 +19138,8 @@ numberProto.a = 1; var actual = _.unset(0, path); - strictEqual(actual, true); - ok(!('a' in numberProto)); + assert.strictEqual(actual, true); + assert.notOk('a' in numberProto); delete numberProto.a; }); @@ -16625,14 +19148,16 @@ stringProto.replace.b = 1; var actual = _.unset(object, path); - strictEqual(actual, true); - ok(!('a' in stringProto.replace)); + assert.strictEqual(actual, true); + assert.notOk('a' in stringProto.replace); delete stringProto.replace.b; }); }); - test('should return `false` for non-configurable properties', 1, function() { + QUnit.test('should return `false` for non-configurable properties', function(assert) { + assert.expect(1); + var object = {}; if (!isStrict && defineProperty) { @@ -16640,10 +19165,10 @@ 'configurable': false, 'value': 1 }); - strictEqual(_.unset(object, 'a'), false); + assert.strictEqual(_.unset(object, 'a'), false); } else { - skipTest(); + skipTest(assert); } }); }()); @@ -16653,22 +19178,28 @@ QUnit.module('lodash.unzipWith'); (function() { - test('should unzip arrays combining regrouped elements with `iteratee`', 1, function() { + QUnit.test('should unzip arrays combining regrouped elements with `iteratee`', function(assert) { + assert.expect(1); + var array = [[1, 4], [2, 5], [3, 6]]; - deepEqual(_.unzipWith(array, _.add), [6, 15]); + assert.deepEqual(_.unzipWith(array, _.add), [6, 15]); }); - test('should provide the correct `iteratee` arguments', 1, function() { + QUnit.test('should provide the correct `iteratee` arguments', function(assert) { + assert.expect(1); + var args; _.unzipWith([[1, 3, 5], [2, 4, 6]], function() { args || (args = slice.call(arguments)); }); - deepEqual(args, [1, 2, 1, [1, 2]]); + assert.deepEqual(args, [1, 2, 1, [1, 2]]); }); - test('should perform a basic unzip when `iteratee` is nullish', 1, function() { + QUnit.test('should perform a basic unzip when `iteratee` is nullish', function(assert) { + assert.expect(1); + var array = [[1, 3], [2, 4]], values = [, null, undefined], expected = _.map(values, _.constant(_.unzip(array))); @@ -16677,7 +19208,7 @@ return index ? _.unzipWith(array, value) : _.unzipWith(array); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }()); @@ -16686,14 +19217,18 @@ QUnit.module('lodash.values'); (function() { - test('should get the values of an object', 1, function() { + QUnit.test('should get the values of an object', function(assert) { + assert.expect(1); + var object = { 'a': 1, 'b': 2 }; - deepEqual(_.values(object), [1, 2]); + assert.deepEqual(_.values(object), [1, 2]); }); - test('should work with an object that has a `length` property', 1, function() { + QUnit.test('should work with an object that has a `length` property', function(assert) { + assert.expect(1); + var object = { '0': 'a', '1': 'b', 'length': 2 }; - deepEqual(_.values(object), ['a', 'b', 2]); + assert.deepEqual(_.values(object), ['a', 'b', 2]); }); }()); @@ -16702,18 +19237,22 @@ QUnit.module('lodash.without'); (function() { - test('should use strict equality to determine the values to reject', 2, function() { + QUnit.test('should use strict equality to determine the values to reject', function(assert) { + assert.expect(2); + var object1 = { 'a': 1 }, object2 = { 'b': 2 }, array = [object1, object2]; - deepEqual(_.without(array, { 'a': 1 }), array); - deepEqual(_.without(array, object1), [object2]); + assert.deepEqual(_.without(array, { 'a': 1 }), array); + assert.deepEqual(_.without(array, object1), [object2]); }); - test('should remove all occurrences of each value from an array', 1, function() { + QUnit.test('should remove all occurrences of each value from an array', function(assert) { + assert.expect(1); + var array = [1, 2, 3, 1, 2, 3]; - deepEqual(_.without(array, 1, 2), [3, 3]); + assert.deepEqual(_.without(array, 1, 2), [3, 3]); }); }(1, 2, 3)); @@ -16722,7 +19261,9 @@ QUnit.module('lodash.words'); (function() { - test('should treat latin-1 supplementary letters as words', 1, function() { + QUnit.test('should treat latin-1 supplementary letters as words', function(assert) { + assert.expect(1); + var expected = _.map(burredLetters, function(letter) { return [letter]; }); @@ -16731,37 +19272,45 @@ return _.words(letter); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should not treat mathematical operators as words', 1, function() { + QUnit.test('should not treat mathematical operators as words', function(assert) { + assert.expect(1); + var operators = ['\xd7', '\xf7'], expected = _.map(operators, _.constant([])), actual = _.map(operators, _.words); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should work as an iteratee for methods like `_.map`', 1, function() { + QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { + assert.expect(1); + var strings = _.map(['a', 'b', 'c'], Object), actual = _.map(strings, _.words); - deepEqual(actual, [['a'], ['b'], ['c']]); + assert.deepEqual(actual, [['a'], ['b'], ['c']]); }); - test('should work with compound words', 6, function() { - deepEqual(_.words('aeiouAreVowels'), ['aeiou', 'Are', 'Vowels']); - deepEqual(_.words('enable 24h format'), ['enable', '24', 'h', 'format']); - deepEqual(_.words('LETTERSAeiouAreVowels'), ['LETTERS', 'Aeiou', 'Are', 'Vowels']); - deepEqual(_.words('tooLegit2Quit'), ['too', 'Legit', '2', 'Quit']); - deepEqual(_.words('walk500Miles'), ['walk', '500', 'Miles']); - deepEqual(_.words('xhr2Request'), ['xhr', '2', 'Request']); + QUnit.test('should work with compound words', function(assert) { + assert.expect(6); + + assert.deepEqual(_.words('aeiouAreVowels'), ['aeiou', 'Are', 'Vowels']); + assert.deepEqual(_.words('enable 24h format'), ['enable', '24', 'h', 'format']); + assert.deepEqual(_.words('LETTERSAeiouAreVowels'), ['LETTERS', 'Aeiou', 'Are', 'Vowels']); + assert.deepEqual(_.words('tooLegit2Quit'), ['too', 'Legit', '2', 'Quit']); + assert.deepEqual(_.words('walk500Miles'), ['walk', '500', 'Miles']); + assert.deepEqual(_.words('xhr2Request'), ['xhr', '2', 'Request']); }); - test('should work with compound words containing diacritical marks', 3, function() { - deepEqual(_.words('LETTERSÆiouAreVowels'), ['LETTERS', 'Æiou', 'Are', 'Vowels']); - deepEqual(_.words('æiouAreVowels'), ['æiou', 'Are', 'Vowels']); - deepEqual(_.words('æiou2Consonants'), ['æiou', '2', 'Consonants']); + QUnit.test('should work with compound words containing diacritical marks', function(assert) { + assert.expect(3); + + assert.deepEqual(_.words('LETTERSÆiouAreVowels'), ['LETTERS', 'Æiou', 'Are', 'Vowels']); + assert.deepEqual(_.words('æiouAreVowels'), ['æiou', 'Are', 'Vowels']); + assert.deepEqual(_.words('æiou2Consonants'), ['æiou', '2', 'Consonants']); }); }()); @@ -16770,15 +19319,19 @@ QUnit.module('lodash.wrap'); (function() { - test('should create a wrapped function', 1, function() { + QUnit.test('should create a wrapped function', function(assert) { + assert.expect(1); + var p = _.wrap(_.escape, function(func, text) { return '

    ' + func(text) + '

    '; }); - strictEqual(p('fred, barney, & pebbles'), '

    fred, barney, & pebbles

    '); + assert.strictEqual(p('fred, barney, & pebbles'), '

    fred, barney, & pebbles

    '); }); - test('should provide the correct `wrapper` arguments', 1, function() { + QUnit.test('should provide the correct `wrapper` arguments', function(assert) { + assert.expect(1); + var args; var wrapped = _.wrap(_.noop, function() { @@ -16786,10 +19339,12 @@ }); wrapped(1, 2, 3); - deepEqual(args, [_.noop, 1, 2, 3]); + assert.deepEqual(args, [_.noop, 1, 2, 3]); }); - test('should use `_.identity` when `wrapper` is nullish', 1, function() { + QUnit.test('should use `_.identity` when `wrapper` is nullish', function(assert) { + assert.expect(1); + var values = [, null, undefined], expected = _.map(values, _.constant('a')); @@ -16798,16 +19353,18 @@ return wrapped('b', 'c'); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should not set a `this` binding', 1, function() { + QUnit.test('should not set a `this` binding', function(assert) { + assert.expect(1); + var p = _.wrap(_.escape, function(func) { return '

    ' + func(this.text) + '

    '; }); var object = { 'p': p, 'text': 'fred, barney, & pebbles' }; - strictEqual(object.p(), '

    fred, barney, & pebbles

    '); + assert.strictEqual(object.p(), '

    fred, barney, & pebbles

    '); }); }()); @@ -16818,48 +19375,62 @@ (function() { var args = arguments; - test('should return the symmetric difference of the given arrays', 1, function() { + QUnit.test('should return the symmetric difference of the given arrays', function(assert) { + assert.expect(1); + var actual = _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]); - deepEqual(actual, [1, 4, 5]); + assert.deepEqual(actual, [1, 4, 5]); }); - test('should return an array of unique values', 2, function() { + QUnit.test('should return an array of unique values', function(assert) { + assert.expect(2); + var actual = _.xor([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]); - deepEqual(actual, [1, 4, 5]); + assert.deepEqual(actual, [1, 4, 5]); actual = _.xor([1, 1]); - deepEqual(actual, [1]); + assert.deepEqual(actual, [1]); }); - test('should return a new array when a single array is provided', 1, function() { + QUnit.test('should return a new array when a single array is provided', function(assert) { + assert.expect(1); + var array = [1]; - notStrictEqual(_.xor(array), array); + assert.notStrictEqual(_.xor(array), array); }); - test('should ignore individual secondary arguments', 1, function() { + QUnit.test('should ignore individual secondary arguments', function(assert) { + assert.expect(1); + var array = [0]; - deepEqual(_.xor(array, 3, null, { '0': 1 }), array); + assert.deepEqual(_.xor(array, 3, null, { '0': 1 }), array); }); - test('should ignore values that are not arrays or `arguments` objects', 3, function() { + QUnit.test('should ignore values that are not arrays or `arguments` objects', function(assert) { + assert.expect(3); + var array = [1, 2]; - deepEqual(_.xor(array, 3, null, { '0': 1 }), array); - deepEqual(_.xor(null, array, null, [2, 3]), [1, 3]); - deepEqual(_.xor(array, null, args, null), [3]); + assert.deepEqual(_.xor(array, 3, null, { '0': 1 }), array); + assert.deepEqual(_.xor(null, array, null, [2, 3]), [1, 3]); + assert.deepEqual(_.xor(array, null, args, null), [3]); }); - test('should return a wrapped value when chaining', 2, function() { + QUnit.test('should return a wrapped value when chaining', function(assert) { + assert.expect(2); + if (!isNpm) { var wrapped = _([1, 2, 3]).xor([5, 2, 1, 4]); - ok(wrapped instanceof _); - deepEqual(wrapped.value(), [3, 5, 4]); + assert.ok(wrapped instanceof _); + assert.deepEqual(wrapped.value(), [3, 5, 4]); } else { - skipTest(2); + skipTest(assert, 2); } }); - test('should work when in a lazy chain sequence before `first` or `last`', 1, function() { + QUnit.test('should work when in a lazy chain sequence before `first` or `last`', function(assert) { + assert.expect(1); + if (!isNpm) { var array = _.range(LARGE_ARRAY_SIZE + 1), wrapped = _(array).slice(1).xor([LARGE_ARRAY_SIZE, LARGE_ARRAY_SIZE + 1]); @@ -16868,10 +19439,10 @@ return wrapped[methodName](); }); - deepEqual(actual, [1, LARGE_ARRAY_SIZE + 1]); + assert.deepEqual(actual, [1, LARGE_ARRAY_SIZE + 1]); } else { - skipTest(); + skipTest(assert); } }); }(1, 2, 3)); @@ -16884,31 +19455,43 @@ var object = { 'barney': 36, 'fred': 40 }, array = [['barney', 36], ['fred', 40]]; - test('should skip falsey elements in a given two dimensional array', 1, function() { + QUnit.test('should skip falsey elements in a given two dimensional array', function(assert) { + assert.expect(1); + var actual = _.zipObject(array.concat(falsey)); - deepEqual(actual, object); + assert.deepEqual(actual, object); }); - test('should zip together key/value arrays into an object', 1, function() { + QUnit.test('should zip together key/value arrays into an object', function(assert) { + assert.expect(1); + var actual = _.zipObject(['barney', 'fred'], [36, 40]); - deepEqual(actual, object); + assert.deepEqual(actual, object); }); - test('should ignore extra `values`', 1, function() { - deepEqual(_.zipObject(['a'], [1, 2]), { 'a': 1 }); + QUnit.test('should ignore extra `values`', function(assert) { + assert.expect(1); + + assert.deepEqual(_.zipObject(['a'], [1, 2]), { 'a': 1 }); }); - test('should accept a two dimensional array', 1, function() { + QUnit.test('should accept a two dimensional array', function(assert) { + assert.expect(1); + var actual = _.zipObject(array); - deepEqual(actual, object); + assert.deepEqual(actual, object); }); - test('should not assume `keys` is two dimensional if `values` is not provided', 1, function() { + QUnit.test('should not assume `keys` is two dimensional if `values` is not provided', function(assert) { + assert.expect(1); + var actual = _.zipObject(['barney', 'fred']); - deepEqual(actual, { 'barney': undefined, 'fred': undefined }); + assert.deepEqual(actual, { 'barney': undefined, 'fred': undefined }); }); - test('should accept a falsey `array` argument', 1, function() { + 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) { @@ -16917,14 +19500,18 @@ } catch (e) {} }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('should support consuming the return value of `_.pairs`', 1, function() { - deepEqual(_.zipObject(_.pairs(object)), object); + QUnit.test('should support consuming the return value of `_.pairs`', function(assert) { + assert.expect(1); + + assert.deepEqual(_.zipObject(_.pairs(object)), object); }); - test('should work in a lazy chain sequence', 1, function() { + QUnit.test('should work in a lazy chain sequence', function(assert) { + assert.expect(1); + if (!isNpm) { var array = _.times(LARGE_ARRAY_SIZE, function(index) { return ['key' + index, index]; @@ -16932,10 +19519,10 @@ var actual = _(array).zipObject().map(square).filter(isEven).take().value(); - deepEqual(actual, _.take(_.filter(_.map(_.zipObject(array), square), isEven))); + assert.deepEqual(actual, _.take(_.filter(_.map(_.zipObject(array), square), isEven))); } else { - skipTest(); + skipTest(assert); } }); }()); @@ -16945,25 +19532,31 @@ QUnit.module('lodash.zipWith'); (function() { - test('should zip arrays combining grouped elements with `iteratee`', 2, function() { + QUnit.test('should zip arrays combining grouped elements with `iteratee`', function(assert) { + assert.expect(2); + var array1 = [1, 2, 3], array2 = [4, 5, 6]; - deepEqual(_.zipWith(array1, array2, _.add), [5, 7, 9]); - deepEqual(_.zipWith(array1, [], _.add), [1, 2, 3]); + assert.deepEqual(_.zipWith(array1, array2, _.add), [5, 7, 9]); + assert.deepEqual(_.zipWith(array1, [], _.add), [1, 2, 3]); }); - test('should provide the correct `iteratee` arguments', 1, function() { + QUnit.test('should provide the correct `iteratee` arguments', function(assert) { + assert.expect(1); + var args; _.zipWith([1, 2], [3, 4], [5, 6], function() { args || (args = slice.call(arguments)); }); - deepEqual(args, [1, 3, 1, [1, 3, 5]]); + assert.deepEqual(args, [1, 3, 1, [1, 3, 5]]); }); - test('should perform a basic zip when `iteratee` is nullish', 1, function() { + QUnit.test('should perform a basic zip when `iteratee` is nullish', function(assert) { + assert.expect(1); + var array1 = [1, 2], array2 = [3, 4], values = [, null, undefined], @@ -16973,7 +19566,7 @@ return index ? _.zipWith(array1, array2, value) : _.zipWith(array1, array2); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); }()); @@ -17005,46 +19598,56 @@ }; _.forOwn(object, function(pair, key) { - test('`_.' + methodName + '` should work with ' + key, 2, function() { + QUnit.test('`_.' + methodName + '` should work with ' + key, function(assert) { + assert.expect(2); + var actual = func(pair[0]); - deepEqual(actual, pair[1]); - deepEqual(func(actual), actual.length ? pair[0] : []); + assert.deepEqual(actual, pair[1]); + assert.deepEqual(func(actual), actual.length ? pair[0] : []); }); }); - test('`_.' + methodName + '` should work with tuples of different lengths', 4, function() { + QUnit.test('`_.' + methodName + '` should work with tuples of different lengths', function(assert) { + assert.expect(4); + var pair = [ [['barney', 36], ['fred', 40, false]], [['barney', 'fred'], [36, 40], [undefined, false]] ]; var actual = func(pair[0]); - ok('0' in actual[2]); - deepEqual(actual, pair[1]); + assert.ok('0' in actual[2]); + assert.deepEqual(actual, pair[1]); actual = func(actual); - ok('2' in actual[0]); - deepEqual(actual, [['barney', 36, undefined], ['fred', 40, false]]); + assert.ok('2' in actual[0]); + assert.deepEqual(actual, [['barney', 36, undefined], ['fred', 40, false]]); }); - test('`_.' + methodName + '` should treat falsey values as empty arrays', 1, function() { + QUnit.test('`_.' + methodName + '` should treat falsey values as empty arrays', function(assert) { + assert.expect(1); + var expected = _.map(falsey, _.constant([])); var actual = _.map(falsey, function(value) { return func([value, value, value]); }); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); }); - test('`_.' + methodName + '` should ignore values that are not arrays or `arguments` objects', 1, function() { + QUnit.test('`_.' + methodName + '` should ignore values that are not arrays or `arguments` objects', function(assert) { + assert.expect(1); + var array = [[1, 2], [3, 4], null, undefined, { '0': 1 }]; - deepEqual(func(array), [[1, 3], [2, 4]]); + assert.deepEqual(func(array), [[1, 3], [2, 4]]); }); - test('`_.' + methodName + '` should support consuming its return value', 1, function() { + QUnit.test('`_.' + methodName + '` should support consuming its return value', function(assert) { + assert.expect(1); + var expected = [['barney', 'fred'], [36, 40]]; - deepEqual(func(func(func(func(expected)))), expected); + assert.deepEqual(func(func(func(func(expected)))), expected); }); }); @@ -17053,31 +19656,35 @@ QUnit.module('lodash(...).commit'); (function() { - test('should execute the chained sequence and returns the wrapped result', 4, function() { + QUnit.test('should execute the chained sequence and returns the wrapped result', function(assert) { + assert.expect(4); + if (!isNpm) { var array = [1], wrapped = _(array).push(2).push(3); - deepEqual(array, [1]); + assert.deepEqual(array, [1]); var otherWrapper = wrapped.commit(); - ok(otherWrapper instanceof _); - deepEqual(otherWrapper.value(), [1, 2, 3]); - deepEqual(wrapped.value(), [1, 2, 3, 2, 3]); + assert.ok(otherWrapper instanceof _); + assert.deepEqual(otherWrapper.value(), [1, 2, 3]); + assert.deepEqual(wrapped.value(), [1, 2, 3, 2, 3]); } else { - skipTest(4); + skipTest(assert, 4); } }); - test('should track the `__chain__` value of a wrapper', 2, function() { + QUnit.test('should track the `__chain__` value of a wrapper', function(assert) { + assert.expect(2); + if (!isNpm) { var wrapped = _([1]).chain().commit().first(); - ok(wrapped instanceof _); - strictEqual(wrapped.value(), 1); + assert.ok(wrapped instanceof _); + assert.strictEqual(wrapped.value(), 1); } else { - skipTest(2); + skipTest(assert, 2); } }); }()); @@ -17087,20 +19694,24 @@ QUnit.module('lodash(...).concat'); (function() { - test('should concat arrays and values', 2, function() { + QUnit.test('should concat arrays and values', function(assert) { + assert.expect(2); + if (!isNpm) { var array = [1], wrapped = _(array).concat(2, [3], [[4]]); - deepEqual(wrapped.value(), [1, 2, 3, [4]]); - deepEqual(array, [1]); + assert.deepEqual(wrapped.value(), [1, 2, 3, [4]]); + assert.deepEqual(array, [1]); } else { - skipTest(2); + skipTest(assert, 2); } }); - test('should treat sparse arrays as dense', 3, function() { + QUnit.test('should treat sparse arrays as dense', function(assert) { + assert.expect(3); + if (!isNpm) { var expected = [], wrapped = _(Array(1)).concat(Array(1)), @@ -17108,27 +19719,29 @@ expected.push(undefined, undefined); - ok('0'in actual); - ok('1' in actual); - deepEqual(actual, expected); + assert.ok('0'in actual); + assert.ok('1' in actual); + assert.deepEqual(actual, expected); } else { - skipTest(3); + skipTest(assert, 3); } }); - test('should return a new wrapped array', 3, function() { + QUnit.test('should return a new wrapped array', function(assert) { + assert.expect(3); + if (!isNpm) { var array = [1], wrapped = _(array).concat([2, 3]), actual = wrapped.value(); - deepEqual(array, [1]); - deepEqual(actual, [1, 2, 3]); - notStrictEqual(actual, array); + assert.deepEqual(array, [1]); + assert.deepEqual(actual, [1, 2, 3]); + assert.notStrictEqual(actual, array); } else { - skipTest(3); + skipTest(assert, 3); } }); }()); @@ -17140,23 +19753,27 @@ (function() { var array = [1, 2, 3]; - test('should return join all array elements into a string', 2, function() { + QUnit.test('should return join all array elements into a string', function(assert) { + assert.expect(2); + if (!isNpm) { var wrapped = _(array); - strictEqual(wrapped.join('.'), '1.2.3'); - strictEqual(wrapped.value(), array); + assert.strictEqual(wrapped.join('.'), '1.2.3'); + assert.strictEqual(wrapped.value(), array); } else { - skipTest(2); + skipTest(assert, 2); } }); - test('should return a wrapped value when explicitly chaining', 1, function() { + QUnit.test('should return a wrapped value when explicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - ok(_(array).chain().join('.') instanceof _); + assert.ok(_(array).chain().join('.') instanceof _); } else { - skipTest(); + skipTest(assert); } }); }()); @@ -17172,64 +19789,72 @@ var chainType = 'in an ' + (implict ? 'implict' : 'explict') + ' chain'; - test('should follow the iterator protocol ' + chainType, 3, function() { + QUnit.test('should follow the iterator protocol ' + chainType, function(assert) { + assert.expect(3); + if (!isNpm) { var wrapped = chain([1, 2]); - deepEqual(wrapped.next(), { 'done': false, 'value': 1 }); - deepEqual(wrapped.next(), { 'done': false, 'value': 2 }); - deepEqual(wrapped.next(), { 'done': true, 'value': undefined }); + assert.deepEqual(wrapped.next(), { 'done': false, 'value': 1 }); + assert.deepEqual(wrapped.next(), { 'done': false, 'value': 2 }); + assert.deepEqual(wrapped.next(), { 'done': true, 'value': undefined }); } else { - skipTest(3); + skipTest(assert, 3); } }); - test('should act as an iterable ' + chainType, 2, function() { + QUnit.test('should act as an iterable ' + chainType, function(assert) { + assert.expect(2); + if (!isNpm && Symbol && Symbol.iterator) { var array = [1, 2], wrapped = chain(array); - ok(wrapped[Symbol.iterator]() === wrapped); - deepEqual(_.toArray(wrapped), array); + assert.ok(wrapped[Symbol.iterator]() === wrapped); + assert.deepEqual(_.toArray(wrapped), array); } else { - skipTest(2); + skipTest(assert, 2); } }); - test('should reset the iterator correctly ' + chainType, 4, function() { + QUnit.test('should reset the iterator correctly ' + chainType, function(assert) { + assert.expect(4); + if (!isNpm && Symbol && Symbol.iterator) { var array = [1, 2], wrapped = chain(array); - deepEqual(_.toArray(wrapped), array); - deepEqual(_.toArray(wrapped), [], 'produces an empty array for exhausted iterator'); + assert.deepEqual(_.toArray(wrapped), array); + assert.deepEqual(_.toArray(wrapped), [], 'produces an empty array for exhausted iterator'); var other = wrapped.filter(); - deepEqual(_.toArray(other), array, 'reset for new chain segments'); - deepEqual(_.toArray(wrapped), [], 'iterator is still exhausted'); + assert.deepEqual(_.toArray(other), array, 'reset for new chain segments'); + assert.deepEqual(_.toArray(wrapped), [], 'iterator is still exhausted'); } else { - skipTest(4); + skipTest(assert, 4); } }); - test('should work in a lazy sequence ' + chainType, 3, function() { + QUnit.test('should work in a lazy sequence ' + chainType, function(assert) { + assert.expect(3); + if (!isNpm && Symbol && Symbol.iterator) { var array = _.range(LARGE_ARRAY_SIZE), predicate = function(value) { values.push(value); return isEven(value); }, values = [], wrapped = chain(array); - deepEqual(_.toArray(wrapped), array); + assert.deepEqual(_.toArray(wrapped), array); wrapped = wrapped.filter(predicate); - deepEqual(_.toArray(wrapped), _.filter(array, isEven), 'reset for new lazy chain segments'); - deepEqual(values, array, 'memoizes iterator values'); + assert.deepEqual(_.toArray(wrapped), _.filter(array, isEven), 'reset for new lazy chain segments'); + assert.deepEqual(values, array, 'memoizes iterator values'); } else { - skipTest(3); + skipTest(assert, 3); } }); }); @@ -17239,49 +19864,55 @@ QUnit.module('lodash(...).plant'); (function() { - test('should clone the chained sequence planting `value` as the wrapped value', 2, function() { + QUnit.test('should clone the chained sequence planting `value` as the wrapped value', function(assert) { + assert.expect(2); + if (!isNpm) { var array1 = [5, null, 3, null, 1], array2 = [10, null, 8, null, 6], wrapped1 = _(array1).thru(_.compact).map(square).takeRight(2).sort(), wrapped2 = wrapped1.plant(array2); - deepEqual(wrapped2.value(), [36, 64]); - deepEqual(wrapped1.value(), [1, 9]); + assert.deepEqual(wrapped2.value(), [36, 64]); + assert.deepEqual(wrapped1.value(), [1, 9]); } else { - skipTest(2); + skipTest(assert, 2); } }); - test('should clone `chainAll` settings', 1, function() { + QUnit.test('should clone `chainAll` settings', function(assert) { + assert.expect(1); + if (!isNpm) { var array1 = [2, 4], array2 = [6, 8], wrapped1 = _(array1).chain().map(square), wrapped2 = wrapped1.plant(array2); - deepEqual(wrapped2.first().value(), 36); + assert.deepEqual(wrapped2.first().value(), 36); } else { - skipTest(); + skipTest(assert); } }); - test('should reset iterator data on cloned sequences', 3, function() { + QUnit.test('should reset iterator data on cloned sequences', function(assert) { + assert.expect(3); + if (!isNpm && Symbol && Symbol.iterator) { var array1 = [2, 4], array2 = [6, 8], wrapped1 = _(array1).map(square); - deepEqual(_.toArray(wrapped1), [4, 16]); - deepEqual(_.toArray(wrapped1), []); + assert.deepEqual(_.toArray(wrapped1), [4, 16]); + assert.deepEqual(_.toArray(wrapped1), []); var wrapped2 = wrapped1.plant(array2); - deepEqual(_.toArray(wrapped2), [36, 64]); + assert.deepEqual(_.toArray(wrapped2), [36, 64]); } else { - skipTest(3); + skipTest(assert, 3); } }); }()); @@ -17291,21 +19922,23 @@ QUnit.module('lodash(...).pop'); (function() { - test('should remove elements from the end of `array`', 5, function() { + QUnit.test('should remove elements from the end of `array`', function(assert) { + assert.expect(5); + if (!isNpm) { var array = [1, 2], wrapped = _(array); - strictEqual(wrapped.pop(), 2); - deepEqual(wrapped.value(), [1]); - strictEqual(wrapped.pop(), 1); + assert.strictEqual(wrapped.pop(), 2); + assert.deepEqual(wrapped.value(), [1]); + assert.strictEqual(wrapped.pop(), 1); var actual = wrapped.value(); - deepEqual(actual, []); - strictEqual(actual, array); + assert.deepEqual(actual, []); + assert.strictEqual(actual, array); } else { - skipTest(5); + skipTest(assert, 5); } }); }()); @@ -17315,17 +19948,19 @@ QUnit.module('lodash(...).push'); (function() { - test('should append elements to `array`', 2, function() { + QUnit.test('should append elements to `array`', function(assert) { + assert.expect(2); + if (!isNpm) { var array = [1], wrapped = _(array).push(2, 3), actual = wrapped.value(); - strictEqual(actual, array); - deepEqual(actual, [1, 2, 3]); + assert.strictEqual(actual, array); + assert.deepEqual(actual, [1, 2, 3]); } else { - skipTest(2); + skipTest(assert, 2); } }); }()); @@ -17335,23 +19970,27 @@ QUnit.module('lodash(...).replace'); (function() { - test('should replace the matched pattern', 2, function() { + QUnit.test('should replace the matched pattern', function(assert) { + assert.expect(2); + if (!isNpm) { var wrapped = _('abcdef'); - strictEqual(wrapped.replace('def', '123'), 'abc123'); - strictEqual(wrapped.replace(/[bdf]/g, '-'), 'a-c-e-'); + assert.strictEqual(wrapped.replace('def', '123'), 'abc123'); + assert.strictEqual(wrapped.replace(/[bdf]/g, '-'), 'a-c-e-'); } else { - skipTest(2); + skipTest(assert, 2); } }); - test('should return a wrapped value when explicitly chaining', 1, function() { + QUnit.test('should return a wrapped value when explicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { - ok(_('abc').chain().replace('b', '_') instanceof _); + assert.ok(_('abc').chain().replace('b', '_') instanceof _); } else { - skipTest(); + skipTest(assert); } }); }()); @@ -17364,7 +20003,9 @@ var largeArray = _.range(LARGE_ARRAY_SIZE).concat(null), smallArray = [0, 1, 2, null]; - test('should return the wrapped reversed `array`', 6, function() { + QUnit.test('should return the wrapped reversed `array`', function(assert) { + assert.expect(6); + if (!isNpm) { _.times(2, function(index) { var array = (index ? largeArray : smallArray).slice(), @@ -17372,33 +20013,37 @@ wrapped = _(array).reverse(), actual = wrapped.value(); - ok(wrapped instanceof _); - strictEqual(actual, array); - deepEqual(actual, clone.slice().reverse()); + assert.ok(wrapped instanceof _); + assert.strictEqual(actual, array); + assert.deepEqual(actual, clone.slice().reverse()); }); } else { - skipTest(6); + skipTest(assert, 6); } }); - test('should work in a lazy chain sequence', 4, function() { + QUnit.test('should work in a lazy chain sequence', function(assert) { + assert.expect(4); + if (!isNpm) { _.times(2, function(index) { var array = (index ? largeArray : smallArray).slice(), expected = array.slice(), actual = _(array).slice(1).reverse().value(); - deepEqual(actual, expected.slice(1).reverse()); - deepEqual(array, expected); + assert.deepEqual(actual, expected.slice(1).reverse()); + assert.deepEqual(array, expected); }); } else { - skipTest(4); + skipTest(assert, 4); } }); - test('should be lazy when in a lazy chain sequence', 3, function() { + QUnit.test('should be lazy when in a lazy chain sequence', function(assert) { + assert.expect(3); + if (!isNpm) { var spy = { 'toString': function() { @@ -17414,16 +20059,18 @@ actual = wrapped.last(); } catch (e) {} - ok(wrapped instanceof _); - strictEqual(actual, '1'); - deepEqual(array, expected); + assert.ok(wrapped instanceof _); + assert.strictEqual(actual, '1'); + assert.deepEqual(array, expected); } else { - skipTest(3); + skipTest(assert, 3); } }); - test('should work in a hybrid chain sequence', 8, function() { + QUnit.test('should work in a hybrid chain sequence', function(assert) { + assert.expect(8); + if (!isNpm) { _.times(2, function(index) { var clone = (index ? largeArray : smallArray).slice(); @@ -17433,34 +20080,36 @@ expected = clone.slice(1, -1).reverse(), actual = _(array)[methodName](_.identity).thru(_.compact).reverse().value(); - deepEqual(actual, expected); + assert.deepEqual(actual, expected); array = clone.slice(); actual = _(array).thru(_.compact)[methodName](_.identity).pull(1).push(3).reverse().value(); - deepEqual(actual, [3].concat(expected.slice(0, -1))); + assert.deepEqual(actual, [3].concat(expected.slice(0, -1))); }); }); } else { - skipTest(8); + skipTest(assert, 8); } }); - test('should track the `__chain__` value of a wrapper', 6, function() { + QUnit.test('should track the `__chain__` value of a wrapper', function(assert) { + assert.expect(6); + if (!isNpm) { _.times(2, function(index) { var array = (index ? largeArray : smallArray).slice(), expected = array.slice().reverse(), wrapped = _(array).chain().reverse().first(); - ok(wrapped instanceof _); - strictEqual(wrapped.value(), _.first(expected)); - deepEqual(array, expected); + assert.ok(wrapped instanceof _); + assert.strictEqual(wrapped.value(), _.first(expected)); + assert.deepEqual(array, expected); }); } else { - skipTest(6); + skipTest(assert, 6); } }); }()); @@ -17470,21 +20119,23 @@ QUnit.module('lodash(...).shift'); (function() { - test('should remove elements from the front of `array`', 5, function() { + QUnit.test('should remove elements from the front of `array`', function(assert) { + assert.expect(5); + if (!isNpm) { var array = [1, 2], wrapped = _(array); - strictEqual(wrapped.shift(), 1); - deepEqual(wrapped.value(), [2]); - strictEqual(wrapped.shift(), 2); + assert.strictEqual(wrapped.shift(), 1); + assert.deepEqual(wrapped.value(), [2]); + assert.strictEqual(wrapped.shift(), 2); var actual = wrapped.value(); - deepEqual(actual, []); - strictEqual(actual, array); + assert.deepEqual(actual, []); + assert.strictEqual(actual, array); } else { - skipTest(5); + skipTest(assert, 5); } }); }()); @@ -17494,18 +20145,20 @@ QUnit.module('lodash(...).slice'); (function() { - test('should return a slice of `array`', 3, function() { + QUnit.test('should return a slice of `array`', function(assert) { + assert.expect(3); + if (!isNpm) { var array = [1, 2, 3], wrapped = _(array).slice(0, 2), actual = wrapped.value(); - deepEqual(array, [1, 2, 3]); - deepEqual(actual, [1, 2]); - notStrictEqual(actual, array); + assert.deepEqual(array, [1, 2, 3]); + assert.deepEqual(actual, [1, 2]); + assert.notStrictEqual(actual, array); } else { - skipTest(3); + skipTest(assert, 3); } }); }()); @@ -17515,17 +20168,19 @@ QUnit.module('lodash(...).sort'); (function() { - test('should return the wrapped sorted `array`', 2, function() { + QUnit.test('should return the wrapped sorted `array`', function(assert) { + assert.expect(2); + if (!isNpm) { var array = [3, 1, 2], wrapped = _(array).sort(), actual = wrapped.value(); - strictEqual(actual, array); - deepEqual(actual, [1, 2, 3]); + assert.strictEqual(actual, array); + assert.deepEqual(actual, [1, 2, 3]); } else { - skipTest(2); + skipTest(assert, 2); } }); }()); @@ -17535,21 +20190,23 @@ QUnit.module('lodash(...).splice'); (function() { - test('should support removing and inserting elements', 5, function() { + QUnit.test('should support removing and inserting elements', function(assert) { + assert.expect(5); + if (!isNpm) { var array = [1, 2], wrapped = _(array); - deepEqual(wrapped.splice(1, 1, 3).value(), [2]); - deepEqual(wrapped.value(), [1, 3]); - deepEqual(wrapped.splice(0, 2).value(), [1, 3]); + assert.deepEqual(wrapped.splice(1, 1, 3).value(), [2]); + assert.deepEqual(wrapped.value(), [1, 3]); + assert.deepEqual(wrapped.splice(0, 2).value(), [1, 3]); var actual = wrapped.value(); - deepEqual(actual, []); - strictEqual(actual, array); + assert.deepEqual(actual, []); + assert.strictEqual(actual, array); } else { - skipTest(5); + skipTest(assert, 5); } }); }()); @@ -17559,24 +20216,28 @@ QUnit.module('lodash(...).split'); (function() { - test('should support string split', 2, function() { + QUnit.test('should support string split', function(assert) { + assert.expect(2); + if (!isNpm) { var wrapped = _('abcde'); - deepEqual(wrapped.split('c').value(), ['ab', 'de']); - deepEqual(wrapped.split(/[bd]/).value(), ['a', 'c', 'e']); + assert.deepEqual(wrapped.split('c').value(), ['ab', 'de']); + assert.deepEqual(wrapped.split(/[bd]/).value(), ['a', 'c', 'e']); } else { - skipTest(2); + skipTest(assert, 2); } }); - test('should allow mixed string and array prototype methods', 1, function() { + QUnit.test('should allow mixed string and array prototype methods', function(assert) { + assert.expect(1); + if (!isNpm) { var wrapped = _('abc'); - strictEqual(wrapped.split('b').join(','), 'a,c'); + assert.strictEqual(wrapped.split('b').join(','), 'a,c'); } else { - skipTest(); + skipTest(assert); } }); }()); @@ -17586,17 +20247,19 @@ QUnit.module('lodash(...).unshift'); (function() { - test('should prepend elements to `array`', 2, function() { + QUnit.test('should prepend elements to `array`', function(assert) { + assert.expect(2); + if (!isNpm) { var array = [3], wrapped = _(array).unshift(1, 2), actual = wrapped.value(); - strictEqual(actual, array); - deepEqual(actual, [1, 2, 3]); + assert.strictEqual(actual, array); + assert.deepEqual(actual, [1, 2, 3]); } else { - skipTest(2); + skipTest(assert, 2); } }); }()); @@ -17606,13 +20269,15 @@ QUnit.module('lodash(...).toString'); (function() { - test('should return the `toString` result of the wrapped value', 1, function() { + QUnit.test('should return the `toString` result of the wrapped value', function(assert) { + assert.expect(1); + if (!isNpm) { var wrapped = _([1, 2, 3]); - strictEqual(String(wrapped), '1,2,3'); + assert.strictEqual(String(wrapped), '1,2,3'); } else { - skipTest(); + skipTest(assert); } }); }()); @@ -17622,50 +20287,58 @@ QUnit.module('lodash(...).value'); (function() { - test('should execute the chained sequence and extract the unwrapped value', 4, function() { + QUnit.test('should execute the chained sequence and extract the unwrapped value', function(assert) { + assert.expect(4); + if (!isNpm) { var array = [1], wrapped = _(array).push(2).push(3); - deepEqual(array, [1]); - deepEqual(wrapped.value(), [1, 2, 3]); - deepEqual(wrapped.value(), [1, 2, 3, 2, 3]); - deepEqual(array, [1, 2, 3, 2, 3]); + assert.deepEqual(array, [1]); + assert.deepEqual(wrapped.value(), [1, 2, 3]); + assert.deepEqual(wrapped.value(), [1, 2, 3, 2, 3]); + assert.deepEqual(array, [1, 2, 3, 2, 3]); } else { - skipTest(4); + skipTest(assert, 4); } }); - test('should return the `valueOf` result of the wrapped value', 1, function() { + QUnit.test('should return the `valueOf` result of the wrapped value', function(assert) { + assert.expect(1); + if (!isNpm) { var wrapped = _(123); - strictEqual(Number(wrapped), 123); + assert.strictEqual(Number(wrapped), 123); } else { - skipTest(); + skipTest(assert); } }); - test('should stringify the wrapped value when used by `JSON.stringify`', 1, function() { + QUnit.test('should stringify the wrapped value when used by `JSON.stringify`', function(assert) { + assert.expect(1); + if (!isNpm && JSON) { var wrapped = _([1, 2, 3]); - strictEqual(JSON.stringify(wrapped), '[1,2,3]'); + assert.strictEqual(JSON.stringify(wrapped), '[1,2,3]'); } else { - skipTest(); + skipTest(assert); } }); - test('should be aliased', 3, function() { + QUnit.test('should be aliased', function(assert) { + assert.expect(3); + if (!isNpm) { var expected = _.prototype.value; - strictEqual(_.prototype.run, expected); - strictEqual(_.prototype.toJSON, expected); - strictEqual(_.prototype.valueOf, expected); + assert.strictEqual(_.prototype.run, expected); + assert.strictEqual(_.prototype.toJSON, expected); + assert.strictEqual(_.prototype.valueOf, expected); } else { - skipTest(3); + skipTest(assert, 3); } }); }()); @@ -17683,17 +20356,19 @@ ]; _.each(funcs, function(methodName) { - test('`_(...).' + methodName + '` should return a new wrapper', 2, function() { + QUnit.test('`_(...).' + methodName + '` should return a new wrapper', function(assert) { + assert.expect(2); + if (!isNpm) { var array = [1, 2, 3], wrapped = _(array), actual = wrapped[methodName](); - ok(actual instanceof _); - notStrictEqual(actual, wrapped); + assert.ok(actual instanceof _); + assert.notStrictEqual(actual, wrapped); } else { - skipTest(2); + skipTest(assert, 2); } }); }); @@ -17711,17 +20386,19 @@ ]; _.each(funcs, function(methodName) { - test('`_(...).' + methodName + '` should return a new wrapped value', 2, function() { + QUnit.test('`_(...).' + methodName + '` should return a new wrapped value', function(assert) { + assert.expect(2); + if (!isNpm) { var array = [1, 2, 3], wrapped = _(array), actual = wrapped[methodName](); - ok(actual instanceof _); - notStrictEqual(actual, wrapped); + assert.ok(actual instanceof _); + assert.notStrictEqual(actual, wrapped); } else { - skipTest(2); + skipTest(assert, 2); } }); }); @@ -17780,27 +20457,31 @@ ]; _.each(funcs, function(methodName) { - test('`_(...).' + methodName + '` should return an unwrapped value when implicitly chaining', 1, function() { + QUnit.test('`_(...).' + methodName + '` should return an unwrapped value when implicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { var array = [1, 2, 3], actual = _(array)[methodName](); - ok(!(actual instanceof _)); + assert.notOk(actual instanceof _); } else { - skipTest(); + skipTest(assert); } }); - test('`_(...).' + methodName + '` should return a wrapped value when explicitly chaining', 1, function() { + QUnit.test('`_(...).' + methodName + '` should return a wrapped value when explicitly chaining', function(assert) { + assert.expect(1); + if (!isNpm) { var array = [1, 2, 3], actual = _(array).chain()[methodName](); - ok(actual instanceof _); + assert.ok(actual instanceof _); } else { - skipTest(); + skipTest(assert); } }); }); @@ -17815,64 +20496,70 @@ sortedArgs = (function() { return arguments; }(1, [3], 5, null, null)), array = [1, 2, 3, 4, 5, 6]; - test('should work with `arguments` objects', 30, function() { + QUnit.test('should work with `arguments` objects', function(assert) { + assert.expect(30); + function message(methodName) { return '`_.' + methodName + '` should work with `arguments` objects'; } - deepEqual(_.difference(args, [null]), [1, [3], 5], message('difference')); - deepEqual(_.difference(array, args), [2, 3, 4, 6], '_.difference should work with `arguments` objects as secondary arguments'); - - deepEqual(_.union(args, [null, 6]), [1, null, [3], 5, 6], message('union')); - deepEqual(_.union(array, args), array.concat([null, [3]]), '_.union should work with `arguments` objects as secondary arguments'); - - deepEqual(_.compact(args), [1, [3], 5], message('compact')); - deepEqual(_.drop(args, 3), [null, 5], message('drop')); - deepEqual(_.dropRight(args, 3), [1, null], message('dropRight')); - deepEqual(_.dropRightWhile(args,_.identity), [1, null, [3], null], message('dropRightWhile')); - deepEqual(_.dropWhile(args,_.identity), [ null, [3], null, 5], message('dropWhile')); - deepEqual(_.findIndex(args, _.identity), 0, message('findIndex')); - deepEqual(_.findLastIndex(args, _.identity), 4, message('findLastIndex')); - deepEqual(_.first(args), 1, message('first')); - deepEqual(_.flatten(args), [1, null, 3, null, 5], message('flatten')); - deepEqual(_.indexOf(args, 5), 4, message('indexOf')); - deepEqual(_.initial(args), [1, null, [3], null], message('initial')); - deepEqual(_.intersection(args, [1]), [1], message('intersection')); - deepEqual(_.last(args), 5, message('last')); - deepEqual(_.lastIndexOf(args, 1), 0, message('lastIndexOf')); - deepEqual(_.rest(args, 4), [null, [3], null, 5], message('rest')); - deepEqual(_.sortedIndex(sortedArgs, 6), 3, message('sortedIndex')); - deepEqual(_.sortedIndexOf(sortedArgs, 5), 2, message('sortedIndexOf')); - deepEqual(_.sortedLastIndex(sortedArgs, 5), 3, message('sortedLastIndex')); - deepEqual(_.sortedLastIndexOf(sortedArgs, 1), 0, message('sortedLastIndexOf')); - deepEqual(_.take(args, 2), [1, null], message('take')); - deepEqual(_.takeRight(args, 1), [5], message('takeRight')); - deepEqual(_.takeRightWhile(args, _.identity), [5], message('takeRightWhile')); - deepEqual(_.takeWhile(args, _.identity), [1], message('takeWhile')); - deepEqual(_.uniq(args), [1, null, [3], 5], message('uniq')); - deepEqual(_.without(args, null), [1, [3], 5], message('without')); - deepEqual(_.zip(args, args), [[1, 1], [null, null], [[3], [3]], [null, null], [5, 5]], message('zip')); - }); - - test('should accept falsey primary arguments', 4, function() { + assert.deepEqual(_.difference(args, [null]), [1, [3], 5], message('difference')); + assert.deepEqual(_.difference(array, args), [2, 3, 4, 6], '_.difference should work with `arguments` objects as secondary arguments'); + + assert.deepEqual(_.union(args, [null, 6]), [1, null, [3], 5, 6], message('union')); + assert.deepEqual(_.union(array, args), array.concat([null, [3]]), '_.union should work with `arguments` objects as secondary arguments'); + + assert.deepEqual(_.compact(args), [1, [3], 5], message('compact')); + assert.deepEqual(_.drop(args, 3), [null, 5], message('drop')); + assert.deepEqual(_.dropRight(args, 3), [1, null], message('dropRight')); + assert.deepEqual(_.dropRightWhile(args,_.identity), [1, null, [3], null], message('dropRightWhile')); + 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(_.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(_.take(args, 2), [1, null], message('take')); + assert.deepEqual(_.takeRight(args, 1), [5], message('takeRight')); + assert.deepEqual(_.takeRightWhile(args, _.identity), [5], message('takeRightWhile')); + assert.deepEqual(_.takeWhile(args, _.identity), [1], message('takeWhile')); + assert.deepEqual(_.uniq(args), [1, null, [3], 5], message('uniq')); + assert.deepEqual(_.without(args, null), [1, [3], 5], message('without')); + assert.deepEqual(_.zip(args, args), [[1, 1], [null, null], [[3], [3]], [null, null], [5, 5]], message('zip')); + }); + + QUnit.test('should accept falsey primary arguments', function(assert) { + assert.expect(4); + function message(methodName) { return '`_.' + methodName + '` should accept falsey primary arguments'; } - deepEqual(_.difference(null, array), [], message('difference')); - deepEqual(_.intersection(null, array), [], message('intersection')); - deepEqual(_.union(null, array), array, message('union')); - deepEqual(_.xor(null, array), array, message('xor')); + assert.deepEqual(_.difference(null, array), [], message('difference')); + assert.deepEqual(_.intersection(null, array), [], message('intersection')); + assert.deepEqual(_.union(null, array), array, message('union')); + assert.deepEqual(_.xor(null, array), array, message('xor')); }); - test('should accept falsey secondary arguments', 3, function() { + QUnit.test('should accept falsey secondary arguments', function(assert) { + assert.expect(3); + function message(methodName) { return '`_.' + methodName + '` should accept falsey secondary arguments'; } - deepEqual(_.difference(array, null), array, message('difference')); - deepEqual(_.intersection(array, null), [], message('intersection')); - deepEqual(_.union(array, null), array, message('union')); + assert.deepEqual(_.difference(array, null), array, message('difference')); + assert.deepEqual(_.intersection(array, null), [], message('intersection')); + assert.deepEqual(_.union(array, null), array, message('union')); }); }()); @@ -17901,10 +20588,12 @@ _.each(stringMethods, function(methodName) { var func = _[methodName]; - test('`_.' + methodName + '` should return an empty string for empty values', 3, function() { - strictEqual(func(null), ''); - strictEqual(func(undefined), ''); - strictEqual(func(''), ''); + QUnit.test('`_.' + methodName + '` should return an empty string for empty values', function(assert) { + assert.expect(3); + + assert.strictEqual(func(null), ''); + assert.strictEqual(func(undefined), ''); + assert.strictEqual(func(''), ''); }); }); }()); @@ -17986,7 +20675,9 @@ var acceptFalsey = _.difference(allMethods, rejectFalsey); - test('should accept falsey arguments', 233, function() { + QUnit.test('should accept falsey arguments', function(assert) { + assert.expect(233); + var emptyArrays = _.map(falsey, _.constant([])); _.each(acceptFalsey, function(methodName) { @@ -18009,20 +20700,22 @@ expected = falsey; } if (_.includes(returnArrays, methodName) && methodName != 'sample') { - deepEqual(actual, expected, '_.' + methodName + ' returns an array'); + assert.deepEqual(actual, expected, '_.' + methodName + ' returns an array'); } - ok(pass, '`_.' + methodName + '` accepts falsey arguments'); + assert.ok(pass, '`_.' + methodName + '` accepts falsey arguments'); }); // Skip tests for missing methods of modularized builds. _.each(['chain', 'noConflict', 'runInContext'], function(methodName) { if (!_[methodName]) { - skipTest(); + skipTest(assert); } }); }); - test('should return an array', 66, function() { + QUnit.test('should return an array', function(assert) { + assert.expect(66); + var array = [1, 2, 3]; _.each(returnArrays, function(methodName) { @@ -18039,14 +20732,16 @@ default: actual = func(array); } - ok(_.isArray(actual), '_.' + methodName + ' returns an array'); + assert.ok(_.isArray(actual), '_.' + methodName + ' returns an array'); var isPull = methodName == 'pull'; - strictEqual(actual === array, isPull, '_.' + methodName + ' should ' + (isPull ? '' : 'not ') + 'return the provided array'); + assert.strictEqual(actual === array, isPull, '_.' + methodName + ' should ' + (isPull ? '' : 'not ') + 'return the provided array'); }); }); - test('should throw an error for falsey arguments', 24, function() { + QUnit.test('should throw an error for falsey arguments', function(assert) { + assert.expect(24); + _.each(rejectFalsey, function(methodName) { var expected = _.map(falsey, _.constant(true)), func = _[methodName]; @@ -18064,13 +20759,15 @@ return pass; }); - deepEqual(actual, expected, '`_.' + methodName + '` rejects falsey arguments'); + assert.deepEqual(actual, expected, '`_.' + methodName + '` rejects falsey arguments'); }); }); - test('should not contain minified method names (test production builds)', 1, function() { + QUnit.test('should not contain minified method names (test production builds)', function(assert) { + assert.expect(1); + var shortNames = ['at', 'eq', 'gt', 'lt']; - ok(_.every(_.functions(_), function(methodName) { + assert.ok(_.every(_.functions(_), function(methodName) { return methodName.length > 2 || _.includes(shortNames, methodName); })); }); From 02a28d565bb6de439ed9ad55ce7f7539f7aec6f2 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Tue, 8 Sep 2015 22:48:37 -0700 Subject: [PATCH 285/935] Add `_.flip`. [closes #1449] --- lodash.js | 28 +++++++++++++++++++++++++++- test/test.js | 3 ++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/lodash.js b/lodash.js index b17ae1da97..724469099a 100644 --- a/lodash.js +++ b/lodash.js @@ -23,7 +23,8 @@ PARTIAL_FLAG = 32, PARTIAL_RIGHT_FLAG = 64, ARY_FLAG = 128, - REARG_FLAG = 256; + REARG_FLAG = 256, + FLIP_FLAG = 512; /** Used to compose bitmasks for comparison styles. */ var UNORDERED_COMPARE_FLAG = 1, @@ -3453,6 +3454,7 @@ isCurry = bitmask & CURRY_FLAG, isCurryBound = bitmask & CURRY_BOUND_FLAG, isCurryRight = bitmask & CURRY_RIGHT_FLAG, + isFlip = bitmask & FLIP_FLAG, Ctor = isBindKey ? undefined : createCtorWrapper(func); function wrapper() { @@ -3505,6 +3507,8 @@ if (argPos) { args = reorder(args, argPos); + } else if (isFlip) { + args.reverse(); } if (isAry && ary < args.length) { args.length = ary; @@ -7471,6 +7475,27 @@ return baseDelay(func, wait, args); }); + /** + * Creates a function that invokes `func` with arguments reversed. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to flip arguments for. + * @returns {Function} Returns the new function. + * @example + * + * var flipped = _.flip(function() { + * return _.toArray(arguments); + * }); + * + * flipped('a', 'b', 'c') + * // => ['c', 'b', 'a'] + */ + function flip(func) { + return createWrapper(func, FLIP_FLAG); + } + /** * Creates a function that returns the result of invoking the provided * functions with the `this` binding of the created function, where each @@ -11854,6 +11879,7 @@ lodash.filter = filter; lodash.flatten = flatten; lodash.flattenDeep = flattenDeep; + lodash.flip = flip; lodash.flow = flow; lodash.flowRight = flowRight; lodash.functions = functions; diff --git a/test/test.js b/test/test.js index e2b9826528..96fcd8ee5d 100644 --- a/test/test.js +++ b/test/test.js @@ -20617,6 +20617,7 @@ 'debounce', 'defer', 'delay', + 'flip', 'memoize', 'modArgs', 'modArgsSet', @@ -20740,7 +20741,7 @@ }); QUnit.test('should throw an error for falsey arguments', function(assert) { - assert.expect(24); + assert.expect(25); _.each(rejectFalsey, function(methodName) { var expected = _.map(falsey, _.constant(true)), From 7364c84b6b41886cc16d1b09f7b2ec58d9e11c80 Mon Sep 17 00:00:00 2001 From: Phillip Alexander Date: Tue, 8 Sep 2015 20:53:09 -0700 Subject: [PATCH 286/935] Add Node.js v4 stable to Travis config. NodeJS v4 was just released [NodeJS v4 announcement](https://nodejs.org/en/blog/release/v4.0.0/). This updates the CI build script to accommodate the release. Note: It should be "4", not "4.0" since Node will surely get a lot of minor updates before it goes LTS and reveal.js should test on the latest of them. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index dfc74c545b..12fce33270 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ language: node_js node_js: - "0.12" + - "4" env: global: - PATTERN1="s|\s*if\s*\(isHostObject\b[\s\S]+?\}(?=\n)||" From 6b09f1f233172eeff0643213f4ad846a5b74edd4 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Tue, 8 Sep 2015 22:51:46 -0700 Subject: [PATCH 287/935] Remove iojs from travis-yml tests. --- .travis.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 12fce33270..a3cbe3162c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: node_js node_js: - - "0.12" - "4" env: global: @@ -18,13 +17,13 @@ env: # - BIN="ringo" OPTION="-o -1" matrix: include: - - node_js: "iojs" - env: - node_js: "0.8" env: NPM_VERSION="~1.4.0" - node_js: "0.10" env: - node_js: "0.12" + env: + - node_js: "4" env: SAUCE_LABS=true git: depth: 10 From 4d7aeb8b964ec488611cf9a7aa80dce83313da10 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Wed, 9 Sep 2015 08:31:03 -0700 Subject: [PATCH 288/935] Don't flip if there's less than 2 arguments. --- lodash.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lodash.js b/lodash.js index 724469099a..1d6f02e824 100644 --- a/lodash.js +++ b/lodash.js @@ -3507,7 +3507,7 @@ if (argPos) { args = reorder(args, argPos); - } else if (isFlip) { + } else if (isFlip && args.length > 1) { args.reverse(); } if (isAry && ary < args.length) { From 0a08edb6d744c68997413e045cf97f60635c3906 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Wed, 9 Sep 2015 08:31:19 -0700 Subject: [PATCH 289/935] Remove second `_.rearg` example. [ci skip] --- lodash.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lodash.js b/lodash.js index 1d6f02e824..f97eefd634 100644 --- a/lodash.js +++ b/lodash.js @@ -7823,12 +7823,6 @@ * * rearged('b', 'c', 'a') * // => ['a', 'b', 'c'] - * - * var map = _.rearg(_.map, [1, 0]); - * map(function(n) { - * return n * 3; - * }, [1, 2, 3]); - * // => [3, 6, 9] */ var rearg = restParam(function(func, indexes) { return createWrapper(func, REARG_FLAG, undefined, undefined, undefined, baseFlatten(indexes)); From c604be31e0dbc07ecd2b40c347ccfc6816a7431c Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Wed, 9 Sep 2015 08:31:28 -0700 Subject: [PATCH 290/935] Add `_.flip` test. --- test/test.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/test.js b/test/test.js index 96fcd8ee5d..496e4a772e 100644 --- a/test/test.js +++ b/test/test.js @@ -4663,6 +4663,23 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.flip'); + + (function() { + function fn() { + return slice.call(arguments); + } + + QUnit.test('should flip arguments provided to `func`', function(assert) { + assert.expect(1); + + var flipped = _.flip(fn); + assert.deepEqual(flipped('a', 'b', 'c'), ['c', 'b', 'a']); + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.take'); (function() { From c32a6837e6d72ca3829549897ee8534ebb7c7b0c Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Wed, 9 Sep 2015 10:29:43 -0700 Subject: [PATCH 291/935] Update `_.flip` doc example and test to better show effect. --- lodash.js | 4 ++-- test/test.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lodash.js b/lodash.js index f97eefd634..958a401b47 100644 --- a/lodash.js +++ b/lodash.js @@ -7489,8 +7489,8 @@ * return _.toArray(arguments); * }); * - * flipped('a', 'b', 'c') - * // => ['c', 'b', 'a'] + * flipped('a', 'b', 'c', 'd'); + * // => ['d', 'c', 'b', 'a'] */ function flip(func) { return createWrapper(func, FLIP_FLAG); diff --git a/test/test.js b/test/test.js index 496e4a772e..a9c052627a 100644 --- a/test/test.js +++ b/test/test.js @@ -4674,7 +4674,7 @@ assert.expect(1); var flipped = _.flip(fn); - assert.deepEqual(flipped('a', 'b', 'c'), ['c', 'b', 'a']); + assert.deepEqual(flipped('a', 'b', 'c', 'd'), ['d', 'c', 'b', 'a']); }); }()); From d77c5123c17c5e6d1968db0f5c0d444c8ba10617 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Wed, 9 Sep 2015 10:34:50 -0700 Subject: [PATCH 292/935] Add `_.flip` and `_.modArgsSet` to `lodash` doc note. [ci skip] --- lodash.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/lodash.js b/lodash.js index 958a401b47..179bec8367 100644 --- a/lodash.js +++ b/lodash.js @@ -1412,20 +1412,20 @@ * `countBy`, `create`, `curry`, `debounce`, `defaults`, `defaultsDeep`, * `defer`, `delay`, `difference`, `drop`, `dropRight`, `dropRightWhile`, * `dropWhile`, `extend`, `extendWith`, `fill`, `filter`, `flatten`, - * `flattenDeep`, `flow`, `flowRight`, `forEach`, `forEachRight`, `forIn`, - * `forInRight`, `forOwn`, `forOwnRight`, `functions`, `groupBy`, `initial`, - * `intersection`, `invert`, `invoke`, `iteratee`, `keyBy`, `keys`, `keysIn`, - * `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`, `memoize`, - * `merge`, `mergeWith` `method`, `methodOf`, `mixin`, `modArgs`, `negate`, - * `omit`, `omitBy`, `once`, `pairs`, `partial`, `partialRight`, `partition`, - * `pick`, `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAt`, - * `push`, `range`, `rearg`, `reject`, `remove`, `rest`, `restParam`, `reverse`, - * `set`, `setWith`, `shuffle`, `slice`, `sort`, `sortBy`, `sortByOrder`, - * `splice`, `spread`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, - * `tap`, `throttle`, `thru`, `times`, `toArray`, `toPath`, `toPlainObject`, - * `transform`, `union`, `uniq`, `uniqBy`, `unset`, `unshift`, `unzip`, - * `unzipWith`, `values`, `valuesIn`, `without`, `wrap`, `xor`, `zip`, - * `zipObject`, and `zipWith` + * `flattenDeep`, `flip`, `flow`, `flowRight`, `forEach`, `forEachRight`, + * `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `functions`, `groupBy`, + * `initial`, `intersection`, `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`, `pullAt`, `push`, `range`, `rearg`, `reject`, + * `remove`, `rest`, `restParam`, `reverse`, `set`, `setWith`, `shuffle`, + * `slice`, `sort`, `sortBy`, `sortByOrder`, `splice`, `spread`, `take`, + * `takeRight`, `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, + * `times`, `toArray`, `toPath`, `toPlainObject`, `transform`, `union`, `uniq`, + * `uniqBy`, `unset`, `unshift`, `unzip`, `unzipWith`, `values`, `valuesIn`, + * `without`, `wrap`, `xor`, `zip`, `zipObject`, and `zipWith` * * The wrapper methods that are **not** chainable by default are: * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clone`, `cloneDeep`, From 20695548f1f25f2189766818a7805229fccc9401 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Wed, 9 Sep 2015 18:05:48 -0700 Subject: [PATCH 293/935] Use more pre-QUnit 2.0 APIs. --- test/test.js | 306 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 184 insertions(+), 122 deletions(-) diff --git a/test/test.js b/test/test.js index a9c052627a..69d833fde7 100644 --- a/test/test.js +++ b/test/test.js @@ -577,9 +577,11 @@ } }); - QUnit.asyncTest('should support loading ' + basename + ' in a web worker', function(assert) { + QUnit.test('should support loading ' + basename + ' in a web worker', function(assert) { assert.expect(1); + var done = assert.async(); + if (Worker) { var limit = 30000 / QUnit.config.asyncRetries, start = +new Date; @@ -591,14 +593,14 @@ return; } assert.strictEqual(actual, _.VERSION); - QUnit.start(); + done(); }; attempt(); } else { skipTest(assert); - QUnit.start(); + done(); } }); @@ -2983,8 +2985,10 @@ QUnit.module('lodash.debounce'); (function() { - QUnit.asyncTest('should debounce a function', function(assert) { - assert.expect(2); + QUnit.test('should debounce a function', function(assert) { + assert.expect(2); + + var done = assert.async(); if (!(isRhino && isModularize)) { var callCount = 0, @@ -2998,17 +3002,19 @@ setTimeout(function() { assert.strictEqual(callCount, 1); - QUnit.start(); + done(); }, 96); } else { skipTest(assert, 2); - QUnit.start(); + done(); } }); - QUnit.asyncTest('subsequent debounced calls return the last `func` result', function(assert) { - assert.expect(2); + QUnit.test('subsequent debounced calls return the last `func` result', function(assert) { + assert.expect(2); + + var done = assert.async(); if (!(isRhino && isModularize)) { var debounced = _.debounce(_.identity, 32); @@ -3020,17 +3026,19 @@ setTimeout(function() { assert.notEqual(debounced('z'), 'z'); - QUnit.start(); + done(); }, 128); } else { skipTest(assert, 2); - QUnit.start(); + done(); } }); - QUnit.asyncTest('subsequent "immediate" debounced calls return the last `func` result', function(assert) { - assert.expect(2); + QUnit.test('subsequent "immediate" debounced calls return the last `func` result', function(assert) { + assert.expect(2); + + var done = assert.async(); if (!(isRhino && isModularize)) { var debounced = _.debounce(_.identity, 32, { 'leading': true, 'trailing': false }), @@ -3041,17 +3049,19 @@ setTimeout(function() { var result = [debounced('a'), debounced('b')]; assert.deepEqual(result, ['a', 'a']); - QUnit.start(); + done(); }, 64); } else { skipTest(assert, 2); - QUnit.start(); + done(); } }); - QUnit.asyncTest('should apply default options', function(assert) { - assert.expect(2); + QUnit.test('should apply default options', function(assert) { + assert.expect(2); + + var done = assert.async(); if (!(isRhino && isModularize)) { var callCount = 0; @@ -3065,17 +3075,19 @@ setTimeout(function() { assert.strictEqual(callCount, 1); - QUnit.start(); + done(); }, 64); } else { skipTest(assert, 2); - QUnit.start(); + done(); } }); - QUnit.asyncTest('should support a `leading` option', function(assert) { - assert.expect(5); + QUnit.test('should support a `leading` option', function(assert) { + assert.expect(5); + + var done = assert.async(); if (!(isRhino && isModularize)) { var callCounts = [0, 0]; @@ -3105,17 +3117,19 @@ withLeading('x'); assert.strictEqual(callCounts[0], 2); - QUnit.start(); + done(); }, 64); } else { skipTest(assert, 5); - QUnit.start(); + done(); } }); - QUnit.asyncTest('should support a `trailing` option', function(assert) { - assert.expect(4); + QUnit.test('should support a `trailing` option', function(assert) { + assert.expect(4); + + var done = assert.async(); if (!(isRhino && isModularize)) { var withCount = 0, @@ -3137,17 +3151,19 @@ setTimeout(function() { assert.strictEqual(withCount, 1); assert.strictEqual(withoutCount, 0); - QUnit.start(); + done(); }, 64); } else { skipTest(assert, 4); - QUnit.start(); + done(); } }); - QUnit.asyncTest('should support a `maxWait` option', function(assert) { - assert.expect(1); + QUnit.test('should support a `maxWait` option', function(assert) { + assert.expect(1); + + var done = assert.async(); if (!(isRhino && isModularize)) { var limit = (argv || isPhantom) ? 1000 : 320, @@ -3171,17 +3187,19 @@ setTimeout(function() { assert.deepEqual(actual, [true, false]); - QUnit.start(); + done(); }, 1); } else { skipTest(assert); - QUnit.start(); + done(); } }); - QUnit.asyncTest('should cancel `maxDelayed` when `delayed` is invoked', function(assert) { - assert.expect(1); + QUnit.test('should cancel `maxDelayed` when `delayed` is invoked', function(assert) { + assert.expect(1); + + var done = assert.async(); if (!(isRhino && isModularize)) { var callCount = 0; @@ -3194,17 +3212,19 @@ setTimeout(function() { assert.strictEqual(callCount, 1); - QUnit.start(); + done(); }, 128); } else { skipTest(assert); - QUnit.start(); + done(); } }); - QUnit.asyncTest('should invoke the `trailing` call with the correct arguments and `this` binding', function(assert) { - assert.expect(2); + QUnit.test('should invoke the `trailing` call with the correct arguments and `this` binding', function(assert) { + assert.expect(2); + + var done = assert.async(); if (!(isRhino && isModularize)) { var actual, @@ -3225,12 +3245,12 @@ setTimeout(function() { assert.strictEqual(callCount, 2); assert.deepEqual(actual, [object, 'a']); - QUnit.start(); + done(); }, 64); } else { skipTest(assert, 2); - QUnit.start(); + done(); } }); }()); @@ -3379,8 +3399,10 @@ QUnit.module('lodash.defer'); (function() { - QUnit.asyncTest('should defer `func` execution', function(assert) { - assert.expect(1); + QUnit.test('should defer `func` execution', function(assert) { + assert.expect(1); + + var done = assert.async(); if (!(isRhino && isModularize)) { var pass = false; @@ -3388,17 +3410,19 @@ setTimeout(function() { assert.ok(pass); - QUnit.start(); + done(); }, 32); } else { skipTest(assert); - QUnit.start(); + done(); } }); - QUnit.asyncTest('should provide additional arguments to `func`', function(assert) { - assert.expect(1); + QUnit.test('should provide additional arguments to `func`', function(assert) { + assert.expect(1); + + var done = assert.async(); if (!(isRhino && isModularize)) { var args; @@ -3409,17 +3433,19 @@ setTimeout(function() { assert.deepEqual(args, [1, 2]); - QUnit.start(); + done(); }, 32); } else { skipTest(assert); - QUnit.start(); + done(); } }); - QUnit.asyncTest('should be cancelable', function(assert) { - assert.expect(1); + QUnit.test('should be cancelable', function(assert) { + assert.expect(1); + + var done = assert.async(); if (!(isRhino && isModularize)) { var pass = true; @@ -3432,12 +3458,12 @@ setTimeout(function() { assert.ok(pass); - QUnit.start(); + done(); }, 32); } else { skipTest(assert); - QUnit.start(); + done(); } }); }()); @@ -3447,8 +3473,10 @@ QUnit.module('lodash.delay'); (function() { - QUnit.asyncTest('should delay `func` execution', function(assert) { - assert.expect(2); + QUnit.test('should delay `func` execution', function(assert) { + assert.expect(2); + + var done = assert.async(); if (!(isRhino && isModularize)) { var pass = false; @@ -3460,17 +3488,19 @@ setTimeout(function() { assert.ok(pass); - QUnit.start(); + done(); }, 64); } else { skipTest(assert, 2); - QUnit.start(); + done(); } }); - QUnit.asyncTest('should provide additional arguments to `func`', function(assert) { - assert.expect(1); + QUnit.test('should provide additional arguments to `func`', function(assert) { + assert.expect(1); + + var done = assert.async(); if (!(isRhino && isModularize)) { var args; @@ -3481,17 +3511,19 @@ setTimeout(function() { assert.deepEqual(args, [1, 2]); - QUnit.start(); + done(); }, 64); } else { skipTest(assert); - QUnit.start(); + done(); } }); - QUnit.asyncTest('should be cancelable', function(assert) { - assert.expect(1); + QUnit.test('should be cancelable', function(assert) { + assert.expect(1); + + var done = assert.async(); if (!(isRhino && isModularize)) { var pass = true; @@ -3504,12 +3536,12 @@ setTimeout(function() { assert.ok(pass); - QUnit.start(); + done(); }, 64); } else { skipTest(assert); - QUnit.start(); + done(); } }); }()); @@ -13163,8 +13195,10 @@ QUnit.module('lodash.now'); (function() { - QUnit.asyncTest('should return the number of milliseconds that have elapsed since the Unix epoch', function(assert) { - assert.expect(2); + QUnit.test('should return the number of milliseconds that have elapsed since the Unix epoch', function(assert) { + assert.expect(2); + + var done = assert.async(); var stamp = +new Date, actual = _.now(); @@ -13174,12 +13208,12 @@ if (!(isRhino && isModularize)) { setTimeout(function() { assert.ok(_.now() > actual); - QUnit.start(); + done(); }, 32); } else { skipTest(assert); - QUnit.start(); + done(); } }); }()); @@ -17735,8 +17769,10 @@ QUnit.module('lodash.throttle'); (function() { - QUnit.asyncTest('should throttle a function', function(assert) { - assert.expect(2); + QUnit.test('should throttle a function', function(assert) { + assert.expect(2); + + var done = assert.async(); if (!(isRhino && isModularize)) { var callCount = 0, @@ -17751,17 +17787,19 @@ setTimeout(function() { assert.ok(callCount > lastCount); - QUnit.start(); + done(); }, 64); } else { skipTest(assert, 2); - QUnit.start(); + done(); } }); - QUnit.asyncTest('subsequent calls should return the result of the first call', function(assert) { - assert.expect(5); + QUnit.test('subsequent calls should return the result of the first call', function(assert) { + assert.expect(5); + + var done = assert.async(); if (!(isRhino && isModularize)) { var throttled = _.throttle(_.identity, 32), @@ -17776,17 +17814,19 @@ assert.notEqual(result[1], 'y'); assert.notStrictEqual(result[1], undefined); - QUnit.start(); + done(); }, 64); } else { skipTest(assert, 5); - QUnit.start(); + done(); } }); - QUnit.asyncTest('should clear timeout when `func` is called', function(assert) { - assert.expect(1); + QUnit.test('should clear timeout when `func` is called', function(assert) { + assert.expect(1); + + var done = assert.async(); if (!isModularize) { var callCount = 0, @@ -17814,17 +17854,19 @@ setTimeout(function() { assert.strictEqual(callCount, 2); - QUnit.start(); + done(); }, 64); } else { skipTest(assert); - QUnit.start(); + done(); } }); - QUnit.asyncTest('should not trigger a trailing call when invoked once', function(assert) { - assert.expect(2); + QUnit.test('should not trigger a trailing call when invoked once', function(assert) { + assert.expect(2); + + var done = assert.async(); if (!(isRhino && isModularize)) { var callCount = 0, @@ -17835,19 +17877,21 @@ setTimeout(function() { assert.strictEqual(callCount, 1); - QUnit.start(); + done(); }, 64); } else { skipTest(assert, 2); - QUnit.start(); + done(); } }); _.times(2, function(index) { - QUnit.asyncTest('should trigger a call when invoked repeatedly' + (index ? ' and `leading` is `false`' : ''), function(assert) { + QUnit.test('should trigger a call when invoked repeatedly' + (index ? ' and `leading` is `false`' : ''), function(assert) { assert.expect(1); + var done = assert.async(); + if (!(isRhino && isModularize)) { var callCount = 0, limit = (argv || isPhantom) ? 1000 : 320, @@ -17865,18 +17909,20 @@ setTimeout(function() { assert.ok(actual); - QUnit.start(); + done(); }, 1); } else { skipTest(assert); - QUnit.start(); + done(); } }); }); - QUnit.asyncTest('should apply default options', function(assert) { - assert.expect(3); + QUnit.test('should apply default options', function(assert) { + assert.expect(3); + + var done = assert.async(); if (!(isRhino && isModularize)) { var callCount = 0; @@ -17891,12 +17937,12 @@ setTimeout(function() { assert.strictEqual(callCount, 2); - QUnit.start(); + done(); }, 128); } else { skipTest(assert, 3); - QUnit.start(); + done(); } }); @@ -17915,8 +17961,10 @@ } }); - QUnit.asyncTest('should support a `trailing` option', function(assert) { - assert.expect(6); + QUnit.test('should support a `trailing` option', function(assert) { + assert.expect(6); + + var done = assert.async(); if (!(isRhino && isModularize)) { var withCount = 0, @@ -17941,17 +17989,19 @@ setTimeout(function() { assert.strictEqual(withCount, 2); assert.strictEqual(withoutCount, 1); - QUnit.start(); + done(); }, 256); } else { skipTest(assert, 6); - QUnit.start(); + done(); } }); - QUnit.asyncTest('should not update `lastCalled`, at the end of the timeout, when `trailing` is `false`', function(assert) { - assert.expect(1); + QUnit.test('should not update `lastCalled`, at the end of the timeout, when `trailing` is `false`', function(assert) { + assert.expect(1); + + var done = assert.async(); if (!(isRhino && isModularize)) { var callCount = 0; @@ -17970,12 +18020,12 @@ setTimeout(function() { assert.ok(callCount > 1); - QUnit.start(); + done(); }, 192); } else { skipTest(assert); - QUnit.start(); + done(); } }); }()); @@ -18001,8 +18051,10 @@ assert.ok(pass); }); - QUnit.asyncTest('_.' + methodName + ' should have a default `wait` of `0`', function(assert) { - assert.expect(1); + QUnit.test('_.' + methodName + ' should have a default `wait` of `0`', function(assert) { + assert.expect(1); + + var done = assert.async(); if (!(isRhino && isModularize)) { var callCount = 0; @@ -18016,17 +18068,19 @@ setTimeout(function() { funced(); assert.strictEqual(callCount, isDebounce ? 1 : 2); - QUnit.start(); + done(); }, 32); } else { skipTest(assert); - QUnit.start(); + done(); } }); - QUnit.asyncTest('_.' + methodName + ' should invoke `func` with the correct `this` binding', function(assert) { - assert.expect(1); + QUnit.test('_.' + methodName + ' should invoke `func` with the correct `this` binding', function(assert) { + assert.expect(1); + + var done = assert.async(); if (!(isRhino && isModularize)) { var object = { @@ -18042,17 +18096,19 @@ } setTimeout(function() { assert.deepEqual(actual, expected); - QUnit.start(); + done(); }, 64); } else { skipTest(assert); - QUnit.start(); + done(); } }); - QUnit.asyncTest('_.' + methodName + ' supports recursive calls', function(assert) { - assert.expect(2); + QUnit.test('_.' + methodName + ' supports recursive calls', function(assert) { + assert.expect(2); + + var done = assert.async(); if (!(isRhino && isModularize)) { var actual = [], @@ -18077,17 +18133,19 @@ setTimeout(function() { assert.deepEqual(actual, expected.slice(0, actual.length)); - QUnit.start(); + done(); }, 256); } else { skipTest(assert, 2); - QUnit.start(); + done(); } }); - QUnit.asyncTest('_.' + methodName + ' should work if the system time is set backwards', function(assert) { - assert.expect(1); + QUnit.test('_.' + methodName + ' should work if the system time is set backwards', function(assert) { + assert.expect(1); + + var done = assert.async(); if (!isModularize) { var callCount = 0, @@ -18114,17 +18172,19 @@ setTimeout(function() { funced(); assert.strictEqual(callCount, isDebounce ? 1 : 2); - QUnit.start(); + done(); }, 64); } else { skipTest(assert); - QUnit.start(); + done(); } }); - QUnit.asyncTest('_.' + methodName + ' should support cancelling delayed calls', function(assert) { - assert.expect(1); + QUnit.test('_.' + methodName + ' should support cancelling delayed calls', function(assert) { + assert.expect(1); + + var done = assert.async(); if (!(isRhino && isModularize)) { var callCount = 0; @@ -18138,17 +18198,19 @@ setTimeout(function() { assert.strictEqual(callCount, 0); - QUnit.start(); + done(); }, 64); } else { skipTest(assert); - QUnit.start(); + done(); } }); - QUnit.asyncTest('_.' + methodName + ' should reset `lastCalled` after cancelling', function(assert) { - assert.expect(3); + QUnit.test('_.' + methodName + ' should reset `lastCalled` after cancelling', function(assert) { + assert.expect(3); + + var done = assert.async(); if (!(isRhino && isModularize)) { var callCount = 0; @@ -18163,12 +18225,12 @@ setTimeout(function() { assert.strictEqual(callCount, 2); - QUnit.start(); + done(); }, 64); } else { skipTest(assert, 3); - QUnit.start(); + done(); } }); }); From 012cc521f50ac5d855752d0ce64c2d546bae0c6c Mon Sep 17 00:00:00 2001 From: Ilya Mochalov Date: Thu, 10 Sep 2015 04:32:16 +0500 Subject: [PATCH 294/935] Minor `_.plant` doc fix. [ci skip] --- lodash.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lodash.js b/lodash.js index 179bec8367..5f320945c4 100644 --- a/lodash.js +++ b/lodash.js @@ -6025,6 +6025,7 @@ * @name plant * @memberOf _ * @category Chain + * @param {*} value The value to plant. * @returns {Object} Returns the new `lodash` wrapper instance. * @example * From 9b41ae847b010210ea48506d4ac709b86bdae17f Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Wed, 9 Sep 2015 20:44:58 -0700 Subject: [PATCH 295/935] Consolidate `this` binding tests. --- test/test.js | 96 +++++++++++++++++++--------------------------------- 1 file changed, 35 insertions(+), 61 deletions(-) diff --git a/test/test.js b/test/test.js index 69d833fde7..6d2d16af6c 100644 --- a/test/test.js +++ b/test/test.js @@ -11857,18 +11857,6 @@ assert.deepEqual(actual, expected); }); - QUnit.test('should not set a `this` binding', function(assert) { - assert.expect(2); - - var memoized = _.memoize(function(a, b, c) { - return a + this.b + this.c; - }); - - var object = { 'b': 2, 'c': 3, 'memoized': memoized }; - assert.strictEqual(object.memoized(1), 6); - assert.strictEqual(object.memoized(2), 7); - }); - QUnit.test('should check cache for own properties', function(assert) { assert.expect(1); @@ -13345,17 +13333,6 @@ assert.strictEqual(count, 1); }); - QUnit.test('should not set a `this` binding', function(assert) { - assert.expect(2); - - var once = _.once(function() { return ++this.count; }), - object = { 'count': 0, 'once': once }; - - object.once(); - assert.strictEqual(object.once(), 1); - assert.strictEqual(object.count, 1); - }); - QUnit.test('should ignore recursive calls', function(assert) { assert.expect(2); @@ -13705,22 +13682,6 @@ } }); - QUnit.test('`_.' + methodName + '` should not set a `this` binding', function(assert) { - assert.expect(3); - - var fn = function() { return this.a; }, - object = { 'a': 1 }; - - var par = func(_.bind(fn, object)); - assert.strictEqual(par(), object.a); - - par = _.bind(func(fn), object); - assert.strictEqual(par(), object.a); - - object.par = func(fn); - assert.strictEqual(object.par(), object.a); - }); - QUnit.test('`_.' + methodName + '` creates a function with a `length` of `0`', function(assert) { assert.expect(1); @@ -15694,17 +15655,6 @@ assert.deepEqual(rp(1, 2, 3, 4, 5), [1, 2, 3, [4, 5]]); }); - - QUnit.test('should not set a `this` binding', function(assert) { - assert.expect(1); - - var rp = _.restParam(function(x, y) { - return this[x] + this[y[0]]; - }); - - var object = { 'rp': rp, 'x': 4, 'y': 2 }; - assert.strictEqual(object.rp('x', 'y'), 6); - }); }()); /*--------------------------------------------------------------------------*/ @@ -16960,17 +16910,6 @@ spread([4, 2], 'ignored'); assert.deepEqual(args, [4, 2]); }); - - QUnit.test('should not set a `this` binding', function(assert) { - assert.expect(1); - - var spread = _.spread(function(x, y) { - return this[x] + this[y]; - }); - - var object = { 'spread': spread, 'x': 4, 'y': 2 }; - assert.strictEqual(object.spread(['x', 'y']), 6); - }); }()); /*--------------------------------------------------------------------------*/ @@ -20710,6 +20649,20 @@ 'throttle' ]; + var noBinding = [ + 'flip', + 'memoize', + 'modArgs', + 'modArgsSet', + 'negate', + 'once', + 'partial', + 'partialRight', + 'rearg', + 'restParam', + 'spread' + ]; + var rejectFalsey = [ 'flow', 'flowRight', @@ -20843,6 +20796,27 @@ }); }); + QUnit.test('should not set a `this` binding', function(assert) { + assert.expect(33); + + _.each(noBinding, function(methodName) { + var fn = function() { return this.a; }, + func = _[methodName], + isNegate = methodName == 'negate', + object = { 'a': 1 }, + expected = isNegate ? false : 1; + + var wrapper = func(_.bind(fn, object)); + assert.strictEqual(wrapper(), expected, '`_.' + methodName + '` can consume a bound function'); + + wrapper = _.bind(func(fn), object); + assert.strictEqual(wrapper(), expected, '`_.' + methodName + '` can be bound'); + + object.wrapper = func(fn); + assert.strictEqual(object.wrapper(), expected, '`_.' + methodName + '` uses the `this` of its parent object'); + }); + }); + QUnit.test('should not contain minified method names (test production builds)', function(assert) { assert.expect(1); From 86d06e0a4c3b028540302a4dfc5429ce9eec6d96 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Wed, 9 Sep 2015 22:09:10 -0700 Subject: [PATCH 296/935] Cleanup `_.merge` tests. --- test/test.js | 160 +++++++++++++++++++++++++-------------------------- 1 file changed, 80 insertions(+), 80 deletions(-) diff --git a/test/test.js b/test/test.js index 6d2d16af6c..a3c78eb4b6 100644 --- a/test/test.js +++ b/test/test.js @@ -12100,38 +12100,65 @@ assert.ok(actual.bar.b === actual.foo.b && actual.foo.b.c.d === actual.foo.b.c.d.foo.b.c.d); }); - QUnit.test('should treat sources that are sparse arrays as dense', function(assert) { + QUnit.test('should work with four arguments', function(assert) { + assert.expect(1); + + var expected = { 'a': 4 }, + actual = _.merge({ 'a': 1 }, { 'a': 2 }, { 'a': 3 }, expected); + + assert.deepEqual(actual, expected); + }); + + QUnit.test('should work with a function for `object`', function(assert) { assert.expect(2); - var array = Array(3); - array[0] = 1; - array[2] = 3; + function Foo() {} - var actual = _.merge([], array), - expected = array.slice(); + var source = { 'a': 1 }, + actual = _.merge(Foo, source); - expected[1] = undefined; + assert.strictEqual(actual, Foo); + assert.strictEqual(Foo.a, 1); + }); - assert.ok('1' in actual); - assert.deepEqual(actual, expected); + QUnit.test('should work with a non-plain `object`', function(assert) { + assert.expect(2); + + function Foo() {} + + var object = new Foo, + source = { 'a': 1 }, + actual = _.merge(object, source); + + assert.strictEqual(actual, object); + assert.strictEqual(object.a, 1); }); - QUnit.test('should skip `undefined` values in arrays if a destination value exists', function(assert) { + QUnit.test('should pass thru primitive `object` values', function(assert) { + assert.expect(1); + + var values = [true, 1, '1']; + + var actual = _.map(values, function(value) { + return _.merge(value, { 'a': 1 }); + }); + + assert.deepEqual(actual, values); + }); + + QUnit.test('should treat sparse array sources as dense', function(assert) { assert.expect(2); var array = Array(3); array[0] = 1; array[2] = 3; - var actual = _.merge([4, 5, 6], array), - expected = [1, 5, 3]; - - assert.deepEqual(actual, expected); + var actual = _.merge([], array), + expected = array.slice(); - array = [1, , 3]; - array[1] = undefined; + expected[1] = undefined; - actual = _.merge([4, 5, 6], array); + assert.ok('1' in actual); assert.deepEqual(actual, expected); }); @@ -12198,15 +12225,6 @@ assert.deepEqual(actual, expected); }); - QUnit.test('should work with four arguments', function(assert) { - assert.expect(1); - - var expected = { 'a': 4 }, - actual = _.merge({ 'a': 1 }, { 'a': 2 }, { 'a': 3 }, expected); - - assert.deepEqual(actual, expected); - }); - QUnit.test('should assign `null` values', function(assert) { assert.expect(1); @@ -12214,30 +12232,6 @@ assert.strictEqual(actual.a, null); }); - QUnit.test('should not assign `undefined` values', function(assert) { - assert.expect(1); - - var actual = _.merge({ 'a': 1 }, { 'a': undefined, 'b': undefined }); - assert.deepEqual(actual, { 'a': 1 }); - }); - - QUnit.test('should not error on DOM elements', function(assert) { - assert.expect(1); - - var object1 = { 'el': document && document.createElement('div') }, - object2 = { 'el': document && document.createElement('div') }, - pairs = [[{}, object1], [object1, object2]], - expected = _.map(pairs, _.constant(true)); - - var actual = _.map(pairs, function(pair) { - try { - return _.merge(pair[0], pair[1]).el === pair[1].el; - } catch (e) {} - }); - - assert.deepEqual(actual, expected); - }); - QUnit.test('should assign non array/plain-object values directly', function(assert) { assert.expect(1); @@ -12273,6 +12267,32 @@ assert.deepEqual(actual, [new Foo(object)]); }); + QUnit.test('should not assign `undefined` values', function(assert) { + assert.expect(1); + + var actual = _.merge({ 'a': 1 }, { 'a': undefined, 'b': undefined }); + assert.deepEqual(actual, { 'a': 1 }); + }); + + QUnit.test('should skip `undefined` values in `source` arrays if a destination value exists', function(assert) { + assert.expect(2); + + var array = Array(3); + array[0] = 1; + array[2] = 3; + + var actual = _.merge([4, 5, 6], array), + expected = [1, 5, 3]; + + assert.deepEqual(actual, expected); + + array = [1, , 3]; + array[1] = undefined; + + actual = _.merge([4, 5, 6], array); + assert.deepEqual(actual, expected); + }); + QUnit.test('should convert values to arrays when merging with arrays of `source`', function(assert) { assert.expect(2); @@ -12294,41 +12314,21 @@ assert.deepEqual(actual, { 'a': ['x', 'y', 'z'] }); }); - QUnit.test('should work with a function for `object`', function(assert) { - assert.expect(2); - - function Foo() {} - - var source = { 'a': 1 }, - actual = _.merge(Foo, source); - - assert.strictEqual(actual, Foo); - assert.strictEqual(Foo.a, 1); - }); - - QUnit.test('should work with a non-plain `object` value', function(assert) { - assert.expect(2); - - function Foo() {} - - var object = new Foo, - source = { 'a': 1 }, - actual = _.merge(object, source); - - assert.strictEqual(actual, object); - assert.strictEqual(object.a, 1); - }); - - QUnit.test('should pass thru primitive `object` values', function(assert) { + QUnit.test('should not error on DOM elements', function(assert) { assert.expect(1); - var values = [true, 1, '1']; + var object1 = { 'el': document && document.createElement('div') }, + object2 = { 'el': document && document.createElement('div') }, + pairs = [[{}, object1], [object1, object2]], + expected = _.map(pairs, _.constant(true)); - var actual = _.map(values, function(value) { - return _.merge(value, { 'a': 1 }); + var actual = _.map(pairs, function(pair) { + try { + return _.merge(pair[0], pair[1]).el === pair[1].el; + } catch (e) {} }); - assert.deepEqual(actual, values); + assert.deepEqual(actual, expected); }); }(1, 2, 3)); From 4a4e54479a6eecd916a0e39d400c54bcbba51c31 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Wed, 9 Sep 2015 22:10:08 -0700 Subject: [PATCH 297/935] Ensure `_.merge` assigns typed arrays directly. [closes #1453] --- lodash.js | 2 +- test/test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lodash.js b/lodash.js index 5f320945c4..c149ccbbfc 100644 --- a/lodash.js +++ b/lodash.js @@ -2584,7 +2584,7 @@ if (isArray(srcValue) || isTypedArray(srcValue)) { newValue = isArray(oldValue) ? oldValue - : ((isObject(oldValue) && isArrayLike(oldValue)) ? copyArray(oldValue) : []); + : ((isObject(oldValue) && isArrayLike(oldValue)) ? copyArray(oldValue) : srcValue); } else if (isPlainObject(srcValue) || isArguments(srcValue)) { newValue = isArguments(oldValue) diff --git a/test/test.js b/test/test.js index a3c78eb4b6..e6292e8865 100644 --- a/test/test.js +++ b/test/test.js @@ -12237,7 +12237,7 @@ function Foo() {} - var values = [new Foo, new Boolean, new Date, Foo, new Number, new String, new RegExp], + var values = [new Foo, new Boolean, new Date, Foo, new Number, new String, new RegExp, new (Uint8Array || noop)], expected = _.map(values, _.constant(true)); var actual = _.map(values, function(value) { From a48f48ca95f85f3d25d11dda3531882acedc2922 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Wed, 9 Sep 2015 22:56:24 -0700 Subject: [PATCH 298/935] Ensure `_.merge` skips merging when `object` and `source` are the same value. --- lodash.js | 3 +++ test/test.js | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/lodash.js b/lodash.js index c149ccbbfc..0af9883e6f 100644 --- a/lodash.js +++ b/lodash.js @@ -2529,6 +2529,9 @@ * @param {Array} [stackB=[]] Associates values with source counterparts. */ function baseMerge(object, source, customizer, stackA, stackB) { + if (object === source) { + return; + } var props = (isArray(source) || isTypedArray(source)) ? undefined : keysIn(source); arrayEach(props || source, function(srcValue, key) { if (props) { diff --git a/test/test.js b/test/test.js index e6292e8865..544ef50476 100644 --- a/test/test.js +++ b/test/test.js @@ -12293,6 +12293,28 @@ assert.deepEqual(actual, expected); }); + QUnit.test('should skip merging when `object` and `source` are the same value', function(assert) { + assert.expect(1); + + if (defineProperty) { + var object = {}, + pass = true; + + defineProperty(object, 'a', { + 'enumerable': true, + 'configurable': true, + 'get': function() { pass = false; }, + 'set': function() { pass = false; } + }); + + _.merge(object, object); + assert.ok(pass); + } + else { + skipTest(assert); + } + }); + QUnit.test('should convert values to arrays when merging with arrays of `source`', function(assert) { assert.expect(2); From e8244f7f0770d325690a2f2831d57ac73adf140e Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Wed, 9 Sep 2015 22:57:06 -0700 Subject: [PATCH 299/935] Adjust property descriptors in tests. --- test/test.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/test/test.js b/test/test.js index 544ef50476..2b0a92f979 100644 --- a/test/test.js +++ b/test/test.js @@ -195,7 +195,7 @@ /** Poison the free variable `root` in Node.js */ try { Object.defineProperty(global.root, 'root', { - 'configurable': true, + 'configurable': false, 'enumerable': false, 'get': function() { throw new ReferenceError; } }); @@ -5800,12 +5800,14 @@ pass = true; defineProperty(object, 'a', { + 'enumerable': true, + 'configurable': true, 'get': _.constant(value), 'set': function() { pass = false; } }); func(object, { 'a': value }); - assert.ok(pass, value); + assert.ok(pass); } else { skipTest(assert); @@ -16161,12 +16163,14 @@ pass = true; defineProperty(object, 'a', { + 'enumerable': true, + 'configurable': true, 'get': _.constant(value), 'set': function() { pass = false; } }); func(object, 'a', value); - assert.ok(pass, value); + assert.ok(pass); } else { skipTest(assert); @@ -19203,7 +19207,9 @@ if (!isStrict && defineProperty) { defineProperty(object, 'a', { 'configurable': false, - 'value': 1 + 'enumerable': true, + 'writable': true, + 'value': 1, }); assert.strictEqual(_.unset(object, 'a'), false); } From 94c95469e15cb15477d6cafd050a601cad13e36f Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Wed, 9 Sep 2015 22:58:04 -0700 Subject: [PATCH 300/935] Minor test cleanup. --- test/test.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/test/test.js b/test/test.js index 2b0a92f979..3e4e04c163 100644 --- a/test/test.js +++ b/test/test.js @@ -1338,14 +1338,14 @@ var bound = _.bind(fn, null), actual = bound('a'); - assert.ok(actual[0] === null || actual[0] && actual[0].Array); + assert.ok(actual[0] === null || (actual[0] && actual[0].Array)); assert.strictEqual(actual[1], 'a'); _.times(2, function(index) { bound = index ? _.bind(fn, undefined) : _.bind(fn); actual = bound('b'); - assert.ok(actual[0] === undefined || actual[0] && actual[0].Array); + assert.ok(actual[0] === undefined || (actual[0] && actual[0].Array)); assert.strictEqual(actual[1], 'b'); }); }); @@ -4244,7 +4244,9 @@ actual = _.fill(array); assert.deepEqual(actual, Array(3)); - assert.ok(_.every(actual, function(value, index) { return index in actual; })); + assert.ok(_.every(actual, function(value, index) { + return index in actual; + })); }); QUnit.test('should work with a positive `start`', function(assert) { @@ -13194,7 +13196,7 @@ vm.runInContext(source + '\nthis.lodash = this._.noConflict()', context); assert.strictEqual(context._, expected); - assert.ok(!!context.lodash); + assert.ok(context.lodash); } else { skipTest(assert, 2); @@ -19857,7 +19859,7 @@ var array = [1, 2], wrapped = chain(array); - assert.ok(wrapped[Symbol.iterator]() === wrapped); + assert.strictEqual(wrapped[Symbol.iterator](), wrapped); assert.deepEqual(_.toArray(wrapped), array); } else { From d8c5f85cd22ec035eb18a4f76afa3d0d23c084dd Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Wed, 9 Sep 2015 23:45:37 -0700 Subject: [PATCH 301/935] Add `_.modArgsSet` tests. --- test/test.js | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/test/test.js b/test/test.js index 3e4e04c163..84fd710406 100644 --- a/test/test.js +++ b/test/test.js @@ -13058,63 +13058,66 @@ /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.modArgs'); + QUnit.module('modArgs methods'); + + _.each(['modArgs', 'modArgsSet'], function(methodName) { + var func = _[methodName], + isModArgs = methodName == 'modArgs'; - (function() { function fn() { return slice.call(arguments); } - QUnit.test('should transform each argument', function(assert) { + QUnit.test('`_.' + methodName + '` should transform each argument', function(assert) { assert.expect(1); - var modded = _.modArgs(fn, doubled, square); - assert.deepEqual(modded(5, 10), [10, 100]); + var modded = func(fn, doubled, square); + assert.deepEqual(modded(5, 10), isModArgs ? [10, 100] : [10, 25]); }); - QUnit.test('should flatten `transforms`', function(assert) { + QUnit.test('`_.' + methodName + '` should flatten `transforms`', function(assert) { assert.expect(1); - var modded = _.modArgs(fn, [doubled, square], String); - assert.deepEqual(modded(5, 10, 15), [10, 100, '15']); + var modded = func(fn, [doubled, square], String); + assert.deepEqual(modded(5, 10, 15), isModArgs ? [10, 100, '15'] : [10, 25, '5']); }); - QUnit.test('should not transform any argument greater than the number of transforms', function(assert) { + QUnit.test('`_.' + methodName + '` should not transform any argument greater than the number of transforms', function(assert) { assert.expect(1); - var modded = _.modArgs(fn, doubled, square); - assert.deepEqual(modded(5, 10, 18), [10, 100, 18]); + var modded = func(fn, doubled, square); + assert.deepEqual(modded(5, 10, 18), isModArgs ? [10, 100, 18] : [10, 25, 18]); }); - QUnit.test('should not transform any arguments if no transforms are provided', function(assert) { + QUnit.test('`_.' + methodName + '` should not transform any arguments if no transforms are provided', function(assert) { assert.expect(1); - var modded = _.modArgs(fn); + var modded = func(fn); assert.deepEqual(modded(5, 10, 18), [5, 10, 18]); }); - QUnit.test('should not pass `undefined` if there are more transforms than arguments', function(assert) { + QUnit.test('`_.' + methodName + '` should not pass `undefined` if there are more transforms than arguments', function(assert) { assert.expect(1); - var modded = _.modArgs(fn, doubled, _.identity); + var modded = func(fn, doubled, _.identity); assert.deepEqual(modded(5), [10]); }); - QUnit.test('should provide the correct argument to each transform', function(assert) { + QUnit.test('`_.' + methodName + '` should provide the correct argument to each transform', function(assert) { assert.expect(1); var argsList = [], transform = function() { argsList.push(slice.call(arguments)); }, - modded = _.modArgs(_.noop, transform, transform, transform); + modded = func(_.noop, transform, transform, transform); - modded('a', 'b', 'c'); - assert.deepEqual(argsList, [['a'], ['b'], ['c']]); + modded('a', 'b'); + assert.deepEqual(argsList, isModArgs ? [['a'], ['b']] : [['a', 'b'], ['a', 'b']]); }); - QUnit.test('should use `this` binding of function for transforms', function(assert) { + QUnit.test('`_.' + methodName + '` should use `this` binding of function for transforms', function(assert) { assert.expect(1); - var modded = _.modArgs(function(x) { + var modded = func(function(x) { return this[x]; }, function(x) { return this === x; @@ -13123,7 +13126,7 @@ var object = { 'modded': modded, 'true': 1 }; assert.strictEqual(object.modded(object), 1); }); - }()); + }); /*--------------------------------------------------------------------------*/ From 307dae4facf7e8c8952a22a09958e3cc90893c8e Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 10 Sep 2015 07:38:56 -0700 Subject: [PATCH 302/935] Adjust `_.omit` and `_.pickBy` doc examples to show more of a difference between them. [ci skip] --- lodash.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lodash.js b/lodash.js index 0af9883e6f..ba4c5669c8 100644 --- a/lodash.js +++ b/lodash.js @@ -9764,8 +9764,8 @@ * * var object = { 'user': 'fred', 'age': 40 }; * - * _.omit(object, 'age'); - * // => { 'user': 'fred' } + * _.omit(object, 'user'); + * // => { 'age': 40 } */ var omit = restParam(function(object, props) { if (object == null) { @@ -9855,8 +9855,8 @@ * * var object = { 'user': 'fred', 'age': 40 }; * - * _.pickBy(object, _.isString); - * // => { 'user': 'fred' } + * _.pickBy(object, _.isNumber); + * // => { 'age': 40 } */ function pickBy(object, predicate) { return object == null ? {} : basePickBy(object, getIteratee(predicate)); From e50734a6fb5ba768474a219175cd4d4c42a1b920 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 10 Sep 2015 19:03:53 -0700 Subject: [PATCH 303/935] Update jscs rules. --- .jscsrc | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/.jscsrc b/.jscsrc index 7cdd0fa4b3..121f5acced 100644 --- a/.jscsrc +++ b/.jscsrc @@ -25,15 +25,17 @@ "<=" ], "requireCamelCaseOrUpperCaseIdentifiers": true, - "maximumLineLength": false, + "maximumLineLength": { + "value": 180, + "allExcept": ["comments", "functionSignature", "regex"] + }, "validateIndentation": 2, + "validateQuoteMarks": { "mark": "'", "escape": true }, "disallowMultipleLineStrings": true, "disallowMixedSpacesAndTabs": true, "disallowTrailingWhitespace": true, "disallowSpaceAfterPrefixUnaryOperators": true, - "disallowMultipleVarDecl": false, - "disallowKeywordsOnNewLine": false, "requireSpaceAfterKeywords": [ "if", @@ -65,8 +67,7 @@ "disallowSpacesInAnonymousFunctionExpression": { "beforeOpeningRoundBrace": true }, - "disallowSpacesInsideObjectBrackets": false, - "disallowSpacesInsideArrayBrackets": "all", + "disallowSpacesInsideArrayBrackets": true, "disallowSpacesInsideParentheses": true, "disallowMultipleLineBreaks": true, @@ -81,8 +82,15 @@ "disallowSpacesInCallExpression": true, "disallowSpaceAfterObjectKeys": true, "requireSpaceBeforeObjectValues": true, - "requireCapitalizedConstructors": false, - "requireDotNotation": false, "requireSemicolons": true, - "validateParameterSeparator": ", " + "validateParameterSeparator": ", ", + + "jsDoc": { + "requireParamTypes": true, + "requireReturnTypes": true, + "checkTypes": true, + "checkRedundantAccess": true, + "requireNewlineAfterDescription": true, + "requireParamDescription": true + } } From 8e0011d07a10b5f9cd66569b8afdece9d57adef6 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 10 Sep 2015 19:05:25 -0700 Subject: [PATCH 304/935] Ensure clone methods create maps and sets from other realms. --- lodash.js | 92 ++++++++++++++++++++++++++++++++++------------------ test/test.js | 41 ++++++++++++++--------- 2 files changed, 86 insertions(+), 47 deletions(-) diff --git a/lodash.js b/lodash.js index ba4c5669c8..4bbc3b6fbe 100644 --- a/lodash.js +++ b/lodash.js @@ -976,28 +976,6 @@ return object; } - /** - * Creates a map from key-value `pairs`. - * - * @private - * @param {Array} pairs The key-value pairs to add. - * @returns {Object} Returns the new map. - */ - function createMap(pairs) { - return arrayReduce(pairs, addMapEntry, new Map); - } - - /** - * Creates a set from `values`. - * - * @private - * @param {Array} values The values to add. - * @returns {Object} Returns the new set. - */ - function createSet(values) { - return arrayReduce(values, addSetEntry, new Set); - } - /** * Used by `_.deburr` to convert latin-1 supplementary letters to basic latin letters. * @@ -3113,20 +3091,75 @@ } /** - * Creates a clone of the given array buffer. + * Creates a clone of `buffer`. * * @private * @param {ArrayBuffer} buffer The array buffer to clone. * @returns {ArrayBuffer} Returns the cloned array buffer. */ function cloneBuffer(buffer) { - var result = new ArrayBuffer(buffer.byteLength), + var Ctor = buffer.constructor, + result = new Ctor(buffer.byteLength), view = new Uint8Array(result); view.set(new Uint8Array(buffer)); return result; } + /** + * Creates a clone of `map`. + * + * @private + * @param {Object} map The map to clone. + * @returns {Object} Returns the cloned map. + */ + function cloneMap(map) { + var Ctor = map.constructor; + return arrayReduce(mapToArray(map), addMapEntry, new Ctor); + } + + /** + * Creates a clone of `regexp`. + * + * @private + * @param {Object} regexp The regexp to clone. + * @returns {Object} Returns the cloned regexp. + */ + function cloneRegExp(regexp) { + var Ctor = regexp.constructor, + result = new Ctor(regexp.source, reFlags.exec(regexp)); + + result.lastIndex = regexp.lastIndex; + return result; + } + + /** + * Creates a clone of `set`. + * + * @private + * @param {Object} set The set to clone. + * @returns {Object} Returns the cloned set. + */ + function cloneSet(set) { + var Ctor = set.constructor; + return arrayReduce(setToArray(set), addSetEntry, new Ctor); + } + + /** + * Creates a clone of `typedArray`. + * + * @private + * @param {Object} typedArray The typed array to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the cloned typed array. + */ + function cloneTypedArray(typedArray, isDeep) { + var buffer = typedArray.buffer, + Ctor = typedArray.constructor; + + return new Ctor(isDeep ? cloneBuffer(buffer) : buffer, typedArray.byteOffset, typedArray.length); + } + /** * Creates an array that is the composition of partially applied arguments, * placeholders, and provided arguments into a single array of arguments. @@ -4088,24 +4121,21 @@ case float32Tag: case float64Tag: case int8Tag: case int16Tag: case int32Tag: case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag: - var buffer = object.buffer; - return new Ctor(isDeep ? cloneBuffer(buffer) : buffer, object.byteOffset, object.length); + return cloneTypedArray(object, isDeep); case mapTag: - return createMap(mapToArray(object)); + return cloneMap(object); case numberTag: case stringTag: return new Ctor(object); case setTag: - return createSet(setToArray(object)); + return cloneSet(object); case regexpTag: - var result = new Ctor(object.source, reFlags.exec(object)); - result.lastIndex = object.lastIndex; + return cloneRegExp(object); } - return result; } /** diff --git a/test/test.js b/test/test.js index 84fd710406..36f4f0e76f 100644 --- a/test/test.js +++ b/test/test.js @@ -449,24 +449,29 @@ _.attempt(function() { _.extend(_, require('vm').runInNewContext([ '(function() {', - ' var object = {', - " '_arguments': (function() { return arguments; }(1, 2, 3)),", - " '_array': [1, 2, 3],", - " '_boolean': Object(false),", - " '_date': new Date,", - " '_errors': [new Error, new EvalError, new RangeError, new ReferenceError, new SyntaxError, new TypeError, new URIError],", - " '_function': function() {},", - " '_nan': NaN,", - " '_null': null,", - " '_number': Object(0),", - " '_object': { 'a': 1, 'b': 2, 'c': 3 },", - " '_regexp': /x/,", - " '_string': Object('a'),", - " '_undefined': undefined", + ' var root = this;', + '', + ' var object = {', + " '_arguments': (function() { return arguments; }(1, 2, 3)),", + " '_array': [1, 2, 3],", + " '_arrayBuffer': new (this.ArrayByffer || Object),", + " '_boolean': Object(false),", + " '_date': new Date,", + " '_errors': [new Error, new EvalError, new RangeError, new ReferenceError, new SyntaxError, new TypeError, new URIError],", + " '_function': function() {},", + " '_map': new (root.Map || Object),", + " '_nan': NaN,", + " '_null': null,", + " '_number': Object(0),", + " '_object': { 'a': 1, 'b': 2, 'c': 3 },", + " '_regexp': /x/,", + " '_set': new (root.Set || Object),", + " '_string': Object('a'),", + " '_undefined': undefined", ' };', '', " ['" + typedArrays.join("', '") + "'].forEach(function(type) {", - " var Ctor = Function('return typeof ' + type + \" != 'undefined' && \" + type)()", + " var Ctor = root[type]", ' if (Ctor) {', " object['_' + type.toLowerCase()] = new Ctor(new ArrayBuffer(24));", ' }', @@ -486,22 +491,26 @@ var idoc = (idoc = iframe.contentDocument || iframe.contentWindow).document || idoc; idoc.write([ ' -
    +
    + + diff --git a/test/test.js b/test/test.js index 46dbb44735..50f8364a9a 100644 --- a/test/test.js +++ b/test/test.js @@ -214,22 +214,15 @@ QUnit = QUnit.QUnit || QUnit )); - /** Load QUnit Extras and ES6 shims. */ - (function() { - var paths = [ - '../node_modules/qunit-extras/qunit-extras.js' - ]; - - var index = -1, - length = paths.length; - - while (++index < length) { - var object = load(paths[index]); - if (object) { - object.runInContext(root); - } - } - }()); + /** Load stable Lodash and QUnit Extras. */ + var lodashStable = root.lodashStable || load('../node_modules/lodash/index.js'); + if (lodashStable) { + lodashStable.runInContext(root); + } + var QUnitExtras = load('../node_modules/qunit-extras/qunit-extras.js'); + if (QUnitExtras) { + QUnitExtras.runInContext(root); + } /** The `lodash` function to test. */ var _ = root._ || (root._ = ( @@ -347,7 +340,7 @@ * @param {Object} object The object to empty. */ function emptyObject(object) { - _.forOwn(object, function(value, key, object) { + lodashStable.forOwn(object, function(value, key, object) { delete object[key]; }); } @@ -403,7 +396,7 @@ reToString = /toString/g; function createToString(funcName) { - return _.constant(nativeString.replace(reToString, funcName)); + return lodashStable.constant(nativeString.replace(reToString, funcName)); } // Allow bypassing native checks. @@ -415,7 +408,7 @@ }); // Add prototype extensions. - funcProto._method = _.noop; + funcProto._method = noop; // Set bad shims. var _propertyIsEnumerable = objectProto.propertyIsEnumerable; @@ -438,9 +431,9 @@ setProperty(root.Map, 'toString', createToString('Map')); } - setProperty(Object, 'create', _.noop); - setProperty(root, 'Set', _.noop); - setProperty(root, 'WeakMap', _.noop); + setProperty(Object, 'create', noop); + setProperty(root, 'Set', noop); + setProperty(root, 'WeakMap', noop); // Fake `WinRTError`. setProperty(root, 'WinRTError', Error); @@ -476,8 +469,8 @@ }()); // Add other realm values from the `vm` module. - _.attempt(function() { - _.extend(realm, require('vm').runInNewContext([ + lodashStable.attempt(function() { + lodashStable.assign(realm, require('vm').runInNewContext([ '(function() {', ' var root = this;', '', @@ -513,7 +506,7 @@ }); // Add other realm values from an iframe. - _.attempt(function() { + lodashStable.attempt(function() { _._realm = realm; var iframe = document.createElement('iframe'); @@ -523,7 +516,7 @@ var idoc = (idoc = iframe.contentDocument || iframe.contentWindow).document || idoc; idoc.write([ ' diff --git a/perf/perf.js b/perf/perf.js index 76080fe7eb..ea9c78129d 100644 --- a/perf/perf.js +++ b/perf/perf.js @@ -88,13 +88,10 @@ /** Detect if in a browser environment. */ var isBrowser = isHostType(root, 'document') && isHostType(root, 'navigator'); - /** Detect if in a Java environment. */ - var isJava = !isBrowser && /Java/.test(toString.call(root.java)); - /** Use a single "load" function. */ var load = (typeof require == 'function' && !amd) ? require - : (isJava && root.load) || noop; + : noop; /** Load lodash. */ var lodash = root.lodash || (root.lodash = ( @@ -205,7 +202,7 @@ fbPanel.getElementById('fbPanel1'); log('\nSit back and relax, this may take a while.'); - suites[0].run({ 'async': !isJava }); + suites[0].run({ 'async': true }); } /*--------------------------------------------------------------------------*/ @@ -258,7 +255,7 @@ if (suites.length) { // Run next suite. - suites[0].run({ 'async': !isJava }); + suites[0].run({ 'async': true }); } else { var aMeanHz = getGeometricMean(score.a), @@ -981,19 +978,17 @@ ); // Avoid Underscore induced `OutOfMemoryError` in Rhino and Ringo. - if (!isJava) { - suites.push( - Benchmark.Suite('`_.find` with `_.matches` shorthand') - .add(buildName, { - 'fn': 'lodashFindWhere(objects, source)', - 'teardown': 'function matches(){}' - }) - .add(otherName, { - 'fn': '_findWhere(objects, source)', - 'teardown': 'function matches(){}' - }) - ); - } + suites.push( + Benchmark.Suite('`_.find` with `_.matches` shorthand') + .add(buildName, { + 'fn': 'lodashFindWhere(objects, source)', + 'teardown': 'function matches(){}' + }) + .add(otherName, { + 'fn': '_findWhere(objects, source)', + 'teardown': 'function matches(){}' + }) + ); /*--------------------------------------------------------------------------*/ From 3d31423eef0e417fe2151a58d8993bffdc054c86 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Fri, 27 Nov 2015 16:21:40 -0600 Subject: [PATCH 693/935] Remove `thisArg` param benchmarks. --- perf/perf.js | 108 --------------------------------------------------- 1 file changed, 108 deletions(-) diff --git a/perf/perf.js b/perf/perf.js index ea9c78129d..6a9b3315d8 100644 --- a/perf/perf.js +++ b/perf/perf.js @@ -829,22 +829,6 @@ ) ); - suites.push( - Benchmark.Suite('`_.each` iterating an array with `thisArg` (slow path)') - .add(buildName, '\ - var result = [];\ - lodash.each(numbers, function(num, index) {\ - result.push(num + this["key" + index]);\ - }, object)' - ) - .add(otherName, '\ - var result = [];\ - _.each(numbers, function(num, index) {\ - result.push(num + this["key" + index]);\ - }, object)' - ) - ); - suites.push( Benchmark.Suite('`_.each` iterating an object') .add(buildName, '\ @@ -907,20 +891,6 @@ ) ); - suites.push( - Benchmark.Suite('`_.filter` iterating an array with `thisArg` (slow path)') - .add(buildName, '\ - lodash.filter(numbers, function(num, index) {\ - return this["key" + index] % 2;\ - }, object)' - ) - .add(otherName, '\ - _.filter(numbers, function(num, index) {\ - return this["key" + index] % 2;\ - }, object)' - ) - ); - suites.push( Benchmark.Suite('`_.filter` iterating an object') .add(buildName, '\ @@ -1400,20 +1370,6 @@ ) ); - suites.push( - Benchmark.Suite('`_.map` with `thisArg` iterating an array (slow path)') - .add(buildName, '\ - lodash.map(objects, function(value, index) {\ - return this["key" + index] + value.num;\ - }, object)' - ) - .add(otherName, '\ - _.map(objects, function(value, index) {\ - return this["key" + index] + value.num;\ - }, object)' - ) - ); - suites.push( Benchmark.Suite('`_.map` iterating an object') .add(buildName, '\ @@ -1530,20 +1486,6 @@ ) ); - suites.push( - Benchmark.Suite('`_.partition` iterating an array with `thisArg` (slow path)') - .add(buildName, '\ - lodash.partition(numbers, function(num, index) {\ - return this["key" + index] % 2;\ - }, object)' - ) - .add(otherName, '\ - _.partition(numbers, function(num, index) {\ - return this["key" + index] % 2;\ - }, object)' - ) - ); - suites.push( Benchmark.Suite('`_.partition` iterating an object') .add(buildName, '\ @@ -1666,20 +1608,6 @@ ) ); - suites.push( - Benchmark.Suite('`_.reject` iterating an array with `thisArg` (slow path)') - .add(buildName, '\ - lodash.reject(numbers, function(num, index) {\ - return this["key" + index] % 2;\ - }, object)' - ) - .add(otherName, '\ - _.reject(numbers, function(num, index) {\ - return this["key" + index] % 2;\ - }, object)' - ) - ); - suites.push( Benchmark.Suite('`_.reject` iterating an object') .add(buildName, '\ @@ -1746,20 +1674,6 @@ ) ); - suites.push( - Benchmark.Suite('`_.some` with `thisArg` iterating an array (slow path)') - .add(buildName, '\ - lodash.some(objects, function(value, index) {\ - return this["key" + index] == (limit - 1);\ - }, object)' - ) - .add(otherName, '\ - _.some(objects, function(value, index) {\ - return this["key" + index] == (limit - 1);\ - }, object)' - ) - ); - suites.push( Benchmark.Suite('`_.some` iterating an object') .add(buildName, '\ @@ -1786,16 +1700,6 @@ ) ); - suites.push( - Benchmark.Suite('`_.sortBy` with `callback` and `thisArg` (slow path)') - .add(buildName, '\ - lodash.sortBy(numbers, function(num) { return this.sin(num); }, Math)' - ) - .add(otherName, '\ - _.sortBy(numbers, function(num) { return this.sin(num); }, Math)' - ) - ); - suites.push( Benchmark.Suite('`_.sortBy` with `property` name') .add(buildName, { @@ -1902,18 +1806,6 @@ ) ); - suites.push( - Benchmark.Suite('`_.times` with `thisArg` (slow path)') - .add(buildName, '\ - var result = [];\ - lodash.times(limit, function(n) { result.push(this.sin(n)); }, Math)' - ) - .add(otherName, '\ - var result = [];\ - _.times(limit, function(n) { result.push(this.sin(n)); }, Math)' - ) - ); - /*--------------------------------------------------------------------------*/ suites.push( From 411f3ecb3e2e8e0386d3322707a09a2790918e84 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Fri, 27 Nov 2015 17:07:45 -0600 Subject: [PATCH 694/935] Update benchmarks. --- perf/perf.js | 265 +++++++++++++++++++++++++-------------------------- 1 file changed, 128 insertions(+), 137 deletions(-) diff --git a/perf/perf.js b/perf/perf.js index 6a9b3315d8..40f743b706 100644 --- a/perf/perf.js +++ b/perf/perf.js @@ -357,13 +357,13 @@ uncompacted[6] = null;\ uncompacted[18] = "";\ }\ - if (typeof compose != "undefined") {\ + if (typeof flowRight != "undefined") {\ var compAddOne = function(n) { return n + 1; },\ compAddTwo = function(n) { return n + 2; },\ compAddThree = function(n) { return n + 3; };\ \ - var _composed = _.compose(compAddThree, compAddTwo, compAddOne),\ - lodashComposed = lodash.compose(compAddThree, compAddTwo, compAddOne);\ + var _composed = _.flowRight(compAddThree, compAddTwo, compAddOne),\ + lodashComposed = lodash.flowRight(compAddThree, compAddTwo, compAddOne);\ }\ if (typeof countBy != "undefined" || typeof omit != "undefined") {\ var wordToNumber = {\ @@ -458,11 +458,8 @@ if (typeof matches != "undefined") {\ var source = { "num": 9 };\ \ - var _findWhere = _.findWhere || _.find,\ - _matcher = (_.matches || _.createCallback || _.noop)(source);\ - \ - var lodashFindWhere = lodash.findWhere || lodash.find,\ - lodashMatcher = (lodash.matches || lodash.createCallback || lodash.noop)(source);\ + var _matcher = (_.matches || _.noop)(source),\ + lodashMatcher = (lodash.matches || lodash.noop)(source);\ }\ if (typeof multiArrays != "undefined") {\ var twentyValues = belt.shuffle(belt.range(20)),\ @@ -642,25 +639,13 @@ /*--------------------------------------------------------------------------*/ suites.push( - Benchmark.Suite('`_.bindAll` iterating arguments') + Benchmark.Suite('`_.bindAll`') .add(buildName, { - 'fn': 'lodash.bindAll.apply(lodash, [bindAllObjects[++bindAllCount]].concat(funcNames))', + 'fn': 'lodash.bindAll(bindAllObjects[++bindAllCount], funcNames)', 'teardown': 'function bindAll(){}' }) .add(otherName, { - 'fn': '_.bindAll.apply(_, [bindAllObjects[++bindAllCount]].concat(funcNames))', - 'teardown': 'function bindAll(){}' - }) - ); - - suites.push( - Benchmark.Suite('`_.bindAll` iterating the `object`') - .add(buildName, { - 'fn': 'lodash.bindAll(bindAllObjects[++bindAllCount])', - 'teardown': 'function bindAll(){}' - }) - .add(otherName, { - 'fn': '_.bindAll(bindAllObjects[++bindAllCount])', + 'fn': '_.bindAll(bindAllObjects[++bindAllCount], funcNames)', 'teardown': 'function bindAll(){}' }) ); @@ -703,32 +688,6 @@ /*--------------------------------------------------------------------------*/ - suites.push( - Benchmark.Suite('`_.compose`') - .add(buildName, { - 'fn': 'lodash.compose(compAddThree, compAddTwo, compAddOne)', - 'teardown': 'function compose(){}' - }) - .add(otherName, { - 'fn': '_.compose(compAddThree, compAddTwo, compAddOne)', - 'teardown': 'function compose(){}' - }) - ); - - suites.push( - Benchmark.Suite('composed call') - .add(buildName, { - 'fn': 'lodashComposed(0)', - 'teardown': 'function compose(){}' - }) - .add(otherName, { - 'fn': '_composed(0)', - 'teardown': 'function compose(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - suites.push( Benchmark.Suite('`_.countBy` with `callback` iterating an array') .add(buildName, '\ @@ -905,6 +864,18 @@ ) ); + suites.push( + Benchmark.Suite('`_.filter` with `_.matches` shorthand') + .add(buildName, { + 'fn': 'lodash.filter(objects, source)', + 'teardown': 'function matches(){}' + }) + .add(otherName, { + 'fn': '_.filter(objects, source)', + 'teardown': 'function matches(){}' + }) + ); + suites.push( Benchmark.Suite('`_.filter` with `_.matches` predicate') .add(buildName, { @@ -951,11 +922,11 @@ suites.push( Benchmark.Suite('`_.find` with `_.matches` shorthand') .add(buildName, { - 'fn': 'lodashFindWhere(objects, source)', + 'fn': 'lodash.find(objects, source)', 'teardown': 'function matches(){}' }) .add(otherName, { - 'fn': '_findWhere(objects, source)', + 'fn': '_.find(objects, source)', 'teardown': 'function matches(){}' }) ); @@ -974,32 +945,60 @@ }) ); + /*--------------------------------------------------------------------------*/ + suites.push( - Benchmark.Suite('`_.flatten` nested arrays of numbers with `isDeep`') + Benchmark.Suite('`_.flattenDeep` nested arrays of numbers') .add(buildName, { - 'fn': 'lodash.flatten(nestedNumbers, lodashFlattenDeep)', + 'fn': 'lodash.flattenDeep(nestedNumbers)', 'teardown': 'function flatten(){}' }) .add(otherName, { - 'fn': '_.flatten(nestedNumbers, _flattenDeep)', + 'fn': '_.flattenDeep(nestedNumbers)', 'teardown': 'function flatten(){}' }) ); suites.push( - Benchmark.Suite('`_.flatten` nest arrays of objects with `isDeep`') + Benchmark.Suite('`_.flattenDeep` nest arrays of objects') .add(buildName, { - 'fn': 'lodash.flatten(nestedObjects, lodashFlattenDeep)', + 'fn': 'lodash.flattenDeep(nestedObjects)', 'teardown': 'function flatten(){}' }) .add(otherName, { - 'fn': '_.flatten(nestedObjects, _flattenDeep)', + 'fn': '_.flattenDeep(nestedObjects)', 'teardown': 'function flatten(){}' }) ); /*--------------------------------------------------------------------------*/ + suites.push( + Benchmark.Suite('`_.flowRight`') + .add(buildName, { + 'fn': 'lodash.flowRight(compAddThree, compAddTwo, compAddOne)', + 'teardown': 'function flowRight(){}' + }) + .add(otherName, { + 'fn': '_.flowRight(compAddThree, compAddTwo, compAddOne)', + 'teardown': 'function flowRight(){}' + }) + ); + + suites.push( + Benchmark.Suite('composed call') + .add(buildName, { + 'fn': 'lodashComposed(0)', + 'teardown': 'function flowRight(){}' + }) + .add(otherName, { + 'fn': '_composed(0)', + 'teardown': 'function flowRight(){}' + }) + ); + + /*--------------------------------------------------------------------------*/ + suites.push( Benchmark.Suite('`_.functions`') .add(buildName, '\ @@ -1094,18 +1093,6 @@ }) ); - suites.push( - Benchmark.Suite('`_.indexOf` performing a binary search') - .add(buildName, { - 'fn': 'lodash.indexOf(hundredSortedValues, 99, true)', - 'teardown': 'function multiArrays(){}' - }) - .add(otherName, { - 'fn': '_.indexOf(hundredSortedValues, 99, true)', - 'teardown': 'function multiArrays(){}' - }) - ); - /*--------------------------------------------------------------------------*/ suites.push( @@ -1342,18 +1329,6 @@ }) ); - suites.push( - Benchmark.Suite('`_.lastIndexOf` performing a binary search') - .add(buildName, { - 'fn': 'lodash.lastIndexOf(hundredSortedValues, 0, true)', - 'teardown': 'function multiArrays(){}' - }) - .add(otherName, { - 'fn': '_.lastIndexOf(hundredSortedValues, 0, true)', - 'teardown': 'function multiArrays(){}' - }) - ); - /*--------------------------------------------------------------------------*/ suites.push( @@ -1384,6 +1359,16 @@ ) ); + suites.push( + Benchmark.Suite('`_.map` with `_.property` shorthand') + .add(buildName, '\ + lodash.map(objects, "num")' + ) + .add(otherName, '\ + _.map(objects, "num")' + ) + ); + /*--------------------------------------------------------------------------*/ suites.push( @@ -1434,18 +1419,6 @@ /*--------------------------------------------------------------------------*/ - suites.push( - Benchmark.Suite('`_.pairs`') - .add(buildName, '\ - lodash.pairs(object)' - ) - .add(otherName, '\ - _.pairs(object)' - ) - ); - - /*--------------------------------------------------------------------------*/ - suites.push( Benchmark.Suite('`_.partial` (slow path)') .add(buildName, { @@ -1514,18 +1487,6 @@ /*--------------------------------------------------------------------------*/ - suites.push( - Benchmark.Suite('`_.pluck`') - .add(buildName, '\ - lodash.pluck(objects, "num")' - ) - .add(otherName, '\ - _.pluck(objects, "num")' - ) - ); - - /*--------------------------------------------------------------------------*/ - suites.push( Benchmark.Suite('`_.reduce` iterating an array') .add(buildName, '\ @@ -1625,12 +1586,12 @@ /*--------------------------------------------------------------------------*/ suites.push( - Benchmark.Suite('`_.sample` with an `n`') + Benchmark.Suite('`_.sampleSize`') .add(buildName, '\ - lodash.sample(numbers, limit / 2)' + lodash.sampleSize(numbers, limit / 2)' ) .add(otherName, '\ - _.sample(numbers, limit / 2)' + _.sampleSize(numbers, limit / 2)' ) ); @@ -1724,18 +1685,20 @@ ) ); + /*--------------------------------------------------------------------------*/ + suites.push( - Benchmark.Suite('`_.sortedIndex` with `callback`') + Benchmark.Suite('`_.sortedIndexBy`') .add(buildName, { 'fn': '\ - lodash.sortedIndex(words, "twenty-five", function(value) {\ + lodash.sortedIndexBy(words, "twenty-five", function(value) {\ return wordToNumber[value];\ })', 'teardown': 'function countBy(){}' }) .add(otherName, { 'fn': '\ - _.sortedIndex(words, "twenty-five", function(value) {\ + _.sortedIndexBy(words, "twenty-five", function(value) {\ return wordToNumber[value];\ })', 'teardown': 'function countBy(){}' @@ -1744,6 +1707,34 @@ /*--------------------------------------------------------------------------*/ + suites.push( + Benchmark.Suite('`_.sortedIndexOf`') + .add(buildName, { + 'fn': 'lodash.sortedIndexOf(hundredSortedValues, 99)', + 'teardown': 'function multiArrays(){}' + }) + .add(otherName, { + 'fn': '_.sortedIndexOf(hundredSortedValues, 99)', + 'teardown': 'function multiArrays(){}' + }) + ); + + /*--------------------------------------------------------------------------*/ + + suites.push( + Benchmark.Suite('`_.sortedLastIndexOf`') + .add(buildName, { + 'fn': 'lodash.sortedLastIndexOf(hundredSortedValues, 0)', + 'teardown': 'function multiArrays(){}' + }) + .add(otherName, { + 'fn': '_.sortedLastIndexOf(hundredSortedValues, 0)', + 'teardown': 'function multiArrays(){}' + }) + ); + + /*--------------------------------------------------------------------------*/ + suites.push( Benchmark.Suite('`_.sum`') .add(buildName, '\ @@ -1830,6 +1821,18 @@ /*--------------------------------------------------------------------------*/ + suites.push( + Benchmark.Suite('`_.toPairs`') + .add(buildName, '\ + lodash.toPairs(object)' + ) + .add(otherName, '\ + _.toPairs(object)' + ) + ); + + /*--------------------------------------------------------------------------*/ + suites.push( Benchmark.Suite('`_.unescape` string without html entities') .add(buildName, '\ @@ -1886,20 +1889,6 @@ ) ); - suites.push( - Benchmark.Suite('`_.uniq` with `callback`') - .add(buildName, '\ - lodash.uniq(numbers.concat(twoNumbers, fourNumbers), function(num) {\ - return num % 2;\ - })' - ) - .add(otherName, '\ - _.uniq(numbers.concat(twoNumbers, fourNumbers), function(num) {\ - return num % 2;\ - })' - ) - ); - suites.push( Benchmark.Suite('`_.uniq` iterating an array of 200 elements') .add(buildName, { @@ -1915,27 +1904,29 @@ /*--------------------------------------------------------------------------*/ suites.push( - Benchmark.Suite('`_.values`') + Benchmark.Suite('`_.uniqBy`') .add(buildName, '\ - lodash.values(object)' + lodash.uniqBy(numbers.concat(twoNumbers, fourNumbers), function(num) {\ + return num % 2;\ + })' ) .add(otherName, '\ - _.values(object)' + _.uniqBy(numbers.concat(twoNumbers, fourNumbers), function(num) {\ + return num % 2;\ + })' ) ); /*--------------------------------------------------------------------------*/ suites.push( - Benchmark.Suite('`_.where`') - .add(buildName, { - 'fn': 'lodash.where(objects, source)', - 'teardown': 'function matches(){}' - }) - .add(otherName, { - 'fn': '_.where(objects, source)', - 'teardown': 'function matches(){}' - }) + Benchmark.Suite('`_.values`') + .add(buildName, '\ + lodash.values(object)' + ) + .add(otherName, '\ + _.values(object)' + ) ); /*--------------------------------------------------------------------------*/ From 8f190b1fb19f8de7eee95a597cd2b848d16599ad Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Fri, 27 Nov 2015 17:37:54 -0600 Subject: [PATCH 695/935] Update Firefox in test/saucelabs.js. --- test/saucelabs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/saucelabs.js b/test/saucelabs.js index 615c0252a1..ee2a5f5a51 100644 --- a/test/saucelabs.js +++ b/test/saucelabs.js @@ -105,8 +105,8 @@ var platforms = [ ['Linux', 'android', '5.1'], ['Windows 10', 'chrome', '46'], ['Windows 10', 'chrome', '45'], + ['Windows 10', 'firefox', '42'], ['Windows 10', 'firefox', '41'], - ['Windows 10', 'firefox', '40'], ['Windows 10', 'microsoftedge', '20.10240'], ['Windows 10', 'internet explorer', '11'], ['Windows 8', 'internet explorer', '10'], From 876fe52efcc84a9e1f5c7eb36849624713f8cb5d Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Fri, 27 Nov 2015 20:16:11 -0600 Subject: [PATCH 696/935] Describe `HOT` vars a bit more. [ci skip] --- lodash.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lodash.js b/lodash.js index 64fe03ae7a..84e8b3a404 100644 --- a/lodash.js +++ b/lodash.js @@ -34,7 +34,7 @@ var DEFAULT_TRUNC_LENGTH = 30, DEFAULT_TRUNC_OMISSION = '...'; - /** Used to detect when a function becomes hot. */ + /** Used to detect hot functions by number of calls within a span of milliseconds. */ var HOT_COUNT = 150, HOT_SPAN = 16; From e99a31c2fa7351b8204fadd2d98a6db97579de23 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Fri, 27 Nov 2015 20:18:09 -0600 Subject: [PATCH 697/935] Update `call` and `invocation` use. [ci skip] --- lodash.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lodash.js b/lodash.js index 84e8b3a404..2c48ea9062 100644 --- a/lodash.js +++ b/lodash.js @@ -8373,7 +8373,7 @@ * 'maxWait': 1000 * })); * - * // cancel a debounced call + * // cancel a debounced invocation * var todoChanges = _.debounce(batchLog, 1000); * Object.observe(models.todo, todoChanges); * @@ -8387,7 +8387,7 @@ * models.todo.completed = true; * * // ...before 1 second has passed `models.todo` is deleted - * // which cancels the debounced `todoChanges` call + * // which cancels the debounced `todoChanges` invocation * delete models.todo; */ function debounce(func, wait, options) { @@ -8731,8 +8731,8 @@ /** * Creates a function that is restricted to invoking `func` once. Repeat calls - * to the function return the value of the first call. The `func` is invoked - * with the `this` binding and arguments of the created function. + * to the function return the value of the first invocation. The `func` is + * invoked with the `this` binding and arguments of the created function. * * @static * @memberOf _ @@ -8948,7 +8948,7 @@ * `func` should be invoked on the leading and/or trailing edge of the `wait` * timeout. The `func` is invoked with the last arguments provided to the * throttled function. Subsequent calls to the throttled function return the - * result of the last `func` call. + * result of the last `func` invocation. * * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked * on the trailing edge of the timeout only if the the throttled function is @@ -8978,7 +8978,7 @@ * 'trailing': false * })); * - * // cancel a trailing throttled call + * // cancel a trailing throttled invocation * jQuery(window).on('popstate', throttled.cancel); */ function throttle(func, wait, options) { From 1f991a7cdc4dc982c3494929ffcd8a451e2147f3 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Fri, 27 Nov 2015 23:31:08 -0600 Subject: [PATCH 698/935] Rename `binaryIndex` and `binaryIndexBy` to `baseSortedIndex` and `baseSortedIndexBy`. --- lodash.js | 169 +++++++++++++++++++++++++++--------------------------- 1 file changed, 85 insertions(+), 84 deletions(-) diff --git a/lodash.js b/lodash.js index 2c48ea9062..fd43113f88 100644 --- a/lodash.js +++ b/lodash.js @@ -3372,6 +3372,85 @@ }); } + /** + * The base implementation of `_.sortedIndex` and `_.sortedLastIndex` which + * performs a binary search of `array` to determine the index at which `value` + * should be inserted into `array` in order to maintain its sort order. + * + * @private + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {boolean} [retHighest] Specify returning the highest qualified index. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + */ + function baseSortedIndex(array, value, retHighest) { + var low = 0, + high = array ? array.length : low; + + if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) { + while (low < high) { + var mid = (low + high) >>> 1, + computed = array[mid]; + + if ((retHighest ? (computed <= value) : (computed < value)) && computed !== null) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + return baseSortedIndexBy(array, value, identity, retHighest); + } + + /** + * The base implementation of `_.sortedIndexBy` and `_.sortedLastIndexBy` + * which invokes `iteratee` for `value` and each element of `array` to compute + * their sort ranking. The iteratee is invoked with one argument; (value). + * + * @private + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function} iteratee The iteratee invoked per element. + * @param {boolean} [retHighest] Specify returning the highest qualified index. + * @returns {number} Returns the index at which `value` should be inserted into `array`. + */ + function baseSortedIndexBy(array, value, iteratee, retHighest) { + value = iteratee(value); + + var low = 0, + high = array ? array.length : 0, + valIsNaN = value !== value, + valIsNull = value === null, + valIsUndef = value === undefined; + + while (low < high) { + var mid = nativeFloor((low + high) / 2), + computed = iteratee(array[mid]), + isDef = computed !== undefined, + isReflexive = computed === computed; + + if (valIsNaN) { + var setLow = isReflexive || retHighest; + } else if (valIsNull) { + setLow = isReflexive && isDef && (retHighest || computed != null); + } else if (valIsUndef) { + setLow = isReflexive && (retHighest || isDef); + } else if (computed == null) { + setLow = false; + } else { + setLow = retHighest ? (computed <= value) : (computed < value); + } + if (setLow) { + low = mid + 1; + } else { + high = mid; + } + } + return nativeMin(high, MAX_ARRAY_INDEX); + } + /** * The base implementation of `_.sortedUniq`. * @@ -3568,84 +3647,6 @@ return (result && result.length) ? baseUniq(result, iteratee, comparator) : []; } - /** - * Performs a binary search of `array` to determine the index at which `value` - * should be inserted into `array` in order to maintain its sort order. - * - * @private - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {boolean} [retHighest] Specify returning the highest qualified index. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - */ - function binaryIndex(array, value, retHighest) { - var low = 0, - high = array ? array.length : low; - - if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) { - while (low < high) { - var mid = (low + high) >>> 1, - computed = array[mid]; - - if ((retHighest ? (computed <= value) : (computed < value)) && computed !== null) { - low = mid + 1; - } else { - high = mid; - } - } - return high; - } - return binaryIndexBy(array, value, identity, retHighest); - } - - /** - * This function is like `binaryIndex` except that it invokes `iteratee` for - * `value` and each element of `array` to compute their sort ranking. The - * iteratee is invoked with one argument; (value). - * - * @private - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {Function} iteratee The iteratee invoked per element. - * @param {boolean} [retHighest] Specify returning the highest qualified index. - * @returns {number} Returns the index at which `value` should be inserted into `array`. - */ - function binaryIndexBy(array, value, iteratee, retHighest) { - value = iteratee(value); - - var low = 0, - high = array ? array.length : 0, - valIsNaN = value !== value, - valIsNull = value === null, - valIsUndef = value === undefined; - - while (low < high) { - var mid = nativeFloor((low + high) / 2), - computed = iteratee(array[mid]), - isDef = computed !== undefined, - isReflexive = computed === computed; - - if (valIsNaN) { - var setLow = isReflexive || retHighest; - } else if (valIsNull) { - setLow = isReflexive && isDef && (retHighest || computed != null); - } else if (valIsUndef) { - setLow = isReflexive && (retHighest || isDef); - } else if (computed == null) { - setLow = false; - } else { - setLow = retHighest ? (computed <= value) : (computed < value); - } - if (setLow) { - low = mid + 1; - } else { - high = mid; - } - } - return nativeMin(high, MAX_ARRAY_INDEX); - } - /** * Creates a clone of `buffer`. * @@ -6124,7 +6125,7 @@ * // => 0 */ function sortedIndex(array, value) { - return binaryIndex(array, value); + return baseSortedIndex(array, value); } /** @@ -6151,7 +6152,7 @@ * // => 0 */ function sortedIndexBy(array, value, iteratee) { - return binaryIndexBy(array, value, getIteratee(iteratee)); + return baseSortedIndexBy(array, value, getIteratee(iteratee)); } /** @@ -6172,7 +6173,7 @@ function sortedIndexOf(array, value) { var length = array ? array.length : 0; if (length) { - var index = binaryIndex(array, value); + var index = baseSortedIndex(array, value); if (index < length && (value === value ? (value === array[index]) : (array[index] !== array[index]))) { return index; @@ -6198,7 +6199,7 @@ * // => 1 */ function sortedLastIndex(array, value) { - return binaryIndex(array, value, true); + return baseSortedIndex(array, value, true); } /** @@ -6220,7 +6221,7 @@ * // => 1 */ function sortedLastIndexBy(array, value, iteratee) { - return binaryIndexBy(array, value, getIteratee(iteratee), true); + return baseSortedIndexBy(array, value, getIteratee(iteratee), true); } /** @@ -6241,7 +6242,7 @@ function sortedLastIndexOf(array, value) { var length = array ? array.length : 0; if (length) { - var index = binaryIndex(array, value, true) - 1, + var index = baseSortedIndex(array, value, true) - 1, other = array[index]; if (value === value ? (value === other) : (other !== other)) { From a37c6db377028898b19d6c9ba3cb5c8b18de0afe Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sat, 28 Nov 2015 10:02:42 -0600 Subject: [PATCH 699/935] Use `apply` in `_.invokeMap`. --- lodash.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lodash.js b/lodash.js index fd43113f88..b055b1152b 100644 --- a/lodash.js +++ b/lodash.js @@ -384,6 +384,7 @@ */ function apply(func, thisArg, args) { switch (args.length) { + case 0: return func.call(thisArg); case 1: return func.call(thisArg, args[0]); case 2: return func.call(thisArg, args[0], args[1]); case 3: return func.call(thisArg, args[0], args[1], args[2]); @@ -7524,7 +7525,7 @@ baseEach(collection, function(value) { var func = isFunc ? path : ((isProp && value != null) ? value[path] : undefined); - result[++index] = func ? func.apply(value, args) : baseInvoke(value, path, args); + result[++index] = func ? apply(func, value, args) : baseInvoke(value, path, args); }); return result; }); From d07343a1aa5a9ab252d8dbfb702bb203bf871af7 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sat, 28 Nov 2015 23:13:55 -0600 Subject: [PATCH 700/935] Use `apply` in more places. --- lodash.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lodash.js b/lodash.js index b055b1152b..15a8f088ae 100644 --- a/lodash.js +++ b/lodash.js @@ -2736,7 +2736,7 @@ path = last(path); } var func = object == null ? object : object[path]; - return func == null ? undefined : func.apply(object, args); + return func == null ? undefined : apply(func, object, args); } /** @@ -4178,7 +4178,7 @@ return rest(function(args) { var thisArg = this; return arrayFunc(iteratees, function(iteratee) { - return iteratee.apply(thisArg, args); + return apply(iteratee, thisArg, args); }); }); }); @@ -8898,7 +8898,7 @@ otherArgs[index] = args[index]; } otherArgs[start] = array; - return func.apply(this, otherArgs); + return apply(func, this, otherArgs); }; } @@ -8938,7 +8938,7 @@ throw new TypeError(FUNC_ERROR_TEXT); } return function(array) { - return func.apply(this, array); + return apply(func, this, array); }; } @@ -10529,7 +10529,7 @@ */ var defaults = rest(function(args) { args.push(undefined, assignInDefaults); - return assignInWith.apply(undefined, args); + return apply(assignInWith, undefined, args); }); /** @@ -10552,7 +10552,7 @@ */ var defaultsDeep = rest(function(args) { args.push(undefined, mergeDefaults); - return mergeWith.apply(undefined, args); + return apply(mergeWith, undefined, args); }); /** @@ -12720,7 +12720,7 @@ */ var attempt = rest(function(func, args) { try { - return func.apply(undefined, args); + return apply(func, undefined, args); } catch (e) { return isError(e) ? e : new Error(e); } From 3874b5bf840368bfe16c02106c5ba6c3b7bc83c0 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sun, 29 Nov 2015 00:01:16 -0600 Subject: [PATCH 701/935] Add semicolons. --- test/test.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/test.js b/test/test.js index 46345a5fb4..dfaa7f639b 100644 --- a/test/test.js +++ b/test/test.js @@ -2125,9 +2125,9 @@ QUnit.test('should clamp positive numbers', function(assert) { assert.expect(3); - assert.strictEqual(_.clamp(10, -5, 5), 5) + assert.strictEqual(_.clamp(10, -5, 5), 5); assert.strictEqual(_.clamp(10.6, -5.6, 5.4), 5.4); - assert.strictEqual(_.clamp(Infinity, -5, 5), 5) + assert.strictEqual(_.clamp(Infinity, -5, 5), 5); }); QUnit.test('should not alter negative numbers in range', function(assert) { @@ -19951,7 +19951,7 @@ func(Object(other)) ]; }) - ) + ); }); assert.deepEqual(actual, expected); @@ -20019,7 +20019,7 @@ func(mod(other)), func(Object(mod(other))) ]; - }) + }); }) ); }); @@ -20046,7 +20046,7 @@ func(mod(value)), func(Object(mod(value))) ]; - }) + }); }) ); }); From 0a55eff5d56ed1cc6a30481bad02e84fa79b5f16 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sat, 28 Nov 2015 23:33:47 -0600 Subject: [PATCH 702/935] Fix `spread` test fail. --- lodash.js | 3 ++- test/test.js | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/lodash.js b/lodash.js index 15a8f088ae..651df4e5a4 100644 --- a/lodash.js +++ b/lodash.js @@ -383,7 +383,8 @@ * @returns {*} Returns the result of `func`. */ function apply(func, thisArg, args) { - switch (args.length) { + var length = args ? args.length : 0; + switch (length) { case 0: return func.call(thisArg); case 1: return func.call(thisArg, args[0]); case 2: return func.call(thisArg, args[0], args[1]); diff --git a/test/test.js b/test/test.js index dfaa7f639b..2cfbcb1b85 100644 --- a/test/test.js +++ b/test/test.js @@ -17716,10 +17716,20 @@ assert.strictEqual(spread([4, 2]), 6); }); - QUnit.test('should throw a TypeError when receiving a non-array `array` argument', function(assert) { + QUnit.test('should accept a falsey `array` argument', function(assert) { assert.expect(1); - assert.raises(function() { _.spread(4, 2); }, TypeError); + var alwaysTrue = lodashStable.constant(true), + spread = _.spread(alwaysTrue), + expected = lodashStable.map(falsey, alwaysTrue); + + var actual = lodashStable.map(falsey, function(array, index) { + try { + return index ? spread(array) : spread(); + } catch (e) {} + }); + + assert.deepEqual(actual, expected); }); QUnit.test('should provide the correct `func` arguments', function(assert) { From e778458f7855ec7d901bf0c279581fb865007629 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sun, 29 Nov 2015 00:09:13 -0600 Subject: [PATCH 703/935] Minor style tweak to `_.overEvery` test. --- test/test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test.js b/test/test.js index 2cfbcb1b85..f0d5e82dc9 100644 --- a/test/test.js +++ b/test/test.js @@ -14069,9 +14069,9 @@ assert.expect(2); var count = 0, - falsey = function() { count++; return false; }, - truthy = function() { count++; return true; }, - over = _.overEvery(truthy, falsey, truthy); + alwaysFalse = function() { count++; return false; }, + alwaysTrue = function() { count++; return true; }, + over = _.overEvery(alwaysTrue, alwaysFalse, alwaysTrue); assert.strictEqual(over(), false); assert.strictEqual(count, 2); From fdc15df3b3f34afd5646041f2e06e2dfe5e31890 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sun, 29 Nov 2015 12:00:53 -0600 Subject: [PATCH 704/935] Remove rhino testing. --- CONTRIBUTING.md | 2 - test/run-test.sh | 14 - test/test.js | 824 ++++++++++++++++++----------------------------- 3 files changed, 315 insertions(+), 525 deletions(-) delete mode 100644 test/run-test.sh diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 670c101d9c..245c18b5b6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,8 +10,6 @@ Don’t worry about regenerating the documentation, lodash.js, or lodash.min.js. Before running the unit tests you’ll need to install, `npm i`, [development dependencies](https://docs.npmjs.com/files/package.json#devdependencies). Run unit tests from the command-line via `node test/test`, or open `test/index.html` in a web browser. - -The `test/run-test.sh` script attempts to run the tests in [Rhino](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rhino), [RingoJS](http://ringojs.org/), [PhantomJS](http://phantomjs.org/), & [Node](http://nodejs.org/), before running them in your default browser. The [Backbone](http://backbonejs.org/) & [Underscore](http://underscorejs.org/) test suites are included as well. ## Contributor License Agreement diff --git a/test/run-test.sh b/test/run-test.sh deleted file mode 100644 index e828d926df..0000000000 --- a/test/run-test.sh +++ /dev/null @@ -1,14 +0,0 @@ -cd "$(dirname "$0")" - -echo "Testing in node..." -node test.js ../lodash.js - -for cmd in rhino "rhino -require" ringo phantomjs; do - echo "" - echo "Testing in $cmd..." - $cmd test.js ../lodash.js -done - -echo "" -echo "Testing in a browser..." -open index.html diff --git a/test/test.js b/test/test.js index f0d5e82dc9..8c6804c07e 100644 --- a/test/test.js +++ b/test/test.js @@ -123,9 +123,6 @@ /** The basename of the lodash file to test. */ var basename = /[\w.-]+$/.exec(filePath)[0]; - /** Detect if in a Java environment. */ - var isJava = !document && !!root.java; - /** Used to indicate testing a modularized build. */ var isModularize = ui.isModularize; @@ -135,9 +132,6 @@ /** Detect if running in PhantomJS. */ var isPhantom = phantom || typeof callPhantom == 'function'; - /** Detect if running in Rhino. */ - var isRhino = isJava && typeof global == 'function' && global().Array === root.Array; - /** Detect if lodash is in strict mode. */ var isStrict = ui.isStrict; @@ -207,18 +201,15 @@ /** Use a single "load" function. */ var load = (!amd && typeof require == 'function') ? require - : (isJava ? root.load : noop); + : noop; /** The unit testing framework. */ - var QUnit = root.QUnit || (root.QUnit = ( - QUnit = load('../node_modules/qunitjs/qunit/qunit.js') || root.QUnit, - QUnit = QUnit.QUnit || QUnit - )); + var QUnit = root.QUnit || (root.QUnit = load('../node_modules/qunitjs/qunit/qunit.js')); /** Load stable Lodash and QUnit Extras. */ var lodashStable = root.lodashStable || load('../node_modules/lodash/index.js'); if (lodashStable) { - lodashStable.runInContext(root); + lodashStable = lodashStable.runInContext(root); } var QUnitExtras = load('../node_modules/qunit-extras/qunit-extras.js'); if (QUnitExtras) { @@ -227,7 +218,7 @@ /** The `lodash` function to test. */ var _ = root._ || (root._ = ( - _ = load(filePath) || root._, + _ = load(filePath), _ = _._ || (isStrict = ui.isStrict = isStrict || 'default' in _, _['default']) || _, (_.runInContext ? _.runInContext(root) : _) )); @@ -3326,25 +3317,19 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var callCount = 0, - debounced = _.debounce(function() { callCount++; }, 32); + var callCount = 0, + debounced = _.debounce(function() { callCount++; }, 32); - debounced(); - debounced(); - debounced(); + debounced(); + debounced(); + debounced(); - assert.strictEqual(callCount, 0); + assert.strictEqual(callCount, 0); - setTimeout(function() { - assert.strictEqual(callCount, 1); - done(); - }, 96); - } - else { - skipTest(assert, 2); + setTimeout(function() { + assert.strictEqual(callCount, 1); done(); - } + }, 96); }); QUnit.test('subsequent debounced calls return the last `func` result', function(assert) { @@ -3352,23 +3337,17 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var debounced = _.debounce(identity, 32); - debounced('x'); + var debounced = _.debounce(identity, 32); + debounced('x'); - setTimeout(function() { - assert.notEqual(debounced('y'), 'y'); - }, 64); + setTimeout(function() { + assert.notEqual(debounced('y'), 'y'); + }, 64); - setTimeout(function() { - assert.notEqual(debounced('z'), 'z'); - done(); - }, 128); - } - else { - skipTest(assert, 2); + setTimeout(function() { + assert.notEqual(debounced('z'), 'z'); done(); - } + }, 128); }); QUnit.test('subsequent "immediate" debounced calls return the last `func` result', function(assert) { @@ -3376,22 +3355,16 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var debounced = _.debounce(identity, 32, { 'leading': true, 'trailing': false }), - result = [debounced('x'), debounced('y')]; + var debounced = _.debounce(identity, 32, { 'leading': true, 'trailing': false }), + result = [debounced('x'), debounced('y')]; - assert.deepEqual(result, ['x', 'x']); + assert.deepEqual(result, ['x', 'x']); - setTimeout(function() { - var result = [debounced('a'), debounced('b')]; - assert.deepEqual(result, ['a', 'a']); - done(); - }, 64); - } - else { - skipTest(assert, 2); + setTimeout(function() { + var result = [debounced('a'), debounced('b')]; + assert.deepEqual(result, ['a', 'a']); done(); - } + }, 64); }); QUnit.test('should apply default options', function(assert) { @@ -3399,25 +3372,19 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var callCount = 0; + var callCount = 0; - var debounced = _.debounce(function(value) { - callCount++; - return value; - }, 32, {}); + var debounced = _.debounce(function(value) { + callCount++; + return value; + }, 32, {}); - assert.strictEqual(debounced('a'), undefined); + assert.strictEqual(debounced('a'), undefined); - setTimeout(function() { - assert.strictEqual(callCount, 1); - done(); - }, 64); - } - else { - skipTest(assert, 2); + setTimeout(function() { + assert.strictEqual(callCount, 1); done(); - } + }, 64); }); QUnit.test('should support a `leading` option', function(assert) { @@ -3425,41 +3392,35 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var callCounts = [0, 0]; + var callCounts = [0, 0]; - var withLeading = _.debounce(function(value) { - callCounts[0]++; - return value; - }, 32, { 'leading': true }); + var withLeading = _.debounce(function(value) { + callCounts[0]++; + return value; + }, 32, { 'leading': true }); - assert.strictEqual(withLeading('a'), 'a'); + assert.strictEqual(withLeading('a'), 'a'); - var withoutLeading = _.debounce(identity, 32, { 'leading': false }); - assert.strictEqual(withoutLeading('a'), undefined); + var withoutLeading = _.debounce(identity, 32, { 'leading': false }); + assert.strictEqual(withoutLeading('a'), undefined); - var withLeadingAndTrailing = _.debounce(function() { - callCounts[1]++; - }, 32, { 'leading': true }); + var withLeadingAndTrailing = _.debounce(function() { + callCounts[1]++; + }, 32, { 'leading': true }); - withLeadingAndTrailing(); - withLeadingAndTrailing(); + withLeadingAndTrailing(); + withLeadingAndTrailing(); - assert.strictEqual(callCounts[1], 1); + assert.strictEqual(callCounts[1], 1); - setTimeout(function() { - assert.deepEqual(callCounts, [1, 2]); + setTimeout(function() { + assert.deepEqual(callCounts, [1, 2]); - withLeading('a'); - assert.strictEqual(callCounts[0], 2); + withLeading('a'); + assert.strictEqual(callCounts[0], 2); - done(); - }, 64); - } - else { - skipTest(assert, 5); done(); - } + }, 64); }); QUnit.test('should support a `trailing` option', function(assert) { @@ -3467,33 +3428,27 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var withCount = 0, - withoutCount = 0; + var withCount = 0, + withoutCount = 0; - var withTrailing = _.debounce(function(value) { - withCount++; - return value; - }, 32, { 'trailing': true }); + var withTrailing = _.debounce(function(value) { + withCount++; + return value; + }, 32, { 'trailing': true }); - var withoutTrailing = _.debounce(function(value) { - withoutCount++; - return value; - }, 32, { 'trailing': false }); + var withoutTrailing = _.debounce(function(value) { + withoutCount++; + return value; + }, 32, { 'trailing': false }); - assert.strictEqual(withTrailing('a'), undefined); - assert.strictEqual(withoutTrailing('a'), undefined); + assert.strictEqual(withTrailing('a'), undefined); + assert.strictEqual(withoutTrailing('a'), undefined); - setTimeout(function() { - assert.strictEqual(withCount, 1); - assert.strictEqual(withoutCount, 0); - done(); - }, 64); - } - else { - skipTest(assert, 4); + setTimeout(function() { + assert.strictEqual(withCount, 1); + assert.strictEqual(withoutCount, 0); done(); - } + }, 64); }); QUnit.test('should support a `maxWait` option', function(assert) { @@ -3501,35 +3456,29 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var limit = (argv || isPhantom) ? 1000 : 320, - withCount = 0, - withoutCount = 0; + var limit = (argv || isPhantom) ? 1000 : 320, + withCount = 0, + withoutCount = 0; - var withMaxWait = _.debounce(function() { - withCount++; - }, 64, { 'maxWait': 128 }); + var withMaxWait = _.debounce(function() { + withCount++; + }, 64, { 'maxWait': 128 }); - var withoutMaxWait = _.debounce(function() { - withoutCount++; - }, 96); + var withoutMaxWait = _.debounce(function() { + withoutCount++; + }, 96); - var start = +new Date; - while ((new Date - start) < limit) { - withMaxWait(); - withoutMaxWait(); - } - var actual = [Boolean(withCount), Boolean(withoutCount)]; - - setTimeout(function() { - assert.deepEqual(actual, [true, false]); - done(); - }, 1); + var start = +new Date; + while ((new Date - start) < limit) { + withMaxWait(); + withoutMaxWait(); } - else { - skipTest(assert); + var actual = [Boolean(withCount), Boolean(withoutCount)]; + + setTimeout(function() { + assert.deepEqual(actual, [true, false]); done(); - } + }, 1); }); QUnit.test('should cancel `maxDelayed` when `delayed` is invoked', function(assert) { @@ -3537,24 +3486,18 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var callCount = 0; + var callCount = 0; - var debounced = _.debounce(function() { - callCount++; - }, 32, { 'maxWait': 64 }); + var debounced = _.debounce(function() { + callCount++; + }, 32, { 'maxWait': 64 }); - debounced(); + debounced(); - setTimeout(function() { - assert.strictEqual(callCount, 1); - done(); - }, 128); - } - else { - skipTest(assert); + setTimeout(function() { + assert.strictEqual(callCount, 1); done(); - } + }, 128); }); QUnit.test('should invoke the `trailing` call with the correct arguments and `this` binding', function(assert) { @@ -3562,32 +3505,26 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var actual, - callCount = 0, - object = {}; + var actual, + callCount = 0, + object = {}; - var debounced = _.debounce(function(value) { - actual = [this]; - push.apply(actual, arguments); - return ++callCount != 2; - }, 32, { 'leading': true, 'maxWait': 64 }); + var debounced = _.debounce(function(value) { + actual = [this]; + push.apply(actual, arguments); + return ++callCount != 2; + }, 32, { 'leading': true, 'maxWait': 64 }); - while (true) { - if (!debounced.call(object, 'a')) { - break; - } + while (true) { + if (!debounced.call(object, 'a')) { + break; } - setTimeout(function() { - assert.strictEqual(callCount, 2); - assert.deepEqual(actual, [object, 'a']); - done(); - }, 64); } - else { - skipTest(assert, 2); + setTimeout(function() { + assert.strictEqual(callCount, 2); + assert.deepEqual(actual, [object, 'a']); done(); - } + }, 64); }); }()); @@ -3765,19 +3702,13 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var pass = false; - _.defer(function() { pass = true; }); + var pass = false; + _.defer(function() { pass = true; }); - setTimeout(function() { - assert.ok(pass); - done(); - }, 32); - } - else { - skipTest(assert); + setTimeout(function() { + assert.ok(pass); done(); - } + }, 32); }); QUnit.test('should provide additional arguments to `func`', function(assert) { @@ -3785,22 +3716,16 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var args; + var args; - _.defer(function() { - args = slice.call(arguments); - }, 1, 2); + _.defer(function() { + args = slice.call(arguments); + }, 1, 2); - setTimeout(function() { - assert.deepEqual(args, [1, 2]); - done(); - }, 32); - } - else { - skipTest(assert); + setTimeout(function() { + assert.deepEqual(args, [1, 2]); done(); - } + }, 32); }); QUnit.test('should be cancelable', function(assert) { @@ -3808,24 +3733,18 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var pass = true; + var pass = true; - var timerId = _.defer(function() { - pass = false; - }); + var timerId = _.defer(function() { + pass = false; + }); - clearTimeout(timerId); + clearTimeout(timerId); - setTimeout(function() { - assert.ok(pass); - done(); - }, 32); - } - else { - skipTest(assert); + setTimeout(function() { + assert.ok(pass); done(); - } + }, 32); }); }()); @@ -3839,23 +3758,17 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var pass = false; - _.delay(function() { pass = true; }, 32); + var pass = false; + _.delay(function() { pass = true; }, 32); - setTimeout(function() { - assert.notOk(pass); - }, 1); + setTimeout(function() { + assert.notOk(pass); + }, 1); - setTimeout(function() { - assert.ok(pass); - done(); - }, 64); - } - else { - skipTest(assert, 2); + setTimeout(function() { + assert.ok(pass); done(); - } + }, 64); }); QUnit.test('should provide additional arguments to `func`', function(assert) { @@ -3863,22 +3776,16 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var args; + var args; - _.delay(function() { - args = slice.call(arguments); - }, 32, 1, 2); + _.delay(function() { + args = slice.call(arguments); + }, 32, 1, 2); - setTimeout(function() { - assert.deepEqual(args, [1, 2]); - done(); - }, 64); - } - else { - skipTest(assert); + setTimeout(function() { + assert.deepEqual(args, [1, 2]); done(); - } + }, 64); }); QUnit.test('should be cancelable', function(assert) { @@ -3886,24 +3793,18 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var pass = true; + var pass = true; - var timerId = _.delay(function() { - pass = false; - }, 32); + var timerId = _.delay(function() { + pass = false; + }, 32); - clearTimeout(timerId); + clearTimeout(timerId); - setTimeout(function() { - assert.ok(pass); - done(); - }, 64); - } - else { - skipTest(assert); + setTimeout(function() { + assert.ok(pass); done(); - } + }, 64); }); }()); @@ -13729,13 +13630,7 @@ if (!isModularize) { assert.strictEqual(_.noConflict(), oldDash); - - if (!(isRhino && typeof require == 'function')) { - assert.notStrictEqual(root._, oldDash); - } - else { - skipTest(assert); - } + assert.notStrictEqual(root._, oldDash); root._ = oldDash; } else { @@ -13779,16 +13674,10 @@ assert.ok(actual >= stamp); - if (!(isRhino && isModularize)) { - setTimeout(function() { - assert.ok(_.now() > actual); - done(); - }, 32); - } - else { - skipTest(assert); + setTimeout(function() { + assert.ok(_.now() > actual); done(); - } + }, 32); }); }()); @@ -19119,26 +19008,20 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var callCount = 0, - throttled = _.throttle(function() { callCount++; }, 32); + var callCount = 0, + throttled = _.throttle(function() { callCount++; }, 32); - throttled(); - throttled(); - throttled(); + throttled(); + throttled(); + throttled(); - var lastCount = callCount; - assert.ok(callCount > 0); + var lastCount = callCount; + assert.ok(callCount > 0); - setTimeout(function() { - assert.ok(callCount > lastCount); - done(); - }, 64); - } - else { - skipTest(assert, 2); + setTimeout(function() { + assert.ok(callCount > lastCount); done(); - } + }, 64); }); QUnit.test('subsequent calls should return the result of the first call', function(assert) { @@ -19146,26 +19029,20 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var throttled = _.throttle(identity, 32), - result = [throttled('a'), throttled('b')]; + var throttled = _.throttle(identity, 32), + result = [throttled('a'), throttled('b')]; - assert.deepEqual(result, ['a', 'a']); + assert.deepEqual(result, ['a', 'a']); - setTimeout(function() { - var result = [throttled('x'), throttled('y')]; - assert.notEqual(result[0], 'a'); - assert.notStrictEqual(result[0], undefined); + setTimeout(function() { + var result = [throttled('x'), throttled('y')]; + assert.notEqual(result[0], 'a'); + assert.notStrictEqual(result[0], undefined); - assert.notEqual(result[1], 'y'); - assert.notStrictEqual(result[1], undefined); - done(); - }, 64); - } - else { - skipTest(assert, 5); + assert.notEqual(result[1], 'y'); + assert.notStrictEqual(result[1], undefined); done(); - } + }, 64); }); QUnit.test('should clear timeout when `func` is called', function(assert) { @@ -19213,54 +19090,42 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var callCount = 0, - throttled = _.throttle(function() { callCount++; }, 32); + var callCount = 0, + throttled = _.throttle(function() { callCount++; }, 32); - throttled(); - assert.strictEqual(callCount, 1); + throttled(); + assert.strictEqual(callCount, 1); - setTimeout(function() { - assert.strictEqual(callCount, 1); - done(); - }, 64); - } - else { - skipTest(assert, 2); + setTimeout(function() { + assert.strictEqual(callCount, 1); done(); - } + }, 64); }); lodashStable.times(2, function(index) { QUnit.test('should trigger a call when invoked repeatedly' + (index ? ' and `leading` is `false`' : ''), function(assert) { - assert.expect(1); - - var done = assert.async(); + assert.expect(1); - if (!(isRhino && isModularize)) { - var callCount = 0, - limit = (argv || isPhantom) ? 1000 : 320, - options = index ? { 'leading': false } : {}; + var done = assert.async(); - var throttled = _.throttle(function() { - callCount++; - }, 32, options); + var callCount = 0, + limit = (argv || isPhantom) ? 1000 : 320, + options = index ? { 'leading': false } : {}; - var start = +new Date; - while ((new Date - start) < limit) { - throttled(); - } - var actual = callCount > 1; + var throttled = _.throttle(function() { + callCount++; + }, 32, options); - setTimeout(function() { - assert.ok(actual); - done(); - }, 1); + var start = +new Date; + while ((new Date - start) < limit) { + throttled(); } - else { - skipTest(assert); + var actual = callCount > 1; + + setTimeout(function() { + assert.ok(actual); done(); - } + }, 1); }); }); @@ -19269,41 +19134,30 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var callCount = 0; + var callCount = 0; - var throttled = _.throttle(function(value) { - callCount++; - return value; - }, 32, {}); + var throttled = _.throttle(function(value) { + callCount++; + return value; + }, 32, {}); - assert.strictEqual(throttled('a'), 'a'); - assert.strictEqual(throttled('b'), 'a'); + assert.strictEqual(throttled('a'), 'a'); + assert.strictEqual(throttled('b'), 'a'); - setTimeout(function() { - assert.strictEqual(callCount, 2); - done(); - }, 128); - } - else { - skipTest(assert, 3); + setTimeout(function() { + assert.strictEqual(callCount, 2); done(); - } + }, 128); }); QUnit.test('should support a `leading` option', function(assert) { assert.expect(2); - if (!(isRhino && isModularize)) { - var withLeading = _.throttle(identity, 32, { 'leading': true }); - assert.strictEqual(withLeading('a'), 'a'); + var withLeading = _.throttle(identity, 32, { 'leading': true }); + assert.strictEqual(withLeading('a'), 'a'); - var withoutLeading = _.throttle(identity, 32, { 'leading': false }); - assert.strictEqual(withoutLeading('a'), undefined); - } - else { - skipTest(assert, 2); - } + var withoutLeading = _.throttle(identity, 32, { 'leading': false }); + assert.strictEqual(withoutLeading('a'), undefined); }); QUnit.test('should support a `trailing` option', function(assert) { @@ -19311,36 +19165,30 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var withCount = 0, - withoutCount = 0; + var withCount = 0, + withoutCount = 0; - var withTrailing = _.throttle(function(value) { - withCount++; - return value; - }, 64, { 'trailing': true }); + var withTrailing = _.throttle(function(value) { + withCount++; + return value; + }, 64, { 'trailing': true }); - var withoutTrailing = _.throttle(function(value) { - withoutCount++; - return value; - }, 64, { 'trailing': false }); + var withoutTrailing = _.throttle(function(value) { + withoutCount++; + return value; + }, 64, { 'trailing': false }); - assert.strictEqual(withTrailing('a'), 'a'); - assert.strictEqual(withTrailing('b'), 'a'); + assert.strictEqual(withTrailing('a'), 'a'); + assert.strictEqual(withTrailing('b'), 'a'); - assert.strictEqual(withoutTrailing('a'), 'a'); - assert.strictEqual(withoutTrailing('b'), 'a'); + assert.strictEqual(withoutTrailing('a'), 'a'); + assert.strictEqual(withoutTrailing('b'), 'a'); - setTimeout(function() { - assert.strictEqual(withCount, 2); - assert.strictEqual(withoutCount, 1); - done(); - }, 256); - } - else { - skipTest(assert, 6); + setTimeout(function() { + assert.strictEqual(withCount, 2); + assert.strictEqual(withoutCount, 1); done(); - } + }, 256); }); QUnit.test('should not update `lastCalled`, at the end of the timeout, when `trailing` is `false`', function(assert) { @@ -19348,30 +19196,24 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var callCount = 0; + var callCount = 0; - var throttled = _.throttle(function() { - callCount++; - }, 64, { 'trailing': false }); + var throttled = _.throttle(function() { + callCount++; + }, 64, { 'trailing': false }); + throttled(); + throttled(); + + setTimeout(function() { throttled(); throttled(); + }, 96); - setTimeout(function() { - throttled(); - throttled(); - }, 96); - - setTimeout(function() { - assert.ok(callCount > 1); - done(); - }, 192); - } - else { - skipTest(assert); + setTimeout(function() { + assert.ok(callCount > 1); done(); - } + }, 192); }); }()); @@ -19401,25 +19243,19 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var callCount = 0; + var callCount = 0; - var funced = func(function() { - callCount++; - }); + var funced = func(function() { + callCount++; + }); - funced(); + funced(); - setTimeout(function() { - funced(); - assert.strictEqual(callCount, isDebounce ? 1 : 2); - done(); - }, 32); - } - else { - skipTest(assert); + setTimeout(function() { + funced(); + assert.strictEqual(callCount, isDebounce ? 1 : 2); done(); - } + }, 32); }); QUnit.test('_.' + methodName + ' should invoke `func` with the correct `this` binding', function(assert) { @@ -19427,27 +19263,21 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var object = { - 'funced': func(function() { actual.push(this); }, 32) - }; + var object = { + 'funced': func(function() { actual.push(this); }, 32) + }; - var actual = [], - expected = lodashStable.times(isDebounce ? 1 : 2, lodashStable.constant(object)); + var actual = [], + expected = lodashStable.times(isDebounce ? 1 : 2, lodashStable.constant(object)); + object.funced(); + if (!isDebounce) { object.funced(); - if (!isDebounce) { - object.funced(); - } - setTimeout(function() { - assert.deepEqual(actual, expected); - done(); - }, 64); } - else { - skipTest(assert); + setTimeout(function() { + assert.deepEqual(actual, expected); done(); - } + }, 64); }); QUnit.test('_.' + methodName + ' supports recursive calls', function(assert) { @@ -19455,36 +19285,30 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var actual = [], - args = lodashStable.map(['a', 'b', 'c'], function(chr) { return [{}, chr]; }), - expected = args.slice(), - queue = args.slice(); - - var funced = func(function() { - var current = [this]; - push.apply(current, arguments); - actual.push(current); - - var next = queue.shift(); - if (next) { - funced.call(next[0], next[1]); - } - }, 32); + var actual = [], + args = lodashStable.map(['a', 'b', 'c'], function(chr) { return [{}, chr]; }), + expected = args.slice(), + queue = args.slice(); + + var funced = func(function() { + var current = [this]; + push.apply(current, arguments); + actual.push(current); var next = queue.shift(); - funced.call(next[0], next[1]); - assert.deepEqual(actual, expected.slice(0, isDebounce ? 0 : 1)); + if (next) { + funced.call(next[0], next[1]); + } + }, 32); - setTimeout(function() { - assert.deepEqual(actual, expected.slice(0, actual.length)); - done(); - }, 256); - } - else { - skipTest(assert, 2); + var next = queue.shift(); + funced.call(next[0], next[1]); + assert.deepEqual(actual, expected.slice(0, isDebounce ? 0 : 1)); + + setTimeout(function() { + assert.deepEqual(actual, expected.slice(0, actual.length)); done(); - } + }, 256); }); QUnit.test('_.' + methodName + ' should work if the system time is set backwards', function(assert) { @@ -19531,25 +19355,19 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var callCount = 0; + var callCount = 0; - var funced = func(function() { - callCount++; - }, 32, { 'leading': false }); + var funced = func(function() { + callCount++; + }, 32, { 'leading': false }); - funced(); - funced.cancel(); + funced(); + funced.cancel(); - setTimeout(function() { - assert.strictEqual(callCount, 0); - done(); - }, 64); - } - else { - skipTest(assert); + setTimeout(function() { + assert.strictEqual(callCount, 0); done(); - } + }, 64); }); QUnit.test('_.' + methodName + ' should reset `lastCalled` after cancelling', function(assert) { @@ -19557,26 +19375,20 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var callCount = 0; + var callCount = 0; - var funced = func(function() { - return ++callCount; - }, 32, { 'leading': true }); + var funced = func(function() { + return ++callCount; + }, 32, { 'leading': true }); - assert.strictEqual(funced(), 1); - funced.cancel(); - assert.strictEqual(funced(), 2); + assert.strictEqual(funced(), 1); + funced.cancel(); + assert.strictEqual(funced(), 2); - setTimeout(function() { - assert.strictEqual(callCount, 2); - done(); - }, 64); - } - else { - skipTest(assert, 3); + setTimeout(function() { + assert.strictEqual(callCount, 2); done(); - } + }, 64); }); QUnit.test('_.' + methodName + ' should support flushing delayed calls', function(assert) { @@ -19584,26 +19396,20 @@ var done = assert.async(); - if (!(isRhino && isModularize)) { - var callCount = 0; + var callCount = 0; - var funced = func(function() { - return ++callCount; - }, 32, { 'leading': false }); + var funced = func(function() { + return ++callCount; + }, 32, { 'leading': false }); - funced(); - var actual = funced.flush(); + funced(); + var actual = funced.flush(); - setTimeout(function() { - assert.strictEqual(actual, 1); - assert.strictEqual(callCount, 1); - done(); - }, 64); - } - else { - skipTest(assert, 2); + setTimeout(function() { + assert.strictEqual(actual, 1); + assert.strictEqual(callCount, 1); done(); - } + }, 64); }); }); From 9bcbcc5293d6a34fa6af6014ff58da7b2f06ab9d Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sun, 29 Nov 2015 17:00:45 -0600 Subject: [PATCH 705/935] Ensure `_.clone` handles generators correctly. --- lodash.js | 2 +- test/test.js | 34 ++++++++++++++++++---------------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/lodash.js b/lodash.js index 651df4e5a4..9cd66e6549 100644 --- a/lodash.js +++ b/lodash.js @@ -2262,7 +2262,7 @@ } } else { var tag = getTag(value), - isFunc = tag == funcTag; + isFunc = tag == funcTag || tag == genTag; if (tag == objectTag || tag == argsTag || (isFunc && !object)) { if (isHostObject(value)) { diff --git a/test/test.js b/test/test.js index 8c6804c07e..4c3d37e5ca 100644 --- a/test/test.js +++ b/test/test.js @@ -226,6 +226,11 @@ /** Used to restore the `_` reference. */ var oldDash = root._; + /** Used to test generator functions. */ + var generator = lodashStable.attempt(function() { + return Function('return function*(){}'); + }); + /** List of latin-1 supplementary letters to basic latin letters. */ var burredLetters = [ '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7', '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', @@ -2219,7 +2224,8 @@ var uncloneable = { 'DOM elements': body, - 'functions': Foo + 'functions': Foo, + 'generators': generator }; lodashStable.each(errors, function(error) { @@ -2452,14 +2458,18 @@ QUnit.test('`_.' + methodName + '` should not clone ' + key, function(assert) { assert.expect(3); - var object = { 'a': value, 'b': { 'c': value } }, - actual = func(object); + if (value) { + var object = { 'a': value, 'b': { 'c': value } }, + actual = func(object), + expected = (typeof value == 'function' && !!value.c) ? { 'c': Foo.c } : {}; - assert.deepEqual(actual, object); - assert.notStrictEqual(actual, object); - - var expected = typeof value == 'function' ? { 'c': Foo.c } : (value && {}); - assert.deepEqual(func(value), expected); + assert.deepEqual(actual, object); + assert.notStrictEqual(actual, object); + assert.deepEqual(func(value), expected); + } + else { + skipTest(assert, 3); + } }); }); }); @@ -7300,10 +7310,6 @@ QUnit.test('should return `false` for non-arrays', function(assert) { assert.expect(10); - var generator = lodashStable.attempt(function() { - return Function('return function*(){}'); - }); - var expected = lodashStable.map(falsey, function(value) { return value === ''; }); @@ -8526,10 +8532,6 @@ QUnit.test('should return `true` for generator functions', function(assert) { assert.expect(1); - var generator = lodashStable.attempt(function() { - return Function('return function*(){}'); - }); - assert.strictEqual(_.isFunction(generator), typeof generator == 'function'); }); From 562b04a763fdfabb1a7502691f754ba27ca33120 Mon Sep 17 00:00:00 2001 From: Brian Mock Date: Sun, 29 Nov 2015 15:18:12 -0800 Subject: [PATCH 706/935] Update email address in CoC. [ci skip] --- CODE_OF_CONDUCT.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 2024847f05..ec7efa06ab 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -35,12 +35,11 @@ This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting a project maintainer at [INSERT EMAIL ADDRESS]. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. Maintainers are -obligated to maintain confidentiality with regard to the reporter of an -incident. - +reported by contacting a project maintainer at +[coc@lodash.com](mailto:coc@lodash.com). All complaints will be reviewed and +investigated and will result in a response that is deemed necessary and +appropriate to the circumstances. Maintainers are obligated to maintain +confidentiality with regard to the reporter of an incident. This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.3.0, available at From f4467f6033e58f0e5555895d986398e3ebdaf332 Mon Sep 17 00:00:00 2001 From: greenkeeperio-bot Date: Mon, 30 Nov 2015 08:27:49 -0800 Subject: [PATCH 707/935] Update sauce-tunnel to 2.3.0. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e5ec1d67f4..5555fb4a25 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "qunitjs": "~1.20.0", "request": "^2.67.0", "requirejs": "~2.1.22", - "sauce-tunnel": "2.2.3", + "sauce-tunnel": "2.3.0", "uglify-js": "2.6.1", "webpack": "^1.12.9" }, From 8154e5e521bb5238699925919ad2cbdd3a511910 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Mon, 30 Nov 2015 20:18:08 -0800 Subject: [PATCH 708/935] Fix argument juggling. --- lib/common/minify.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/common/minify.js b/lib/common/minify.js index cf30679be1..3872707425 100644 --- a/lib/common/minify.js +++ b/lib/common/minify.js @@ -9,9 +9,12 @@ var uglifyOptions = require('./uglify.options.js'); /*----------------------------------------------------------------------------*/ function minify(inpath, outpath, callback, options) { - if (typeof outpath == 'function') { + if (_.isFunction(outpath)) { + if (_.isObject(callback)) { + options = callback; + } + callback = outpath; outpath = undefined; - callback = options; } if (!outpath) { outpath = inpath.replace(/(?=\.js$)/, '.min'); From 230e8d07878e1f12769d2028ad3cb4d6f0b6ad79 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Mon, 30 Nov 2015 20:19:56 -0800 Subject: [PATCH 709/935] Make build expose fp mapping in the dist. --- lib/fp/build.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/fp/build.js b/lib/fp/build.js index daf160a342..f4c5237ca0 100644 --- a/lib/fp/build.js +++ b/lib/fp/build.js @@ -10,11 +10,10 @@ var minify = require('../common/minify.js'); var basePath = path.join(__dirname, '..', '..'), distPath = path.join(basePath, 'dist'), - entryPath = path.join(__dirname, 'bower.js'), filename = 'lodash.fp.js'; -var webpackConfig = { - 'entry': entryPath, +var fpConfig = { + 'entry': path.join(__dirname, 'bower.js'), 'output': { 'path': distPath, 'filename': filename, @@ -27,6 +26,16 @@ var webpackConfig = { ] }; +var mappingConfig = { + 'entry': path.join(__dirname, 'mapping.js'), + 'output': { + 'path': distPath, + 'filename': 'fp-mapping.js', + 'library': 'mapping', + 'libraryTarget': 'umd' + } +}; + /*----------------------------------------------------------------------------*/ function onComplete(error) { @@ -36,6 +45,7 @@ function onComplete(error) { } async.series([ - _.partial(webpack, webpackConfig), + _.partial(webpack, mappingConfig), + _.partial(webpack, fpConfig), _.partial(minify, path.join(distPath, filename)) ], onComplete); From 3d43cc102975ffe356ff11122f375110301b5c83 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Tue, 1 Dec 2015 10:05:42 -0800 Subject: [PATCH 710/935] Use "IE" instead of "Internet Explorer" in comment. [ci skip] --- lodash.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lodash.js b/lodash.js index 9cd66e6549..9c91ab191c 100644 --- a/lodash.js +++ b/lodash.js @@ -11796,8 +11796,8 @@ * Converts the characters "&", "<", ">", '"', "'", and "\`" in `string` to * their corresponding HTML entities. * - * **Note:** No other characters are escaped. To escape additional characters - * use a third-party library like [_he_](https://mths.be/he). + * **Note:** No other characters are escaped. To escape additional + * characters use a third-party library like [_he_](https://mths.be/he). * * Though the ">" character is escaped for symmetry, characters like * ">" and "/" don't need escaping in HTML and have no special meaning @@ -11805,8 +11805,8 @@ * See [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands) * (under "semi-related fun fact") for more details. * - * Backticks are escaped because in Internet Explorer < 9, they can break out - * of attribute values or HTML comments. See [#59](https://html5sec.org/#59), + * Backticks are escaped because in IE < 9, they can break out of + * attribute values or HTML comments. See [#59](https://html5sec.org/#59), * [#102](https://html5sec.org/#102), [#108](https://html5sec.org/#108), and * [#133](https://html5sec.org/#133) of the [HTML5 Security Cheatsheet](https://html5sec.org/) * for more details. From 1ae6e67cdcaee549f62ec51c43b245a75bc914f4 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Wed, 2 Dec 2015 21:42:51 -0800 Subject: [PATCH 711/935] Add `_.rangeRight`. --- lodash.js | 47 ++++++++++++++++++++++++++++++++++------------- test/test.js | 5 +++-- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/lodash.js b/lodash.js index 9c91ab191c..22c3e342c7 100644 --- a/lodash.js +++ b/lodash.js @@ -3247,6 +3247,33 @@ return min + nativeFloor(nativeRandom() * (max - min + 1)); } + function baseRange(start, end, step, fromRight) { + start = toNumber(start); + start = start === start ? start : 0; + + if (end === undefined) { + end = start; + start = 0; + } else { + end = toNumber(end) || 0; + } + step = step === undefined ? (start < end ? 1 : -1) : (toNumber(step) || 0); + + var index = -1, + length = nativeMax(nativeCeil((end - start) / (step || 1)), 0), + result = Array(length); + + while (++index < length) { + if (fromRight) { + result[index] = (end -= step); + } else { + result[index] = start; + start+= step; + } + } + return result; + } + /** * The base implementation of `_.set`. * @@ -13279,21 +13306,14 @@ if (step && isIterateeCall(start, end, step)) { end = step = undefined; } - start = toNumber(start); - start = start === start ? start : 0; + return baseRange(start, end, step); + } - if (end === undefined) { - end = start; - start = 0; - } else { - end = toNumber(end) || 0; + function rangeRight(start, end, step) { + if (step && isIterateeCall(start, end, step)) { + end = step = undefined; } - step = step === undefined ? (start < end ? 1 : -1) : (toNumber(step) || 0); - - var n = nativeMax(nativeCeil((end - start) / (step || 1)), 0); - return baseTimes(n, function(index) { - return index ? (start += step) : start; - }); + return baseRange(start, end, step, true); } /** @@ -13795,6 +13815,7 @@ lodash.pullAllBy = pullAllBy; lodash.pullAt = pullAt; lodash.range = range; + lodash.rangeRight = rangeRight; lodash.rearg = rearg; lodash.reject = reject; lodash.remove = remove; diff --git a/test/test.js b/test/test.js index 4c3d37e5ca..07d81681d7 100644 --- a/test/test.js +++ b/test/test.js @@ -22570,6 +22570,7 @@ 'pullAll', 'pullAt', 'range', + 'rangeRight', 'reject', 'remove', 'sampleSize', @@ -22592,7 +22593,7 @@ var acceptFalsey = lodashStable.difference(allMethods, rejectFalsey); QUnit.test('should accept falsey arguments', function(assert) { - assert.expect(282); + assert.expect(284); var emptyArrays = lodashStable.map(falsey, lodashStable.constant([])); @@ -22630,7 +22631,7 @@ }); QUnit.test('should return an array', function(assert) { - assert.expect(68); + assert.expect(70); var array = [1, 2, 3]; From 1cbb6f1405c40a565255bd518bf19dc77a62e8b5 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 3 Dec 2015 11:54:27 -0800 Subject: [PATCH 712/935] Add doc note to `_.includes` about string values. [ci skip] --- lodash.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lodash.js b/lodash.js index 22c3e342c7..f9ed24b4fe 100644 --- a/lodash.js +++ b/lodash.js @@ -7483,10 +7483,10 @@ }); /** - * Checks if `value` is in `collection` using - * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) - * for equality comparisons. If `fromIndex` is negative, it's used as the offset - * from the end of `collection`. + * Checks if `value` is in `collection`. If `collection` is a string it's checked + * for a substring of `value`, otherwise [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) + * is used for equality comparisons. If `fromIndex` is negative, it's used as + * the offset from the end of `collection`. * * @static * @memberOf _ From 81e39f7c4b25c06687cb4d7a35548e52acfb503b Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 3 Dec 2015 17:59:46 -0800 Subject: [PATCH 713/935] Add `_.rangeRight` docs. [ci skip] --- lodash.js | 58 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/lodash.js b/lodash.js index f9ed24b4fe..e329ac0c32 100644 --- a/lodash.js +++ b/lodash.js @@ -1517,10 +1517,10 @@ * `methodOf`, `mixin`, `modArgs`, `modArgsSet', `negate`, `nthArg`, `omit`, * `omitBy`, `once`, `over`, `overEvery`, `overSome`, `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`, + * `pullAll`, `pullAllBy`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, + * `reject`, `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, + * `shuffle`, `slice`, `sort`, `sortBy`, `sortByOrder`, `splice`, `spread`, + * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, `tap`, `throttle`, * `thru`, `toArray`, `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, * `transform`, `unary`, `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, * `uniqWith`, `unset`, `unshift`, `unzip`, `unzipWith`, `values`, `valuesIn`, @@ -3247,6 +3247,16 @@ return min + nativeFloor(nativeRandom() * (max - min + 1)); } + /** + * The base implementation of `_.range` and `_.rangeRight`. + * + * @private + * @param {number} [start=0] The start of the range. + * @param {number} end The end of the range. + * @param {number} [step=1] The value to increment or decrement by. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Array} Returns the new array of numbers. + */ function baseRange(start, end, step, fromRight) { start = toNumber(start); start = start === start ? start : 0; @@ -3268,7 +3278,7 @@ result[index] = (end -= step); } else { result[index] = start; - start+= step; + start += step; } } return result; @@ -7599,8 +7609,8 @@ * * The guarded methods are: * `ary`, `curry`, `curryRight`, `drop`, `dropRight`, `every`, `fill`, - * `invert`, `parseInt`, `random`, `range`, `slice`, `some`, `sortBy`, - * `take`, `takeRight`, `template`, `trim`, `trimEnd`, `trimStart`, + * `invert`, `parseInt`, `random`, `range`, `rangeRight`, `slice`, `some`, + * `sortBy`, `take`, `takeRight`, `template`, `trim`, `trimEnd`, `trimStart`, * and `words` * * @static @@ -13309,6 +13319,40 @@ return baseRange(start, end, step); } + /** + * This method is like `_.range` except that it populates values in + * descending order. + * + * @static + * @memberOf _ + * @category Utility + * @param {number} [start=0] The start of the range. + * @param {number} end The end of the range. + * @param {number} [step=1] The value to increment or decrement by. + * @returns {Array} Returns the new array of numbers. + * @example + * + * _.rangeRight(4); + * // => [3, 2, 1, 0] + * + * _.rangeRight(-4); + * // => [-3, -2, -1, 0] + * + * _.rangeRight(1, 5); + * // => [4, 3, 2, 1] + * + * _.rangeRight(0, 20, 5); + * // => [15, 10, 5, 0] + * + * _.rangeRight(0, -4, -1); + * // => [-3, -2, -1, 0] + * + * _.rangeRight(1, 4, 0); + * // => [4, 4, 4] + * + * _.rangeRight(0); + * // => [] + */ function rangeRight(start, end, step) { if (step && isIterateeCall(start, end, step)) { end = step = undefined; From dc136cbf314de5ea75e308a51c6a4fc11491d778 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 3 Dec 2015 18:00:00 -0800 Subject: [PATCH 714/935] Remove perf/run-perf.sh. --- perf/run-perf.sh | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100755 perf/run-perf.sh diff --git a/perf/run-perf.sh b/perf/run-perf.sh deleted file mode 100755 index eaa63ae4c4..0000000000 --- a/perf/run-perf.sh +++ /dev/null @@ -1,14 +0,0 @@ -cd "$(dirname "$0")" - -echo "Running performance suite in node..." -node perf.js ../lodash.js && node perf.js ../lodash.min.js - -for cmd in rhino "rhino -require" narwhal ringo phantomjs; do - echo "" - echo "Running performance suite in $cmd..." - $cmd perf.js ../lodash.min.js -done - -echo "" -echo "Running performance suite in a browser..." -open index.html From 58736f743e0f0afa3db66a024bd203b42e68b713 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 3 Dec 2015 18:00:38 -0800 Subject: [PATCH 715/935] Add `rangeRight` to fp mapping. --- lib/fp/mapping.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/fp/mapping.js b/lib/fp/mapping.js index 181e554250..f7e4ad0795 100644 --- a/lib/fp/mapping.js +++ b/lib/fp/mapping.js @@ -85,11 +85,11 @@ module.exports = { 'forOwn,forOwnRight,get,groupBy,includes,indexBy,indexOf,intersection,' + 'invoke,invokeMap,isMatch,lastIndexOf,map,mapKeys,mapValues,matchesProperty,' + 'maxBy,mean,minBy,merge,modArgs,modArgsSet,omit,pad,padLeft,padRight,parseInt,' + - 'partition,pick,pull,pullAll,pullAt,random,range,rearg,reject,remove,repeat,' + - 'result,sampleSize,set,some,sortBy,sortByOrder,sortedIndexBy,sortedLastIndexBy,' + - 'sortedUniqBy,startsWith,subtract,sumBy,take,takeRight,takeRightWhile,' + - 'takeWhile,throttle,times,truncate,union,uniqBy,without,wrap,xor,zip,' + - 'zipObject').split(','), + 'partition,pick,pull,pullAll,pullAt,random,range,rangeRight,rearg,reject,' + + 'remove,repeat,result,sampleSize,set,some,sortBy,sortByOrder,sortedIndexBy,' + + 'sortedLastIndexBy,sortedUniqBy,startsWith,subtract,sumBy,take,takeRight,' + + 'takeRightWhile,takeWhile,throttle,times,truncate,union,uniqBy,without,wrap,' + + 'xor,zip,zipObject').split(','), 3: ( 'assignWith,clamp,differenceBy,extendWith,getOr,inRange,intersectionBy,' + 'isEqualWith,isMatchWith,mergeWith,omitBy,pickBy,pullAllBy,reduce,' + @@ -153,6 +153,7 @@ module.exports = { 'matchesProperty': true, 'random': true, 'range': true, + 'rangeRight': true, 'zip': true, 'zipObject': true } From 229f0b48cd71427056a45bb1f1986011ffd67756 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 3 Dec 2015 18:01:34 -0800 Subject: [PATCH 716/935] Update perf/perf.js to correctly load libs when running from the command line. --- perf/perf.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/perf/perf.js b/perf/perf.js index 40f743b706..353f2cfc46 100644 --- a/perf/perf.js +++ b/perf/perf.js @@ -101,6 +101,12 @@ lodash.noConflict() )); + /** Load Underscore. */ + var _ = root.underscore || (root.underscore = ( + _ = load('../vendor/underscore/underscore.js') || root._, + _._ || _ + )); + /** Load Benchmark.js. */ var Benchmark = root.Benchmark || (root.Benchmark = ( Benchmark = load('../vendor/benchmark.js/benchmark.js') || root.Benchmark, @@ -108,12 +114,6 @@ Benchmark.runInContext(lodash.extend({}, root, { '_': lodash })) )); - /** Load Underscore. */ - var _ = root._ || (root._ = ( - _ = load('../vendor/underscore/underscore.js') || root._, - _._ || _ - )); - /*--------------------------------------------------------------------------*/ /** @@ -281,7 +281,7 @@ lodash.extend(Benchmark.options, { 'async': true, 'setup': '\ - var _ = global._,\ + var _ = global.underscore,\ lodash = global.lodash,\ belt = this.name == buildName ? lodash : _;\ \ @@ -348,8 +348,8 @@ square = function(v) { return v * v; };\ \ var largeArray = belt.range(10000),\ - _chaining = _.chain ? _(largeArray).chain() : _(largeArray),\ - lodashChaining = lodash(largeArray);\ + _chaining = _(largeArray).chain(),\ + lodashChaining = lodash(largeArray).chain();\ }\ if (typeof compact != "undefined") {\ var uncompacted = numbers.slice();\ From 19500d36c7b9da8a56c29d4f9cbe97e9dfd36d0f Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 3 Dec 2015 18:49:04 -0800 Subject: [PATCH 717/935] Avoid fails in `flowRight` setup. --- perf/perf.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/perf/perf.js b/perf/perf.js index 353f2cfc46..5ac64ee663 100644 --- a/perf/perf.js +++ b/perf/perf.js @@ -362,8 +362,8 @@ compAddTwo = function(n) { return n + 2; },\ compAddThree = function(n) { return n + 3; };\ \ - var _composed = _.flowRight(compAddThree, compAddTwo, compAddOne),\ - lodashComposed = lodash.flowRight(compAddThree, compAddTwo, compAddOne);\ + var _composed = _.flowRight && _.flowRight(compAddThree, compAddTwo, compAddOne),\ + lodashComposed = lodash.flowRight && lodash.flowRight(compAddThree, compAddTwo, compAddOne);\ }\ if (typeof countBy != "undefined" || typeof omit != "undefined") {\ var wordToNumber = {\ From 39192ad3885528f1c0a2bd6c0f6e22f9c6e700cb Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 3 Dec 2015 22:36:33 -0800 Subject: [PATCH 718/935] Shorten flag vars. --- test/test.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/test.js b/test/test.js index 07d81681d7..6bd08cc415 100644 --- a/test/test.js +++ b/test/test.js @@ -2476,7 +2476,7 @@ lodashStable.each(['cloneWith', 'cloneDeepWith'], function(methodName) { var func = _[methodName], - isDeepWith = methodName == 'cloneDeepWith'; + isDeep = methodName == 'cloneDeepWith'; QUnit.test('`_.' + methodName + '` should provide the correct `customizer` arguments', function(assert) { assert.expect(1); @@ -2491,7 +2491,7 @@ argsList.push(args); }); - assert.deepEqual(argsList, isDeepWith ? [[foo], [1, 'a', foo]] : [[foo]]); + assert.deepEqual(argsList, isDeep ? [[foo], [1, 'a', foo]] : [[foo]]); }); QUnit.test('`_.' + methodName + '` should handle cloning if `customizer` returns `undefined`', function(assert) { @@ -20854,16 +20854,16 @@ lodashStable.each(['uniqBy', 'sortedUniqBy'], function(methodName) { var func = _[methodName], - isSortedUniqBy = methodName == 'sortedUniqBy', + isSorted = methodName == 'sortedUniqBy', objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }, { 'a': 2 }, { 'a': 3 }, { 'a': 1 }]; - if (isSortedUniqBy) { + if (isSorted) { objects = _.sortBy(objects, 'a'); } QUnit.test('`_.' + methodName + '` should work with an `iteratee` argument', function(assert) { assert.expect(1); - var expected = isSortedUniqBy ? [{ 'a': 1 }, { 'a': 2 }, { 'a': 3 }] : objects.slice(0, 3); + var expected = isSorted ? [{ 'a': 1 }, { 'a': 2 }, { 'a': 3 }] : objects.slice(0, 3); var actual = func(objects, function(object) { return object.a; @@ -20900,16 +20900,16 @@ QUnit.test('`_.' + methodName + '` should work with a "_.property" style `iteratee`', function(assert) { assert.expect(2); - var expected = isSortedUniqBy ? [{ 'a': 1 }, { 'a': 2 }, { 'a': 3 }] : objects.slice(0, 3), + var expected = isSorted ? [{ 'a': 1 }, { 'a': 2 }, { 'a': 3 }] : objects.slice(0, 3), actual = func(objects, 'a'); assert.deepEqual(actual, expected); var arrays = [[2], [3], [1], [2], [3], [1]]; - if (isSortedUniqBy) { + if (isSorted) { arrays = lodashStable.sortBy(arrays, 0); } - expected = isSortedUniqBy ? [[1], [2], [3]] : arrays.slice(0, 3); + expected = isSorted ? [[1], [2], [3]] : arrays.slice(0, 3); actual = func(arrays, 0); assert.deepEqual(actual, expected); From f3d54d097532328b05b151bbe30575b1423ccbf9 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 3 Dec 2015 22:43:55 -0800 Subject: [PATCH 719/935] Add `_.rangeRight` tests. --- lodash.js | 12 +++------ test/test.js | 69 +++++++++++++++++++++++++++++----------------------- 2 files changed, 42 insertions(+), 39 deletions(-) diff --git a/lodash.js b/lodash.js index e329ac0c32..fe79ab6338 100644 --- a/lodash.js +++ b/lodash.js @@ -3273,13 +3273,9 @@ length = nativeMax(nativeCeil((end - start) / (step || 1)), 0), result = Array(length); - while (++index < length) { - if (fromRight) { - result[index] = (end -= step); - } else { - result[index] = start; - start += step; - } + while (length--) { + result[fromRight ? length : ++index] = start; + start += step; } return result; } @@ -13348,7 +13344,7 @@ * // => [-3, -2, -1, 0] * * _.rangeRight(1, 4, 0); - * // => [4, 4, 4] + * // => [1, 1, 1] * * _.rangeRight(0); * // => [] diff --git a/test/test.js b/test/test.js index 6bd08cc415..d409beda57 100644 --- a/test/test.js +++ b/test/test.js @@ -15443,90 +15443,97 @@ /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.range'); + QUnit.module('range methods'); - (function() { - QUnit.test('should infer the sign of `step` when provided only an `end` argument', function(assert) { + lodashStable.each(['range', 'rangeRight'], function(methodName) { + var func = _[methodName], + isRange = methodName == 'range'; + + function resolve(range) { + return isRange ? range : range.reverse(); + } + + QUnit.test('`_.' + methodName + '` should infer the sign of `step` when provided only an `end` argument', function(assert) { assert.expect(2); - assert.deepEqual(_.range(4), [0, 1, 2, 3]); - assert.deepEqual(_.range(-4), [0, -1, -2, -3]); + assert.deepEqual(func(4), resolve([0, 1, 2, 3])); + assert.deepEqual(func(-4), resolve([0, -1, -2, -3])); }); - QUnit.test('should infer the sign of `step` when provided only a `start` and `end` argument', function(assert) { + QUnit.test('`_.' + methodName + '` should infer the sign of `step` when provided only a `start` and `end` argument', function(assert) { assert.expect(2); - assert.deepEqual(_.range(1, 5), [1, 2, 3, 4]); - assert.deepEqual(_.range(5, 1), [5, 4, 3, 2]); + assert.deepEqual(func(1, 5), resolve([1, 2, 3, 4])); + assert.deepEqual(func(5, 1), resolve([5, 4, 3, 2])); }); - QUnit.test('should work with `start`, `end`, and `step` arguments', function(assert) { + QUnit.test('`_.' + methodName + '` should work with `start`, `end`, and `step` arguments', function(assert) { assert.expect(3); - assert.deepEqual(_.range(0, -4, -1), [0, -1, -2, -3]); - assert.deepEqual(_.range(5, 1, -1), [5, 4, 3, 2]); - assert.deepEqual(_.range(0, 20, 5), [0, 5, 10, 15]); + assert.deepEqual(func(0, -4, -1), resolve([0, -1, -2, -3])); + assert.deepEqual(func(5, 1, -1), resolve([5, 4, 3, 2])); + assert.deepEqual(func(0, 20, 5), resolve([0, 5, 10, 15])); }); - QUnit.test('should support a `step` of `0`', function(assert) { + QUnit.test('`_.' + methodName + '` should support a `step` of `0`', function(assert) { assert.expect(1); - assert.deepEqual(_.range(1, 4, 0), [1, 1, 1]); + assert.deepEqual(func(1, 4, 0), [1, 1, 1]); }); - QUnit.test('should work with a `step` larger than `end`', function(assert) { + QUnit.test('`_.' + methodName + '` should work with a `step` larger than `end`', function(assert) { assert.expect(1); - assert.deepEqual(_.range(1, 5, 20), [1]); + assert.deepEqual(func(1, 5, 20), [1]); }); - QUnit.test('should work with a negative `step` argument', function(assert) { + QUnit.test('`_.' + methodName + '` should work with a negative `step` argument', function(assert) { assert.expect(2); - assert.deepEqual(_.range(0, -4, -1), [0, -1, -2, -3]); - assert.deepEqual(_.range(21, 10, -3), [21, 18, 15, 12]); + assert.deepEqual(func(0, -4, -1), resolve([0, -1, -2, -3])); + assert.deepEqual(func(21, 10, -3), resolve([21, 18, 15, 12])); }); - QUnit.test('should support `start` of `-0`', function(assert) { + QUnit.test('`_.' + methodName + '` should support `start` of `-0`', function(assert) { assert.expect(1); - var actual = _.range(-0, 1); + var actual = func(-0, 1); assert.strictEqual(1 / actual[0], -Infinity); }); - QUnit.test('should treat falsey `start` arguments as `0`', function(assert) { + QUnit.test('`_.' + methodName + '` should treat falsey `start` arguments as `0`', function(assert) { assert.expect(13); lodashStable.each(falsey, function(value, index) { if (index) { - assert.deepEqual(_.range(value), []); - assert.deepEqual(_.range(value, 1), [0]); + assert.deepEqual(func(value), []); + assert.deepEqual(func(value, 1), [0]); } else { - assert.deepEqual(_.range(), []); + assert.deepEqual(func(), []); } }); }); - QUnit.test('should coerce arguments to finite numbers', function(assert) { + QUnit.test('`_.' + methodName + '` should coerce arguments to finite numbers', function(assert) { assert.expect(1); - var actual = [_.range('0', 1), _.range('1'), _.range(0, 1, '1'), _.range(NaN), _.range(NaN, NaN)]; + var actual = [func('0', 1), func('1'), func(0, 1, '1'), func(NaN), func(NaN, NaN)]; assert.deepEqual(actual, [[0], [0], [0], [], []]); }); - QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { + QUnit.test('`_.' + methodName + '` should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(2); var array = [1, 2, 3], object = { 'a': 1, 'b': 2, 'c': 3 }, - expected = [[0], [0, 1], [0, 1, 2]]; + expected = lodashStable.map([[0], [0, 1], [0, 1, 2]], resolve); lodashStable.each([array, object], function(collection) { - var actual = lodashStable.map(collection, _.range); + var actual = lodashStable.map(collection, func); assert.deepEqual(actual, expected); }); }); - }()); + }); /*--------------------------------------------------------------------------*/ From 42d5cc584eceac1cb20013140f32b27494044d26 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 3 Dec 2015 22:44:51 -0800 Subject: [PATCH 720/935] Simplify iteration in `createBaseFor` . --- lodash.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lodash.js b/lodash.js index fe79ab6338..364524ea08 100644 --- a/lodash.js +++ b/lodash.js @@ -3912,13 +3912,13 @@ */ function createBaseFor(fromRight) { return function(object, iteratee, keysFunc) { - var iterable = Object(object), + var index = -1, + iterable = Object(object), props = keysFunc(object), - length = props.length, - index = fromRight ? length : -1; + length = props.length; - while ((fromRight ? index-- : ++index < length)) { - var key = props[index]; + while (length--) { + var key = props[fromRight ? length : ++index]; if (iteratee(iterable[key], key, iterable) === false) { break; } From b69ba06db9e0ad0750e5eb4aedeaf6f5856138b8 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Fri, 4 Dec 2015 08:35:45 -0800 Subject: [PATCH 721/935] Add a doc on path creation for `_.set`. [ci skip] --- lodash.js | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/lodash.js b/lodash.js index 364524ea08..fdf45e8406 100644 --- a/lodash.js +++ b/lodash.js @@ -11336,8 +11336,10 @@ } /** - * Sets the value at `path` of `object`. If a portion of `path` doesn't - * exist it's created. + * Sets the value at `path` of `object`. If a portion of `path` doesn't exist + * it's created. Arrays are created for missing index properties while objects + * are created for all other missing properties. Use `_.setWith` to customize + * `path` creation. * * @static * @memberOf _ @@ -11378,13 +11380,7 @@ * @returns {Object} Returns `object`. * @example * - * function customizer(nsValue) { - * if (!_.isObject(nsValue)) { - * return {}; - * } - * } - * - * _.setWith({ '0': { 'length': 2 } }, '[0][1][2]', 3, customizer); + * _.setWith({ '0': { 'length': 2 } }, '[0][1][2]', 3, Object); * // => { '0': { '1': { '2': 3 }, 'length': 2 } } */ function setWith(object, path, value, customizer) { From 769f78a2b755f841d7b2ef9d98e5c07d7d410d5f Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sat, 5 Dec 2015 22:01:05 -0800 Subject: [PATCH 722/935] Rename test/test.fp.js to test/test-fp.js. --- test/{test.fp.js => test-fp.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/{test.fp.js => test-fp.js} (100%) diff --git a/test/test.fp.js b/test/test-fp.js similarity index 100% rename from test/test.fp.js rename to test/test-fp.js From 42c077de025c80acdeef6499cd32fcbbc642a6e3 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sat, 5 Dec 2015 23:36:02 -0800 Subject: [PATCH 723/935] Make fp tests browser runnable. --- .travis.yml | 1 + dist/lodash.fp.js | 92 +++- dist/lodash.fp.min.js | 2 +- dist/mapping.fp.js | 222 ++++++++ lib/fp/build.js | 2 +- test/fp.html | 42 ++ test/test-fp.js | 1131 ++++++++++++++++++++++------------------- 7 files changed, 929 insertions(+), 563 deletions(-) create mode 100644 dist/mapping.fp.js create mode 100644 test/fp.html diff --git a/.travis.yml b/.travis.yml index f598102d03..00a2b89af6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -53,6 +53,7 @@ script: - "[ $SAUCE_LABS == true ] || [ $ISTANBUL == true ] || [ $TRAVIS_SECURE_ENV_VARS == false ] || $BIN $OPTION ./test.js ../lodash.min.js" - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"lodash tests\" runner=\"test/index.html?build=../lodash.js&noglobals=true\" tags=\"development\"" - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"lodash tests\" runner=\"test/index.html?build=../lodash.min.js&noglobals=true\" tags=\"production\"" + - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"lodash-fp tests\" runner=\"test/fp.html?noglobals=true\" tags=\"development\"" - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"underscore tests\" runner=\"test/underscore.html?build=../lodash.js\" tags=\"development,underscore\"" - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"underscore tests\" runner=\"test/underscore.html?build=../lodash.min.js\" tags=\"production,underscore\"" - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"backbone tests\" runner=\"test/backbone.html?build=../lodash.js\" tags=\"development,backbone\"" diff --git a/dist/lodash.fp.js b/dist/lodash.fp.js index a6f10d2283..432ed6f44a 100644 --- a/dist/lodash.fp.js +++ b/dist/lodash.fp.js @@ -86,14 +86,14 @@ return /******/ (function(modules) { // webpackBootstrap * @returns {Function|Object} Returns the converted function or object. */ function baseConvert(util, name, func) { - if (!func) { + if (typeof func != 'function') { func = name; - name = null; + name = undefined; } if (func == null) { throw new TypeError; } - var isLib = name == null && typeof func.VERSION == 'string'; + var isLib = name === undefined && typeof func.VERSION == 'string'; var _ = isLib ? func : { 'ary': util.ary, @@ -264,19 +264,26 @@ return /******/ (function(modules) { // webpackBootstrap // Iterate over methods for the current ary cap. var pairs = []; each(mapping.caps, function(cap) { - each(mapping.aryMethodMap[cap], function(name) { - var func = _[mapping.keyMap[name] || name]; + each(mapping.aryMethodMap[cap], function(key) { + var func = _[mapping.keyMap[key] || key]; if (func) { - // Wrap the lodash method and its aliases. - var wrapped = wrap(name, func); - pairs.push([name, wrapped]); - each(mapping.aliasMap[name] || [], function(alias) { pairs.push([alias, wrapped]); }); + pairs.push([key, wrap(key, func)]); } }); }); // Assign to `_` leaving `_.prototype` unchanged to allow chaining. - each(pairs, function(pair) { _[pair[0]] = pair[1]; }); + each(pairs, function(pair) { + _[pair[0]] = pair[1]; + }); + + // Wrap the lodash method and its aliases. + each(keys(_), function(key) { + each(mapping.aliasMap[key] || [], function(alias) { + _[alias] = _[key]; + }); + }); + return _; } @@ -291,9 +298,33 @@ return /******/ (function(modules) { // webpackBootstrap /** Used to map method names to their aliases. */ 'aliasMap': { + 'ary': ['nAry'], + 'conj': ['allPass'], + 'disj': ['somePass'], + 'filter': ['whereEq'], + 'flatten': ['unnest'], + 'flow': ['pipe'], + 'flowRight': ['compose'], 'forEach': ['each'], 'forEachRight': ['eachRight'], - 'head': ['first'] + 'get': ['path'], + 'getOr': ['pathOr'], + 'head': ['first'], + 'includes': ['contains'], + 'initial': ['init'], + 'isEqual': ['equals'], + 'mapValues': ['mapObj'], + 'matchesProperty': ['pathEq'], + 'modArgs': ['useWith'], + 'modArgsSet': ['converge'], + 'omit': ['dissoc', 'omitAll'], + 'pick': ['pickAll'], + 'property': ['prop'], + 'propertyOf': ['propOf'], + 'rest': ['unapply'], + 'some': ['all'], + 'spread': ['apply'], + 'zipObject': ['zipObj'] }, /** Used to map method names to their iteratee ary. */ @@ -312,6 +343,7 @@ return /******/ (function(modules) { // webpackBootstrap 'findLast': 1, 'findLastIndex': 1, 'findLastKey': 1, + 'flatMap': 1, 'forEach': 1, 'forEachRight': 1, 'forIn': 1, @@ -338,24 +370,26 @@ return /******/ (function(modules) { // webpackBootstrap /** Used to map ary to method names. */ 'aryMethodMap': { 1: ( - 'attempt,ceil,create,curry,floor,iteratee,invert,memoize,method,methodOf,' + - 'mixin,rest,reverse,round,runInContext,template,trim,trimLeft,trimRight,' + - 'words,zipObject').split(','), + 'attempt,ceil,create,curry,floor,fromPairs,iteratee,invert,over,overEvery,' + + 'overSome,memoize,method,methodOf,mixin,rest,reverse,round,runInContext,template,' + + 'trim,trimLeft,trimRight,uniqueId,words').split(','), 2: ( - 'ary,assign,at,bind,bindKey,cloneDeepWith,cloneWith,countBy,curryN,debounce,' + - 'defaults,defaultsDeep,delay,difference,drop,dropRight,dropRightWhile,' + + 'add,ary,assign,at,bind,bindKey,cloneDeepWith,cloneWith,concat,countBy,curryN,' + + 'debounce,defaults,defaultsDeep,delay,difference,drop,dropRight,dropRightWhile,' + 'dropWhile,endsWith,every,extend,filter,find,find,findIndex,findKey,findLast,' + - 'findLastIndex,findLastKey,forEach,forEachRight,forIn,forInRight,forOwn,' + - 'forOwnRight,get,groupBy,includes,indexBy,indexOf,intersection,invoke,' + - 'isMatch,lastIndexOf,map,mapKeys,mapValues,maxBy,minBy,merge,omit,pad,padLeft,' + - 'padRight,parseInt,partition,pick,pull,pullAll,pullAt,random,range,rearg,reject,' + + 'findLastIndex,findLastKey,flatMap,forEach,forEachRight,forIn,forInRight,' + + 'forOwn,forOwnRight,get,groupBy,includes,indexBy,indexOf,intersection,' + + 'invoke,invokeMap,isMatch,lastIndexOf,map,mapKeys,mapValues,matchesProperty,' + + 'maxBy,mean,minBy,merge,modArgs,modArgsSet,omit,pad,padLeft,padRight,parseInt,' + + 'partition,pick,pull,pullAll,pullAt,random,range,rangeRight,rearg,reject,' + 'remove,repeat,result,sampleSize,set,some,sortBy,sortByOrder,sortedIndexBy,' + - 'sortedLastIndexBy,sortedUniqBy,startsWith,sumBy,take,takeRight,takeRightWhile,' + - 'takeWhile,throttle,times,trunc,union,uniqBy,uniqueId,without,wrap,xor,zip').split(','), + 'sortedLastIndexBy,sortedUniqBy,startsWith,subtract,sumBy,take,takeRight,' + + 'takeRightWhile,takeWhile,throttle,times,truncate,union,uniqBy,without,wrap,' + + 'xor,zip,zipObject').split(','), 3: ( - 'assignWith,clamp,differenceBy,extendWith,inRange,intersectionBy,isEqualWith,' + - 'isMatchWith,mergeWith,omitBy,pickBy,pullAllBy,reduce,reduceRight,slice,' + - 'transform,unionBy,xorBy,zipWith').split(','), + 'assignWith,clamp,differenceBy,extendWith,getOr,inRange,intersectionBy,' + + 'isEqualWith,isMatchWith,mergeWith,omitBy,pickBy,pullAllBy,reduce,' + + 'reduceRight,slice,transform,unionBy,xorBy,zipWith').split(','), 4: ['fill'] }, @@ -377,14 +411,13 @@ return /******/ (function(modules) { // webpackBootstrap }, /** Used to iterate `mapping.aryMethodMap` keys. */ - 'caps': ['1', '2', '3', '4'], + 'caps': [1, 2, 3, 4], /** Used to map keys to other keys. */ 'keyMap': { 'curryN': 'curry', 'curryRightN': 'curryRight', - 'debounceOpt': 'debounce', - 'throttleOpt': 'throttle' + 'getOr': 'get' }, /** Used to identify methods which mutate arrays or objects. */ @@ -413,8 +446,11 @@ return /******/ (function(modules) { // webpackBootstrap /** Used to track methods that skip `_.rearg`. */ 'skipReargMap': { 'difference': true, + 'matchesProperty': true, 'random': true, 'range': true, + 'rangeRight': true, + 'zip': true, 'zipObject': true } }; diff --git a/dist/lodash.fp.min.js b/dist/lodash.fp.min.js index edada6f2c2..747b41dc56 100644 --- a/dist/lodash.fp.min.js +++ b/dist/lodash.fp.min.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.fp=t():e.fp=t()}(this,function(){return function(e){function t(n){if(r[n])return r[n].exports;var i=r[n]={exports:{},id:n,loaded:!1};return e[n].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}var r={};return t.m=e,t.c=r,t.p="",t(0)}([function(e,t,r){function n(e){return i(e,e)}var i=r(1);e.exports=n},function(e,t,r){function n(e,t,r){if(r||(r=t,t=null),null==r)throw new TypeError;var o=null==t&&"string"==typeof r.VERSION,u=o?r:{ary:e.ary,curry:e.curry,forEach:e.forEach,isFunction:e.isFunction,iteratee:e.iteratee,keys:e.keys,rearg:e.rearg},p=u.ary,f=u.curry,c=u.forEach,s=u.isFunction,l=u.keys,d=u.rearg,h=function(e,t){return function(){var r=arguments,n=Math.min(r.length,t);switch(n){case 1:return e(r[0]);case 2:return e(r[0],r[1])}for(r=Array(n);n--;)r[n]=arguments[n];return e.apply(void 0,r)}},y=function(e){return function(){for(var t=-1,r=arguments.length,n=Array(r);r--;)n[r]=arguments[r];var i=n[0];for(r=i?i.length:0,n[0]=Array(r);++t2?r-2:1,t=e(t);var n=t.length;return r>=n?t:h(t,r)}},mixin:function(e){return function(t){var r=this;if(!s(r))return e(r,Object(t));var n=[],i=[];return c(l(t),function(e){var a=t[e];s(a)&&(i.push(e),n.push(r.prototype[e]))}),e(r,Object(t)),c(i,function(e,t){var i=n[t];s(i)?r.prototype[e]=i:delete r.prototype[e]}),r}},runInContext:function(t){return function(r){return n(e,t(r))}}},x=function(e,t){var r=v[e];if(r)return r(t);a.array[e]?t=y(t):a.object[e]&&(t=g(t));var n;return c(i.caps,function(r){return c(i.aryMethodMap[r],function(a){if(e==a){n=p(t,r),r>1&&!i.skipReargMap[e]&&(n=d(n,i.methodReargMap[e]||i.aryReargMap[r]));var u=!o&&i.aryIterateeMap[e];return u&&(n=m(n,u)),r>1&&(n=f(n,r)),!1}}),!n}),n||t};if(!o)return x(t,r);var R=[];return c(i.caps,function(e){c(i.aryMethodMap[e],function(e){var t=u[i.keyMap[e]||e];if(t){var r=x(e,t);R.push([e,r]),c(i.aliasMap[e]||[],function(e){R.push([e,r])})}})}),c(R,function(e){u[e[0]]=e[1]}),u}var i=r(2),a=i.mutateMap;e.exports=n},function(e,t){e.exports={aliasMap:{forEach:["each"],forEachRight:["eachRight"],head:["first"]},aryIterateeMap:{assignWith:2,cloneDeepWith:1,cloneWith:1,dropRightWhile:1,dropWhile:1,every:1,extendWith:2,filter:1,find:1,findIndex:1,findKey:1,findLast:1,findLastIndex:1,findLastKey:1,forEach:1,forEachRight:1,forIn:1,forInRight:1,forOwn:1,forOwnRight:1,isEqualWith:2,isMatchWith:2,map:1,mapKeys:1,mapValues:1,partition:1,reduce:2,reduceRight:2,reject:1,remove:1,some:1,takeRightWhile:1,takeWhile:1,times:1,transform:2},aryMethodMap:{1:"attempt,ceil,create,curry,floor,iteratee,invert,memoize,method,methodOf,mixin,rest,reverse,round,runInContext,template,trim,trimLeft,trimRight,words,zipObject".split(","),2:"ary,assign,at,bind,bindKey,cloneDeepWith,cloneWith,countBy,curryN,debounce,defaults,defaultsDeep,delay,difference,drop,dropRight,dropRightWhile,dropWhile,endsWith,every,extend,filter,find,find,findIndex,findKey,findLast,findLastIndex,findLastKey,forEach,forEachRight,forIn,forInRight,forOwn,forOwnRight,get,groupBy,includes,indexBy,indexOf,intersection,invoke,isMatch,lastIndexOf,map,mapKeys,mapValues,maxBy,minBy,merge,omit,pad,padLeft,padRight,parseInt,partition,pick,pull,pullAll,pullAt,random,range,rearg,reject,remove,repeat,result,sampleSize,set,some,sortBy,sortByOrder,sortedIndexBy,sortedLastIndexBy,sortedUniqBy,startsWith,sumBy,take,takeRight,takeRightWhile,takeWhile,throttle,times,trunc,union,uniqBy,uniqueId,without,wrap,xor,zip".split(","),3:"assignWith,clamp,differenceBy,extendWith,inRange,intersectionBy,isEqualWith,isMatchWith,mergeWith,omitBy,pickBy,pullAllBy,reduce,reduceRight,slice,transform,unionBy,xorBy,zipWith".split(","),4:["fill"]},aryReargMap:{2:[1,0],3:[2,1,0],4:[3,2,0,1]},methodReargMap:{clamp:[2,0,1],reduce:[2,0,1],reduceRight:[2,0,1],slice:[2,0,1],transform:[2,0,1]},caps:["1","2","3","4"],keyMap:{curryN:"curry",curryRightN:"curryRight",debounceOpt:"debounce",throttleOpt:"throttle"},mutateMap:{array:{fill:!0,pull:!0,pullAll:!0,pullAllBy:!0,pullAt:!0,remove:!0,reverse:!0},object:{assign:!0,assignWith:!0,defaults:!0,defaultsDeep:!0,extend:!0,extendWith:!0,merge:!0,mergeWith:!0}},skipReargMap:{difference:!0,random:!0,range:!0,zipObject:!0}}}])}); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.fp=t():e.fp=t()}(this,function(){return function(e){function t(n){if(r[n])return r[n].exports;var i=r[n]={exports:{},id:n,loaded:!1};return e[n].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}var r={};return t.m=e,t.c=r,t.p="",t(0)}([function(e,t,r){function n(e){return i(e,e)}var i=r(1);e.exports=n},function(e,t,r){function n(e,t,r){if("function"!=typeof r&&(r=t,t=void 0),null==r)throw new TypeError;var o=void 0===t&&"string"==typeof r.VERSION,p=o?r:{ary:e.ary,curry:e.curry,forEach:e.forEach,isFunction:e.isFunction,iteratee:e.iteratee,keys:e.keys,rearg:e.rearg},u=p.ary,s=p.curry,c=p.forEach,f=p.isFunction,l=p.keys,d=p.rearg,h=function(e,t){return function(){var r=arguments,n=Math.min(r.length,t);switch(n){case 1:return e(r[0]);case 2:return e(r[0],r[1])}for(r=Array(n);n--;)r[n]=arguments[n];return e.apply(void 0,r)}},y=function(e){return function(){for(var t=-1,r=arguments.length,n=Array(r);r--;)n[r]=arguments[r];var i=n[0];for(r=i?i.length:0,n[0]=Array(r);++t2?r-2:1,t=e(t);var n=t.length;return r>=n?t:h(t,r)}},mixin:function(e){return function(t){var r=this;if(!f(r))return e(r,Object(t));var n=[],i=[];return c(l(t),function(e){var a=t[e];f(a)&&(i.push(e),n.push(r.prototype[e]))}),e(r,Object(t)),c(i,function(e,t){var i=n[t];f(i)?r.prototype[e]=i:delete r.prototype[e]}),r}},runInContext:function(t){return function(r){return n(e,t(r))}}},x=function(e,t){var r=v[e];if(r)return r(t);a.array[e]?t=y(t):a.object[e]&&(t=g(t));var n;return c(i.caps,function(r){return c(i.aryMethodMap[r],function(a){if(e==a){n=u(t,r),r>1&&!i.skipReargMap[e]&&(n=d(n,i.methodReargMap[e]||i.aryReargMap[r]));var p=!o&&i.aryIterateeMap[e];return p&&(n=m(n,p)),r>1&&(n=s(n,r)),!1}}),!n}),n||t};if(!o)return x(t,r);var R=[];return c(i.caps,function(e){c(i.aryMethodMap[e],function(e){var t=p[i.keyMap[e]||e];t&&R.push([e,x(e,t)])})}),c(R,function(e){p[e[0]]=e[1]}),c(l(p),function(e){c(i.aliasMap[e]||[],function(t){p[t]=p[e]})}),p}var i=r(2),a=i.mutateMap;e.exports=n},function(e,t){e.exports={aliasMap:{ary:["nAry"],conj:["allPass"],disj:["somePass"],filter:["whereEq"],flatten:["unnest"],flow:["pipe"],flowRight:["compose"],forEach:["each"],forEachRight:["eachRight"],get:["path"],getOr:["pathOr"],head:["first"],includes:["contains"],initial:["init"],isEqual:["equals"],mapValues:["mapObj"],matchesProperty:["pathEq"],modArgs:["useWith"],modArgsSet:["converge"],omit:["dissoc","omitAll"],pick:["pickAll"],property:["prop"],propertyOf:["propOf"],rest:["unapply"],some:["all"],spread:["apply"],zipObject:["zipObj"]},aryIterateeMap:{assignWith:2,cloneDeepWith:1,cloneWith:1,dropRightWhile:1,dropWhile:1,every:1,extendWith:2,filter:1,find:1,findIndex:1,findKey:1,findLast:1,findLastIndex:1,findLastKey:1,flatMap:1,forEach:1,forEachRight:1,forIn:1,forInRight:1,forOwn:1,forOwnRight:1,isEqualWith:2,isMatchWith:2,map:1,mapKeys:1,mapValues:1,partition:1,reduce:2,reduceRight:2,reject:1,remove:1,some:1,takeRightWhile:1,takeWhile:1,times:1,transform:2},aryMethodMap:{1:"attempt,ceil,create,curry,floor,fromPairs,iteratee,invert,over,overEvery,overSome,memoize,method,methodOf,mixin,rest,reverse,round,runInContext,template,trim,trimLeft,trimRight,uniqueId,words".split(","),2:"add,ary,assign,at,bind,bindKey,cloneDeepWith,cloneWith,concat,countBy,curryN,debounce,defaults,defaultsDeep,delay,difference,drop,dropRight,dropRightWhile,dropWhile,endsWith,every,extend,filter,find,find,findIndex,findKey,findLast,findLastIndex,findLastKey,flatMap,forEach,forEachRight,forIn,forInRight,forOwn,forOwnRight,get,groupBy,includes,indexBy,indexOf,intersection,invoke,invokeMap,isMatch,lastIndexOf,map,mapKeys,mapValues,matchesProperty,maxBy,mean,minBy,merge,modArgs,modArgsSet,omit,pad,padLeft,padRight,parseInt,partition,pick,pull,pullAll,pullAt,random,range,rangeRight,rearg,reject,remove,repeat,result,sampleSize,set,some,sortBy,sortByOrder,sortedIndexBy,sortedLastIndexBy,sortedUniqBy,startsWith,subtract,sumBy,take,takeRight,takeRightWhile,takeWhile,throttle,times,truncate,union,uniqBy,without,wrap,xor,zip,zipObject".split(","),3:"assignWith,clamp,differenceBy,extendWith,getOr,inRange,intersectionBy,isEqualWith,isMatchWith,mergeWith,omitBy,pickBy,pullAllBy,reduce,reduceRight,slice,transform,unionBy,xorBy,zipWith".split(","),4:["fill"]},aryReargMap:{2:[1,0],3:[2,1,0],4:[3,2,0,1]},methodReargMap:{clamp:[2,0,1],reduce:[2,0,1],reduceRight:[2,0,1],slice:[2,0,1],transform:[2,0,1]},caps:[1,2,3,4],keyMap:{curryN:"curry",curryRightN:"curryRight",getOr:"get"},mutateMap:{array:{fill:!0,pull:!0,pullAll:!0,pullAllBy:!0,pullAt:!0,remove:!0,reverse:!0},object:{assign:!0,assignWith:!0,defaults:!0,defaultsDeep:!0,extend:!0,extendWith:!0,merge:!0,mergeWith:!0}},skipReargMap:{difference:!0,matchesProperty:!0,random:!0,range:!0,rangeRight:!0,zip:!0,zipObject:!0}}}])}); \ No newline at end of file diff --git a/dist/mapping.fp.js b/dist/mapping.fp.js new file mode 100644 index 0000000000..a591a2bd60 --- /dev/null +++ b/dist/mapping.fp.js @@ -0,0 +1,222 @@ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports["mapping"] = factory(); + else + root["mapping"] = factory(); +})(this, function() { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; + +/******/ // The require function +/******/ function __webpack_require__(moduleId) { + +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) +/******/ return installedModules[moduleId].exports; + +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ exports: {}, +/******/ id: moduleId, +/******/ loaded: false +/******/ }; + +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); + +/******/ // Flag the module as loaded +/******/ module.loaded = true; + +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } + + +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; + +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; + +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; + +/******/ // Load entry module and return exports +/******/ return __webpack_require__(0); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ function(module, exports) { + + module.exports = { + + /** Used to map method names to their aliases. */ + 'aliasMap': { + 'ary': ['nAry'], + 'conj': ['allPass'], + 'disj': ['somePass'], + 'filter': ['whereEq'], + 'flatten': ['unnest'], + 'flow': ['pipe'], + 'flowRight': ['compose'], + 'forEach': ['each'], + 'forEachRight': ['eachRight'], + 'get': ['path'], + 'getOr': ['pathOr'], + 'head': ['first'], + 'includes': ['contains'], + 'initial': ['init'], + 'isEqual': ['equals'], + 'mapValues': ['mapObj'], + 'matchesProperty': ['pathEq'], + 'modArgs': ['useWith'], + 'modArgsSet': ['converge'], + 'omit': ['dissoc', 'omitAll'], + 'pick': ['pickAll'], + 'property': ['prop'], + 'propertyOf': ['propOf'], + 'rest': ['unapply'], + 'some': ['all'], + 'spread': ['apply'], + 'zipObject': ['zipObj'] + }, + + /** Used to map method names to their iteratee ary. */ + 'aryIterateeMap': { + 'assignWith': 2, + 'cloneDeepWith': 1, + 'cloneWith': 1, + 'dropRightWhile': 1, + 'dropWhile': 1, + 'every': 1, + 'extendWith': 2, + 'filter': 1, + 'find': 1, + 'findIndex': 1, + 'findKey': 1, + 'findLast': 1, + 'findLastIndex': 1, + 'findLastKey': 1, + 'flatMap': 1, + 'forEach': 1, + 'forEachRight': 1, + 'forIn': 1, + 'forInRight': 1, + 'forOwn': 1, + 'forOwnRight': 1, + 'isEqualWith': 2, + 'isMatchWith': 2, + 'map': 1, + 'mapKeys': 1, + 'mapValues': 1, + 'partition': 1, + 'reduce': 2, + 'reduceRight': 2, + 'reject': 1, + 'remove': 1, + 'some': 1, + 'takeRightWhile': 1, + 'takeWhile': 1, + 'times': 1, + 'transform': 2 + }, + + /** Used to map ary to method names. */ + 'aryMethodMap': { + 1: ( + 'attempt,ceil,create,curry,floor,fromPairs,iteratee,invert,over,overEvery,' + + 'overSome,memoize,method,methodOf,mixin,rest,reverse,round,runInContext,template,' + + 'trim,trimLeft,trimRight,uniqueId,words').split(','), + 2: ( + 'add,ary,assign,at,bind,bindKey,cloneDeepWith,cloneWith,concat,countBy,curryN,' + + 'debounce,defaults,defaultsDeep,delay,difference,drop,dropRight,dropRightWhile,' + + 'dropWhile,endsWith,every,extend,filter,find,find,findIndex,findKey,findLast,' + + 'findLastIndex,findLastKey,flatMap,forEach,forEachRight,forIn,forInRight,' + + 'forOwn,forOwnRight,get,groupBy,includes,indexBy,indexOf,intersection,' + + 'invoke,invokeMap,isMatch,lastIndexOf,map,mapKeys,mapValues,matchesProperty,' + + 'maxBy,mean,minBy,merge,modArgs,modArgsSet,omit,pad,padLeft,padRight,parseInt,' + + 'partition,pick,pull,pullAll,pullAt,random,range,rangeRight,rearg,reject,' + + 'remove,repeat,result,sampleSize,set,some,sortBy,sortByOrder,sortedIndexBy,' + + 'sortedLastIndexBy,sortedUniqBy,startsWith,subtract,sumBy,take,takeRight,' + + 'takeRightWhile,takeWhile,throttle,times,truncate,union,uniqBy,without,wrap,' + + 'xor,zip,zipObject').split(','), + 3: ( + 'assignWith,clamp,differenceBy,extendWith,getOr,inRange,intersectionBy,' + + 'isEqualWith,isMatchWith,mergeWith,omitBy,pickBy,pullAllBy,reduce,' + + 'reduceRight,slice,transform,unionBy,xorBy,zipWith').split(','), + 4: + ['fill'] + }, + + /** Used to map ary to rearg configs by method ary. */ + 'aryReargMap': { + 2: [1, 0], + 3: [2, 1, 0], + 4: [3, 2, 0, 1] + }, + + /** Used to map ary to rearg configs by method names. */ + 'methodReargMap': { + 'clamp': [2, 0, 1], + 'reduce': [2, 0, 1], + 'reduceRight': [2, 0, 1], + 'slice': [2, 0, 1], + 'transform': [2, 0, 1] + }, + + /** Used to iterate `mapping.aryMethodMap` keys. */ + 'caps': [1, 2, 3, 4], + + /** Used to map keys to other keys. */ + 'keyMap': { + 'curryN': 'curry', + 'curryRightN': 'curryRight', + 'getOr': 'get' + }, + + /** Used to identify methods which mutate arrays or objects. */ + 'mutateMap': { + 'array': { + 'fill': true, + 'pull': true, + 'pullAll': true, + 'pullAllBy': true, + 'pullAt': true, + 'remove': true, + 'reverse': true + }, + 'object': { + 'assign': true, + 'assignWith': true, + 'defaults': true, + 'defaultsDeep': true, + 'extend': true, + 'extendWith': true, + 'merge': true, + 'mergeWith': true + } + }, + + /** Used to track methods that skip `_.rearg`. */ + 'skipReargMap': { + 'difference': true, + 'matchesProperty': true, + 'random': true, + 'range': true, + 'rangeRight': true, + 'zip': true, + 'zipObject': true + } + }; + + +/***/ } +/******/ ]) +}); +; \ No newline at end of file diff --git a/lib/fp/build.js b/lib/fp/build.js index f4c5237ca0..2ee8923f7c 100644 --- a/lib/fp/build.js +++ b/lib/fp/build.js @@ -30,7 +30,7 @@ var mappingConfig = { 'entry': path.join(__dirname, 'mapping.js'), 'output': { 'path': distPath, - 'filename': 'fp-mapping.js', + 'filename': 'mapping.fp.js', 'library': 'mapping', 'libraryTarget': 'umd' } diff --git a/test/fp.html b/test/fp.html new file mode 100644 index 0000000000..5d7cfe2480 --- /dev/null +++ b/test/fp.html @@ -0,0 +1,42 @@ + + + + + lodash-fp Test Suite + + + + + + + + + + + + +
    + + + diff --git a/test/test-fp.js b/test/test-fp.js index 8491b12be0..8f278e18f5 100644 --- a/test/test-fp.js +++ b/test/test-fp.js @@ -1,744 +1,809 @@ -'use strict'; - -var _ = require('lodash'), - path = require('path'); - -var basePath = path.join(__dirname, '..'), - libPath = path.join(basePath, 'lib'), - fpPath = path.join(libPath, 'fp'); - -var convert = require(path.join(fpPath, 'fp.js')), - mapping = require(path.join(fpPath, 'mapping.js')); - -var fp = convert(_.runInContext()); - -global.QUnit = require('qunitjs'); -require('qunit-extras').runInContext(global); - -/*----------------------------------------------------------------------------*/ +;(function() { + + /** Used as a safe reference for `undefined` in pre-ES5 environments. */ + var undefined; + + /** Used as the size to cover large array optimizations. */ + var LARGE_ARRAY_SIZE = 200; + + /** Used as a reference to the global object. */ + var root = (typeof global == 'object' && global) || this; + + /** Used for native method references. */ + var arrayProto = Array.prototype; + + /** Method and object shortcuts. */ + var phantom = root.phantom, + amd = root.define && define.amd, + document = !phantom && root.document, + noop = function() {}, + slice = arrayProto.slice; + + /*--------------------------------------------------------------------------*/ + + /** Use a single "load" function. */ + var load = (!amd && typeof require == 'function') + ? require + : noop; + + /** The unit testing framework. */ + var QUnit = root.QUnit || (root.QUnit = ( + QUnit = load('../node_modules/qunitjs/qunit/qunit.js') || root.QUnit, + QUnit = QUnit.QUnit || QUnit + )); + + /** Load stable Lodash and QUnit Extras. */ + var _ = root._ || load('../lodash.js'); + if (_) { + _ = _.runInContext(root); + } + var QUnitExtras = load('../node_modules/qunit-extras/qunit-extras.js'); + if (QUnitExtras) { + QUnitExtras.runInContext(root); + } + + var convert = root.fp || load('../dist/lodash.fp.js'), + mapping = root.mapping || load('../lib/fp/mapping.js'), + fp = convert(_.runInContext()); + + /*--------------------------------------------------------------------------*/ + + /** + * Skips a given number of tests with a passing result. + * + * @private + * @param {Object} assert The QUnit assert object. + * @param {number} [count=1] The number of tests to skip. + */ + function skipTest(assert, count) { + count || (count = 1); + while (count--) { + assert.ok(true, 'test skipped'); + } + } + + /*--------------------------------------------------------------------------*/ + + QUnit.module('method aliases'); + + (function() { + QUnit.test('should have correct aliases', function(assert) { + assert.expect(1); + + var actual = _.transform(mapping.aliasMap, function(result, aliases, methodName) { + var func = fp[methodName]; + _.each(aliases, function(alias) { + result.push([alias, fp[alias] === func]); + }); + }, []); + + assert.deepEqual(_.reject(actual, 1), []); + }); + }()); -/** Used as the size to cover large array optimizations. */ -var LARGE_ARRAY_SIZE = 200; + /*--------------------------------------------------------------------------*/ -/** Used for native method references. */ -var arrayProto = Array.prototype; + QUnit.module('method ary caps'); -/** Method and object shortcuts. */ -var slice = arrayProto.slice; + (function() { + QUnit.test('should have a cap of 1', function(assert) { + assert.expect(1); -/*----------------------------------------------------------------------------*/ + var funcMethods = [ + 'curry', 'iteratee', 'memoize', 'over', 'overEvery', 'overSome', + 'method', 'methodOf', 'restParam', 'runInContext' + ]; -QUnit.module('method aliases'); + var exceptions = funcMethods.concat('mixin', 'template'), + expected = _.map(mapping.aryMethodMap[1], _.constant(true)); -(function() { - QUnit.test('should have correct aliases', function(assert) { - assert.expect(1); + var actual = _.map(mapping.aryMethodMap[1], function(methodName) { + var arg = _.includes(funcMethods, methodName) ? _.noop : 1, + result = _.attempt(function() { return fp[methodName](arg); }); - var actual = _.transform(mapping.aliasMap, function(result, aliases, methodName) { - var func = fp[methodName]; - _.each(aliases, function(alias) { - result.push([alias, fp[alias] === func]); + if (_.includes(exceptions, methodName) + ? typeof result == 'function' + : typeof result != 'function' + ) { + return true; + } + console.log(methodName, result); + return false; }); - }, []); - - assert.deepEqual(_.reject(actual, 1), []); - }); -}()); - -/*----------------------------------------------------------------------------*/ - -QUnit.module('method ary caps'); - -(function() { - QUnit.test('should have a cap of 1', function(assert) { - assert.expect(1); - var funcMethods = [ - 'curry', 'iteratee', 'memoize', 'over', 'overEvery', 'overSome', - 'method', 'methodOf', 'restParam', 'runInContext' - ]; - - var exceptions = funcMethods.concat('mixin', 'template'), - expected = _.map(mapping.aryMethodMap[1], _.constant(true)); - - var actual = _.map(mapping.aryMethodMap[1], function(methodName) { - var arg = _.includes(funcMethods, methodName) ? _.noop : 1, - result = _.attempt(function() { return fp[methodName](arg); }); - - if (_.includes(exceptions, methodName) - ? typeof result == 'function' - : typeof result != 'function' - ) { - return true; - } - console.log(methodName, result); - return false; + assert.deepEqual(actual, expected); }); - assert.deepEqual(actual, expected); - }); - - QUnit.test('should have a cap of 2', function(assert) { - assert.expect(1); - - var funcMethods = [ - 'after', 'ary', 'before', 'bind', 'bindKey', 'cloneDeepWith', 'cloneWith', - 'curryN', 'debounce', 'delay', 'modArgs', 'modArgsSet', 'rearg', 'throttle', - 'wrap' - ]; - - var exceptions = _.difference(funcMethods.concat('matchesProperty'), ['cloneDeepWith', 'cloneWith', 'delay']), - expected = _.map(mapping.aryMethodMap[2], _.constant(true)); - - var actual = _.map(mapping.aryMethodMap[2], function(methodName) { - var args = _.includes(funcMethods, methodName) ? [methodName == 'curryN' ? 1 : _.noop, _.noop] : [1, []], - result = _.attempt(function() { return fp[methodName](args[0])(args[1]); }); + QUnit.test('should have a cap of 2', function(assert) { + assert.expect(1); + + var funcMethods = [ + 'after', 'ary', 'before', 'bind', 'bindKey', 'cloneDeepWith', 'cloneWith', + 'curryN', 'debounce', 'delay', 'modArgs', 'modArgsSet', 'rearg', 'throttle', + 'wrap' + ]; + + var exceptions = _.difference(funcMethods.concat('matchesProperty'), ['cloneDeepWith', 'cloneWith', 'delay']), + expected = _.map(mapping.aryMethodMap[2], _.constant(true)); + + var actual = _.map(mapping.aryMethodMap[2], function(methodName) { + var args = _.includes(funcMethods, methodName) ? [methodName == 'curryN' ? 1 : _.noop, _.noop] : [1, []], + result = _.attempt(function() { return fp[methodName](args[0])(args[1]); }); + + if (_.includes(exceptions, methodName) + ? typeof result == 'function' + : typeof result != 'function' + ) { + return true; + } + console.log(methodName, result); + return false; + }); - if (_.includes(exceptions, methodName) - ? typeof result == 'function' - : typeof result != 'function' - ) { - return true; - } - console.log(methodName, result); - return false; + assert.deepEqual(actual, expected); }); - assert.deepEqual(actual, expected); - }); + QUnit.test('should have a cap of 3', function(assert) { + assert.expect(1); - QUnit.test('should have a cap of 3', function(assert) { - assert.expect(1); + var funcMethods = [ + 'assignWith', 'extendWith', 'isEqualWith', 'isMatchWith', 'omitBy', + 'pickBy', 'reduce', 'reduceRight', 'transform', 'zipWith' + ]; - var funcMethods = [ - 'assignWith', 'extendWith', 'isEqualWith', 'isMatchWith', 'omitBy', - 'pickBy', 'reduce', 'reduceRight', 'transform', 'zipWith' - ]; + var expected = _.map(mapping.aryMethodMap[3], _.constant(true)); - var expected = _.map(mapping.aryMethodMap[3], _.constant(true)); + var actual = _.map(mapping.aryMethodMap[3], function(methodName) { + var args = _.includes(funcMethods, methodName) ? [_.noop, 0, 1] : [0, 1, []], + result = _.attempt(function() { return fp[methodName](args[0])(args[1])(args[2]); }); - var actual = _.map(mapping.aryMethodMap[3], function(methodName) { - var args = _.includes(funcMethods, methodName) ? [_.noop, 0, 1] : [0, 1, []], - result = _.attempt(function() { return fp[methodName](args[0])(args[1])(args[2]); }); + if (typeof result != 'function') { + return true; + } + console.log(methodName, result); + return false; + }); - if (typeof result != 'function') { - return true; - } - console.log(methodName, result); - return false; + assert.deepEqual(actual, expected); }); + }()); - assert.deepEqual(actual, expected); - }); -}()); - -/*----------------------------------------------------------------------------*/ + /*--------------------------------------------------------------------------*/ -QUnit.module('methods that use `indexOf`'); + QUnit.module('methods that use `indexOf`'); -(function() { - QUnit.test('should work with `fp.indexOf`', function(assert) { - assert.expect(10); + (function() { + QUnit.test('should work with `fp.indexOf`', function(assert) { + assert.expect(10); - var array = ['a', 'b', 'c'], - other = ['b', 'b', 'd'], - object = { 'a': 1, 'b': 2, 'c': 2 }, - actual = fp.difference(array, other); + var array = ['a', 'b', 'c'], + other = ['b', 'b', 'd'], + object = { 'a': 1, 'b': 2, 'c': 2 }, + actual = fp.difference(array, other); - assert.deepEqual(actual, ['a', 'c'], 'fp.difference'); + assert.deepEqual(actual, ['a', 'c'], 'fp.difference'); - actual = fp.includes('b', array); - assert.strictEqual(actual, true, 'fp.includes'); + actual = fp.includes('b', array); + assert.strictEqual(actual, true, 'fp.includes'); - actual = fp.intersection(other, array); - assert.deepEqual(actual, ['b'], 'fp.intersection'); + actual = fp.intersection(other, array); + assert.deepEqual(actual, ['b'], 'fp.intersection'); - actual = fp.omit(other, object); - assert.deepEqual(actual, { 'a': 1, 'c': 2 }, 'fp.omit'); + actual = fp.omit(other, object); + assert.deepEqual(actual, { 'a': 1, 'c': 2 }, 'fp.omit'); - actual = fp.union(other, array); - assert.deepEqual(actual, ['a', 'b', 'c', 'd'], 'fp.union'); + actual = fp.union(other, array); + assert.deepEqual(actual, ['a', 'b', 'c', 'd'], 'fp.union'); - actual = fp.uniq(other); - assert.deepEqual(actual, ['b', 'd'], 'fp.uniq'); + actual = fp.uniq(other); + assert.deepEqual(actual, ['b', 'd'], 'fp.uniq'); - actual = fp.uniqBy(_.identity, other); - assert.deepEqual(actual, ['b', 'd'], 'fp.uniqBy'); + actual = fp.uniqBy(_.identity, other); + assert.deepEqual(actual, ['b', 'd'], 'fp.uniqBy'); - actual = fp.without('b', array); - assert.deepEqual(actual, ['a', 'c'], 'fp.without'); + actual = fp.without('b', array); + assert.deepEqual(actual, ['a', 'c'], 'fp.without'); - actual = fp.xor(other, array); - assert.deepEqual(actual, ['a', 'c', 'd'], 'fp.xor'); + actual = fp.xor(other, array); + assert.deepEqual(actual, ['a', 'c', 'd'], 'fp.xor'); - actual = fp.pull('b', array); - assert.deepEqual(actual, ['a', 'c'], 'fp.pull'); - }); -}()); + actual = fp.pull('b', array); + assert.deepEqual(actual, ['a', 'c'], 'fp.pull'); + }); + }()); -/*----------------------------------------------------------------------------*/ + /*--------------------------------------------------------------------------*/ -QUnit.module('cherry-picked methods'); + QUnit.module('cherry-picked methods'); -(function() { - QUnit.test('should provide the correct `iteratee` arguments', function(assert) { - assert.expect(1); + (function() { + QUnit.test('should provide the correct `iteratee` arguments', function(assert) { + assert.expect(1); - var args, - array = [1, 2, 3], - map = convert('map', _.map); + if (!document) { + var args, + array = [1, 2, 3], + map = convert('map', _.map); - map(function() { - args || (args = slice.call(arguments)); - })(array); + map(function() { + args || (args = slice.call(arguments)); + })(array); - assert.deepEqual(args, [1]); - }); + assert.deepEqual(args, [1]); + } + else { + skipTest(assert); + } + }); - QUnit.test('should not support shortcut fusion', function(assert) { - assert.expect(3); + QUnit.test('should not support shortcut fusion', function(assert) { + assert.expect(3); - var array = fp.range(0, LARGE_ARRAY_SIZE), - filterCount = 0, - mapCount = 0; + if (!document) { + var array = fp.range(0, LARGE_ARRAY_SIZE), + filterCount = 0, + mapCount = 0; - var iteratee = function(value) { - mapCount++; - return value * value; - }; + var iteratee = function(value) { + mapCount++; + return value * value; + }; - var predicate = function(value) { - filterCount++; - return value % 2 == 0; - }; + var predicate = function(value) { + filterCount++; + return value % 2 == 0; + }; - var map1 = convert('map', _.map), - filter1 = convert('filter', _.filter), - take1 = convert('take', _.take); + var map1 = convert('map', _.map), + filter1 = convert('filter', _.filter), + take1 = convert('take', _.take); - var filter2 = filter1(predicate), - map2 = map1(iteratee), - take2 = take1(2); + var filter2 = filter1(predicate), + map2 = map1(iteratee), + take2 = take1(2); - var combined = fp.flow(map2, filter2, fp.compact, take2); + var combined = fp.flow(map2, filter2, fp.compact, take2); - assert.deepEqual(combined(array), [4, 16]); - assert.strictEqual(filterCount, 200, 'filterCount'); - assert.strictEqual(mapCount, 200, 'mapCount'); - }); -}()); + assert.deepEqual(combined(array), [4, 16]); + assert.strictEqual(filterCount, 200, 'filterCount'); + assert.strictEqual(mapCount, 200, 'mapCount'); + } + else { + skipTest(assert, 3); + } + }); + }()); -/*----------------------------------------------------------------------------*/ + /*--------------------------------------------------------------------------*/ -QUnit.module('fp.curry'); + QUnit.module('fp.curry'); -(function() { - QUnit.test('should accept only a `func` param', function(assert) { - assert.expect(1); + (function() { + QUnit.test('should accept only a `func` param', function(assert) { + assert.expect(1); - assert.raises(function() { fp.curry(1, _.noop); }, TypeError); - }); -}()); + assert.raises(function() { fp.curry(1, _.noop); }, TypeError); + }); + }()); -/*----------------------------------------------------------------------------*/ + /*--------------------------------------------------------------------------*/ -QUnit.module('fp.curryN'); + QUnit.module('fp.curryN'); -(function() { - QUnit.test('should accept an `arity` param', function(assert) { - assert.expect(1); + (function() { + QUnit.test('should accept an `arity` param', function(assert) { + assert.expect(1); - var actual = fp.curryN(1, function(a, b) { return [a, b]; })('a'); - assert.deepEqual(actual, ['a', undefined]); - }); -}()); + var actual = fp.curryN(1, function(a, b) { return [a, b]; })('a'); + assert.deepEqual(actual, ['a', undefined]); + }); + }()); -/*----------------------------------------------------------------------------*/ + /*--------------------------------------------------------------------------*/ -QUnit.module('fp.difference'); + QUnit.module('fp.difference'); -(function() { - QUnit.test('should return the elements of the first array not included in the second array', function(assert) { - assert.expect(1); + (function() { + QUnit.test('should return the elements of the first array not included in the second array', function(assert) { + assert.expect(1); - assert.deepEqual(fp.difference([1, 2])([2, 3]), [1]); - }); -}()); + assert.deepEqual(fp.difference([1, 2])([2, 3]), [1]); + }); + }()); -/*----------------------------------------------------------------------------*/ + /*--------------------------------------------------------------------------*/ -QUnit.module('fp.fill'); + QUnit.module('fp.fill'); -(function() { - QUnit.test('should have an argument order of `start`, `end`, then `value`', function(assert) { - assert.expect(1); + (function() { + QUnit.test('should have an argument order of `start`, `end`, then `value`', function(assert) { + assert.expect(1); - var array = [1, 2, 3]; - assert.deepEqual(fp.fill(1)(2)('*')(array), [1, '*', 3]); - }); -}()); + var array = [1, 2, 3]; + assert.deepEqual(fp.fill(1)(2)('*')(array), [1, '*', 3]); + }); + }()); -/*----------------------------------------------------------------------------*/ + /*--------------------------------------------------------------------------*/ -QUnit.module('fp.flow and fp.flowRight'); + QUnit.module('fp.flow and fp.flowRight'); -_.each(['flow', 'flowRight'], function(methodName, index) { - var func = fp[methodName], - isFlow = methodName == 'flow'; + _.each(['flow', 'flowRight'], function(methodName, index) { + var func = fp[methodName], + isFlow = methodName == 'flow'; - QUnit.test('`fp.' + methodName + '` should support shortcut fusion', function(assert) { - assert.expect(6); + QUnit.test('`fp.' + methodName + '` should support shortcut fusion', function(assert) { + assert.expect(6); - var filterCount, - mapCount, - array = fp.range(0, LARGE_ARRAY_SIZE); + var filterCount, + mapCount, + array = fp.range(0, LARGE_ARRAY_SIZE); - var iteratee = function(value) { - mapCount++; - return value * value; - }; + var iteratee = function(value) { + mapCount++; + return value * value; + }; - var predicate = function(value) { - filterCount++; - return value % 2 == 0; - }; + var predicate = function(value) { + filterCount++; + return value % 2 == 0; + }; - var filter = fp.filter(predicate), - map = fp.map(iteratee), - take = fp.take(2); + var filter = fp.filter(predicate), + map = fp.map(iteratee), + take = fp.take(2); - _.times(2, function(index) { - var combined = isFlow - ? func(map, filter, fp.compact, take) - : func(take, fp.compact, filter, map); + _.times(2, function(index) { + var combined = isFlow + ? func(map, filter, fp.compact, take) + : func(take, fp.compact, filter, map); - filterCount = mapCount = 0; + filterCount = mapCount = 0; - assert.deepEqual(combined(array), [4, 16]); - assert.strictEqual(filterCount, 5, 'filterCount'); - assert.strictEqual(mapCount, 5, 'mapCount'); + assert.deepEqual(combined(array), [4, 16]); + assert.strictEqual(filterCount, 5, 'filterCount'); + assert.strictEqual(mapCount, 5, 'mapCount'); + }); }); }); -}); -/*----------------------------------------------------------------------------*/ + /*--------------------------------------------------------------------------*/ -QUnit.module('fp.inRange'); + QUnit.module('fp.inRange'); -(function() { - QUnit.test('should have an argument order of `start`, `end`, then `value`', function(assert) { - assert.expect(1); + (function() { + QUnit.test('should have an argument order of `start`, `end`, then `value`', function(assert) { + assert.expect(1); - assert.strictEqual(fp.inRange(2)(4)(3), true); - }); -}()); + assert.strictEqual(fp.inRange(2)(4)(3), true); + }); + }()); -/*----------------------------------------------------------------------------*/ + /*--------------------------------------------------------------------------*/ -QUnit.module('fp.iteratee'); + QUnit.module('fp.iteratee'); -(function() { - QUnit.test('should return a iteratee with capped params', function(assert) { - assert.expect(1); + (function() { + QUnit.test('should return a iteratee with capped params', function(assert) { + assert.expect(1); - var func = fp.iteratee(function(a, b, c) { return [a, b, c]; }, undefined, 3); - assert.deepEqual(func(1, 2, 3), [1, undefined, undefined]); - }); + var func = fp.iteratee(function(a, b, c) { return [a, b, c]; }, undefined, 3); + assert.deepEqual(func(1, 2, 3), [1, undefined, undefined]); + }); - QUnit.test('should convert by name', function(assert) { - assert.expect(1); + QUnit.test('should convert by name', function(assert) { + assert.expect(1); - var iteratee = convert('iteratee', _.iteratee), - func = iteratee(function(a, b, c) { return [a, b, c]; }, undefined, 3); + if (!document) { + var iteratee = convert('iteratee', _.iteratee), + func = iteratee(function(a, b, c) { return [a, b, c]; }, undefined, 3); - assert.deepEqual(func(1, 2, 3), [1, undefined, undefined]); - }); -}()); + assert.deepEqual(func(1, 2, 3), [1, undefined, undefined]); + } + else { + skipTest(assert); + } + }); + }()); -/*----------------------------------------------------------------------------*/ + /*--------------------------------------------------------------------------*/ -QUnit.module('fp.maxBy and fp.minBy'); + QUnit.module('fp.maxBy and fp.minBy'); -_.each(['maxBy', 'minBy'], function(methodName, index) { - var array = [1, 2, 3], - func = fp[methodName], - isMax = !index; + _.each(['maxBy', 'minBy'], function(methodName, index) { + var array = [1, 2, 3], + func = fp[methodName], + isMax = !index; - QUnit.test('`fp.' + methodName + '` should work with an `iteratee` argument', function(assert) { - assert.expect(1); + QUnit.test('`fp.' + methodName + '` should work with an `iteratee` argument', function(assert) { + assert.expect(1); - var actual = func(function(num) { - return -num; - })(array); + var actual = func(function(num) { + return -num; + })(array); - assert.strictEqual(actual, isMax ? 1 : 3); - }); + assert.strictEqual(actual, isMax ? 1 : 3); + }); - QUnit.test('`fp.' + methodName + '` should provide the correct `iteratee` arguments', function(assert) { - assert.expect(1); + QUnit.test('`fp.' + methodName + '` should provide the correct `iteratee` arguments', function(assert) { + assert.expect(1); - var args; + var args; - func(function() { - args || (args = slice.call(arguments)); - })(array); + func(function() { + args || (args = slice.call(arguments)); + })(array); - assert.deepEqual(args, [1]); + assert.deepEqual(args, [1]); + }); }); -}); -/*----------------------------------------------------------------------------*/ + /*--------------------------------------------------------------------------*/ -QUnit.module('fp.mixin'); + QUnit.module('fp.mixin'); -(function() { - var source = { 'a': _.noop }; + (function() { + var source = { 'a': _.noop }; - QUnit.test('should mixin static methods but not prototype methods', function(assert) { - assert.expect(2); + QUnit.test('should mixin static methods but not prototype methods', function(assert) { + assert.expect(2); - fp.mixin(source); + fp.mixin(source); - assert.strictEqual(typeof fp.a, 'function'); - assert.notOk('a' in fp.prototype); + assert.strictEqual(typeof fp.a, 'function'); + assert.notOk('a' in fp.prototype); - delete fp.a; - delete fp.prototype.a; - }); + delete fp.a; + delete fp.prototype.a; + }); - QUnit.test('should not assign inherited `source` methods', function(assert) { - assert.expect(2); + QUnit.test('should not assign inherited `source` methods', function(assert) { + assert.expect(2); - function Foo() {} - Foo.prototype.a = _.noop; - fp.mixin(new Foo); + function Foo() {} + Foo.prototype.a = _.noop; + fp.mixin(new Foo); - assert.notOk('a' in fp); - assert.notOk('a' in fp.prototype); + assert.notOk('a' in fp); + assert.notOk('a' in fp.prototype); - delete fp.a; - delete fp.prototype.a; - }); + delete fp.a; + delete fp.prototype.a; + }); - QUnit.test('should not remove existing prototype methods', function(assert) { - assert.expect(2); + QUnit.test('should not remove existing prototype methods', function(assert) { + assert.expect(2); - var each1 = fp.each, - each2 = fp.prototype.each; + var each1 = fp.each, + each2 = fp.prototype.each; - fp.mixin({ 'each': source.a }); + fp.mixin({ 'each': source.a }); - assert.strictEqual(fp.each, source.a); - assert.strictEqual(fp.prototype.each, each2); + assert.strictEqual(fp.each, source.a); + assert.strictEqual(fp.prototype.each, each2); - fp.each = each1; - fp.prototype.each = each2; - }); + fp.each = each1; + fp.prototype.each = each2; + }); - QUnit.test('should not export to the global when `source` is not an object', function(assert) { - assert.expect(2); + QUnit.test('should not export to the global when `source` is not an object', function(assert) { + assert.expect(2); - var props = _.without(_.keys(_), '_'); + var props = _.without(_.keys(_), '_'); - _.times(2, function(index) { - fp.mixin.apply(fp, index ? [1] : []); + _.times(2, function(index) { + fp.mixin.apply(fp, index ? [1] : []); - assert.ok(_.every(props, function(key) { - return global[key] !== fp[key]; - })); + assert.ok(_.every(props, function(key) { + return root[key] !== fp[key]; + })); - _.each(props, function(key) { - delete global[key]; + _.each(props, function(key) { + delete root[key]; + }); }); }); - }); - QUnit.test('should convert by name', function(assert) { - assert.expect(3); + QUnit.test('should convert by name', function(assert) { + assert.expect(3); - var object = { 'mixin': convert('mixin', _.mixin) }; + if (!document) { + var object = { 'mixin': convert('mixin', _.mixin) }; - function Foo() {} - Foo.mixin = object.mixin; - Foo.mixin(source); + function Foo() {} + Foo.mixin = object.mixin; + Foo.mixin(source); - assert.strictEqual(typeof Foo.a, 'function'); - assert.notOk('a' in Foo.prototype); + assert.strictEqual(typeof Foo.a, 'function'); + assert.notOk('a' in Foo.prototype); - object.mixin(source); - assert.strictEqual(typeof object.a, 'function'); - }); -}()); + object.mixin(source); + assert.strictEqual(typeof object.a, 'function'); + } + else { + skipTest(assert, 3); + } + }); + }()); -/*----------------------------------------------------------------------------*/ + /*--------------------------------------------------------------------------*/ -QUnit.module('fp.random'); + QUnit.module('fp.random'); -(function() { - var array = Array(1000); + (function() { + var array = Array(1000); - QUnit.test('should support a `min` and `max` argument', function(assert) { - assert.expect(1); + QUnit.test('should support a `min` and `max` argument', function(assert) { + assert.expect(1); - var min = 5, - max = 10; + var min = 5, + max = 10; - assert.ok(_.some(array, function() { - var result = fp.random(min)(max); - return result >= min && result <= max; - })); - }); -}()); + assert.ok(_.some(array, function() { + var result = fp.random(min)(max); + return result >= min && result <= max; + })); + }); + }()); -/*----------------------------------------------------------------------------*/ + /*--------------------------------------------------------------------------*/ -QUnit.module('fp.range'); + QUnit.module('fp.range'); -(function() { - QUnit.test('should have an argument order of `start` then `end`', function(assert) { - assert.expect(1); + (function() { + QUnit.test('should have an argument order of `start` then `end`', function(assert) { + assert.expect(1); - assert.deepEqual(fp.range(1)(4), [1, 2, 3]); - }); -}()); + assert.deepEqual(fp.range(1)(4), [1, 2, 3]); + }); + }()); -/*----------------------------------------------------------------------------*/ + /*--------------------------------------------------------------------------*/ -QUnit.module('fp.runInContext'); + QUnit.module('fp.runInContext'); -(function() { - QUnit.test('should return a converted lodash instance', function(assert) { - assert.expect(1); + (function() { + QUnit.test('should return a converted lodash instance', function(assert) { + assert.expect(1); - assert.strictEqual(typeof fp.runInContext({}).curryN, 'function'); - }); + assert.strictEqual(typeof fp.runInContext({}).curryN, 'function'); + }); - QUnit.test('should convert by name', function(assert) { - assert.expect(1); + QUnit.test('should convert by name', function(assert) { + assert.expect(1); - var runInContext = convert('runInContext', _.runInContext); - assert.strictEqual(typeof runInContext({}).curryN, 'function'); - }); -}()); + if (!document) { + var runInContext = convert('runInContext', _.runInContext); + assert.strictEqual(typeof runInContext({}).curryN, 'function'); + } + else { + skipTest(assert); + } + }); + }()); -/*----------------------------------------------------------------------------*/ + /*--------------------------------------------------------------------------*/ -QUnit.module('fp.uniqBy'); + QUnit.module('fp.uniqBy'); -(function() { - var objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }, { 'a': 2 }, { 'a': 3 }, { 'a': 1 }]; + (function() { + var objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }, { 'a': 2 }, { 'a': 3 }, { 'a': 1 }]; - QUnit.test('should work with an `iteratee` argument', function(assert) { - assert.expect(1); + QUnit.test('should work with an `iteratee` argument', function(assert) { + assert.expect(1); - var expected = objects.slice(0, 3); + var expected = objects.slice(0, 3); - var actual = fp.uniqBy(function(object) { - return object.a; - })(objects); + var actual = fp.uniqBy(function(object) { + return object.a; + })(objects); - assert.deepEqual(actual, expected); - }); + assert.deepEqual(actual, expected); + }); - QUnit.test('should provide the correct `iteratee` arguments', function(assert) { - assert.expect(1); + QUnit.test('should provide the correct `iteratee` arguments', function(assert) { + assert.expect(1); - var args; + var args; - fp.uniqBy(function() { - args || (args = slice.call(arguments)); - })(objects); + fp.uniqBy(function() { + args || (args = slice.call(arguments)); + })(objects); - assert.deepEqual(args, [objects[0]]); - }); -}()); + assert.deepEqual(args, [objects[0]]); + }); + }()); -/*----------------------------------------------------------------------------*/ + /*--------------------------------------------------------------------------*/ -QUnit.module('fp.zip'); + QUnit.module('fp.zip'); -(function() { - QUnit.test('should zip together two arrays', function(assert) { - assert.expect(1); + (function() { + QUnit.test('should zip together two arrays', function(assert) { + assert.expect(1); - assert.deepEqual(fp.zip([1, 2], [3, 4]), [[1, 3], [2, 4]]); - }); -}()); + assert.deepEqual(fp.zip([1, 2], [3, 4]), [[1, 3], [2, 4]]); + }); + }()); -/*----------------------------------------------------------------------------*/ + /*--------------------------------------------------------------------------*/ -QUnit.module('fp.zipObject'); + QUnit.module('fp.zipObject'); -(function() { - QUnit.test('should zip together key/value arrays into an object', function(assert) { - assert.expect(1); + (function() { + QUnit.test('should zip together key/value arrays into an object', function(assert) { + assert.expect(1); - assert.deepEqual(fp.zipObject(['a', 'b'], [1, 2]), { 'a': 1, 'b': 2 }); - }); -}()); + assert.deepEqual(fp.zipObject(['a', 'b'], [1, 2]), { 'a': 1, 'b': 2 }); + }); + }()); -/*----------------------------------------------------------------------------*/ + /*--------------------------------------------------------------------------*/ -QUnit.module('mutation methods'); + QUnit.module('mutation methods'); -(function() { - var array = [1, 2, 3], - object = { 'a': 1 }; + (function() { + var array = [1, 2, 3], + object = { 'a': 1 }; - QUnit.test('should not mutate values', function(assert) { - assert.expect(28); + QUnit.test('should not mutate values', function(assert) { + assert.expect(28); - function Foo() {} - Foo.prototype = { 'b': 2 }; + function Foo() {} + Foo.prototype = { 'b': 2 }; - var value = _.clone(object), - actual = fp.assign({ 'b': 2 }, value); + var value = _.clone(object), + actual = fp.assign({ 'b': 2 }, value); - assert.deepEqual(value, object, 'fp.assign'); - assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.assign'); + assert.deepEqual(value, object, 'fp.assign'); + assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.assign'); - value = _.clone(object); - actual = fp.assignWith(function(objValue, srcValue) { - return srcValue; - }, { 'b': 2 }, value); + value = _.clone(object); + actual = fp.assignWith(function(objValue, srcValue) { + return srcValue; + }, { 'b': 2 }, value); - assert.deepEqual(value, object, 'fp.assignWith'); - assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.assignWith'); + assert.deepEqual(value, object, 'fp.assignWith'); + assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.assignWith'); - value = _.clone(object); - actual = fp.defaults({ 'a': 2, 'b': 2 }, value); + value = _.clone(object); + actual = fp.defaults({ 'a': 2, 'b': 2 }, value); - assert.deepEqual(value, object, 'fp.defaults'); - assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.defaults'); + assert.deepEqual(value, object, 'fp.defaults'); + assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.defaults'); - value = _.clone(object); - value.b = { 'c': 1 }; - actual = fp.defaultsDeep({ 'b': { 'c': 2, 'd': 2 } }, value); + value = _.clone(object); + value.b = { 'c': 1 }; + actual = fp.defaultsDeep({ 'b': { 'c': 2, 'd': 2 } }, value); - assert.deepEqual(value, { 'a': 1, 'b': { 'c': 1 } } , 'fp.defaultsDeep'); - assert.deepEqual(actual, { 'a': 1, 'b': { 'c': 1, 'd': 2 } }, 'fp.defaultsDeep'); + assert.deepEqual(value, { 'a': 1, 'b': { 'c': 1 } } , 'fp.defaultsDeep'); + assert.deepEqual(actual, { 'a': 1, 'b': { 'c': 1, 'd': 2 } }, 'fp.defaultsDeep'); - value = _.clone(object); - actual = fp.extend(new Foo, value); + value = _.clone(object); + actual = fp.extend(new Foo, value); - assert.deepEqual(value, object, 'fp.extend'); - assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.extend'); + assert.deepEqual(value, object, 'fp.extend'); + assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.extend'); - value = _.clone(object); - actual = fp.extendWith(function(objValue, srcValue) { - return srcValue; - }, new Foo, value); + value = _.clone(object); + actual = fp.extendWith(function(objValue, srcValue) { + return srcValue; + }, new Foo, value); - assert.deepEqual(value, object, 'fp.extendWith'); - assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.extendWith'); + assert.deepEqual(value, object, 'fp.extendWith'); + assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.extendWith'); - value = _.clone(array); - actual = fp.fill(1, 2, '*', value); + value = _.clone(array); + actual = fp.fill(1, 2, '*', value); - assert.deepEqual(value, array, 'fp.fill'); - assert.deepEqual(actual, [1, '*', 3], 'fp.fill'); + assert.deepEqual(value, array, 'fp.fill'); + assert.deepEqual(actual, [1, '*', 3], 'fp.fill'); - value = { 'a': { 'b': 2 } }; - actual = fp.merge({ 'a': { 'c': 3 } }, value); + value = { 'a': { 'b': 2 } }; + actual = fp.merge({ 'a': { 'c': 3 } }, value); - assert.deepEqual(value, { 'a': { 'b': 2 } }, 'fp.merge'); - assert.deepEqual(actual, { 'a': { 'b': 2, 'c': 3 } }, 'fp.merge'); + assert.deepEqual(value, { 'a': { 'b': 2 } }, 'fp.merge'); + assert.deepEqual(actual, { 'a': { 'b': 2, 'c': 3 } }, 'fp.merge'); - value = { 'a': [1] }; - actual = fp.mergeWith(function(objValue, srcValue) { - if (_.isArray(objValue)) { - return objValue.concat(srcValue); - } - }, { 'a': [2, 3] }, value); + value = { 'a': [1] }; + actual = fp.mergeWith(function(objValue, srcValue) { + if (_.isArray(objValue)) { + return objValue.concat(srcValue); + } + }, { 'a': [2, 3] }, value); - assert.deepEqual(value, { 'a': [1] }, 'fp.mergeWith'); - assert.deepEqual(actual, { 'a': [1, 2, 3] }, 'fp.mergeWith'); + assert.deepEqual(value, { 'a': [1] }, 'fp.mergeWith'); + assert.deepEqual(actual, { 'a': [1, 2, 3] }, 'fp.mergeWith'); - value = _.clone(array); - actual = fp.pull(2, value); + value = _.clone(array); + actual = fp.pull(2, value); - assert.deepEqual(value, array, 'fp.pull'); - assert.deepEqual(actual, [1, 3], 'fp.pull'); + assert.deepEqual(value, array, 'fp.pull'); + assert.deepEqual(actual, [1, 3], 'fp.pull'); - value = _.clone(array); - actual = fp.pullAll([1, 3], value); + value = _.clone(array); + actual = fp.pullAll([1, 3], value); - assert.deepEqual(value, array, 'fp.pullAll'); - assert.deepEqual(actual, [2], 'fp.pullAll'); + assert.deepEqual(value, array, 'fp.pullAll'); + assert.deepEqual(actual, [2], 'fp.pullAll'); - value = _.clone(array); - actual = fp.pullAt([0, 2], value); + value = _.clone(array); + actual = fp.pullAt([0, 2], value); - assert.deepEqual(value, array, 'fp.pullAt'); - assert.deepEqual(actual, [2], 'fp.pullAt'); + assert.deepEqual(value, array, 'fp.pullAt'); + assert.deepEqual(actual, [2], 'fp.pullAt'); - value = _.clone(array); - actual = fp.remove(function(value) { - return value === 2; - }, value); + value = _.clone(array); + actual = fp.remove(function(value) { + return value === 2; + }, value); - assert.deepEqual(value, array, 'fp.remove'); - assert.deepEqual(actual, [1, 3], 'fp.remove'); + assert.deepEqual(value, array, 'fp.remove'); + assert.deepEqual(actual, [1, 3], 'fp.remove'); - value = _.clone(array); - actual = fp.reverse(value); + value = _.clone(array); + actual = fp.reverse(value); - assert.deepEqual(value, array, 'fp.reverse'); - assert.deepEqual(actual, [3, 2, 1], 'fp.reverse'); - }); -}()); + assert.deepEqual(value, array, 'fp.reverse'); + assert.deepEqual(actual, [3, 2, 1], 'fp.reverse'); + }); + }()); -/*----------------------------------------------------------------------------*/ + /*--------------------------------------------------------------------------*/ -QUnit.module('with methods'); + QUnit.module('with methods'); -(function() { - var array = [1, 2, 3], - object = { 'a': 1 }; + (function() { + var array = [1, 2, 3], + object = { 'a': 1 }; - QUnit.test('should provice the correct `customizer` arguments', function(assert) { - assert.expect(3); + QUnit.test('should provice the correct `customizer` arguments', function(assert) { + assert.expect(3); - var args, - value = _.clone(object); + var args, + value = _.clone(object); - var actual = fp.assignWith(function(objValue, srcValue) { - args || (args = _.map(arguments, _.cloneDeep)); - return srcValue; - }, { 'b': 2 }, value); + var actual = fp.assignWith(function(objValue, srcValue) { + args || (args = _.map(arguments, _.cloneDeep)); + return srcValue; + }, { 'b': 2 }, value); - assert.deepEqual(args, [undefined, 2, 'b', { 'a': 1 }, { 'b': 2 }], 'fp.assignWith'); + assert.deepEqual(args, [undefined, 2, 'b', { 'a': 1 }, { 'b': 2 }], 'fp.assignWith'); - args = null; - value = _.clone(object); + args = null; + value = _.clone(object); - actual = fp.extendWith(function(objValue, srcValue) { - args || (args = _.map(arguments, _.cloneDeep)); - return srcValue; - }, { 'b': 2 }, value); + actual = fp.extendWith(function(objValue, srcValue) { + args || (args = _.map(arguments, _.cloneDeep)); + return srcValue; + }, { 'b': 2 }, value); - assert.deepEqual(args, [undefined, 2, 'b', { 'a': 1 }, { 'b': 2 }], 'fp.extendWith'); + assert.deepEqual(args, [undefined, 2, 'b', { 'a': 1 }, { 'b': 2 }], 'fp.extendWith'); - args = null; - value = { 'a': [1] }; + args = null; + value = { 'a': [1] }; - var stack = { '__data__': { 'array': [], 'map': null } }, - expected = [[1], [2, 3], 'a', { 'a': [ 1 ] }, { 'a': [2, 3] }, stack]; + var stack = { '__data__': { 'array': [], 'map': null } }, + expected = [[1], [2, 3], 'a', { 'a': [ 1 ] }, { 'a': [2, 3] }, stack]; - actual = fp.mergeWith(function(objValue, srcValue) { - args || (args = _.map(arguments, _.cloneDeep)); - if (_.isArray(objValue)) { - return objValue.concat(srcValue); - } - }, { 'a': [2, 3] }, value); + actual = fp.mergeWith(function(objValue, srcValue) { + args || (args = _.map(arguments, _.cloneDeep)); + if (_.isArray(objValue)) { + return objValue.concat(srcValue); + } + }, { 'a': [2, 3] }, value); - assert.deepEqual(args, expected, 'fp.mergeWith'); - }); -}()); + assert.deepEqual(args, expected, 'fp.mergeWith'); + }); + }()); + + /*--------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ + QUnit.config.asyncRetries = 10; + QUnit.config.hidepassed = true; -QUnit.config.asyncRetries = 10; -QUnit.config.hidepassed = true; -QUnit.config.noglobals = true; -QUnit.load(); + if (!document) { + QUnit.config.noglobals = true; + QUnit.load(); + } +}.call(this)); From 7cdf708e3c907de6ad74db0d4c679c3ca7713bbf Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sun, 6 Dec 2015 10:35:41 -0800 Subject: [PATCH 724/935] Prevent false minified method name test fail. --- test/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test.js b/test/test.js index d409beda57..963b5dd7cf 100644 --- a/test/test.js +++ b/test/test.js @@ -22711,7 +22711,7 @@ QUnit.test('should not contain minified method names (test production builds)', function(assert) { assert.expect(1); - var shortNames = ['at', 'eq', 'gt', 'lt']; + var shortNames = ['_', 'at', 'eq', 'gt', 'lt']; assert.ok(lodashStable.every(_.functions(_), function(methodName) { return methodName.length > 2 || lodashStable.includes(shortNames, methodName); })); From 268d411bb410d11903d1d10fb75f022478c331f0 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sun, 6 Dec 2015 00:15:44 -0800 Subject: [PATCH 725/935] Update lodash builds in travis.yml. --- .travis.yml | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index 00a2b89af6..73189fbaa6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,23 +40,27 @@ before_install: - "nvm use $TRAVIS_NODE_VERSION" - "npm config set loglevel error" - "npm i -g npm@\"$NPM_VERSION\"" - - "git clone --depth=10 --branch=master git://github.com/lodash/lodash-cli ./node_modules/lodash-cli && mkdir $_/node_modules && cd $_ && ln -s ../../../ ./lodash && cd ../ && npm i && cd ../../" - - "node ./node_modules/lodash-cli/bin/lodash -o ./lodash.js" - "[ $ISTANBUL == false ] || perl -0pi -e \"$PATTERN1\" ./lodash.js" - "[ $ISTANBUL == false ] || perl -0pi -e \"$PATTERN2\" ./lodash.js" - "[ $ISTANBUL == false ] || perl -0pi -e \"$PATTERN3\" ./lodash.js" + - "git clone --depth=10 --branch=master git://github.com/lodash/lodash-cli ./node_modules/lodash-cli && mkdir $_/node_modules && cd $_ && ln -s ../../../ ./lodash && cd ../ && npm i && cd ../../" + - "node ./node_modules/lodash-cli/bin/lodash -o ./dist/lodash.js" script: - - "[ $ISTANBUL == false ] || node ./node_modules/istanbul/lib/cli.js cover -x \"**/vendor/**\" --report lcovonly ./test/test.js -- ./lodash.js" + - "[ $ISTANBUL == false ] || node ./node_modules/istanbul/lib/cli.js cover -x \"**/vendor/**\" --report lcovonly ./test/test.js -- ./dist/lodash.js" - "[ $ISTANBUL == false ] || [ $TRAVIS_SECURE_ENV_VARS == false ] || (cat ./coverage/lcov.info | coveralls) || true" - "[ $SAUCE_LABS == true ] || [ $ISTANBUL == true ] || cd ./test" - "[ $SAUCE_LABS == true ] || [ $ISTANBUL == true ] || $BIN $OPTION ./test.js ../lodash.js" - - "[ $SAUCE_LABS == true ] || [ $ISTANBUL == true ] || [ $TRAVIS_SECURE_ENV_VARS == false ] || $BIN $OPTION ./test.js ../lodash.min.js" - - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"lodash tests\" runner=\"test/index.html?build=../lodash.js&noglobals=true\" tags=\"development\"" - - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"lodash tests\" runner=\"test/index.html?build=../lodash.min.js&noglobals=true\" tags=\"production\"" - - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"lodash-fp tests\" runner=\"test/fp.html?noglobals=true\" tags=\"development\"" - - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"underscore tests\" runner=\"test/underscore.html?build=../lodash.js\" tags=\"development,underscore\"" - - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"underscore tests\" runner=\"test/underscore.html?build=../lodash.min.js\" tags=\"production,underscore\"" - - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"backbone tests\" runner=\"test/backbone.html?build=../lodash.js\" tags=\"development,backbone\"" - - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"backbone tests\" runner=\"test/backbone.html?build=../lodash.min.js\" tags=\"production,backbone\"" - - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"backbone tests\" runner=\"test/backbone.html?build=../dist/lodash.core.js\" tags=\"development,backbone\"" - - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"backbone tests\" runner=\"test/backbone.html?build=../dist/lodash.core.min.js\" tags=\"production,backbone\"" + - "[ $SAUCE_LABS == true ] || [ $ISTANBUL == true ] || [ $TRAVIS_SECURE_ENV_VARS == false ] || $BIN $OPTION ./test.js ../dist/lodash.min.js" + - "[ $SAUCE_LABS == false ] || rm -rf ./node_modules/lodash" + - "[ $SAUCE_LABS == false ] || ($BIN ./node_modules/lodash-cli/bin/lodash modularize exports=node -o ./node_modules/lodash && node ./node_modules/lodash-cli/bin/lodash -d -o ./node_modules/lodash/index.js)" + - "[ $SAUCE_LABS == false ] || $BIN ./node_modules/lodash-cli/bin/lodash core -o ./dist/lodash.core.js" + - "[ $SAUCE_LABS == false ] || npm run build" + - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"lodash tests\" runner=\"test/index.html?build=../dist/lodash.js&noglobals=true\" tags=\"development\"" + - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"lodash tests\" runner=\"test/index.html?build=../dist/lodash.min.js&noglobals=true\" tags=\"production\"" + - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"lodash-fp tests\" runner=\"test/fp.html?noglobals=true\" tags=\"development\"" + - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"underscore tests\" runner=\"test/underscore.html?build=../dist/lodash.js\" tags=\"development,underscore\"" + - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"underscore tests\" runner=\"test/underscore.html?build=../dist/lodash.min.js\" tags=\"production,underscore\"" + - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"backbone tests\" runner=\"test/backbone.html?build=../dist/lodash.js\" tags=\"development,backbone\"" + - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"backbone tests\" runner=\"test/backbone.html?build=../dist/lodash.min.js\" tags=\"production,backbone\"" + - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"backbone tests\" runner=\"test/backbone.html?build=../dist/lodash.core.js\" tags=\"development,backbone\"" + - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"backbone tests\" runner=\"test/backbone.html?build=../dist/lodash.core.min.js\" tags=\"production,backbone\"" From a7f1c3c883862dc74f3dc8d054c3b985e08df502 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Mon, 7 Dec 2015 00:37:37 -0800 Subject: [PATCH 726/935] Fix test fails in IE11. --- lodash.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lodash.js b/lodash.js index fdf45e8406..4758a51d56 100644 --- a/lodash.js +++ b/lodash.js @@ -219,8 +219,8 @@ /** Used to assign default `context` object properties. */ var contextProps = [ 'Array', 'Date', 'Error', 'Float32Array', 'Float64Array', 'Function', - 'Int8Array', 'Int16Array', 'Int32Array', 'Math', 'Object', 'Reflect', - 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array', + 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object', + 'Reflect', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array', 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap', '_', 'clearTimeout', 'isFinite', 'parseFloat', 'parseInt', 'setTimeout' ]; @@ -4713,9 +4713,15 @@ Ctor = result == objectTag ? value.constructor : null, ctorString = typeof Ctor == 'function' ? fnToString.call(Ctor) : ''; - return ctorString == mapCtorString - ? mapTag - : (ctorString == setCtorString ? setTag : result); + if (ctorString) { + if (ctorString == mapCtorString) { + return mapTag; + } + if (ctorString == setCtorString) { + return setTag; + } + } + return result; }; } From 58b235b43508071ddd265495563f5be835acd527 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Mon, 7 Dec 2015 00:58:03 -0800 Subject: [PATCH 727/935] Fix fp test fails in IE10 and Firefox. --- test/test-fp.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/test/test-fp.js b/test/test-fp.js index 8f278e18f5..7f840c6390 100644 --- a/test/test-fp.js +++ b/test/test-fp.js @@ -17,7 +17,8 @@ amd = root.define && define.amd, document = !phantom && root.document, noop = function() {}, - slice = arrayProto.slice; + slice = arrayProto.slice, + WeakMap = root.WeakMap; /*--------------------------------------------------------------------------*/ @@ -360,9 +361,14 @@ filterCount = mapCount = 0; - assert.deepEqual(combined(array), [4, 16]); - assert.strictEqual(filterCount, 5, 'filterCount'); - assert.strictEqual(mapCount, 5, 'mapCount'); + if (WeakMap && WeakMap.name) { + assert.deepEqual(combined(array), [4, 16]); + assert.strictEqual(filterCount, 5, 'filterCount'); + assert.strictEqual(mapCount, 5, 'mapCount'); + } + else { + skipTest(assert, 3); + } }); }); }); @@ -499,7 +505,9 @@ })); _.each(props, function(key) { - delete root[key]; + if (root[key] === fp[key]) { + delete root[key]; + } }); }); }); From f7a49778ea4d91fc5da2bd9ed0d909c139801c7e Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Tue, 8 Dec 2015 08:02:12 -0800 Subject: [PATCH 728/935] Rename `_.modArgs` to `_.overArgs` and remove `_.modArgsSet`. --- lib/fp/mapping.js | 18 +++--- lodash.js | 160 ++++++++++++++++------------------------------ test/test-fp.js | 3 +- test/test.js | 62 +++++++++--------- 4 files changed, 93 insertions(+), 150 deletions(-) diff --git a/lib/fp/mapping.js b/lib/fp/mapping.js index f7e4ad0795..57305f3e7e 100644 --- a/lib/fp/mapping.js +++ b/lib/fp/mapping.js @@ -19,8 +19,7 @@ module.exports = { 'isEqual': ['equals'], 'mapValues': ['mapObj'], 'matchesProperty': ['pathEq'], - 'modArgs': ['useWith'], - 'modArgsSet': ['converge'], + 'overArgs': ['useWith'], 'omit': ['dissoc', 'omitAll'], 'pick': ['pickAll'], 'property': ['prop'], @@ -82,14 +81,13 @@ module.exports = { 'debounce,defaults,defaultsDeep,delay,difference,drop,dropRight,dropRightWhile,' + 'dropWhile,endsWith,every,extend,filter,find,find,findIndex,findKey,findLast,' + 'findLastIndex,findLastKey,flatMap,forEach,forEachRight,forIn,forInRight,' + - 'forOwn,forOwnRight,get,groupBy,includes,indexBy,indexOf,intersection,' + - 'invoke,invokeMap,isMatch,lastIndexOf,map,mapKeys,mapValues,matchesProperty,' + - 'maxBy,mean,minBy,merge,modArgs,modArgsSet,omit,pad,padLeft,padRight,parseInt,' + - 'partition,pick,pull,pullAll,pullAt,random,range,rangeRight,rearg,reject,' + - 'remove,repeat,result,sampleSize,set,some,sortBy,sortByOrder,sortedIndexBy,' + - 'sortedLastIndexBy,sortedUniqBy,startsWith,subtract,sumBy,take,takeRight,' + - 'takeRightWhile,takeWhile,throttle,times,truncate,union,uniqBy,without,wrap,' + - 'xor,zip,zipObject').split(','), + 'forOwn,forOwnRight,get,groupBy,includes,indexBy,indexOf,intersection,invoke,' + + 'invokeMap,isMatch,lastIndexOf,map,mapKeys,mapValues,matchesProperty,maxBy,' + + 'mean,minBy,merge,omit,overArgs,pad,padLeft,padRight,parseInt,partition,' + + 'pick,pull,pullAll,pullAt,random,range,rangeRight,rearg,reject,remove,repeat,' + + 'result,sampleSize,set,some,sortBy,sortByOrder,sortedIndexBy,sortedLastIndexBy,' + + 'sortedUniqBy,startsWith,subtract,sumBy,take,takeRight,takeRightWhile,takeWhile,' + + 'throttle,times,truncate,union,uniqBy,without,wrap,xor,zip,zipObject').split(','), 3: ( 'assignWith,clamp,differenceBy,extendWith,getOr,inRange,intersectionBy,' + 'isEqualWith,isMatchWith,mergeWith,omitBy,pickBy,pullAllBy,reduce,' + diff --git a/lodash.js b/lodash.js index 4758a51d56..ee69b9b2fb 100644 --- a/lodash.js +++ b/lodash.js @@ -1514,13 +1514,13 @@ * `intersection`, `intersectionBy`, `intersectionWith`, invert`, `invokeMap`, * `iteratee`, `keyBy`, `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, * `matches`, `matchesProperty`, `memoize`, `merge`, `mergeWith`, `method`, - * `methodOf`, `mixin`, `modArgs`, `modArgsSet', `negate`, `nthArg`, `omit`, - * `omitBy`, `once`, `over`, `overEvery`, `overSome`, `partial`, `partialRight`, - * `partition`, `pick`, `pickBy`, `plant`, `property`, `propertyOf`, `pull`, - * `pullAll`, `pullAllBy`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, - * `reject`, `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, - * `shuffle`, `slice`, `sort`, `sortBy`, `sortByOrder`, `splice`, `spread`, - * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, `tap`, `throttle`, + * `methodOf`, `mixin`, `negate`, `nthArg`, `omit`, `omitBy`, `once`, `over`, + * `overArgs`, `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, + * `pick`, `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, + * `pullAllBy`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`,`reject`, + * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`, + * `slice`, `sort`, `sortBy`, `sortByOrder`, `splice`, `spread`, `tail`, + * `take`, `takeRight`, `takeRightWhile`, `takeWhile`, `tap`, `throttle`, * `thru`, `toArray`, `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, * `transform`, `unary`, `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, * `uniqWith`, `unset`, `unshift`, `unzip`, `unzipWith`, `values`, `valuesIn`, @@ -4173,32 +4173,6 @@ return wrapper; } - /** - * Creates a function like `_.modArgs`. - * - * @private - * @param {Function} resolver The function to resolve which invocation - * arguments are provided to each transform. - * @returns {Function} Returns the new arguments modifier function. - */ - function createModArgs(resolver) { - return rest(function(func, transforms) { - transforms = arrayMap(baseFlatten(transforms), getIteratee()); - - var funcsLength = transforms.length; - return rest(function(args) { - var index = -1, - length = nativeMin(args.length, funcsLength), - modded = copyArray(args); - - while (++index < length) { - modded[index] = transforms[index].apply(this, resolver(args[index], index, args)); - } - return func.apply(this, modded); - }); - }); - } - /** * Creates a function like `_.over`. * @@ -8673,76 +8647,6 @@ return memoized; } - /** - * Creates a function that invokes `func` with arguments modified by - * corresponding `transforms`. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to wrap. - * @param {...(Function|Function[])} [transforms] The functions to transform - * arguments, specified individually or in arrays. - * @returns {Function} Returns the new function. - * @example - * - * function doubled(n) { - * return n * 2; - * } - * - * function square(n) { - * return n * n; - * } - * - * var modded = _.modArgs(function(x, y) { - * return [x, y]; - * }, square, doubled); - * - * modded(9, 3); - * // => [81, 6] - * - * modded(10, 5); - * // => [100, 10] - */ - var modArgs = createModArgs(function(value) { - return [value]; - }); - - /** - * This method is like `_.modArgs` except that each of the `transforms` is - * provided the complete set of arguments the created function is invoked with. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to wrap. - * @param {...(Function|Function[])} [transforms] The functions to transform - * arguments, specified individually or in arrays. - * @returns {Function} Returns the new function. - * @example - * - * function divide(x, y) { - * return x / y; - * } - * - * function multiply(x, y) { - * return x * y; - * } - * - * var modded = _.modArgsSet(function(x, y) { - * return [x, y]; - * }, multiply, divide); - * - * modded(9, 3); - * // => [27, 3] - * - * modded(10, 5); - * // => [50, 2] - */ - var modArgsSet = createModArgs(function(value, index, args) { - return args; - }); - /** * Creates a function that negates the result of the predicate `func`. The * `func` predicate is invoked with the `this` binding and arguments of the @@ -8792,6 +8696,53 @@ return before(2, func); } + /** + * Creates a function that invokes `func` with arguments transformed by + * corresponding `transforms`. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to wrap. + * @param {...(Function|Function[])} [transforms] The functions to transform + * arguments, specified individually or in arrays. + * @returns {Function} Returns the new function. + * @example + * + * function doubled(n) { + * return n * 2; + * } + * + * function square(n) { + * return n * n; + * } + * + * var func = _.overArgs(function(x, y) { + * return [x, y]; + * }, square, doubled); + * + * func(9, 3); + * // => [81, 6] + * + * func(10, 5); + * // => [100, 10] + */ + var overArgs = rest(function(func, transforms) { + transforms = arrayMap(baseFlatten(transforms), getIteratee()); + + var funcsLength = transforms.length; + return rest(function(args) { + var index = -1, + length = nativeMin(args.length, funcsLength), + newArgs = copyArray(args); + + while (++index < length) { + newArgs[index] = transforms[index].call(this, args[index]); + } + return apply(func, this, newArgs); + }); + }); + /** * Creates a function that invokes `func` with `partial` arguments prepended * to those provided to the new function. This method is like `_.bind` except @@ -13835,14 +13786,13 @@ lodash.method = method; lodash.methodOf = methodOf; lodash.mixin = mixin; - lodash.modArgs = modArgs; - lodash.modArgsSet = modArgsSet; lodash.negate = negate; lodash.nthArg = nthArg; lodash.omit = omit; lodash.omitBy = omitBy; lodash.once = once; lodash.over = over; + lodash.overArgs = overArgs; lodash.overEvery = overEvery; lodash.overSome = overSome; lodash.partial = partial; diff --git a/test/test-fp.js b/test/test-fp.js index 7f840c6390..6ee269cf49 100644 --- a/test/test-fp.js +++ b/test/test-fp.js @@ -120,8 +120,7 @@ var funcMethods = [ 'after', 'ary', 'before', 'bind', 'bindKey', 'cloneDeepWith', 'cloneWith', - 'curryN', 'debounce', 'delay', 'modArgs', 'modArgsSet', 'rearg', 'throttle', - 'wrap' + 'curryN', 'debounce', 'delay', 'overArgs', 'rearg', 'throttle', 'wrap' ]; var exceptions = _.difference(funcMethods.concat('matchesProperty'), ['cloneDeepWith', 'cloneWith', 'delay']), diff --git a/test/test.js b/test/test.js index 963b5dd7cf..45f0fecf37 100644 --- a/test/test.js +++ b/test/test.js @@ -13518,75 +13518,72 @@ /*--------------------------------------------------------------------------*/ - QUnit.module('modArgs methods'); - - lodashStable.each(['modArgs', 'modArgsSet'], function(methodName) { - var func = _[methodName], - isModArgs = methodName == 'modArgs'; + QUnit.module('lodash.overArgs'); + (function() { function fn() { return slice.call(arguments); } - QUnit.test('`_.' + methodName + '` should transform each argument', function(assert) { + QUnit.test('should transform each argument', function(assert) { assert.expect(1); - var modded = func(fn, doubled, square); - assert.deepEqual(modded(5, 10), isModArgs ? [10, 100] : [10, 25]); + var over = _.overArgs(fn, doubled, square); + assert.deepEqual(over(5, 10), [10, 100]); }); - QUnit.test('`_.' + methodName + '` should flatten `transforms`', function(assert) { + QUnit.test('should flatten `transforms`', function(assert) { assert.expect(1); - var modded = func(fn, [doubled, square], String); - assert.deepEqual(modded(5, 10, 15), isModArgs ? [10, 100, '15'] : [10, 25, '5']); + var over = _.overArgs(fn, [doubled, square], String); + assert.deepEqual(over(5, 10, 15), [10, 100, '15']); }); - QUnit.test('`_.' + methodName + '` should not transform any argument greater than the number of transforms', function(assert) { + QUnit.test('should not transform any argument greater than the number of transforms', function(assert) { assert.expect(1); - var modded = func(fn, doubled, square); - assert.deepEqual(modded(5, 10, 18), isModArgs ? [10, 100, 18] : [10, 25, 18]); + var over = _.overArgs(fn, doubled, square); + assert.deepEqual(over(5, 10, 18), [10, 100, 18]); }); - QUnit.test('`_.' + methodName + '` should not transform any arguments if no transforms are provided', function(assert) { + QUnit.test('should not transform any arguments if no transforms are provided', function(assert) { assert.expect(1); - var modded = func(fn); - assert.deepEqual(modded(5, 10, 18), [5, 10, 18]); + var over = _.overArgs(fn); + assert.deepEqual(over(5, 10, 18), [5, 10, 18]); }); - QUnit.test('`_.' + methodName + '` should not pass `undefined` if there are more transforms than arguments', function(assert) { + QUnit.test('should not pass `undefined` if there are more transforms than arguments', function(assert) { assert.expect(1); - var modded = func(fn, doubled, identity); - assert.deepEqual(modded(5), [10]); + var over = _.overArgs(fn, doubled, identity); + assert.deepEqual(over(5), [10]); }); - QUnit.test('`_.' + methodName + '` should provide the correct argument to each transform', function(assert) { + QUnit.test('should provide the correct argument to each transform', function(assert) { assert.expect(1); var argsList = [], transform = function() { argsList.push(slice.call(arguments)); }, - modded = func(noop, transform, transform, transform); + over = _.overArgs(noop, transform, transform, transform); - modded('a', 'b'); - assert.deepEqual(argsList, isModArgs ? [['a'], ['b']] : [['a', 'b'], ['a', 'b']]); + over('a', 'b'); + assert.deepEqual(argsList, [['a'], ['b']]); }); - QUnit.test('`_.' + methodName + '` should use `this` binding of function for transforms', function(assert) { + QUnit.test('should use `this` binding of function for transforms', function(assert) { assert.expect(1); - var modded = func(function(x) { + var over = _.overArgs(function(x) { return this[x]; }, function(x) { return this === x; }); - var object = { 'modded': modded, 'true': 1 }; - assert.strictEqual(object.modded(object), 1); + var object = { 'over': over, 'true': 1 }; + assert.strictEqual(object.over(object), 1); }); - }); + }()); /*--------------------------------------------------------------------------*/ @@ -22541,10 +22538,9 @@ var noBinding = [ 'flip', 'memoize', - 'modArgs', - 'modArgsSet', 'negate', 'once', + 'overArgs', 'partial', 'partialRight', 'rearg', @@ -22600,7 +22596,7 @@ var acceptFalsey = lodashStable.difference(allMethods, rejectFalsey); QUnit.test('should accept falsey arguments', function(assert) { - assert.expect(284); + assert.expect(283); var emptyArrays = lodashStable.map(falsey, lodashStable.constant([])); @@ -22688,7 +22684,7 @@ }); QUnit.test('should not set a `this` binding', function(assert) { - assert.expect(33); + assert.expect(30); lodashStable.each(noBinding, function(methodName) { var fn = function() { return this.a; }, From 095cf94c45b54cc66c9fbde8f312c1a6c564ebdb Mon Sep 17 00:00:00 2001 From: greenkeeperio-bot Date: Tue, 8 Dec 2015 16:29:35 -0800 Subject: [PATCH 729/935] Update jscs to 2.7.0. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5555fb4a25..131d18b8ed 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "fs-extra": "~0.26.2", "istanbul": "0.4.1", "jquery": "~1.11.0", - "jscs": "^2.6.0", + "jscs": "^2.7.0", "lodash": "^3.10.1", "platform": "^1.3.0", "qunit-extras": "~1.4.0", From c96a57929113f0e9f03820ff2c38dcdcdf8a9d85 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Wed, 9 Dec 2015 01:37:34 -0800 Subject: [PATCH 730/935] Simplify `_.overArgs`. --- lodash.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lodash.js b/lodash.js index ee69b9b2fb..0251d03e14 100644 --- a/lodash.js +++ b/lodash.js @@ -8733,13 +8733,12 @@ var funcsLength = transforms.length; return rest(function(args) { var index = -1, - length = nativeMin(args.length, funcsLength), - newArgs = copyArray(args); + length = nativeMin(args.length, funcsLength); while (++index < length) { - newArgs[index] = transforms[index].call(this, args[index]); + args[index] = transforms[index].call(this, args[index]); } - return apply(func, this, newArgs); + return apply(func, this, args); }); }); From 2192b7748e0feef5eeee28af67680913ce22eb1f Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Wed, 9 Dec 2015 23:36:40 -0800 Subject: [PATCH 731/935] Remove test/asset/test-ui.js use from test/fp.html. --- test/fp.html | 1 - 1 file changed, 1 deletion(-) diff --git a/test/fp.html b/test/fp.html index 5d7cfe2480..712296664f 100644 --- a/test/fp.html +++ b/test/fp.html @@ -23,7 +23,6 @@ -