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

View File

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

View File

@ -6,48 +6,14 @@
* Licensed under the Apache 2.0 license.
*/
var http = require('http');
"use strict";
module.exports = function(config) {
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 http = require("http");
var unauthorized = function unauthorized(res) {
res.statusCode = 401;
res.setHeader('WWW-Authenticate', 'Basic realm="Authorization Required"');
res.end('Unauthorized');
res.setHeader("WWW-Authenticate", "Basic realm=\"Authorization Required\"");
res.end("Unauthorized");
};
var error = function error(code, msg){
@ -55,3 +21,39 @@ var error = function error(code, msg){
err.status = code;
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
* cylonjs.com
@ -6,9 +8,11 @@
* 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
// present in the route params.
@ -20,21 +24,27 @@ var load = function load(req, res, next) {
if (robot) {
req.robot = Cylon.robots[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) {
req.device = req.robot.devices[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) {
req.connection = req.robot.connections[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;
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Connection': 'keep-alive',
'Cache-Control': 'no-cache'
"Content-Type": "text/event-stream",
"Connection": "keep-alive",
"Cache-Control": "no-cache"
});
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);
res.on('close', function() {
res.on("close", function() {
req.device.removeListener(event, writeData);
});
});

View File

@ -8,9 +8,9 @@
"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
// drivers. It provides some useful base methods and functionality
@ -46,7 +46,7 @@ Basestar.prototype.proxyMethods = function(methods, target, source, force) {
// target
// - target - object to proxy event to
// - 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
Basestar.prototype.defineEvent = function(opts) {
@ -59,7 +59,7 @@ Basestar.prototype.defineEvent = function(opts) {
opts.target.emit.apply(opts.target, args);
if (opts.sendUpdate) {
args.unshift('update');
args.unshift("update");
opts.target.emit.apply(opts.target, args);
}
});
@ -67,8 +67,8 @@ Basestar.prototype.defineEvent = function(opts) {
return opts.source;
};
// Public: Creates an event handler that proxies events from an adaptor's
// 'connector' (reference to whatever module is actually talking to the hw)
// Public: Creates an event handler that proxies events from an adaptor"s
// "connector" (reference to whatever module is actually talking to the hw)
// to the adaptor
//
// 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);
};
// 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
//
// 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) {
opts = (typeof opts === 'string') ? { eventName: opts } : opts;
opts = (typeof opts === "string") ? { eventName: opts } : opts;
opts.source = source;
opts.target = target
opts.target = target;
return this.defineEvent(opts);
}
};

View File

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

View File

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

View File

@ -8,22 +8,22 @@
"use strict";
var Async = require('async');
var Async = require("async");
var Logger = require('./logger'),
Robot = require('./robot'),
Config = require('./config'),
Utils = require('./utils');
var Logger = require("./logger"),
Robot = require("./robot"),
Config = require("./config"),
Utils = require("./utils");
var Cylon = module.exports = {
Logger: Logger,
Driver: require('./driver'),
Adaptor: require('./adaptor'),
Driver: require("./driver"),
Adaptor: require("./adaptor"),
Utils: Utils,
IO: {
DigitalPin: require('./io/digital-pin'),
Utils: require('./io/utils')
DigitalPin: require("./io/digital-pin"),
Utils: require("./io/utils")
},
api_instance: null,
@ -39,8 +39,8 @@ var Cylon = module.exports = {
// Returns a shiny new Robot
// Examples:
// Cylon.robot
// connection: { name: 'arduino', adaptor: 'firmata' }
// device: { name: 'led', driver: 'led', pin: 13 }
// connection: { name: "arduino", adaptor: "firmata" }
// device: { name: "led", driver: "led", pin: 13 }
//
// work: (me) ->
// me.led.toggle()
@ -51,25 +51,29 @@ Cylon.robot = function robot(opts) {
if (opts.name && this.robots[opts.name]) {
var original = opts.name;
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);
this.robots[robot.name] = robot;
return robot;
var bot = new Robot(opts);
this.robots[bot.name] = bot;
return bot;
};
// Public: Creates a new API based on passed options
//
// Returns nothing
Cylon.api = function api(opts) {
if (typeof opts === 'object') {
if (typeof opts === "object") {
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.listen();
@ -83,9 +87,10 @@ Cylon.start = function start() {
for (var bot in this.robots) {
starters.push(this.robots[bot].start);
}
Async.parallel(starters, function(err, results) {
var mode = Utils.fetch(Config, 'workMode', 'async');
if (mode === 'sync') {
Async.parallel(starters, function() {
var mode = Utils.fetch(Config, "workMode", "async");
if (mode === "sync") {
for (var bot in this.robots) {
this.robots[bot].startWork();
}
@ -101,7 +106,7 @@ Cylon.start = function start() {
Cylon.config = function(opts) {
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) {
Config[o] = opts[o];
}
@ -120,9 +125,9 @@ Cylon.config = function(opts) {
//
// Returns nothing
Cylon.halt = function halt(callback) {
callback = callback || function() {}
// if robots can't shut down quickly enough, forcefully self-terminate
var timeout = Config.haltTimeout || 3000
callback = callback || function() {};
// if robots can"t shut down quickly enough, forcefully self-terminate
var timeout = Config.haltTimeout || 3000;
Utils.after(timeout, callback);
var fns = [];
@ -145,7 +150,7 @@ Cylon.toJSON = function() {
return {
robots: robots,
commands: Object.keys(this.commands)
}
};
};
if (process.platform === "win32") {

View File

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

View File

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

View File

@ -8,24 +8,21 @@
"use strict";
var FS = require('fs'),
EventEmitter = require('events').EventEmitter;
var FS = require("fs"),
EventEmitter = require("events").EventEmitter;
var Utils = require('../utils');
var Utils = require("../utils");
var GPIO_PATH = "/sys/class/gpio";
var GPIO_READ = "in";
var GPIO_WRITE = "out";
var HIGH = 1;
var LOW = 0;
// DigitalPin class offers an interface with the Linux GPIO system present in
// single-board computers such as a Raspberry Pi, or a BeagleBone
var DigitalPin = module.exports = function DigitalPin(opts) {
this.pinNum = opts.pin.toString();
this.status = 'low';
this.status = "low";
this.ready = false;
this.mode = opts.mode;
};
@ -38,7 +35,11 @@ DigitalPin.prototype.connect = function(mode) {
}
FS.exists(this._pinPath(), function(exists) {
exists ? this._openPin() : this._createGPIOPin();
if (exists) {
this._openPin();
} else {
this._createGPIOPin();
}
}.bind(this));
};
@ -54,40 +55,43 @@ DigitalPin.prototype.closeSync = function() {
};
DigitalPin.prototype.digitalWrite = function(value) {
if (this.mode !== 'w') {
this._setMode('w');
if (this.mode !== "w") {
this._setMode("w");
}
this.status = value === 1 ? 'high' : 'low';
this.status = value === 1 ? "high" : "low";
FS.writeFile(this._valuePath(), value, function(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 {
this.emit('digitalWrite', value);
this.emit("digitalWrite", value);
}
}.bind(this));
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
//
// interval - time (in milliseconds) to read from the pin at
//
// Returns the defined interval
DigitalPin.prototype.digitalRead = function(interval) {
if (this.mode !== 'r') { this._setMode('r'); }
if (this.mode !== "r") { this._setMode("r"); }
Utils.every(interval, function() {
FS.readFile(this._valuePath(), function(err, data) {
if (err) {
var error = "Error occurred while reading from pin " + this.pinNum;
this.emit('error', error);
this.emit("error", error);
} else {
var readData = parseInt(data.toString());
this.emit('digitalRead', readData);
this.emit("digitalRead", readData);
}
}.bind(this));
}.bind(this));
@ -102,14 +106,14 @@ DigitalPin.prototype.setLow = 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
DigitalPin.prototype._createGPIOPin = function() {
FS.writeFile(this._exportPath(), this.pinNum, function(err) {
if (err) {
this.emit('error', 'Error while creating pin files');
this.emit("error", "Error while creating pin files");
} else {
this._openPin();
}
@ -118,24 +122,24 @@ DigitalPin.prototype._createGPIOPin = function() {
DigitalPin.prototype._openPin = function() {
this._setMode(this.mode, true);
this.emit('open');
this.emit("open");
};
DigitalPin.prototype._closeCallback = function(err) {
if (err) {
this.emit('error', 'Error while closing pin files');
this.emit("error", "Error while closing pin files");
} 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) {
if (emitConnect == null) { emitConnect = false; }
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) {
this._setModeCallback(err, emitConnect);
@ -144,13 +148,13 @@ DigitalPin.prototype._setMode = function(mode, emitConnect) {
DigitalPin.prototype._setModeCallback = function(err, emitConnect) {
if (err) {
return this.emit('error', "Setting up pin direction failed");
return this.emit("error", "Setting up pin direction failed");
}
this.ready = true;
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 }
// Calculated based on params value, freq, pulseWidth = { min: int, max: int }
// pulseWidth min and max need to be specified in microseconds
periodAndDuty: function(scaledDuty, freq, pulseWidth, polarity) {
var period, duty, maxDuty;
polarity = polarity || 'high';
polarity = polarity || "high";
period = Math.round(1.0e9 / freq);
if (pulseWidth != null) {
@ -18,12 +20,10 @@ Utils = {
duty = Math.round(period * scaledDuty);
}
if (polarity == 'low') {
if (polarity === "low") {
duty = period - duty;
}
return { period: period, duty: duty };
}
};
module.exports = Utils;

View File

@ -10,55 +10,15 @@
var levels = ["debug", "info", "warn", "error", "fatal"];
var BasicLogger = require('./logger/basic_logger'),
NullLogger = require('./logger/null_logger'),
Config = require('./config');
var BasicLogger = require("./logger/basic_logger"),
NullLogger = require("./logger/null_logger"),
Config = require("./config");
// 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
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 index = levels.indexOf(level),
active,
@ -80,7 +40,47 @@ var setLogLevel = function(level) {
ignored.forEach(function(level) {
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();

View File

@ -1,4 +1,4 @@
'use strict';
"use strict";
var getArgs = function(args) {
return args.length >= 1 ? [].slice.call(args, 0) : [];
@ -6,10 +6,10 @@ var getArgs = function(args) {
var logString = function(type) {
var time = new Date().toISOString(),
type = String(type).toUpperCase(),
padded = String(" " + type).slice(-5);
upcase = String(type).toUpperCase(),
padded = String(" " + upcase).slice(-5);
return type[0] + ", [" + time + "] " + padded + " -- :";
return upcase[0] + ", [" + time + "] " + padded + " -- :";
};
// The BasicLogger logs to console.log
@ -17,7 +17,7 @@ var BasicLogger = module.exports = {
toString: function() { return "BasicLogger"; },
};
['debug', 'info', 'warn', 'error', 'fatal'].forEach(function(type) {
["debug", "info", "warn", "error", "fatal"].forEach(function(type) {
BasicLogger[type] = function() {
var args = getArgs(arguments);
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
// print to anywhere. Every proxied method from the Logger returns a noop.
var NullLogger = module.exports = {
toString: function() { return "NullLogger"; }
};
['debug', 'info', 'warn', 'error', 'fatal'].forEach(function(type) {
["debug", "info", "warn", "error", "fatal"].forEach(function(type) {
NullLogger[type] = function() {};
});

View File

@ -12,21 +12,22 @@
"use strict";
var Logger = require('./logger');
var Logger = require("./logger");
// Explicitly these modules here, so Browserify can grab them later
require('./test/loopback');
require('./test/test-adaptor');
require('./test/test-driver');
require('./test/ping');
require("./test/loopback");
require("./test/test-adaptor");
require("./test/test-driver");
require("./test/ping");
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 str = "Cannot find the '" + module + "' module.\n";
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 = {
@ -86,7 +87,7 @@ var Registry = module.exports = {
Logger.debug("Registering module " + name);
['adaptors', 'drivers', 'dependencies'].forEach(function(field) {
["adaptors", "drivers", "dependencies"].forEach(function(field) {
if (module[field].length) {
Logger.debug(" " + field + ":");
module[field].forEach(function(item) {
@ -110,6 +111,6 @@ var Registry = module.exports = {
};
// Default drivers/adaptors:
['loopback', 'ping', 'test-adaptor', 'test-driver'].forEach(function(module) {
Registry.register('./test/' + module);
["loopback", "ping", "test-adaptor", "test-driver"].forEach(function(module) {
Registry.register("./test/" + module);
});

View File

@ -6,25 +6,16 @@
* Licensed under the Apache 2.0 license.
*/
'use strict';
"use strict";
var Connection = require("./connection"),
Device = require("./device"),
Logger = require('./logger'),
Utils = require('./utils'),
Config = require('./config');
var initConnection = require("./connection"),
initDevice = require("./device"),
Logger = require("./logger"),
Utils = require("./utils"),
Config = require("./config");
var Async = require("async"),
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');
};
EventEmitter = require("events").EventEmitter;
// Public: Creates a new Robot
//
@ -40,10 +31,10 @@ var missingModuleError = function(module) {
// name: "Spherobot!"
//
// connection:
// name: 'sphero', adaptor: 'sphero', port: '/dev/rfcomm0'
// name: "sphero", adaptor: "sphero", port: "/dev/rfcomm0"
//
// device:
// name: 'sphero', driver: 'sphero'
// name: "sphero", driver: "sphero"
//
// work: (me) ->
// Utils.every 1.second(), ->
@ -90,7 +81,7 @@ var Robot = module.exports = function Robot(opts) {
this[n] = opt;
if (typeof opt === 'function' && opts.commands == null) {
if (typeof opt === "function" && opts.commands == null) {
this.commands[n] = opt;
}
}
@ -98,14 +89,14 @@ var Robot = module.exports = function Robot(opts) {
if (opts.commands) {
var cmds = opts.commands;
if (typeof cmds === 'object') {
if (typeof cmds === "object") {
this.commands = cmds;
}
if (typeof cmds === 'function') {
if (typeof cmds === "function") {
var result = cmds.call(this, this);
if (typeof result === 'object' && !Array.isArray(result)) {
if (typeof result === "object" && !Array.isArray(result)) {
this.commands = result;
} else {
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') {
// run on the next tick, to allow for 'work' event handlers to be set up
if (mode === "auto") {
// run on the next tick, to allow for "work" event handlers to be set up
setTimeout(this.start, 0);
}
};
@ -159,12 +150,16 @@ Robot.prototype.connection = function(name, conn) {
conn.name = name;
if (this.connections[conn.name]) {
var original = conn.name;
var original = conn.name,
str;
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;
};
@ -177,6 +172,8 @@ Robot.prototype.connection = function(name, conn) {
Robot.prototype.initConnections = function(opts) {
Logger.info("Initializing connections.");
var str;
var isArray = Array.isArray;
if (opts.connection == null && opts.connections == null) {
@ -184,19 +181,27 @@ Robot.prototype.initConnections = function(opts) {
}
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);
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) {
this.connection(name, opts.connections[name]);
}
}
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) {
this.connection(conn.name, conn);
}, this);
@ -206,20 +211,25 @@ Robot.prototype.initConnections = function(opts) {
};
Robot.prototype.device = function(name, device) {
var str;
device.robot = this;
device.name = name;
if (this.devices[device.name]) {
var original = device.name;
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) {
var str = "No connection found with the name " + device.connection + ".\n";
str = "No connection found with the name " + device.connection + ".\n";
Logger.fatal(str);
process.emit('SIGINT');
process.emit("SIGINT");
}
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;
}
};
// Public: Initializes all devices for the robot
//
@ -241,9 +251,10 @@ Robot.prototype.device = function(name, device) {
//
// Returns initialized devices
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) {
return this.devices;
@ -251,23 +262,28 @@ Robot.prototype.initDevices = function(opts) {
// check that there are connections to use
if (!Object.keys(this.connections).length) {
throw new Error("No connections specified")
throw new Error("No connections specified");
}
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);
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) {
this.device(name, opts.devices[name]);
}
}
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) {
this.device(device.name, device);
}, this);
@ -286,13 +302,13 @@ Robot.prototype.start = function(callback) {
return this;
}
var mode = Utils.fetch(Config, 'workMode', 'async');
var mode = Utils.fetch(Config, "workMode", "async");
Async.series([
this.startConnections,
this.startDevices,
function(callback) {
if (mode === 'async') {
if (mode === "async") {
this.startWork();
}
callback(null, true);
@ -301,12 +317,12 @@ Robot.prototype.start = function(callback) {
if (!!err) {
Logger.fatal("An error occured while trying to start the robot:");
Logger.fatal(err);
if (typeof(this.error) === 'function') {
if (typeof(this.error) === "function") {
this.error.call(this, err);
}
this.emit('error', err);
this.emit("error", err);
}
if (typeof(callback) === 'function') {
if (typeof(callback) === "function") {
callback(err, results);
}
}.bind(this));
@ -314,20 +330,20 @@ Robot.prototype.start = function(callback) {
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
//
// Returns nothing
Robot.prototype.startWork = function() {
Logger.info('Working.');
Logger.info("Working.");
this.emit('ready', this);
this.emit("ready", this);
this.work.call(this, this);
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
//
@ -355,7 +371,7 @@ Robot.prototype.startConnections = function(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
//

View File

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

View File

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

View File

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

View File

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

View File

@ -6,248 +6,12 @@
* Licensed under the Apache 2.0 license.
*/
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();
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;
}
};
"use strict";
var addCoreExtensions = function addCoreExtensions() {
var max = Math.max,
min = Math.min;
// Public: Monkey-patches Number to have Rails-like //seconds() function.
// Warning, due to the way the Javascript parser works, applying functions on
// numbers is kind of weird. See examples for details.
@ -294,7 +58,7 @@ var addCoreExtensions = function addCoreExtensions() {
//
// Returns an integer representing the scaled value
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) {
return 1;
@ -319,7 +83,7 @@ var addCoreExtensions = function addCoreExtensions() {
//
// Returns an integer representing the scaled value
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) {
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();