Merge pull request #191 from hybridgroup/refactor/utils

Refactor Utils (mostly) out of global namespace
This commit is contained in:
Ron Evans 2014-06-06 18:21:46 -04:00
commit 836b7938db
24 changed files with 191 additions and 170 deletions

View File

@ -9,7 +9,8 @@
"use strict";
var Basestar = require('./basestar'),
Logger = require('./logger');
Logger = require('./logger'),
Utils = require('./utils');
// The Adaptor class is a base class for Adaptor classes in external Cylon
// modules to use. It offers basic functions for connecting/disconnecting that
@ -34,7 +35,7 @@ module.exports = Adaptor = function Adaptor(opts) {
this.commandList = [];
};
subclass(Adaptor, Basestar);
Utils.subclass(Adaptor, Basestar);
// Public: Exposes all commands the adaptor will respond to/proxy
//

View File

@ -8,10 +8,10 @@
"use strict";
require('./utils');
var EventEmitter = require('events').EventEmitter;
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
//
@ -23,7 +23,7 @@ module.exports = Basestar = function Basestar(opts) {
this.self = this;
}
subclass(Basestar, EventEmitter);
Utils.subclass(Basestar, EventEmitter);
// Public: Proxies calls from all methods in the object to a target object
//
@ -35,7 +35,7 @@ subclass(Basestar, EventEmitter);
// Returns the klass where the methods have been proxied
Basestar.prototype.proxyMethods = function(methods, target, source, force) {
if (force == null) { force = false; }
return proxyFunctionsToObject(methods, target, source, force);
return Utils.proxyFunctionsToObject(methods, target, source, force);
};
// Public: Defines an event handler that proxies events from a source object

View File

@ -8,11 +8,10 @@
'use strict';
require("./utils");
var EventEmitter = require('events').EventEmitter;
var Logger = require('./logger');
var Logger = require('./logger'),
Utils = require('./utils');
// The Connection class represents the interface to
// a specific group of hardware devices. Examples would be an
@ -38,7 +37,7 @@ module.exports = Connection = function Connection(opts) {
opts.id = Math.floor(Math.random() * 10000);
}
this.connect = bind(this.connect, this);
this.connect = Utils.bind(this.connect, this);
this.self = this;
this.robot = opts.robot;
@ -47,10 +46,10 @@ module.exports = Connection = function Connection(opts) {
this.port = opts.port;
this.adaptor = this.initAdaptor(opts);
proxyFunctionsToObject(this.adaptor.commands(), this.adaptor, this.self);
Utils.proxyFunctionsToObject(this.adaptor.commands(), this.adaptor, this.self);
}
subclass(Connection, EventEmitter);
Utils.subclass(Connection, EventEmitter);
// Public: Exports basic data for the Connection
//

View File

