arnaucube
arnaucube/thoughtsPublic Self-hosted repository
thoughts/node_modules/mongoose/lib/statemachine.js
node_modules/mongoose/lib/statemachine.jsRaw
  1
  2/*!
  3 * Module dependencies.
  4 */
  5
  6var utils = require('./utils');
  7
  8/*!
  9 * StateMachine represents a minimal `interface` for the
 10 * constructors it builds via StateMachine.ctor(...).
 11 *
 12 * @api private
 13 */
 14
 15var StateMachine = module.exports = exports = function StateMachine() {
 16};
 17
 18/*!
 19 * StateMachine.ctor('state1', 'state2', ...)
 20 * A factory method for subclassing StateMachine.
 21 * The arguments are a list of states. For each state,
 22 * the constructor's prototype gets state transition
 23 * methods named after each state. These transition methods
 24 * place their path argument into the given state.
 25 *
 26 * @param {String} state
 27 * @param {String} [state]
 28 * @return {Function} subclass constructor
 29 * @private
 30 */
 31
 32StateMachine.ctor = function() {
 33  var states = utils.args(arguments);
 34
 35  var ctor = function() {
 36    StateMachine.apply(this, arguments);
 37    this.paths = {};
 38    this.states = {};
 39    this.stateNames = states;
 40
 41    var i = states.length,
 42        state;
 43
 44    while (i--) {
 45      state = states[i];
 46      this.states[state] = {};
 47    }
 48  };
 49
 50  ctor.prototype = new StateMachine();
 51
 52  states.forEach(function(state) {
 53    // Changes the `path`'s state to `state`.
 54    ctor.prototype[state] = function(path) {
 55      this._changeState(path, state);
 56    };
 57  });
 58
 59  return ctor;
 60};
 61
 62/*!
 63 * This function is wrapped by the state change functions:
 64 *
 65 * - `require(path)`
 66 * - `modify(path)`
 67 * - `init(path)`
 68 *
 69 * @api private
 70 */
 71
 72StateMachine.prototype._changeState = function _changeState(path, nextState) {
 73  var prevBucket = this.states[this.paths[path]];
 74  if (prevBucket) delete prevBucket[path];
 75
 76  this.paths[path] = nextState;
 77  this.states[nextState][path] = true;
 78};
 79
 80/*!
 81 * ignore
 82 */
 83
 84StateMachine.prototype.clear = function clear(state) {
 85  var keys = Object.keys(this.states[state]),
 86      i = keys.length,
 87      path;
 88
 89  while (i--) {
 90    path = keys[i];
 91    delete this.states[state][path];
 92    delete this.paths[path];
 93  }
 94};
 95
 96/*!
 97 * Checks to see if at least one path is in the states passed in via `arguments`
 98 * e.g., this.some('required', 'inited')
 99 *
100 * @param {String} state that we want to check for.
101 * @private
102 */
103
104StateMachine.prototype.some = function some() {
105  var _this = this;
106  var what = arguments.length ? arguments : this.stateNames;
107  return Array.prototype.some.call(what, function(state) {
108    return Object.keys(_this.states[state]).length;
109  });
110};
111
112/*!
113 * This function builds the functions that get assigned to `forEach` and `map`,
114 * since both of those methods share a lot of the same logic.
115 *
116 * @param {String} iterMethod is either 'forEach' or 'map'
117 * @return {Function}
118 * @api private
119 */
120
121StateMachine.prototype._iter = function _iter(iterMethod) {
122  return function() {
123    var numArgs = arguments.length,
124        states = utils.args(arguments, 0, numArgs - 1),
125        callback = arguments[numArgs - 1];
126
127    if (!states.length) states = this.stateNames;
128
129    var _this = this;
130
131    var paths = states.reduce(function(paths, state) {
132      return paths.concat(Object.keys(_this.states[state]));
133    }, []);
134
135    return paths[iterMethod](function(path, i, paths) {
136      return callback(path, i, paths);
137    });
138  };
139};
140
141/*!
142 * Iterates over the paths that belong to one of the parameter states.
143 *
144 * The function profile can look like:
145 * this.forEach(state1, fn);         // iterates over all paths in state1
146 * this.forEach(state1, state2, fn); // iterates over all paths in state1 or state2
147 * this.forEach(fn);                 // iterates over all paths in all states
148 *
149 * @param {String} [state]
150 * @param {String} [state]
151 * @param {Function} callback
152 * @private
153 */
154
155StateMachine.prototype.forEach = function forEach() {
156  this.forEach = this._iter('forEach');
157  return this.forEach.apply(this, arguments);
158};
159
160/*!
161 * Maps over the paths that belong to one of the parameter states.
162 *
163 * The function profile can look like:
164 * this.forEach(state1, fn);         // iterates over all paths in state1
165 * this.forEach(state1, state2, fn); // iterates over all paths in state1 or state2
166 * this.forEach(fn);                 // iterates over all paths in all states
167 *
168 * @param {String} [state]
169 * @param {String} [state]
170 * @param {Function} callback
171 * @return {Array}
172 * @private
173 */
174
175StateMachine.prototype.map = function map() {
176  this.map = this._iter('map');
177  return this.map.apply(this, arguments);
178};