Files
biomedjs/node_modules/mongoose/lib/statemachine.js

179 lines
4.3 KiB
JavaScript
Raw Permalink Normal View History

2014-09-14 07:04:16 -04:00
/*!
* Module dependencies.
*/
var utils = require('./utils');
/*!
* StateMachine represents a minimal `interface` for the
* constructors it builds via StateMachine.ctor(...).
*
* @api private
*/
2015-11-24 22:08:58 -08:00
var StateMachine = module.exports = exports = function StateMachine() {
};
2014-09-14 07:04:16 -04:00
/*!
* StateMachine.ctor('state1', 'state2', ...)
* A factory method for subclassing StateMachine.
* The arguments are a list of states. For each state,
* the constructor's prototype gets state transition
* methods named after each state. These transition methods
* place their path argument into the given state.
*
* @param {String} state
* @param {String} [state]
* @return {Function} subclass constructor
* @private
*/
2015-11-24 22:08:58 -08:00
StateMachine.ctor = function() {
2014-09-14 07:04:16 -04:00
var states = utils.args(arguments);
2015-11-24 22:08:58 -08:00
var ctor = function() {
2014-09-14 07:04:16 -04:00
StateMachine.apply(this, arguments);
2015-11-24 22:08:58 -08:00
this.paths = {};
this.states = {};
2014-09-14 07:04:16 -04:00
this.stateNames = states;
2015-11-24 22:08:58 -08:00
var i = states.length,
state;
2014-09-14 07:04:16 -04:00
while (i--) {
state = states[i];
this.states[state] = {};
}
};
2015-11-24 22:08:58 -08:00
ctor.prototype = new StateMachine();
2014-09-14 07:04:16 -04:00
2015-11-24 22:08:58 -08:00
states.forEach(function(state) {
2014-09-14 07:04:16 -04:00
// Changes the `path`'s state to `state`.
2015-11-24 22:08:58 -08:00
ctor.prototype[state] = function(path) {
2014-09-14 07:04:16 -04:00
this._changeState(path, state);
2015-11-24 22:08:58 -08:00
};
2014-09-14 07:04:16 -04:00
});
return ctor;
};
/*!
* This function is wrapped by the state change functions:
*
* - `require(path)`
* - `modify(path)`
* - `init(path)`
*
* @api private
*/
2015-11-24 22:08:58 -08:00
StateMachine.prototype._changeState = function _changeState(path, nextState) {
2014-09-14 07:04:16 -04:00
var prevBucket = this.states[this.paths[path]];
if (prevBucket) delete prevBucket[path];
this.paths[path] = nextState;
this.states[nextState][path] = true;
2015-11-24 22:08:58 -08:00
};
2014-09-14 07:04:16 -04:00
/*!
* ignore
*/
2015-11-24 22:08:58 -08:00
StateMachine.prototype.clear = function clear(state) {
var keys = Object.keys(this.states[state]),
i = keys.length,
path;
2014-09-14 07:04:16 -04:00
while (i--) {
path = keys[i];
delete this.states[state][path];
delete this.paths[path];
}
2015-11-24 22:08:58 -08:00
};
2014-09-14 07:04:16 -04:00
/*!
* Checks to see if at least one path is in the states passed in via `arguments`
* e.g., this.some('required', 'inited')
*
* @param {String} state that we want to check for.
* @private
*/
2015-11-24 22:08:58 -08:00
StateMachine.prototype.some = function some() {
2014-09-14 07:04:16 -04:00
var self = this;
var what = arguments.length ? arguments : this.stateNames;
2015-11-24 22:08:58 -08:00
return Array.prototype.some.call(what, function(state) {
2014-09-14 07:04:16 -04:00
return Object.keys(self.states[state]).length;
});
2015-11-24 22:08:58 -08:00
};
2014-09-14 07:04:16 -04:00
/*!
* This function builds the functions that get assigned to `forEach` and `map`,
* since both of those methods share a lot of the same logic.
*
* @param {String} iterMethod is either 'forEach' or 'map'
* @return {Function}
* @api private
*/
2015-11-24 22:08:58 -08:00
StateMachine.prototype._iter = function _iter(iterMethod) {
return function() {
var numArgs = arguments.length,
states = utils.args(arguments, 0, numArgs - 1),
callback = arguments[numArgs - 1];
2014-09-14 07:04:16 -04:00
if (!states.length) states = this.stateNames;
var self = this;
2015-11-24 22:08:58 -08:00
var paths = states.reduce(function(paths, state) {
2014-09-14 07:04:16 -04:00
return paths.concat(Object.keys(self.states[state]));
}, []);
2015-11-24 22:08:58 -08:00
return paths[iterMethod](function(path, i, paths) {
2014-09-14 07:04:16 -04:00
return callback(path, i, paths);
});
};
2015-11-24 22:08:58 -08:00
};
2014-09-14 07:04:16 -04:00
/*!
* Iterates over the paths that belong to one of the parameter states.
*
* The function profile can look like:
* this.forEach(state1, fn); // iterates over all paths in state1
* this.forEach(state1, state2, fn); // iterates over all paths in state1 or state2
* this.forEach(fn); // iterates over all paths in all states
*
* @param {String} [state]
* @param {String} [state]
* @param {Function} callback
* @private
*/
2015-11-24 22:08:58 -08:00
StateMachine.prototype.forEach = function forEach() {
2014-09-14 07:04:16 -04:00
this.forEach = this._iter('forEach');
return this.forEach.apply(this, arguments);
2015-11-24 22:08:58 -08:00
};
2014-09-14 07:04:16 -04:00
/*!
* Maps over the paths that belong to one of the parameter states.
*
* The function profile can look like:
* this.forEach(state1, fn); // iterates over all paths in state1
* this.forEach(state1, state2, fn); // iterates over all paths in state1 or state2
* this.forEach(fn); // iterates over all paths in all states
*
* @param {String} [state]
* @param {String} [state]
* @param {Function} callback
* @return {Array}
* @private
*/
2015-11-24 22:08:58 -08:00
StateMachine.prototype.map = function map() {
2014-09-14 07:04:16 -04:00
this.map = this._iter('map');
return this.map.apply(this, arguments);
2015-11-24 22:08:58 -08:00
};