@ -19,6 +19,7 @@ var Cylon = module.exports = {
Logger: Logger,
Driver: require('./driver'),
Adaptor: require('./adaptor'),
Utils: Utils,
IO: {
DigitalPin: require('./io/digital-pin')

View File

@ -8,11 +8,10 @@
'use strict';
require('./utils');
var EventEmitter = require('events').EventEmitter;
var Logger = require('./logger');
var Logger = require('./logger'),
Utils = require('./utils');
// The Artoo::Device class represents the interface to
// a specific individual hardware devices. Examples would be a digital
@ -34,8 +33,8 @@ module.exports = Device = function Device(opts) {
opts = {};
}
this.halt = bind(this.halt, this);
this.start = bind(this.start, this);
this.halt = Utils.bind(this.halt, this);
this.start = Utils.bind(this.start, this);
this.self = this;
this.robot = opts.robot;
@ -44,10 +43,10 @@ module.exports = Device = function Device(opts) {
this.connection = this.determineConnection(opts.connection) || this.defaultConnection();
this.driver = this.initDriver(opts);
proxyFunctionsToObject(this.driver.commands(), this.driver, this.self);
Utils.proxyFunctionsToObject(this.driver.commands(), this.driver, this.self);
};
subclass(Device, EventEmitter);
Utils.subclass(Device, EventEmitter);
// Public: Starts the device driver
//

View File

@ -9,7 +9,8 @@
'use strict';
var Basestar = require('./basestar'),
Logger = require('./logger');
Logger = require('./logger'),
Utils = require('./utils');
// The Driver class is a base class for Driver classes in external Cylon
// modules to use. It offers basic functions for starting/halting that
@ -35,7 +36,7 @@ module.exports = Driver = function Driver(opts) {
this.commandList = [];
};
subclass(Driver, Basestar);
Utils.subclass(Driver, Basestar);
// Public: Exposes all commands the driver will respond to/proxy
//

View File

@ -11,6 +11,8 @@
var FS = require('fs'),
EventEmitter = require('events').EventEmitter;
var Utils = require('../utils');
var GPIO_PATH = "/sys/class/gpio";
var GPIO_READ = "in";
@ -28,7 +30,7 @@ var DigitalPin = module.exports = function DigitalPin(opts) {
this.mode = opts.mode;
}
subclass(DigitalPin, EventEmitter);
Utils.subclass(DigitalPin, EventEmitter);
DigitalPin.prototype.connect = function(mode) {
var _this = this;
@ -81,7 +83,7 @@ DigitalPin.prototype.digitalRead = function(interval) {
if (this.mode !== 'r') { this._setMode('r'); }
every(interval, function() {
Utils.every(interval, function() {
FS.readFile(_this._valuePath(), function(err, data) {
if (err) {
var error = "Error occurred while reading from pin " + _this.pinNum;

View File

@ -8,11 +8,10 @@
'use strict';
require('./utils');
var Connection = require("./connection"),
Device = require("./device"),
Logger = require('./logger'),
Utils = require('./utils'),
config = require('./config');
var Async = require("async"),
@ -43,7 +42,7 @@ var Robot;
// name: 'sphero', driver: 'sphero'
//
// work: (me) ->
// every 1.second(), ->
// Utils.every 1.second(), ->
// me.sphero.roll 60, Math.floor(Math.random() * 360//
module.exports = Robot = function Robot(opts) {
if (opts == null) {
@ -66,7 +65,7 @@ module.exports = Robot = function Robot(opts) {
for (var i = 0; i < methods.length ; i++) {
var method = methods[i];
this[method] = bind(this[method], this);
this[method] = Utils.bind(this[method], this);
}
this.robot = this;
@ -101,7 +100,7 @@ module.exports = Robot = function Robot(opts) {
}
};
subclass(Robot, EventEmitter);
Utils.subclass(Robot, EventEmitter);
// Public: Generates a random name for a Robot.
//
@ -276,7 +275,7 @@ Robot.prototype.initAdaptor = function(adaptorName, connection, opts) {
connection: connection,
extraParams: opts
});
return proxyTestStubs(adaptor.commands(), testAdaptor);
return Utils.proxyTestStubs(adaptor.commands(), testAdaptor);
} else {
return adaptor;
}
@ -339,7 +338,7 @@ Robot.prototype.initDriver = function(driverName, device, opts) {
extraParams: opts
});
return proxyTestStubs(driver.commands(), testDriver);
return Utils.proxyTestStubs(driver.commands(), testDriver);
} else {
return driver;
}

View File

@ -8,7 +8,8 @@
"use strict";
var Adaptor = require('../adaptor');
var Adaptor = require('../adaptor'),
Utils = require('../utils');
var Loopback;
@ -16,7 +17,7 @@ module.exports = Loopback = function Loopback() {
Loopback.__super__.constructor.apply(this, arguments);
};
subclass(Loopback, Adaptor);
Utils.subclass(Loopback, Adaptor);
Loopback.prototype.commands = function() {
return ['ping'];

View File

@ -8,7 +8,8 @@
'use strict';
var Driver = require('../driver');
var Driver = require('../driver'),
Utils = require('../utils');
var Ping;
@ -16,7 +17,7 @@ module.exports = Ping = function Ping() {
Ping.__super__.constructor.apply(this, arguments);
};
subclass(Ping, Driver);
Utils.subclass(Ping, Driver);
Ping.prototype.commands = function() {
return ['ping'];

View File

@ -8,7 +8,8 @@
"use strict";
var Adaptor = require('../adaptor')
var Adaptor = require('../adaptor'),
Utils = require('../utils');
var TestAdaptor;
@ -16,6 +17,6 @@ module.exports = TestAdaptor = function TestAdaptor() {
TestAdaptor.__super__.constructor.apply(this, arguments);
};
subclass(TestAdaptor, Adaptor);
Utils.subclass(TestAdaptor, Adaptor);
TestAdaptor.adaptor = function(opts) { return new TestAdaptor(opts); };

View File

@ -8,7 +8,8 @@
'use strict';
var Driver = require('../driver');
var Driver = require('../driver'),
Utils = require('../utils');
var TestDriver;
@ -16,6 +17,6 @@ module.exports = TestDriver = function TestDriver() {
TestDriver.__super__.constructor.apply(this, arguments);
};
subclass(TestDriver, Driver);
Utils.subclass(TestDriver, Driver);
TestDriver.driver = function(opts) { return new TestDriver(opts); };

View File

@ -1,11 +1,214 @@
/*
* utils
* Cylon - Utils
* cylonjs.com
*
* Copyright (c) 2013 The Hybrid Group
* 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;
},
// 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 fn = function(method) {
return base[method] = function() {
var args = arguments.length >= 1 ? [].slice.call(arguments, 0) : [];
return target[method].apply(target, args);
};
};
for (var i = 0; i < methods.length; i++) {
var method = methods[i];
if (!force && typeof(base[method]) === 'function') {
continue;
}
fn(method);
}
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
proxyTestStubs: function proxyTestStubs(methods, base) {
if (base == null) {
base = this;
}
methods.forEach(function(method) {
base[method] = function() {
return true;
};
base.commandList.push(method);
});
return base;
},
// Public: Binds an argument to a caller
//
// fn - function to bind
// me - value for 'this' scope inside the function
//
// Examples
//
// var me = { hello: "Hello World" };
// var proxy = { boundMethod: function() { return this.hello; } };
//
// proxy.boundMethod = bind(proxy.boundMethod, me);
// proxy.boundMethod();
//
// //=> "Hello World"
//
// Returns a function wrapper
bind: function bind(fn, me) {
return function() {
return fn.apply(me, arguments);
};
},
// 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() {
// 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.
@ -77,190 +280,6 @@ Number.prototype.toScale = function(start, end) {
return i;
}
};
global.Utils = {
// 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;
}
},
// Copies
slice: [].slice,
hasProp: {}.hasOwnProperty,
// 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 (hasProp.call(parent, key)) { child[key] = parent[key]; }
}
ctor.prototype = parent.prototype;
child.prototype = new ctor();
child.__super__ = parent.prototype;
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
proxyFunctionsToObject: function proxyFunctionsToObject(methods, target, base, force) {
if (base == null) { base = this; }
if (force == null) { force = false; }
var fn = function(method) {
return base[method] = function() {
var args = arguments.length >= 1 ? [].slice.call(arguments, 0) : [];
return target[method].apply(target, args);
};
};
for (var i = 0; i < methods.length; i++) {
var method = methods[i];
if (!force) {
if (typeof base[method] === 'function') { continue; }
}
fn(method);
}
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
proxyTestStubs: function proxyTestStubs(methods, base) {
if (base == null) { base = this; }
methods.forEach(function(method) {
base[method] = function() { return true; };
base.commandList.push(method);
});
return base;
},
// Public: Binds an argument to a caller
//
// fn - function to bind
// me - value for 'this' scope inside the function
//
// Examples
//
// var me = { hello: "Hello World" };
// var proxy = { boundMethod: function() { return this.hello; } };
//
// proxy.boundMethod = bind(proxy.boundMethod, me);
// proxy.boundMethod();
//
// //=> "Hello World"
//
// Returns a function wrapper
bind: function bind(fn, me) {
return function() { return fn.apply(me, arguments); };
},
// Public: Adds all methods from Cylon.Utils directly to the global
// namespace.
//
// Examples
//
// Utils.bootstrap();
// (after === Utils.after) // true
//
// Returns Cylon.Utils
bootstrap: function bootstrap() {
for (util in this) {
// we're not going to attach the 'bootstrap' method
if (!(util === "bootstrap")) {
global[util] = this[util];
}
}
return this;
}
};
module.exports = Utils.bootstrap();
Utils.bootstrap();

View File

@ -3,7 +3,8 @@
var EventEmitter = require('events').EventEmitter;
var Adaptor = source("adaptor"),
Logger = source('logger');
Logger = source('logger'),
Utils = source('utils');
describe("Adaptor", function() {
var connection = new EventEmitter;

View File

@ -4,7 +4,8 @@ var express = require('express'),
https = require('https'),
fs = require('fs');
var API = source('api');
var API = source('api'),
Utils = source('utils');
describe("API", function() {
var api, opts;

View File

@ -1,6 +1,7 @@
"use strict";
var Basestar = source('basestar');
var Basestar = source('basestar'),
Utils = source('utils');
var EventEmitter = require('events').EventEmitter;
@ -34,7 +35,7 @@ describe('Basestar', function() {
this.proxyMethods(methods, this.testInstance, this, true);
}
subclass(TestClass, Basestar);
Utils.subclass(TestClass, Basestar);
it('can alias methods', function() {
var testclass = new TestClass;
@ -70,8 +71,8 @@ describe('Basestar', function() {
});
}
subclass(ProxyClass, Basestar);
subclass(EmitterClass, Basestar);
Utils.subclass(ProxyClass, Basestar);
Utils.subclass(EmitterClass, Basestar);
it("proxies events from one class to another", function() {
var eventSpy = spy(),

View File

@ -1,7 +1,8 @@
"use strict";
var Robot = source("robot"),
Logger = source('logger');
Logger = source('logger'),
Utils = source('utils');
describe("Cylon.Connection", function() {
var robot = new Robot({

View File

@ -1,6 +1,7 @@
"use strict";
var Cylon = source("cylon");
var Cylon = source("cylon"),
Utils = source('utils');
var API = source('api'),
Logger = source('logger'),

View File

@ -3,7 +3,8 @@
var Ping = source('test/ping'),
Device = source("device"),
Robot = source("robot"),
Logger = source('logger');
Logger = source('logger'),
Utils = source('utils');
describe("Cylon.Device", function() {
var robot = new Robot({

View File

@ -2,7 +2,8 @@
var fs = require('fs');
var DigitalPin = source('io/digital-pin');
var DigitalPin = source('io/digital-pin'),
Utils = source('utils');
describe("Cylon.IO.DigitalPin", function() {
var pin = new DigitalPin({ pin: '4', mode: 'w' })
@ -195,12 +196,12 @@ describe("Cylon.IO.DigitalPin", function() {
context("if the mode isn't 'r'", function() {
before(function() {
stub(global, 'every');
stub(Utils, 'every');
stub(pin, '_setMode');
});
after(function() {
global.every.restore();
Utils.every.restore();
pin._setMode.restore();
});

View File

@ -3,7 +3,8 @@
var EventEmitter = require('events').EventEmitter;
var Driver = source("driver"),
Logger = source('logger');
Logger = source('logger'),
Utils = source('utils');
describe("Driver", function() {
var device = {

View File

@ -1,6 +1,7 @@
'use strict';
var Logger = source('logger');
var Logger = source('logger'),
Utils = source('utils');
describe('Logger', function() {
after(function() {

View File

@ -2,7 +2,8 @@
var Device = source('device'),
Connection = source('connection'),
Robot = source("robot");
Robot = source("robot"),
Utils = source('utils');
describe("Robot", function() {
var work = spy();

View File

@ -95,20 +95,6 @@ describe("Utils", function() {
});
});
describe("#slice", function() {
it("performs array slices", function() {
var arr = [1, 2, 3, 4, 5];
expect(slice.call(arr, 1)).to.be.eql([2, 3, 4, 5]);
});
});
describe("hasProp", function() {
it("checks objects have properties", function() {
var obj = { test: 'test' };
expect(hasProp.call(obj, 'test')).to.be.true;
});
});
describe("#subclass", function() {
var BaseClass = (function() {
function BaseClass(opts) {
@ -123,7 +109,7 @@ describe("Utils", function() {
})();
var SubClass = (function(klass) {
subclass(SubClass, klass);
utils.subclass(SubClass, klass);
function SubClass(opts) {
SubClass.__super__.constructor.apply(this, arguments);
@ -164,7 +150,7 @@ describe("Utils", function() {
function TestClass() {
this.self = this;
this.testInstance = new ProxyClass;
proxyFunctionsToObject(methods, this.testInstance, this.self, true);
utils.proxyFunctionsToObject(methods, this.testInstance, this.self, true);
}
return TestClass;
@ -190,7 +176,7 @@ describe("Utils", function() {
var methods = ["hello", "goodbye"],
base = { commandList: [] };
proxyTestStubs(methods, base);
utils.proxyTestStubs(methods, base);
expect(base.commandList).to.be.eql(methods);
});
@ -198,7 +184,7 @@ describe("Utils", function() {
var methods = ["hello", "goodbye"],
base = { commandList: [] };
expect(proxyTestStubs(methods, base)).to.be.eql(base);
expect(utils.proxyTestStubs(methods, base)).to.be.eql(base);
});
});
@ -208,14 +194,14 @@ describe("Utils", function() {
it("binds the 'this' scope for the method", function() {
proxy.boundMethod = function() { return this.hello; };
proxy.boundMethod = bind(proxy.boundMethod, me);
proxy.boundMethod = utils.bind(proxy.boundMethod, me);
expect(proxy.boundMethod()).to.eql("Hello World");
});
it("passes arguments along to bound functions", function() {
proxy.boundMethod = function(hello, world) { return [hello, world]; };
proxy.boundMethod = bind(proxy.boundMethod, me);
proxy.boundMethod = utils.bind(proxy.boundMethod, me);
expect(proxy.boundMethod("Hello", "World")).to.eql(["Hello", "World"]);
})