lodash-contrib
Version:
The brass buckles on lodash's utility belt
259 lines (200 loc) • 10.5 kB
JavaScript
$(document).ready(function() {
module("lodash.function.combinators");
test("always", function() {
equal(_.always(42)(10000), 42, 'should return a function that always returns the same value');
equal(_.always(42)(1,2,3), 42, 'should return a function that always returns the same value');
deepEqual(_.map([1,2,3], _.always(42)), [42,42,42], 'should return a function that always returns the same value');
});
test("pipeline", function() {
var run = _.pipeline(function(n) { return -n; }, function(n) { return "" + n; });
var run2 = _.pipeline([function(n) { return -n; }, function(n) { return "" + n; }]);
equal(run(42), "-42", 'should apply a series of functions, originall given variadically to an initial value');
equal(run2(42), "-42", 'should apply a series of functions, originally given in an array to an initial value');
});
test("conjoin", function() {
var isPositiveEven = _.conjoin(function(x) { return x > 0; }, function(x) { return (x & 1) === 0; });
equal(isPositiveEven([2,4,6,8]), true, 'should recognize when all elements satisfy a conjunction');
equal(isPositiveEven([2,4,6,7,8]), false, 'should recognize when an element fails to satisfy a conjunction');
});
test("disjoin", function() {
var orPositiveEven = _.disjoin(function(x) { return x > 0; }, function(x) { return (x & 1) === 0; });
equal(orPositiveEven([-1,2,3,4,5,6]), true, 'should recognize when all elements satisfy a disjunction');
equal(orPositiveEven([-1,-3]), false, 'should recognize when an element fails to satisfy a disjunction');
});
test("comparator", function() {
var lessOrEqual = function(x, y) { return x <= y; };
var a = [0, 1, -2];
var b = [100, 1, 0, 10, -1, -2, -1];
deepEqual(a.sort(_.comparator(lessOrEqual)), [-2, 0, 1], 'should return a function to convert a predicate to a comparator');
deepEqual(b.sort(_.comparator(lessOrEqual)), [-2, -1, -1, 0, 1, 10, 100], 'should return a function to convert a predicate to a comparator');
});
test("complement", function() {
var notOdd = _.complement(function(n) { return (n & 1) === 1; });
equal(notOdd(2), true, 'should return a function that is the opposite of the function given');
equal(notOdd(3), false, 'should return a function that is the opposite of the function given');
var obj = {
num: 1,
numIsPositive: function () { return this.num > 0; }
};
obj.numIsNotPositive = _.complement(obj.numIsPositive);
equal(obj.numIsNotPositive(), false, 'should function as a method combinator');
});
test('splat', function() {
var sumArgs = function () {
return _.reduce(arguments, function (a, b) { return a + b; }, 0);
};
var sumArray = _.splat(sumArgs);
equal(sumArray([1, 2, 3]), 6, 'should return a function that takes array elements as the arguments for the original function');
var obj = {
a: 1,
b: 2,
getPropsByName: function () {
var props = [];
for (var i = 0; i < arguments.length; i++) {
props.push(this[arguments[i]]);
}
return props;
}
};
obj.getPropsByNameArray = _.splat(obj.getPropsByName);
deepEqual(obj.getPropsByNameArray(['a', 'b']), [1, 2], 'should function as a method combinator');
});
test("unsplat", function() {
var echo = _.unsplat(function (args) { return args; }),
echo2 = _.unsplat(function (first, rest) { return [first, rest]; }),
echo3 = _.unsplat(function (first, second, rest) { return [first, second, rest]; });
deepEqual(echo(), [], 'should return no arguments');
deepEqual(echo(1), [1], 'should return the arguments provded');
deepEqual(echo(1,2), [1,2], 'should return the arguments provded');
deepEqual(echo(1,2,3), [1,2,3], 'should return the arguments provded');
deepEqual(echo2(), [void 0, []], 'should return no arguments');
deepEqual(echo2(1), [1, []], 'should return the arguments provded');
deepEqual(echo2(1,2), [1,[2]], 'should return the arguments provded');
deepEqual(echo2(1,2,3), [1,[2,3]], 'should return the arguments provded');
deepEqual(echo2(1,2,3,4), [1,[2,3,4]], 'should return the arguments provded');
deepEqual(echo3(), [void 0, void 0, []], 'should return no arguments');
deepEqual(echo3(1), [1, void 0, []], 'should return the arguments provded');
deepEqual(echo3(1,2), [1,2,[]], 'should return the arguments provded');
deepEqual(echo3(1,2,3), [1,2,[3]], 'should return the arguments provded');
deepEqual(echo3(1,2,3,4), [1,2,[3,4]], 'should return the arguments provded');
});
test("unsplatl", function() {
var echo = _.unsplatl(function (args) { return args; }),
echo2 = _.unsplatl(function (rest, ultimate) { return [rest, ultimate]; }),
echo3 = _.unsplatl(function (rest, penultimate, ultimate) { return [rest, penultimate, ultimate]; });
deepEqual(echo(), [], 'should return no arguments');
deepEqual(echo(1), [1], 'should return the arguments provded');
deepEqual(echo(1,2), [1,2], 'should return the arguments provded');
deepEqual(echo(1,2,3), [1,2,3], 'should return the arguments provded');
deepEqual(echo2(), [[], void 0], 'should return no arguments');
deepEqual(echo2(1), [[], 1], 'should return the arguments provded');
deepEqual(echo2(1,2), [[1], 2], 'should return the arguments provded');
deepEqual(echo2(1,2,3), [[1, 2], 3], 'should return the arguments provded');
deepEqual(echo2(1,2,3,4), [[1, 2, 3], 4], 'should return the arguments provded');
deepEqual(echo3(), [[], void 0, void 0], 'should return no arguments');
deepEqual(echo3(1), [[], 1, void 0], 'should return the arguments provded');
deepEqual(echo3(1,2), [[], 1, 2], 'should return the arguments provded');
deepEqual(echo3(1,2,3), [[1], 2, 3], 'should return the arguments provded');
deepEqual(echo3(1,2,3,4), [[1, 2], 3, 4], 'should return the arguments provded');
});
test("mapArgsWith", function () {
var echo = _.unsplatl(function (args) { return args; });
function timesTwo (n) { return n * 2; }
function plusOne (n) { return n + 1; }
deepEqual(_.mapArgsWith(timesTwo, echo)(), [], "should handle the empty case");
deepEqual(_.mapArgsWith(timesTwo, echo)(42), [84], "should handle one arg");
deepEqual(_.mapArgsWith(plusOne, echo)(1, 2, 3), [2, 3, 4], "should handle many args");
deepEqual(_.mapArgsWith(timesTwo)(echo)(), [], "should handle the empty case");
deepEqual(_.mapArgsWith(timesTwo)(echo)(42), [84], "should handle one arg");
deepEqual(_.mapArgsWith(plusOne)(echo)(1, 2, 3), [2, 3, 4], "should handle many args");
});
test("flip2", function() {
var div = function(n, d) { return n/d; };
equal(_.flip2(div)(10,2), 0.2, 'should return a function that flips the first two args to a function');
var obj = {
num: 5,
addToNum: function (a, b) { return [a + this.num, b + this.num]; }
};
obj.reversedAddToNum = _.flip2(obj.addToNum);
deepEqual(obj.reversedAddToNum(1, 2), [7, 6], 'should function as a method combinator.');
});
test("flip", function() {
var echo = function() { return Array.prototype.slice.call(arguments, 0); };
deepEqual(_.flip(echo)(1, 2, 3, 4), [4, 3, 2, 1], 'should return a function that flips the first three or more args to a function');
var obj = {
num: 5,
addToNum: function (a, b) { return [a + this.num, b + this.num]; }
};
obj.reversedAddToNum = _.flip(obj.addToNum);
deepEqual(obj.reversedAddToNum(1, 2), [7, 6], 'should function as a method combinator.');
});
test("fnull", function() {
var a = [1,2,3,null,5];
var b = [1,2,3,undefined,5];
var safeMult = _.fnull(function(total, n) { return total * n; }, 1, 1);
equal(_.reduce([1,2,3,5], safeMult), 30, 'should not fill in defaults when not needed');
equal(_.reduce(a, safeMult), 30, 'should fill in defaults for null');
equal(_.reduce(b, safeMult), 30, 'should fill in defaults for undefined');
var obj = {
a: 1,
fallback: "fallback value",
getPropByName: function (name) { return this[name]; }
};
obj.getPropByNameOrDefault = _.fnull(obj.getPropByName, "fallback");
equal(obj.getPropByNameOrDefault(), "fallback value", 'should function as a method combinator.');
});
test("juxt", function() {
var run = _.juxt(function(s, n) { return s.length + n; }, parseInt, _.always(108));
deepEqual(run('42', 10), [12, 42, 108], 'should return a function that returns an array of the originally supplied functions called');
var obj = {
name: "Elizabeth 1",
firstChar: function () { return this.name[0]; },
lastChar: function () { return this.name[this.name.length - 1]; }
};
obj.firstAndLastChars = _.juxt(obj.firstChar, obj.lastChar);
deepEqual(obj.firstAndLastChars(), ['E', '1'], 'should function as a method combinator.');
});
test("accessor", function() {
var f = _.accessor('a');
equal(f({a: 42}), 42, 'should retrieve a pluckable field');
equal(f({z: 42}), undefined, 'should fail to retrieve a field if not there');
});
test("bound", function() {
var obj = {
fun: function(b) {
return this.a + b;
},
a: 'hello ',
nofun: null
};
var f = _.bound(obj, 'fun');
equal(f('there'), 'hello there', 'should return concatenation of obj.a and string argument');
throws(function() {
_.bound(obj, 'nofun');
}, TypeError, 'should throw for non-function properties');
});
test("functionalize", function() {
var rect = {
x: 2,
y: 3,
area: function() {return this.x * this.y;},
extrude: function(z) {return _.merge(this, {z: z});}
};
var areaFunc = _.functionalize(rect.area),
extrudeFunc = _.functionalize(rect.extrude);
equal(areaFunc(rect), 6, "returned function's first arg becomes original method's `this`");
equal(extrudeFunc(rect, 4).z, 4, "all arguments are passed along");
});
test("methodize", function() {
function area(rect) {return rect.x * rect.y;}
function extrude(rect, z) {return _.merge(rect, {z: z});}
var rect = {
x: 2,
y: 3,
area: _.methodize(area),
extrude: _.methodize(extrude)
};
equal(rect.area(), 6, "returned method passes its receiver (`this`) as first arg to original function");
equal(rect.extrude(4).z, 4, "all arguments are passed along");
});
});