function-extended
Version:
Additional function extensions with a chainable api
257 lines (229 loc) • 8.75 kB
JavaScript
(function () {
"use strict";
function defineFunction(extended, is, args) {
var isArray = is.isArray,
isObject = is.isObject,
isString = is.isString,
isFunction = is.isFunction,
argsToArray = args.argsToArray;
function spreadArgs(f, args, scope) {
var ret;
switch ((args || []).length) {
case 0:
ret = f.call(scope);
break;
case 1:
ret = f.call(scope, args[0]);
break;
case 2:
ret = f.call(scope, args[0], args[1]);
break;
case 3:
ret = f.call(scope, args[0], args[1], args[2]);
break;
default:
ret = f.apply(scope, args);
}
return ret;
}
function hitch(scope, method, args) {
args = argsToArray(arguments, 2);
if ((isString(method) && !(method in scope))) {
throw new Error(method + " property not defined in scope");
} else if (!isString(method) && !isFunction(method)) {
throw new Error(method + " is not a function");
}
if (isString(method)) {
return function () {
var func = scope[method];
if (isFunction(func)) {
return spreadArgs(func, args.concat(argsToArray(arguments)), scope);
} else {
return func;
}
};
} else {
if (args.length) {
return function () {
return spreadArgs(method, args.concat(argsToArray(arguments)), scope);
};
} else {
return function () {
return spreadArgs(method, arguments, scope);
};
}
}
}
function applyFirst(method, args) {
args = argsToArray(arguments, 1);
if (!isString(method) && !isFunction(method)) {
throw new Error(method + " must be the name of a property or function to execute");
}
if (isString(method)) {
return function () {
var scopeArgs = argsToArray(arguments), scope = scopeArgs.shift();
var func = scope[method];
if (isFunction(func)) {
scopeArgs = args.concat(scopeArgs);
return spreadArgs(func, scopeArgs, scope);
} else {
return func;
}
};
} else {
return function () {
var scopeArgs = argsToArray(arguments), scope = scopeArgs.shift();
scopeArgs = args.concat(scopeArgs);
return spreadArgs(method, scopeArgs, scope);
};
}
}
function hitchIgnore(scope, method, args) {
args = argsToArray(arguments, 2);
if ((isString(method) && !(method in scope))) {
throw new Error(method + " property not defined in scope");
} else if (!isString(method) && !isFunction(method)) {
throw new Error(method + " is not a function");
}
if (isString(method)) {
return function () {
var func = scope[method];
if (isFunction(func)) {
return spreadArgs(func, args, scope);
} else {
return func;
}
};
} else {
return function () {
return spreadArgs(method, args, scope);
};
}
}
function hitchAll(scope) {
var funcs = argsToArray(arguments, 1);
if (!isObject(scope) && !isFunction(scope)) {
throw new TypeError("scope must be an object");
}
if (funcs.length === 1 && isArray(funcs[0])) {
funcs = funcs[0];
}
if (!funcs.length) {
funcs = [];
for (var k in scope) {
if (scope.hasOwnProperty(k) && isFunction(scope[k])) {
funcs.push(k);
}
}
}
for (var i = 0, l = funcs.length; i < l; i++) {
scope[funcs[i]] = hitch(scope, scope[funcs[i]]);
}
return scope;
}
function partial(method, args) {
args = argsToArray(arguments, 1);
if (!isString(method) && !isFunction(method)) {
throw new Error(method + " must be the name of a property or function to execute");
}
if (isString(method)) {
return function () {
var func = this[method];
if (isFunction(func)) {
var scopeArgs = args.concat(argsToArray(arguments));
return spreadArgs(func, scopeArgs, this);
} else {
return func;
}
};
} else {
return function () {
var scopeArgs = args.concat(argsToArray(arguments));
return spreadArgs(method, scopeArgs, this);
};
}
}
function curryFunc(f, execute) {
return function () {
var args = argsToArray(arguments);
return execute ? spreadArgs(f, arguments, this) : function () {
return spreadArgs(f, args.concat(argsToArray(arguments)), this);
};
};
}
function curry(depth, cb, scope) {
var f;
if (scope) {
f = hitch(scope, cb);
} else {
f = cb;
}
if (depth) {
var len = depth - 1;
for (var i = len; i >= 0; i--) {
f = curryFunc(f, i === len);
}
}
return f;
}
return extended
.define(isObject, {
bind: hitch,
bindAll: hitchAll,
bindIgnore: hitchIgnore,
curry: function (scope, depth, fn) {
return curry(depth, fn, scope);
}
})
.define(isFunction, {
bind: function (fn, obj) {
return spreadArgs(hitch, [obj, fn].concat(argsToArray(arguments, 2)), this);
},
bindIgnore: function (fn, obj) {
return spreadArgs(hitchIgnore, [obj, fn].concat(argsToArray(arguments, 2)), this);
},
partial: partial,
applyFirst: applyFirst,
curry: function (fn, num, scope) {
return curry(num, fn, scope);
},
noWrap: {
f: function () {
return this.value();
}
}
})
.define(isString, {
bind: function (str, scope) {
return hitch(scope, str);
},
bindIgnore: function (str, scope) {
return hitchIgnore(scope, str);
},
partial: partial,
applyFirst: applyFirst,
curry: function (fn, depth, scope) {
return curry(depth, fn, scope);
}
})
.expose({
bind: hitch,
bindAll: hitchAll,
bindIgnore: hitchIgnore,
partial: partial,
applyFirst: applyFirst,
curry: curry
});
}
if ("undefined" !== typeof exports) {
if ("undefined" !== typeof module && module.exports) {
module.exports = defineFunction(require("extended"), require("is-extended"), require("arguments-extended"));
}
} else if ("function" === typeof define && define.amd) {
define(["extended", "is-extended", "arguments-extended"], function (extended, is, args) {
return defineFunction(extended, is, args);
});
} else {
this.functionExtended = defineFunction(this.extended, this.isExtended, this.argumentsExtended);
}
}).call(this);