useful-class
Version:
useful Classical inheritance scaffolding, including singletons and easy to use mixin functionality
1 lines • 7.65 kB
JavaScript
function Class(a){var b,c=null;return a&&"object"==typeof a&&(b=a.singleton,delete a.singleton,c=make_class(a)),b?make_singleton(c,b):c}function create(a){var b,c=get(a);return c?(b=arguments.length>1?Array.prototype.slice.call(arguments,1):[],create_instance.apply(c,b)):null}function define(a,b){if(a&&"object"==typeof a&&(b=a,a=b.__classname__||b.classname),a&&"string"==typeof a?(a=a.replace(re_invalid_chars,""),g=a.toLowerCase()):a=g=null,g in cache)throw new Error("class `"+a+"` already exists.","cannot overwrite existing class.");var c,d,e,f,g,h,i=b.module||root,j=!!b.singleton;return iter.remove(b,["__classname__","classname","module"]),e=Class(b),a&&(h=a.split("."),c=h.pop(),i&&i!==this&&h.shift(),f=value.bless(h,i),f[c]=e,d=j?e.constructor:e,cache[g]=cache[d.__guid__],Object.defineProperty(d,"__classname__",{configurable:!1,enumerable:!1,value:a,writable:!1})),e}function extend(a){return a&&"object"==typeof a||(a=Object.create(null)),a.extend=this,Class(a)}function get(a){return"function"==typeof a?a:(cache[String(a).toLowerCase()]||cache.__empty__).class}function is(a,b){return"string"==typeof b&&(b=get(b)),"function"==typeof b?a instanceof b:!1}function mixin_add(a,b){var c,d=this.__mixins__;if(a&&"object"==typeof a){b=a;for(a in b)Object.prototype.hasOwnProperty.call(b,a)&&mixin_add.call(this,a,b[a])}else if(!(a in d)&&("string"==typeof b&&(b=get(b)),b))switch(typeof b){case"function":b=b.prototype;case"object":d[a]=b,c=this.prototype;for(a in b)a in c||(c[a]=b[a])}return this}function create_instance(){return singleton(this)||this.apply(Object.create(this.prototype),arguments)}function override(a,b){if(a&&"object"==typeof a){b=a;for(a in b)Object.prototype.hasOwnProperty.call(b,a)&&override.call(this,a,b[a])}else override_instance_method.call(this.prototype,a,b);return this}function EmptyConstructor(){if(this.constructor.__super__!==Object){var a=this.parent(arguments);return a===UNDEF?this:a}}function mixin(a,b){if(a&&"string"==typeof a){var c,d,e=this.__method__,f=this.constructor.__mixins__;if(f&&"object"==typeof f){switch(arguments.length){case 2:break;case 1:b=[];break;default:b=Array.prototype.slice.call(arguments,1)}c=f[a],d=c&&"function"==typeof c[e]?c[e].apply(this,b):UNDEF}}return this.__chain__!==!0||d!==UNDEF?d:this}function override_instance_method(a,b){return"function"==typeof b&&(this[a]=make_method("original",a,b,this[a])),this}function add_statics(a,b){return b&&"object"==typeof b&©(a,b,!0),a.__super__&©(a,a.__super__,!0),a}function decorate(a){return a.create=a.new=create_instance.bind(a),a.extend=extend.bind(a),a.mixin=mixin_add.bind(a),a.override=override.bind(a),a}function extract_defaults(a){return configuration_props.reduce(function(b,c){return b[c]=a[c],delete a[c],b},Object.create(null))}function make_class(a){function b(){if(!this||this===root)return create_instance.apply(b,arguments);if(singleton(this.constructor))return this.constructor.__singleton__;this.__processing__!==!0&&(this.__processing__=!0,process_before(this,arguments));var a=c.apply(this,arguments);return delete this.__processing__,a===UNDEF?this:a}var c,d=make_config(a),e=extract_defaults(d),f=e.constructor,g=b.prototype=make_prototype(d,e);return("function"!=typeof f||f===Object||f===e.extend)&&(f=EmptyConstructor),b.toString=to_string.bind(null,f),b.valueOf=value_of.bind(null,f),c=make_method("parent","constructor",f,e.extend),g.constructor=b,Object.defineProperty(b,"__super__",{configurable:!1,enumerable:!1,value:e.extend,writable:!1}),register(decorate(b)),make_accessors(g,e.accessors),make_mixinable(b,e.mixins),make_processable(b,e.afterdefine,e.beforeinstance),add_statics(b,e.statics),process_after(b),b}function make_accessors(a,b){if(b&&"object"==typeof b){var c,d,e={configurable:!1,enumerable:!1};for(d in b)Object.prototype.hasOwnProperty.call(b,d)&&(c=b[d],c&&"object"==typeof c&&(delete b[d].writable,Object.defineProperty(a,d,copy(b[d],e,!0))))}}function make_config(a){var b=copy.merge(Object.create(null),a),c=b.extend;return"string"==typeof c&&(c=get(c)),"function"!=typeof c&&(c=Object),b.extend=c,b}function make_method(a,b,c,d){function e(){var e,f,g=this.__method__,h=this[a]||noop,i=!(g in internal_methods||b in internal_methods);return this[a]=d||noop,i&&(this.__method__=b),e=get_arguments(arguments,b,g),f=(c||this[a]).apply(this,e),i&&(this.__method__=g),this[a]=h,this.__chain__===!1||f!==UNDEF?f:this}var f;return"function"==typeof d&&d===d.valueOf()&&(f=d,d=function(){var a=f.apply(this,arguments);return this.__chain__===!1||a!==UNDEF?a:this}),e.displayName=b,e.valueOf=value_of.bind(null,c),e.toString=to_string.bind(null,c),e}function make_mixinable(a,b){return a.__mixins__=Object.create(null),b&&"object"==typeof b&&a.mixin(b),b=a.__super__?a.__super__.__mixins__:null,b&&"object"==typeof b&&a.mixin(b),a}function make_processable(a,b,c){var d,e,f=cache[a.__guid__],g=cache[a.__super__.__guid__];return d=g&&Array.isArray(g.after)?g.after.slice():[],"function"==typeof b&&d.push(b),d.length&&(f.after=d),e=g&&Array.isArray(g.before)?g.before.slice():[],"function"==typeof c&&e.push(c),e.length&&(f.before=e),a}function make__proto__(a){return a===Error||a.prototype instanceof Error?new a:Object.create(a.prototype)}function make_prototype(a,b){var c,d={__chain__:{configurable:!0,enumerable:!1,value:b.chain!==!1,writable:!0},__method__:{configurable:!0,enumerable:!1,value:null,writable:!0}},e=make__proto__(b.extend);for(c in a)if(Object.prototype.hasOwnProperty.call(a,c))switch(typeof a[c]){case"function":e[c]=make_method("parent",c,a[c],e[c]);break;default:e[c]=a[c]}for(c in internal_methods)c in e||(d[c]=internal_methods[c]);return Object.defineProperties(e,d),e}function make_singleton(a,b){var c=create_instance.apply(a,b===!0?[]:[].concat(b));return Object.defineProperty(a,"__singleton__",{configurable:!1,enumerable:!1,value:c,writable:!1}),c}function register(a){var b=string.guid();return cache[b]={"class":a},Object.defineProperty(a,"__guid__",{configurable:!1,enumerable:!1,value:b,writable:!1}),a}function get_arguments(a,b,c){if(a.length&&"[object Arguments]"===Object.prototype.toString.call(a[0])&&a.length<2&&arguments.length>1){if(b in internal_methods)return get_arguments(a[0]);if(c&&b===c)return a[0]}return a}function noop(){}function process_after(a){if(a.__processed__!==!0){var b=(cache[a.__guid__]||cache.__empty__).after,c=-1,d=Array.isArray(b)?b.length:0;if(d){for(;++c<d;)b[c](a);Object.defineProperty(a,"__processed__",{configurable:!1,enumerable:!1,value:!0,writable:!1})}}return a}function process_before(a,b){if(a.__processing__===!0){var c=a.constructor,d=(cache[c.__guid__]||cache.__empty__).before,e=-1,f=Array.isArray(d)?d.length:0;if(f)for(;++e<f;)d[e](c,a,b)}return a}function singleton(a){return a?a.__singleton__||null:null}function to_string(a){return a.toString()}function value_of(a){return a.valueOf()}var copy=require("useful-copy"),iter=require("useful-iter"),string=require("useful-string"),value=require("useful-value"),UNDEF,cache={__empty__:{after:null,before:null,"class":null,mixins:null,proto:null}},configuration_props="accessors afterdefine beforeinstance chain constructor extend mixins singleton statics".split(" "),internal_methods=copy(Object.create(null),{__override__:{enumerable:!1,value:override_instance_method},mixin:{enumerable:!1,value:mixin},original:{configurable:!0,enumerable:!1,value:noop,writable:!0},parent:{configurable:!0,enumerable:!1,value:noop,writable:!0}}),re_invalid_chars=/[^A-Za-z0-9_\.$<>\[\]\{\}]/g,root="undefined"==typeof global?window:global;Class.create=Class.new=create,Class.define=define,Class.get=get,Class.is=is,module.exports=Class;