MINI Sh3ll
/*
---
name: "Class"
description: "Contains the Class Function for easily creating, extending, and implementing reusable Classes."
license:
- "[GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)"
- "[MIT License](http://opensource.org/licenses/mit-license.php)"
requires:
- Core
- CoreExtended
- accessors
- Array
inspiration:
- "[MooTools](http://mootools.net)"
provides: Class
deprecated: "Use declare instead"
...
*/
(function(atom){
var typeOf = atom.core.typeOf,
extend = atom.core.extend,
accessors = atom.accessors.inherit,
prototype = 'prototype',
lambda = function (value) { return function () { return value; }},
prototyping = false;
var Class = function (params) {
if (prototyping) return this;
if (typeof params == 'function' && typeOf(params) == 'function') params = { initialize: params };
var Constructor = function(){
if (this instanceof Constructor) {
if (prototyping) return this;
return this.initialize ? this.initialize.apply(this, arguments) : this;
} else {
return Constructor.invoke.apply(Constructor, arguments);
}
};
extend(Constructor, Class);
Constructor.prototype = getInstance(Class);
Constructor
.implement(params, false)
.reserved(true, {
parent: parent,
self : Constructor
})
.reserved({
factory : function() {
function Factory(args) { return Constructor.apply(this, args); }
Factory.prototype = Constructor.prototype;
return function(args) { return new Factory(args || []); }
}()
});
Constructor.prototype.constructor = Constructor;
return Constructor;
};
var parent = function(){
if (!this.$caller) throw new Error('The method «parent» cannot be called.');
var name = this.$caller.$name,
parent = this.$caller.$owner.parent,
previous = parent && parent.prototype[name];
if (!previous) throw new Error('The method «' + name + '» has no parent.');
return previous.apply(this, arguments);
};
var wrap = function(self, key, method){
// if method is already wrapped
if (method.$origin) method = method.$origin;
var wrapper = function() {
if (!this || this == atom.global) throw new TypeError('Context lost');
if (method.$protected && !this.$caller) throw new Error('The method «' + key + '» is protected.');
var current = this.$caller;
this.$caller = wrapper;
var result = method.apply(this, arguments);
this.$caller = current;
return result;
};
wrapper.$owner = self;
wrapper.$origin = method;
wrapper.$name = key;
return wrapper;
};
var getInstance = function(Class){
if (atom.declare && Class instanceof atom.declare) {
return atom.declare.config.methods.proto(Class);
}
prototyping = true;
var proto = new Class;
prototyping = false;
return proto;
};
Class.extend = function (name, fn) {
if (typeof name == 'string') {
var object = {};
object[name] = fn;
} else {
object = name;
}
for (var i in object) if (!accessors(object, this, i)) {
this[i] = object[i];
}
return this;
};
Class.extend({
implement: function(name, fn, retain){
if (typeof name == 'string') {
var params = {};
params[name] = fn;
} else {
params = name;
retain = fn;
}
for (var key in params) {
if (!accessors(params, this.prototype, key)) {
var value = params[key];
if (Class.Mutators.hasOwnProperty(key)){
value = Class.Mutators[key].call(this, value);
if (value == null) continue;
}
if (typeof value == 'function' && typeOf(value) == 'function'){
if (value.$origin) value = value.$origin;
if (value.$hidden == 'next') {
value.$hidden = true
} else if (value.$hidden) {
continue;
}
this.prototype[key] = (retain) ? value : wrap(this, key, value);
} else {
this.prototype[key] = atom.clone(value);
}
}
}
return this;
},
mixin: function () {
Array.from(arguments).forEach(function (item) {
this.implement(getInstance(item));
}.bind(this));
return this;
},
reserved: function (toProto, props) { // use careful !!
if (arguments.length == 1) {
props = toProto;
toProto = false;
}
var target = toProto ? this.prototype : this;
for (var name in props) {
atom.accessors.define(target, name, { get: lambda(props[name]) });
}
return this;
},
isInstance: function (object) {
return object instanceof this;
},
invoke: function () {
return this.factory( arguments );
},
Mutators: {
Extends: function(parent){
if (parent == null) throw new TypeError('Cant extends from null');
this.extend(parent).reserved({ parent: parent });
this.prototype = getInstance(parent);
},
Implements: function(items){
this.mixin.apply(this, Array.from(items));
},
Static: function(properties) {
this.extend(properties);
}
},
abstractMethod: function () {
throw new Error('Abstract Method «' + this.$caller.$name + '» called');
},
protectedMethod: function (fn) {
return extend(fn, { $protected: true });
},
hiddenMethod: function (fn) {
return extend(fn, { $hidden: 'next' });
}
});
Class.abstractMethod.$abstract = true;
atom.Class = Class;
})(atom);
OHA YOOOO