mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-01-31 23:37: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;
|
||||
}
|
||||
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);
|
||||
@@ -1082,11 +1082,11 @@
|
||||
* @private
|
||||
* @param {*} value The value to wrap.
|
||||
* @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.__queue__ = queue || [];
|
||||
this.__wrapped__ = value;
|
||||
}
|
||||
|
||||
@@ -1321,6 +1321,7 @@
|
||||
* @param {*} value The value to wrap.
|
||||
*/
|
||||
function LazyWrapper(value) {
|
||||
this.actions = null;
|
||||
this.dir = 1;
|
||||
this.dropCount = 0;
|
||||
this.filtered = false;
|
||||
@@ -1339,10 +1340,12 @@
|
||||
* @returns {Object} Returns the cloned `LazyWrapper` object.
|
||||
*/
|
||||
function lazyClone() {
|
||||
var iteratees = this.iteratees,
|
||||
var actions = this.actions,
|
||||
iteratees = this.iteratees,
|
||||
views = this.views,
|
||||
result = new LazyWrapper(this.wrapped);
|
||||
|
||||
result.actions = actions ? baseSlice(actions) : null;
|
||||
result.dir = this.dir;
|
||||
result.dropCount = this.dropCount;
|
||||
result.filtered = this.filtered;
|
||||
@@ -1378,8 +1381,11 @@
|
||||
* @returns {*} Returns the unwrapped value.
|
||||
*/
|
||||
function lazyValue() {
|
||||
var array = this.wrapped.value(),
|
||||
dir = this.dir,
|
||||
var array = this.wrapped.value();
|
||||
if (!isArray(array)) {
|
||||
return baseWrapperValue(array, this.actions);
|
||||
}
|
||||
var dir = this.dir,
|
||||
isRight = dir < 0,
|
||||
length = array.length,
|
||||
view = getView(0, length, this.views),
|
||||
@@ -2658,6 +2664,35 @@
|
||||
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.
|
||||
*
|
||||
@@ -5026,34 +5061,18 @@
|
||||
/**
|
||||
* Extracts the unwrapped value from its wrapper.
|
||||
*
|
||||
* @name valueOf
|
||||
* @name value
|
||||
* @memberOf _
|
||||
* @alias toJSON, value
|
||||
* @alias toJSON, valueOf
|
||||
* @category Chain
|
||||
* @returns {*} Returns the unwrapped value.
|
||||
* @returns {*} Returns the resolved unwrapped value.
|
||||
* @example
|
||||
*
|
||||
* _([1, 2, 3]).valueOf();
|
||||
* _([1, 2, 3]).value();
|
||||
* // => [1, 2, 3]
|
||||
*/
|
||||
function wrapperValueOf() {
|
||||
var result = this.__wrapped__;
|
||||
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;
|
||||
function wrapperValue() {
|
||||
return baseWrapperValue(this.__wrapped__, this.__actions__);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
@@ -6695,9 +6714,9 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a function that invokes the provided functions with the `this`
|
||||
* binding of the created function, where each successive invocation is
|
||||
* supplied the return value of the previous.
|
||||
* Creates a function that returns the result of invoking the provided
|
||||
* functions with the `this` binding of the created function, where each
|
||||
* successive invocation is supplied the return value of the previous.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
@@ -9560,8 +9579,8 @@
|
||||
var chainAll = this.__chain__;
|
||||
if (chain || chainAll) {
|
||||
var result = object(this.__wrapped__);
|
||||
(result.__actions__ = baseSlice(this.__actions__)).push({ 'args': arguments, 'object': object, 'name': methodName });
|
||||
result.__chain__ = chainAll;
|
||||
(result.__queue__ = baseSlice(this.__queue__)).push({ 'args': arguments, 'object': object, 'name': methodName });
|
||||
return result;
|
||||
}
|
||||
var args = [this.value()];
|
||||
@@ -10316,25 +10335,31 @@
|
||||
var value = this.__wrapped__,
|
||||
args = arguments,
|
||||
chainAll = this.__chain__,
|
||||
isHybrid = !!this.__actions__.length,
|
||||
isLazy = value instanceof LazyWrapper,
|
||||
onlyLazy = isLazy && !this.__queue__.length;
|
||||
onlyLazy = isLazy && !isHybrid;
|
||||
|
||||
if (retUnwrapped && !chainAll) {
|
||||
return onlyLazy
|
||||
? func.call(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)) {
|
||||
var wrapper = onlyLazy ? value : new LazyWrapper(this),
|
||||
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 this.thru(function(value) {
|
||||
var otherArgs = [value];
|
||||
push.apply(otherArgs, args);
|
||||
return lodash[methodName].apply(lodash, otherArgs);
|
||||
});
|
||||
return this.thru(interceptor);
|
||||
};
|
||||
});
|
||||
|
||||
@@ -10375,7 +10400,7 @@
|
||||
lodash.prototype.chain = wrapperChain;
|
||||
lodash.prototype.reverse = wrapperReverse;
|
||||
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.
|
||||
lodash.prototype.collect = lodash.prototype.map;
|
||||
|
||||
91
test/test.js
91
test/test.js
@@ -293,17 +293,17 @@
|
||||
*/
|
||||
function getUnwrappedValue(wrapper) {
|
||||
var index = -1,
|
||||
queue = wrapper.__queue__,
|
||||
length = queue.length,
|
||||
actions = wrapper.__actions__,
|
||||
length = actions.length,
|
||||
result = wrapper.__wrapped__;
|
||||
|
||||
while (++index < length) {
|
||||
var args = [result],
|
||||
data = queue[index],
|
||||
object = data.object;
|
||||
action = actions[index],
|
||||
object = action.object;
|
||||
|
||||
push.apply(args, data.args);
|
||||
result = object[data.name].apply(object, args);
|
||||
push.apply(args, action.args);
|
||||
result = object[action.name].apply(object, args);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -2099,6 +2099,19 @@
|
||||
deepEqual(_.countBy(array, 0), { '1': 1, '2': 2 });
|
||||
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');
|
||||
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, 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);
|
||||
}
|
||||
if (_.has(value, '__wrapped__')) {
|
||||
var chain = value.__chain__,
|
||||
queue = _.slice(value.__queue__);
|
||||
var actions = _.slice(value.__actions__),
|
||||
chain = value.__chain__;
|
||||
|
||||
value = value.__wrapped__;
|
||||
}
|
||||
this.__actions__ = actions || [];
|
||||
this.__chain__ = chain || false;
|
||||
this.__queue__ = queue || [];
|
||||
this.__wrapped__ = value;
|
||||
}
|
||||
|
||||
@@ -8435,6 +8475,26 @@
|
||||
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);
|
||||
});
|
||||
|
||||
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() {
|
||||
strictEqual(_.object, _.zipObject);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user