fieldkit
Version:
Basic building blocks for computational design projects. Written in CoffeeScript for browser and server environments.
316 lines (264 loc) • 7.95 kB
JavaScript
// Generated by CoffeeScript 1.6.3
(function() {
var EXObject, Mixin, clone, extend, removeElement, shuffle, util,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
util = require("util");
/*
JavaScript Language Utilities
------------------------------------------------------------------------------------------
*/
extend = function(obj, source) {
var i, il, keys, prop, safeHasOwnProperty;
if (Object.keys) {
keys = Object.keys(source);
i = 0;
il = keys.length;
while (i < il) {
prop = keys[i];
Object.defineProperty(obj, prop, Object.getOwnPropertyDescriptor(source, prop));
i++;
}
} else {
safeHasOwnProperty = {}.hasOwnProperty;
for (prop in source) {
if (safeHasOwnProperty.call(source, prop)) {
obj[prop] = source[prop];
}
}
}
return obj;
};
/*
Swappable Mixins in CoffeeScript
Many thanks to Hashmal, who wrote this to start.
https://gist.github.com/803816/aceed8fc57188c3a19ce2eccdb25acb64f2be94e
Usage
-----
class Derp extends Mixin
setup: ->
@googly = "eyes"
derp: ->
alert "Herp derp! What's with your #{ @googly }?"
class Herp
constructor: ->
Derp::augment this
herp = new Herp
herp.derp()
Mixin
-----
Classes inheriting `Mixin` will become removable mixins, enabling you to
swap them around.
Limitations
-----------
* When a class is augmented, all instances of that class are augmented too,
and when a mixin is ejected from a class, all instances lose that mixin too.
* You can't eject a mixin from an object if that mixin was added to the object's class. Eject the mixin from the class instead.
*/
Mixin = (function() {
function Mixin() {}
Mixin.prototype.augment = function(t) {
var m, n;
for (n in this) {
m = this[n];
if (!(n === 'augment' || (this[n].prototype == null))) {
t[n] = m;
}
}
return t.setup();
};
Mixin.prototype.eject = function(mixin) {
var m, n, o, p, _results;
_results = [];
for (n in this) {
m = this[n];
_results.push(__indexOf.call((function() {
var _ref, _results1;
_ref = mixin.prototype;
_results1 = [];
for (o in _ref) {
p = _ref[o];
_results1.push(p);
}
return _results1;
})(), m) >= 0 ? delete this[n] : void 0);
}
return _results;
};
Mixin.prototype.setup = function() {};
return Mixin;
})();
/*
Clones (copies) an Object using deep copying.
This function supports circular references by default, but if you are certain
there are no circular references in your object, you can save some CPU time
by calling clone(obj, false).
Caution: if `circular` is false and `parent` contains circular references,
your program may enter an infinite loop and crash.
@param `parent` - the object to be cloned
@param `circular` - set to true if the object to be cloned may contain
circular references. (optional - true by default)
*/
clone = function(parent, circular) {
var c, child, circularParent, circularReplace, circularResolved, cloned, i, useBuffer, _clone;
if (typeof circular === "undefined") {
circular = true;
}
useBuffer = typeof Buffer !== "undefined";
i = void 0;
if (circular) {
_clone = function(parent, context, child, cIndex) {
i = void 0;
if (typeof parent === "object") {
if (parent == null) {
return parent;
}
for (i in circularParent) {
if (circularParent[i] === parent) {
circularReplace.push({
resolveTo: i,
child: child,
i: cIndex
});
return null;
}
}
circularParent[context] = parent;
if (util.isArray(parent)) {
child = [];
for (i in parent) {
child[i] = _clone(parent[i], context + "[" + i + "]", child, i);
}
} else if (util.isDate(parent)) {
child = new Date(parent.getTime());
} else if (util.isRegExp(parent)) {
child = new RegExp(parent.source);
} else if (useBuffer && Buffer.isBuffer(parent)) {
child = new Buffer(parent.length);
parent.copy(child);
} else {
child = {};
child.__proto__ = parent.__proto__;
for (i in parent) {
child[i] = _clone(parent[i], context + "[" + i + "]", child, i);
}
}
circularResolved[context] = child;
} else {
child = parent;
}
return child;
};
circularParent = {};
circularResolved = {};
circularReplace = [];
cloned = _clone(parent, "*");
for (i in circularReplace) {
c = circularReplace[i];
if (c && c.child && c.i in c.child) {
c.child[c.i] = circularResolved[c.resolveTo];
}
}
return cloned;
} else {
child = void 0;
if (typeof parent === "object") {
if (parent == null) {
return parent;
}
if (parent.constructor.name === "Array") {
child = [];
for (i in parent) {
child[i] = clone(parent[i], circular);
}
} else if (util.isDate(parent)) {
child = new Date(parent.getTime());
} else if (!util.isRegExp(parent)) {
child = {};
child.__proto__ = parent.__proto__;
for (i in parent) {
child[i] = clone(parent[i], circular);
}
}
} else {
child = parent;
}
return child;
}
};
clone.clonePrototype = function(parent) {
var ctor;
if (parent === null) {
return null;
}
ctor = function() {};
ctor.prototype = parent;
return new ctor();
};
/*
JavaScript getter and setter support for CoffeeScript classes
Ref: https://github.com/jashkenas/coffee-script/issues/1039
Note:
Classes using this wont work under IE6 + IE7
Usage:
class Vector3D extends EXObject
constructor: (@x, @y, @z) ->
@get 'x', -> @[0]
@get 'y', -> @[1]
@get 'z', -> @[2]
@set 'x', (x) -> @[0] = x
@set 'y', (y) -> @[1] = y
@set 'z', (z) -> @[2] = z
*/
EXObject = (function() {
function EXObject() {}
EXObject.get = function(propertyName, func) {
return Object.defineProperty(this.prototype, propertyName, {
configurable: true,
enumerable: true,
get: func
});
};
EXObject.set = function(propertyName, func) {
return Object.defineProperty(this.prototype, propertyName, {
configurable: true,
enumerable: true,
set: func
});
};
return EXObject;
})();
/*
Array Utilities
------------------------------------------------------------------------------------------
*/
removeElement = function(element, list) {
var index;
index = list.indexOf(element);
if (index !== -1) {
list.splice(index, 1);
}
return list;
};
shuffle = function(object, rng) {
var i, j, x;
if (rng == null) {
rng = Math;
}
i = object.length;
while (i) {
j = parseInt(rng.random() * i);
x = object[--i];
object[i] = object[j];
object[j] = x;
}
return object;
};
module.exports = {
extend: extend,
clone: clone,
EXObject: EXObject,
Mixin: Mixin,
removeElement: removeElement,
shuffle: shuffle
};
}).call(this);