mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-02-09 18:37:50 +00:00
Add explicit chaining support to Lo-Dash. [closes #325]
Former-commit-id: 58d01723ddc40f636af9954e5a9f6370e0c88aac
This commit is contained in:
76
build.js
76
build.js
@@ -653,72 +653,6 @@
|
|||||||
* @returns {String} Returns the modified source.
|
* @returns {String} Returns the modified source.
|
||||||
*/
|
*/
|
||||||
function addUnderscoreChaining(source) {
|
function addUnderscoreChaining(source) {
|
||||||
// add `_.chain`
|
|
||||||
source = source.replace(matchFunction(source, 'tap', true), function(match) {
|
|
||||||
var indent = getIndent(match);
|
|
||||||
return match && (indent + [
|
|
||||||
'',
|
|
||||||
'/**',
|
|
||||||
' * 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 lodashWrapper(value);',
|
|
||||||
' value.__chain__ = true;',
|
|
||||||
' return value;',
|
|
||||||
'}',
|
|
||||||
'',
|
|
||||||
match
|
|
||||||
].join('\n' + indent));
|
|
||||||
});
|
|
||||||
|
|
||||||
// add `wrapperChain`
|
|
||||||
source = source.replace(matchFunction(source, 'wrapperToString', true), function(match) {
|
|
||||||
var indent = getIndent(match);
|
|
||||||
return match && (indent + [
|
|
||||||
'',
|
|
||||||
'/**',
|
|
||||||
' * 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' + indent));
|
|
||||||
});
|
|
||||||
|
|
||||||
// remove `lodash.prototype.toString` and `lodash.prototype.valueOf` assignments
|
// remove `lodash.prototype.toString` and `lodash.prototype.valueOf` assignments
|
||||||
source = source.replace(/^ *lodash\.prototype\.(?:toString|valueOf) *=.+\n/gm, '');
|
source = source.replace(/^ *lodash\.prototype\.(?:toString|valueOf) *=.+\n/gm, '');
|
||||||
|
|
||||||
@@ -783,11 +717,6 @@
|
|||||||
].join('\n' + indent);
|
].join('\n' + indent);
|
||||||
});
|
});
|
||||||
|
|
||||||
// replace `_.chain` assignment
|
|
||||||
source = source.replace(getMethodAssignments(source), function(match) {
|
|
||||||
return match.replace(/^( *lodash\.chain *= *)[\s\S]+?(?=;\n)/m, '$1chain')
|
|
||||||
});
|
|
||||||
|
|
||||||
// move `mixin(lodash)` to after the method assignments
|
// move `mixin(lodash)` to after the method assignments
|
||||||
source = source.replace(/(?:\s*\/\/.*)*\n( *)mixin\(lodash\).+/, '');
|
source = source.replace(/(?:\s*\/\/.*)*\n( *)mixin\(lodash\).+/, '');
|
||||||
source = source.replace(getMethodAssignments(source), function(match) {
|
source = source.replace(getMethodAssignments(source), function(match) {
|
||||||
@@ -800,11 +729,6 @@
|
|||||||
].join('\n' + indent);
|
].join('\n' + indent);
|
||||||
});
|
});
|
||||||
|
|
||||||
// move the `lodash.prototype.chain` assignment to after `mixin(lodash)`
|
|
||||||
source = source
|
|
||||||
.replace(/^ *lodash\.prototype\.chain *=[\s\S]+?;\n/m, '')
|
|
||||||
.replace(/^( *)lodash\.prototype\.value *=/m, '$1lodash.prototype.chain = wrapperChain;\n$&');
|
|
||||||
|
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
92
lodash.js
92
lodash.js
@@ -585,7 +585,6 @@
|
|||||||
*
|
*
|
||||||
* @name _
|
* @name _
|
||||||
* @constructor
|
* @constructor
|
||||||
* @alias chain
|
|
||||||
* @category Chaining
|
* @category Chaining
|
||||||
* @param {Mixed} value The value to wrap in a `lodash` instance.
|
* @param {Mixed} value The value to wrap in a `lodash` instance.
|
||||||
* @returns {Object} Returns a `lodash` instance.
|
* @returns {Object} Returns a `lodash` instance.
|
||||||
@@ -622,9 +621,11 @@
|
|||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @param {Mixed} value The value to wrap in a `lodash` instance.
|
* @param {Mixed} value The value to wrap in a `lodash` instance.
|
||||||
|
* @param {Boolean} chainAll A flag to enable chaining for all methods
|
||||||
* @returns {Object} Returns a `lodash` instance.
|
* @returns {Object} Returns a `lodash` instance.
|
||||||
*/
|
*/
|
||||||
function lodashWrapper(value) {
|
function lodashWrapper(value, chainAll) {
|
||||||
|
this.__chain__ = !!chainAll;
|
||||||
this.__wrapped__ = value;
|
this.__wrapped__ = value;
|
||||||
}
|
}
|
||||||
// ensure `new lodashWrapper` is an instance of `lodash`
|
// ensure `new lodashWrapper` is an instance of `lodash`
|
||||||
@@ -5956,6 +5957,34 @@
|
|||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 lodashWrapper(value);
|
||||||
|
value.__chain__ = true;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invokes `interceptor` with the `value` as the first argument, and then
|
* Invokes `interceptor` with the `value` as the first argument, and then
|
||||||
* returns `value`. The purpose of this method is to "tap into" a method chain,
|
* returns `value`. The purpose of this method is to "tap into" a method chain,
|
||||||
@@ -5982,6 +6011,26 @@
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Produces the `toString` result of the wrapped value.
|
* Produces the `toString` result of the wrapped value.
|
||||||
*
|
*
|
||||||
@@ -6024,6 +6073,7 @@
|
|||||||
lodash.bind = bind;
|
lodash.bind = bind;
|
||||||
lodash.bindAll = bindAll;
|
lodash.bindAll = bindAll;
|
||||||
lodash.bindKey = bindKey;
|
lodash.bindKey = bindKey;
|
||||||
|
lodash.chain = chain;
|
||||||
lodash.compact = compact;
|
lodash.compact = compact;
|
||||||
lodash.compose = compose;
|
lodash.compose = compose;
|
||||||
lodash.countBy = countBy;
|
lodash.countBy = countBy;
|
||||||
@@ -6095,10 +6145,6 @@
|
|||||||
// add functions to `lodash.prototype`
|
// add functions to `lodash.prototype`
|
||||||
mixin(lodash);
|
mixin(lodash);
|
||||||
|
|
||||||
// add Underscore compat
|
|
||||||
lodash.chain = lodash;
|
|
||||||
lodash.prototype.chain = function() { return this; };
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
// add functions that return unwrapped values when chaining
|
// add functions that return unwrapped values when chaining
|
||||||
@@ -6162,9 +6208,14 @@
|
|||||||
forOwn(lodash, function(func, methodName) {
|
forOwn(lodash, function(func, methodName) {
|
||||||
if (!lodash.prototype[methodName]) {
|
if (!lodash.prototype[methodName]) {
|
||||||
lodash.prototype[methodName] = function() {
|
lodash.prototype[methodName] = function() {
|
||||||
var args = [this.__wrapped__];
|
var args = [this.__wrapped__],
|
||||||
|
chainAll = this.__chain__;
|
||||||
|
|
||||||
push.apply(args, arguments);
|
push.apply(args, arguments);
|
||||||
return func.apply(lodash, args);
|
var result = func.apply(lodash, args);
|
||||||
|
return chainAll
|
||||||
|
? new lodashWrapper(result, chainAll)
|
||||||
|
: result;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -6182,10 +6233,12 @@
|
|||||||
forOwn(lodash, function(func, methodName) {
|
forOwn(lodash, function(func, methodName) {
|
||||||
if (!lodash.prototype[methodName]) {
|
if (!lodash.prototype[methodName]) {
|
||||||
lodash.prototype[methodName]= function(callback, thisArg) {
|
lodash.prototype[methodName]= function(callback, thisArg) {
|
||||||
var result = func(this.__wrapped__, callback, thisArg);
|
var chainAll = this.__chain__,
|
||||||
return callback == null || (thisArg && typeof callback != 'function')
|
result = func(this.__wrapped__, callback, thisArg);
|
||||||
|
|
||||||
|
return !chainAll && (callback == null || (thisArg && typeof callback != 'function'))
|
||||||
? result
|
? result
|
||||||
: new lodashWrapper(result);
|
: new lodashWrapper(result, chainAll);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -6202,6 +6255,7 @@
|
|||||||
lodash.VERSION = '1.3.1';
|
lodash.VERSION = '1.3.1';
|
||||||
|
|
||||||
// add "Chaining" functions to the wrapper
|
// add "Chaining" functions to the wrapper
|
||||||
|
lodash.prototype.chain = wrapperChain;
|
||||||
lodash.prototype.toString = wrapperToString;
|
lodash.prototype.toString = wrapperToString;
|
||||||
lodash.prototype.value = wrapperValueOf;
|
lodash.prototype.value = wrapperValueOf;
|
||||||
lodash.prototype.valueOf = wrapperValueOf;
|
lodash.prototype.valueOf = wrapperValueOf;
|
||||||
@@ -6210,7 +6264,12 @@
|
|||||||
baseEach(['join', 'pop', 'shift'], function(methodName) {
|
baseEach(['join', 'pop', 'shift'], function(methodName) {
|
||||||
var func = arrayRef[methodName];
|
var func = arrayRef[methodName];
|
||||||
lodash.prototype[methodName] = function() {
|
lodash.prototype[methodName] = function() {
|
||||||
return func.apply(this.__wrapped__, arguments);
|
var chainAll = this.__chain__,
|
||||||
|
result = func.apply(this.__wrapped__, arguments);
|
||||||
|
|
||||||
|
return chainAll
|
||||||
|
? new lodashWrapper(result, chainAll)
|
||||||
|
: result;
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -6227,7 +6286,7 @@
|
|||||||
baseEach(['concat', 'slice', 'splice'], function(methodName) {
|
baseEach(['concat', 'slice', 'splice'], function(methodName) {
|
||||||
var func = arrayRef[methodName];
|
var func = arrayRef[methodName];
|
||||||
lodash.prototype[methodName] = function() {
|
lodash.prototype[methodName] = function() {
|
||||||
return new lodashWrapper(func.apply(this.__wrapped__, arguments));
|
return new lodashWrapper(func.apply(this.__wrapped__, arguments), this.__chain__);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -6239,13 +6298,16 @@
|
|||||||
isSplice = methodName == 'splice';
|
isSplice = methodName == 'splice';
|
||||||
|
|
||||||
lodash.prototype[methodName] = function() {
|
lodash.prototype[methodName] = function() {
|
||||||
var value = this.__wrapped__,
|
var chainAll = this.__chain__,
|
||||||
|
value = this.__wrapped__,
|
||||||
result = func.apply(value, arguments);
|
result = func.apply(value, arguments);
|
||||||
|
|
||||||
if (value.length === 0) {
|
if (value.length === 0) {
|
||||||
delete value[0];
|
delete value[0];
|
||||||
}
|
}
|
||||||
return isSplice ? new lodashWrapper(result) : result;
|
return (chainAll || isSplice)
|
||||||
|
? new lodashWrapper(result, chainAll)
|
||||||
|
: result;
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1214,8 +1214,9 @@
|
|||||||
vm.runInContext(data.source, context);
|
vm.runInContext(data.source, context);
|
||||||
var lodash = context._;
|
var lodash = context._;
|
||||||
|
|
||||||
ok(lodash.chain(1) instanceof lodash, '_.chain: ' + basename);
|
var array = ['abc'];
|
||||||
ok(lodash(1).chain() instanceof lodash, '_#chain: ' + basename);
|
ok(lodash.chain(array).first().first() instanceof lodash, '_.chain: ' + basename);
|
||||||
|
ok(lodash(array).chain().first().first() instanceof lodash, '_#chain: ' + basename);
|
||||||
|
|
||||||
var wrapped = lodash(1);
|
var wrapped = lodash(1);
|
||||||
strictEqual(wrapped.identity(), 1, '_(...) wrapped values are not chainable by default: ' + basename);
|
strictEqual(wrapped.identity(), 1, '_(...) wrapped values are not chainable by default: ' + basename);
|
||||||
|
|||||||
13
test/test.js
13
test/test.js
@@ -408,6 +408,19 @@
|
|||||||
var wrapper = _({ 'a': 0 });
|
var wrapper = _({ 'a': 0 });
|
||||||
equal(wrapper.chain(), wrapper);
|
equal(wrapper.chain(), wrapper);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should enable chaining of methods that return unwrapped values by default', function() {
|
||||||
|
var array = ['abc'];
|
||||||
|
|
||||||
|
ok(_.chain(array).first() instanceof _);
|
||||||
|
ok(_(array).chain().first() instanceof _);
|
||||||
|
|
||||||
|
ok(_.chain(array).isArray() instanceof _);
|
||||||
|
ok(_(array).chain().isArray() instanceof _);
|
||||||
|
|
||||||
|
ok(_.chain(array).first().first() instanceof _);
|
||||||
|
ok(_(array).chain().first().first() instanceof _);
|
||||||
|
});
|
||||||
}());
|
}());
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|||||||
Reference in New Issue
Block a user