Skip to content

Instantly share code, notes, and snippets.

@rhys-vdw
Last active August 29, 2015 14:23
Show Gist options
  • Save rhys-vdw/0157b77038fa0aca9af3 to your computer and use it in GitHub Desktop.
Save rhys-vdw/0157b77038fa0aca9af3 to your computer and use it in GitHub Desktop.
// -- 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