cylon/lib/utils.js

257 lines
6.4 KiB
JavaScript

/*
* Cylon - Utils
* cylonjs.com
*
* Copyright (c) 2013-2015 The Hybrid Group
* Licensed under the Apache 2.0 license.
*/
"use strict";
var _ = require("./utils/helpers");
var monkeyPatches = require("./utils/monkey-patches");
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 = 0;
while (Date.now() < start + ms) {
i = i.toString();
}
},
// 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 (parent.hasOwnProperty(key)) {
child[key] = parent[key];
}
}
Ctor.prototype = parent.prototype;
child.prototype = new Ctor();
child.__super__ = parent.prototype;
return child;
},
proxyFunctions: function proxyFunctions(source, target) {
_.each(source, function(prop, key) {
if (_.isFunction(prop) && !target[key]) {
target[key] = prop.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;
}
force = force || false;
methods.forEach(function(method) {
if (_.isFunction(base[method]) && !force) {
return;
}
base[method] = function() {
return target[method].apply(target, arguments);
};
});
return base;
},
classCallCheck: function(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
},
// 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 (_.isFunction(fallback)) {
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;
monkeyPatches.install();
return this;
}
};
Utils.bootstrap();