From 9999199d2b8b57931021ca5185dd7f542d490331 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Mon, 4 Apr 2016 23:44:44 -0700 Subject: [PATCH] Enable over methods to accept `matchesProperty` shorthands. --- lodash.js | 55 +++++++++++++++++++++++++++++++++++++--------------- test/test.js | 29 +++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 16 deletions(-) diff --git a/lodash.js b/lodash.js index 16a8525cb..fca9ffc84 100644 --- a/lodash.js +++ b/lodash.js @@ -2700,23 +2700,24 @@ * @private * @param {Array} array The array to flatten. * @param {number} depth The maximum recursion depth. - * @param {boolean} [isStrict] Restrict flattening to arrays-like objects. + * @param {boolean} [predicate=isFlattenable] The function invoked per iteration. + * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks. * @param {Array} [result=[]] The initial result value. * @returns {Array} Returns the new flattened array. */ - function baseFlatten(array, depth, isStrict, result) { - result || (result = []); - + function baseFlatten(array, depth, predicate, isStrict, result) { var index = -1, length = array.length; + predicate || (predicate = isFlattenable); + result || (result = []); + while (++index < length) { var value = array[index]; - if (depth > 0 && isArrayLikeObject(value) && - (isStrict || isArray(value) || isArguments(value))) { + if (depth > 0 && predicate(value)) { if (depth > 1) { // Recursively flatten arrays (susceptible to call stack limits). - baseFlatten(value, depth - 1, isStrict, result); + baseFlatten(value, depth - 1, predicate, isStrict, result); } else { arrayPush(result, value); } @@ -4608,7 +4609,7 @@ */ function createOver(arrayFunc) { return rest(function(iteratees) { - iteratees = arrayMap(baseFlatten(iteratees, 1), getIteratee()); + iteratees = arrayMap(baseFlatten(iteratees, 1, isFlattenableIteratee), getIteratee()); return rest(function(args) { var thisArg = this; return arrayFunc(iteratees, function(iteratee) { @@ -5463,6 +5464,29 @@ return null; } + /** + * Checks if `value` is a flattenable `arguments` object or array. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is flattenable, else `false`. + */ + function isFlattenable(value) { + return isArrayLikeObject(value) && (isArray(value) || isArguments(value)); + } + + /** + * Checks if `value` is a flattenable array and not a `_.matchesProperty` + * iteratee shorthand. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is flattenable, else `false`. + */ + function isFlattenableIteratee(value) { + return isArray(value) && !(value.length == 2 && !isFunction(value[0])); + } + /** * Checks if the given arguments are from an iteratee call. * @@ -5922,7 +5946,7 @@ */ var difference = rest(function(array, values) { return isArrayLikeObject(array) - ? baseDifference(array, baseFlatten(values, 1, true)) + ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true)) : []; }); @@ -5956,7 +5980,7 @@ iteratee = undefined; } return isArrayLikeObject(array) - ? baseDifference(array, baseFlatten(values, 1, true), getIteratee(iteratee)) + ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), getIteratee(iteratee)) : []; }); @@ -5987,7 +6011,7 @@ comparator = undefined; } return isArrayLikeObject(array) - ? baseDifference(array, baseFlatten(values, 1, true), undefined, comparator) + ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator) : []; }); @@ -7253,7 +7277,7 @@ * // => [2, 1, 4] */ var union = rest(function(arrays) { - return baseUniq(baseFlatten(arrays, 1, true)); + return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true)); }); /** @@ -7284,7 +7308,7 @@ if (isArrayLikeObject(iteratee)) { iteratee = undefined; } - return baseUniq(baseFlatten(arrays, 1, true), getIteratee(iteratee)); + return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), getIteratee(iteratee)); }); /** @@ -7312,7 +7336,7 @@ if (isArrayLikeObject(comparator)) { comparator = undefined; } - return baseUniq(baseFlatten(arrays, 1, true), undefined, comparator); + return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), undefined, comparator); }); /** @@ -9616,8 +9640,7 @@ * // => [100, 10] */ var overArgs = rest(function(func, transforms) { - transforms = arrayMap(baseFlatten(transforms, 1), getIteratee()); - + transforms = arrayMap(baseFlatten(transforms, 1, isFlattenableIteratee), getIteratee()); var funcsLength = transforms.length; return rest(function(args) { var index = -1, diff --git a/test/test.js b/test/test.js index 7a4c97b5d..4af03d888 100644 --- a/test/test.js +++ b/test/test.js @@ -16040,6 +16040,15 @@ assert.deepEqual(over(object), [false, true]); }); + QUnit.test('should work with "_.matchesProperty" shorthands', function(assert) { + assert.expect(2); + + var over = _.over(['a', 2], [['b', 2]]); + + assert.deepEqual(over({ 'a': 1, 'b': 2 }), [false, true]); + assert.deepEqual(over({ 'a': 2, 'b': 1 }), [true, false]); + }); + QUnit.test('should provide arguments to predicates', function(assert) { assert.expect(1); @@ -16088,6 +16097,7 @@ assert.expect(2); var over = _.overEvery(undefined, null); + assert.strictEqual(over(true), true); assert.strictEqual(over(false), false); }); @@ -16116,6 +16126,15 @@ assert.strictEqual(over(object), false); }); + QUnit.test('should work with "_.matchesProperty" shorthands', function(assert) { + assert.expect(2); + + var over = _.overEvery(['a', 1], [['b', 2]]); + + assert.strictEqual(over({ 'a': 1, 'b': 2 }), true); + assert.strictEqual(over({ 'a': 1, 'b': -2 }), false); + }); + QUnit.test('should flatten `predicates`', function(assert) { assert.expect(1); @@ -16190,6 +16209,7 @@ assert.expect(2); var over = _.overSome(undefined, null); + assert.strictEqual(over(true), true); assert.strictEqual(over(false), false); }); @@ -16218,6 +16238,15 @@ assert.strictEqual(over(object), false); }); + QUnit.test('should work with "_.matchesProperty" shorthands', function(assert) { + assert.expect(2); + + var over = _.overSome(['a', 1], [['b', 2]]); + + assert.strictEqual(over({ 'a': 3, 'b': 2 }), true); + assert.strictEqual(over({ 'a': 2, 'b': 3 }), false); + }); + QUnit.test('should flatten `predicates`', function(assert) { assert.expect(1);