Lodashify

This commit is contained in:
Andrew Stewart 2014-12-17 14:42:34 -08:00
parent 34ed6cea02
commit 6cbf2db122
7 changed files with 140 additions and 184 deletions

View File

@ -9,7 +9,8 @@
"use strict"; "use strict";
var Basestar = require("./basestar"), var Basestar = require("./basestar"),
Utils = require("./utils"); Utils = require("./utils"),
_ = require("./lodash");
// Public: Creates a new Adaptor // Public: Creates a new Adaptor
// //
@ -33,11 +34,13 @@ var Adaptor = module.exports = function Adaptor(opts) {
// misc. details provided in args hash // misc. details provided in args hash
this.details = {}; this.details = {};
for (var opt in opts) { _.forEach(opts, function(opt, name) {
if (["robot", "name", "adaptor"].indexOf(opt) < 0) { if (_.include(["robot", "name", "adaptor"], opt)) {
this.details[opt] = opts[opt]; return;
} }
}
this.details[name] = opt;
}, this);
}; };
Utils.subclass(Adaptor, Basestar); Utils.subclass(Adaptor, Basestar);

View File

@ -9,7 +9,8 @@
"use strict"; "use strict";
var Registry = require("./registry"), var Registry = require("./registry"),
Config = require("./config"); Config = require("./config"),
_ = require("./lodash");
var testMode = function() { var testMode = function() {
return process.env.NODE_ENV === "test" && Config.testMode; return process.env.NODE_ENV === "test" && Config.testMode;
@ -25,8 +26,7 @@ var testMode = function() {
// //
// Returns the newly set-up connection // Returns the newly set-up connection
module.exports = function Connection(opts) { module.exports = function Connection(opts) {
var module, var module;
prop;
opts = opts || {}; opts = opts || {};
@ -43,24 +43,24 @@ module.exports = function Connection(opts) {
var adaptor = module.adaptor(opts); var adaptor = module.adaptor(opts);
for (prop in adaptor) { _.forEach(adaptor, function(prop, name) {
if (~["constructor"].indexOf(prop)) { if (name === "constructor") {
continue; return;
} }
if (typeof adaptor[prop] === "function") { if (_.isFunction(prop)) {
adaptor[prop] = adaptor[prop].bind(adaptor); adaptor[name] = prop.bind(adaptor);
} }
} });
if (testMode()) { if (testMode()) {
var testAdaptor = Registry.findByAdaptor("test").adaptor(opts); var testAdaptor = Registry.findByAdaptor("test").adaptor(opts);
for (prop in adaptor) { _.forEach(adaptor, function(prop, name) {
if (typeof adaptor[prop] === "function" && !testAdaptor[prop]) { if (_.isFunction(prop) && !testAdaptor[name]) {
testAdaptor[prop] = function() { return true; }; testAdaptor[name] = function() { return true; };
} }
} });
return testAdaptor; return testAdaptor;
} }

View File

@ -13,7 +13,8 @@ var Async = require("async");
var Logger = require("./logger"), var Logger = require("./logger"),
Robot = require("./robot"), Robot = require("./robot"),
Config = require("./config"), Config = require("./config"),
Utils = require("./utils"); Utils = require("./utils"),
_ = require("./lodash");
var Cylon = module.exports = { var Cylon = module.exports = {
Logger: Logger, Logger: Logger,
@ -83,17 +84,13 @@ Cylon.api = function api(opts) {
// //
// Returns nothing // Returns nothing
Cylon.start = function start() { Cylon.start = function start() {
var starters = []; var starters = _.map(this.robots, "start");
for (var bot in this.robots) {
starters.push(this.robots[bot].start);
}
Async.parallel(starters, function() { Async.parallel(starters, function() {
var mode = Utils.fetch(Config, "workMode", "async"); var mode = Utils.fetch(Config, "workMode", "async");
if (mode === "sync") { if (mode === "sync") {
for (var bot in this.robots) { _.invoke(this.robots, "startWork");
this.robots[bot].startWork();
}
} }
}.bind(this)); }.bind(this));
}; };
@ -104,15 +101,13 @@ Cylon.start = function start() {
// //
// Returns the current config // Returns the current config
Cylon.config = function(opts) { Cylon.config = function(opts) {
var loggingChanged = (opts.logging && Config.logging !== opts.logging); var logChanges = (opts.logging && !_.isEqual(Config.logging, opts.logging));
if (opts && typeof(opts) === "object" && !Array.isArray(opts)) { if (_.isObject(opts) && !_.isArray(opts)) {
for (var o in opts) { Config = _.merge(Config, opts);
Config[o] = opts[o];
}
} }
if (loggingChanged) { if (logChanges) {
Logger.setup(); Logger.setup();
} }
@ -126,30 +121,20 @@ Cylon.config = function(opts) {
// Returns nothing // Returns nothing
Cylon.halt = function halt(callback) { Cylon.halt = function halt(callback) {
callback = callback || function() {}; callback = callback || function() {};
var fns = _.map(this.robots, "halt");
// if robots can"t shut down quickly enough, forcefully self-terminate // if robots can"t shut down quickly enough, forcefully self-terminate
var timeout = Config.haltTimeout || 3000; var timeout = Config.haltTimeout || 3000;
Utils.after(timeout, callback); Utils.after(timeout, callback);
var fns = [];
for (var bot in this.robots) {
var robot = this.robots[bot];
fns.push(robot.halt.bind(robot));
}
Async.parallel(fns, callback); Async.parallel(fns, callback);
}; };
Cylon.toJSON = function() { Cylon.toJSON = function() {
var robots = [];
for (var bot in this.robots) {
robots.push(this.robots[bot].toJSON());
}
return { return {
robots: robots, robots: _.invoke(this.robots, "toJSON"),
commands: Object.keys(this.commands) commands: _.keys(this.commands)
}; };
}; };

View File

@ -9,7 +9,8 @@
"use strict"; "use strict";
var Registry = require("./registry"), var Registry = require("./registry"),
Config = require("./config"); Config = require("./config"),
_ = require("./lodash");
var testMode = function() { var testMode = function() {
return process.env.NODE_ENV === "test" && Config.testMode; return process.env.NODE_ENV === "test" && Config.testMode;
@ -26,8 +27,7 @@ var testMode = function() {
// //
// Returns a new Device // Returns a new Device
module.exports = function Device(opts) { module.exports = function Device(opts) {
var module, var module;
prop;
if (opts.module) { if (opts.module) {
module = Registry.register(opts.module); module = Registry.register(opts.module);
@ -44,24 +44,24 @@ module.exports = function Device(opts) {
var driver = module.driver(opts); var driver = module.driver(opts);
for (prop in driver) { _.forEach(driver, function(prop, name) {
if (~["constructor"].indexOf(prop)) { if (name === "constructor") {
continue; return;
} }
if (typeof driver[prop] === "function") { if (_.isFunction(prop)) {
driver[prop] = driver[prop].bind(driver); driver[name] = prop.bind(driver);
} }
} });
if (testMode()) { if (testMode()) {
var testDriver = Registry.findByDriver("test").driver(opts); var testDriver = Registry.findByDriver("test").driver(opts);
for (prop in driver) { _.forEach(driver, function(prop, name) {
if (typeof driver[prop] === "function" && !testDriver[prop]) { if (_.isFunction(prop) && !testDriver[name]) {
testDriver[prop] = function() { return true; }; testDriver[name] = function() { return true; };
} }
} });
return testDriver; return testDriver;
} }

View File

@ -9,7 +9,8 @@
"use strict"; "use strict";
var Basestar = require("./basestar"), var Basestar = require("./basestar"),
Utils = require("./utils"); Utils = require("./utils"),
_ = require("./lodash");
// Public: Creates a new Driver // Public: Creates a new Driver
// //
@ -34,11 +35,13 @@ var Driver = module.exports = function Driver(opts) {
this.details = {}; this.details = {};
for (var opt in opts) { _.forEach(opts, function(opt, name) {
if (["robot", "name", "connection", "driver"].indexOf(opt) < 0) { if (_.include(["robot", "name", "connection", "driver"], opt)) {
this.details[opt] = opts[opt]; return;
} }
}
this.details[name] = opt;
}, this);
}; };
Utils.subclass(Driver, Basestar); Utils.subclass(Driver, Basestar);
@ -50,9 +53,7 @@ Driver.prototype.setupCommands = function(commands, proxy) {
this.proxyMethods(commands, proxy, this); this.proxyMethods(commands, proxy, this);
for (var i = 0; i < commands.length; i++) { _.forEach(commands, function(command) {
var command = commands[i];
var snake_case = command.replace(/[A-Z]+/g, function(match) { var snake_case = command.replace(/[A-Z]+/g, function(match) {
if (match.length > 1) { if (match.length > 1) {
match = match.replace(/[A-Z]$/, function(m) { match = match.replace(/[A-Z]$/, function(m) {
@ -64,7 +65,7 @@ Driver.prototype.setupCommands = function(commands, proxy) {
}).replace(/^_/, ""); }).replace(/^_/, "");
this.commands[snake_case] = this[command]; this.commands[snake_case] = this[command];
} }, this);
}; };
Driver.prototype.toJSON = function() { Driver.prototype.toJSON = function() {
@ -72,7 +73,7 @@ Driver.prototype.toJSON = function() {
name: this.name, name: this.name,
driver: this.constructor.name || this.name, driver: this.constructor.name || this.name,
connection: this.connection.name, connection: this.connection.name,
commands: Object.keys(this.commands), commands: _.keys(this.commands),
details: this.details details: this.details
}; };
}; };

View File

@ -12,7 +12,8 @@ var initConnection = require("./connection"),
initDevice = require("./device"), initDevice = require("./device"),
Logger = require("./logger"), Logger = require("./logger"),
Utils = require("./utils"), Utils = require("./utils"),
Config = require("./config"); Config = require("./config"),
_ = require("./lodash");
var Async = require("async"), var Async = require("async"),
EventEmitter = require("events").EventEmitter; EventEmitter = require("events").EventEmitter;
@ -52,9 +53,7 @@ var Robot = module.exports = function Robot(opts) {
"initConnections" "initConnections"
]; ];
methods.forEach(function(method) { _.bindAll(this, methods);
this[method] = this[method].bind(this);
}, this);
this.name = opts.name || Robot.randomName(); this.name = opts.name || Robot.randomName();
this.connections = {}; this.connections = {};
@ -72,31 +71,29 @@ var Robot = module.exports = function Robot(opts) {
this.initConnections(opts); this.initConnections(opts);
this.initDevices(opts); this.initDevices(opts);
for (var n in opts) { _.forEach(opts, function(opt, name) {
var opt = opts[n]; if (this[name] !== undefined) {
return;
if (this[n] !== undefined) {
continue;
} }
this[n] = opt; this[name] = opt;
if (typeof opt === "function" && opts.commands == null) { if (opts.commands == null && _.isFunction(opt)) {
this.commands[n] = opt; this.commands[name] = opt;
} }
} }, this);
if (opts.commands) { if (opts.commands) {
var cmds = opts.commands; var cmds = opts.commands;
if (typeof cmds === "object") { if (_.isObject(cmds)) {
this.commands = cmds; this.commands = cmds;
} }
if (typeof cmds === "function") { if (_.isFunction(cmds)) {
var result = cmds.call(this, this); var result = cmds.call(this, this);
if (typeof result === "object" && !Array.isArray(result)) { if (_.isObject(result) && !_.isArray(result)) {
this.commands = result; this.commands = result;
} else { } else {
throw new Error("#commands function must return an object"); throw new Error("#commands function must return an object");
@ -125,23 +122,11 @@ Robot.randomName = function() {
// //
// Returns an Object containing Robot data // Returns an Object containing Robot data
Robot.prototype.toJSON = function() { Robot.prototype.toJSON = function() {
var devices = [],
connections = [],
n;
for (n in this.connections) {
connections.push(this.connections[n].toJSON());
}
for (n in this.devices) {
devices.push(this.devices[n].toJSON());
}
return { return {
name: this.name, name: this.name,
connections: connections, connections: _.invoke(this.connections, "toJSON"),
devices: devices, devices: _.invoke(this.devices, "toJSON"),
commands: Object.keys(this.commands) commands: _.keys(this.commands)
}; };
}; };
@ -170,11 +155,9 @@ Robot.prototype.connection = function(name, conn) {
// //
// Returns initialized connections // Returns initialized connections
Robot.prototype.initConnections = function(opts) { Robot.prototype.initConnections = function(opts) {
Logger.info("Initializing connections.");
var str; var str;
var isArray = Array.isArray; Logger.info("Initializing connections.");
if (opts.connection == null && opts.connections == null) { if (opts.connection == null && opts.connections == null) {
return this.connections; return this.connections;
@ -190,20 +173,17 @@ Robot.prototype.initConnections = function(opts) {
return this.connections; return this.connections;
} }
if (typeof opts.connections === "object" && !isArray(opts.connections)) { if (_.isObject(opts.connections)) {
for (var name in opts.connections) { if (_.isArray(opts.connections)) {
this.connection(name, opts.connections[name]); str = "Specifying connections as an array is deprecated. ";
str += "It will be removed in 1.0.0.";
Logger.warn(str);
} }
}
if (isArray(opts.connections)) { _.forEach(opts.connections, function(conn, key) {
str = "Specifying connections as an array is deprecated. "; var name = _.isString(key) ? key : conn.name;
str += "It will be removed in 1.0.0."; this.connection(name, conn);
Logger.warn(str);
opts.connections.forEach(function(conn) {
this.connection(conn.name, conn);
}, this); }, this);
} }
@ -232,12 +212,9 @@ Robot.prototype.device = function(name, device) {
process.emit("SIGINT"); process.emit("SIGINT");
} }
device.connection = this.connections[device.connection]; device.connection = this.connections[device.connection];
} else { } else {
for (var conn in this.connections) { device.connection = _.first(_.values(this.connections));
device.connection = this.connections[conn];
break;
}
} }
this.devices[device.name] = initDevice(device); this.devices[device.name] = initDevice(device);
@ -251,8 +228,7 @@ Robot.prototype.device = function(name, device) {
// //
// Returns initialized devices // Returns initialized devices
Robot.prototype.initDevices = function(opts) { Robot.prototype.initDevices = function(opts) {
var isArray = Array.isArray, var str;
str;
Logger.info("Initializing devices."); Logger.info("Initializing devices.");
@ -274,18 +250,17 @@ Robot.prototype.initDevices = function(opts) {
return this.devices; return this.devices;
} }
if (typeof opts.devices === "object" && !isArray(opts.devices)) { if (_.isObject(opts.devices)) {
for (var name in opts.devices) { if (_.isArray(opts.devices)) {
this.device(name, opts.devices[name]); str = "Specifying devices as an array is deprecated. ";
} str += "It will be removed in 1.0.0.";
}
if (isArray(opts.devices)) { Logger.warn(str);
str = "Specifying devices as an array is deprecated."; }
str += "It will be removed in 1.0.0.";
Logger.warn(str); _.forEach(opts.devices, function(device, key) {
opts.devices.forEach(function(device) { var name = _.isString(key) ? key : device.name;
this.device(device.name, device); this.device(name, device);
}, this); }, this);
} }
@ -304,25 +279,29 @@ Robot.prototype.start = function(callback) {
var mode = Utils.fetch(Config, "workMode", "async"); var mode = Utils.fetch(Config, "workMode", "async");
var start = function() {
if (mode === "async") {
this.startWork();
}
}.bind(this);
Async.series([ Async.series([
this.startConnections, this.startConnections,
this.startDevices, this.startDevices,
function(callback) { start
if (mode === "async") {
this.startWork();
}
callback(null, true);
}.bind(this)
], function(err, results) { ], function(err, results) {
if (!!err) { if (!!err) {
Logger.fatal("An error occured while trying to start the robot:"); Logger.fatal("An error occured while trying to start the robot:");
Logger.fatal(err); Logger.fatal(err);
if (typeof(this.error) === "function") { if (typeof(this.error) === "function") {
this.error.call(this, err); this.error.call(this, err);
} }
this.emit("error", err); this.emit("error", err);
} }
if (typeof(callback) === "function") {
if (_.isFunction(callback)) {
callback(err, results); callback(err, results);
} }
}.bind(this)); }.bind(this));
@ -351,11 +330,11 @@ Robot.prototype.startWork = function() {
Robot.prototype.startConnections = function(callback) { Robot.prototype.startConnections = function(callback) {
Logger.info("Starting connections."); Logger.info("Starting connections.");
var starters = Object.keys(this.connections).map(function(n) { var starters = _.map(this.connections, function(conn, name) {
var conn = this[n] = this.connections[n]; this[name] = conn;
return function(cb) { return function(cb) {
var str = "Starting connection '" + n + "'"; var str = "Starting connection '" + name + "'";
if (conn.host) { if (conn.host) {
str += " on host " + conn.host; str += " on host " + conn.host;
@ -379,11 +358,11 @@ Robot.prototype.startConnections = function(callback) {
Robot.prototype.startDevices = function(callback) { Robot.prototype.startDevices = function(callback) {
Logger.info("Starting devices."); Logger.info("Starting devices.");
var starters = Object.keys(this.devices).map(function(n) { var starters = _.map(this.devices, function(device, name) {
var device = this[n] = this.devices[n]; this[name] = device;
return function(cb) { return function(cb) {
var str = "Starting device '" + n + "'"; var str = "Starting device '" + name + "'";
if (device.pin) { if (device.pin) {
str += " on pin " + device.pin; str += " on pin " + device.pin;
@ -407,19 +386,12 @@ Robot.prototype.startDevices = function(callback) {
Robot.prototype.halt = function(callback) { Robot.prototype.halt = function(callback) {
callback = callback || function() {}; callback = callback || function() {};
var fns = Object.keys(this.devices).map(function(d) { var devices = _.map(this.devices, "halt");
var device = this.devices[d]; var connections = _.map(this.connections, "disconnect");
return device.halt.bind(device);
}, this);
Async.parallel(fns, function() { Async.parallel(devices, function() {
var fns = Object.keys(this.connections).map(function(c) { Async.parallel(connections, callback);
var connection = this.connections[c]; });
return connection.disconnect.bind(connection);
}, this);
Async.parallel(fns, callback);
}.bind(this));
this.running = false; this.running = false;
}; };

View File

@ -8,6 +8,8 @@
"use strict"; "use strict";
var _ = require("./lodash");
var addCoreExtensions = function addCoreExtensions() { var addCoreExtensions = function addCoreExtensions() {
var max = Math.max, var max = Math.max,
min = Math.min; min = Math.min;
@ -181,11 +183,9 @@ var Utils = module.exports = {
this.constructor = child; this.constructor = child;
}; };
for (var key in parent) { _.forOwn(parent, function(prop, key) {
if (Object.hasOwnProperty.call(parent, key)) { child[key] = prop;
child[key] = parent[key]; });
}
}
Ctor.prototype = parent.prototype; Ctor.prototype = parent.prototype;
child.prototype = new Ctor(); child.prototype = new Ctor();
@ -194,11 +194,11 @@ var Utils = module.exports = {
}, },
proxyFunctions: function proxyFunctions(source, target) { proxyFunctions: function proxyFunctions(source, target) {
for (var opt in source) { _.forEach(source, function(prop, key) {
if (!target[opt] && typeof source[opt] === "function") { if (_.isFunction(prop) && !target[key]) {
target[opt] = source[opt].bind(source); target[key] = prop.bind(source);
} }
} });
}, },
// Public: Proxies a list of methods from one object to another. It will not // Public: Proxies a list of methods from one object to another. It will not
@ -216,25 +216,20 @@ var Utils = module.exports = {
base = this; base = this;
} }
if (force == null) { force = force || false;
force = false;
}
var proxy = function(method) { _.forEach(methods, function(method) {
return base[method] = function() { if (!_.isFunction(target[method])) {
return target[method].apply(target, arguments); return;
};
};
for (var i = 0; i < methods.length; i++) {
var method = methods[i];
if (!force && typeof(base[method]) === "function") {
continue;
} }
proxy(method); if (_.isFunction(base[method]) && !force) {
} return;
}
base[method] = target[method].bind(target);
});
return base; return base;
}, },