/**
* @fileoverview Create Function like Class
* @author teramako teramako.at.gmail.com
* @version 0.1
* @license MIT
* @requires ECMASCript 5th and object.__proto__ property
*/
/**
* Create Function constructor
* @constructor
* @augments Object
* @param {String} [name] class name
* @param {Function} [base] base class
* @param {Object} proto
* @return {Function}
*/
function Class (name, base, proto) {
var args = Array.prototype.slice.call(arguments);
if (typeof args[0] == "string")
var name = args.shift();
var superClass = Class;
if (typeof args[0] == "function")
superClass = args.shift();
proto = args[0];
if (!name)
name = proto.__CLASS_NAME__ || superClass.__CLASS_NAME__ || "Anonymous";
proto.__proto__ = superClass.prototype;
Class.setSuper(proto, superClass.prototype);
Object.defineProperty(proto, "__CLASS_NAME__", { value: name });
var constructor = function () {
var o = Object.create(proto, { constructor: { value: constructor }});
var res = o.init.apply(o, arguments);
return res != undefined ? res : o;
};
constructor.prototype = proto;
var bound = constructor.bind(null);
bound.prototype = proto;
bound.__proto__ = Class;
return bound;
}
Object.defineProperties(Class, {
/**
* Show the first class name.
* @name Class.toString
* @function
* @return {String}
*/
toString: {
value: function () { return "[class " + this.prototype.__CLASS_NAME__ + "]"; },
},
/**
* set "super" property is references the same name property in super
* to functions and gettter/setter properties in proto
* @name Class.setSuper
* @function
* @constant
* @param {Object} proto
* @param {Object} super
*/
setSuper: {
value: function (proto, super) {
var keys = Object.getOwnPropertyNames(proto);
out:
for (var i = 0, len = keys.length; i < len; ++i) {
var key = keys[i];
if (!(key in super))
continue;
var desc = Object.getOwnPropertyDescriptor(proto, key);
if ("get" in desc) {
var p = super;
while (p !== null) {
if (Object.prototype.hasOwnProperty(p, key)) {
Object.defineProperty(proto[key], "super", desc);
continue out;
}
p = Object.getPrototypeOf(p);
}
} else if (typeof proto[key] == "function") {
Object.defineProperty(proto[key], "super", { value: super[key] });
}
}
},
},
/**
* marge properties of the second or later arguments
* to the first arguments
* @function
* @name Class.update
*/
update: {
value: function () {
var args = Array.prototype.slice.call(arguments);
var base = args.shift();
for (var i = 0; i < args.length; ++i) {
var o = args[i];
var keys = Object.getOwnPropertyNames(o);
for (var k = 0, len = keys.length; k < len; ++k) {
var key = keys[i];
Object.defineProperty(base, key, Object.getOwnPropertyDescriptor(o, key));
}
}
},
},
});
Class.prototype = Object.create({}, {
/**
* @memberof Class.prototype
* @type {String}
* @private
*/
__CLASS_NAME__: { value: "Class", },
/**
* do nothing
* @methodof Class.prototype
* @constructs
*/
init: {
value: function Class_init () {},
},
/**
* Show the first class name of the instance.
* @methodof Class.prototype
* @return {String}
*/
toString: {
value: function Class_toString () { return "[instance " + this.__CLASS_NAME__ + "]"; },
},
});
// vim: sw=2 ts=2 et: