@code-o-mat/globals
Version:
Abstract Package to support CodeOMat series of apps.
227 lines (189 loc) • 6.13 kB
JavaScript
import curry from 'curry';
import { NONE } from 'o-mat-globals/globals/values';
import { CODE_O_MAT, METHOD_O_MAT } from 'o-mat-globals/globals/types';
import { REDUCE, STACK } from 'o-mat-globals/globals/methods';
import { assertIsFunction, assertIsObject } from 'o-mat-globals/globals/assertions';
const COMBINE = Symbol('COMBINE');
const SET_COMBINE_MODE = Symbol('SET_COMBINE_MODE');
class MethodOMat {
static APP_FAMILY = O_MAT;
static TYPE = METHOD_O_MAT;
APP_FAMILY = O_MAT;
TYPE = METHOD_O_MAT;
constructor(name='lambda', method=NONE) {
this._props = {
name,
bindToObject: NONE,
doAppend: true,
combineMode: STACK,
returns: false,
method: NONE,
invalidMethod: `Invalid Method at MethodOMat ${name}`,
}
this.method(method);
}
build() {
return this.method();
}
/**
* binds the method to an object.
* @param {Object} bindToObject
* @return {MethodOMat} self for continuation
*/
bind(bindToObject = NONE) {
assertIsObject(bindToObject, this._props.invalidBindObject);
this._props.bindToObject = bindToObject;
return this;
}
curry(doAppend, method, newMethod) {
return this.method(
curry(this.method())
);
}
/**
* Puts MethodOMat into the reduce mode for building the function.
* If a method is passed in, it will combine that method into the
* existing function using append mode.
* @param {function} newMethod
* @return {MethodOMat} self for continuation
*/
append(newMethod = NONE) {
this._props.doAppend = true;
return newMethod === NONE ? this : this._combine(newMethod);
}
/**
* Puts MethodOMat into the prepend mode for building the function.
* If a method is passed in, it will combine that method into the
* existing function using prepend mode.
* @param {function} newMethod
* @return {MethodOMat} self for continuation
*/
prepend(newMethod = NONE) {
this._props.doAppend = false;
return newMethod === NONE ? this : this._combine(newMethod);
}
/**
* Puts MethodOMat into the reduce mode for building the function.
* If a method is passed in, it will combine that method into the
* existing function using reduce mode.
* @param {function} newMethod
* @return {MethodOMat} self for continuation
*/
reduce(newMethod = NONE) {
return this[SET_COMBINE_MODE](REDUCE, newMethod);
}
/**
* puts MethodOMat into the stack mode for building the function.
* This will simply run all the functions in sequence without
* dealing with any return values.
* @param {[type]} newMethod [description]
* @return {[type]} [description]
*/
stack(newMethod = NONE) {
return this[SET_COMBINE_MODE](STACK, newMethod);
}
/**
* puts MethodOMat into the stackWithReturns mode.
* This will run all the functions in sequence and will
* collect their return values in an array in order in which
* the component functions were run.
* @param {[type]} newMethod [description]
* @return {[type]} [description]
*/
stackWithReturns(newMethod = NONE) {
return this[SET_COMBINE_MODE](STACK_WITH_RETURNS, newMethod);
}
/**
* getter or setter for the current method. Will overwrite
* any previous method.
* @param {function | NONE} method
* @returns {function | MethodOMat} either the function to be
* build or the current methodOMat
*/
method(method = NONE) {
if (method === NONE) {
return this._props.method.bind(this._props.bindToObject)
}
assertIsFunction(method, this._props.invalidMethod);
this._props.method = method;
return this;
}
/**
* combines a function to the existing function.
* @private
* @param {function} newMethod the new method
* to be combined to the existing one.
* @return {MethodOMat} self for continuation.
*/
[COMBINE](newMethod) {
assertIsFunction(newMethod, this._props.invalidMethod);
const { doAppend, doReduce, method } = this._props;
return doReduce === true
? this._reduce(doAppend, method, newMethod)
: this._curry(doAppend, method, newMethod);
}
[SET_COMBINE_MODE](mode, newMethod) {
this._props.combineMode = mode;
return newMethod === NONE ? this : this[COMBINE](newMethod);
}
/**
* combines a function to the existing function
* using the reduce method.
* @private
* @param {Boolean} doAppend
* @param {function} method
* @param {function} newMethod
* @return {MethodOMat} self for continuation.
*/
[REDUCE](doAppend, method, newMethod) {
return this.method(
doAppend === true
? function(...p) { return newMethod(method(...p))}
: function(...p) { return method(newMethod(...p))}
);
}
[REDUCE_WITH_RETURNS](doAppend, method, newMethod) {
return this.method(
doAppend === true
? function(...p) {
const rts = [];
rts = rts.concat(method(...p));
return rts.concat(newMethod(rts.slice(-1), rts));
}
: function(...p) {
const rts = [];
rts = rts.concat(newMethod(...p));
return rts.concat(method(rts.slice(-1), rts));
}
);
}
[STACK](doAppend, method, newMethod) {
return this.method(
doAppend === true
? function(...p) {
method(...p);
return newMethod(...p);
}
: function(...p) {
newMethod(...p);
return method(...p);
}
);
}
[STACK_WITH_RETURNS](doAppend, method, newMethod) {
return this.method(
doAppend === true
? function(...p) {
const rts = [];
rts = rts.concat(method(...p));
return rts.concat(newMethod(...p));
}
: function(...p) {
const rts = [];
rts = rts.concat(newMethod(...p));
return rts.concat(method(...p));
}
);
}
}
export default MethodOMat;