Skip to content

Instantly share code, notes, and snippets.

@bttmly
Forked from CrossEye/first.js
Created June 18, 2014 14:55
Show Gist options
  • Save bttmly/ea3904bfa905f7369b69 to your computer and use it in GitHub Desktop.
Save bttmly/ea3904bfa905f7369b69 to your computer and use it in GitHub Desktop.
var first = (function() {
var chainNames = ["then", "andThen", "next"];
var endChainNames = ["finally", "andFinally", "last"];
var chain = function(fn) {
var f1 = function(g) {
var func = function() {return g.call(this, fn.apply(this, arguments));};
chain(func);
return func;
};
var f2 = function(g) {
return function() {return g.call(this, fn.apply(this, arguments));};
};
chainNames.forEach(function(name) {fn[name] = f1;});
endChainNames.forEach(function(name) {fn[name] = f2;});
};
return function(f) {
var fn = function() {
return f.apply(this, arguments);
};
chain(fn);
return fn;
};
}());
// Ex: var f = first(add1).then(mult2).andThen(square).finally(negate); f(3) = -((3 + 1) * 2)^2 = -64;
// TODO?: make aliases configurable properties of `first` function?
//------------------------------------------------------------------------------
var add1 = function(x) {return x + 1;};
var mult2 = function(x) {return x * 2;};
var square = function(x) {return x * x;};
var negate = function(x) {return -x;};
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
console.assert(typeof first == "function", "first should be a function");
console.assert(typeof first(add1).then == "function", "first should add `then` and related functions to a function");
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
var f = first(add1);
console.assert(3 == f(2), "first should not actually change behavior of existing function");
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
f = first(add1).then(mult2);
console.assert(6 == f(2), "initial composition should work appropriately");
f = first(mult2).then(add1);
console.assert(5 == f(2), "initial composition should work appropriately: order matters");
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
f = first(add1).then(mult2).then(square).then(negate);
console.assert(-36 == f(2), "multiple composition should work appropriately");
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
f = first(add1).then(mult2).andThen(square).next(negate);
console.assert(-36 == f(2), "composition name aliases should be available");
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
f = first(add1).then(mult2).andThen(square).finally(negate);
console.assert(-36 == f(2), "composition name aliases should include finalizer");
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
f = first(add1).then(mult2).andThen(square).finally(negate);
console.assert(typeof f.then == "undefined", "finalized functions should not have chainable methods");
console.assert(typeof f.finally == "undefined", "finalized functions should not have finalizer methods");
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
f = first(add1).then(mult2).andThen(square).andFinally(negate);
console.assert(-36 == f(2), "finalizers should also have aliases such as `andFinally`");
console.assert(typeof f.then == "undefined", "finalized functions should not have chainable methods");
f = first(add1).then(mult2).andThen(square).last(negate);
console.assert(-36 == f(2), "finalizers should also have aliases such as `last`");
console.assert(typeof f.last == "undefined", "finalized functions should not have finalizer methods");
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
var a = function() {return this.foo;};
var b = function(x) {return x + " " + this.bar;};
var obj = {
foo: "Hello",
bar: "world",
f: first(a).then(b)
};
console.assert("Hello world" === obj.f(), "context is maintained when composed functions are used as methods");
//------------------------------------------------------------------------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment