Package Exports
- class-o-mat
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (class-o-mat) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
ClassOMat ( the Minion generator )
ClassOMat is a Class Factory System. It creates classes dynamically by adding methods to access elements within an internal _params object.
While everything in ClassOMat can be done manually, ClassOMat provides a more convenient way to dynamically build classes that abstracts most of the code away from the using author.
Furthermore, ClassOMat can modify classes in the most efficient way possible.
ClassOMat handles the complexity to keep your classes simpler to create and run.
Click here to go straight to the QuickStart:
Click here to go straight to ClassOMat Reference:
This is Version 0.3.0 (Alpha):
Before we continue...
A Minion Class is a class created by a ClassOMat.
A minion is an instance of a Minion Class
ClassOMat combines aspects of inheritence with mixins to create new classes:
- ClassOMat can add functions at will to a class.
- ClassOMat can also be set up to provide some inherited traits.
ClassOMat-generated classes can accept new methods dynamically:
- An instance of a class (minion) generated by ClassOMat can have new functions added easily to its API.
ClassOmat can created hierachies of nested class instances automatically:
- A parent minion can copy specified parameters to a child minion and can rename those parameters if needed
- A minion can safely create a child Minion as an instance of its own class.
Quick Start:
0: Install ClassOMat: npm install 'class-o-mat';
1: Import ClassOMat and create a ClassOMat instance:
import ClassOMat from 'class-o-mat';
const classOMat = new ClassOMat('top');
2: Create a Base Class:
class BaseClass {}
3: Add some parameter methods ( fields ) to the ClassOMat instance:
const nameFieldSpec = classOMat.field('name');
const ageFieldSpec = classOMat.field('age');
4: Add a the Base Class to the ClassOMat:
classOMat.BaseClass(BaseClass);
5: Create a Minion Class from the ClassOMat:
// the $() is the 'execute' function.
const MinionClass = classOMat.$()
6: Create an instance ( minion ) of the Minion Class and use it.
const minion = new MinionClass();
minion.name('Dorothy Gale');
minion.age(16);
const name = minion.name(); // name = Dorothy Gale
const age = minion.age(); // age = 16
Same thing using chaining syntax:
import ClassOMat from 'class-o-mat';
const classOMat = new ClassOMat('top');
class BaseClass {};
classOMat.BaseClass(BaseClass).field('name').field('age');
const MinionClass = classOMat.$();
const minion = new MinionClass().name('Dorothy Gale').age(16);
const name = minion.name(); // Dorothy Gale
const age = minion.age(); // 16
What just happened?
- We added two API field methods to the classOMat.
- These fields access elements of the newBaseClass._params object.
- Since we used no other parameters for the api fields except for their name, the default Getter/Setter hybrid method was used ( there are many parameter methods available ). The default Getter/Setter methods does:
If a parameter is passed, the method will set a value into the ._params object. So, minion.age(16) did this: : minion._params.age = 16.
- After the parameter is passed, the minion instance is returned to allow for chaining.
If NO parameter is passed the method will get the value from the ._params object. (minion.age() is the same as minion._params.age;
Is this really better than doing it by hand?
If you only wanted to set two parameter methods on a class, and if you knew ahead of time what those parameter methods would be, then this could have been done by hand.
However: You may wish to consider ClassOMat if you want any ONE of the following:
- multiple parameter methods of varying types to add to a class.
- to be able to use the same ( or similar ) sets of parameters for multiple classes without using direct inheritence.
- to dynamically set parameter methods you want to attach to a Class.
- to be able to easily set validations to your parameters.
- to be able to adapt itself in midstream.
- to be able to adapt other classes in midstream.
- an easy way to generate a chainable syntax.
- an easy way to generate child classes without worrying about infinite recursions.
What would the above have looked like if it was done manually?
This:
import ClassOMat from 'class-o-mat';
const classOMat = new ClassOMat('top');
class BaseClass {};
classOMat.BaseClass(BaseClass).field('name').field('age');
const MinionClass = classOMat.$();
const minion = new MinionClass().name('Dorothy Gale').age(16);
const name = minion.name(); // Dorothy Gale
const age = minion.age(); // 16
Could have been This;
const NONE = Symbol('NONE');
class BaseClass {
constructor() {
this._params = {};
}
name(name=NONE) {
if (name === NONE) return this._params.name;
this._params.name = name;
return this;
}
age(age=NONE) {
if (age === NONE) return this._params.age;
this._params.age = age;
return this;
}
}
const minion = new BaseClass();
minion.name('Dorothy Gale').age(16);
const name = minion.name(); // Dorothy Gale;
const age = minion.age(); 16
In particular, note how setting up two Getter/Setter param methods goes from ~10-13 lines of code ( depending upon your style ) to 1 line
ClassOMat specifying two Getter Setter fields:
classOMat.field('name').field('age);
Standard Class code specifying same fields:
....
name(name=NONE) {
if (name === NONE) return this._params.name;
this._params.name = name;
return this;
}
age(age=NONE) {
if (age === NONE) return this._params.age;
this._params.age = age;
return this;
}
If you wanted to set 6 Getter/Setter fields:
ClassOMat:
classOMat.field('name').field('age').field('gender').field('eyeColor').field('height').field('weight');
// OR... if you wanted to break it up a bit....
classOMat.field('name').field('age').field('gender');
classOMat.field('eyeColor').field('height').field('weight');
More Examples Coming Soon...
## ClassOMat Reference:
Table of Contents:
- ClassOMat:
- Field Methods:
- API Field Methods (docs coming soon):
- API Method Methods (docs coming soon):
- Nesting ( addChild ) Methods:
- Types of Parameter Accessor Functions:
ClassOMat Methods
$(): The executor function. Use this to create a class from the ClassOMat instance.
const classOMat = new ClassOMat('classOMat');
class BaseMinionClass {}
classOMat.BaseClass(BaseMinionClass).field('name').$();
const MinionClass = classOMat.$();
const minionInstance = new MinionClass();
BaseClass: Sets the BaseClass that ClassOMat will modify into a new generated class.
class BaseClass {}
classOMat.BaseClass(BaseClass);
field: Specify a field. Once this is called, use the field methods listed below
const fieldOMat = classOMat.field([name of field]);
clone: Create a clone of this ClassOMat.
subOMat: Create a clone of this ClassOMat that can be modified without affecting the original.
class BaseClass {}
const classOMat = new ClassOMat('COM');
classOMat.field('name').field('age');
const subClassOMat = classOMat.subOMat('SUBCOM');
subClassOMat.field('gender');
const Minion = classOMat.$();
const minion = new Minion();
minion.name('Clara').age(24); // OK.. sets name and age.
minion.gender('female'); // throws error because gender is not specified as a method.
const SubMinion = subClassOMat.$();
const subMinion = new SubMinion();
subMinion.name('Pete').age(31); // OK sets name and age.
subMinion.gender('male'); // OK sets gender.
Field Methods
Setting a parameter access type: Multiple methods are available and outlined in the Parameter Accessor Functions section.
default: Sets a default value for a parameter.
classOMat.field('name').default('Ralphy');
const minion = new (classOMat.$())();
minion.name(); // Ralphy;
field: Attaches a new field to the parent classOMat. Proxies classOmat.field.
classOMat.field('name').field('age');
// same as :
classOMat.field('name');
classOMat.field('age');
internalKey: allows a field to set a parameter with a different name than the name of the field.
classOMat.field('name').field('who').internalKey('name');
const minion = new (classOMat.$())();
minion.name('Sylvie Vartan'); // same as minion._params.name = 'Sylvie Vartan';
minion.name(); // 'Sylvie Vartian'
minion.who('Roy'); // same as minion._params.name = 'Roy';
minion.name(); // 'Roy'
minion.who(); // 'Roy'
key: getterSetter for the classOMat name of this field.. The key is auomatically set with classOMat.field([key])
const field = classOMat.field('name');
field.key(); // name;
field.key('who');
field.key(); // who;
required: specifies that this field MUST be set. ( further testing needed )
const field = classOMat.field('name').required();
addChild: This command creates an instance of a childAdder with its own params... Proxies the same method in the classOMat.
classOMat.field('name').addChild()....
// same as :
classOMat.field('name');
classOMat.addChild()...
again: creates a clone of this field.
// THIS
classOMat.field('name').validate().string().$().again('title').$();
// IS THE SAME AS
classOMat.field('name').validate().string().$()
.field('title').validate().string().$();
validate sets up a validator for the field. This command creates an instance of a field validator. After you finish specifying the validator, you must use the .$() command. This will return the field that called the validator in the continuation. Click here to see all validator methods
classOMat.field('name').validate().string().$();
Parameter Accessor Types:
getter: A read-only function:
classOMat.field('name').getter().default('The Doctor');
const minion = new (classOMat.$())();
minion.name(); // The Doctor
minion.name('Sam'); // The Doctor ( does not set anything )
setter: A write-only function:
classOMat.field('name').setter().default('The Doctor');
const minion = new (classOMat.$())();
minion.name(); // sets name = null and returns minion.
minion.name('Sam'); // sets name = Sam and returns minion.
getterSetter: Default field type. If no argument, retruns the value, if an argument sets the value and returns the instance for chaining.
classOMat.field('name').getterSetter().default('The Doctor');
// OR
classOMat.field('name').default('The Doctor');
const minion = new (classOMat.$())();
minion.name(); // returns 'The Doctor'
minion.name('Sam'); // sets name = Sam and returns minion.
swapper: If no argument is passed, gets the value of the field. If an argument is passed in, sets a new value to the field and returns the existing one.
classOMat.field('name').swapper().default('Kelly Johnson');
const minion = new (classOMat.$())();
minion.name(); // returns 'Kelly Johnson'
minion.name('Sam'); // sets name and returns 'Kelly Johnson'
toggler: Switches between two Boolean arguments and returns the minion
classOMat.field('isCool').toggler().default(false);
const minion = new (classOMat.$())();
minion.isCool(); // sets isCool = true and returns the minion.
queue: Simulates a Queue with an array in the minion._params:
note: this can also be done in the same way the Stack is represented below:
classOMat.field('ages').queue().$(); // Must use $() after specifying a queue
const minion = new (classOMat.$())();
minion.queue().add(10).add(20).add(30);
const values = minion.queue().values(); // [30, 20, 10];
const first = minion.queue().next(); // 10;
const remainingValues = minion.queue().values(); // [30, 20];
stack: Simulates a Stack with an array in the minion._params;
note: this can also be done in the same way the Queue is represented below:
classOMat.field('ages').stack().$(); // Must use $() after specifying a queue
const minion = new (classOMat.$())();
const stack = minion.stack();
stack.add(10).add(20).add(30);
const values = stack.values(); // [10, 20, 30];
const first = stack.next(); // 30;
const remainingValues = stack.values(); // [10, 20];
Validator Methods:
A validator can contain multiple validations chained using AND or OR logic. By default, chaining validations in a validator is assumed to be by AND logic.
ARBITRARY FUNCTION
with: Validates with the passed in function. Also will warn if the value passed in is NOT a function.
const testIsSquare =(dimensions)=>dimensions.width === dimensions.height;
classOMat.field('isSquare').validate().with( testIsSquare ).$()
withFunction: Same as with but will not warn if an improper function is passed in.
TYPES
bool: Boolean. classOMat.field('isAuthorized').validate().bool().$()
int: Integer classOMat.field('age').validate().int().$()
method: Method only
classOMat.field('test').validate().method().$()
const minion = new (classOMat.$())();
minion.test( ()=>true );
number: Number classOMat.field('price').validate().number().$()
string: String classOMat.field('name').validate().string().$()
EQUALITY & RANGES
equal: Same as value===comparatorclassOMat.field('age').validate().equal(21).$()
equalish: Same as value == comparatorclassOMat.field('age').validate().equalish('21').$()
greaterThan: classOMat.field('age').validate().greaterThan(21).$()
gt: also greaterThan
greaterThanOrEqual:classOMat.field('age').validate().greaterThanOrEqual(21).$()
gte: also greaterThanOrEqual
lessThan: classOMat.field('age').validate().lessThan(10).$()
lt: also lessThan
lessThanOrEqual:classOMat.field('age').validate().lessThanOrEqual(10).$()
lte: also lessThanOrEqual
MULTIPLE CHOICE:
selectList: Must be one of the list.classOMat.field('authLevel').validate().selectList(['admin', 'author', 'reader']).$()
CHAINING LOGIC
and: This is the default logic but can still be written out for explicitness.
classOMat.field('name').validate().string().and().gte('a').$();
// since this is default setting: could also be:
classOMat.field('name').validate().string().gte('a').$();
or:
classOMat.field('name').validate().equal('Frank').or('Bill').$();
INVALID PARAMETER HANDLING:
message: The message to throw or warn with.classOMat.field('name').validate().string().message('Very Bad Name Parameter').$()
warn: Will only warn instead of throwing an error. Default is to throw an error.classOMat.field('name').validate().string().message('Very Bad').warn().$()
Nesting (addChild) methods.
Using addChild will expose the ChildAdder API. This allows a minion to create a child minion. A child minion can be an instance of another classOMat ( and associated base class ) OR another minion created by the parent classOMat:
The following example should be seen only as pseudo code until further testing is done.
This is a pretend example of how one might go about setting up a BTree using ClassOMat. Clearly more code would need to be placed in the classes, but here it is.
After an addChild sequence, you must use the $() operator OR the as$() convenience function
class BaseBTree {}
class BaseBTreeNode {}
const nodeOMat = new ClassOMat('BTreeNode');
nodeOMat.BaseClass(BaseBTreeNode)
.field('values').stack().validate().string().$()
.addChild().as('spawn').$();
const bTreeOMat = new ClassOMat('BTree');
bTreeOMat.BaseClass(BaseBTree)
.field('name').validate().string().$()
.addChild(nodeOMat).as$('start');
const BTree = bTreeOMat.$();
const bTree = new BTree();
const bTreeNode = bTree.start();
const stillBTree = bTreeNode.___parent();
const stillBTreeNode = bTree.___child('start');
const anotherBTreeNode = bTree.start();
const bTreeNodes = bTree.___child('start'); // array of the nodes.
comments on relevant parts:
Set up the ClassOMat for the node class.
const nodeOMat = new ClassOMat('BTreeNode');
nodeOMat.BaseClass(BaseBTreeNode);
Allow the BTreeNode to create a child BTreeNode by using the 'spawn' command. Leaving the addChild parameter blank, specifies that the child is an instance of the same class.
nodeOMat.addChild().as('spawn');
Allow the BTree no create a child BTreeNode by using the 'start' command.
bTreeOMat.addChild(nodeOMat).as$('start');
To create the minion classes, run $() on the top level ClassOMat. the child minion classes will automatically be created and nested within the top level instances.
const BTree = bTreeOMat.$();
const bTree = new BTree;
// the BTreeNode class is embedded within bTree
// and will be instantiated using the appropriate
// bTree.start() command.
To get a child created by a parent minion:
const bTreeNode = bTree.start();
const sameBTreeNode = bTree.___child('start');
To get a parent minion:
const theParentBTree = bTreeNode.___parent();
ApiField Methods:
Api Fields allow a minion to add new fields to itself AFTER it is instantiated:
class BaseMinion {}
const classOMat = new ClassOMat('COM');
classOMat.BaseClass(BaseMinion);
// set apiField, which is similar to the way you set a field...
classOMat.apiField('title').validate().string().$().$();
const Minion = classOMat.$();
const minion = new Minion();
// create the method jobTitle that follows
// the validation ruls of the apiField.
minion.title().as('jobTitle').$();
minion.title().as('bookTitle').$();
// now you can do this.
minion.jobTitle('Supervisor');
minion.bookTitle('Fathers and Sons');
minion.jobTitle(); // Supervisor;
minion.bookTitle(); // Fathers and Sons
ApiMethod Methods ( UNTESTED):
ApiMethods allow a minion instance to add an arbitrary function:
class BaseMinion {}
const classOMat = new ClassOMat('COM');
classOMat.BaseClass(BaseMinion);
function randomFunction() {
console.log(' Here is a random function! ');
}
classOMat.apiMethod('addFunction').$();
const Minion = classOMat.$();
const minion = new Minion();
minion.addFunction(randomFunction);
minion.randomFunction() // logs 'Here is a random function!'
Release Notes:
Version 0.3.4 Alpha
All tests currently pass, and some elements of this code are being tested in the creation of the Aenea Database as well as in the tests in this repo.
Currently 3/43 tests are failing all in the parameter validation sections. This will be resolved in next published version
This version has UNTESTED start of adding apiMethod feature. This feature will allow arbitrary methods to be added to a class on the fly as parameters are now added using the apiField feature.
UNTESTED bool parameter validator
This version also corrects many
Version 0.2.0 Alpha
Adds two new field types, queues and stacks.
Adds validators
Adds apiFields
Version 0.1.2 Alpha
Switches addChild to use more standard continuation format rather than multiple arguments. Adds internalKey to addChild.