<commit_before>/**
 * Module dependencies.
 */
var express = require('express')
  , path = require('path')
  , fs = require('fs')
  , diveSync = require('diveSync')
  , util = require('util')
  , utils = require('./utils')
  , Router = require('./router')
  , Controller = require('./controller')
  , debug = require('debug')('locomotive');


/**
 * `Locomotive` constructor.
 *
 * A default `Locomotive` singleton is exported via the module.  Applications
 * should not need to construct additional instances, and are advised against
 * doing so.
 *
 * @api public
 */
function Locomotive() {
  this._routes = new Router(this);
  this._controllers = {};
  this._helpers = {};
  this._dynamicHelpers = {};
  this._datastores = [];
};

/**
 * Register `controller` with given `name`, or return `name`'s controller. 
 *
 * @param {String} name
 * @param {Controller} controller
 * @return {Controller|Locomotive} for chaining, or the controller
 * @api public
 */
Locomotive.prototype.controller = function(name, controller) {
  name = utils.controllerize(name);
  // record the controller in an internal hash.
  if (controller) {
    controller._load(this, name);
    this._controllers[name] = controller;
    return this;
  }
  return this._controllers[name];
}

/**
 * Register helper function(s).
 *
 * Helper functions can be registered by passing an object as an argument, in
 * which case each function of that object will be registered as a helper.  As
 * a convienience, if the object contains a property named `dynamic`, each
 * function attached to that property will be registered as a dynamic helper.
 *
 * Helper functions can also be registered by passing a `name`, which `fn` will
 * be registered as.
 *
 * @param {String|Object} obj
 * @param {Function} fn
 * @api public
 */
Locomotive.prototype.helper =
Locomotive.prototype.helpers = function(name, fn) {
  var helpers = name;
  if (fn) {
    helpers = {};
    helpers[name] = fn;
  }
  
  for (var key in helpers) {
    if (key === 'dynamic') {
      this.dynamicHelpers(helpers[key]);
    } else {
      this._helpers[key] = helpers[key];
    }
  }
  return this;
}

/**
 * Register dynamic helper function(s).
 *
 * Helper functions can be registered by passing an object as an argument, in
 * which case each function of that object will be registered as a helper.
 *
 * Helper functions can also be registered by passing a `name`, which `fn` will
 * be registered as.
 *
 * @param {String|Object} obj
 * @param {Function} fn
 * @api public
 */
Locomotive.prototype.dynamicHelper =
Locomotive.prototype.dynamicHelpers = function(name, fn) {
  var helpers = name;
  if (fn) {
    helpers = {};
    helpers[name] = fn;
  }
  
  for (var key in helpers) {
    this._dynamicHelpers[key] = helpers[key];
  }
  return this;
}

/**
 * Register datastore `store`.
 *
 * To facilitate mapping models to controllers, Locomotive introspects models
 * in order to determine their type.  By default, the constructor name is used;
 * for example, an instance of `Song` maps to `SongsController`.  However, most
 * datastores have APIs that don't conform to this (admittedly, rather
 * simplistic) heuristic.  To accomodate such datastores, adapters can and
 * should be registered with Locomotive to provide the necessary introspection
 * logic.
 *
 * @param {Module} store
 * @api public
 */
Locomotive.prototype.datastore = function(store) {
  this._datastores.push(store);
}

/**
 * Returns a string indicating the type of record of `obj`.
 * 
 * @param {Object} obj
 * @return {String}
 * @api protected
 */
Locomotive.prototype._recordOf = function(obj) {
  for (var i = 0, len = this._datastores.length; i < len; i++) {
    var ds = this._datastores[i];
    var kind = ds.recordOf(obj);
    if (kind) { return kind; }
  }
  return undefined;
}


/**
 * Boot `Locomotive` application.
 *
 * @param {String} dir
 * @param {String} env
 * @param {Function} callback
 * @api public
 */
