Last active
June 18, 2016 03:40
-
-
Save danielkcz/3a1bac834c971f604b8bfac4a6f813c4 to your computer and use it in GitHub Desktop.
Simple example of use of the stampit library to create easy to define models with getters/setters and true private values.
This file contains 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
import stampit from 'stampit'; | |
import EventEmitter from 'events'; | |
const EventEmittable = stampit({ | |
initializers: function initEventEmitter() { | |
Reflect.apply(EventEmitter, this, []); | |
}, | |
methods: ['emit', 'on', 'once', 'removeListener'].reduce((methods, methodName) => { | |
methods[methodName] = EventEmitter.prototype[methodName]; | |
return methods; | |
}, {}), | |
}); | |
export default EventEmittable; |
This file contains 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
import { upperFirst, isFunction } from 'lodash'; | |
import stampit from 'stampit'; | |
import EventEmittable from './EventEmittable'; | |
import Private from './Private'; | |
export const ModelPrivate = Private.methods({ | |
getProperty(owner, propertyName) { | |
return this.get(owner, 'props')[propertyName]; | |
}, | |
setProperty(owner, propertyName, propertyValue) { | |
const props = this.get(owner, 'props'); | |
props[propertyName] = propertyValue; | |
}, | |
}); | |
function Model(modelName, privates = ModelPrivate.create()) { | |
function initializeModelPrivateArea() { | |
privates.init(this); | |
privates.set(this, 'props', {}); | |
} | |
const getter = setupPropertyAccessor(privates, true); | |
const property = setupPropertyAccessor(privates); | |
function valueOf() { | |
return Object.assign({}, privates.get(this, 'props')); | |
} | |
const data = { get: valueOf }; | |
function toString() { | |
return `model of ${modelName}`; | |
} | |
function getModelName() { | |
return modelName; | |
} | |
return stampit.compose(EventEmittable, { | |
initializers: [initializeModelPrivateArea], | |
methods: { getModelName, toString, valueOf }, | |
propertyDescriptors: { data }, | |
staticProperties: { getter, property }, | |
}); | |
} | |
function setupPropertyAccessor(privates, readonly = false) { | |
return function accessProperty(propertyName, defaultValue = null) { | |
const methodSuffix = upperFirst(propertyName); | |
const methods = {}; | |
methods[`get${methodSuffix}`] = function getPropertyValue() { | |
return privates.getProperty(this, propertyName); | |
}; | |
function setPropertyValue(newValue) { | |
const oldValue = privates.getProperty(this, propertyName); | |
privates.setProperty(this, propertyName, newValue); | |
this.emit('change', propertyName, newValue, oldValue); | |
} | |
if (readonly !== true) { | |
methods[`set${methodSuffix}`] = setPropertyValue; | |
} | |
function initializePropertyValue(data) { | |
let initValue = defaultValue; | |
if (isFunction(defaultValue)) { | |
const obtainedValue = Reflect.apply(defaultValue, this, [data]); | |
initValue = obtainedValue; | |
} else if (data && data.hasOwnProperty(propertyName)) { | |
initValue = data[propertyName]; | |
} | |
privates.setProperty(this, propertyName, initValue); | |
} | |
return this.compose({ | |
methods, initializers: [initializePropertyValue], | |
}); | |
}; | |
} | |
export default Model; |
This file contains 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
import Model from './Model'; | |
import Private from './Private'; | |
const privates = Private.create(); | |
export default Model('Person', privates) | |
.property('firstname') | |
.property('surname') | |
.getter('sex', 'male') | |
).methods({ | |
getFullName() { | |
return `${this.getFirstname()} ${this.getSurname} is ${this.getSex()}`.trim(); | |
} | |
}); |
This file contains 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
import stampit from 'stampit'; | |
const Private = stampit() | |
.init((options, { instance }) => { | |
instance.map = new WeakMap(); | |
}) | |
.methods({ | |
init(owner) { | |
const ownerMap = new Map(); | |
this.map.set(owner, ownerMap); | |
return ownerMap; | |
}, | |
for(owner) { | |
return this.map.get(owner); | |
}, | |
get(owner, key) { | |
const ownerMap = this.for(owner); | |
return ownerMap.has(key) ? ownerMap.get(key) : null; | |
}, | |
set(owner, key, value) { | |
this.for(owner).set(key, value); | |
return value; | |
}, | |
}) | |
; | |
export default Private; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The
PersonModel
can be extended in any way you like, composing other stamps into it. This can be used simply like this.