file -> lazy-extensions.js
'use strict';
var Lazy = require('lazy.js').strict();
var Sequence = Lazy.Sequence;
var xor = require('component-xor');
Sequence.prototype.equals = function equals(other_, eqFn_) {
if (!(other_ instanceof Sequence)) {
throw new Error("Invalid Argument: <Sequence>.equals requires a Sequence argument");
} else if (this === other_) {
return true;
} else if ((typeof this.length === 'number') && (typeof other_.length === 'number') && this.length !== other_.length) {
// if both sequences have a length property, we might as well check that before iterating through each element.
return false;
}
var normalizedEqFn = normalizeEqualityFunction(eqFn_, "Invalid Argument: <Sequence>.equals requires the second argument to be undefined, a string, or a function");
var thisIterator = this.getIterator();
var otherIterator = other_.getIterator();
var stillEqual = true;
var shouldIterate
, unequalLength;
function iterate(it1_, it2_) {
var it1Moved = it1_.moveNext();
var it2Moved = it2_.moveNext();
return {
shouldIterate: (it1Moved && it2Moved)
, unequalLength: (xor(it1Moved, it2Moved))
};
}
var itRes = iterate(thisIterator, otherIterator);
shouldIterate = itRes.shouldIterate;
unequalLength = itRes.unequalLength;
while (stillEqual && shouldIterate && !unequalLength) {
stillEqual = normalizedEqFn(thisIterator.current(), otherIterator.current());
itRes = iterate(thisIterator, otherIterator);
shouldIterate = itRes.shouldIterate;
unequalLength = itRes.unequalLength;
}
return stillEqual && !unequalLength;
};
// helper fxn
function normalizeEqualityFunction(eqFn_, err_) {
var normalizedEqFn;
// Logic for below is as follows:
// - If eqFn is undefined, then test for strict equality
// - If it is a string, then we assume the iterated element has an equality property named whatever eqFn is
// - If it's a function, then we assume it takes in two arguments and returns a boolean for equality.
// - normalizedEqFn turns each of the above into a normalized equality function(left, right).
if (typeof eqFn_ === 'undefined') {
normalizedEqFn = function(left, right) {
return left === right;
};
} else if (typeof eqFn_ === 'string') {
normalizedEqFn = function(left, right) {
return left[eqFn_](right);
};
} else if (typeof eqFn_ === 'function') {
normalizedEqFn = eqFn_;
} else {
var msg = (typeof err_ === 'string')
? err_
: "Invalid Argument: normalizedEqualityFunction requires an undefined, string, or function argument";
throw new Error(msg);
}
return normalizedEqFn;
}
Mocha tests
file -> test.js
'use strict';
var Lazy = require('./lazy-extensions');
suite("lazy-extensions.js", function() {
var vals
, valsConst
, objs
, objsConst;
function TestObj(name, val) {
this.name = name;
this.val = val;
}
TestObj.prototype.equals = function equals(other) {
return this.name === other.name
&& this.val === other.val;
};
TestObj.equals = function equals(left, right) {
return left.equals(right);
};
function getNewObjs() {
return [new TestObj('name1', 'val1')
, new TestObj('name2', 'val2')
, new TestObj('name3', 'val3')
, new TestObj('name4', 'val4')
, new TestObj('name5', 'val5')
];
}
function getNewVals() {
return [1, 2, 3, 4, 5];
}
setup(function() {
vals = Lazy(getNewVals());
valsConst = Lazy(getNewVals());
objs = Lazy(getNewObjs());
objsConst = Lazy(getNewObjs());
});
test("Sequence.equals", function Sequence_equals() {
// using strictEqual because isTrue wasn't giving a line number in its error message.
assert.strictEqual(vals.equals(valsConst), true);
var vals2 = Lazy(getNewVals()).concat([6]);
assert.strictEqual(vals.equals(vals2), false);
assert.strictEqual(objs.equals(objsConst), false);
assert.strictEqual(objs.equals(objsConst, 'equals'), true);
assert.strictEqual(objs.equals(objsConst, TestObj.equals), true);
});
});