jaredhanson/bootable

View on GitHub
lib/initializer.js

Summary

Maintainability
A
2 hrs
Test Coverage
/**
 * Module dependencies.
 */
var debug = require('debug')('bootable');


/**
 * Creates an instance of `Initializer`.
 *
 * @constructor
 * @api public
 */
function Initializer() {
  this._phases = [];
}

/**
 * Run all phases.
 *
 * When the initializer is run, all phases will be executed sequentially, in
 * the order in which they were registered.  Once complete, `cb` will be
 * invoked.
 *
 * @param {Function} cb
 * @param {Object} [thisArg]
 * @api public
 */
Initializer.prototype.run = function(cb, thisArg) {
  var phases = this._phases
    , idx = 0;
  
  function next(err) {
    if (err) { return cb(err); }
    
    var phase = phases[idx++];
    // all done
    if (!phase) { return cb(); }
    
    try {
      if (typeof phase == 'object') {
        debug('%s', phase.constructor ? phase.constructor.name + '#boot' : 'anonymous#boot');
        phase.boot(next);
      } else {
        debug('%s', phase.name || 'anonymous');
        var arity = phase.length;
        if (arity == 1) {
          phase.call(thisArg, next);
        } else {
          phase.call(thisArg);
          next();
        }
      }
    } catch (ex) {
      next(ex);
    }
  }
  next();
};

/**
 * Register a phase.
 *
 * A phase can be either synchronous or asynchronous.  Synchronous phases have
 * following function signature
 *
 *     function myPhase() {
 *       // perform initialization
 *     }
 *
 * Asynchronous phases have the following function signature.
 *
 *     function myAsyncPhase(done) {
 *       // perform initialization
 *       done();  // or done(err);
 *     }
 *
 * The phase may also be an object that has a `boot` function.  In this case,
 * the object's boot function will be called during the boot sequence.  This is
 * typically used for objects that need to establish a persistent connection,
 * for example to a database or message queue.
 *
 * @param {Function|Object} fn
 * @returns {Initializer} `this`, for a fluent interface.
 * @api public
 */
Initializer.prototype.phase = function(fn) {
  this._phases.push(fn);
  return this;
};


/**
 * Expose `Initializer`.
 */
module.exports = Initializer;