diff --git a/build.js b/build.js
index e8476b684..59c515b65 100755
--- a/build.js
+++ b/build.js
@@ -257,7 +257,126 @@
/*--------------------------------------------------------------------------*/
/**
- * Adds the given build `commands` to the copyright/license header of `source`.
+ * Adds support for Underscore style chaining to the `source`.
+ *
+ * @private
+ * @param {String} source The source to process.
+ * @returns {String} Returns the modified source.
+ */
+ function addChainMethods(source) {
+ // add `_.chain`
+ source = source.replace(matchFunction(source, 'tap'), function(match) {
+ return [
+ '',
+ ' /**',
+ ' * Creates a `lodash` object that wraps the given `value`.',
+ ' *',
+ ' * @static',
+ ' * @memberOf _',
+ ' * @category Chaining',
+ ' * @param {Mixed} value The value to wrap.',
+ ' * @returns {Object} Returns the wrapper object.',
+ ' * @example',
+ ' *',
+ ' * var stooges = [',
+ " * { 'name': 'moe', 'age': 40 },",
+ " * { 'name': 'larry', 'age': 50 },",
+ " * { 'name': 'curly', 'age': 60 }",
+ ' * ];',
+ ' *',
+ ' * var youngest = _.chain(stooges)',
+ ' * .sortBy(function(stooge) { return stooge.age; })',
+ " * .map(function(stooge) { return stooge.name + ' is ' + stooge.age; })",
+ ' * .first();',
+ " * // => 'moe is 40'",
+ ' */',
+ ' function chain(value) {',
+ ' value = new lodash(value);',
+ ' value.__chain__ = true;',
+ ' return value;',
+ ' }',
+ '',
+ match
+ ].join('\n');
+ });
+
+ // add `wrapperChain`
+ source = source.replace(matchFunction(source, 'wrapperToString'), function(match) {
+ return [
+ '',
+ ' /**',
+ ' * Enables method chaining on the wrapper object.',
+ ' *',
+ ' * @name chain',
+ ' * @memberOf _',
+ ' * @category Chaining',
+ ' * @returns {Mixed} Returns the wrapper object.',
+ ' * @example',
+ ' *',
+ ' * var sum = _([1, 2, 3])',
+ ' * .chain()',
+ ' * .reduce(function(sum, num) { return sum + num; })',
+ ' * .value()',
+ ' * // => 6`',
+ ' */',
+ ' function wrapperChain() {',
+ ' this.__chain__ = true;',
+ ' return this;',
+ ' }',
+ '',
+ match
+ ].join('\n');
+ });
+
+ // add `__chain__` checks to `_.mixin` and `Array` function wrappers
+ _.each([
+ matchFunction(source, 'mixin'),
+ /(?:\s*\/\/.*)*\n( *)forEach\(\['[\s\S]+?\n\1}.+/g
+ ], function(pattern) {
+ source = source.replace(pattern, function(match) {
+ return match.replace(/( *)return new lodash\(([^)]+)\).+/, function(submatch, indent, varName) {
+ return indent + [
+ 'if (this.__chain__) {',
+ ' varName = new lodash(varName);',
+ ' varName.__chain__ = true;',
+ '}',
+ 'return varName;'
+ ].join('\n' + indent)
+ .replace(/varName/g, varName);
+ });
+ });
+ });
+
+ // add `lodash.chain` assignment
+ source = source.replace(getMethodAssignments(source), function(match) {
+ return match.replace(/^(?: *\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/\n)?( *)lodash\.VERSION *=/m, '$1lodash.chain = chain;\n\n$&');
+ });
+
+ // add `lodash.prototype.chain` assignment
+ source = source.replace(/^( *)lodash\.prototype\.value *=.+\n/m, '$1lodash.prototype.chain = wrapperChain;\n$&');
+
+ // remove `lodash.prototype.toString` and `lodash.prototype.valueOf` assignments
+ source = source.replace(/^ *lodash\.prototype\.(?:toString|valueOf) *=.+\n/gm, '');
+
+ // remove `lodash.prototype` batch method assignments
+ source = source.replace(/(?:\s*\/\/.*)*\n( *)forOwn\(lodash, *function\(func, *methodName\)[\s\S]+?\n\1}.+/g, '');
+
+ // move `mixin(lodash)` to after the method assignments
+ source = source.replace(/(?:\s*\/\/.*)*\s*mixin\(lodash\).+/, '');
+ source = source.replace(getMethodAssignments(source), function(match) {
+ return match + [
+ '',
+ '',
+ ' // add functions to `lodash.prototype`',
+ ' mixin(lodash);'
+ ].join('\n');
+ });
+
+ return source;
+ }
+
+ /**
+ * Adds build `commands` to the copyright/license header of the `source`.
*
* @private
* @param {String} source The source to process.
@@ -1177,115 +1296,9 @@
source = replaceVar(source, 'noArgsClass', 'true');
source = removeKeysOptimization(source);
}
- // add Underscore's chaining API
if (isBackbone || isUnderscore) {
- // add `_.chain`
- source = source.replace(matchFunction(source, 'tap'), function(match) {
- return [
- '',
- ' /**',
- ' * Creates a `lodash` object that wraps the given `value`.',
- ' *',
- ' * @static',
- ' * @memberOf _',
- ' * @category Chaining',
- ' * @param {Mixed} value The value to wrap.',
- ' * @returns {Object} Returns the wrapper object.',
- ' * @example',
- ' *',
- ' * var stooges = [',
- " * { 'name': 'moe', 'age': 40 },",
- " * { 'name': 'larry', 'age': 50 },",
- " * { 'name': 'curly', 'age': 60 }",
- ' * ];',
- ' *',
- ' * var youngest = _.chain(stooges)',
- ' * .sortBy(function(stooge) { return stooge.age; })',
- " * .map(function(stooge) { return stooge.name + ' is ' + stooge.age; })",
- ' * .first();',
- " * // => 'moe is 40'",
- ' */',
- ' function chain(value) {',
- ' value = new lodash(value);',
- ' value.__chain__ = true;',
- ' return value;',
- ' }',
- '',
- match
- ].join('\n');
- });
-
- // add `wrapperChain`
- source = source.replace(matchFunction(source, 'wrapperToString'), function(match) {
- return [
- '',
- ' /**',
- ' * Enables method chaining on the wrapper object.',
- ' *',
- ' * @name chain',
- ' * @memberOf _',
- ' * @category Chaining',
- ' * @returns {Mixed} Returns the wrapper object.',
- ' * @example',
- ' *',
- ' * var sum = _([1, 2, 3])',
- ' * .chain()',
- ' * .reduce(function(sum, num) { return sum + num; })',
- ' * .value()',
- ' * // => 6`',
- ' */',
- ' function wrapperChain() {',
- ' this.__chain__ = true;',
- ' return this;',
- ' }',
- '',
- match
- ].join('\n');
- });
-
- // add `__chain__` checks to `_.mixin` and `Array` function wrappers
- _.each([
- matchFunction(source, 'mixin'),
- /(?:\s*\/\/.*)*\n( *)forEach\(\['[\s\S]+?\n\1}.+/g
- ], function(pattern) {
- source = source.replace(pattern, function(match) {
- return match.replace(/( *)return new lodash\(([^)]+)\).+/, function(submatch, indent, varName) {
- return indent + [
- 'if (this.__chain__) {',
- ' varName = new lodash(varName);',
- ' varName.__chain__ = true;',
- '}',
- 'return varName;'
- ].join('\n' + indent)
- .replace(/varName/g, varName);
- });
- });
- });
-
- // add `lodash.chain` assignment
- source = source.replace(getMethodAssignments(source), function(match) {
- return match.replace(/^(?: *\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/\n)?( *)lodash\.VERSION *=/m, '$1lodash.chain = chain;\n\n$&');
- });
-
- // add `lodash.prototype.chain` assignment
- source = source.replace(/^( *)lodash\.prototype\.value *=.+\n/m, '$1lodash.prototype.chain = wrapperChain;\n$&');
-
- // remove `lodash.prototype.toString` and `lodash.prototype.valueOf` assignments
- source = source.replace(/^ *lodash\.prototype\.(?:toString|valueOf) *=.+\n/gm, '');
-
- // remove `lodash.prototype` batch method assignments
- source = source.replace(/(?:\s*\/\/.*)*\n( *)forOwn\(lodash, *function\(func, *methodName\)[\s\S]+?\n\1}.+/g, '');
-
- // move `mixin(lodash)` to after the method assignments
- source = source.replace(/(?:\s*\/\/.*)*\s*mixin\(lodash\).+/, '');
- source = source.replace(getMethodAssignments(source), function(match) {
- return match + [
- '',
- '',
- ' // add functions to `lodash.prototype`',
- ' mixin(lodash);'
- ].join('\n');
- });
+ // add Underscore style chaining
+ source = addChainMethods(source);
}
if (isUnderscore) {
// remove unneeded variables
diff --git a/doc/README.md b/doc/README.md
index 455cafffc..8a7b65cd3 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -681,7 +681,7 @@ _.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]);
### `_(value)`
# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L275 "View in source") [Ⓣ][1]
-Creates a `lodash` object, that wraps the given `value`, to enable method chaining. The wrapper functions capable of chaining are: `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`, `compose`, `countBy`, `debounce`, `defaults`, `defer`, `delay`, `difference`, `filter`, `flatten`, `forEach`, `forIn`, `forOwn`, `functions`, `groupBy`, `initial`, `intersection`, `invert`, `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`, `once`, `pairs`, `partial`, `pick`, `pluck`, `range`, `reject`, `rest`, `shuffle`, `sortBy`, `tap`, `throttle`, `times`, `toArray`, `union`, `uniq`, `values`, `where`, `without`, `wrap`, and `zip` The wrapper functions that do not chain are: `clone`, `contains`, `escape`, `every`, `find`, `has`, `identity`, `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`, `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`, `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `lastIndexOf`, `mixin`, `noConflict`, `random`, `reduce`, `reduceRight`, `result`, `size`, `some`, `sortedIndex`, `template`, `unescape`, and `uniqueId` The wrapper functions `first` and `last` return wrapped values when `n` is passed, otherwise unwrapped values are returned.
+Creates a `lodash` object, that wraps the given `value`, to enable method chaining. The chainable wrapper functions are: `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`, `compose`, `countBy`, `debounce`, `defaults`, `defer`, `delay`, `difference`, `filter`, `flatten`, `forEach`, `forIn`, `forOwn`, `functions`, `groupBy`, `initial`, `intersection`, `invert`, `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`, `once`, `pairs`, `partial`, `pick`, `pluck`, `range`, `reject`, `rest`, `shuffle`, `sortBy`, `tap`, `throttle`, `times`, `toArray`, `union`, `uniq`, `values`, `where`, `without`, `wrap`, and `zip` The non-chainable wrapper functions are: `clone`, `contains`, `escape`, `every`, `find`, `has`, `identity`, `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`, `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`, `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `lastIndexOf`, `mixin`, `noConflict`, `random`, `reduce`, `reduceRight`, `result`, `size`, `some`, `sortedIndex`, `template`, `unescape`, and `uniqueId` The wrapper functions `first` and `last` return wrapped values when `n` is passed, otherwise return unwrapped values.
#### Arguments
1. `value` *(Mixed)*: The value to wrap in a `lodash` instance.
diff --git a/lodash.js b/lodash.js
index 04d13ce22..0143819ae 100644
--- a/lodash.js
+++ b/lodash.js
@@ -246,7 +246,7 @@
* Creates a `lodash` object, that wraps the given `value`, to enable
* method chaining.
*
- * The wrapper functions capable of chaining are:
+ * The chainable wrapper functions are:
* `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`,
* `compose`, `countBy`, `debounce`, `defaults`, `defer`, `delay`, `difference`,
* `filter`, `flatten`, `forEach`, `forIn`, `forOwn`, `functions`, `groupBy`,
@@ -255,16 +255,16 @@
* `range`, `reject`, `rest`, `shuffle`, `sortBy`, `tap`, `throttle`, `times`,
* `toArray`, `union`, `uniq`, `values`, `where`, `without`, `wrap`, and `zip`
*
- * The wrapper functions that do not chain are:
- * `clone`, `contains`, `escape`, `every`, `find`, `has`, `identity`,
- * `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`,
- * `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`,
- * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `lastIndexOf`,
- * `mixin`, `noConflict`, `random`, `reduce`, `reduceRight`, `result`, `size`,
- * `some`, `sortedIndex`, `template`, `unescape`, and `uniqueId`
+ * The non-chainable wrapper functions are:
+ * `clone`, `contains`, `escape`, `every`, `find`, `has`, `identity`, `indexOf`,
+ * `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`, `isEmpty`,
+ * `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`, `isObject`,
+ * `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `lastIndexOf`, `mixin`,
+ * `noConflict`, `random`, `reduce`, `reduceRight`, `result`, `size`, `some`,
+ * `sortedIndex`, `template`, `unescape`, and `uniqueId`
*
* The wrapper functions `first` and `last` return wrapped values when `n` is
- * passed, otherwise unwrapped values are returned.
+ * passed, otherwise return unwrapped values.
*
* @name _
* @constructor