Add helpers to replace some lodash functionality
Not a 1:1, and probably much slower than Lodash's ultra-optimised implementations, but we do enough I/O that it's not really relevant, is it?
This commit is contained in:
parent
618aa8212d
commit
6e3d7c6667
|
@ -9,7 +9,8 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var Basestar = require("./basestar"),
|
var Basestar = require("./basestar"),
|
||||||
Utils = require("./utils");
|
Utils = require("./utils"),
|
||||||
|
_ = require("./utils/helpers");
|
||||||
|
|
||||||
// Public: Creates a new Adaptor
|
// Public: Creates a new Adaptor
|
||||||
//
|
//
|
||||||
|
@ -33,14 +34,11 @@ 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 name in opts) {
|
_.each(opts, function(opt, name) {
|
||||||
var opt = opts[name],
|
if (!~["robot", "name", "adaptor", "events"].indexOf(name)) {
|
||||||
banned = ["robot", "name", "adaptor", "events"];
|
|
||||||
|
|
||||||
if (!~banned.indexOf(name)) {
|
|
||||||
this.details[name] = opt;
|
this.details[name] = opt;
|
||||||
}
|
}
|
||||||
}
|
}, this);
|
||||||
};
|
};
|
||||||
|
|
||||||
Utils.subclass(Adaptor, Basestar);
|
Utils.subclass(Adaptor, Basestar);
|
||||||
|
|
|
@ -10,7 +10,8 @@
|
||||||
|
|
||||||
var EventEmitter = require("events").EventEmitter;
|
var EventEmitter = require("events").EventEmitter;
|
||||||
|
|
||||||
var Utils = require("./utils");
|
var Utils = require("./utils"),
|
||||||
|
_ = require("./utils/helpers");
|
||||||
|
|
||||||
// Basestar is a base class to be used when writing external Cylon adaptors and
|
// Basestar is a base class to be used when writing external Cylon adaptors and
|
||||||
// drivers. It provides some useful base methods and functionality
|
// drivers. It provides some useful base methods and functionality
|
||||||
|
@ -83,7 +84,7 @@ Basestar.prototype.defineDriverEvent = function(opts) {
|
||||||
};
|
};
|
||||||
|
|
||||||
Basestar.prototype._proxyEvents = function(opts, source, target) {
|
Basestar.prototype._proxyEvents = function(opts, source, target) {
|
||||||
opts = (typeof opts === "string") ? { eventName: opts } : opts;
|
opts = _.isString(opts) ? { eventName: opts } : opts;
|
||||||
|
|
||||||
opts.source = source;
|
opts.source = source;
|
||||||
opts.target = target;
|
opts.target = target;
|
||||||
|
|
50
lib/cylon.js
50
lib/cylon.js
|
@ -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("./utils/helpers");
|
||||||
|
|
||||||
var EventEmitter = require("events").EventEmitter;
|
var EventEmitter = require("events").EventEmitter;
|
||||||
|
|
||||||
|
@ -73,19 +74,15 @@ Cylon.robot = function robot(opts) {
|
||||||
//
|
//
|
||||||
// Returns nothing
|
// Returns nothing
|
||||||
Cylon.api = function api(Server, opts) {
|
Cylon.api = function api(Server, opts) {
|
||||||
var isObject = function(arg) { return typeof arg === "object"; },
|
|
||||||
isFunction = function(arg) { return typeof arg === "function"; },
|
|
||||||
isString = function(arg) { return typeof arg === "string"; };
|
|
||||||
|
|
||||||
// if only passed options (or nothing), assume HTTP server
|
// if only passed options (or nothing), assume HTTP server
|
||||||
if (Server == null || isObject(Server) && !isFunction(Server)) {
|
if (Server == null || _.isObject(Server) && !_.isFunction(Server)) {
|
||||||
opts = Server;
|
opts = Server;
|
||||||
Server = "http";
|
Server = "http";
|
||||||
}
|
}
|
||||||
|
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
|
|
||||||
if (isString(Server)) {
|
if (_.isString(Server)) {
|
||||||
var req = "cylon-api-" + Server;
|
var req = "cylon-api-" + Server;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -106,9 +103,7 @@ Cylon.api = function api(Server, opts) {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
messages.forEach(function(str) {
|
_.each(messages, _.arity(Logger.error, 1));
|
||||||
Logger.error(str);
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
throw e;
|
throw e;
|
||||||
|
@ -126,22 +121,13 @@ Cylon.api = function api(Server, opts) {
|
||||||
//
|
//
|
||||||
// Returns nothing
|
// Returns nothing
|
||||||
Cylon.start = function start() {
|
Cylon.start = function start() {
|
||||||
var starters = [],
|
var starters = _.pluck(this.robots, "start");
|
||||||
name;
|
|
||||||
|
|
||||||
for (name in this.robots) {
|
|
||||||
var bot = this.robots[name];
|
|
||||||
starters.push(bot.start.bind(bot));
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (name in this.robots) {
|
_.invoke(this.robots, "startWork");
|
||||||
var bot = this.robots[name];
|
|
||||||
bot.startWork.call(bot);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
};
|
};
|
||||||
|
@ -153,11 +139,11 @@ Cylon.start = function start() {
|
||||||
// Returns the current config
|
// Returns the current config
|
||||||
Cylon.config = function(opts) {
|
Cylon.config = function(opts) {
|
||||||
var loggingChanged = (
|
var loggingChanged = (
|
||||||
opts.logging && Config.logging !== Utils.merge(Config.logging, opts.logging)
|
opts.logging && Config.logging !== _.extend(Config.logging, opts.logging)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (typeof opts === "object" && !Array.isArray(opts)) {
|
if (_.isObject(opts)) {
|
||||||
Config = Utils.merge(Config, opts);
|
Config = _.extend(Config, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loggingChanged) {
|
if (loggingChanged) {
|
||||||
|
@ -175,12 +161,7 @@ Cylon.config = function(opts) {
|
||||||
Cylon.halt = function halt(callback) {
|
Cylon.halt = function halt(callback) {
|
||||||
callback = callback || function() {};
|
callback = callback || function() {};
|
||||||
|
|
||||||
var fns = [];
|
var fns = _.pluck(this.robots, "halt");
|
||||||
|
|
||||||
for (var name in this.robots) {
|
|
||||||
var bot = this.robots[name];
|
|
||||||
fns.push(bot.halt.bind(bot));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
||||||
|
@ -190,15 +171,8 @@ Cylon.halt = function halt(callback) {
|
||||||
};
|
};
|
||||||
|
|
||||||
Cylon.toJSON = function() {
|
Cylon.toJSON = function() {
|
||||||
var robots = [];
|
|
||||||
|
|
||||||
for (var name in this.robots) {
|
|
||||||
var bot = this.robots[name];
|
|
||||||
robots.push(bot.toJSON.call(bot));
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
robots: robots,
|
robots: _.invoke(this.robots, "toJSON"),
|
||||||
commands: Object.keys(this.commands),
|
commands: Object.keys(this.commands),
|
||||||
events: this.events
|
events: this.events
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var Basestar = require("./basestar"),
|
var Basestar = require("./basestar"),
|
||||||
Utils = require("./utils");
|
Utils = require("./utils"),
|
||||||
|
_ = require("./utils/helpers");
|
||||||
|
|
||||||
// Public: Creates a new Driver
|
// Public: Creates a new Driver
|
||||||
//
|
//
|
||||||
|
@ -35,14 +36,13 @@ var Driver = module.exports = function Driver(opts) {
|
||||||
|
|
||||||
this.details = {};
|
this.details = {};
|
||||||
|
|
||||||
for (var name in opts) {
|
_.each(opts, function(opt, name) {
|
||||||
var opt = opts[name],
|
var banned = ["robot", "name", "connection", "driver", "events"];
|
||||||
banned = ["robot", "name", "connection", "driver", "events"];
|
|
||||||
|
|
||||||
if (!~banned.indexOf(name)) {
|
if (!~banned.indexOf(name)) {
|
||||||
this.details[name] = opt;
|
this.details[name] = opt;
|
||||||
}
|
}
|
||||||
}
|
}, this);
|
||||||
};
|
};
|
||||||
|
|
||||||
Utils.subclass(Driver, Basestar);
|
Utils.subclass(Driver, Basestar);
|
||||||
|
|
|
@ -9,14 +9,15 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var Registry = require("./registry"),
|
var Registry = require("./registry"),
|
||||||
Config = require("./config");
|
Config = require("./config"),
|
||||||
|
_ = require("./utils/helpers");
|
||||||
|
|
||||||
function testMode() {
|
function testMode() {
|
||||||
return process.env.NODE_ENV === "test" && Config.testMode;
|
return process.env.NODE_ENV === "test" && Config.testMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = function Initializer(type, opts) {
|
module.exports = function Initializer(type, opts) {
|
||||||
var mod, name, prop;
|
var mod;
|
||||||
|
|
||||||
mod = Registry.findBy(type, opts[type]);
|
mod = Registry.findBy(type, opts[type]);
|
||||||
|
|
||||||
|
@ -32,28 +33,24 @@ module.exports = function Initializer(type, opts) {
|
||||||
|
|
||||||
var obj = mod[type](opts);
|
var obj = mod[type](opts);
|
||||||
|
|
||||||
for (name in obj) {
|
_.each(obj, function(prop, name) {
|
||||||
prop = obj[name];
|
|
||||||
|
|
||||||
if (name === "constructor") {
|
if (name === "constructor") {
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof prop === "function") {
|
if (_.isFunction(prop)) {
|
||||||
obj[name] = prop.bind(obj);
|
obj[name] = prop.bind(obj);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
if (testMode()) {
|
if (testMode()) {
|
||||||
var test = Registry.findBy(type, "test")[type](opts);
|
var test = Registry.findBy(type, "test")[type](opts);
|
||||||
|
|
||||||
for (name in obj) {
|
_.each(obj, function(prop, name) {
|
||||||
prop = obj[name];
|
if (_.isFunction(prop) && !test[name]) {
|
||||||
|
|
||||||
if (typeof prop === "function" && !test[name]) {
|
|
||||||
test[name] = function() { return true; };
|
test[name] = function() { return true; };
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,12 +13,12 @@ var levels = ["debug", "info", "warn", "error", "fatal"];
|
||||||
var BasicLogger = require("./logger/basic_logger"),
|
var BasicLogger = require("./logger/basic_logger"),
|
||||||
NullLogger = require("./logger/null_logger"),
|
NullLogger = require("./logger/null_logger"),
|
||||||
Config = require("./config"),
|
Config = require("./config"),
|
||||||
Utils = require("./utils");
|
_ = require("./utils/helpers");
|
||||||
|
|
||||||
var Logger = module.exports = {
|
var Logger = module.exports = {
|
||||||
setup: function(opts) {
|
setup: function(opts) {
|
||||||
if (typeof opts === "object") {
|
if (_.isObject(opts)) {
|
||||||
Config.logging = Utils.merge(Config.logging, opts);
|
Config.logging = _.extend(Config.logging, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
var logger = Config.logging.logger,
|
var logger = Config.logging.logger,
|
||||||
|
|
113
lib/robot.js
113
lib/robot.js
|
@ -11,7 +11,8 @@
|
||||||
var initializer = require("./initializer"),
|
var initializer = require("./initializer"),
|
||||||
Logger = require("./logger"),
|
Logger = require("./logger"),
|
||||||
Utils = require("./utils"),
|
Utils = require("./utils"),
|
||||||
Config = require("./config");
|
Config = require("./config"),
|
||||||
|
_ = require("./utils/helpers");
|
||||||
|
|
||||||
var Async = require("async"),
|
var Async = require("async"),
|
||||||
EventEmitter = require("events").EventEmitter;
|
EventEmitter = require("events").EventEmitter;
|
||||||
|
@ -48,30 +49,28 @@ var Robot = module.exports = function Robot(opts) {
|
||||||
this.initConnections(opts);
|
this.initConnections(opts);
|
||||||
this.initDevices(opts);
|
this.initDevices(opts);
|
||||||
|
|
||||||
for (var name in opts) {
|
_.each(opts, function(opt, name) {
|
||||||
var opt = opts[name];
|
|
||||||
|
|
||||||
if (this[name] !== undefined) {
|
if (this[name] !== undefined) {
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this[name] = opt;
|
this[name] = opt;
|
||||||
|
|
||||||
if (opts.commands == null && typeof opt === "function") {
|
if (opts.commands == null && _.isFunction(opt)) {
|
||||||
this.commands[name] = opt;
|
this.commands[name] = opt;
|
||||||
}
|
}
|
||||||
}
|
}, this);
|
||||||
|
|
||||||
if (opts.commands) {
|
if (opts.commands) {
|
||||||
var cmds;
|
var cmds;
|
||||||
|
|
||||||
if (typeof opts.commands === "function") {
|
if (_.isFunction(opts.commands)) {
|
||||||
cmds = opts.commands.call(this);
|
cmds = opts.commands.call(this);
|
||||||
} else {
|
} else {
|
||||||
cmds = opts.commands;
|
cmds = opts.commands;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof cmds === "object" && !Array.isArray(cmds)) {
|
if (_.isObject(cmds)) {
|
||||||
this.commands = cmds;
|
this.commands = cmds;
|
||||||
} else {
|
} else {
|
||||||
var err = "#commands must be an object ";
|
var err = "#commands must be an object ";
|
||||||
|
@ -101,26 +100,12 @@ Robot.randomName = function() {
|
||||||
//
|
//
|
||||||
// Returns an Object containing Robot data
|
// Returns an Object containing Robot data
|
||||||
Robot.prototype.toJSON = function() {
|
Robot.prototype.toJSON = function() {
|
||||||
var connections = [],
|
|
||||||
devices = [],
|
|
||||||
n;
|
|
||||||
|
|
||||||
for (n in this.connections) {
|
|
||||||
var conn = this.connections[n];
|
|
||||||
connections.push(conn.toJSON.call(conn));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (n in this.devices) {
|
|
||||||
var device = this.devices[n];
|
|
||||||
devices.push(device.toJSON.call(device));
|
|
||||||
}
|
|
||||||
|
|
||||||
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: Object.keys(this.commands),
|
||||||
events: Array.isArray(this.events) ? this.events : []
|
events: _.isArray(this.events) ? this.events : []
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -182,30 +167,28 @@ Robot.prototype.initConnections = function(opts) {
|
||||||
return this.connections;
|
return this.connections;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof opts.connections === "object") {
|
if (_.isObjectLoose(opts.connections)) {
|
||||||
if (Array.isArray(opts.connections)) {
|
if (_.isArray(opts.connections)) {
|
||||||
this.performArraySetup(opts.connections, "connection", "connections");
|
this.performArraySetup(opts.connections, "connection", "connections");
|
||||||
return this.connections;
|
return this.connections;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var key in opts.connections) {
|
_.each(opts.connections, function(conn, key) {
|
||||||
var conn = opts.connections[key],
|
var name = _.isString(key) ? key : conn.name;
|
||||||
name = typeof key === "string" ? key : conn.name;
|
|
||||||
|
|
||||||
if (conn.devices) {
|
if (conn.devices) {
|
||||||
opts.devices = opts.devices || {};
|
opts.devices = opts.devices || {};
|
||||||
|
|
||||||
for (var d in conn.devices) {
|
_.each(conn.devices, function(device, d) {
|
||||||
var device = conn.devices[d];
|
|
||||||
device.connection = name;
|
device.connection = name;
|
||||||
opts.devices[d] = device;
|
opts.devices[d] = device;
|
||||||
}
|
});
|
||||||
|
|
||||||
delete conn.devices;
|
delete conn.devices;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.connection(name, conn);
|
this.connection(name, conn);
|
||||||
}
|
}, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.connections;
|
return this.connections;
|
||||||
|
@ -226,7 +209,7 @@ Robot.prototype.device = function(name, device) {
|
||||||
this.log("warn", str);
|
this.log("warn", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof device.connection === "string") {
|
if (_.isString(device.connection)) {
|
||||||
if (this.connections[device.connection] == null) {
|
if (this.connections[device.connection] == null) {
|
||||||
str = "No connection found with the name " + device.connection + ".\n";
|
str = "No connection found with the name " + device.connection + ".\n";
|
||||||
this.log("fatal", str);
|
this.log("fatal", str);
|
||||||
|
@ -269,18 +252,16 @@ Robot.prototype.initDevices = function(opts) {
|
||||||
return this.devices;
|
return this.devices;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof opts.devices === "object") {
|
if (_.isObjectLoose(opts.devices)) {
|
||||||
if (Array.isArray(opts.devices)) {
|
if (_.isArray(opts.devices)) {
|
||||||
this.performArraySetup(opts.devices, "device", "devices");
|
this.performArraySetup(opts.devices, "device", "devices");
|
||||||
return this.devices;
|
return this.devices;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var key in opts.devices) {
|
_.each(opts.devices, function(device, key) {
|
||||||
var device = opts.devices[key],
|
var name = _.isString(key) ? key : device.name;
|
||||||
name = typeof key === "string" ? key : device.name;
|
|
||||||
|
|
||||||
this.device(name, device);
|
this.device(name, device);
|
||||||
}
|
}, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.devices;
|
return this.devices;
|
||||||
|
@ -314,7 +295,7 @@ Robot.prototype.start = function(callback) {
|
||||||
this.log("fatal", err);
|
this.log("fatal", err);
|
||||||
|
|
||||||
this.halt(function() {
|
this.halt(function() {
|
||||||
if (typeof(this.error) === "function") {
|
if (_.isFunction(this.error)) {
|
||||||
this.error.call(this, err);
|
this.error.call(this, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,7 +305,7 @@ Robot.prototype.start = function(callback) {
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof callback === "function") {
|
if (_.isFunction(callback)) {
|
||||||
callback(err, results);
|
callback(err, results);
|
||||||
}
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
@ -353,11 +334,7 @@ Robot.prototype.startWork = function() {
|
||||||
Robot.prototype.startConnections = function(callback) {
|
Robot.prototype.startConnections = function(callback) {
|
||||||
this.log("info", "Starting connections.");
|
this.log("info", "Starting connections.");
|
||||||
|
|
||||||
var starters = [];
|
var starters = _.map(this.connections, function(conn, name) {
|
||||||
|
|
||||||
var createStarter = function(name) {
|
|
||||||
var conn = this.connections[name];
|
|
||||||
|
|
||||||
this[name] = conn;
|
this[name] = conn;
|
||||||
|
|
||||||
return function(cb) {
|
return function(cb) {
|
||||||
|
@ -372,11 +349,7 @@ Robot.prototype.startConnections = function(callback) {
|
||||||
this.log("debug", str + ".");
|
this.log("debug", str + ".");
|
||||||
return conn.connect.call(conn, cb);
|
return conn.connect.call(conn, cb);
|
||||||
}.bind(this);
|
}.bind(this);
|
||||||
}.bind(this);
|
}, this);
|
||||||
|
|
||||||
for (var name in this.connections) {
|
|
||||||
starters.push(createStarter(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Async.parallel(starters, callback);
|
return Async.parallel(starters, callback);
|
||||||
};
|
};
|
||||||
|
@ -391,11 +364,7 @@ Robot.prototype.startDevices = function(callback) {
|
||||||
|
|
||||||
log("info", "Starting devices.");
|
log("info", "Starting devices.");
|
||||||
|
|
||||||
var starters = [];
|
var starters = _.map(this.devices, function(device, name) {
|
||||||
|
|
||||||
var createStarter = function(name) {
|
|
||||||
var device = this.devices[name];
|
|
||||||
|
|
||||||
this[name] = device;
|
this[name] = device;
|
||||||
|
|
||||||
return function(cb) {
|
return function(cb) {
|
||||||
|
@ -408,12 +377,7 @@ Robot.prototype.startDevices = function(callback) {
|
||||||
log("debug", str + ".");
|
log("debug", str + ".");
|
||||||
return device.start.call(device, cb);
|
return device.start.call(device, cb);
|
||||||
};
|
};
|
||||||
|
}, this);
|
||||||
}.bind(this);
|
|
||||||
|
|
||||||
for (var name in this.devices) {
|
|
||||||
starters.push(createStarter(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Async.parallel(starters, callback);
|
return Async.parallel(starters, callback);
|
||||||
};
|
};
|
||||||
|
@ -432,19 +396,8 @@ Robot.prototype.halt = function(callback) {
|
||||||
return callback();
|
return callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
var devices = [],
|
var devices = _.pluck(this.devices, "halt"),
|
||||||
connections = [],
|
connections = _.pluck(this.connections, "disconnect");
|
||||||
n;
|
|
||||||
|
|
||||||
for (n in this.devices) {
|
|
||||||
var device = this.devices[n];
|
|
||||||
devices.push(device.halt.bind(device));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (n in this.connections) {
|
|
||||||
var conn = this.connections[n];
|
|
||||||
connections.push(conn.disconnect.bind(conn));
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Async.parallel(devices, function() {
|
Async.parallel(devices, function() {
|
||||||
|
@ -481,7 +434,7 @@ Robot.prototype.performArraySetup = function(things, typeOfThing, arrayName) {
|
||||||
this.log("warn", str);
|
this.log("warn", str);
|
||||||
|
|
||||||
things.forEach(function(t, key) {
|
things.forEach(function(t, key) {
|
||||||
var name = typeof key === "string" ? key : t.name;
|
var name = _.isString(key) === "string" ? key : t.name;
|
||||||
this[typeOfThing](name, t);
|
this[typeOfThing](name, t);
|
||||||
}, this);
|
}, this);
|
||||||
};
|
};
|
||||||
|
|
59
lib/utils.js
59
lib/utils.js
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
var _ = require("./utils/helpers");
|
||||||
|
|
||||||
var monkeyPatches = require("./utils/monkey-patches");
|
var monkeyPatches = require("./utils/monkey-patches");
|
||||||
|
|
||||||
var Utils = module.exports = {
|
var Utils = module.exports = {
|
||||||
|
@ -106,13 +108,11 @@ var Utils = module.exports = {
|
||||||
},
|
},
|
||||||
|
|
||||||
proxyFunctions: function proxyFunctions(source, target) {
|
proxyFunctions: function proxyFunctions(source, target) {
|
||||||
for (var key in source) {
|
_.each(source, function(prop, key) {
|
||||||
var prop = source[key];
|
if (_.isFunction(prop) && !target[key]) {
|
||||||
|
|
||||||
if (typeof prop === "function" && !target[key]) {
|
|
||||||
target[key] = prop.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
|
||||||
|
@ -133,7 +133,7 @@ var Utils = module.exports = {
|
||||||
force = force || false;
|
force = force || false;
|
||||||
|
|
||||||
methods.forEach(function(method) {
|
methods.forEach(function(method) {
|
||||||
if (typeof base[method] === "function" && !force) {
|
if (_.isFunction(base[method]) && !force) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ var Utils = module.exports = {
|
||||||
throw new Error("key not found: \"" + property + "\"");
|
throw new Error("key not found: \"" + property + "\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof(fallback) === "function") {
|
if (_.isFunction(fallback)) {
|
||||||
var value = fallback(property);
|
var value = fallback(property);
|
||||||
|
|
||||||
if (value === void 0) {
|
if (value === void 0) {
|
||||||
|
@ -200,51 +200,6 @@ var Utils = module.exports = {
|
||||||
return fallback;
|
return fallback;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Public: Merges two arrays/objects together, recursively.
|
|
||||||
//
|
|
||||||
// base - what should be merged onto
|
|
||||||
// source - what should be merged into it
|
|
||||||
//
|
|
||||||
// Returns a merged object/array
|
|
||||||
merge: function(base, source) {
|
|
||||||
var isArray = Array.isArray(source);
|
|
||||||
|
|
||||||
if (base == null) {
|
|
||||||
base = isArray ? [] : {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// merge objects
|
|
||||||
if (isArray) {
|
|
||||||
source.forEach(function(e, i) {
|
|
||||||
if (typeof base[i] === "undefined") {
|
|
||||||
base[i] = e;
|
|
||||||
} else if (typeof e === "object") {
|
|
||||||
base[i] = Utils.merge(base[i], e);
|
|
||||||
} else {
|
|
||||||
if (!~base.indexOf(e)) {
|
|
||||||
base.push(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
var key;
|
|
||||||
|
|
||||||
for (key in source) {
|
|
||||||
if (typeof source[key] !== "object" || !source[key]) {
|
|
||||||
base[key] = source[key];
|
|
||||||
} else {
|
|
||||||
if (base[key]) {
|
|
||||||
Utils.merge(base[key], source[key]);
|
|
||||||
} else {
|
|
||||||
base[key] = source[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return base;
|
|
||||||
},
|
|
||||||
|
|
||||||
// Public: Given a name, and an array of existing names, returns a unique
|
// Public: Given a name, and an array of existing names, returns a unique
|
||||||
// name.
|
// name.
|
||||||
//
|
//
|
||||||
|
|
|
@ -0,0 +1,156 @@
|
||||||
|
// A collection of useful helper functions, used internally but not exported
|
||||||
|
// with the rest of Cylon.
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var __slice = Array.prototype.slice;
|
||||||
|
|
||||||
|
var H = module.exports = {};
|
||||||
|
|
||||||
|
function identity(value) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function extend(base, source) {
|
||||||
|
var isArray = Array.isArray(source);
|
||||||
|
|
||||||
|
if (base == null) {
|
||||||
|
base = isArray ? [] : {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isArray) {
|
||||||
|
source.forEach(function(e, i) {
|
||||||
|
if (typeof base[i] === "undefined") {
|
||||||
|
base[i] = e;
|
||||||
|
} else if (typeof e === "object") {
|
||||||
|
base[i] = extend(base[i], e);
|
||||||
|
} else {
|
||||||
|
if (!~base.indexOf(e)) {
|
||||||
|
base.push(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
var key;
|
||||||
|
|
||||||
|
for (key in source) {
|
||||||
|
if (typeof source[key] !== "object" || !source[key]) {
|
||||||
|
base[key] = source[key];
|
||||||
|
} else {
|
||||||
|
if (base[key]) {
|
||||||
|
extend(base[key], source[key]);
|
||||||
|
} else {
|
||||||
|
base[key] = source[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
extend(H, {
|
||||||
|
identity: identity,
|
||||||
|
extend: extend
|
||||||
|
});
|
||||||
|
|
||||||
|
function kind(thing) {
|
||||||
|
return Object.prototype.toString.call(thing).slice(8, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isA(type) {
|
||||||
|
return function(thing) {
|
||||||
|
return kind(thing) === type;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
extend(H, {
|
||||||
|
isObject: isA("Object"),
|
||||||
|
isObjectLoose: function(thing) { return typeof thing === "object"; },
|
||||||
|
isFunction: isA("Function"),
|
||||||
|
isArray: isA("Array"),
|
||||||
|
isString: isA("String"),
|
||||||
|
isNumber: isA("Number"),
|
||||||
|
isArguments: isA("Arguments"),
|
||||||
|
isUndefined: isA("Undefined")
|
||||||
|
});
|
||||||
|
|
||||||
|
function iterate(thing, fn, thisVal) {
|
||||||
|
if (H.isArray(thing)) {
|
||||||
|
thing.forEach(fn, thisVal);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (H.isObject(thing)) {
|
||||||
|
Object.keys(thing).forEach(function(key) {
|
||||||
|
var value = thing[key];
|
||||||
|
fn.call(thisVal, value, key);
|
||||||
|
}, thisVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function pluck(collection, key) {
|
||||||
|
var keys = [];
|
||||||
|
|
||||||
|
iterate(collection, function(object) {
|
||||||
|
if (H.isObject(object)) {
|
||||||
|
if (H.isFunction(object[key])) {
|
||||||
|
keys.push(object[key].bind(object));
|
||||||
|
} else {
|
||||||
|
keys.push(object[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
function map(collection, fn, thisVal) {
|
||||||
|
var vals = [];
|
||||||
|
|
||||||
|
if (fn == null) {
|
||||||
|
fn = identity;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterate(collection, function(object, index) {
|
||||||
|
vals.push(fn.call(thisVal, object, index));
|
||||||
|
});
|
||||||
|
|
||||||
|
return vals;
|
||||||
|
}
|
||||||
|
|
||||||
|
function invoke(collection, fn) {
|
||||||
|
var args = __slice.call(arguments, 2),
|
||||||
|
vals = [];
|
||||||
|
|
||||||
|
iterate(collection, function(object) {
|
||||||
|
if (H.isFunction(fn)) {
|
||||||
|
vals.push(fn.apply(object, args));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vals.push(object[fn].apply(object, arguments));
|
||||||
|
});
|
||||||
|
|
||||||
|
return vals;
|
||||||
|
}
|
||||||
|
|
||||||
|
extend(H, {
|
||||||
|
pluck: pluck,
|
||||||
|
each: iterate,
|
||||||
|
map: map,
|
||||||
|
invoke: invoke
|
||||||
|
});
|
||||||
|
|
||||||
|
function arity(fn, n) {
|
||||||
|
return function() {
|
||||||
|
var args = __slice.call(arguments, 0, n);
|
||||||
|
return fn.apply(null, args);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
extend(H, {
|
||||||
|
arity: arity
|
||||||
|
});
|
|
@ -252,37 +252,4 @@ describe("Utils", function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#merge", function() {
|
|
||||||
var merge = utils.merge;
|
|
||||||
|
|
||||||
var base = {
|
|
||||||
fruits: ["apple"],
|
|
||||||
vegetables: ["beet"],
|
|
||||||
thing: null,
|
|
||||||
otherThing: "hello!",
|
|
||||||
data: [{ "user": "barney" }, { "user": "fred" }]
|
|
||||||
};
|
|
||||||
|
|
||||||
var source = {
|
|
||||||
fruits: ["banana"],
|
|
||||||
vegetables: ["carrot"],
|
|
||||||
thing: "hello!",
|
|
||||||
otherThing: null,
|
|
||||||
data: [{ "age": 36 }, { "age": 40 }]
|
|
||||||
};
|
|
||||||
|
|
||||||
var expected = {
|
|
||||||
data: [ { age: 36, user: "barney" }, { age: 40, user: "fred" } ],
|
|
||||||
fruits: [ "apple", "banana" ],
|
|
||||||
vegetables: [ "beet", "carrot" ],
|
|
||||||
thing: "hello!",
|
|
||||||
otherThing: null
|
|
||||||
};
|
|
||||||
|
|
||||||
it("merges two objects", function() {
|
|
||||||
var merged = merge(base, source);
|
|
||||||
expect(merged).to.be.eql(expected);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,223 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var _ = source("utils/helpers");
|
||||||
|
|
||||||
|
describe("Helpers", function() {
|
||||||
|
describe("extend", function() {
|
||||||
|
var extend = _.extend;
|
||||||
|
|
||||||
|
var base = {
|
||||||
|
fruits: ["apple"],
|
||||||
|
vegetables: ["beet"],
|
||||||
|
thing: null,
|
||||||
|
otherThing: "hello!",
|
||||||
|
data: [{ "user": "barney" }, { "user": "fred" }]
|
||||||
|
};
|
||||||
|
|
||||||
|
var source = {
|
||||||
|
fruits: ["banana"],
|
||||||
|
vegetables: ["carrot"],
|
||||||
|
thing: "hello!",
|
||||||
|
otherThing: null,
|
||||||
|
data: [{ "age": 36 }, { "age": 40 }]
|
||||||
|
};
|
||||||
|
|
||||||
|
var expected = {
|
||||||
|
data: [ { age: 36, user: "barney" }, { age: 40, user: "fred" } ],
|
||||||
|
fruits: [ "apple", "banana" ],
|
||||||
|
vegetables: [ "beet", "carrot" ],
|
||||||
|
thing: "hello!",
|
||||||
|
otherThing: null
|
||||||
|
};
|
||||||
|
|
||||||
|
it("extends two objects", function() {
|
||||||
|
var extended = extend(base, source);
|
||||||
|
expect(extended).to.be.eql(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("isObject", function() {
|
||||||
|
var fn =_.isObject;
|
||||||
|
|
||||||
|
it("checks if a value is an Object", function() {
|
||||||
|
var Klass = function() {},
|
||||||
|
instance = new Klass();
|
||||||
|
|
||||||
|
expect(fn({})).to.be.eql(true);
|
||||||
|
expect(fn(instance)).to.be.eql(true);
|
||||||
|
|
||||||
|
expect(fn([])).to.be.eql(false);
|
||||||
|
expect(fn(function() {})).to.be.eql(false);
|
||||||
|
expect(fn(10)).to.be.eql(false);
|
||||||
|
expect(fn("")).to.be.eql(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("isFunction", function() {
|
||||||
|
var fn =_.isFunction;
|
||||||
|
|
||||||
|
it("checks if a value is a Function", function() {
|
||||||
|
expect(fn(function() {})).to.be.eql(true);
|
||||||
|
|
||||||
|
expect(fn({})).to.be.eql(false);
|
||||||
|
expect(fn([])).to.be.eql(false);
|
||||||
|
expect(fn(10)).to.be.eql(false);
|
||||||
|
expect(fn("")).to.be.eql(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("isArray", function() {
|
||||||
|
var fn = _.isArray;
|
||||||
|
|
||||||
|
it("checks if a value is an Array", function() {
|
||||||
|
expect(fn([])).to.be.eql(true);
|
||||||
|
|
||||||
|
expect(fn(function() {})).to.be.eql(false);
|
||||||
|
expect(fn({})).to.be.eql(false);
|
||||||
|
expect(fn(10)).to.be.eql(false);
|
||||||
|
expect(fn("")).to.be.eql(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("isNumber", function() {
|
||||||
|
var fn = _.isNumber;
|
||||||
|
|
||||||
|
it("checks if a value is a Number", function() {
|
||||||
|
expect(fn(10)).to.be.eql(true);
|
||||||
|
|
||||||
|
expect(fn(function() {})).to.be.eql(false);
|
||||||
|
expect(fn({})).to.be.eql(false);
|
||||||
|
expect(fn([])).to.be.eql(false);
|
||||||
|
expect(fn("")).to.be.eql(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("isString", function() {
|
||||||
|
var fn = _.isString;
|
||||||
|
|
||||||
|
it("checks if a value is a String", function() {
|
||||||
|
expect(fn("")).to.be.eql(true);
|
||||||
|
|
||||||
|
expect(fn(10)).to.be.eql(false);
|
||||||
|
expect(fn(function() {})).to.be.eql(false);
|
||||||
|
expect(fn({})).to.be.eql(false);
|
||||||
|
expect(fn([])).to.be.eql(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#pluck", function() {
|
||||||
|
var object = { a: { item: "hello" }, b: { item: "world" } },
|
||||||
|
array = [ { item: "hello" }, { item: "world" } ];
|
||||||
|
|
||||||
|
it("plucks values from a collection", function() {
|
||||||
|
expect(_.pluck(object, "item")).to.be.eql(["hello", "world"]);
|
||||||
|
expect(_.pluck(array, "item")).to.be.eql(["hello", "world"]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#map", function() {
|
||||||
|
var object = { a: { item: "hello" }, b: { item: "world" } },
|
||||||
|
array = [ { item: "hello" }, { item: "world" } ];
|
||||||
|
|
||||||
|
var fn = function(value, key) {
|
||||||
|
return [value, key];
|
||||||
|
};
|
||||||
|
|
||||||
|
it("runs a function over items in a collection", function() {
|
||||||
|
expect(_.map(object, fn)).to.be.eql([
|
||||||
|
[{ item: "hello" }, "a"],
|
||||||
|
[{ item: "world" }, "b"]
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(_.map(array, fn)).to.be.eql([
|
||||||
|
[{ item: "hello" }, 0],
|
||||||
|
[{ item: "world" }, 1]
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("defaults to the identity function", function() {
|
||||||
|
expect(_.map(array)).to.be.eql(array);
|
||||||
|
expect(_.map(object)).to.be.eql(array);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#invoke", function() {
|
||||||
|
var array = [
|
||||||
|
{
|
||||||
|
name: "bob",
|
||||||
|
toString: function() {
|
||||||
|
return "Hi from " + this.name;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dave",
|
||||||
|
toString: function() {
|
||||||
|
return "hello from " + this.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
var object = {
|
||||||
|
bob: {
|
||||||
|
name: "bob",
|
||||||
|
toString: function() {
|
||||||
|
return "Hi from " + this.name;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dave: {
|
||||||
|
name: "dave",
|
||||||
|
toString: function() {
|
||||||
|
return "hello from " + this.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
it("runs a instance function over items in a collection", function() {
|
||||||
|
expect(_.invoke(object, "toString")).to.be.eql([
|
||||||
|
"Hi from bob",
|
||||||
|
"hello from dave"
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(_.invoke(array, "toString")).to.be.eql([
|
||||||
|
"Hi from bob",
|
||||||
|
"hello from dave"
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(_.invoke([1, 2, 3, 4, 5], Number.prototype.toString)).to.be.eql([
|
||||||
|
"1", "2", "3", "4", "5"
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#each", function() {
|
||||||
|
var object = { a: { item: "hello" }, b: { item: "world" } },
|
||||||
|
array = [ { item: "hello" }, { item: "world" } ];
|
||||||
|
|
||||||
|
var fn = function(value, key) {
|
||||||
|
return [value, key];
|
||||||
|
};
|
||||||
|
|
||||||
|
it("runs a function over items in a collection", function() {
|
||||||
|
fn = spy();
|
||||||
|
_.map(object, fn);
|
||||||
|
|
||||||
|
expect(fn).to.be.calledWith(object.a, "a");
|
||||||
|
expect(fn).to.be.calledWith(object.b, "b");
|
||||||
|
|
||||||
|
fn = spy();
|
||||||
|
_.map(array, fn);
|
||||||
|
|
||||||
|
expect(fn).to.be.calledWith(array[0], 0);
|
||||||
|
expect(fn).to.be.calledWith(array[1], 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#arity", function() {
|
||||||
|
it("creates a function that only takes a certain # of args", function() {
|
||||||
|
var fn = spy();
|
||||||
|
var one = _.arity(fn, 1);
|
||||||
|
one("one", "two", "three");
|
||||||
|
expect(fn).to.be.calledWith("one");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue