genData
A normalization pattern to build, query, and manipulate everything.
(5/22/12)
version 2.0.0
by Bemi Faison
DESCRIPTION
genData enumerates member values and returns a dataset, an array of generated content. genData lets you control iteration rules, process members, and alter dataset content with custom functions, called parsers. Additionally, parsers may be captured and extended through curry-like functions called generators.
USAGE
By default, genData normalizes the first argument into a depth-first index of generic data objects.
var
stuff = {hello:{world:'!'}},
helloData = genData(stuff);
console.log(helloData);
genData even normalizes nothing...
console.log(genData());
Data Customization
Data objects represent the initial value and it's descendents, with simple name and value properties. Modify this generic structure via one or more parser functions. Parsers execute in order, scoped to each data object.
var
customData = genData(
stuff,
function () {
this.randNum = Math.random();
},
function () {
this.randTen = Math.floor(this.randNum * 10);
}
);
console.log(customData);
Data objects use genData's prototype, allowing you to propogate members and methods.
genData.prototype.getType = function () {
return typeof this.value;
};
var
objData = genData(
stuff,
function () {
this.isObject = this.getType() == 'object';
}
);
console.log(objData);
console.log(helloData[0].getType());
console.log(customData[2].getType());
Generators
To isolate and/or pair prototyped members with specific data structures, genData supports "spawning". Spawning curries parser configurations and extends the prototype chain of genData or it's spawned generators.
var
genObj = genData.spawn(function () {
this.isObject = this.getType() == 'object';
});
genObj.prototype.getType = genData.prototype.getType;
delete genData.prototype.getType;
console.log('Generators hide parser and prototype configurations!', JSON.stringify(objData) == JSON.stringify(genObj(stuff)));
Prototype substitution
Lastly, you can substitute an entire prototype, by scoping genData/generators calls to a function.
function Foo() {}
Foo.prototype.greet = function () {
console.log('hello world!');
};
genData.call(Foo)[0].greet();
Parser Signature
Parsers receive a special argument signature, which lets them do more than modify the data object. Below are the ordered arguments sent to each parser function.
- name - The key string for this value, from the parent object. Since the first data object represents the initial value, it's name argument is an empty string. For array elements, the name reflects it's numeric index.
- value - The value corresponding the key, from the parent object (except in the case of the initial value's data object).
- parent - The parent object that contains the name/value pair. For the first data object, this argument will be
null.
- dataset - The array returned by genData (or the generator).
- flags - An object with iteration and execution flags that control genData's behavior.
- omit When truthy, the current data object will not be added to the dataset. (Default is
false.)
- scan When falsy, members of the current data object will be processed by genData. (Default is true.)
- parent When set, genData will scan the given object instead of the current object. (Default is null.)
- exit When truthy, genData will halt all processing and return the dataset. (Default is false.)
- shared - An object that is untouched between parser invocations and discarded when genData completes.
Use of these flags, lets you use genData as a filter (or to create generators that filter).
var
getAllArrays = genData.spawn(function (name, value, parent, dataset, flags) {
flags.omit = 1;
if (value instanceof Array) {
this.isArray = true;
dataset.push(value);
}
}),
getFirstArrays = getAllArrays.spawn(function (name, value, parent, dataset, flags) {
flags.scan = !this.isArray;
});
Spawning Psuedo-Klasses
With generators and prototyped methods, parsers can initialize data objects, as if you were defining a class constructor and methods.
var
menuDom = document.getElementById('someUL'),
genListItems = genData.spawn(function (name, value, parent, dataset, flags, ) {
flags.omit = typeof value !== 'string';
this.text = this.value;
delete this.name;
delete this.value;
});
getListItems.prototype.getElement = function () {
if (!this.cachedNode) {
this.cachedNode = document.createElement('li');
this.cachedNode.appendChild(document.createTextNode(this.text));
}
return this.cachedNode.cloneNode(1);
};
genListItems(['menu item 1', 'menu item 2']).forEach(function (LI) {
menuDom.appendChild(LI.getElement());
});
View the genData wiki, for more ways to use genData and generators.
FILES
- gendata-min.js - genData source file (minified with UglifyJS)
- LICENSE - The legal terms and conditions under which this software may be used
- README.md - This readme file
- src/ - Directory containing the source code
- test/ - Directory containing Qunit test files
INSTALL
For HTML environments, reference gendata-min.js as you would any external JavaScript file.
<script type="text/javascript" src="somepath/gendata-min.js"></script>
<script type="text/javascript">
</script>
For Node, use npm.
npm install genData
Then require the genData module and reference the exported genData function.
var genData = require('genData').genData;
LICENSE
genData is available under the terms of the MIT-License.
Copyright 2012, Bemi Faison