2013-10-25 05:25:42 +08:00
|
|
|
/*
|
2014-06-06 03:11:37 +08:00
|
|
|
* Cylon - Utils
|
2013-10-25 05:25:42 +08:00
|
|
|
* cylonjs.com
|
|
|
|
*
|
2015-01-08 04:58:50 +08:00
|
|
|
* Copyright (c) 2013-2015 The Hybrid Group
|
2013-10-25 05:25:42 +08:00
|
|
|
* Licensed under the Apache 2.0 license.
|
|
|
|
*/
|
|
|
|
|
2014-12-16 03:15:29 +08:00
|
|
|
"use strict";
|
|
|
|
|
2015-02-21 10:49:31 +08:00
|
|
|
var _ = require("./utils/helpers");
|
|
|
|
|
2015-02-20 09:23:41 +08:00
|
|
|
var monkeyPatches = require("./utils/monkey-patches");
|
2014-12-16 03:15:29 +08:00
|
|
|
|
2014-06-06 03:11:37 +08:00
|
|
|
var Utils = module.exports = {
|
2014-05-14 09:24:41 +08:00
|
|
|
// 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
|
|
|
|
//
|
2014-06-06 00:32:20 +08:00
|
|
|
// every((5).seconds(), function() {
|
2014-12-16 03:15:29 +08:00
|
|
|
// console.log("Hello world (and again in 5 seconds)!");
|
2014-06-06 00:32:20 +08:00
|
|
|
// });
|
2014-05-14 09:24:41 +08:00
|
|
|
//
|
|
|
|
// 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
|
|
|
|
//
|
2014-06-06 00:32:20 +08:00
|
|
|
// after((10).seconds(), function() {
|
2014-12-16 03:15:29 +08:00
|
|
|
// console.log("Hello world from ten seconds ago!");
|
2014-06-06 00:32:20 +08:00
|
|
|
// });
|
2014-05-14 09:24:41 +08:00
|
|
|
//
|
|
|
|
// Returns an interval
|
|
|
|
after: function after(delay, action) {
|
|
|
|
return setTimeout(action, delay);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Public: Alias to the `every` function, but passing 0
|
|
|
|
// Examples
|
|
|
|
//
|
2014-06-06 00:32:20 +08:00
|
|
|
// constantly(function() {
|
2014-12-16 03:15:29 +08:00
|
|
|
// console.log("hello world (and again and again)!");
|
2014-06-06 00:32:20 +08:00
|
|
|
// });
|
2014-05-14 09:24:41 +08:00
|
|
|
//
|
|
|
|
// 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
|
|
|
|
//
|
2014-06-06 00:32:20 +08:00
|
|
|
// Examples
|
|
|
|
//
|
|
|
|
// sleep((1).second());
|
|
|
|
//
|
2014-05-14 09:24:41 +08:00
|
|
|
// Returns a function
|
|
|
|
sleep: function sleep(ms) {
|
2014-12-16 03:15:29 +08:00
|
|
|
var start = Date.now(),
|
2015-04-15 12:49:12 +08:00
|
|
|
i = 0;
|
2014-05-14 09:24:41 +08:00
|
|
|
|
2015-04-15 12:49:12 +08:00
|
|
|
while (Date.now() < start + ms) {
|
|
|
|
i = i.toString();
|
2014-05-14 09:24:41 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2014-12-16 03:15:29 +08:00
|
|
|
// Public: Function to use for class inheritance.
|
|
|
|
// Based on CoffeeScript's implementation.
|
2014-05-14 09:24:41 +08:00
|
|
|
//
|
|
|
|
// Example
|
|
|
|
//
|
2014-06-06 00:32:20 +08:00
|
|
|
// var Sphero = function Sphero() {};
|
|
|
|
//
|
|
|
|
// subclass(Sphero, ParentClass);
|
|
|
|
//
|
|
|
|
// // Sphero is now a subclass of Parent, and can access parent methods
|
|
|
|
// // through Sphero.__super__
|
2014-05-14 09:24:41 +08:00
|
|
|
//
|
|
|
|
// Returns subclass
|
|
|
|
subclass: function subclass(child, parent) {
|
2014-12-16 03:15:29 +08:00
|
|
|
var Ctor = function() {
|
2014-06-06 07:30:05 +08:00
|
|
|
this.constructor = child;
|
|
|
|
};
|
2014-05-14 09:24:41 +08:00
|
|
|
|
2015-02-20 09:23:41 +08:00
|
|
|
for (var key in parent) {
|
|
|
|
if (parent.hasOwnProperty(key)) {
|
|
|
|
child[key] = parent[key];
|
|
|
|
}
|
|
|
|
}
|
2014-04-02 03:31:13 +08:00
|
|
|
|
2014-12-16 03:15:29 +08:00
|
|
|
Ctor.prototype = parent.prototype;
|
|
|
|
child.prototype = new Ctor();
|
2014-05-14 09:24:41 +08:00
|
|
|
child.__super__ = parent.prototype;
|
|
|
|
return child;
|
|
|
|
},
|
|
|
|
|
2014-10-03 02:00:39 +08:00
|
|
|
proxyFunctions: function proxyFunctions(source, target) {
|
2015-02-21 10:49:31 +08:00
|
|
|
_.each(source, function(prop, key) {
|
|
|
|
if (_.isFunction(prop) && !target[key]) {
|
2014-12-18 06:42:34 +08:00
|
|
|
target[key] = prop.bind(source);
|
2014-10-03 02:00:39 +08:00
|
|
|
}
|
2015-02-21 10:49:31 +08:00
|
|
|
});
|
2014-10-03 02:00:39 +08:00
|
|
|
},
|
|
|
|
|
2014-05-14 09:24:41 +08:00
|
|
|
// 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
|
2014-12-16 03:15:29 +08:00
|
|
|
// 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
|
2014-05-14 09:24:41 +08:00
|
|
|
//
|
|
|
|
// Returns base
|
2014-12-16 03:15:29 +08:00
|
|
|
proxyFunctionsToObject: function(methods, target, base, force) {
|
2014-06-06 07:30:05 +08:00
|
|
|
if (base == null) {
|
|
|
|
base = this;
|
|
|
|
}
|
|
|
|
|
2014-12-18 06:42:34 +08:00
|
|
|
force = force || false;
|
2014-03-11 03:00:48 +08:00
|
|
|
|
2015-02-20 09:23:41 +08:00
|
|
|
methods.forEach(function(method) {
|
2015-02-21 10:49:31 +08:00
|
|
|
if (_.isFunction(base[method]) && !force) {
|
2014-12-18 06:42:34 +08:00
|
|
|
return;
|
2014-03-11 03:00:48 +08:00
|
|
|
}
|
2014-04-02 03:31:13 +08:00
|
|
|
|
2014-12-19 05:15:30 +08:00
|
|
|
base[method] = function() {
|
|
|
|
return target[method].apply(target, arguments);
|
|
|
|
};
|
2014-12-18 06:42:34 +08:00
|
|
|
});
|
|
|
|
|
2014-05-14 09:24:41 +08:00
|
|
|
return base;
|
|
|
|
},
|
|
|
|
|
2014-12-16 03:15:29 +08:00
|
|
|
// Public: Analogue to Ruby"s Hash#fetch method for looking up object
|
2014-06-18 07:00:36 +08:00
|
|
|
// properties.
|
|
|
|
//
|
|
|
|
// obj - object to do property lookup on
|
|
|
|
// property - string property name to attempt to look up
|
|
|
|
// fallback - either:
|
2014-12-16 03:15:29 +08:00
|
|
|
// - a fallback value to return if `property` can"t be found
|
|
|
|
// - a function to be executed if `property` can"t be found. The function
|
2014-06-18 07:00:36 +08:00
|
|
|
// 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
|
2014-12-16 03:15:29 +08:00
|
|
|
// running "fallback". If the property isn"t found, and "fallback" hasn"t been
|
2014-06-18 07:00:36 +08:00
|
|
|
// provided, will throw an error.
|
|
|
|
fetch: function(obj, property, fallback) {
|
|
|
|
if (obj.hasOwnProperty(property)) {
|
|
|
|
return obj[property];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fallback === void 0) {
|
2014-12-16 03:15:29 +08:00
|
|
|
throw new Error("key not found: \"" + property + "\"");
|
2014-06-18 07:00:36 +08:00
|
|
|
}
|
|
|
|
|
2015-02-21 10:49:31 +08:00
|
|
|
if (_.isFunction(fallback)) {
|
2014-06-18 07:00:36 +08:00
|
|
|
var value = fallback(property);
|
|
|
|
|
|
|
|
if (value === void 0) {
|
2014-12-16 03:15:29 +08:00
|
|
|
throw new Error("no return value from provided fallback function");
|
2014-06-18 07:00:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fallback;
|
|
|
|
},
|
|
|
|
|
2014-09-05 05:51:44 +08:00
|
|
|
// Public: Given a name, and an array of existing names, returns a unique
|
|
|
|
// name.
|
|
|
|
//
|
2014-12-16 03:15:29 +08:00
|
|
|
// name - name that"s colliding with existing names
|
2014-09-05 05:51:44 +08:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2014-06-06 03:11:37 +08:00
|
|
|
// Public: Adds necessary utils to global namespace, along with base class
|
|
|
|
// extensions.
|
2014-05-14 09:24:41 +08:00
|
|
|
//
|
|
|
|
// Examples
|
|
|
|
//
|
2014-06-06 03:11:37 +08:00
|
|
|
// Number.prototype.seconds // undefined
|
|
|
|
// after // undefined
|
|
|
|
//
|
2014-06-06 00:32:20 +08:00
|
|
|
// Utils.bootstrap();
|
2014-06-06 03:11:37 +08:00
|
|
|
//
|
|
|
|
// Number.prototype.seconds // [function]
|
|
|
|
// (after === Utils.after) // true
|
2014-05-14 09:24:41 +08:00
|
|
|
//
|
|
|
|
// Returns Cylon.Utils
|
|
|
|
bootstrap: function bootstrap() {
|
2014-06-06 03:11:37 +08:00
|
|
|
global.every = this.every;
|
|
|
|
global.after = this.after;
|
|
|
|
global.constantly = this.constantly;
|
|
|
|
|
2015-02-21 02:52:01 +08:00
|
|
|
monkeyPatches.install();
|
2014-03-11 03:00:48 +08:00
|
|
|
|
2014-05-14 09:24:41 +08:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-06-06 03:11:37 +08:00
|
|
|
Utils.bootstrap();
|