Locomotive.prototype.boot = function(dir, env, callback) {
  var self = this;
  var entry;
  
  var server = express.createServer();
  this._routes.init(server);
  
  // Forward function calls from Locomotive to Express.
  utils.forward(this, server, [ 'set', 'enabled', 'disabled', 'enable', 'disable',
                                'use', 'register' ]);
  this.router = server.router;
  
  
  // TODO: Should set('env', env) here on the underlying Express server
  
  // Register helpers.
  this.helpers(require('./helpers'));
  this.dynamicHelpers(require('./helpers/dynamic'));
  
  var configDir = dir + '/config';
  
  // Require initializers.
  entry = configDir + '/initializers';
  if (path.existsSync(entry)) {
    // NOTE: Sorting is required, due to the fact that no order is guaranteed
    //       by the system for a directory listing.  Sorting allows initializers
    //       to be prefixed with a number, and loaded in a pre-determined order.
    fs.readdirSync(entry).sort().forEach(function(filename) {
      if (/\.js$/.test(filename)) {
        debug('requiring initializer: %s', filename);
        require(entry + '/' + filename);
      }
    });
  }
  
  // Apply configuration for all environments.
  entry = configDir + '/environments/all.js';
  if (path.existsSync(entry)) {
    debug('configuring environment: %s', 'all');
    require(entry).apply(this);
  }
  // Apply configuration for current environment.
  entry = configDir + '/environments/' + env + '.js';
  if (path.existsSync(entry)) {
    debug('configuring environment: %s', env);
    require(entry).apply(this);
  }
  
  // Register fallback datastore.  Environments will have registered preferred
  // datastores ahead of this one.
  this.datastore(require('./datastores/object'));
  
  // Draw routes.
  var routesPath = configDir + '/routes.js';
  if (path.existsSync(routesPath)) {
    debug('drawing routes')
    this._routes.draw(require(routesPath));
  }
  
  var appDir = dir + '/app';
  
  // Auto-load controllers.
  entry = appDir + '/controllers';
  if (path.existsSync(entry)) {
    diveSync(entry, function (err, path) {
      if (/\.js$/.test(path)) {
        var name = path.slice(entry.length + 1).replace(/\.js$/, '');
        debug('registering controller: %s', name)
        self.controller(name, require(path));
      }
    });
  }
  
  callback(null, server);
}


/**
 * Export default singleton.
 *
 * @api public
 */
exports = module.exports = new Locomotive();

/**
 * Framework version.
 */
require('pkginfo')(module, 'version');

/**
 * Expose constructors.
 */
exports.Locomotive = Locomotive;
exports.Controller = Controller;

/**
 * Expose CLI.
 *
 * @api private
 */
exports.cli = require('./cli');
<commit_msg>Set env on boot.<commit_after>/**
 * Module dependencies.
 */
var express = require('express')
  , path = require('path')
  , fs = require('fs')
  , diveSync = require('diveSync')
  , util = require('util')
  , utils = require('./utils')
  , Router = require('./router')
  , Controller = require('./controller')
  , debug = require('debug')('locomotive');


/**
 * `Locomotive` constructor.
 *
 * A default `Locomotive` singleton is exported via the module.  Applications
 * should not need to construct additional instances, and are advised against
 * doing so.
 *
 * @api public
 */
function Locomotive() {
  this._routes = new Router(this);
  this._controllers = {};
  this._helpers = {};
  this._dynamicHelpers = {};
  this._datastores = [];
};

/**
 * Register `controller` with given `name`, or return `name`'s controller. 
 *
 * @param {String} name
 * @param {Controller} controller
 * @return {Controller|Locomotive} for chaining, or the controller
 * @api public
 */
Locomotive.prototype.controller = function(name, controller) {
  name = utils.controllerize(name);
  // record the controller in an internal hash.
  if (controller) {
    controller._load(this, name);
    this._controllers[name] = controller;
    return this;
  }
  return this._controllers[name];
}

/**
 * Register helper function(s).
 *
 * Helper functions can be registered by passing an object as an argument, in
 * which case each function of that object will be registered as a helper.  As
 * a convienience, if the object contains a property named `dynamic`, each
 * function attached to that property will be registered as a dynamic helper.
 *
 * Helper functions can also be registered by passing a `name`, which `fn` will
 * be registered as.
 *
 * @param {String|Object} obj
 * @param {Function} fn
 * @api public
 */
Locomotive.prototype.helper =
Locomotive.prototype.helpers = function(name, fn) {
  var helpers = name;
  if (fn) {
    helpers = {};
    helpers[name] = fn;
  }
  
  for (var key in helpers) {
    if (key === 'dynamic') {
      this.dynamicHelpers(helpers[key]);
    } else {
      this._helpers[key] = helpers[key];
    }
  }
  return this;
}

/**
 * Register dynamic helper function(s).
 *
 * Helper functions can be registered by passing an object as an argument, in
 * which case each function of that object will be registered as a helper.
 *
 * Helper functions can also be registered by passing a `name`, which `fn` will
 * be registered as.
 *
 * @param {String|Object} obj
 * @param {Function} fn
 * @api public
 */
