Skip to content

Instantly share code, notes, and snippets.

@fd
Created April 29, 2011 12:39
Show Gist options
  • Save fd/948234 to your computer and use it in GitHub Desktop.
Save fd/948234 to your computer and use it in GitHub Desktop.
/*
* Curry a JS function.
*
* Note:
* Curry doesn't change `this`.
*
* Example:
* function f(a, b, c){
* return [a, b, c];
* };
* var g = f.curry('a', 'b');
* g('c'); # => ['a', 'b', 'c']
*/
Function.prototype.curry = function(){
var curry_arguments = Array.prototype.slice.apply(arguments)
, base_function = this
;
return function(){
var arguments = Array.prototype.slice.apply(arguments)
;
return base_function.apply(this, curry_arguments.concat(arguments));
};
};
/*
* Bind a JS function.
*
* Example:
* function f(){
* return "Hello " + this;
* };
* var g = f.bind('Anais');
* g(); # => "Hello Anais"
*/
Function.prototype.bind = function(receiver){
var base_function = this
;
return function(){
var arguments = Array.prototype.slice.apply(arguments)
;
return base_function.apply(receiver, arguments);
};
};
var _default_chainer_target;
/*
* Create a chainer.
*
* Example:
* var _ = Function.chainer(
* { hello: function(self){ console.log("Hello " + self); }
* , bye: function(self){ console.log("Bye " + self); }
* });
* _('Anais').hello().bye();
* # console:
* # Hello Anais
* # Bye Anais
*
* Example:
* Function.chainer(
* String.prototype,
* { hello: function(self){ console.log("Hello " + self); }
* , bye: function(self){ console.log("Bye " + self); }
* });
* 'Anais'.hello().bye();
* # console:
* # Hello Anais
* # Bye Anais
*
* Example:
* var gf = "Anais";
* Function.chainer(
* gf,
* { hello: function(self){ console.log("Hello " + self); }
* , bye: function(self){ console.log("Bye " + self); }
* });
* gf.hello().bye();
* # console:
* # Hello Anais
* # Bye Anais
*/
Function.chainer = function(target, functions){
var chainer = target
;
if (functions === undefined){
functions = target;
chainer = _default_chainer_target()
target = chainer.prototype;
}
var name
;
for (name in functions) {
(function(name, func){
target[name] = function(){
var arguments = Array.prototype.slice.apply(arguments)
, use_member = false
;
try {
use_member = (this instanceof chainer);
} catch (e) {};
if (use_member) {
func.apply(functions, [this.receiver].concat(arguments));
return this;
} else {
func.apply(functions, [this].concat(arguments));
return this;
}
};
}(name, functions[name]));
}
return chainer;
};
_default_chainer_target = function(){
var base
;
base = function(receiver){
if (this instanceof base) {
this.receiver = receiver;
} else {
return new base(receiver);
}
};
return base;
};
/*
* Easy duck typing for JS objects.
*
* Example:
* var f = Function.duck('concat');
* var g = f.bind(['a']);
* g(['b']); # => ['a', 'b']
*
* Example:
* var f = Function.duck('concat');
* var g = f.bind(5);
* g(['b']); # => undefined
*/
Function.duck = function(function_name){
return function(){
var member
;
member = this[function_name];
if (member == undefined) { return; }
if (!(member instanceof Function)) { return; }
return member.apply(this, arguments);
};
};
/*
* Fire a function only once.
*
*/
Function.prototype.once = function(){
var base_function = this
, fired = false
, result = null
;
return function(){
var arguments = Array.prototype.slice.apply(arguments)
;
if (!fired) {
result = base_function.apply(this, arguments);
}
return result;
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment