/* Get an array of parameter names for a function. Example: js> function f(a, b, c) { return a + b * c; } js> JSON.stringify(Function.parameters(f)); ["a","b","c"] */ Function.parameters = function(f) { var m = /function[^\(]*\(([^\)]*)\)/.exec(f.toString()); if (!m) { throw new TypeError("Invalid function in parameters"); } var params = m[1].split(','); for (var i = 0; i < params.length; i++) { // trim any spaces params[i] = params[i].replace(/^\s*|\s*$/g, ''); } return params; }; /* Create a new function that accepts its parameters in an object instead of its positional parameters. An optional array of names can be provided instead of using the parameters defined in the function (to rename parameters, or since some functions might use parameters that aren't named). Examples: js> function f(a, b, c) { return a + b * c; } js> f(1, 2, 3); 7 js> var f1 = Function.withNamedParameters(f); js> f1({ a:1, b:2, c:3 }); 7 js> // Call with an array (like f.apply) js> var f2 = Function.withNamedParameters(f, [0, 1, 2]); js> f2([1, 2, 3]); 7 */ Function.withNamedParameters = function(f, params) { // XXX: should this force f to be a function, or should anything that passes // the parameters RegExp with an apply function work? params = params || Function.parameters(f); return function(args) { var argsArray = new Array(params.length); for (var i = 0; i < params.length; i++) { argsArray[i] = args[params[i]]; } return f.apply(this, argsArray); }; }; /* Create a new function that accepts its positional parameters as objects mapping parameter names to values. Each parameter array maps ascending arguments to properties in an object. With a single parameter array, this is the opposite of Function.withNamedParameters. Examples: js> function f(p1, p2) { return { x: p1.x + p2.x, y: p1.y + p2.y }; } js> var f1 = Function.withPositionalParameters(f, ["x","y"], ["x","y"]); js> JSON.stringify(f1(1, 2, 3, 4)); {"x":4,"y":6} js> function f(a, b, c) { return a + b * c; } js> var f1 = Function.withNamedParameters(f); js> var f2 = Function.withPositionalParameters(f1, ["a", "b", "c"]); js> f2(1, 2, 3); // f2 is equivalent to (but slower than) f 7 js> // Reorder parameters js> var f3 = Function.withPositionalParameters(f1, ["c", "b", "a"]); js> f3(3, 2, 1); 7 */ Function.withPositionalParameters = function(f, params /*, ... */) { params = Array.prototype.slice.call(arguments, 1); return function() { var args = []; var argumentsIndex = 0; for (var i = 0; i < params.length; i++) { var arg = {}; var paramList = params[i]; args.push(arg); for (var p = 0; p < paramList.length; p++) { arg[paramList[p]] = arguments[argumentsIndex]; ++argumentsIndex; } } return f.apply(this, args); }; };