1 
  2 var comb = exports;
  3 
  4 /**
  5  * Determins if something is a function
  6  * @param {Anything} obj the thing to test if it is a function
  7  *
  8  * @returns {Boolean} true if the obj is a function false otherwise
  9  */
 10 comb.isFunction = function(obj) {
 11     return typeof obj == "function";
 12 };
 13 
 14 /**
 15  * Binds a method to a particular scope
 16  *
 17  * @param {Object} scope the scope to bind the callback to
 18  * @param {String|Function} method the method to callback
 19  * @param {Anything} [args] optional args to pass to the callback
 20  *
 21  * @returns {Function} the hitched function
 22  */
 23 comb.hitch = function(scope, method, args) {
 24     var args = Array.prototype.slice.call(arguments).slice(2);
 25     if (typeof method == "string") {
 26         method = scope[method];
 27     }
 28     if (method) {
 29         return function() {
 30             var scopeArgs = args.concat(Array.prototype.slice.call(arguments));
 31             return method.apply(scope, scopeArgs);
 32         };
 33     } else {
 34         throw new Error(method + "Method not defined");
 35     }
 36 };
 37 
 38 /**
 39  * Allows the passing of additional arguments to a function when it is called
 40  * especially useful for callbacks that you want to provide additional parameters to
 41  *
 42  * @param {String|Function} method the method to callback
 43  * @param {Anything} [args] variable number of arguments to pass
 44  *
 45  * @returns {Function} partially hitched function
 46  */
 47 comb.partial = function(method, args) {
 48     var args = Array.prototype.slice.call(arguments).slice(1);
 49     if (typeof method == "function") {
 50         return function() {
 51             var scopeArgs = args.concat(Array.prototype.slice.call(arguments));
 52             return method.apply(null, scopeArgs);
 53         };
 54     } else {
 55         throw new Error(method + "Method not defined");
 56     }
 57 };
 58 
 59 var curry = function(f, execute) {
 60     return function(arg) {
 61         var args = Array.prototype.slice.call(arguments);
 62         return execute ? f.apply(this, arguments) : function(arg) {
 63             return f.apply(this, args.concat(Array.prototype.slice.call(arguments)));
 64         };
 65     }
 66 };
 67 
 68 /**
 69  * Curries a function
 70  * @example
 71  * var curried = comb.curry(4, function(a,b,c,d){
 72  *     return [a,b,c,d].join(",");
 73  * }
 74  *  curried("a");
 75  *  curried("b");
 76  *  curried("c");
 77  *  curried("d") => "a,b,c,d"
 78  *
 79  *  //OR
 80  *
 81  *  curried("a")("b")("c")("d") => "a,b,c,d"
 82  *
 83  *
 84  * @param {Number} depth the number of args you expect
 85  * @param {Function} cb the function to call once all args are gathered
 86  * @param {Object} [scope] what scope to call the function in
 87  *
 88  * @returns {Function} the curried version of the function
 89  * */
 90 comb.curry = function(depth, cb, scope) {
 91     var f;
 92     if (scope) {
 93         f = comb.hitch(scope, cb);
 94     } else {
 95         f = cb;
 96     }
 97     if (depth) {
 98         var len = depth - 1;
 99         for (var i = len; i >= 0; i--) {
100             f = curry(f, i == len);
101         }
102     }
103     return f;
104 };
105 
106