Last active
August 29, 2015 14:23
-
-
Save rhys-vdw/0157b77038fa0aca9af3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// -- ChainFactory | |
// ChainFactory generates command chains that inherit from its static interface. | |
// Any call to `chain` will either create a new chain, or continue an existing | |
// one. | |
// | |
// The rule here is that every chainable method calls `chain` internally | |
// to get an instance of "itself". This ensure that it will make sense when | |
// bound to the ChainFactory constructor, and also when it's intantiated. When | |
// instantiated `chainInstance.chain` is overridden to return itself. | |
class ChainFactory { | |
static chain() { | |
// Create new object with this constructor as its prototype. This will give | |
// the `chain` the static properties Class.* | |
let chain = Object.create(this); | |
// Remove any static functions we don't want to chain. eg. `forge`. | |
// We just override their name on the current object, shadowing the super | |
// version. | |
// | |
// __notChainable is assigned by the `@doNotChain` decorator. | |
for (property of this) { | |
if (property.__notChainable) { | |
chain[property] = null; | |
} | |
} | |
// Now override the `prototype.chain` (ie. `ChainFactory.chain`), with a | |
// function that returns itself. This way any chained calls | |
// will not produce new instances. | |
chain.chain = function () { return this; }; | |
// Allow state to be assigned here by inheriting classes. | |
if (this.initializeChain) this.initializeChain(chain); | |
// Return the new chain instance. | |
return chain; | |
} | |
} | |
// -- `@doNotChain` static method decoration | |
// | |
// Tacks on a little flag to methods that we don't want to reveal in chains. | |
// | |
// class MyThingo extends ChainFactory { | |
// @doNotChain | |
// someStaticFunction() { | |
// // ... | |
// } | |
// } | |
// | |
function doNotChain() { | |
return function decorator(staticFunction, name, descriptor) { | |
staticFunction.__notChainable = true; | |
} | |
} | |
// -- Example | |
class Adder extends ChainFactory { | |
static intializeChain() { | |
let chain = this.chain(); | |
chain._currentValue = 0; | |
return chain; | |
} | |
static add(value) { | |
let chain = this.chain(); | |
chain._currentValue += value; | |
return chain; | |
} | |
static value() { | |
return this.chain()._currentValue; | |
} | |
} | |
let adder1 = Adder.add(5).add(2).add(5); | |
let adder2 = Adder.add(1); | |
adder1.value() // 12 | |
adder2.value() // 1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment