Skip to content

Instantly share code, notes, and snippets.

@koresar
Created December 27, 2016 01:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save koresar/9e3e6ded004383c7a1c4b73b8e8387b2 to your computer and use it in GitHub Desktop.
Save koresar/9e3e6ded004383c7a1c4b73b8e8387b2 to your computer and use it in GitHub Desktop.
Fun with Stamps. Episode 11. Interfering composition
const _ = require('lodash');
const stampit = require('stampit');
const isStamp = require('stampit/isStamp');
const Tracked = stampit()
.composers(({composables, stamp}) => { // declaring a composer
console.log(`Composed a stamp "${stamp}" from the following:
"${composables.join()}"`);
});
const SelfAware = stampit()
.composers(({stamp}) => {
const methods = stamp.compose.methods || {};
methods.getStamp = () => stamp; // mutation! Adding a method
stamp.compose.methods = methods;
});
const ComponentsMonitoring = stampit()
.composers(({stamp, composables}) => {
// get or create the configuration metadata
const conf = stamp.compose.configuration || {};
stamp.compose.configuration = conf;
// concatenate new composables with the previous list
conf.wasComposedOf = composables.concat(conf.wasComposedOf);
// de-duplicate the array
conf.wasComposedOf = _.uniq(conf.wasComposedOf);
// get or create the methods metadata
const methods = stamp.compose.methods || {};
stamp.compose.methods = methods;
// add or overwrite the method which returns the composables
const wasComposedOf = conf.wasComposedOf;
methods.getOrigins = () => wasComposedOf;
});
const ThrowOnMethodCollision = stampit()
.composers(({stamp, composables}) => { // declaring a composer
const methodsArray = composables
// convert stamps to descriptors
.map(c => isStamp(c) ? c.compose : c)
// get methods metadata from the descriptors
.map(d => d.methods).filter(m => m);
// do the checks
const methodsStore = {};
methodsArray.forEach(methods => {
// `methods` is an object, each property should be checked
Object.keys(methods).forEach(methodName => {
if (methodsStore[methodName]) {
// oops, we see this method name second time!
throw new Error(`Method "${methodName}" conflict`);
} else {
// all good, we haven't seen that method yet
methodsStore[methodName] = true;
}
});
});
});
function alwaysFirstInitializer(options) {
Object.assign(this, options);
}
const AssignFirstArgument = stampit({
init: alwaysFirstInitializer, // The initializer itself
composers({stamp}) { // The composer callback
let inits = stamp.compose.initializers;
// removing the initializer from the array
inits = inits.filter(i => i !== alwaysFirstInitializer);
// insert our initializer to the beginning of the list
inits.unshift(alwaysFirstInitializer);
// mutating the stamp - overwriting the initializers list
stamp.compose.initializers = inits;
}
});
const Blended = stampit(
Tracked,
SelfAware,
ComponentsMonitoring,
ThrowOnMethodCollision,
AssignFirstArgument
);
// 1) will log via Tracked composable behavior
// 2) will check method name collisions via ThrowOnMethodCollision
const obj = Blended({myFlag: true});
console.log(obj);
// 3) will have "myFlag" assigned to true via AssignFirstArgument
console.log(obj.myFlag);
// 4) will return the Blended stamp via SelfAware
console.log(obj.getStamp());
// 5) will return the list of all 5 stamps via ComponentsMonitoring
console.log(obj.getOrigins().length);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment