function Class(params) { if (params instanceof Function) params = { initialize: params }; var newClass = function () { Object.reset(this); if (newClass._prototyping) return this; this._current = $empty; var value = (this.initialize) ? this.initialize.apply(this, arguments) : this; delete this._current; delete this.caller; return value; } .extend(this); newClass.implement(params); newClass.constructor = Class; newClass.prototype.constructor = newClass; return newClass; }; Function.prototype.protect = function () { this._protected = true; return this; }; Object.reset = function (object, key) {if (key == null) { for (var p in object) Object.reset(object, p); return object; }delete object[key]; switch ($type(object[key])) { case 'object': var F = function () { }; F.prototype = object[key]; var i = new F; object[key] = Object.reset(i); break; case 'array': object[key] = $unlink(object[key]); break; }return object;}; new Native({ name: 'Class', initialize: Class }).extend({ instantiate: function (F) { F._prototyping = true; var proto = new F; delete F._prototyping; return proto; }, wrap: function (self, key, method) { if (method._origin) method = method._origin; return function () { if (method._protected && this._current == null) throw new Error('The method "' + key + '" cannot be called.'); var caller = this.caller, current = this._current; this.caller = current; this._current = arguments.callee; var result = method.apply(this, arguments); this._current = current; this.caller = caller; return result; } .extend({ _owner: self, _origin: method, _name: key }); } }); Class.implement({ implement: function (key, value) {if ($type(key) == 'object') { for (var p in key) this.implement(p, key[p]); return this; }var mutator = Class.Mutators[key]; if (mutator) { value = mutator.call(this, value); if (value == null) return this; }var proto = this.prototype; switch ($type(value)) { case 'function': if (value._hidden) return this; proto[key] = Class.wrap(this, key, value); break; case 'object': var previous = proto[key]; if ($type(previous) == 'object') $mixin(previous, value); else proto[key] = $unlink(value); break; case 'array': proto[key] = $unlink(value); break; default: proto[key] = value; }return this;}}); Class.Mutators = { Extends: function (parent) { this.parent = parent; this.prototype = Class.instantiate(parent); this.implement('parent', function () { var name = this.caller._name, previous = this.caller._owner.parent.prototype[name]; if (!previous) throw new Error('The method "' + name + '" has no parent.'); return previous.apply(this, arguments); } .protect()); }, Implements: function (items) { $splat(items).each(function (item) { if (item instanceof Function) item = Class.instantiate(item); this.implement(item); }, this); } };
