underscore-contrib
Advanced tools
Comparing version 0.1.1 to 0.1.4
@@ -9,2 +9,2 @@ ## How to contribute to Underscore-contrib | ||
* In your pull request, do not add documentation or re-build the minified contrib files. We'll do those things before cutting a new release. | ||
* In your pull request, do not add documentation, edit the files in `dist/` or use grunt to re-build the files in `dist/`. We'll do those things before cutting a new release. |
27
index.js
@@ -1,16 +0,15 @@ | ||
['array.builders', | ||
'array.selectors', | ||
'collections.walk', | ||
'function.arity', | ||
'function.combinators', | ||
'function.iterators', | ||
'function.predicates', | ||
'object.builders', | ||
'object.selectors', | ||
'util.existential', | ||
'util.strings', | ||
'util.trampolines'].forEach(function (lib) { | ||
require('./underscore.'+lib); | ||
}); | ||
require('./underscore.array.builders'); | ||
require('./underscore.array.selectors'); | ||
require('./underscore.collections.walk'); | ||
require('./underscore.function.arity'); | ||
require('./underscore.function.combinators'); | ||
require('./underscore.function.iterators'); | ||
require('./underscore.function.predicates'); | ||
require('./underscore.object.builders'); | ||
require('./underscore.object.selectors'); | ||
require('./underscore.util.existential'); | ||
require('./underscore.util.operators'); | ||
require('./underscore.util.strings'); | ||
require('./underscore.util.trampolines'); | ||
module.exports = require('underscore'); |
{ | ||
"name": "underscore-contrib", | ||
"version": "0.1.1", | ||
"version": "0.1.4", | ||
"main": "index.js", | ||
@@ -8,2 +8,7 @@ "dependencies": { | ||
}, | ||
"devDependencies": { | ||
"grunt": "~0.4.0", | ||
"grunt-contrib-concat": "0.3.0", | ||
"grunt-contrib-uglify": "0.2.0" | ||
}, | ||
"repository": { | ||
@@ -16,3 +21,4 @@ "type": "git", | ||
"email": "me@fogus.me", | ||
"url": "http://www.fogus.me"} | ||
"url": "http://www.fogus.me"}, | ||
"homepage": "https://github.com/documentcloud/underscore-contrib" | ||
} |
@@ -17,13 +17,13 @@ $(document).ready(function() { | ||
}); | ||
test("arity", function () { | ||
function variadic () { return arguments.length; } | ||
function unvariadic (a, b, c) { return arguments.length; } | ||
equal( _.arity(unvariadic.length, variadic).length, unvariadic.length, "should set the length"); | ||
equal( _.arity(3, variadic)(1, 2, 3, 4, 5), unvariadic(1, 2, 3, 4, 5), "shouldn't trim arguments"); | ||
equal( _.arity(3, variadic)(1, 2, 3, 4, 5), unvariadic(1, 2, 3, 4, 5), "shouldn't trim arguments"); | ||
equal( _.arity(3, variadic)(1), unvariadic(1), "shouldn't pad arguments"); | ||
// this is the big use case for _.arity: | ||
function reverse (list) { | ||
@@ -35,3 +35,3 @@ return [].reduce.call(list, function (acc, element) { | ||
} | ||
function naiveFlip (fun) { | ||
@@ -42,27 +42,116 @@ return function () { | ||
} | ||
function echo (a, b, c) { return [a, b, c]; } | ||
deepEqual(naiveFlip(echo)(1, 2, 3), [3, 2, 1], "naive flip flips its arguments"); | ||
notEqual(naiveFlip(echo).length, echo.length, "naiveFlip gets its arity wrong"); | ||
function flipWithArity (fun) { | ||
return _.arity(fun.length, naiveFlip(fun)); | ||
} | ||
deepEqual(flipWithArity(echo)(1, 2, 3), [3, 2, 1], "flipWithArity flips its arguments"); | ||
equal(flipWithArity(echo).length, echo.length, "flipWithArity gets its arity correct"); | ||
}); | ||
test("curry", function() { | ||
var func = function (x, y, z) { | ||
return x + y + z; | ||
}, | ||
curried = _.curry(func), | ||
rCurried = _.rCurry(func); | ||
equal(func(1, 2, 3), 6, "Test pure function"); | ||
equal(typeof curried, 'function', "Curry returns a function"); | ||
equal(typeof curried(1), 'function', "Curry returns a function after partial application"); | ||
equal(curried(1)(2)(3), 6, "Curry returns a value after total application"); | ||
equal(curried(1)(2)(3), 6, "Curry invocations have no side effects and do not interact with each other"); | ||
equal(curried(2)(4)(8), 14, "Curry invocations have no side effects and do not interact with each other"); | ||
equal(rCurried('a')('b')('c'), 'cba', "Flipped curry applies arguments in reverse."); | ||
var addyz = curried(1); | ||
equal(addyz(2)(3), 6, "Partial applications can be used multiple times"); | ||
equal(addyz(2)(4), 7, "Partial applications can be used multiple times"); | ||
var failure = false; | ||
try { | ||
curried(1, 2999); | ||
} catch (e) { | ||
failure = true; | ||
} finally { | ||
equal(failure, true, "Curried functions only accept one argument at a time"); | ||
} | ||
}); | ||
test("curry2", function () { | ||
function echo () { return [].slice.call(arguments, 0); } | ||
deepEqual(echo(1, 2), [1, 2], "Control test"); | ||
deepEqual(_.curry2(echo)(1, 2), [1, 2], "Accepts arguments greedily"); | ||
deepEqual(_.curry2(echo)(1)(2), [1, 2], "Accepts curried arguments"); | ||
}); | ||
test("rcurry2", function () { | ||
function echo () { return [].slice.call(arguments, 0); } | ||
deepEqual(echo(1, 2), [1, 2], "Control test"); | ||
deepEqual(_.rcurry2(echo)(1)(2), [2, 1], "Reverses curried arguments"); | ||
}); | ||
test("curry3", function () { | ||
function echo () { return [].slice.call(arguments, 0); } | ||
deepEqual(echo(1, 2, 3), [1, 2, 3], "Control test"); | ||
deepEqual(_.curry3(echo)(1)(2)(3), [1, 2, 3], "Accepts curried arguments"); | ||
}); | ||
test("rcurry3", function () { | ||
function echo () { return [].slice.call(arguments, 0); } | ||
deepEqual(echo(1, 2, 3), [1, 2, 3], "Control test"); | ||
deepEqual(_.rcurry3(echo)(1)(2)(3), [3, 2, 1], "Reverses curried arguments"); | ||
}); | ||
test("enforce", function () { | ||
function binary (a, b) { | ||
return a + b; | ||
} | ||
function ternary (a, b, c) { | ||
return a + b + c; | ||
} | ||
function altTernary (a, b, c) { | ||
return a - b - c; | ||
} | ||
var fBinary = _.enforce(binary), | ||
fTernary = _.enforce(ternary), | ||
fAltTernary = _.enforce(altTernary), | ||
failure = false; | ||
try { | ||
fBinary(1); | ||
} catch (e) { | ||
failure = true; | ||
} finally { | ||
equal(failure, true, "Binary must have two arguments."); | ||
} | ||
equal(fBinary(1, 2), 3, "Function returns after proper application"); | ||
failure = false; | ||
try { | ||
fTernary(1, 3); | ||
} catch (e) { | ||
failure = true; | ||
} finally { | ||
equal(failure, true, "Ternary must have three arguments."); | ||
} | ||
equal(fTernary(1, 2, 3), 6, "Function returns after proper application"); | ||
equal(fAltTernary(1, 2, 3), -4, "Function cache does not collide"); | ||
}); | ||
}); |
@@ -144,2 +144,22 @@ $(document).ready(function() { | ||
}); | ||
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'); | ||
equal(f.length, 1, 'f should have arity of 1'); | ||
throws(function() { | ||
_.bound(obj, 'nofun'); | ||
}, TypeError, 'should throw for non-function properties'); | ||
}); | ||
}); |
@@ -33,4 +33,6 @@ $(document).ready(function() { | ||
var deepArr = [[["thirdLevel"]]]; | ||
var ks = ["a", "b", "c"]; | ||
strictEqual(_.getPath(deepObject, ["a", "b", "c"]), "c", "should get a deep property's value from objects"); | ||
strictEqual(_.getPath(deepObject, ks), "c", "should get a deep property's value from objects"); | ||
deepEqual(ks, ["a", "b", "c"], "should not have mutated ks argument"); | ||
strictEqual(_.getPath(deepArr, [0, 0, 0]), "thirdLevel", "should get a deep property's value from arrays"); | ||
@@ -47,5 +49,7 @@ strictEqual(_.getPath(deepObject, ["arrayVal", 0]), "arr", "should get a deep property's value from nested arrays and objects"); | ||
var deepObject = { a: { b: { c: "c" } }, falseVal: false, nullVal: null, undefinedVal: undefined, arrayVal: ["arr"] }; | ||
var ks = ["a", "b", "c"]; | ||
strictEqual(_.hasPath(deepObject, ["notHere", "notHereEither"]), false, "should return false if the path doesn't exist"); | ||
strictEqual(_.hasPath(deepObject, ["a", "b", "c"]), true, "should return true if the path exists"); | ||
strictEqual(_.hasPath(deepObject, ks), true, "should return true if the path exists"); | ||
deepEqual(ks, ["a", "b", "c"], "should not have mutated ks argument"); | ||
@@ -52,0 +56,0 @@ strictEqual(_.hasPath(deepObject, ["arrayVal", 0]), true, "should return true for an array's index if it is defined"); |
@@ -16,3 +16,60 @@ // Underscore-contrib (underscore.function.arity.js 0.0.1) | ||
function enforcesUnary (fn) { | ||
return function mustBeUnary () { | ||
if (arguments.length === 1) { | ||
return fn.apply(this, arguments); | ||
} | ||
else throw new RangeError('Only a single argument may be accepted.'); | ||
} | ||
} | ||
// Curry | ||
// ------- | ||
var curry = (function () { | ||
function collectArgs(func, that, argCount, args, newArg, reverse) { | ||
if (reverse == true) { | ||
args.unshift(newArg); | ||
} else { | ||
args.push(newArg); | ||
} | ||
if (args.length == argCount) { | ||
return func.apply(that, args); | ||
} else { | ||
return enforcesUnary(function () { | ||
return collectArgs(func, that, argCount, args.slice(0), arguments[0], reverse); | ||
}); | ||
} | ||
} | ||
return function curry (func, reverse) { | ||
var that = this; | ||
return enforcesUnary(function () { | ||
return collectArgs(func, that, func.length, [], arguments[0], reverse); | ||
}); | ||
}; | ||
}()); | ||
// Enforce Arity | ||
// -------------------- | ||
var enforce = (function () { | ||
var CACHE = []; | ||
return function enforce (func) { | ||
if (typeof func !== 'function') { | ||
throw new Error('Argument 1 must be a function.'); | ||
} | ||
var funcLength = func.length; | ||
if (CACHE[funcLength] === undefined) { | ||
CACHE[funcLength] = function (enforceFunc) { | ||
return function () { | ||
if (arguments.length !== funcLength) { | ||
throw new RangeError(funcLength + ' arguments must be applied.'); | ||
} | ||
return enforceFunc.apply(this, arguments); | ||
}; | ||
}; | ||
} | ||
return CACHE[funcLength](func); | ||
}; | ||
}()); | ||
// Mixing in the arity functions | ||
@@ -69,29 +126,54 @@ // ----------------------------- | ||
}, | ||
// greedy currying for functions taking two arguments. | ||
// Flexible curry function with strict arity. | ||
// Argument application left to right. | ||
// source: https://github.com/eborden/js-curry | ||
curry: curry, | ||
// Flexible right to left curry with strict arity. | ||
rCurry: function (func) { | ||
return curry.call(this, func, true); | ||
}, | ||
curry2: function (fun) { | ||
return function curried (first, optionalLast) { | ||
if (arguments.length === 1) { | ||
return function (last) { | ||
return fun(first, last); | ||
}; | ||
} | ||
else return fun(first, optionalLast); | ||
}; | ||
return enforcesUnary(function curried (first) { | ||
return enforcesUnary(function (last) { | ||
return fun.call(this, first, last); | ||
}); | ||
}) | ||
}, | ||
// greedy flipped currying for functions taking two arguments. | ||
curry2flipped: function (fun) { | ||
return function curried (last, optionalFirst) { | ||
if (arguments.length === 1) { | ||
return function (first) { | ||
return fun(first, last); | ||
}; | ||
} | ||
else return fun(optionalFirst, last); | ||
}; | ||
} | ||
curry3: function (fun) { | ||
return enforcesUnary(function (first) { | ||
return enforcesUnary(function (second) { | ||
return enforcesUnary(function (last) { | ||
return fun.call(this, first, second, last); | ||
}) | ||
}) | ||
}) | ||
}, | ||
// reverse currying for functions taking two arguments. | ||
rcurry2: function (fun) { | ||
return enforcesUnary(function (last) { | ||
return enforcesUnary(function (first) { | ||
return fun.call(this, first, last); | ||
}) | ||
}) | ||
}, | ||
rcurry3: function (fun) { | ||
return enforcesUnary(function (last) { | ||
return enforcesUnary(function (second) { | ||
return enforcesUnary(function (first) { | ||
return fun.call(this, first, second, last); | ||
}) | ||
}) | ||
}) | ||
}, | ||
// Dynamic decorator to enforce function arity and defeat varargs. | ||
enforce: enforce | ||
}); | ||
_.arity = (function () { | ||
@@ -98,0 +180,0 @@ var FUNCTIONS = {}; |
@@ -241,4 +241,10 @@ // Underscore-contrib (underscore.function.combinators.js 0.0.1) | ||
// Returns function property of object by name, bound to object | ||
_.bound = function(obj, fname) { | ||
var fn = obj[fname]; | ||
if (!_.isFunction(fn)) | ||
throw new TypeError("Expected property to be a function"); | ||
return _.bind(fn, obj); | ||
}; | ||
})(this); |
@@ -68,3 +68,3 @@ // Underscore-contrib (underscore.object.selectors.js 0.0.1) | ||
return getPath(obj[[].shift.call(ks)], ks); | ||
return getPath(obj[_.first(ks)], _.rest(ks)); | ||
}, | ||
@@ -83,3 +83,3 @@ | ||
return hasPath(obj[[].shift.call(ks)], ks); | ||
return hasPath(obj[_.first(ks)], _.rest(ks)); | ||
} | ||
@@ -86,0 +86,0 @@ }); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
759507
55
15842
0
3
3