Clean up lib for JSHint

This commit is contained in:
Andrew Stewart 2014-12-15 11:15:29 -08:00
parent e2bec78de7
commit ac6b09fe50
22 changed files with 599 additions and 547 deletions

View File

@ -8,9 +8,8 @@
"use strict"; "use strict";
var Basestar = require('./basestar'), var Basestar = require("./basestar"),
Logger = require('./logger'), Utils = require("./utils");
Utils = require('./utils');
// Public: Creates a new Adaptor // Public: Creates a new Adaptor
// //
@ -35,7 +34,7 @@ var Adaptor = module.exports = function Adaptor(opts) {
this.details = {}; this.details = {};
for (var opt in opts) { for (var opt in opts) {
if (['robot', 'name', 'adaptor'].indexOf(opt) < 0) { if (["robot", "name", "adaptor"].indexOf(opt) < 0) {
this.details[opt] = opts[opt]; this.details[opt] = opts[opt];
} }
} }

View File

@ -8,13 +8,13 @@
"use strict"; "use strict";
var fs = require('fs'), var fs = require("fs"),
path = require('path'); path = require("path");
var express = require('express'), var express = require("express"),
bodyParser = require('body-parser'); bodyParser = require("body-parser");
var Logger = require('./logger'); var Logger = require("./logger");
var API = module.exports = function API(opts) { var API = module.exports = function API(opts) {
if (opts == null) { if (opts == null) {
@ -27,7 +27,7 @@ var API = module.exports = function API(opts) {
this.createServer(); this.createServer();
this.express.set('title', 'Cylon API Server'); this.express.set("title", "Cylon API Server");
this.express.use(this.setupAuth()); this.express.use(this.setupAuth());
@ -40,7 +40,7 @@ var API = module.exports = function API(opts) {
this.express.use(function(req, res, next) { this.express.use(function(req, res, next) {
res.set("Access-Control-Allow-Origin", this.CORS || "*"); res.set("Access-Control-Allow-Origin", this.CORS || "*");
res.set("Access-Control-Allow-Headers", "Content-Type"); res.set("Access-Control-Allow-Headers", "Content-Type");
res.set('Content-Type', 'application/json'); res.set("Content-Type", "application/json");
return next(); return next();
}.bind(this)); }.bind(this));
@ -56,19 +56,19 @@ var API = module.exports = function API(opts) {
}); });
// load route definitions // load route definitions
this.express.use('/api', require('./api/routes')); this.express.use("/api", require("./api/routes"));
// error handling // error handling
this.express.use(function(err, req, res, next) { this.express.use(function(err, req, res) {
res.status(500).json({ error: err.message || "An error occured."}) res.status(500).json({ error: err.message || "An error occured."});
}); });
}; };
API.prototype.defaults = { API.prototype.defaults = {
host: '127.0.0.1', host: "127.0.0.1",
port: '3000', port: "3000",
auth: false, auth: false,
CORS: '', CORS: "",
ssl: { ssl: {
key: path.normalize(__dirname + "/api/ssl/server.key"), key: path.normalize(__dirname + "/api/ssl/server.key"),
cert: path.normalize(__dirname + "/api/ssl/server.crt") cert: path.normalize(__dirname + "/api/ssl/server.crt")
@ -79,15 +79,18 @@ API.prototype.createServer = function createServer() {
this.express = express(); this.express = express();
//configure ssl if requested //configure ssl if requested
if (this.ssl && typeof(this.ssl) === 'object') { if (this.ssl && typeof(this.ssl) === "object") {
var https = require('https'); var https = require("https");
this.server = https.createServer({ this.server = https.createServer({
key: fs.readFileSync(this.ssl.key), key: fs.readFileSync(this.ssl.key),
cert: fs.readFileSync(this.ssl.cert) cert: fs.readFileSync(this.ssl.cert)
}, this.express); }, this.express);
} else { } else {
Logger.warn("API using insecure connection. We recommend using an SSL certificate with Cylon."); var str = "API using insecure connection. ";
str += "We recommend using an SSL certificate with Cylon.";
Logger.warn(str);
this.server = this.express; this.server = this.express;
} }
}; };
@ -95,7 +98,7 @@ API.prototype.createServer = function createServer() {
API.prototype.setupAuth = function setupAuth() { API.prototype.setupAuth = function setupAuth() {
var authfn = function auth(req, res, next) { next(); }; var authfn = function auth(req, res, next) { next(); };
if (!!this.auth && typeof(this.auth) === 'object' && this.auth.type) { if (!!this.auth && typeof(this.auth) === "object" && this.auth.type) {
var type = this.auth.type, var type = this.auth.type,
module = "./api/auth/" + type, module = "./api/auth/" + type,
filename = path.normalize(__dirname + "/" + module + ".js"), filename = path.normalize(__dirname + "/" + module + ".js"),
@ -104,17 +107,20 @@ API.prototype.setupAuth = function setupAuth() {
if (exists) { if (exists) {
authfn = require(filename)(this.auth); authfn = require(filename)(this.auth);
} }
}; }
return authfn; return authfn;
}; };
API.prototype.listen = function() { API.prototype.listen = function() {
this.server.listen(this.port, this.host, null, function() { this.server.listen(this.port, this.host, null, function() {
var title = this.express.get('title'); var title = this.express.get("title");
var protocol = this.ssl ? "https" : "http"; var protocol = this.ssl ? "https" : "http",
str;
str = "Listening at " + protocol + "://" + this.host + ":" + this.port;
Logger.info(title + " is now online."); Logger.info(title + " is now online.");
Logger.info("Listening at " + protocol + "://" + this.host + ":" + this.port); Logger.info(str);
}.bind(this)); }.bind(this));
}; };

View File

@ -6,48 +6,14 @@
* Licensed under the Apache 2.0 license. * Licensed under the Apache 2.0 license.
*/ */
var http = require('http'); "use strict";
module.exports = function(config) { var http = require("http");
var user = config.user,
pass = config.pass;
return function auth(req, res, next) {
var auth = req.headers.authorization;
if (!auth) {
return unauthorized(res);
}
// malformed
var parts = auth.split(' ');
if ('basic' != parts[0].toLowerCase() || !parts[1]) {
return next(error(400));
}
auth = parts[1];
// credentials
auth = new Buffer(auth, 'base64').toString();
auth = auth.match(/^([^:]+):(.+)$/);
if (!auth) {
return unauthorized(res);
}
if (auth[1] === user && auth[2] === pass) {
return next();
}
return unauthorized(res);
};
};
var unauthorized = function unauthorized(res) { var unauthorized = function unauthorized(res) {
res.statusCode = 401; res.statusCode = 401;
res.setHeader('WWW-Authenticate', 'Basic realm="Authorization Required"'); res.setHeader("WWW-Authenticate", "Basic realm=\"Authorization Required\"");
res.end('Unauthorized'); res.end("Unauthorized");
}; };
var error = function error(code, msg){ var error = function error(code, msg){
@ -55,3 +21,39 @@ var error = function error(code, msg){
err.status = code; err.status = code;
return err; return err;
}; };
module.exports = function(config) {
var user = config.user,
pass = config.pass;
return function auth(req, res, next) {
var authorization = req.headers.authorization;
if (!authorization) {
return unauthorized(res);
}
// malformed
var parts = authorization.split(" ");
if ("basic" !== parts[0].toLowerCase() || !parts[1]) {
return next(error(400));
}
authorization = parts[1];
// credentials
authorization = new Buffer(authorization, "base64").toString();
authorization = authorization.match(/^([^:]+):(.+)$/);
if (!authorization) {
return unauthorized(res);
}
if (authorization[1] === user && authorization[2] === pass) {
return next();
}
return unauthorized(res);
};
};

View File

@ -1,3 +1,5 @@
/* jshint maxlen: false */
/* /*
* Cylon API - Route Definitions * Cylon API - Route Definitions
* cylonjs.com * cylonjs.com
@ -6,9 +8,11 @@
* Licensed under the Apache 2.0 license. * Licensed under the Apache 2.0 license.
*/ */
var Cylon = require('../cylon'); "use strict";
var router = module.exports = require('express').Router(); var Cylon = require("../cylon");
var router = module.exports = require("express").Router();
// Loads up the appropriate Robot/Device/Connection instances, if they are // Loads up the appropriate Robot/Device/Connection instances, if they are
// present in the route params. // present in the route params.
@ -20,21 +24,27 @@ var load = function load(req, res, next) {
if (robot) { if (robot) {
req.robot = Cylon.robots[robot]; req.robot = Cylon.robots[robot];
if (!req.robot) { if (!req.robot) {
return res.status(404).json({ error: "No Robot found with the name " + robot }); return res.status(404).json({
error: "No Robot found with the name " + robot
});
} }
} }
if (device) { if (device) {
req.device = req.robot.devices[device]; req.device = req.robot.devices[device];
if (!req.device) { if (!req.device) {
return res.status(404).json({ error: "No device found with the name " + device }); return res.status(404).json({
error: "No device found with the name " + device
});
} }
} }
if (connection) { if (connection) {
req.connection = req.robot.connections[connection]; req.connection = req.robot.connections[connection];
if (!req.connection) { if (!req.connection) {
return res.status(404).json({ error: "No connection found with the name " + connection }); return res.status(404).json({
error: "No connection found with the name " + connection
});
} }
} }
@ -85,9 +95,9 @@ router.get("/robots/:robot/devices/:device/events/:event", load, function(req, r
var event = req.params.event; var event = req.params.event;
res.writeHead(200, { res.writeHead(200, {
'Content-Type': 'text/event-stream', "Content-Type": "text/event-stream",
'Connection': 'keep-alive', "Connection": "keep-alive",
'Cache-Control': 'no-cache' "Cache-Control": "no-cache"
}); });
var writeData = function(data) { var writeData = function(data) {
@ -96,7 +106,7 @@ router.get("/robots/:robot/devices/:device/events/:event", load, function(req, r
req.device.on(event, writeData); req.device.on(event, writeData);
res.on('close', function() { res.on("close", function() {
req.device.removeListener(event, writeData); req.device.removeListener(event, writeData);
}); });
}); });

View File

@ -8,9 +8,9 @@
"use strict"; "use strict";
var EventEmitter = require('events').EventEmitter; var EventEmitter = require("events").EventEmitter;
var Utils = require('./utils'); var Utils = require("./utils");
// 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
@ -46,7 +46,7 @@ Basestar.prototype.proxyMethods = function(methods, target, source, force) {
// target // target
// - target - object to proxy event to // - target - object to proxy event to
// - source - object to proxy event from // - source - object to proxy event from
// - sendUpdate - whether or not to send an 'update' event // - sendUpdate - whether or not to send an "update" event
// //
// Returns the source // Returns the source
Basestar.prototype.defineEvent = function(opts) { Basestar.prototype.defineEvent = function(opts) {
@ -59,7 +59,7 @@ Basestar.prototype.defineEvent = function(opts) {
opts.target.emit.apply(opts.target, args); opts.target.emit.apply(opts.target, args);
if (opts.sendUpdate) { if (opts.sendUpdate) {
args.unshift('update'); args.unshift("update");
opts.target.emit.apply(opts.target, args); opts.target.emit.apply(opts.target, args);
} }
}); });
@ -67,8 +67,8 @@ Basestar.prototype.defineEvent = function(opts) {
return opts.source; return opts.source;
}; };
// Public: Creates an event handler that proxies events from an adaptor's // Public: Creates an event handler that proxies events from an adaptor"s
// 'connector' (reference to whatever module is actually talking to the hw) // "connector" (reference to whatever module is actually talking to the hw)
// to the adaptor // to the adaptor
// //
// opts - hash of opts to be passed to defineEvent() // opts - hash of opts to be passed to defineEvent()
@ -78,7 +78,7 @@ Basestar.prototype.defineAdaptorEvent = function(opts) {
return this._proxyEvents(opts, this.connector, this); return this._proxyEvents(opts, this.connector, this);
}; };
// Public: Creates an event handler that proxies events from a driver's // Public: Creates an event handler that proxies events from a driver"s
// connection to the driver // connection to the driver
// //
// opts - hash of opts to be passed to defineEvent() // opts - hash of opts to be passed to defineEvent()
@ -89,10 +89,10 @@ 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 = (typeof opts === "string") ? { eventName: opts } : opts;
opts.source = source; opts.source = source;
opts.target = target opts.target = target;
return this.defineEvent(opts); return this.defineEvent(opts);
} };

View File

@ -6,7 +6,7 @@
* Licensed under the Apache 2.0 license. * Licensed under the Apache 2.0 license.
*/ */
'use strict'; "use strict";
module.exports = { module.exports = {
logging: {}, logging: {},

View File

@ -6,14 +6,13 @@
* Licensed under the Apache 2.0 license. * Licensed under the Apache 2.0 license.
*/ */
'use strict'; "use strict";
var Registry = require('./registry'), var Registry = require("./registry"),
Config = require('./config'), Config = require("./config");
Logger = require('./logger');
var testMode = function() { var testMode = function() {
return process.env.NODE_ENV === 'test' && Config.testMode; return process.env.NODE_ENV === "test" && Config.testMode;
}; };
// Public: Creates a new Adaptor and returns it. // Public: Creates a new Adaptor and returns it.
@ -26,7 +25,8 @@ 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 || {};
@ -37,27 +37,27 @@ module.exports = function Connection(opts) {
} }
if (!module) { if (!module) {
Registry.register('cylon-' + opts.adaptor); Registry.register("cylon-" + opts.adaptor);
module = Registry.findByAdaptor(opts.adaptor); module = Registry.findByAdaptor(opts.adaptor);
} }
var adaptor = module.adaptor(opts); var adaptor = module.adaptor(opts);
for (var prop in adaptor) { for (prop in adaptor) {
if (~['constructor'].indexOf(prop)) { if (~["constructor"].indexOf(prop)) {
continue; continue;
} }
if (typeof adaptor[prop] === 'function') { if (typeof adaptor[prop] === "function") {
adaptor[prop] = adaptor[prop].bind(adaptor); adaptor[prop] = adaptor[prop].bind(adaptor);
} }
} }
if (testMode()) { if (testMode()) {
var testAdaptor = Registry.findByAdaptor('test').adaptor(opts); var testAdaptor = Registry.findByAdaptor("test").adaptor(opts);
for (var prop in adaptor) { for (prop in adaptor) {
if (typeof adaptor[prop] === 'function' && !testAdaptor[prop]) { if (typeof adaptor[prop] === "function" && !testAdaptor[prop]) {
testAdaptor[prop] = function() { return true; }; testAdaptor[prop] = function() { return true; };
} }
} }

View File

@ -8,22 +8,22 @@
"use strict"; "use strict";
var Async = require('async'); 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");
var Cylon = module.exports = { var Cylon = module.exports = {
Logger: Logger, Logger: Logger,
Driver: require('./driver'), Driver: require("./driver"),
Adaptor: require('./adaptor'), Adaptor: require("./adaptor"),
Utils: Utils, Utils: Utils,
IO: { IO: {
DigitalPin: require('./io/digital-pin'), DigitalPin: require("./io/digital-pin"),
Utils: require('./io/utils') Utils: require("./io/utils")
}, },
api_instance: null, api_instance: null,
@ -39,8 +39,8 @@ var Cylon = module.exports = {
// Returns a shiny new Robot // Returns a shiny new Robot
// Examples: // Examples:
// Cylon.robot // Cylon.robot
// connection: { name: 'arduino', adaptor: 'firmata' } // connection: { name: "arduino", adaptor: "firmata" }
// device: { name: 'led', driver: 'led', pin: 13 } // device: { name: "led", driver: "led", pin: 13 }
// //
// work: (me) -> // work: (me) ->
// me.led.toggle() // me.led.toggle()
@ -51,25 +51,29 @@ Cylon.robot = function robot(opts) {
if (opts.name && this.robots[opts.name]) { if (opts.name && this.robots[opts.name]) {
var original = opts.name; var original = opts.name;
opts.name = Utils.makeUnique(original, Object.keys(this.robots)); opts.name = Utils.makeUnique(original, Object.keys(this.robots));
Logger.warn("Robot names must be unique. Renaming '" + original + "' to '" + opts.name + "'");
var str = "Robot names must be unique. Renaming '";
str += original + "' to '" + opts.name + "'";
Logger.warn(str);
} }
var robot = new Robot(opts); var bot = new Robot(opts);
this.robots[robot.name] = robot; this.robots[bot.name] = bot;
return robot; return bot;
}; };
// Public: Creates a new API based on passed options // Public: Creates a new API based on passed options
// //
// Returns nothing // Returns nothing
Cylon.api = function api(opts) { Cylon.api = function api(opts) {
if (typeof opts === 'object') { if (typeof opts === "object") {
this.config({ api: opts }); this.config({ api: opts });
} }
var API = require('./api'); var API = require("./api");
var config = Utils.fetch(Config, 'api', {}); var config = Utils.fetch(Config, "api", {});
this.api_instance = new API(config); this.api_instance = new API(config);
this.api_instance.listen(); this.api_instance.listen();
@ -83,13 +87,14 @@ Cylon.start = function start() {
for (var bot in this.robots) { for (var bot in this.robots) {
starters.push(this.robots[bot].start); starters.push(this.robots[bot].start);
} }
Async.parallel(starters, function(err, results) { 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) { for (var bot in this.robots) {
this.robots[bot].startWork(); this.robots[bot].startWork();
} }
} }
}.bind(this)); }.bind(this));
}; };
@ -101,7 +106,7 @@ Cylon.start = function start() {
Cylon.config = function(opts) { Cylon.config = function(opts) {
var loggingChanged = (opts.logging && Config.logging !== opts.logging); var loggingChanged = (opts.logging && Config.logging !== opts.logging);
if (opts && typeof(opts) === 'object' && !Array.isArray(opts)) { if (opts && typeof(opts) === "object" && !Array.isArray(opts)) {
for (var o in opts) { for (var o in opts) {
Config[o] = opts[o]; Config[o] = opts[o];
} }
@ -120,9 +125,9 @@ Cylon.config = function(opts) {
// //
// Returns nothing // Returns nothing
Cylon.halt = function halt(callback) { Cylon.halt = function halt(callback) {
callback = callback || function() {} callback = callback || function() {};
// 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 = []; var fns = [];
@ -145,7 +150,7 @@ Cylon.toJSON = function() {
return { return {
robots: robots, robots: robots,
commands: Object.keys(this.commands) commands: Object.keys(this.commands)
} };
}; };
if (process.platform === "win32") { if (process.platform === "win32") {

View File

@ -6,13 +6,13 @@
* Licensed under the Apache 2.0 license. * Licensed under the Apache 2.0 license.
*/ */
'use strict'; "use strict";
var Registry = require('./registry'), var Registry = require("./registry"),
Config = require('./config'); Config = require("./config");
var testMode = function() { var testMode = function() {
return process.env.NODE_ENV === 'test' && Config.testMode; return process.env.NODE_ENV === "test" && Config.testMode;
}; };
// Public: Creates a new Device // Public: Creates a new Device
@ -26,7 +26,8 @@ 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);
@ -37,27 +38,27 @@ module.exports = function Device(opts) {
opts.device = this; opts.device = this;
if (!module) { if (!module) {
Registry.register('cylon-' + opts.driver); Registry.register("cylon-" + opts.driver);
module = Registry.findByDriver(opts.driver); module = Registry.findByDriver(opts.driver);
} }
var driver = module.driver(opts); var driver = module.driver(opts);
for (var prop in driver) { for (prop in driver) {
if (~['constructor'].indexOf(prop)) { if (~["constructor"].indexOf(prop)) {
continue; continue;
} }
if (typeof driver[prop] === 'function') { if (typeof driver[prop] === "function") {
driver[prop] = driver[prop].bind(driver); driver[prop] = driver[prop].bind(driver);
} }
} }
if (testMode()) { if (testMode()) {
var testDriver = Registry.findByDriver('test').driver(opts); var testDriver = Registry.findByDriver("test").driver(opts);
for (var prop in driver) { for (prop in driver) {
if (typeof driver[prop] === 'function' && !testDriver[prop]) { if (typeof driver[prop] === "function" && !testDriver[prop]) {
testDriver[prop] = function() { return true; }; testDriver[prop] = function() { return true; };
} }
} }

View File

@ -6,11 +6,10 @@
* Licensed under the Apache 2.0 license. * Licensed under the Apache 2.0 license.
*/ */
'use strict'; "use strict";
var Basestar = require('./basestar'), var Basestar = require("./basestar"),
Logger = require('./logger'), Utils = require("./utils");
Utils = require('./utils');
// Public: Creates a new Driver // Public: Creates a new Driver
// //
@ -23,7 +22,7 @@ var Driver = module.exports = function Driver(opts) {
opts = opts || {}; opts = opts || {};
this.name = opts.name; this.name = opts.name;
this.robot = opts.robot this.robot = opts.robot;
this.connection = opts.connection; this.connection = opts.connection;
@ -36,7 +35,7 @@ var Driver = module.exports = function Driver(opts) {
this.details = {}; this.details = {};
for (var opt in opts) { for (var opt in opts) {
if (['robot', 'name', 'connection', 'driver'].indexOf(opt) < 0) { if (["robot", "name", "connection", "driver"].indexOf(opt) < 0) {
this.details[opt] = opts[opt]; this.details[opt] = opts[opt];
} }
} }
@ -62,11 +61,11 @@ Driver.prototype.setupCommands = function(commands, proxy) {
} }
return "_" + match.toLowerCase(); return "_" + match.toLowerCase();
}).replace(/^_/, ''); }).replace(/^_/, "");
this.commands[snake_case] = this[command]; this.commands[snake_case] = this[command];
} }
} };
Driver.prototype.toJSON = function() { Driver.prototype.toJSON = function() {
return { return {

View File

@ -8,24 +8,21 @@
"use strict"; "use strict";
var FS = require('fs'), var FS = require("fs"),
EventEmitter = require('events').EventEmitter; EventEmitter = require("events").EventEmitter;
var Utils = require('../utils'); var Utils = require("../utils");
var GPIO_PATH = "/sys/class/gpio"; var GPIO_PATH = "/sys/class/gpio";
var GPIO_READ = "in"; var GPIO_READ = "in";
var GPIO_WRITE = "out"; var GPIO_WRITE = "out";
var HIGH = 1;
var LOW = 0;
// DigitalPin class offers an interface with the Linux GPIO system present in // DigitalPin class offers an interface with the Linux GPIO system present in
// single-board computers such as a Raspberry Pi, or a BeagleBone // single-board computers such as a Raspberry Pi, or a BeagleBone
var DigitalPin = module.exports = function DigitalPin(opts) { var DigitalPin = module.exports = function DigitalPin(opts) {
this.pinNum = opts.pin.toString(); this.pinNum = opts.pin.toString();
this.status = 'low'; this.status = "low";
this.ready = false; this.ready = false;
this.mode = opts.mode; this.mode = opts.mode;
}; };
@ -38,7 +35,11 @@ DigitalPin.prototype.connect = function(mode) {
} }
FS.exists(this._pinPath(), function(exists) { FS.exists(this._pinPath(), function(exists) {
exists ? this._openPin() : this._createGPIOPin(); if (exists) {
this._openPin();
} else {
this._createGPIOPin();
}
}.bind(this)); }.bind(this));
}; };
@ -54,40 +55,43 @@ DigitalPin.prototype.closeSync = function() {
}; };
DigitalPin.prototype.digitalWrite = function(value) { DigitalPin.prototype.digitalWrite = function(value) {
if (this.mode !== 'w') { if (this.mode !== "w") {
this._setMode('w'); this._setMode("w");
} }
this.status = value === 1 ? 'high' : 'low'; this.status = value === 1 ? "high" : "low";
FS.writeFile(this._valuePath(), value, function(err) { FS.writeFile(this._valuePath(), value, function(err) {
if (err) { if (err) {
this.emit('error', "Error occurred while writing value " + value + " to pin " + this.pinNum); var str = "Error occurred while writing value ";
str += value + " to pin " + this.pinNum;
this.emit("error", str);
} else { } else {
this.emit('digitalWrite', value); this.emit("digitalWrite", value);
} }
}.bind(this)); }.bind(this));
return value; return value;
}; };
// Public: Reads the digial pin's value periodicly on a supplied interval, // Public: Reads the digial pin"s value periodicly on a supplied interval,
// and emits the result or an error // and emits the result or an error
// //
// interval - time (in milliseconds) to read from the pin at // interval - time (in milliseconds) to read from the pin at
// //
// Returns the defined interval // Returns the defined interval
DigitalPin.prototype.digitalRead = function(interval) { DigitalPin.prototype.digitalRead = function(interval) {
if (this.mode !== 'r') { this._setMode('r'); } if (this.mode !== "r") { this._setMode("r"); }
Utils.every(interval, function() { Utils.every(interval, function() {
FS.readFile(this._valuePath(), function(err, data) { FS.readFile(this._valuePath(), function(err, data) {
if (err) { if (err) {
var error = "Error occurred while reading from pin " + this.pinNum; var error = "Error occurred while reading from pin " + this.pinNum;
this.emit('error', error); this.emit("error", error);
} else { } else {
var readData = parseInt(data.toString()); var readData = parseInt(data.toString());
this.emit('digitalRead', readData); this.emit("digitalRead", readData);
} }
}.bind(this)); }.bind(this));
}.bind(this)); }.bind(this));
@ -102,14 +106,14 @@ DigitalPin.prototype.setLow = function() {
}; };
DigitalPin.prototype.toggle = function() { DigitalPin.prototype.toggle = function() {
return (this.status === 'low') ? this.setHigh() : this.setLow(); return (this.status === "low") ? this.setHigh() : this.setLow();
}; };
// Creates the GPIO file to read/write from // Creates the GPIO file to read/write from
DigitalPin.prototype._createGPIOPin = function() { DigitalPin.prototype._createGPIOPin = function() {
FS.writeFile(this._exportPath(), this.pinNum, function(err) { FS.writeFile(this._exportPath(), this.pinNum, function(err) {
if (err) { if (err) {
this.emit('error', 'Error while creating pin files'); this.emit("error", "Error while creating pin files");
} else { } else {
this._openPin(); this._openPin();
} }
@ -118,24 +122,24 @@ DigitalPin.prototype._createGPIOPin = function() {
DigitalPin.prototype._openPin = function() { DigitalPin.prototype._openPin = function() {
this._setMode(this.mode, true); this._setMode(this.mode, true);
this.emit('open'); this.emit("open");
}; };
DigitalPin.prototype._closeCallback = function(err) { DigitalPin.prototype._closeCallback = function(err) {
if (err) { if (err) {
this.emit('error', 'Error while closing pin files'); this.emit("error", "Error while closing pin files");
} else { } else {
this.emit('close', this.pinNum); this.emit("close", this.pinNum);
} }
}; };
// Sets the mode for the GPIO pin by writing the correct values to the pin reference files // Sets the mode for the pin by writing the values to the pin reference files
DigitalPin.prototype._setMode = function(mode, emitConnect) { DigitalPin.prototype._setMode = function(mode, emitConnect) {
if (emitConnect == null) { emitConnect = false; } if (emitConnect == null) { emitConnect = false; }
this.mode = mode; this.mode = mode;
var data = (mode === 'w') ? GPIO_WRITE : GPIO_READ; var data = (mode === "w") ? GPIO_WRITE : GPIO_READ;
FS.writeFile(this._directionPath(), data, function(err) { FS.writeFile(this._directionPath(), data, function(err) {
this._setModeCallback(err, emitConnect); this._setModeCallback(err, emitConnect);
@ -144,13 +148,13 @@ DigitalPin.prototype._setMode = function(mode, emitConnect) {
DigitalPin.prototype._setModeCallback = function(err, emitConnect) { DigitalPin.prototype._setModeCallback = function(err, emitConnect) {
if (err) { if (err) {
return this.emit('error', "Setting up pin direction failed"); return this.emit("error", "Setting up pin direction failed");
} }
this.ready = true; this.ready = true;
if (emitConnect) { if (emitConnect) {
this.emit('connect', this.mode); this.emit("connect", this.mode);
} }
}; };

View File

@ -1,11 +1,13 @@
Utils = { "use strict";
module.exports = {
// Returns { period: int, duty: int } // Returns { period: int, duty: int }
// Calculated based on params value, freq, pulseWidth = { min: int, max: int } // Calculated based on params value, freq, pulseWidth = { min: int, max: int }
// pulseWidth min and max need to be specified in microseconds // pulseWidth min and max need to be specified in microseconds
periodAndDuty: function(scaledDuty, freq, pulseWidth, polarity) { periodAndDuty: function(scaledDuty, freq, pulseWidth, polarity) {
var period, duty, maxDuty; var period, duty, maxDuty;
polarity = polarity || 'high'; polarity = polarity || "high";
period = Math.round(1.0e9 / freq); period = Math.round(1.0e9 / freq);
if (pulseWidth != null) { if (pulseWidth != null) {
@ -18,12 +20,10 @@ Utils = {
duty = Math.round(period * scaledDuty); duty = Math.round(period * scaledDuty);
} }
if (polarity == 'low') { if (polarity === "low") {
duty = period - duty; duty = period - duty;
} }
return { period: period, duty: duty }; return { period: period, duty: duty };
} }
}; };
module.exports = Utils;

View File

@ -10,55 +10,15 @@
var levels = ["debug", "info", "warn", "error", "fatal"]; 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");
// The Logger is a global object to facilitate logging stuff to the console (or // The Logger is a global object to facilitate logging stuff to the console (or
// other output) easily and consistently. It's available anywhere in Cylon, as // other output) easily and consistently. It"s available anywhere in Cylon, as
// well as in external modules that are loaded into Cylon // well as in external modules that are loaded into Cylon
var Logger = module.exports = {}; var Logger = module.exports = {};
// Public: Creates a Logger instance and assigns it to @logger
//
// logger - logger object to use. Defaults to a BasicLogger, or a NullLogger if
// false is supplied
//
// level - logging level to use. if supplied, will only log to specified level
// or above
//
// Returns the new logger instance
Logger.setup = function setup(opts) {
var Cylon = require('./cylon');
if (typeof opts === 'object') {
Cylon.config({ logging: opts });
}
var logger = Config.logging.logger,
level = Config.logging.level || "info";
if (logger == null) { logger = BasicLogger; }
this.logger = logger || NullLogger;
if (typeof level === 'string') {
setLogLevel(level);
}
return this.logger;
};
Logger.toString = function() {
return this.logger.toString();
};
levels.forEach(function(level) {
Logger[level] = function() {
return this.logger[level].apply(this.logger, arguments);
};
});
var setLogLevel = function(level) { var setLogLevel = function(level) {
var index = levels.indexOf(level), var index = levels.indexOf(level),
active, active,
@ -80,7 +40,47 @@ var setLogLevel = function(level) {
ignored.forEach(function(level) { ignored.forEach(function(level) {
Logger[level] = function() {}; Logger[level] = function() {};
}); });
} };
// Public: Creates a Logger instance and assigns it to @logger
//
// logger - logger object to use. Defaults to a BasicLogger, or a NullLogger if
// false is supplied
//
// level - logging level to use. if supplied, will only log to specified level
// or above
//
// Returns the new logger instance
Logger.setup = function setup(opts) {
var Cylon = require("./cylon");
if (typeof opts === "object") {
Cylon.config({ logging: opts });
}
var logger = Config.logging.logger,
level = Config.logging.level || "info";
if (logger == null) { logger = BasicLogger; }
this.logger = logger || NullLogger;
if (typeof level === "string") {
setLogLevel(level);
}
return this.logger;
};
Logger.toString = function() {
return this.logger.toString();
};
levels.forEach(function(level) {
Logger[level] = function() {
return this.logger[level].apply(this.logger, arguments);
};
});
Logger.setup(); Logger.setup();

View File

@ -1,4 +1,4 @@
'use strict'; "use strict";
var getArgs = function(args) { var getArgs = function(args) {
return args.length >= 1 ? [].slice.call(args, 0) : []; return args.length >= 1 ? [].slice.call(args, 0) : [];
@ -6,10 +6,10 @@ var getArgs = function(args) {
var logString = function(type) { var logString = function(type) {
var time = new Date().toISOString(), var time = new Date().toISOString(),
type = String(type).toUpperCase(), upcase = String(type).toUpperCase(),
padded = String(" " + type).slice(-5); padded = String(" " + upcase).slice(-5);
return type[0] + ", [" + time + "] " + padded + " -- :"; return upcase[0] + ", [" + time + "] " + padded + " -- :";
}; };
// The BasicLogger logs to console.log // The BasicLogger logs to console.log
@ -17,7 +17,7 @@ var BasicLogger = module.exports = {
toString: function() { return "BasicLogger"; }, toString: function() { return "BasicLogger"; },
}; };
['debug', 'info', 'warn', 'error', 'fatal'].forEach(function(type) { ["debug", "info", "warn", "error", "fatal"].forEach(function(type) {
BasicLogger[type] = function() { BasicLogger[type] = function() {
var args = getArgs(arguments); var args = getArgs(arguments);
return console.log.apply(console, [].concat(logString(type), args)); return console.log.apply(console, [].concat(logString(type), args));

View File

@ -1,9 +1,11 @@
"use strict";
// The NullLogger is designed for cases where you want absolutely nothing to // The NullLogger is designed for cases where you want absolutely nothing to
// print to anywhere. Every proxied method from the Logger returns a noop. // print to anywhere. Every proxied method from the Logger returns a noop.
var NullLogger = module.exports = { var NullLogger = module.exports = {
toString: function() { return "NullLogger"; } toString: function() { return "NullLogger"; }
}; };
['debug', 'info', 'warn', 'error', 'fatal'].forEach(function(type) { ["debug", "info", "warn", "error", "fatal"].forEach(function(type) {
NullLogger[type] = function() {}; NullLogger[type] = function() {};
}); });

View File

@ -12,21 +12,22 @@
"use strict"; "use strict";
var Logger = require('./logger'); var Logger = require("./logger");
// Explicitly these modules here, so Browserify can grab them later // Explicitly these modules here, so Browserify can grab them later
require('./test/loopback'); require("./test/loopback");
require('./test/test-adaptor'); require("./test/test-adaptor");
require('./test/test-driver'); require("./test/test-driver");
require('./test/ping'); require("./test/ping");
var missingModuleError = function(module) { var missingModuleError = function(module) {
var string = "Cannot find the '" + module + "' module.\n"; var str = "Cannot find the '" + module + "' module.\n";
string += "This problem might be fixed by installing it with 'npm install " + module + "' and trying again."; str += "This problem might be fixed by installing it with ";
str +="'npm install " + module + "' and trying again.";
console.log(string); console.log(str);
process.emit('SIGINT'); process.emit("SIGINT");
}; };
var Registry = module.exports = { var Registry = module.exports = {
@ -86,7 +87,7 @@ var Registry = module.exports = {
Logger.debug("Registering module " + name); Logger.debug("Registering module " + name);
['adaptors', 'drivers', 'dependencies'].forEach(function(field) { ["adaptors", "drivers", "dependencies"].forEach(function(field) {
if (module[field].length) { if (module[field].length) {
Logger.debug(" " + field + ":"); Logger.debug(" " + field + ":");
module[field].forEach(function(item) { module[field].forEach(function(item) {
@ -110,6 +111,6 @@ var Registry = module.exports = {
}; };
// Default drivers/adaptors: // Default drivers/adaptors:
['loopback', 'ping', 'test-adaptor', 'test-driver'].forEach(function(module) { ["loopback", "ping", "test-adaptor", "test-driver"].forEach(function(module) {
Registry.register('./test/' + module); Registry.register("./test/" + module);
}); });

View File

@ -6,25 +6,16 @@
* Licensed under the Apache 2.0 license. * Licensed under the Apache 2.0 license.
*/ */
'use strict'; "use strict";
var Connection = require("./connection"), var initConnection = require("./connection"),
Device = require("./device"), initDevice = require("./device"),
Logger = require('./logger'), Logger = require("./logger"),
Utils = require('./utils'), Utils = require("./utils"),
Config = require('./config'); Config = require("./config");
var Async = require("async"), var Async = require("async"),
EventEmitter = require('events').EventEmitter; EventEmitter = require("events").EventEmitter;
var missingModuleError = function(module) {
var string = "Cannot find the '" + module + "' module. ";
string += "Please install it with 'npm install " + module + "' and try again.";
console.log(string);
process.emit('SIGINT');
};
// Public: Creates a new Robot // Public: Creates a new Robot
// //
@ -40,10 +31,10 @@ var missingModuleError = function(module) {
// name: "Spherobot!" // name: "Spherobot!"
// //
// connection: // connection:
// name: 'sphero', adaptor: 'sphero', port: '/dev/rfcomm0' // name: "sphero", adaptor: "sphero", port: "/dev/rfcomm0"
// //
// device: // device:
// name: 'sphero', driver: 'sphero' // name: "sphero", driver: "sphero"
// //
// work: (me) -> // work: (me) ->
// Utils.every 1.second(), -> // Utils.every 1.second(), ->
@ -90,7 +81,7 @@ var Robot = module.exports = function Robot(opts) {
this[n] = opt; this[n] = opt;
if (typeof opt === 'function' && opts.commands == null) { if (typeof opt === "function" && opts.commands == null) {
this.commands[n] = opt; this.commands[n] = opt;
} }
} }
@ -98,14 +89,14 @@ var Robot = module.exports = function Robot(opts) {
if (opts.commands) { if (opts.commands) {
var cmds = opts.commands; var cmds = opts.commands;
if (typeof cmds === 'object') { if (typeof cmds === "object") {
this.commands = cmds; this.commands = cmds;
} }
if (typeof cmds === 'function') { if (typeof cmds === "function") {
var result = cmds.call(this, this); var result = cmds.call(this, this);
if (typeof result === 'object' && !Array.isArray(result)) { if (typeof result === "object" && !Array.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");
@ -113,10 +104,10 @@ var Robot = module.exports = function Robot(opts) {
} }
} }
var mode = Utils.fetch(Config, 'mode', 'manual'); var mode = Utils.fetch(Config, "mode", "manual");
if (mode === 'auto') { if (mode === "auto") {
// run on the next tick, to allow for 'work' event handlers to be set up // run on the next tick, to allow for "work" event handlers to be set up
setTimeout(this.start, 0); setTimeout(this.start, 0);
} }
}; };
@ -159,12 +150,16 @@ Robot.prototype.connection = function(name, conn) {
conn.name = name; conn.name = name;
if (this.connections[conn.name]) { if (this.connections[conn.name]) {
var original = conn.name; var original = conn.name,
str;
conn.name = Utils.makeUnique(original, Object.keys(this.connections)); conn.name = Utils.makeUnique(original, Object.keys(this.connections));
Logger.warn("Connection names must be unique. Renaming '" + original + "' to '" + conn.name + "'");
str = "Connection names must be unique.";
str += "Renaming '" + original + "' to '" + conn.name + "'";
Logger.warn(str);
} }
this.connections[conn.name] = Connection(conn); this.connections[conn.name] = initConnection(conn);
return this; return this;
}; };
@ -177,6 +172,8 @@ Robot.prototype.connection = function(name, conn) {
Robot.prototype.initConnections = function(opts) { Robot.prototype.initConnections = function(opts) {
Logger.info("Initializing connections."); Logger.info("Initializing connections.");
var str;
var isArray = Array.isArray; var isArray = Array.isArray;
if (opts.connection == null && opts.connections == null) { if (opts.connection == null && opts.connections == null) {
@ -184,19 +181,27 @@ Robot.prototype.initConnections = function(opts) {
} }
if (opts.connection) { if (opts.connection) {
Logger.warn("Specifying a single connection with the 'connection' key is deprecated, and will be removed in 1.0.0."); str = "Specifying a single connection with the 'connection' key ";
str += "is deprecated. It will be removed in 1.0.0.";
Logger.warn(str);
this.connection(opts.connection.name, opts.connection); this.connection(opts.connection.name, opts.connection);
return this.connections; return this.connections;
} }
if (typeof opts.connections == 'object' && !isArray(opts.connections)) { if (typeof opts.connections === "object" && !isArray(opts.connections)) {
for (var name in opts.connections) { for (var name in opts.connections) {
this.connection(name, opts.connections[name]); this.connection(name, opts.connections[name]);
} }
} }
if (isArray(opts.connections)) { if (isArray(opts.connections)) {
Logger.warn("Specifying connections as an array is deprecated, and will be removed in 1.0.0."); str = "Specifying connections as an array is deprecated. ";
str += "It will be removed in 1.0.0.";
Logger.warn(str);
opts.connections.forEach(function(conn) { opts.connections.forEach(function(conn) {
this.connection(conn.name, conn); this.connection(conn.name, conn);
}, this); }, this);
@ -206,20 +211,25 @@ Robot.prototype.initConnections = function(opts) {
}; };
Robot.prototype.device = function(name, device) { Robot.prototype.device = function(name, device) {
var str;
device.robot = this; device.robot = this;
device.name = name; device.name = name;
if (this.devices[device.name]) { if (this.devices[device.name]) {
var original = device.name; var original = device.name;
device.name = Utils.makeUnique(original, Object.keys(this.devices)); device.name = Utils.makeUnique(original, Object.keys(this.devices));
Logger.warn("Device names must be unique. Renaming '" + original + "' to '" + device.name + "'");
str = "Device names must be unique.";
str += "Renaming '" + original + "' to '" + device.name + "'";
Logger.warn(str);
} }
if (typeof device.connection === 'string') { if (typeof device.connection === "string") {
if (this.connections[device.connection] == null) { if (this.connections[device.connection] == null) {
var str = "No connection found with the name " + device.connection + ".\n"; str = "No connection found with the name " + device.connection + ".\n";
Logger.fatal(str); Logger.fatal(str);
process.emit('SIGINT'); process.emit("SIGINT");
} }
device.connection = this.connections[device.connection]; device.connection = this.connections[device.connection];
@ -230,10 +240,10 @@ Robot.prototype.device = function(name, device) {
} }
} }
this.devices[device.name] = Device(device); this.devices[device.name] = initDevice(device);
return this; return this;
} };
// Public: Initializes all devices for the robot // Public: Initializes all devices for the robot
// //
@ -241,9 +251,10 @@ Robot.prototype.device = function(name, device) {
// //
// Returns initialized devices // Returns initialized devices
Robot.prototype.initDevices = function(opts) { Robot.prototype.initDevices = function(opts) {
Logger.info("Initializing devices."); var isArray = Array.isArray,
str;
var isArray = Array.isArray; Logger.info("Initializing devices.");
if (opts.device == null && opts.devices == null) { if (opts.device == null && opts.devices == null) {
return this.devices; return this.devices;
@ -251,23 +262,28 @@ Robot.prototype.initDevices = function(opts) {
// check that there are connections to use // check that there are connections to use
if (!Object.keys(this.connections).length) { if (!Object.keys(this.connections).length) {
throw new Error("No connections specified") throw new Error("No connections specified");
} }
if (opts.device) { if (opts.device) {
Logger.warn("Specifying a single device with the 'device' key is deprecated, and will be removed in 1.0.0."); str = "Specifying a single device with the 'device' key is deprecated. ";
str += "It will be removed in 1.0.0.";
Logger.warn(str);
this.device(opts.device.name, opts.device); this.device(opts.device.name, opts.device);
return this.devices; return this.devices;
} }
if (typeof opts.devices == 'object' && !isArray(opts.devices)) { if (typeof opts.devices === "object" && !isArray(opts.devices)) {
for (var name in opts.devices) { for (var name in opts.devices) {
this.device(name, opts.devices[name]); this.device(name, opts.devices[name]);
} }
} }
if (isArray(opts.devices)) { if (isArray(opts.devices)) {
Logger.warn("Specifying devices as an array is deprecated, and will be removed in 1.0.0."); str = "Specifying devices as an array is deprecated.";
str += "It will be removed in 1.0.0.";
Logger.warn(str);
opts.devices.forEach(function(device) { opts.devices.forEach(function(device) {
this.device(device.name, device); this.device(device.name, device);
}, this); }, this);
@ -286,13 +302,13 @@ Robot.prototype.start = function(callback) {
return this; return this;
} }
var mode = Utils.fetch(Config, 'workMode', 'async'); var mode = Utils.fetch(Config, "workMode", "async");
Async.series([ Async.series([
this.startConnections, this.startConnections,
this.startDevices, this.startDevices,
function(callback) { function(callback) {
if (mode === 'async') { if (mode === "async") {
this.startWork(); this.startWork();
} }
callback(null, true); callback(null, true);
@ -301,12 +317,12 @@ Robot.prototype.start = function(callback) {
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 (typeof(callback) === "function") {
callback(err, results); callback(err, results);
} }
}.bind(this)); }.bind(this));
@ -314,20 +330,20 @@ Robot.prototype.start = function(callback) {
return this; return this;
}; };
// Public: Starts the Robot's work and triggers a callback // Public: Starts the Robot"s work and triggers a callback
// //
// callback - callback function to be triggered // callback - callback function to be triggered
// //
// Returns nothing // Returns nothing
Robot.prototype.startWork = function() { Robot.prototype.startWork = function() {
Logger.info('Working.'); Logger.info("Working.");
this.emit('ready', this); this.emit("ready", this);
this.work.call(this, this); this.work.call(this, this);
this.running = true; this.running = true;
}; };
// Public: Starts the Robot's connections and triggers a callback // Public: Starts the Robot"s connections and triggers a callback
// //
// callback - callback function to be triggered // callback - callback function to be triggered
// //
@ -355,7 +371,7 @@ Robot.prototype.startConnections = function(callback) {
return Async.parallel(starters, callback); return Async.parallel(starters, callback);
}; };
// Public: Starts the Robot's devices and triggers a callback // Public: Starts the Robot"s devices and triggers a callback
// //
// callback - callback function to be triggered // callback - callback function to be triggered
// //

View File

@ -8,8 +8,8 @@
"use strict"; "use strict";
var Adaptor = require('../adaptor'), var Adaptor = require("../adaptor"),
Utils = require('../utils'); Utils = require("../utils");
var Loopback; var Loopback;
@ -27,5 +27,5 @@ Loopback.prototype.disconnect = function(callback) {
callback(); callback();
}; };
Loopback.adaptors = ['loopback']; Loopback.adaptors = ["loopback"];
Loopback.adaptor = function(opts) { return new Loopback(opts); }; Loopback.adaptor = function(opts) { return new Loopback(opts); };

View File

@ -6,10 +6,10 @@
* Licensed under the Apache 2.0 license. * Licensed under the Apache 2.0 license.
*/ */
'use strict'; "use strict";
var Driver = require('../driver'), var Driver = require("../driver"),
Utils = require('../utils'); Utils = require("../utils");
var Ping = module.exports = function Ping() { var Ping = module.exports = function Ping() {
Ping.__super__.constructor.apply(this, arguments); Ping.__super__.constructor.apply(this, arguments);
@ -22,7 +22,7 @@ var Ping = module.exports = function Ping() {
Utils.subclass(Ping, Driver); Utils.subclass(Ping, Driver);
Ping.prototype.ping = function() { Ping.prototype.ping = function() {
this.emit('ping', 'ping'); this.emit("ping", "ping");
return "pong"; return "pong";
}; };
@ -34,5 +34,5 @@ Ping.prototype.halt = function(callback) {
callback(); callback();
}; };
Ping.drivers = ['ping']; Ping.drivers = ["ping"];
Ping.driver = function(opts) { return new Ping(opts); }; Ping.driver = function(opts) { return new Ping(opts); };

View File

@ -8,8 +8,8 @@
"use strict"; "use strict";
var Adaptor = require('../adaptor'), var Adaptor = require("../adaptor"),
Utils = require('../utils'); Utils = require("../utils");
var TestAdaptor; var TestAdaptor;
@ -19,5 +19,5 @@ module.exports = TestAdaptor = function TestAdaptor() {
Utils.subclass(TestAdaptor, Adaptor); Utils.subclass(TestAdaptor, Adaptor);
TestAdaptor.adaptors = ['test']; TestAdaptor.adaptors = ["test"];
TestAdaptor.adaptor = function(opts) { return new TestAdaptor(opts); }; TestAdaptor.adaptor = function(opts) { return new TestAdaptor(opts); };

View File

@ -6,10 +6,10 @@
* Licensed under the Apache 2.0 license. * Licensed under the Apache 2.0 license.
*/ */
'use strict'; "use strict";
var Driver = require('../driver'), var Driver = require("../driver"),
Utils = require('../utils'); Utils = require("../utils");
var TestDriver; var TestDriver;
@ -19,5 +19,5 @@ module.exports = TestDriver = function TestDriver() {
Utils.subclass(TestDriver, Driver); Utils.subclass(TestDriver, Driver);
TestDriver.drivers = ['test']; TestDriver.drivers = ["test"];
TestDriver.driver = function(opts) { return new TestDriver(opts); }; TestDriver.driver = function(opts) { return new TestDriver(opts); };

View File

@ -6,248 +6,12 @@
* Licensed under the Apache 2.0 license. * Licensed under the Apache 2.0 license.
*/ */
var Utils = module.exports = { "use strict";
// Public: Alias to setInterval, combined with Number monkeypatches below to
// create an artoo-like syntax.
//
// interval - interval to run action on
// action - action to perform at interval
//
// Examples
//
// every((5).seconds(), function() {
// console.log('Hello world (and again in 5 seconds)!');
// });
//
// Returns an interval
every: function every(interval, action) {
return setInterval(action, interval);
},
// Public: Alias to setTimeout, combined with Number monkeypatches below to
// create an artoo-like syntax.
//
// interval - interval to run action on
// action - action to perform at interval
//
// Examples
//
// after((10).seconds(), function() {
// console.log('Hello world from ten seconds ago!');
// });
//
// Returns an interval
after: function after(delay, action) {
return setTimeout(action, delay);
},
// Public: Alias to the `every` function, but passing 0
// Examples
//
// constantly(function() {
// console.log('hello world (and again and again)!');
// });
//
// Returns an interval
constantly: function constantly(action) {
return every(0, action);
},
// Public: Sleep - do nothing for some duration of time.
//
// ms - number of ms to sleep for
//
// Examples
//
// sleep((1).second());
//
// Returns a function
sleep: function sleep(ms) {
var start = Date.now();
while(Date.now() < start + ms) {
var i = 0;
}
},
// Public: Function to use for class inheritance. Copy of a CoffeeScript helper
// function.
//
// Example
//
// var Sphero = function Sphero() {};
//
// subclass(Sphero, ParentClass);
//
// // Sphero is now a subclass of Parent, and can access parent methods
// // through Sphero.__super__
//
// Returns subclass
subclass: function subclass(child, parent) {
var ctor = function() {
this.constructor = child;
};
for (var key in parent) {
if (Object.hasOwnProperty.call(parent, key)) {
child[key] = parent[key];
}
}
ctor.prototype = parent.prototype;
child.prototype = new ctor();
child.__super__ = parent.prototype;
return child;
},
proxyFunctions: function proxyFunctions(source, target) {
for (var opt in source) {
if (!target[opt] && typeof source[opt] === 'function') {
target[opt] = source[opt].bind(source);
}
}
},
// Public: Proxies a list of methods from one object to another. It will not
// overwrite existing methods unless told to.
//
// methods - array of functions to proxy
// target - object to proxy the functions to
// base - (optional) object that proxied functions will be declared on. Defaults
// to this
// force - (optional) boolean - whether or not to force method assignment
//
// Returns base
proxyFunctionsToObject: function proxyFunctionsToObject(methods, target, base, force) {
if (base == null) {
base = this;
}
if (force == null) {
force = false;
}
var proxy = function(method) {
return base[method] = function() {
return target[method].apply(target, arguments);
};
};
for (var i = 0; i < methods.length; i++) {
var method = methods[i];
if (!force && typeof(base[method]) === 'function') {
continue;
}
proxy(method);
}
return base;
},
// Public: Analogue to Ruby's Hash#fetch method for looking up object
// properties.
//
// obj - object to do property lookup on
// property - string property name to attempt to look up
// fallback - either:
// - a fallback value to return if `property` can't be found
// - a function to be executed if `property` can't be found. The function
// will be passed `property` as an argument.
//
// Examples
//
// var object = { property: "hello world" };
// fetch(object, "property");
// //=> "hello world"
//
// fetch(object, "notaproperty", "default value");
// //=> "default value"
//
// var notFound = function(prop) { return prop + " not found!" };
// fetch(object, "notaproperty", notFound)
// // "notaproperty not found!"
//
// var badFallback = function(prop) { prop + " not found!" };
// fetch(object, "notaproperty", badFallback)
// // Error: no return value from provided callback function
//
// fetch(object, "notaproperty");
// // Error: key not found: "notaproperty"
//
// Returns the value of obj[property], a fallback value, or the results of
// running 'fallback'. If the property isn't found, and 'fallback' hasn't been
// provided, will throw an error.
fetch: function(obj, property, fallback) {
if (obj.hasOwnProperty(property)) {
return obj[property];
}
if (fallback === void 0) {
throw new Error('key not found: "' + property + '"');
}
if (typeof(fallback) === 'function') {
var value = fallback(property);
if (value === void 0) {
throw new Error('no return value from provided fallback function');
}
return value;
}
return fallback;
},
// Public: Given a name, and an array of existing names, returns a unique
// name.
//
// name - name that's colliding with existing names
// arr - array of existing names
//
// Returns the new name as a string
makeUnique: function(name, arr) {
var newName;
if (!~arr.indexOf(name)) {
return name;
}
for (var n = 1; ; n++) {
newName = name + "-" + n;
if (!~arr.indexOf(newName)) {
return newName;
}
}
},
// Public: Adds necessary utils to global namespace, along with base class
// extensions.
//
// Examples
//
// Number.prototype.seconds // undefined
// after // undefined
//
// Utils.bootstrap();
//
// Number.prototype.seconds // [function]
// (after === Utils.after) // true
//
// Returns Cylon.Utils
bootstrap: function bootstrap() {
global.every = this.every;
global.after = this.after;
global.constantly = this.constantly;
addCoreExtensions();
return this;
}
};
var addCoreExtensions = function addCoreExtensions() { var addCoreExtensions = function addCoreExtensions() {
var max = Math.max,
min = Math.min;
// Public: Monkey-patches Number to have Rails-like //seconds() function. // Public: Monkey-patches Number to have Rails-like //seconds() function.
// Warning, due to the way the Javascript parser works, applying functions on // Warning, due to the way the Javascript parser works, applying functions on
// numbers is kind of weird. See examples for details. // numbers is kind of weird. See examples for details.
@ -294,7 +58,7 @@ var addCoreExtensions = function addCoreExtensions() {
// //
// Returns an integer representing the scaled value // Returns an integer representing the scaled value
Number.prototype.fromScale = function(start, end) { Number.prototype.fromScale = function(start, end) {
var val = (this - Math.min(start, end)) / (Math.max(start, end) - Math.min(start, end)); var val = (this - min(start, end)) / (max(start, end) - min(start, end));
if (val > 1) { if (val > 1) {
return 1; return 1;
@ -319,7 +83,7 @@ var addCoreExtensions = function addCoreExtensions() {
// //
// Returns an integer representing the scaled value // Returns an integer representing the scaled value
Number.prototype.toScale = function(start, end) { Number.prototype.toScale = function(start, end) {
var i = this * (Math.max(start, end) - Math.min(start, end)) + Math.min(start, end); var i = this * (max(start, end) - min(start, end)) + min(start, end);
if (i < start) { if (i < start) {
return start; return start;
@ -333,4 +97,247 @@ var addCoreExtensions = function addCoreExtensions() {
}; };
}; };
var Utils = module.exports = {
// Public: Alias to setInterval, combined with Number monkeypatches below to
// create an artoo-like syntax.
//
// interval - interval to run action on
// action - action to perform at interval
//
// Examples
//
// every((5).seconds(), function() {
// console.log("Hello world (and again in 5 seconds)!");
// });
//
// Returns an interval
every: function every(interval, action) {
return setInterval(action, interval);
},
// Public: Alias to setTimeout, combined with Number monkeypatches below to
// create an artoo-like syntax.
//
// interval - interval to run action on
// action - action to perform at interval
//
// Examples
//
// after((10).seconds(), function() {
// console.log("Hello world from ten seconds ago!");
// });
//
// Returns an interval
after: function after(delay, action) {
return setTimeout(action, delay);
},
// Public: Alias to the `every` function, but passing 0
// Examples
//
// constantly(function() {
// console.log("hello world (and again and again)!");
// });
//
// Returns an interval
constantly: function constantly(action) {
return every(0, action);
},
// Public: Sleep - do nothing for some duration of time.
//
// ms - number of ms to sleep for
//
// Examples
//
// sleep((1).second());
//
// Returns a function
sleep: function sleep(ms) {
var start = Date.now(),
i;
while(Date.now() < start + ms) {
i = 0;
}
},
// Public: Function to use for class inheritance.
// Based on CoffeeScript's implementation.
//
// Example
//
// var Sphero = function Sphero() {};
//
// subclass(Sphero, ParentClass);
//
// // Sphero is now a subclass of Parent, and can access parent methods
// // through Sphero.__super__
//
// Returns subclass
subclass: function subclass(child, parent) {
var Ctor = function() {
this.constructor = child;
};
for (var key in parent) {
if (Object.hasOwnProperty.call(parent, key)) {
child[key] = parent[key];
}
}
Ctor.prototype = parent.prototype;
child.prototype = new Ctor();
child.__super__ = parent.prototype;
return child;
},
proxyFunctions: function proxyFunctions(source, target) {
for (var opt in source) {
if (!target[opt] && typeof source[opt] === "function") {
target[opt] = source[opt].bind(source);
}
}
},
// Public: Proxies a list of methods from one object to another. It will not
// overwrite existing methods unless told to.
//
// methods - array of functions to proxy
// target - object to proxy the functions to
// base - (optional) object that proxied functions will be declared on.
// Defaults to 'this'.
// force - (optional) boolean - whether or not to force method assignment
//
// Returns base
proxyFunctionsToObject: function(methods, target, base, force) {
if (base == null) {
base = this;
}
if (force == null) {
force = false;
}
var proxy = function(method) {
return base[method] = function() {
return target[method].apply(target, arguments);
};
};
for (var i = 0; i < methods.length; i++) {
var method = methods[i];
if (!force && typeof(base[method]) === "function") {
continue;
}
proxy(method);
}
return base;
},
// Public: Analogue to Ruby"s Hash#fetch method for looking up object
// properties.
//
// obj - object to do property lookup on
// property - string property name to attempt to look up
// fallback - either:
// - a fallback value to return if `property` can"t be found
// - a function to be executed if `property` can"t be found. The function
// will be passed `property` as an argument.
//
// Examples
//
// var object = { property: "hello world" };
// fetch(object, "property");
// //=> "hello world"
//
// fetch(object, "notaproperty", "default value");
// //=> "default value"
//
// var notFound = function(prop) { return prop + " not found!" };
// fetch(object, "notaproperty", notFound)
// // "notaproperty not found!"
//
// var badFallback = function(prop) { prop + " not found!" };
// fetch(object, "notaproperty", badFallback)
// // Error: no return value from provided callback function
//
// fetch(object, "notaproperty");
// // Error: key not found: "notaproperty"
//
// Returns the value of obj[property], a fallback value, or the results of
// running "fallback". If the property isn"t found, and "fallback" hasn"t been
// provided, will throw an error.
fetch: function(obj, property, fallback) {
if (obj.hasOwnProperty(property)) {
return obj[property];
}
if (fallback === void 0) {
throw new Error("key not found: \"" + property + "\"");
}
if (typeof(fallback) === "function") {
var value = fallback(property);
if (value === void 0) {
throw new Error("no return value from provided fallback function");
}
return value;
}
return fallback;
},
// Public: Given a name, and an array of existing names, returns a unique
// name.
//
// name - name that"s colliding with existing names
// arr - array of existing names
//
// Returns the new name as a string
makeUnique: function(name, arr) {
var newName;
if (!~arr.indexOf(name)) {
return name;
}
for (var n = 1; ; n++) {
newName = name + "-" + n;
if (!~arr.indexOf(newName)) {
return newName;
}
}
},
// Public: Adds necessary utils to global namespace, along with base class
// extensions.
//
// Examples
//
// Number.prototype.seconds // undefined
// after // undefined
//
// Utils.bootstrap();
//
// Number.prototype.seconds // [function]
// (after === Utils.after) // true
//
// Returns Cylon.Utils
bootstrap: function bootstrap() {
global.every = this.every;
global.after = this.after;
global.constantly = this.constantly;
addCoreExtensions();
return this;
}
};
Utils.bootstrap(); Utils.bootstrap();