glass-platform
Version:
Glass platform
501 lines (454 loc) • 15.2 kB
JavaScript
// Generated by CoffeeScript 1.6.2
(function() {
var Component, assert, dispose, extend, generateId, getBaseDefiningClass, getUnderrideName, glass_Component, initialize, isPrimitive, properties, underride,
__slice = [].slice;
require('./global');
generateId = function(parent, type) {
var count, counts, name, _ref, _ref1;
name = type.name;
if (name == null) {
throw new Error("type did not have a name: " + type);
}
counts = (_ref = parent._Component_generateId_counts) != null ? _ref : parent._Component_generateId_counts = {};
count = (_ref1 = counts[name]) != null ? _ref1 : counts[name] = 0;
count++;
counts[name] = count;
return "" + name + "_" + count;
};
module.exports = Component = glass_Component = (function() {
function glass_Component(properties) {
this.initialize(properties);
this;
}
return glass_Component;
})();
isPrimitive = function(object) {
return Object.isNumber(object) || Object.isBoolean(object) || Object.isString(object);
};
Component.normalizeProperties = function(properties, definingClass) {
var name, property, _base, _base1, _ref, _ref1, _ref2, _ref3;
if (properties == null) {
properties = {};
}
for (name in properties) {
property = properties[name];
if (Object.isFunction(property)) {
property = {
writable: false,
value: property
};
} else if ((property == null) || isPrimitive(property) || Object.isArray(property)) {
property = {
value: property
};
}
if ((property.get == null) && (property.set == null) && !property.hasOwnProperty('value')) {
property.value = null;
}
if (property.hasOwnProperty('value')) {
if ((_ref = property.writable) == null) {
property.writable = true;
}
}
if (Object.isFunction(property.value)) {
if ((_ref1 = (_base = property.value).id) == null) {
_base.id = name;
}
}
if (definingClass != null) {
if ((_ref2 = property.definingClass) == null) {
property.definingClass = definingClass;
}
if (Object.isFunction(property.value)) {
if ((_ref3 = (_base1 = property.value).definingClass) == null) {
_base1.definingClass = definingClass;
}
}
}
properties[name] = property;
}
return properties;
};
Component.defineProperties = function(object, properties, definingClass) {
properties = Component.normalizeProperties(properties, definingClass);
Object.defineProperties(object, properties);
return properties;
};
Component.disposeProperties = function(object) {
var key, value;
for (key in object) {
value = object[key];
if ((value != null) && value.parent === object && Object.isFunction(value.dispose)) {
value.dispose();
}
}
};
Component.id = "glass.Component";
Component.toString = function() {
return this.id;
};
Component.valueOf = function() {
var _ref;
return (_ref = this.value) != null ? _ref : this.id;
};
properties = {
id: {
get: function() {
return this._id;
},
set: function(value) {
if (this._id != null) {
throw new Error("id has already been set to " + this._id);
}
return this._id = value;
}
},
parent: {
get: function() {
return this._parent;
},
set: function(value) {
if (this._parent != null) {
throw new Error("parent has already been set to " + this._parent);
}
return this._parent = value;
}
},
inner: {
description: "Calls the subclass defined function if present.",
value: function() {
var args, fn, innerName, _ref, _ref1;
fn = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
innerName = (_ref = fn.innerName) != null ? _ref : fn.innerName = getUnderrideName(fn.definingClass, fn.id);
return (_ref1 = this[innerName]) != null ? _ref1.apply(this, args) : void 0;
}
},
initialize: initialize = function(properties) {
var id, key, parent, value, _ref;
if (properties == null) {
throw new Error("properties object is required " + properties);
}
if (properties.parent == null) {
throw new Error("parent is required");
}
parent = properties.parent;
id = (_ref = properties.id) != null ? _ref : properties.id = generateId(parent, this.constructor);
parent[id] = this;
for (key in properties) {
value = properties[key];
this[key] = value;
}
return this.inner(initialize);
},
dispose: dispose = function() {
if (this._parent != null) {
Component.disposeProperties(this);
if (this._parent === global) {
delete this._parent[this.id];
} else {
this._parent[this.id] = null;
}
this._parent = null;
this.inner(dispose);
}
},
disposed: {
get: function() {
return this._parent === null;
}
},
get: function(id, parsed) {
var colon, factory, isClass, throwError, type, value, _base;
if (id == null) {
throw new Error("id is required");
}
value = this[id];
if (value != null) {
if (value.disposed === true) {
value = null;
} else {
return value;
}
}
throwError = parsed == null;
if (parsed == null) {
colon = id.indexOf(':');
if (colon > 0) {
parsed = {
type: id.substring(0, colon),
properties: JSON.parse(id.substring(colon + 1))
};
} else {
parsed = false;
}
}
if (parsed) {
type = parsed.type;
properties = parsed.properties;
factory = this[type];
if (Object.isFunction(factory)) {
properties.parent = this;
isClass = factory.properties != null;
if (isClass) {
value = new factory(properties);
} else {
value = factory(properties);
}
}
}
if (value == null) {
value = typeof (_base = this.parent).get === "function" ? _base.get(id, parsed) : void 0;
}
if (value != null) {
this[id] = value;
} else if (throwError) {
throw new Error("Component not found: " + id);
}
return value;
}
};
Component.properties = Component.defineProperties(Component.prototype, properties, Component);
getUnderrideName = function(baseDefiningClass, name) {
return "" + baseDefiningClass.name + "_subclass_" + name;
};
getBaseDefiningClass = function(classDefinition, properties, name) {
var baseDefiningClass, baseFunction, baseProperty, callsUnderride, underrideName, underrideProperty;
baseProperty = properties[name];
while (true) {
baseFunction = baseProperty.value;
baseDefiningClass = baseProperty.definingClass;
underrideName = getUnderrideName(baseDefiningClass, name);
callsUnderride = baseFunction.toString().has(underrideName) || baseFunction.toString().has(/\binner\b/);
if (!callsUnderride) {
throw new Error("" + classDefinition.name + "." + name + " cannot be defined because " + baseDefiningClass.name + "." + name + " does not call " + underrideName + ".");
}
underrideProperty = properties[underrideName];
if (underrideProperty != null) {
baseProperty = underrideProperty;
} else {
return baseDefiningClass;
}
}
};
underride = function(classDefinition, properties, rootDefiningClass, name, fn) {
var baseDefiningClass;
baseDefiningClass = getBaseDefiningClass(classDefinition, properties, name);
properties[getUnderrideName(baseDefiningClass, name)] = fn;
};
extend = function(baseClass, subClassDefinition) {
var baseProperty, name, property, prototype, subClass, subProperties;
if (!Object.isString(subClassDefinition != null ? subClassDefinition.id : void 0)) {
throw new Error("missing id property");
}
subClassDefinition.name = subClassDefinition.id.replace(/[\.\/]/g, '_');
subClass = eval("(function " + subClassDefinition.name + "(properties) {\n this.initialize(properties);\n})");
subProperties = subClassDefinition.properties = Component.normalizeProperties(subClassDefinition.properties, subClass);
prototype = subClass.prototype;
properties = Object.clone(baseClass.properties);
for (name in subProperties) {
property = subProperties[name];
baseProperty = properties[name];
if (Object.isFunction(baseProperty != null ? baseProperty.value : void 0)) {
if (!Object.isFunction(property.value)) {
throw new Error("Functions can only be overridden with other functions: " + property.value);
}
underride(subClassDefinition, properties, baseProperty.definingClass, name, property.value);
} else {
properties[name] = property;
}
}
subClassDefinition.properties = properties;
Object.merge(subClass, subClassDefinition);
Component.defineProperties(prototype, properties, subClass);
subClass.extend = function(subClassDefinition) {
return extend(subClass, subClassDefinition);
};
return subClass;
};
Component.extend = function(subClassDefinition) {
return extend(Component, subClassDefinition);
};
if (typeof describe === 'function') {
assert = require('assert');
describe('glass.Component', function() {
it("should have an id", function() {
return assert(Object.isString(Component.id));
});
it("its toString should return it's id", function() {
return assert.equal(Component.toString(), "glass.Component");
});
it("should have a name", function() {
return assert.equal(Component.name, "glass_Component");
});
describe('#dispose', function() {
it('should mark self disposed', function() {
var a;
a = new Component({
parent: global
});
a.dispose();
return assert(a.disposed);
});
it('should dispose of children', function() {
var a, b;
a = new Component({
parent: global
});
b = new Component({
parent: a
});
a.dispose();
return assert(b.disposed);
});
return it('should remove property from parent', function() {
var a;
a = new Component({
parent: global
});
a.dispose();
return assert(global[a.id] == null);
});
});
describe('#defineProperties', function() {
return it("should allow primitive values", function() {
var object;
object = {};
Component.defineProperties(object, {
f: function() {
return "function";
},
i: 2,
b: true,
a: [],
s: "hello"
});
assert(Object.isFunction(object.f));
assert.equal(object.f(), "function");
assert.equal(object.i, 2);
assert.equal(object.b, true);
assert(Object.equal(object.a, []));
return assert.equal(object.s, "hello");
});
});
describe('#Constructor', function() {
it('should set itself as property on parent', function() {
var a;
a = new Component({
parent: global
});
assert(Object.isString(a.id));
assert.equal(global[a.id], a);
return a.dispose();
});
it('should require parent', function() {
return assert.throws(function() {
var a;
return a = new Component;
});
});
return it('should generate a missing id', function() {
var a;
a = new Component({
parent: global
});
assert(Object.isString(a.id));
return a.dispose();
});
});
describe("#get", function() {
it('should throw exception if instance not found', function() {
var a;
a = new Component({
parent: global
});
assert.throws(function() {
return a.get("foo");
});
return a.dispose();
});
return it('should create instances with factory', function() {
var a, b, c;
a = new Component({
parent: global
});
b = new Component({
parent: a
});
a[Component] = Component;
c = b.get('glass.Component:{"x":2,"y":3}');
assert.equal(c.x, 2);
assert.equal(c.y, 3);
assert.equal(c.parent, a);
return a.dispose();
});
});
return describe('extend', function() {
it('should inherit base properties', function() {
var SubComponent;
SubComponent = Component.extend({
id: 'SubComponent'
});
return assert(SubComponent.properties.id != null);
});
it('should allow underriding constructors and functions', function() {
var SubComponent, sub;
SubComponent = Component.extend({
id: 'SubComponent',
properties: {
initialize: function() {
this.constructorCalled = true;
return this;
},
dispose: function() {
this.disposeCalled = true;
}
}
});
sub = new SubComponent({
parent: global
});
assert(sub.constructorCalled);
sub.dispose();
assert(sub.disposed);
return assert(sub.disposeCalled);
});
it('should allow recursive extension', function() {
var AComponent, BComponent;
AComponent = Component.extend({
id: 'AComponent',
properties: {
dispose: function() {}
}
});
return BComponent = AComponent.extend({
id: 'BComponent',
properties: {
foo: function() {}
}
});
});
return it('should not allow final functions to be underridden', function() {
var AComponent;
AComponent = Component.extend({
id: 'AComponent',
properties: {
dispose: function() {}
}
});
return assert.throws(function() {
var BComponent;
return BComponent = AComponent.extend({
id: 'BComponent',
properties: {
dispose: function() {}
}
});
});
});
});
});
}
}).call(this);
/*
//@ sourceMappingURL=Component.map
*/