      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 [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