Locomotive.prototype.dynamicHelper =
Locomotive.prototype.dynamicHelpers = function(name, fn) {
  var helpers = name;
  if (fn) {
    helpers = {};
    helpers[name] = fn;
  }
  
  for (var key in helpers) {
    this._dynamicHelpers[key] = helpers[key];
  }
  return this;
}

/**
 * Register datastore `store`.
 *
 * To facilitate mapping models to controllers, Locomotive introspects models
 * in order to determine their type.  By default, the constructor name is used;
 * for example, an instance of `Song` maps to `SongsController`.  However, most
 * datastores have APIs that don't conform to this (admittedly, rather
 * simplistic) heuristic.  To accomodate such datastores, adapters can and
 * should be registered with Locomotive to provide the necessary introspection
 * logic.
 *
 * @param {Module} store
 * @api public
 */
Locomotive.prototype.datastore = function(store) {
  this._datastores.push(store);
}

/**
 * Returns a string indicating the type of record of `obj`.
 * 
 * @param {Object} obj
 * @return {String}
 * @api protected
 */
Locomotive.prototype._recordOf = function(obj) {
  for (var i = 0, len = this._datastores.length; i < len; i++) {
    var ds = this._datastores[i];
    var kind = ds.recordOf(obj);
    if (kind) { return kind; }
  }
  return undefined;
}


/**
 * Boot `Locomotive` application.
 *
 * @param {String} dir
 * @param {String} env
 * @param {Function} callback
 * @api public
 */
Locomotive.prototype.boot = function(dir, env, callback) {
  var self = this
    , server = express.createServer()
    , entry;
  
  this._routes.init(server);
  
  // Forward function calls from Locomotive to Express.  This allows Locomotive
  // to be used interchangably with Express.
  utils.forward(this, server, [ 'set', 'enabled', 'disabled', 'enable', 'disable',
                                'use', 'register' ]);
  this.router = server.router;
  
  // Set the environment.  This syncs Express with the environment supplied to
  // the Locomotive CLI.
  this.set('env', env);
  
  var configDir = dir + '/config';
  
  // Require initializers.
  entry = configDir + '/initializers';
  if (path.existsSync(entry)) {
    // NOTE: Sorting is required, due to the fact that no order is guaranteed
    //       by the system for a directory listing.  Sorting allows initializers
    //       to be prefixed with a number, and loaded in a pre-determined order.
    fs.readdirSync(entry).sort().forEach(function(filename) {
      if (/\.js$/.test(filename)) {
        debug('requiring initializer: %s', filename);
        require(entry + '/' + filename);
      }
    });
  }
  
  // Register helpers.
  this.helpers(require('./helpers'));
  this.dynamicHelpers(require('./helpers/dynamic'));
  
  // Apply configuration for all environments.
  entry = configDir + '/environments/all.js';
  if (path.existsSync(entry)) {
    debug('configuring environment: %s', 'all');
    require(entry).apply(this);
  }
  // Apply configuration for current environment.
  entry = configDir + '/environments/' + env + '.js';
  if (path.existsSync(entry)) {
    debug('configuring environment: %s', env);
    require(entry).apply(this);
  }
  
  // Register fallback datastore.  Environments will have registered preferred
  // datastores ahead of this one.
  this.datastore(require('./datastores/object'));
  
  // Draw routes.
  var routesPath = configDir + '/routes.js';
  if (path.existsSync(routesPath)) {
    debug('drawing routes')
    this._routes.draw(require(routesPath));
  }
  
  var appDir = dir + '/app';
  
  // Auto-load controllers.
  entry = appDir + '/controllers';
  if (path.existsSync(entry)) {
    diveSync(entry, function (err, path) {
      if (/\.js$/.test(path)) {
        var name = path.slice(entry.length + 1).replace(/\.js$/, '');
        debug('registering controller: %s', name)
        self.controller(name, require(path));
      }
    });
  }
  
  callback(null, server);
}


/**
 * Export default singleton.
 *
 * @api public
 */
exports = module.exports = new Locomotive();

/**
 * Framework version.
 */
require('pkginfo')(module, 'version');

/**
 * Expose constructors.
 */
exports.Locomotive = Locomotive;
exports.Controller = Controller;

/**
 * Expose CLI.
 *
 * @api private
 */
exports.cli = require('./cli');

{'fraction_non_alphanumeric': 0.1371153133110864, 'fraction_numerical': 0.00029662588060808305, 'mean_word_length': 3.228911884603324, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2847471', 'n_tokens_mistral': 4119, 'n_tokens_neox': 4101, 'n_words': 1258}