From 86443992769d89408e167269e20db7c0c689df0b Mon Sep 17 00:00:00 2001 From: xixebombilla Date: Thu, 27 Feb 2014 16:42:33 -0600 Subject: [PATCH] 210 comments JS --- lib/api.js | 5 +++ lib/basestar.js | 38 ++++++++++++++++ lib/config.js | 22 +++++++++ lib/connection.js | 31 +++++++++++++ lib/cylon.js | 64 ++++++++++++++++++++++++++ lib/device.js | 40 ++++++++++++++++- lib/digital-pin.js | 10 +++++ lib/driver.js | 22 +++++++++ lib/logger.js | 14 ++++++ lib/port.js | 19 ++++++++ lib/robot.js | 101 ++++++++++++++++++++++++++++++++++++++++- lib/utils.js | 110 +++++++++++++++++++++++++++++++++++++++++++++ 12 files changed, 474 insertions(+), 2 deletions(-) diff --git a/lib/api.js b/lib/api.js index e147582..2084207 100644 --- a/lib/api.js +++ b/lib/api.js @@ -12,6 +12,8 @@ var express = require('express.io'); var namespace = require('node-namespace'); namespace("Cylon", function() { + // The Cylon API Server provides an interface to communicate with master class + // and retrieve information about the robots being controlled. this.ApiServer = (function() { var master; @@ -40,6 +42,9 @@ namespace("Cylon", function() { }); } + // Parses req to extract params to be used for commands. + // + // Returns an array of params ApiServer.prototype.parseCommandParams = function(req) { var param_container, params, v, _; params = []; diff --git a/lib/basestar.js b/lib/basestar.js index 513c8b5..2370069 100644 --- a/lib/basestar.js +++ b/lib/basestar.js @@ -12,6 +12,11 @@ require('./utils'); var namespace = require('node-namespace'); var EventEmitter = require('events').EventEmitter; + // Basestar is a base class to be used when writing external Cylon adaptors and + // drivers. It provides some useful base methods and functionality + // + // It also extends EventEmitter, so child classes are capable of emitting events + // for other parts of the system to handle. namespace("Cylon", function() { this.Basestar = (function(klass) { subclass(Basestar, klass); @@ -20,6 +25,14 @@ namespace("Cylon", function() { this.self = this; } + // Public: Proxies calls from all methods in the object to a target object + // + // methods - array of methods to proxy + // target - object to proxy methods to + // source - object to proxy methods from + // force - whether or not to overwrite existing method definitions + // + // Returns the klass where the methods have been proxied Basestar.prototype.proxyMethods = function(methods, target, source, force) { if (force == null) { force = false; @@ -27,6 +40,17 @@ namespace("Cylon", function() { return proxyFunctionsToObject(methods, target, source, force); }; + // Public: Defines an event handler that proxies events from a source object + // to a target object + // + // opts - object containing options: + // - targetEventName or eventName - event that should be emitted from the + // target + // - target - object to proxy event to + // - source - object to proxy event from + // - update - whether or not to send an 'update' event + // + // Returns the source Basestar.prototype.defineEvent = function(opts) { var sendUpdate, targetEventName, _this = this; @@ -43,6 +67,13 @@ namespace("Cylon", function() { 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) + // to the adaptor's associated connection. + // + // opts - hash of opts to be passed to defineEvent() + // + // Returns @connector Basestar.prototype.defineAdaptorEvent = function(opts) { opts['source'] = this.connector; opts['target'] = this.connection; @@ -52,6 +83,13 @@ namespace("Cylon", function() { return this.defineEvent(opts); }; + // Public: Creates an event handler that proxies events from an device's + // 'connector' (reference to whatever module is actually talking to the hw) + // to the device's associated connection. + // + // opts - hash of opts to be passed to defineEvent() + // + // Returns @connection Basestar.prototype.defineDriverEvent = function(opts) { opts['source'] = this.connection; opts['target'] = this.device; diff --git a/lib/config.js b/lib/config.js index 043a8b3..f7b6a48 100644 --- a/lib/config.js +++ b/lib/config.js @@ -10,6 +10,28 @@ var namespace = require('node-namespace'); + +// Public: Fetches a variable from the environment, returning a provided value if +// it's not set. +// +// variable - variable to fetch from the environment +// defaultValue - value to return if the ENV variable isn't set +// +// Examples +// +// process.env["CYLON_TEST"] #=> undefined +// fetch("CYLON_TEST", "not set") +// #=> "not set" +// +// process.env["CYLON_TEST"] #=> false +// fetch("CYLON_TEST", true) +// #=> false +// +// process.env["CYLON_TEST"] #=> true +// fetch("CYLON_TEST", false) +// #=> true +// +// Returns the env var or default value var fetch = function(variable, defaultValue) { if (defaultValue == null) { defaultValue = false; diff --git a/lib/connection.js b/lib/connection.js index 45d794b..5fb0cf6 100644 --- a/lib/connection.js +++ b/lib/connection.js @@ -15,10 +15,24 @@ var namespace = require('node-namespace'); var EventEmitter = require('events').EventEmitter; var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; } + +// The Connection class represents the interface to +// a specific group of hardware devices. Examples would be an +// Arduino, a Sphero, or an ARDrone. namespace("Cylon", function() { this.Connection = (function(klass) { subclass(Connection, klass); + // Public: Creates a new Connection + // + // opts - hash of acceptable params: + // id - string ID for the connection + // robot - Robot the Connection belongs to + // name - name for the connection + // adaptor - string module name of the adaptor to be set up + // port - string port to use for the Connection + // + // Returns the newly set-up connection function Connection(opts) { if (opts == null) { opts = {}; @@ -36,6 +50,9 @@ namespace("Cylon", function() { proxyFunctionsToObject(this.adaptor.commands(), this.adaptor, this.self); } + // Public: Exports basic data for the Connection + // + // Returns an Object containing Connection data Connection.prototype.data = function() { return { name: this.name, @@ -45,6 +62,11 @@ namespace("Cylon", function() { }; }; + // Public: Connect the adaptor's connection + // + // callback - callback function to run when the adaptor is connected + // + // Returns the result of the supplied callback function Connection.prototype.connect = function(callback) { var msg; msg = "Connecting to '" + this.name + "'"; @@ -55,6 +77,9 @@ namespace("Cylon", function() { return this.adaptor.connect(callback); }; + // Public: Disconnect the adaptor's connection + // + // Returns nothing Connection.prototype.disconnect = function() { var msg; msg = "Disconnecting from '" + this.name + "'"; @@ -65,6 +90,12 @@ namespace("Cylon", function() { return this.adaptor.disconnect(); }; + // Public: sets up adaptor with @robot + // + // opts - options for adaptor being initialized + // adaptor - name of the adaptor + // + // Returns the set-up adaptor Connection.prototype.initAdaptor = function(opts) { Logger.debug("Loading adaptor '" + opts.adaptor + "'"); return this.robot.initAdaptor(opts.adaptor, this.self, opts); diff --git a/lib/cylon.js b/lib/cylon.js index 11c2d9a..5711cff 100644 --- a/lib/cylon.js +++ b/lib/cylon.js @@ -9,6 +9,7 @@ (function() { 'use strict'; + var Cylon, __slice = [].slice, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; @@ -25,6 +26,8 @@ Logger.setup(); + // Cylon is the global namespace for the project, and also in charge of + // maintaining the Master singleton that controls all the robots. Cylon = (function() { var Master, instance; @@ -32,6 +35,10 @@ instance = null; + // Public: Fetches singleton instance of Master, or creates a new one if it + // doesn't already exist + // + // Returns a Master instance Cylon.getInstance = function() { var args; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; @@ -42,6 +49,8 @@ })(Master, args, function(){}); }; + // The Master class is our puppeteer that manages all the robots, as well as + // starting them and the API. Master = (function() { var api, api_config, robots; @@ -54,6 +63,9 @@ port: '3000' }; + // Public: Creates a new Master + // + // Returns a Master instance function Master() { this.robot = __bind(this.robot, this); var readLine, rl; @@ -74,6 +86,18 @@ }); } + // Public: Creates a new Robot + // + // opts - hash of Robot attributes + // + // Returns a shiny new Robot + // Examples: + // Cylon.robot + // connection: { name: 'arduino', adaptor: 'firmata' } + // device: { name: 'led', driver: 'led', pin: 13 } + // + // work: (me) -> + // me.led.toggle() Master.prototype.robot = function(opts) { var Robot, robot; Robot = require("./robot"); @@ -83,10 +107,20 @@ return robot; }; + // Public: Returns all Robots the Master knows about + // + // Returns an array of all Robot instances Master.prototype.robots = function() { return robots; }; + // Public: Configures the API host and port based on passed options + // + // opts - object containing API options + // host - host address API should serve from + // port - port API should listen for requests on + // + // Returns the API configuration Master.prototype.api = function(opts) { if (opts == null) { opts = {}; @@ -96,6 +130,12 @@ return api_config; }; + // Public: Finds a particular robot by name + // + // name - name of the robot to find + // callback - optional callback to be executed + // + // Returns the found Robot or result of the callback if it's supplied Master.prototype.findRobot = function(name, callback) { var bot, error, robot, _i, _len; robot = null; @@ -117,6 +157,13 @@ } }; + // Public: Finds a particular Robot's device by name + // + // robotid - name of the robot to find + // deviceid - name of the device to find + // callback - optional callback to be executed + // + // Returns the found Device or result of the callback if it's supplied Master.prototype.findRobotDevice = function(robotid, deviceid, callback) { return this.findRobot(robotid, function(err, robot) { var device, error; @@ -140,6 +187,13 @@ }); }; + // Public: Finds a particular Robot's connection by name + // + // robotid - name of the robot to find + // connid - name of the device to find + // callback - optional callback to be executed + // + // Returns the found Connection or result of the callback if it's supplied Master.prototype.findRobotConnection = function(robotid, connid, callback) { return this.findRobot(robotid, function(err, robot) { var connection, error; @@ -163,6 +217,9 @@ }); }; + // Public: Starts up the API and the robots + // + // Returns nothing Master.prototype.start = function() { var robot, _i, _len, _results; this.startAPI(); @@ -174,6 +231,9 @@ return _results; }; + // Public: Stops the API and the robots + // + // Returns nothing Master.prototype.stop = function() { var robot, _i, _len, _results; _results = []; @@ -184,6 +244,10 @@ return _results; }; + // Creates a new instance of the Cylon API server, or returns the + // already-existing one. + // + // Returns an Cylon.ApiServer instance Master.prototype.startAPI = function() { var server; server = require('./api'); diff --git a/lib/device.js b/lib/device.js index c26d1e1..1e02f13 100644 --- a/lib/device.js +++ b/lib/device.js @@ -13,11 +13,24 @@ require('./driver'); var namespace = require('node-namespace'); var EventEmitter = require('events').EventEmitter; var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; } - + +// The Artoo::Device class represents the interface to +// a specific individual hardware devices. Examples would be a digital +// thermometer connected to an Arduino, or a Sphero's accelerometer namespace("Cylon", function() { this.Device = (function(klass) { subclass(Device, klass); + // Public: Creates a new Device + // + // opts - object containing Device params + // name - string name of the device + // pin - string pin of the device + // robot - parent Robot to the device + // connection - connection to the device + // driver - string name of the module the device driver logic lives in + // + // Returns a new Device function Device(opts) { if (opts == null) { opts = {}; @@ -33,6 +46,11 @@ namespace("Cylon", function() { proxyFunctionsToObject(this.driver.commands(), this.driver, this.self); } + // Public: Starts the device driver + // + // callback - callback function to be executed by the driver start + // + // Returns result of supplied callback Device.prototype.start = function(callback) { var msg; msg = "Starting device '" + this.name + "'"; @@ -43,11 +61,17 @@ namespace("Cylon", function() { return this.driver.start(callback); }; + // Public: Stops the device driver + // + // Returns result of supplied callback Device.prototype.stop = function() { Logger.info("Stopping device '" + this.name + "'"); return this.driver.stop(); }; + // Public: Exports basic data for the Connection + // + // Returns an Object containing Connection data Device.prototype.data = function() { return { name: this.name, @@ -58,12 +82,20 @@ namespace("Cylon", function() { }; }; + // Public: Retrieves the connections from the parent Robot instances + // + // c - name of the connection to fetch + // + // Returns a Connection instance Device.prototype.determineConnection = function(c) { if (c) { return this.robot.connections[c]; } }; + // Public: Returns a default Connection to use + // + // Returns a Connection instance Device.prototype.defaultConnection = function() { var first, k, v, _ref; first = 0; @@ -75,6 +107,12 @@ namespace("Cylon", function() { return first; }; + // Public: sets up driver with @robot + // + // opts - object containing options when initializing driver + // driver - name of the driver to intt() + // + // Returns the set-up driver Device.prototype.initDriver = function(opts) { if (opts == null) { opts = {}; diff --git a/lib/digital-pin.js b/lib/digital-pin.js index dc98177..afe4577 100644 --- a/lib/digital-pin.js +++ b/lib/digital-pin.js @@ -12,6 +12,8 @@ var FS = require('fs'); var EventEmitter = require('events').EventEmitter; var namespace = require('node-namespace'); +// DigitalPin class offers an interface with the Linux GPIO system present in +// single-board computers such as a Raspberry Pi, or a BeagleBone namespace("Cylon.IO", function() { this.DigitalPin = (function(klass) { subclass(DigitalPin, klass); @@ -74,6 +76,12 @@ namespace("Cylon.IO", function() { return value; }; + // 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) { var readData, _this = this; @@ -109,6 +117,7 @@ namespace("Cylon.IO", function() { } }; + // Creates the GPIO file to read/write from DigitalPin.prototype._createGPIOPin = function() { var _this = this; return FS.writeFile(this._exportPath(), "" + this.pinNum, function(err) { @@ -133,6 +142,7 @@ namespace("Cylon.IO", function() { } }; + // Sets the mode for the GPIO pin by writing the correct values to the pin reference files DigitalPin.prototype._setMode = function(mode, emitConnect) { var _this = this; if (emitConnect == null) { diff --git a/lib/driver.js b/lib/driver.js index 1a234ba..2c72370 100644 --- a/lib/driver.js +++ b/lib/driver.js @@ -11,10 +11,20 @@ require('./basestar'); var namespace = require('node-namespace'); +// The Driver class is a base class for Driver classes in external Cylon +// modules to use. It offers basic functions for starting/stopping that +// descendant classes can. namespace("Cylon", function() { this.Driver = (function(klass) { subclass(Driver, klass); + // Public: Creates a new Driver + // + // opts - hash of acceptable params + // name - name of the Driver, used when printing to console + // device - Device the driver will use to proxy commands/events + // + // Returns a new Driver function Driver(opts) { if (opts == null) { opts = {}; @@ -26,10 +36,19 @@ namespace("Cylon", function() { this.commandList = []; } + // Public: Exposes all commands the driver will respond to/proxy + // + // Returns an array of string method names Driver.prototype.commands = function() { return this.commandList; }; + // Public: Starts up the driver, and emits 'connect' from the @device + // when done. + // + // callback - function to run when the driver is started + // + // Returns nothing Driver.prototype.start = function(callback) { Logger.info("Driver " + this.name + " started"); callback(null); @@ -37,6 +56,9 @@ namespace("Cylon", function() { return true; }; + // Public: Stops the driver + // + // Returns nothing Driver.prototype.stop = function() { return Logger.info("Driver " + this.name + " stopped"); }; diff --git a/lib/logger.js b/lib/logger.js index 9b0cfc8..232c925 100644 --- a/lib/logger.js +++ b/lib/logger.js @@ -11,7 +11,17 @@ var BasicLogger, NullLogger, __slice = [].slice; +// 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 +// well as in external modules that are loaded into Cylon global.Logger = { + + // 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 + // + // Returns the new logger instance setup: function(logger) { if (logger == null) { logger = new BasicLogger; @@ -48,6 +58,7 @@ } }; + // The BasicLogger pushes stuff to console.log. Nothing more, nothing less. BasicLogger = (function() { function BasicLogger() {} @@ -89,6 +100,9 @@ })(); + + // The NullLogger is designed for cases where you want absolutely nothing to + // print to anywhere. Every proxied method from the Logger returns a noo NullLogger = (function() { function NullLogger() {} diff --git a/lib/port.js b/lib/port.js index dd1c085..da7c4d9 100644 --- a/lib/port.js +++ b/lib/port.js @@ -10,27 +10,42 @@ var namespace = require('node-namespace'); +// The Port class represents a port and/or host to be used to connect to +// a specific hardware device namespace("Cylon", function() { return this.Port = (function() { + // Public: Creates a new Port based on a passed String representation + // + // data - string representation of the Port + // + // Returns a new Port function Port(data) { this.self = this; this.isTcp = this.isSerial = this.isPortless = false; this.parse(data); } + // Public: Parses the Port's data to determine what kind of port it is + // + // data - string representation of the port to parse + // + // Returns nothing. Port.prototype.parse = function(data) { var match; if (data === void 0) { this.port = void 0; return this.isPortless = true; + // is TCP host/port? } else if (match = /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d{1,5})/.exec(data)) { this.port = match[2]; this.host = match[1]; return this.isTcp = true; + // is it a numeric port for localhost tcp? } else if (/^[0-9]{1,5}$/.exec(data)) { this.port = data; this.host = "localhost"; return this.isTcp = true; + // must be a serial port } else { this.port = data; this.host = void 0; @@ -38,6 +53,10 @@ namespace("Cylon", function() { } }; + // Public: Returns a string representation of the port that can be used to + // connect to it. + // + // Returns a string Port.prototype.toString = function() { if (this.isPortless) { return "none"; diff --git a/lib/robot.js b/lib/robot.js index b67f605..89e0e62 100644 --- a/lib/robot.js +++ b/lib/robot.js @@ -23,10 +23,35 @@ var EventEmitter = require('events').EventEmitter; var namespace = require('node-namespace'); +// A Robot is the primary interface for interacting with a collection of physical +// computing capabilities. namespace("Cylon", function() { this.Robot = (function(klass) { subclass(Robot, klass); + // Public: Creates a new Robot + // + // opts - object containing Robot options + // name - optional, string name of the robot + // master - Cylon.Master class that orchestrates robots + // connection/connections - object connections to connect to + // device/devices - object devices to connect to + // work - work to be performed when the Robot is started + // + // Returns a new Robot + // Example (CoffeeScript): + // Cylon.robot + // name: "Spherobot!" + // + // connection: + // name: 'sphero', adaptor: 'sphero', port: '/dev/rfcomm0' + // + // device: + // name: 'sphero', driver: 'sphero' + // + // work: (me) -> + // every 1.second(), -> + // me.sphero.roll 60, Math.floor(Math.random() * 360// function Robot(opts) { var func, n, reserved; if (opts == null) { @@ -70,10 +95,16 @@ namespace("Cylon", function() { } } + // Public: Generates a random name for a Robot. + // + // Returns a string name Robot.randomName = function() { return "Robot " + (Math.floor(Math.random() * 100000)); }; + // Public: Exports basic data for the Robot + // + // Returns an Object containing Robot data Robot.prototype.data = function() { var connection, device, n; return { @@ -102,6 +133,11 @@ namespace("Cylon", function() { }; }; + // Public: Initializes all connections for the robot + // + // connections - connections to initialize + // + // Returns initialized connections Robot.prototype.initConnections = function(connections) { var connection, _i, _len; Logger.info("Initializing connections..."); @@ -118,6 +154,11 @@ namespace("Cylon", function() { return this.connections; }; + // Public: Initializes all devices for the robot + // + // devices - devices to initialize + // + // Returns initialized devices Robot.prototype.initDevices = function(devices) { var device, _i, _len, _results; Logger.info("Initializing devices..."); @@ -135,6 +176,11 @@ namespace("Cylon", function() { return _results; }; + // Public: Starts the Robot working. + // + // Starts the connections, devices, and work. + // + // Returns the result of the work Robot.prototype.start = function() { var _this = this; return this.startConnections(function() { @@ -147,6 +193,11 @@ namespace("Cylon", function() { }); }; + // Public: Starts the Robot's connections and triggers a callback + // + // callback - callback function to be triggered + // + // Returns nothing Robot.prototype.startConnections = function(callback) { var connection, n, starters, _ref; Logger.info("Starting connections..."); @@ -160,6 +211,11 @@ namespace("Cylon", function() { return Async.parallel(starters, callback); }; + // Public: Starts the Robot's devices and triggers a callback + // + // callback - callback function to be triggered + // + // Returns nothing Robot.prototype.startDevices = function(callback) { var device, n, starters, _ref; Logger.info("Starting devices..."); @@ -173,6 +229,11 @@ namespace("Cylon", function() { return Async.parallel(starters, callback); }; + // Public: Stops the Robot working. + // + // Stops the devices, disconnects the connections. + // + // Returns nothing Robot.prototype.stop = function() { var connection, device, n, _ref, _ref1, _results; _ref = this.devices; @@ -189,6 +250,12 @@ namespace("Cylon", function() { return _results; }; + // Public: Initialize an adaptor and adds it to @robot.adaptors + // + // adaptorName - module name of adaptor to require + // connection - the Connection that requested the adaptor be required + // + // Returns the adaptor Robot.prototype.initAdaptor = function(adaptorName, connection, opts) { var realAdaptor, testAdaptor; if (opts == null) { @@ -211,6 +278,11 @@ namespace("Cylon", function() { } }; + // Public: Requires a hardware adaptor and adds it to @robot.adaptors + // + // adaptorName - module name of adaptor to require + // + // Returns the module for the adaptor Robot.prototype.requireAdaptor = function(adaptorName) { if (this.robot.adaptors[adaptorName] == null) { this.robot.registerAdaptor("cylon-" + adaptorName, adaptorName); @@ -219,12 +291,25 @@ namespace("Cylon", function() { return this.robot.adaptors[adaptorName]; }; + // Public: Registers an Adaptor with the Robot + // + // moduleName - name of the Node module to require + // adaptorName - name of the adaptor to register the moduleName under + // + // Returns the registered module name Robot.prototype.registerAdaptor = function(moduleName, adaptorName) { if (this.adaptors[adaptorName] == null) { return this.adaptors[adaptorName] = require(moduleName); } }; + // Public: Init a hardware driver + // + // driverName - driver name + // device - the Device that requested the driver be initialized + // opts - object containing options when initializing driver + // + // Returns the new driver Robot.prototype.initDriver = function(driverName, device, opts) { var realDriver, testDriver; if (opts == null) { @@ -245,8 +330,13 @@ namespace("Cylon", function() { } else { return realDriver; } - }; + }; + // Public: Requires module for a driver and adds it to @robot.drivers + // + // driverName - module name of driver to require + // + // Returns the module for driver Robot.prototype.requireDriver = function(driverName) { if (this.robot.drivers[driverName] == null) { this.robot.registerDriver("cylon-" + driverName, driverName); @@ -255,12 +345,21 @@ namespace("Cylon", function() { return this.robot.drivers[driverName]; }; + // Public: Registers an Driver with the Robot + // + // moduleName - name of the Node module to require + // driverName - name of the driver to register the moduleName under + // + // Returns the registered module nam// Robot.prototype.registerDriver = function(moduleName, driverName) { if (this.drivers[driverName] == null) { return this.drivers[driverName] = require(moduleName); } }; + // Public: Returns basic info about the robot as a String + // + // Returns a String Robot.prototype.toString = function() { return "[Robot name='" + this.name + "']"; }; diff --git a/lib/utils.js b/lib/utils.js index f2d6dac..11492f9 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -10,18 +10,53 @@ (function() { var __slice = [].slice; + // 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(), -> console.log("hello world (and again in 5 seconds)!") + // + // Returns an interval global.every = function(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(), -> console.log("hello world from ten seconds ago!") + // + // Returns an interval global.after = function(delay, action) { return setTimeout(action, delay); }; + // Public: Alias to the `every` function, but passing 0 + // Examples + // + // constantly -> console.log("hello world (and again and again)!") + // + // Returns an interval global.constantly = function(action) { return every(0, action); }; + // Public: Sleep - do nothing for some duration of time. + // + // ms - number of ms to sleep for + // + // Returns a function + // Examples: + // sleep 1.second() global.sleep = function(ms) { var i, start, _results; start = Date.now(); @@ -36,6 +71,18 @@ global.hasProp = {}.hasOwnProperty; + // Public: Function to use for class inheritance. Copy of a CoffeeScript helper + // function. + // + // Example + // + // var Sphero = (function(klass) { + // subclass(Sphero, klass); + // // Sphero is now a subclass of Parent, and can access it's methods through + // // Sphero.__super__ + // })(Parent); + // + // Returns subclass global.subclass = function(child, parent) { var ctor, key; ctor = function() { @@ -52,6 +99,16 @@ return child; }; + // 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 global.proxyFunctionsToObject = function(methods, target, base, force) { var method, _fn, _i, _len; if (base == null) { @@ -79,6 +136,13 @@ return base; }; + // Public: Proxies a list of methods for test stubbing. + // + // methods - array of functions to proxy + // base - (optional) object that proxied functions will be declared on. Defaults + // to this + // + // Returns base global.proxyTestStubs = function(methods, base) { var method, _i, _len; if (base == null) { @@ -96,18 +160,64 @@ return base; }; + // 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. + // + // Examples + // + // 2.seconds() + // #=> SyntaxError: Unexpected token ILLEGAL + // + // 10..seconds() + // #=> 10000 + // + // (5).seconds() + // #=> 5000 + // + // Returns an integer representing time in milliseconds Number.prototype.seconds = function() { return this * 1000; }; + // Public: Alias for Number::seconds, see comments for that method + // + // Examples + // + // 1.second() + // #=> 1000 + // + // Returns an integer representing time in milliseconds Number.prototype.second = function() { return this.seconds(this); }; + // Public: Convert value from old scale (start, end) to (0..1) scale + // + // start - low point of scale to convert value from + // end - high point of scale to convert value from + // + // Examples + // + // 5..fromScale(0, 10) + // #=> 0.5 + // + // Returns an integer representing the scaled value Number.prototype.fromScale = function(start, end) { return (this - Math.min(start, end)) / (Math.max(start, end) - Math.min(start, end)); }; + // Public: Convert value from (0..1) scale to new (start, end) scale + // + // start - low point of scale to convert value to + // end - high point of scale to convert value to + // + // Examples + // + // 0.5.toScale(0, 10) + // #=> 5 + // + // Returns an integer representing the scaled value Number.prototype.toScale = function(start, end) { return Math.ceil(this * (Math.max(start, end) - Math.min(start, end)) + Math.min(start, end)); };