Hook Repository class up, change-up module loading
Cylon modules were previously styled something like this: module.exports = { adaptor: function(args) { return new Adaptor(args); }, register: function(robot) { Cylon.Logger.debug("Registering Firmata adaptor for " + robot.name); robot.registerAdaptor('cylon-firmata', 'firmata'); GPIO.register(robot); I2C.register(robot); } }; Now, they should be something more like this: module.exports = { adaptors: ['firmata'], dependencies: ['cylon-gpio', 'cylon-i2c'], adaptor: function(args) { return new Adaptor(args); }, };
This commit is contained in:
parent
63e43cc553
commit
44075a1a30
|
@ -10,9 +10,12 @@
|
|||
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
|
||||
var Logger = require('./logger'),
|
||||
var Repository = require('./repository'),
|
||||
Logger = require('./logger'),
|
||||
Utils = require('./utils');
|
||||
|
||||
var testMode = process.env.NODE_ENV === 'test' && !CYLON_TEST;
|
||||
|
||||
// Public: Creates a new Connection
|
||||
//
|
||||
// opts - hash of acceptable params:
|
||||
|
@ -87,8 +90,30 @@ Connection.prototype.disconnect = function(callback) {
|
|||
//
|
||||
// Returns the set-up adaptor
|
||||
Connection.prototype.initAdaptor = function(opts) {
|
||||
Logger.debug("Loading adaptor '" + opts.adaptor + "'.");
|
||||
return this.robot.initAdaptor(opts.adaptor, this, opts);
|
||||
var module = Repository.findByAdaptor(opts.adaptor);
|
||||
|
||||
opts.connection = this;
|
||||
|
||||
if (!module) {
|
||||
Repository.register('cylon-' + opts.adaptor);
|
||||
module = Repository.findByAdaptor(opts.adaptor);
|
||||
}
|
||||
|
||||
var adaptor = module.adaptor(opts);
|
||||
|
||||
if (testMode) {
|
||||
var testAdaptor = Repository.findByAdaptor('test').adaptor(opts);
|
||||
|
||||
for (var prop in adaptor) {
|
||||
if (typeof adaptor[prop] === 'function' && !testAdaptor[prop]) {
|
||||
testAdaptor[prop] = function() { return true; };
|
||||
}
|
||||
}
|
||||
|
||||
return testAdaptor;
|
||||
}
|
||||
|
||||
return adaptor;
|
||||
};
|
||||
|
||||
Connection.prototype._logstring = function _logstring(action) {
|
||||
|
|
|
@ -10,9 +10,12 @@
|
|||
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
|
||||
var Logger = require('./logger'),
|
||||
var Repository = require('./repository'),
|
||||
Logger = require('./logger'),
|
||||
Utils = require('./utils');
|
||||
|
||||
var testMode = process.env.NODE_ENV === 'test' && !CYLON_TEST;
|
||||
|
||||
// Public: Creates a new Device
|
||||
//
|
||||
// opts - object containing Device params
|
||||
|
@ -123,10 +126,28 @@ Device.prototype.defaultConnection = function() {
|
|||
//
|
||||
// Returns the set-up driver
|
||||
Device.prototype.initDriver = function(opts) {
|
||||
if (opts == null) {
|
||||
opts = {};
|
||||
var module = Repository.findByDriver(opts.driver);
|
||||
|
||||
opts.device = this;
|
||||
|
||||
if (!module) {
|
||||
Repository.register('cylon-' + opts.driver);
|
||||
module = Repository.findByDriver(opts.driver);
|
||||
}
|
||||
|
||||
Logger.debug("Loading driver '" + opts.driver + "'.");
|
||||
return this.robot.initDriver(opts.driver, this, opts);
|
||||
var driver = module.driver(opts);
|
||||
|
||||
if (testMode) {
|
||||
var testDriver = Repository.findByDriver('test').driver(opts);
|
||||
|
||||
for (var prop in driver) {
|
||||
if (typeof driver[prop] === 'function' && !testDriver[prop]) {
|
||||
testDriver[prop] = function() { return true; };
|
||||
}
|
||||
}
|
||||
|
||||
return testDriver;
|
||||
}
|
||||
|
||||
return driver;
|
||||
};
|
||||
|
|
|
@ -12,39 +12,70 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var Repository = {};
|
||||
var missingModuleError = function(module) {
|
||||
var string = "Cannot find the '" + module + "' module.\n";
|
||||
string += "This problem might be fixed by installing it with 'npm install " + module + "' and trying again.";
|
||||
|
||||
var search = function(entry, value) {
|
||||
for (var name in Repository) {
|
||||
var repo = Repository[name];
|
||||
console.log(string);
|
||||
|
||||
if (~repo[entry].indexOf(value)) {
|
||||
return repo.module;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
process.emit('SIGINT');
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
register: function(module) {
|
||||
var pkg = require(module);
|
||||
var Repository = module.exports = {
|
||||
data: {},
|
||||
|
||||
Repository[module] = {
|
||||
register: function(module) {
|
||||
if (this.data[module]) {
|
||||
return;
|
||||
}
|
||||
|
||||
var pkg;
|
||||
|
||||
try {
|
||||
pkg = require(module);
|
||||
} catch (e) {
|
||||
if (e.code === "MODULE_NOT_FOUND") {
|
||||
missingModuleError(module);
|
||||
}
|
||||
|
||||
throw e;
|
||||
}
|
||||
|
||||
this.data[module] = {
|
||||
module: pkg,
|
||||
adaptors: pkg.adaptors,
|
||||
drivers: pkg.drivers
|
||||
adaptors: pkg.adaptors || [],
|
||||
drivers: pkg.drivers || []
|
||||
};
|
||||
|
||||
if (pkg.dependencies && Array.isArray(pkg.dependencies)) {
|
||||
pkg.dependencies.forEach(function(dep) {
|
||||
Repository.register(dep);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
findByAdaptor: function(adaptor) {
|
||||
return search("adaptors", adaptor);
|
||||
return this.search("adaptors", adaptor);
|
||||
},
|
||||
|
||||
findByDriver: function(driver) {
|
||||
return search("drivers", driver);
|
||||
return this.search("drivers", driver);
|
||||
},
|
||||
|
||||
// here for tests, should not be publicly used
|
||||
_data: Repository
|
||||
search: function(entry, value) {
|
||||
for (var name in this.data) {
|
||||
var repo = this.data[name];
|
||||
|
||||
if (~repo[entry].indexOf(value)) {
|
||||
return repo.module;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Default drivers/adaptors:
|
||||
['loopback', 'ping', 'test-adaptor', 'test-driver'].forEach(function(module) {
|
||||
Repository.register('./test/' + module);
|
||||
});
|
||||
|
|
160
lib/robot.js
160
lib/robot.js
|
@ -60,10 +60,6 @@ var Robot = module.exports = function Robot(opts) {
|
|||
|
||||
var methods = [
|
||||
"toString",
|
||||
"registerDriver",
|
||||
"requireDriver",
|
||||
"registerAdaptor",
|
||||
"requireAdaptor",
|
||||
"halt",
|
||||
"startDevices",
|
||||
"startConnections",
|
||||
|
@ -89,8 +85,6 @@ var Robot = module.exports = function Robot(opts) {
|
|||
this.work = function() { Logger.debug("No work yet."); };
|
||||
}
|
||||
|
||||
this.registerDefaults();
|
||||
|
||||
this.initConnections(opts.connection || opts.connections);
|
||||
this.initDevices(opts.device || opts.devices);
|
||||
|
||||
|
@ -143,17 +137,6 @@ var Robot = module.exports = function Robot(opts) {
|
|||
|
||||
Utils.subclass(Robot, EventEmitter);
|
||||
|
||||
// Public: Registers the default Drivers and Adaptors with Cylon.
|
||||
//
|
||||
// Returns nothing.
|
||||
Robot.prototype.registerDefaults = function registerDefaults() {
|
||||
this.registerAdaptor("./test/loopback", "loopback");
|
||||
this.registerAdaptor("./test/test-adaptor", "test");
|
||||
|
||||
this.registerDriver("./test/ping", "ping");
|
||||
this.registerDriver("./test/test-driver", "test");
|
||||
};
|
||||
|
||||
// Public: Generates a random name for a Robot.
|
||||
//
|
||||
// Returns a string name
|
||||
|
@ -200,6 +183,8 @@ Robot.prototype.initConnections = function(connections) {
|
|||
connections = [].concat(connections);
|
||||
|
||||
connections.forEach(function(conn) {
|
||||
conn.robot = this;
|
||||
|
||||
if (this.connections[conn.name]) {
|
||||
var original = conn.name;
|
||||
conn.name = Utils.makeUnique(original, Object.keys(this.connections));
|
||||
|
@ -207,7 +192,7 @@ Robot.prototype.initConnections = function(connections) {
|
|||
}
|
||||
|
||||
Logger.info("Initializing connection '" + conn.name + "'.");
|
||||
conn['robot'] = this;
|
||||
|
||||
this.connections[conn.name] = new Connection(conn);
|
||||
}.bind(this));
|
||||
|
||||
|
@ -229,6 +214,8 @@ Robot.prototype.initDevices = function(devices) {
|
|||
devices = [].concat(devices);
|
||||
|
||||
devices.forEach(function(device) {
|
||||
device.robot = this;
|
||||
|
||||
if (this.devices[device.name]) {
|
||||
var original = device.name;
|
||||
device.name = Utils.makeUnique(original, Object.keys(this.devices));
|
||||
|
@ -236,7 +223,6 @@ Robot.prototype.initDevices = function(devices) {
|
|||
}
|
||||
|
||||
Logger.info("Initializing device '" + device.name + "'.");
|
||||
device['robot'] = this;
|
||||
this.devices[device.name] = new Device(device);
|
||||
}.bind(this));
|
||||
|
||||
|
@ -365,142 +351,6 @@ Robot.prototype.halt = function(callback) {
|
|||
this.running = false;
|
||||
};
|
||||
|
||||
// Public: Initialize an adaptor and adds it to @robot.adaptors
|
||||
//
|
||||
// adaptorName - module name of adaptor to require
|
||||
// connection - the Connection that requested the adaptor be required
|
||||
//
|
||||
// Returns the adaptor
|
||||
Robot.prototype.initAdaptor = function(adaptorName, connection, opts) {
|
||||
if (opts == null) {
|
||||
opts = {};
|
||||
}
|
||||
|
||||
var adaptor = this.requireAdaptor(adaptorName, opts).adaptor({
|
||||
name: adaptorName,
|
||||
connection: connection,
|
||||
extraParams: opts
|
||||
});
|
||||
|
||||
if (process.env.NODE_ENV === 'test' && !CYLON_TEST) {
|
||||
var testAdaptor = this.requireAdaptor('test').adaptor({
|
||||
name: adaptorName,
|
||||
connection: connection,
|
||||
extraParams: opts
|
||||
});
|
||||
|
||||
Utils.proxyTestStubs(adaptor.commands, testAdaptor);
|
||||
|
||||
for (var prop in adaptor) {
|
||||
if (typeof adaptor[prop] === 'function' && !testAdaptor[prop]) {
|
||||
testAdaptor[prop] = function() { return true; };
|
||||
}
|
||||
}
|
||||
|
||||
return testAdaptor;
|
||||
} else {
|
||||
return adaptor;
|
||||
}
|
||||
};
|
||||
|
||||
// Public: Requires a hardware adaptor and adds it to @robot.adaptors
|
||||
//
|
||||
// adaptorName - module name of adaptor to require
|
||||
//
|
||||
// Returns the module for the adaptor
|
||||
Robot.prototype.requireAdaptor = function(adaptorName, opts) {
|
||||
if (this.adaptors[adaptorName] == null) {
|
||||
var moduleName = opts.module || adaptorName;
|
||||
this.registerAdaptor("cylon-" + moduleName, adaptorName);
|
||||
this.adaptors[adaptorName].register(this);
|
||||
}
|
||||
return this.adaptors[adaptorName];
|
||||
};
|
||||
|
||||
// Public: Registers an Adaptor with the Robot
|
||||
//
|
||||
// moduleName - name of the Node module to require
|
||||
// adaptorName - name of the adaptor to register the moduleName under
|
||||
//
|
||||
// Returns the registered module name
|
||||
Robot.prototype.registerAdaptor = function(moduleName, adaptorName) {
|
||||
if (this.adaptors[adaptorName] == null) {
|
||||
try {
|
||||
return this.adaptors[adaptorName] = require(moduleName);
|
||||
} catch (e) {
|
||||
if (e.code === "MODULE_NOT_FOUND") {
|
||||
missingModuleError(moduleName);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Public: Init a hardware driver
|
||||
//
|
||||
// driverName - driver name
|
||||
// device - the Device that requested the driver be initialized
|
||||
// opts - object containing options when initializing driver
|
||||
//
|
||||
// Returns the new driver
|
||||
Robot.prototype.initDriver = function(driverName, device, opts) {
|
||||
if (opts == null) {
|
||||
opts = {};
|
||||
}
|
||||
|
||||
var driver = this.requireDriver(driverName).driver({
|
||||
name: driverName,
|
||||
device: device,
|
||||
extraParams: opts
|
||||
});
|
||||
|
||||
if (process.env.NODE_ENV === 'test' && !CYLON_TEST) {
|
||||
var testDriver = this.requireDriver('test').driver({
|
||||
name: driverName,
|
||||
device: device,
|
||||
extraParams: opts
|
||||
});
|
||||
|
||||
return Utils.proxyTestStubs(driver.commands, testDriver);
|
||||
} else {
|
||||
return driver;
|
||||
}
|
||||
};
|
||||
|
||||
// Public: Requires module for a driver and adds it to @robot.drivers
|
||||
//
|
||||
// driverName - module name of driver to require
|
||||
//
|
||||
// Returns the module for driver
|
||||
Robot.prototype.requireDriver = function(driverName) {
|
||||
if (this.drivers[driverName] == null) {
|
||||
this.registerDriver("cylon-" + driverName, driverName);
|
||||
this.drivers[driverName].register(this);
|
||||
}
|
||||
return this.drivers[driverName];
|
||||
};
|
||||
|
||||
// Public: Registers an Driver with the Robot
|
||||
//
|
||||
// moduleName - name of the Node module to require
|
||||
// driverName - name of the driver to register the moduleName under
|
||||
//
|
||||
// Returns the registered module name
|
||||
Robot.prototype.registerDriver = function(moduleName, driverName) {
|
||||
if (this.drivers[driverName] == null) {
|
||||
try {
|
||||
return this.drivers[driverName] = require(moduleName);
|
||||
} catch (e) {
|
||||
if (e.code === "MODULE_NOT_FOUND") {
|
||||
missingModuleError(moduleName);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Public: Returns basic info about the robot as a String
|
||||
//
|
||||
// Returns a String
|
||||
|
|
|
@ -27,4 +27,5 @@ Loopback.prototype.disconnect = function(callback) {
|
|||
callback();
|
||||
};
|
||||
|
||||
Loopback.adaptors = ['loopback'];
|
||||
Loopback.adaptor = function(opts) { return new Loopback(opts); };
|
||||
|
|
|
@ -34,6 +34,5 @@ Ping.prototype.halt = function(callback) {
|
|||
callback();
|
||||
};
|
||||
|
||||
Ping.driver = function(opts) {
|
||||
return new Ping(opts);
|
||||
};
|
||||
Ping.drivers = ['ping'];
|
||||
Ping.driver = function(opts) { return new Ping(opts); };
|
||||
|
|
|
@ -19,4 +19,5 @@ module.exports = TestAdaptor = function TestAdaptor() {
|
|||
|
||||
Utils.subclass(TestAdaptor, Adaptor);
|
||||
|
||||
TestAdaptor.adaptors = ['test'];
|
||||
TestAdaptor.adaptor = function(opts) { return new TestAdaptor(opts); };
|
||||
|
|
|
@ -19,4 +19,5 @@ module.exports = TestDriver = function TestDriver() {
|
|||
|
||||
Utils.subclass(TestDriver, Driver);
|
||||
|
||||
TestDriver.drivers = ['test'];
|
||||
TestDriver.driver = function(opts) { return new TestDriver(opts); };
|
||||
|
|
|
@ -26,7 +26,7 @@ describe("Device", function() {
|
|||
driver.string = "";
|
||||
driver.robot = spy();
|
||||
|
||||
initDriver = stub(robot, 'initDriver').returns(driver);
|
||||
initDriver = stub(Device.prototype, 'initDriver').returns(driver);
|
||||
|
||||
device = new Device({
|
||||
robot: robot,
|
||||
|
@ -36,6 +36,10 @@ describe("Device", function() {
|
|||
});
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
initDriver.restore();
|
||||
});
|
||||
|
||||
describe("constructor", function() {
|
||||
it("sets @robot to the passed robot", function() {
|
||||
expect(device.robot).to.be.eql(robot);
|
||||
|
@ -56,7 +60,6 @@ describe("Device", function() {
|
|||
it("asks the Robot to init a driver", function() {
|
||||
expect(device.driver).to.be.eql(driver);
|
||||
expect(initDriver).to.be.calledOnce
|
||||
initDriver.restore();
|
||||
});
|
||||
|
||||
it("does not override existing functions", function() {
|
||||
|
|
|
@ -7,13 +7,24 @@ var path = './../spec/support/mock_module.js';
|
|||
var module = require('./../support/mock_module.js')
|
||||
|
||||
describe("Repository", function() {
|
||||
var original;
|
||||
|
||||
beforeEach(function() {
|
||||
original = Repository.data;
|
||||
Repository.data = {};
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
Repository.data = original;
|
||||
})
|
||||
|
||||
describe("#register", function() {
|
||||
it("adds the supplied module to the Registry", function() {
|
||||
expect(Repository._data).to.be.eql({});
|
||||
expect(Repository.data).to.be.eql({});
|
||||
|
||||
Repository.register(path);
|
||||
|
||||
expect(Repository._data).to.be.eql({
|
||||
expect(Repository.data).to.be.eql({
|
||||
"./../spec/support/mock_module.js": {
|
||||
module: module,
|
||||
drivers: ['test-driver'],
|
||||
|
|
|
@ -59,14 +59,6 @@ describe("Robot", function() {
|
|||
expect(robot.devices).to.be.eql({});
|
||||
});
|
||||
|
||||
it("sets @adaptors to an object containing all adaptors the Robot knows of", function() {
|
||||
expect(robot.adaptors).to.have.keys(["loopback", "test"]);
|
||||
});
|
||||
|
||||
it("sets @drivers to an object containing all drivers the Robot knows of", function() {
|
||||
expect(robot.drivers).to.have.keys(["ping", "test"]);
|
||||
});
|
||||
|
||||
it("sets @work to the passed work function", function() {
|
||||
expect(robot.work).to.be.eql(work);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue