Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added composers for stamp composition control #197

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions examples/static-queue/example-1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@

var stampit = require('../../dist/stampit.js');

/*
example of replacing the base composer for stamps.
*/

var staticQueueComposer = {
// replaces base composer
name: 'base',
order: 0,
compose: function (self, other) {
console.log('static queue compose');

var selfId = '';
var selfQueue = [];
if(self){
selfId = self.static.id || '';
selfQueue = self.static.queue || [];
}

var otherId = '';
var otherQueue = [];
if(other){
otherId = other.static.id || '';
otherQueue = other.static.queue || [];
}

console.log(' - self ', selfId, selfQueue);
console.log(' - other ', otherId, otherQueue);

console.log('');

var q1 = [];
var q2 = [];

if(self && self.static.queue){
q1 = self.static.queue;
}

if(other && other.static.queue){
q2 = other.static.queue;
}

var q = q1.concat(q2);

// call the base stampit composer
self = stampit.baseComposer.compose(self, other);

self.static.queue = q;
return self;

}
};

var StaticQueue = stampit({
static: {
id: 'X',
},
// must be added to replace base composer in every stamp
composers: [staticQueueComposer]
});


var A = stampit({
static: {
id: 'A',
queue: [
'a',
'aa',
'aaa',
],
},
// must be added to replace base composer in every stamp
composers: [staticQueueComposer]
});


var B = stampit({
static: {
id: 'B',
queue: [
'b',
'bb',
'bbb',
],
},
// must be added to replace base composer in every stamp
composers: [staticQueueComposer]
});

var C = stampit({
static: {
id: 'C',
queue: [
'c',
'cc',
'ccc',
],
},
// must be added to replace base composer in every stamp
composers: [staticQueueComposer]
});

var X = StaticQueue.compose(A, B, C);

console.log('queue:', X.fixed.static.queue);

103 changes: 103 additions & 0 deletions examples/static-queue/example-2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@

var stampit = require('../../dist/stampit.js');

/*
example of adding composer that runs before base composer
*/

var staticQueueComposer = {
// named composer will not be duplicated every compose
name: 'staticQueue',
// run before the base composer
sort: -1,
compose: function (self, other) {
console.log('static queue compose');

var selfId = '';
var selfQueue = [];
if(self){
selfId = self.static.id || '';
selfQueue = self.static.queue || [];
}

var otherId = '';
var otherQueue = [];
if(other){
otherId = other.static.id || '';
otherQueue = other.static.queue || [];
}

console.log(' - self ', selfId, selfQueue);
console.log(' - other ', otherId, otherQueue);

console.log('');

var q1 = [];
var q2 = [];

if(self && self.static.queue){
q1 = self.static.queue;
}

if(other && other.static.queue){
q2 = other.static.queue;
}


var q = q1.concat(q2);

// set the merged queue on the `other` obect to be merged into self by base composer
other.static.queue = q1.concat(q2);

return self;
}
};

var StaticQueue = stampit({

static: {
id: 'X',
},

composers: [staticQueueComposer]

});

var A = stampit({
static: {
id: 'A',
queue: [
'a',
'aa',
'aaa',
],
},
});


var B = stampit({
static: {
id: 'B',
queue: [
'b',
'bb',
'bbb',
],
},
});

var C = stampit({
static: {
id: 'C',
queue: [
'c',
'cc',
'ccc',
],
},
});

var X = StaticQueue.compose(A, B, C);

console.log('queue:', X.fixed.static.queue);

143 changes: 126 additions & 17 deletions src/stampit.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
import forEach from 'lodash/collection/forEach';
import isFunction from 'lodash/lang/isFunction';
import isObject from 'lodash/lang/isObject';
import isArray from 'lodash/lang/isArray';
import objectValues from 'lodash/object/values';
import sortBy from 'lodash/collection/sortBy';
import {
merge,
mergeChainNonFunctions,
Expand Down Expand Up @@ -68,23 +71,112 @@ function cloneAndExtend(fixed, extensionFunction, ...args) {
return stamp;
}

function splitComposers(array) {
let anon = [];
let named = {};

forEach(array, comp => {
if (comp.name) {
named[comp.name] = comp;
} else {
anon.push(comp);
}
});

return {
anon: anon,
named: named
};
}

function addComposers(fixed, newComposers) {
let composers = newComposers;
if (!isArray(composers)) {
if (isObject(composers)) {
composers = [composers];
} else {
return fixed.composers;
}
}

if (!composers) {
return fixed.composers;
}

const current = splitComposers(fixed.composers);
const added = splitComposers(composers);

// replace current.named with added.named where names are the same
const named = Object.assign({}, current.named, added.named);

let finalComps = objectValues(named);

finalComps = finalComps.concat(added.anon, current.anon);

finalComps = sortBy(finalComps, (comp) => {
return comp.sort;
});

fixed.composers = finalComps;

return fixed.composers;
}

function callComposers(fixed, sourceFixed) {
if (!fixed.composers) {
return fixed;
}

let fixedResult = fixed;

forEach(fixed.composers, composer => {
if (!isFunction(composer.compose)) {
return; // not a function, do nothing.
}

fixedResult = composer.compose.call(null, fixed, sourceFixed) || fixed;
});

return fixedResult;
}

function compose(...factories) {
const result = stampit();
let result = stampit();
forEach(factories, source => {
let sourceFixed;

if (source && source.fixed) {
addMethods(result.fixed, source.fixed.methods);
addComposers(result.fixed, source.fixed.composers);
sourceFixed = source.fixed;
}

result.fixed = callComposers(result.fixed, sourceFixed) || result.fixed;
});

result = mixin(result, result.fixed.static);

return result;
}

const baseComposer = {
name: 'base',
sort: 0,
compose(fixed, sourceFixed) {
if (sourceFixed) {
addMethods(fixed, sourceFixed.methods);
// We might end up having two different stampit modules loaded and used in conjunction.
// These || operators ensure that old stamps could be combined with the current version stamps.
// 'state' is the old name for 'refs'
addRefs(result.fixed, source.fixed.refs || source.fixed.state);
addRefs(fixed, sourceFixed.refs || sourceFixed.state);
// 'enclose' is the old name for 'init'
addInit(result.fixed, source.fixed.init || source.fixed.enclose);
addProps(result.fixed, source.fixed.props);
addStatic(result.fixed, source.fixed.static);
addInit(fixed, sourceFixed.init || sourceFixed.enclose);
addProps(fixed, sourceFixed.props);
addStatic(fixed, sourceFixed.static);
}
});
return mixin(result, result.fixed.static);
}
return fixed;
}
};


/**
* Return a factory function that will produce new objects using the
Expand All @@ -107,16 +199,14 @@ function compose(...factories) {
* @return {Function(statics)} factory.static Add properties to the stamp (not objects!). Chainable.
*/
const stampit = function stampit(options) {
const fixed = {methods: {}, refs: {}, init: [], props: {}, static: {}};
let fixed = {methods: {}, refs: {}, init: [], props: {}, static: {}, composers: [baseComposer]};
fixed.state = fixed.refs; // Backward compatibility. 'state' is the old name for 'refs'.
fixed.enclose = fixed.init; // Backward compatibility. 'enclose' is the old name for 'init'.
if (options) {
addMethods(fixed, options.methods);
addRefs(fixed, options.refs);
addInit(fixed, options.init);
addProps(fixed, options.props);
addStatic(fixed, options.static);
if (options && options.composers) {
addComposers(fixed, options.composers);
}
// allow new instance or mutate existing
fixed = callComposers(fixed, options) || fixed;

const factory = function Factory(refs, ...args) {
let instance = mixin(create(fixed.methods), fixed.refs, refs);
Expand Down Expand Up @@ -365,5 +455,24 @@ export default mixin(stampit, {
* @param {Function} Constructor
* @return {Function} A composable stampit factory (aka stamp).
*/
convertConstructor
convertConstructor,

/**
* Base composer object.
* @type {Object}
*/
baseComposer: baseComposer,

/**
* Expose interal composer utilities
* @type {Object}
*/
composerUtil: {
addMethods: addMethods,
addRefs: addRefs,
addInit: addInit,
addProps: addProps,
addStatic: addStatic
}

});