mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-02-05 09:27:49 +00:00
Ensure objects work in a lazy chain sequence. [closes #796]
This commit is contained in:
105
lodash.js
105
lodash.js
@@ -1070,7 +1070,7 @@
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
if (hasOwnProperty.call(value, '__wrapped__')) {
|
if (hasOwnProperty.call(value, '__wrapped__')) {
|
||||||
return new LodashWrapper(value.__wrapped__, value.__chain__, baseSlice(value.__queue__));
|
return new LodashWrapper(value.__wrapped__, value.__chain__, baseSlice(value.__actions__));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new LodashWrapper(value);
|
return new LodashWrapper(value);
|
||||||
@@ -1082,11 +1082,11 @@
|
|||||||
* @private
|
* @private
|
||||||
* @param {*} value The value to wrap.
|
* @param {*} value The value to wrap.
|
||||||
* @param {boolean} [chainAll=false] Enable chaining for all wrapper methods.
|
* @param {boolean} [chainAll=false] Enable chaining for all wrapper methods.
|
||||||
* @param {Array} [queue=[]] Actions to peform to resolve the unwrapped value.
|
* @param {Array} [actions=[]] Actions to peform to resolve the unwrapped value.
|
||||||
*/
|
*/
|
||||||
function LodashWrapper(value, chainAll, queue) {
|
function LodashWrapper(value, chainAll, actions) {
|
||||||
|
this.__actions__ = actions || [];
|
||||||
this.__chain__ = !!chainAll;
|
this.__chain__ = !!chainAll;
|
||||||
this.__queue__ = queue || [];
|
|
||||||
this.__wrapped__ = value;
|
this.__wrapped__ = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1321,6 +1321,7 @@
|
|||||||
* @param {*} value The value to wrap.
|
* @param {*} value The value to wrap.
|
||||||
*/
|
*/
|
||||||
function LazyWrapper(value) {
|
function LazyWrapper(value) {
|
||||||
|
this.actions = null;
|
||||||
this.dir = 1;
|
this.dir = 1;
|
||||||
this.dropCount = 0;
|
this.dropCount = 0;
|
||||||
this.filtered = false;
|
this.filtered = false;
|
||||||
@@ -1339,10 +1340,12 @@
|
|||||||
* @returns {Object} Returns the cloned `LazyWrapper` object.
|
* @returns {Object} Returns the cloned `LazyWrapper` object.
|
||||||
*/
|
*/
|
||||||
function lazyClone() {
|
function lazyClone() {
|
||||||
var iteratees = this.iteratees,
|
var actions = this.actions,
|
||||||
|
iteratees = this.iteratees,
|
||||||
views = this.views,
|
views = this.views,
|
||||||
result = new LazyWrapper(this.wrapped);
|
result = new LazyWrapper(this.wrapped);
|
||||||
|
|
||||||
|
result.actions = actions ? baseSlice(actions) : null;
|
||||||
result.dir = this.dir;
|
result.dir = this.dir;
|
||||||
result.dropCount = this.dropCount;
|
result.dropCount = this.dropCount;
|
||||||
result.filtered = this.filtered;
|
result.filtered = this.filtered;
|
||||||
@@ -1378,8 +1381,11 @@
|
|||||||
* @returns {*} Returns the unwrapped value.
|
* @returns {*} Returns the unwrapped value.
|
||||||
*/
|
*/
|
||||||
function lazyValue() {
|
function lazyValue() {
|
||||||
var array = this.wrapped.value(),
|
var array = this.wrapped.value();
|
||||||
dir = this.dir,
|
if (!isArray(array)) {
|
||||||
|
return baseWrapperValue(array, this.actions);
|
||||||
|
}
|
||||||
|
var dir = this.dir,
|
||||||
isRight = dir < 0,
|
isRight = dir < 0,
|
||||||
length = array.length,
|
length = array.length,
|
||||||
view = getView(0, length, this.views),
|
view = getView(0, length, this.views),
|
||||||
@@ -2658,6 +2664,35 @@
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 unwrapped 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 args = [result],
|
||||||
|
action = actions[index],
|
||||||
|
object = action.object;
|
||||||
|
|
||||||
|
push.apply(args, action.args);
|
||||||
|
result = object[action.name].apply(object, args);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a clone of the given array buffer.
|
* Creates a clone of the given array buffer.
|
||||||
*
|
*
|
||||||
@@ -5026,34 +5061,18 @@
|
|||||||
/**
|
/**
|
||||||
* Extracts the unwrapped value from its wrapper.
|
* Extracts the unwrapped value from its wrapper.
|
||||||
*
|
*
|
||||||
* @name valueOf
|
* @name value
|
||||||
* @memberOf _
|
* @memberOf _
|
||||||
* @alias toJSON, value
|
* @alias toJSON, valueOf
|
||||||
* @category Chain
|
* @category Chain
|
||||||
* @returns {*} Returns the unwrapped value.
|
* @returns {*} Returns the resolved unwrapped value.
|
||||||
* @example
|
* @example
|
||||||
*
|
*
|
||||||
* _([1, 2, 3]).valueOf();
|
* _([1, 2, 3]).value();
|
||||||
* // => [1, 2, 3]
|
* // => [1, 2, 3]
|
||||||
*/
|
*/
|
||||||
function wrapperValueOf() {
|
function wrapperValue() {
|
||||||
var result = this.__wrapped__;
|
return baseWrapperValue(this.__wrapped__, this.__actions__);
|
||||||
if (result instanceof LazyWrapper) {
|
|
||||||
result = result.value();
|
|
||||||
}
|
|
||||||
var index = -1,
|
|
||||||
queue = this.__queue__,
|
|
||||||
length = queue.length;
|
|
||||||
|
|
||||||
while (++index < length) {
|
|
||||||
var args = [result],
|
|
||||||
data = queue[index],
|
|
||||||
object = data.object;
|
|
||||||
|
|
||||||
push.apply(args, data.args);
|
|
||||||
result = object[data.name].apply(object, args);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
@@ -6695,9 +6714,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a function that invokes the provided functions with the `this`
|
* Creates a function that returns the result of invoking the provided
|
||||||
* binding of the created function, where each successive invocation is
|
* functions with the `this` binding of the created function, where each
|
||||||
* supplied the return value of the previous.
|
* successive invocation is supplied the return value of the previous.
|
||||||
*
|
*
|
||||||
* @static
|
* @static
|
||||||
* @memberOf _
|
* @memberOf _
|
||||||
@@ -9560,8 +9579,8 @@
|
|||||||
var chainAll = this.__chain__;
|
var chainAll = this.__chain__;
|
||||||
if (chain || chainAll) {
|
if (chain || chainAll) {
|
||||||
var result = object(this.__wrapped__);
|
var result = object(this.__wrapped__);
|
||||||
|
(result.__actions__ = baseSlice(this.__actions__)).push({ 'args': arguments, 'object': object, 'name': methodName });
|
||||||
result.__chain__ = chainAll;
|
result.__chain__ = chainAll;
|
||||||
(result.__queue__ = baseSlice(this.__queue__)).push({ 'args': arguments, 'object': object, 'name': methodName });
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
var args = [this.value()];
|
var args = [this.value()];
|
||||||
@@ -10316,25 +10335,31 @@
|
|||||||
var value = this.__wrapped__,
|
var value = this.__wrapped__,
|
||||||
args = arguments,
|
args = arguments,
|
||||||
chainAll = this.__chain__,
|
chainAll = this.__chain__,
|
||||||
|
isHybrid = !!this.__actions__.length,
|
||||||
isLazy = value instanceof LazyWrapper,
|
isLazy = value instanceof LazyWrapper,
|
||||||
onlyLazy = isLazy && !this.__queue__.length;
|
onlyLazy = isLazy && !isHybrid;
|
||||||
|
|
||||||
if (retUnwrapped && !chainAll) {
|
if (retUnwrapped && !chainAll) {
|
||||||
return onlyLazy
|
return onlyLazy
|
||||||
? func.call(value)
|
? func.call(value)
|
||||||
: lodash[methodName](this.value());
|
: lodash[methodName](this.value());
|
||||||
}
|
}
|
||||||
|
var interceptor = function(value) {
|
||||||
|
var otherArgs = [value];
|
||||||
|
push.apply(otherArgs, args);
|
||||||
|
return lodash[methodName].apply(lodash, otherArgs);
|
||||||
|
};
|
||||||
if (isLazy || isArray(value)) {
|
if (isLazy || isArray(value)) {
|
||||||
var wrapper = onlyLazy ? value : new LazyWrapper(this),
|
var wrapper = onlyLazy ? value : new LazyWrapper(this),
|
||||||
result = func.apply(wrapper, args);
|
result = func.apply(wrapper, args);
|
||||||
|
|
||||||
|
if (!retUnwrapped && (isHybrid || result.actions)) {
|
||||||
|
var actions = result.actions || (result.actions = []);
|
||||||
|
actions.push({ 'args': [interceptor], 'object': lodash, 'name': 'thru' });
|
||||||
|
}
|
||||||
return new LodashWrapper(result, chainAll);
|
return new LodashWrapper(result, chainAll);
|
||||||
}
|
}
|
||||||
return this.thru(function(value) {
|
return this.thru(interceptor);
|
||||||
var otherArgs = [value];
|
|
||||||
push.apply(otherArgs, args);
|
|
||||||
return lodash[methodName].apply(lodash, otherArgs);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -10375,7 +10400,7 @@
|
|||||||
lodash.prototype.chain = wrapperChain;
|
lodash.prototype.chain = wrapperChain;
|
||||||
lodash.prototype.reverse = wrapperReverse;
|
lodash.prototype.reverse = wrapperReverse;
|
||||||
lodash.prototype.toString = wrapperToString;
|
lodash.prototype.toString = wrapperToString;
|
||||||
lodash.prototype.toJSON = lodash.prototype.value = lodash.prototype.valueOf = wrapperValueOf;
|
lodash.prototype.toJSON = lodash.prototype.valueOf = lodash.prototype.value = wrapperValue;
|
||||||
|
|
||||||
// Add function aliases to the lodash wrapper.
|
// Add function aliases to the lodash wrapper.
|
||||||
lodash.prototype.collect = lodash.prototype.map;
|
lodash.prototype.collect = lodash.prototype.map;
|
||||||
|
|||||||
91
test/test.js
91
test/test.js
@@ -293,17 +293,17 @@
|
|||||||
*/
|
*/
|
||||||
function getUnwrappedValue(wrapper) {
|
function getUnwrappedValue(wrapper) {
|
||||||
var index = -1,
|
var index = -1,
|
||||||
queue = wrapper.__queue__,
|
actions = wrapper.__actions__,
|
||||||
length = queue.length,
|
length = actions.length,
|
||||||
result = wrapper.__wrapped__;
|
result = wrapper.__wrapped__;
|
||||||
|
|
||||||
while (++index < length) {
|
while (++index < length) {
|
||||||
var args = [result],
|
var args = [result],
|
||||||
data = queue[index],
|
action = actions[index],
|
||||||
object = data.object;
|
object = action.object;
|
||||||
|
|
||||||
push.apply(args, data.args);
|
push.apply(args, action.args);
|
||||||
result = object[data.name].apply(object, args);
|
result = object[action.name].apply(object, args);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -2099,6 +2099,19 @@
|
|||||||
deepEqual(_.countBy(array, 0), { '1': 1, '2': 2 });
|
deepEqual(_.countBy(array, 0), { '1': 1, '2': 2 });
|
||||||
deepEqual(_.countBy(array, 1), { 'a': 2, 'b': 1 });
|
deepEqual(_.countBy(array, 1), { 'a': 2, 'b': 1 });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should work in a lazy chain sequence', 1, function() {
|
||||||
|
if (!isNpm) {
|
||||||
|
var array = [1, 2, 1, 3],
|
||||||
|
predicate = function(value) { return value > 1; },
|
||||||
|
actual = _(array).countBy(_.identity).map(String).filter(predicate).take().value();
|
||||||
|
|
||||||
|
deepEqual(actual, ['2']);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
skipTest();
|
||||||
|
}
|
||||||
|
});
|
||||||
}());
|
}());
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------*/
|
||||||
@@ -4865,6 +4878,20 @@
|
|||||||
var actual = _.groupBy(['one', 'two', 'three'], 'length');
|
var actual = _.groupBy(['one', 'two', 'three'], 'length');
|
||||||
deepEqual(actual, { '3': ['one', 'two'], '5': ['three'] });
|
deepEqual(actual, { '3': ['one', 'two'], '5': ['three'] });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should work in a lazy chain sequence', 1, function() {
|
||||||
|
if (!isNpm) {
|
||||||
|
var array = [1, 2, 1, 3],
|
||||||
|
iteratee = function(value) { value.push(value[0]); return value; },
|
||||||
|
predicate = function(value, index) { return index; },
|
||||||
|
actual = _(array).groupBy(_.identity).map(iteratee).filter(predicate).take().value();
|
||||||
|
|
||||||
|
deepEqual(actual, [[2, 2]]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
skipTest();
|
||||||
|
}
|
||||||
|
});
|
||||||
}());
|
}());
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------*/
|
||||||
@@ -5064,6 +5091,19 @@
|
|||||||
deepEqual(_.indexBy(array, 0), { '1': [1 , 'a'], '2': [2, 'b'] });
|
deepEqual(_.indexBy(array, 0), { '1': [1 , 'a'], '2': [2, 'b'] });
|
||||||
deepEqual(_.indexBy(array, 1), { 'a': [2, 'a'], 'b': [2, 'b'] });
|
deepEqual(_.indexBy(array, 1), { 'a': [2, 'a'], 'b': [2, 'b'] });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should work in a lazy chain sequence', 1, function() {
|
||||||
|
if (!isNpm) {
|
||||||
|
var array = [1, 2, 1, 3],
|
||||||
|
predicate = function(value) { return value > 1; },
|
||||||
|
actual = _(array).indexBy(_.identity).map(String).filter(predicate).take().value();
|
||||||
|
|
||||||
|
deepEqual(actual, ['2']);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
skipTest();
|
||||||
|
}
|
||||||
|
});
|
||||||
}());
|
}());
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------*/
|
||||||
@@ -8263,13 +8303,13 @@
|
|||||||
return new Wrapper(value);
|
return new Wrapper(value);
|
||||||
}
|
}
|
||||||
if (_.has(value, '__wrapped__')) {
|
if (_.has(value, '__wrapped__')) {
|
||||||
var chain = value.__chain__,
|
var actions = _.slice(value.__actions__),
|
||||||
queue = _.slice(value.__queue__);
|
chain = value.__chain__;
|
||||||
|
|
||||||
value = value.__wrapped__;
|
value = value.__wrapped__;
|
||||||
}
|
}
|
||||||
|
this.__actions__ = actions || [];
|
||||||
this.__chain__ = chain || false;
|
this.__chain__ = chain || false;
|
||||||
this.__queue__ = queue || [];
|
|
||||||
this.__wrapped__ = value;
|
this.__wrapped__ = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8435,6 +8475,26 @@
|
|||||||
skipTest(2);
|
skipTest(2);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should produce methods that work in a lazy chain sequence', 1, function() {
|
||||||
|
if (!isNpm) {
|
||||||
|
var array = [1, 2, 1, 3],
|
||||||
|
predicate = function(value) { return value > 1; };
|
||||||
|
|
||||||
|
_.mixin({ 'a': _.countBy, 'b': _.filter });
|
||||||
|
|
||||||
|
var actual = _(array).a(_.identity).map(String).b(predicate).take().value();
|
||||||
|
deepEqual(actual, ['2']);
|
||||||
|
|
||||||
|
delete _.a;
|
||||||
|
delete _.prototype.a;
|
||||||
|
delete _.b;
|
||||||
|
delete _.prototype.b;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
skipTest();
|
||||||
|
}
|
||||||
|
});
|
||||||
}());
|
}());
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------*/
|
||||||
@@ -12914,6 +12974,19 @@
|
|||||||
deepEqual(_.zipObject(_.pairs(object)), object);
|
deepEqual(_.zipObject(_.pairs(object)), object);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should work in a lazy chain sequence', 1, function() {
|
||||||
|
if (!isNpm) {
|
||||||
|
var array = [['a', 1], ['b', 2]],
|
||||||
|
predicate = function(value) { return value > 1; },
|
||||||
|
actual = _(array).zipObject().map(String).filter(predicate).take().value();
|
||||||
|
|
||||||
|
deepEqual(actual, ['2']);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
skipTest();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test('should be aliased', 1, function() {
|
test('should be aliased', 1, function() {
|
||||||
strictEqual(_.object, _.zipObject);
|
strictEqual(_.object, _.zipObject);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user