Add new command structure

This commit is contained in:
Andrew Stewart 2014-08-05 18:41:57 -07:00
parent ac737e51ba
commit e6c567a090
8 changed files with 155 additions and 69 deletions

View File

@ -1,29 +1,25 @@
var Cylon = require('../..');
Cylon.api({ host: '0.0.0.0', port: '8080' });
Cylon.api();
var MyRobot = (function() {
function MyRobot() {}
Cylon.robot({
name: 'Frankie',
MyRobot.prototype.commands = ["relax"];
sayRelax: function() {
return this.name + " says relax";
},
MyRobot.prototype.relax = function() {
return "" + this.name + " says relax";
};
MyRobot.prototype.work = function(me) {
every((1).seconds(), function() {
console.log(me.name);
work: function(my) {
every((5).seconds(), function() {
console.log(my.sayRelax());
});
},
commands: function() {
return {
say_relax: this.sayRelax
};
return MyRobot;
})();
var robot = new MyRobot;
robot.name = "frankie";
Cylon.robot(robot);
}
});
Cylon.start();

View File

@ -14,48 +14,40 @@ First, let's make sure to load up Cylon:
var Cylon = require('../..');
Now that we've got that, let's set up a custom API port:
Now that we've got that, let's set up the api:
Cylon.api({ host: '0.0.0.0', port: '8080' });
Cylon.api();
And with that done let's define our robot. We'll make a class to contain this
robot's logic:
And with that done let's define our robot:
var MyRobot = (function() {
function MyRobot() {}
Cylon.robot({
name: 'Frankie',
To let the API know what commands this robot has, we need to provide a `commands` array.
The result of this method will be returned to the HTTP client as part of a JSON
object.
MyRobot.prototype.commands = ["relax"];
And with that done, we can now define the method. The result of this method will
be returned to the HTTP client as part of a JSON object.
MyRobot.prototype.relax = function() {
return "" + this.name + " says relax";
};
sayRelax: function() {
return this.name + " says relax");
},
Since we don't really care what actual work this robot does, but need to keep it
busy, we'll just tell it to print it's name every second.
busy, we'll just tell it to print it's name every five seconds.
MyRobot.prototype.work = function(me) {
every((1).seconds(), function() {
console.log(me.name);
work: function(my) {
every((5).seconds(), function() {
console.log(my.sayRelax());
});
},
We'll then set up the `commands` object, which tells the API which commands the
Robot has should be publically accessible:
commands: function() {
return {
say_relax: this.sayRelax
};
return MyRobot;
})();
And with that all done, we can now instantiate our robot:
var robot = new MyRobot;
Now we can just give it a name and send it off to Cylon.
robot.name = "frankie";
Cylon.robot(robot);
}
});
And now that all the pieces are in place, we can start up Cylon:

View File

@ -64,12 +64,12 @@ router.get("/robots/:robot", load, function(req, res) {
});
router.get("/robots/:robot/commands", load, function(req, res) {
res.json({ commands: req.robot.commands });
res.json({ commands: Object.keys(req.robot.commands) });
});
router.all("/robots/:robot/commands/:command", load, function(req, res) {
var command = req.params.command;
var result = req.robot[command].apply(req.robot, req.commandParams);
var command = req.robot.commands[req.params.command];
var result = command.apply(req.robot, req.commandParams);
res.json({ result: result });
});

View File

@ -25,12 +25,12 @@ var Driver = module.exports = function Driver(opts) {
this.name = opts.name;
this.device = opts.device;
this.connection = this.device.connection;
this.commands = {};
};
Utils.subclass(Driver, Basestar);
Driver.prototype.commands = [];
// Public: Starts up the driver, and triggers the provided callback when done.
//
// callback - function to run when the driver is started

View File

@ -74,7 +74,7 @@ var Robot = module.exports = function Robot(opts) {
this.devices = {};
this.adaptors = {};
this.drivers = {};
this.commands = [];
this.commands = {};
this.running = false;
this.work = opts.work || opts.play;
@ -95,13 +95,31 @@ var Robot = module.exports = function Robot(opts) {
}
for (var n in opts) {
var func = opts[n],
reserved = ['connection', 'connections', 'device', 'devices', 'work'];
var opt = opts[n],
reserved = ['connection', 'connections', 'device', 'devices', 'work', 'commands'];
if (reserved.indexOf(n) < 0) {
this[n] = func;
this[n] = opt;
}
if (opts.commands == null && typeof(opt) === 'function') {
this.commands[n] = opt;
}
}
if (typeof opts.commands === 'function') {
var result = opts.commands.call(this, this);
if (typeof result === 'object' && !Array.isArray(result)) {
this.commands = result;
} else {
throw new Error("commands must be an object or a function that returns an object");
}
}
if (typeof opts.commands === 'object') {
this.commands = opts.commands;
}
};
Utils.subclass(Robot, EventEmitter);
@ -143,7 +161,7 @@ Robot.prototype.toJSON = function() {
name: this.name,
connections: connections,
devices: devices,
commands: this.commands
commands: Object.keys(this.commands)
};
};

View File

@ -11,11 +11,12 @@
var Driver = require('../driver'),
Utils = require('../utils');
var Ping;
module.exports = Ping = function Ping() {
var Ping = module.exports = function Ping() {
Ping.__super__.constructor.apply(this, arguments);
this.commands = ['ping'];
this.commands = {
ping: this.ping
};
};
Utils.subclass(Ping, Driver);
@ -25,4 +26,6 @@ Ping.prototype.ping = function() {
return "pong";
};
Ping.driver = function(opts) { return new Ping(opts); };
Ping.driver = function(opts) {
return new Ping(opts);
};

View File

@ -31,7 +31,7 @@ describe("Driver", function() {
});
it("sets @commands to an empty array by default", function() {
expect(driver.commands).to.be.eql([]);
expect(driver.commands).to.be.eql({});
});
});

View File

@ -84,6 +84,83 @@ describe("Robot", function() {
expect(fn).to.throw(Error, "No connections specified");
});
});
context("if no commands are provided", function() {
var robot;
beforeEach(function() {
robot = new Robot({
name: 'NewBot',
otherThings: { more: 'details' },
sayHello: function() { return "Hello!" }
});
});
it("sets #commands to the additionally provided functions", function() {
expect(robot.commands).to.be.eql({ sayHello: robot.sayHello });
});
});
context("if a commands function is provided", function() {
var robot;
beforeEach(function() {
robot = new Robot({
name: 'NewBot',
sayHello: function() { return this.name + " says hello" },
commands: function() {
return {
say_hello: this.sayHello
}
}
});
});
it("sets #commands to the returned object", function() {
expect(robot.commands.say_hello).to.be.eql(robot.sayHello);
});
context("if the function doesn't return an object", function() {
var fn;
beforeEach(function() {
fn = function() {
new Robot({
name: 'NewBot',
commands: function() {
return [];
}
});
}
});
it("throws an error", function() {
expect(fn).to.throw(Error, "commands must be an object or a function that returns an object");
});
})
});
context("if a commands object is provided", function() {
var robot;
beforeEach(function() {
robot = new Robot({
name: 'NewBot',
sayHello: function() { return this.name + " says hello" },
commands: {
say_hello: function() {}
}
});
});
it("sets #commands to the provided object", function() {
expect(robot.commands.say_hello).to.be.a('function');
});
});
});
describe("all work and no play", function() {
@ -96,7 +173,7 @@ describe("Robot", function() {
it('makes Jack a dull boy', function() {
expect(playBot.work).to.be.eql(play);
})
})
});
describe("#toJSON", function() {
var bot = new Robot({
@ -115,7 +192,7 @@ describe("Robot", function() {
});
it("contains the robot's commands", function() {
expect(json.commands).to.eql(bot.commands);
expect(json.commands).to.eql(Object.keys(bot.commands));
});
it("contains the robot's devices", function() {