Created
December 27, 2016 01:08
-
-
Save koresar/9e3e6ded004383c7a1c4b73b8e8387b2 to your computer and use it in GitHub Desktop.
Fun with Stamps. Episode 11. Interfering composition
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
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