diff --git a/build.js b/build.js index de0312d2d..2807cf4ff 100755 --- a/build.js +++ b/build.js @@ -231,6 +231,7 @@ 'uniq': ['identity', 'indexOf'], 'uniqueId': [], 'values': [], + 'where': ['forIn'], 'without': ['indexOf'], 'wrap': [], 'zip': ['max', 'pluck'], @@ -270,6 +271,7 @@ 'forIn', 'forOwn', 'partial', + 'where', 'zipObject' ])); @@ -338,6 +340,17 @@ return realToAliasMap[funcName] || []; } + /** + * Gets the Lo-Dash method assignments snippet from `source`. + * + * @private + * @param {String} source The source to inspect. + * @returns {String} Returns the method assignments snippet. + */ + function getMethodAssignments(source) { + return (source.match(/lodash\.VERSION *= *[\s\S]+?\/\*-+\*\/\n/) || [''])[0]; + } + /** * Gets an array of depenants for a function by a given name. * @@ -502,7 +515,7 @@ source = source.replace(matchFunction(source, funcName), ''); // grab the method assignments snippet - snippet = source.match(/lodash\.VERSION *= *[\s\S]+?\/\*-+\*\/\n/)[0]; + snippet = getMethodAssignments(source); // remove assignment and aliases modified = getAliases(funcName).concat(funcName).reduce(function(result, otherName) { @@ -771,10 +784,8 @@ if (!iteratorName) { return; } - var snippet, - funcNames = [], - objectSnippets = [], - token = '__isTypeToken__'; + var funcNames = [], + objectSnippets = []; // build replacement code lodash.forOwn({ @@ -788,10 +799,6 @@ funcCode = matchFunction(source, funcName); if (funcCode) { - if (!snippet) { - // use snippet to mark the insert position - snippet = funcCode; - } funcNames.push(funcName); objectSnippets.push("'" + key + "': " + value); } @@ -801,22 +808,21 @@ if (funcNames.length < 2) { return; } - // add a token to mark the position to insert new code - source = source.replace(snippet, '\n' + token + '\n' + snippet); // remove existing isType functions funcNames.forEach(function(funcName) { source = removeFunction(source, funcName); }); - // replace token with new DRY code - source = source.replace(token, + // insert new DRY code after the method assignments + var snippet = getMethodAssignments(source); + source = source.replace(snippet, snippet + '\n' + ' // add `_.' + funcNames.join('`, `_.') + '`\n' + ' ' + iteratorName + '({\n ' + objectSnippets.join(',\n ') + '\n }, function(className, key) {\n' + " lodash['is' + key] = function(value) {\n" + ' return toString.call(value) == className;\n' + ' };\n' + - ' });' + ' });\n' ); }()); diff --git a/build/pre-compile.js b/build/pre-compile.js index c35d3b892..39fb320dc 100644 --- a/build/pre-compile.js +++ b/build/pre-compile.js @@ -18,6 +18,7 @@ 'compareAscending', 'concat', 'ctor', + 'forIn', 'funcClass', 'funcs', 'hasOwnProperty', @@ -35,11 +36,16 @@ 'noaccum', 'object', 'objectTypes', + 'ownIndex', + 'ownProps', + 'pass', 'prop', - 'propIndex', - 'props', + 'properties', 'property', 'propertyIsEnumerable', + 'propIndex', + 'props', + 'propsLength', 'result', 'skipProto', 'slice', @@ -195,6 +201,7 @@ 'values', 'variable', 'VERSION', + 'where', 'without', 'wrap', 'zip', diff --git a/lodash.js b/lodash.js index a7ddd5577..9bdb04829 100644 --- a/lodash.js +++ b/lodash.js @@ -1277,6 +1277,41 @@ return values(collection); } + /** + * Examines each element in a `collection`, returning an array of all elements + * that contain the given `properties`. + * + * @static + * @memberOf _ + * @category Collections + * @param {Array|Object|String} collection The collection to iterate over. + * @param {Object} properties The object of properties/values to filter by. + * @returns {Array} Returns a new array of elements that contain the given `properties`. + * @example + * + * var stooges = [ + * { 'name': 'moe', 'age': 40 }, + * { 'name': 'larry', 'age': 50 }, + * { 'name': 'curly', 'age': 60 } + * ]; + * + * _.where(stooges, { 'age': 40 }); + * // => [{ 'name': 'moe', 'age': 40 }] + */ + var where = createIterator(filterIteratorOptions, { + 'args': 'collection, properties', + 'top': + 'var pass, prop, propIndex, props = [];\n' + + 'forIn(properties, function(value, prop) { props.push(prop) });\n' + + 'var propsLength = props.length', + 'inLoop': + 'for (pass = true, propIndex = 0; propIndex < propsLength; propIndex++) {\n' + + ' prop = props[propIndex];\n' + + ' if (pass = value[prop] === properties[prop]) break\n' + + '}\n' + + 'if (pass) result.push(value)' + }); + /*--------------------------------------------------------------------------*/ /** @@ -3920,6 +3955,7 @@ lodash.uniq = uniq; lodash.uniqueId = uniqueId; lodash.values = values; + lodash.where = where; lodash.without = without; lodash.wrap = wrap; lodash.zip = zip;