class-wrapper
Advanced tools
Comparing version 0.9.3 to 1.0.0
@@ -7,9 +7,9 @@ (function (root, factory) { | ||
} else { | ||
root.classWrappers = factory(); | ||
root["class-wrapper"] = factory(); | ||
} | ||
})(this, function() { | ||
// Set of wrappers for easier creation of different kinds of classes | ||
// v0.9.3 | ||
// Copyright (c) 2016 Valerii Zinchenko | ||
// License: http://valerii-zinchenko.github.io/class-wrapper/LICENSE.txt | ||
// Set of wrappers for easier definition of different kinds of classes | ||
// v1.0.0 | ||
// Copyright (c) 2016 Valerii Zinchenko | ||
// License: MIT http://valerii-zinchenko.github.io/class-wrapper/LICENSE.txt | ||
// All source files are available at: http://github.com/valerii-zinchenko/class-wrapper | ||
@@ -21,3 +21,3 @@ /* | ||
All source files are available at: http://github.com/valerii-zinchenko/cpp-class | ||
All source files are available at: http://github.com/valerii-zinchenko/class-wrapper | ||
*/ | ||
@@ -29,4 +29,2 @@ | ||
* @author Valerii Zinchenko | ||
* | ||
* @version 1.1.0 | ||
*/ | ||
@@ -106,44 +104,2 @@ | ||
return target; | ||
}, | ||
/** | ||
* Encapsulate methods and properties from 'what' object or Class into 'to' Class. | ||
* | ||
* @param {Object | Class} what - Object or Class that will be encapsulated. | ||
* @param {Class} to - Class where the methods and properties will be encapsulated. | ||
*/ | ||
encapsulate: function (what, to) { | ||
if (Object.prototype.toString.call(what) == '[object Function]') { | ||
what = what.prototype; | ||
} | ||
for (var key in what) { | ||
// Note. 'constructor' is excluded to not override the real class constructor. | ||
if (what.hasOwnProperty(key) && key != 'constructor') { | ||
var value = what[key]; | ||
switch (Object.prototype.toString.call(value)) { | ||
// Store functions into "prototype" | ||
case '[object Function]': | ||
to.prototype[key] = value; | ||
break; | ||
// Clone objects and store the copies into "_defaults" | ||
case '[object Object]': | ||
if (key === '_defaults') { | ||
// NOTE. This is only for cases when some instance of ClassBuilder will be encapsulated. | ||
utils.deepCopy(to.prototype._defaults, value); | ||
} else { | ||
if (!to.prototype._defaults[key]) { | ||
to.prototype._defaults[key] = {}; | ||
} | ||
utils.deepCopy(to.prototype._defaults[key], value); | ||
} | ||
break; | ||
// Store evererything else into "_defaults" container | ||
default: | ||
to.prototype._defaults[key] = value; | ||
} | ||
} | ||
} | ||
} | ||
@@ -157,3 +113,3 @@ }; | ||
All source files are available at: http://github.com/valerii-zinchenko/cpp-class | ||
All source files are available at: http://github.com/valerii-zinchenko/class-wrapper | ||
*/ | ||
@@ -168,4 +124,2 @@ | ||
* @author Valerii Zinchenko | ||
* | ||
* @version 1.0.2 | ||
*/ | ||
@@ -185,74 +139,52 @@ | ||
* - inherited methods are stored in class prototype object | ||
* - store default class properties in '_default' object where the objects will be copied, not shared | ||
* - store default class properties in '__default' object where the objects will be copied, not shared | ||
* | ||
* @param {Function} Constructor - Main class constructor subroutine. | ||
* @param {Function} [Parent = Object] - Parent class. Built-in 'Object' will be used if this argument will be omitted | ||
* @param {Function | Object} [...rest] - Classes/function's/object's properties and methods of which will be encapsulated | ||
* @param {Object} props - The last input argument. Defines the properties and methods for a new class | ||
* @param {Object | Array} [props.Encapsulate] - Define which object or an array of objects should be encapsulated into the new class | ||
* @returns {Function} Class constructor | ||
* @param {Function} InstanceBuilder - Function that defines how instances will be created, how constructor(s) will be executed | ||
* @param {Function} [Parent = Object] - Parent class | ||
* @param {Function | null} Constructor - Cconstructor function | ||
* @param {Object} props - Object of properties and methods for a new class. Property names that are used internally and will be ignored by encapsulation: | ||
* - __constructor | ||
* - __parent | ||
* | ||
* @throws {Error} Incorrect input arguments. It should be: ClassBuilder(Function, [Function], [Function | Object]*, Object) | ||
* If some of the object has "__defaults" object, then all of it's properties will be treated as an object of default properties that a new class should have. | ||
* @param {Object | Function | Class | Array} [props.Encapsulate] - Define which object/function/class or an array of objects/functions/classes should be encapsulated into the new class | ||
* @returns {Function} Class | ||
* | ||
* @throws {Error} Incorrect input arguments. It should be: ClassBuilder(Function, [Function], Function | null, Object) | ||
* @throws {Error} Some of the items for encapsulation is incorrect. An item can be: Object, Function, Class | ||
* | ||
* @see {@link Class} | ||
* @see {@link SingletonClass} | ||
*/ | ||
function ClassBuilder(Constructor, Parent, props) { | ||
function ClassBuilder(InstanceBuilder, Parent, Constructor, props) { | ||
// Last input argument is an object of properties for a new class | ||
props = arguments[arguments.length - 1]; | ||
// Second last input argument is a constructor function | ||
Constructor = arguments[arguments.length - 2]; | ||
// Set default Parent class if it is not provided | ||
if (Parent == props) { | ||
if (arguments.length === 3) { | ||
Parent = Object; | ||
} | ||
// An array of an classes, functions and objects properties and methods of which will be incapsulated into a new class | ||
var encapsulations = Array.prototype.slice.call(arguments, 2, -1); | ||
// Validate input arguments | ||
// -------------------------------------------------- | ||
if (arguments.length < 2 | ||
|| typeof Constructor !== 'function' | ||
if (arguments.length < 3 | ||
|| typeof InstanceBuilder !== 'function' | ||
|| Object.prototype.toString.call(Parent) !== '[object Function]' | ||
|| Object.prototype.toString.call(props) !== '[object Object]' | ||
|| encapsulations.some(function(item) { | ||
var type = Object.prototype.toString.call(item); | ||
return type !== '[object Function]' && type !== '[object Object]'; | ||
})) | ||
|| (Constructor !== null && typeof Constructor !== 'function') | ||
|| Object.prototype.toString.call(props) !== '[object Object]') | ||
{ | ||
throw new Error('Incorrect input arguments. It should be: ClassBuilder(Function, [Function], [Function | Object]*, Object)'); | ||
throw new Error('Incorrect input arguments. It should be: ClassBuilder(Function, [Function], Function | null, Object)'); | ||
} | ||
// todo: Validate proprties for a usage of reserverd locally variable names to avoid the interference | ||
// -------------------------------------------------- | ||
// Clone class constructor function | ||
// Prepare an array of what is going to be encapsulated into a new class | ||
// -------------------------------------------------- | ||
var Class; | ||
eval('Class = ' + Constructor.toString()); | ||
// Create reference to a parent's prototype object for internal usage | ||
Class.parent = Parent.prototype; | ||
// -------------------------------------------------- | ||
// Inheritance chain | ||
// -------------------------------------------------- | ||
// Create proxy prototype, in order to not change the parent's prototype | ||
var CoreClass = function(){}; | ||
CoreClass.prototype = Parent.prototype; | ||
Class.prototype = new CoreClass(); | ||
// Revert back the reseted reference to the constructor function | ||
Class.prototype.constructor = Class; | ||
// Create storage for a default properties | ||
Class.prototype._defaults = {}; | ||
// -------------------------------------------------- | ||
// Encapsulate properties and methods of provided objects | ||
// -------------------------------------------------- | ||
var encapsulations = []; | ||
// Collect objects properties and methods of which will be encapsulated into a new class | ||
if (props.Encapsulate) { | ||
if (Object.prototype.toString.call(props.Encapsulate) == '[object Array]') { | ||
if (Object.prototype.toString.call(props.Encapsulate) === '[object Array]') { | ||
encapsulations = encapsulations.concat(props.Encapsulate); | ||
@@ -266,13 +198,51 @@ } else { | ||
} | ||
// Put parent's defaults into an encapsulation chain | ||
if (Parent.prototype._defaults) { | ||
encapsulations.unshift(Parent.prototype._defaults); | ||
// Put parent's defaults into an encapsulation stack | ||
if (Parent.prototype.__defaults) { | ||
encapsulations.unshift(Parent.prototype.__defaults); | ||
} | ||
// Put properties and methods of a new clas into the encapsilation chain | ||
// Put properties and methods for a new class into the encapsulation stack | ||
encapsulations.push(props); | ||
// Setup input properties to the new class | ||
// Encapsulate methods and properties from other classes/objects | ||
// Validate what is going to be encapsulated | ||
if (encapsulations.some(function(item) { | ||
var type = Object.prototype.toString.call(item); | ||
return type !== '[object Function]' && type !== '[object Object]'; | ||
})) | ||
{ | ||
throw new Error('Some of the items for encapsulation is incorrect. An item can be: Object, Function, Class'); | ||
} | ||
// -------------------------------------------------- | ||
// Clone class constructor function to prevent a sharing of instance builder function | ||
// -------------------------------------------------- | ||
var Class; | ||
eval('Class = ' + InstanceBuilder.toString()); | ||
// -------------------------------------------------- | ||
// Inheritance chain | ||
// -------------------------------------------------- | ||
// Derive a new class from a Parent class | ||
Class.prototype = Object.create(Parent.prototype); | ||
// Revert back the reference to the instance builder function | ||
Class.prototype.constructor = Class; | ||
// Store the reference to the constructor function | ||
if (Constructor) { | ||
Class.prototype.__constructor = Constructor; | ||
} | ||
// Create a storage for default properties | ||
Class.prototype.__defaults = {}; | ||
// Store a reference to a parent's prototype object for internal usage | ||
Class.__parent = Parent.prototype; | ||
// -------------------------------------------------- | ||
// Encapsulate properties and methods | ||
// -------------------------------------------------- | ||
for (var n = 0, N = encapsulations.length; n < N; n++) { | ||
utils.encapsulate(encapsulations[n], Class); | ||
ClassBuilder.encapsulate(encapsulations[n], Class); | ||
} | ||
@@ -285,3 +255,47 @@ // -------------------------------------------------- | ||
/** | ||
* Encapsulate methods and properties from 'what' into 'to'. | ||
* If 'what' is a function then its prototype will be encapsulated. | ||
* | ||
* @param {Class | Object | Function} what - Object or Class that will be encapsulated. | ||
* @param {Class} to - Class where the methods and properties will be encapsulated. | ||
*/ | ||
ClassBuilder.encapsulate = function(what, to) { | ||
if (Object.prototype.toString.call(what) === '[object Function]') { | ||
what = what.prototype; | ||
} | ||
for (var key in what) { | ||
// Note. 'constructor' is excluded to not override the real class constructor. | ||
if (what.hasOwnProperty(key) | ||
&& (key !== 'constructor' && key !== '__constructor' && key !== '__parent')) | ||
{ | ||
var value = what[key]; | ||
switch (Object.prototype.toString.call(value)) { | ||
// Store functions into "prototype" | ||
case '[object Function]': | ||
to.prototype[key] = value; | ||
break; | ||
// Clone objects and store the copies into "__defaults" | ||
case '[object Object]': | ||
if (key === '__defaults') { | ||
// NOTE. This is only for cases when some instance of ClassBuilder will be encapsulated. | ||
utils.deepCopy(to.prototype.__defaults, value); | ||
} else { | ||
if (!to.prototype.__defaults[key]) { | ||
to.prototype.__defaults[key] = {}; | ||
} | ||
utils.deepCopy(to.prototype.__defaults[key], value); | ||
} | ||
break; | ||
// Store evererything else into "__defaults" container | ||
default: | ||
to.prototype.__defaults[key] = value; | ||
} | ||
} | ||
} | ||
}; | ||
/* | ||
@@ -292,7 +306,7 @@ Copyright (c) 2016 Valerii Zinchenko | ||
All source files are available at: http://github.com/valerii-zinchenko/cpp-class | ||
All source files are available at: http://github.com/valerii-zinchenko/class-wrapper | ||
*/ | ||
/** | ||
* @file Implementation of a C++-like [class]{@link Class} | ||
* @file Implementation of a simple [class]{@link Class} wrapper | ||
* | ||
@@ -303,4 +317,2 @@ * @see {@link ClassBuilder} | ||
* @author Valerii Zinchenko | ||
* | ||
* @version 1.1.2 | ||
*/ | ||
@@ -311,12 +323,13 @@ | ||
/** | ||
* Core class constructor wrapper. | ||
* This constructor function simulates the behavior of a constructor from C++ () - all parent constructors are executing first, starting from the root parent constructor and finishing with the constructor for the new class. | ||
* Before the constructor's chain will be executed the new instance will be extended by "_default" properties. | ||
* Execute a parent's constructor before the current constructor. | ||
* The behavior of this builder is similar to C++ - all parent constructors are executing first, starting from the root parent constructor and finishing with the constructor of a new class. | ||
* Before the constructor's chain will be executed the new instance will be extended by "__defaults" properties. | ||
*/ | ||
function CoreConstructor() { | ||
utils.deepExtend(this, this.constructor.prototype._defaults); | ||
function ParentConstructorFirst() { | ||
// Extend this.__defaults from a __defaults of a constructor's prototype, because this.__defaults is searching through the whole prototype chain | ||
utils.deepExtend(this, this.constructor.prototype.__defaults); | ||
// Recursively call all parent's constructors, started from the top parent class | ||
// Recursively call all parent's constructors, started from the top most parent node | ||
(function constructParentStack(context, child, args) { | ||
var parent = child.constructor.parent; | ||
var parent = child.constructor.__parent; | ||
// dive to the root parent | ||
@@ -327,12 +340,12 @@ if (parent) { | ||
// execute parent's specific constructor if it explicitly defined | ||
if (child.hasOwnProperty('initialize')) { | ||
child.initialize.apply(context, args); | ||
// execute parent's constructor if it was defined | ||
if (child.hasOwnProperty('__constructor')) { | ||
child.__constructor.apply(context, args); | ||
} | ||
})(this, this.constructor.parent, arguments); | ||
})(this, this.constructor.__parent, arguments); | ||
// Call constructur function of a new class if it was explicitly defined | ||
// If it was not defined then the parent's constructor were already execited | ||
if (this.constructor.prototype.hasOwnProperty('initialize')) { | ||
this.constructor.prototype.initialize.apply(this, arguments); | ||
// Call constructor of a new class if ir is defined | ||
// It is checking the __constructor from a constructor's prototype, because this.__constructor is searching throug the whole prototype chain | ||
if (this.constructor.prototype.hasOwnProperty('__constructor')) { | ||
this.constructor.prototype.__constructor.apply(this, arguments); | ||
} | ||
@@ -343,27 +356,19 @@ } | ||
* Class | ||
* This binds {@link Coreconstructor} function into ClassBuilder function as the first argument, so it will accept the other arguments. | ||
* This sets a simple wrapper under {@link ParentConstructorFirst} function as default instance builder function of {@link ClassBuilder}. | ||
* Simple wrapper function, not {@link ParentConstructorFirst} function directly, is used to not clone {@link ParentConstructorFirst} function. This allows the debugging of instance builder function. | ||
* | ||
* @param {Function | null} Constructor - Class constructor. The second last argument | ||
* @param {Object} props - Defines the properties and methods for a new class. The last input argument | ||
* @param {Object | Function | Class | Array} [props.Encapsulate] - Define which object/function/class or an array of classes/functions/objects should be encapsulated into the new class | ||
* @returns {Function} Class | ||
* | ||
* @throws {Error} Incorrect input arguments. It should be: ClassBuilder(Function, [Function], Function | null, Object) | ||
* @throws {Error} Some of the items for encapsulation is incorrect. An item can be: Object, Function, Class | ||
* | ||
* @see {@link ClassBuilder} | ||
* | ||
* @param {Function} [Parent = Object] - Parent class. Built-in 'Object' will be used if this argument will be omitted | ||
* @param {Function | Object} [...rest] - Classes/function's/object's properties and methods of which will be encapsulated | ||
* @param {Object} props - The last input argument. Defines the properties and methods for a new class | ||
* @param {Object | Array} [props.Encapsulate] - Define which object or an array of objects should be encapsulated into the new class | ||
* @returns {Function} Class constructor | ||
*/ | ||
var Class = ClassBuilder.bind(null, CoreConstructor); | ||
/* | ||
new Class({ | ||
private: { | ||
}, | ||
protected: { | ||
}, | ||
public: { | ||
} | ||
var Class = ClassBuilder.bind(null, function() { | ||
// simple wrapper is used here in order to not clone the ParentConstructorFirst function | ||
ParentConstructorFirst.apply(this, arguments); | ||
}); | ||
*/ | ||
@@ -375,7 +380,7 @@ /* | ||
All source files are available at: http://github.com/valerii-zinchenko/cpp-class | ||
All source files are available at: http://github.com/valerii-zinchenko/class-wrapper | ||
*/ | ||
/** | ||
* @file Implementation of [singleton class]{@link SingletonClass} | ||
* @file Implementation of [singleton class]{@link SingletonClass} wrapper | ||
* | ||
@@ -386,4 +391,2 @@ * @see {@link ClassBuilder} | ||
* @author Valerii Zinchenko | ||
* | ||
* @version 1.1.1 | ||
*/ | ||
@@ -394,13 +397,15 @@ | ||
/** | ||
* Singleton Class | ||
* This additionally wraps the {@link CoreConstructor} to store and return already created instance. | ||
* This binds addtional wrapper into ClassBuilder function as the first argument, so it will accept the other arguments. | ||
* Singleton class | ||
* This sets a default instance builder function of {@link ClassBuilder} to achieve the behaviour of a singleton class. | ||
* A creation of a first instance is controlled by {@link ParentConstructorFirst} function. | ||
* | ||
* @param {Function | null} Constructor - Class constructor. The second last argument | ||
* @param {Object} props - Defines the properties and methods for a new class. The last input argument | ||
* @param {Object | Function | Class | Array} [props.Encapsulate] - Define which object/function/class or an array of classes/functions/objects should be encapsulated into the new class | ||
* @returns {Function} Class | ||
* | ||
* @throws {Error} Incorrect input arguments. It should be: ClassBuilder(Function, [Function], Function | null, Object) | ||
* @throws {Error} Some of the items for encapsulation is incorrect. An item can be: Object, Function, Class | ||
* | ||
* @see {@link ClassBuilder} | ||
* | ||
* @param {Function} [Parent = Object] - Parent class. Built-in 'Object' will be used if this argument will be omitted | ||
* @param {Function | Object} [...rest] - Classes/function's/object's properties and methods of which will be encapsulated | ||
* @param {Object} props - The last input argument. Defines the properties and methods for a new class | ||
* @param {Object | Array} [props.Encapsulate] - Define which object or an array of objects should be encapsulated into the new class | ||
* @returns {Function} Class constructor | ||
*/ | ||
@@ -416,3 +421,3 @@ var SingletonClass = ClassBuilder.bind(null, function() { | ||
CoreConstructor.apply(this, arguments); | ||
ParentConstructorFirst.apply(this, arguments); | ||
}); | ||
@@ -419,0 +424,0 @@ |
@@ -1,6 +0,6 @@ | ||
// Set of wrappers for easier creation of different kinds of classes | ||
// v0.9.3 | ||
// Copyright (c) 2016 Valerii Zinchenko | ||
// License: http://valerii-zinchenko.github.io/class-wrapper/LICENSE.txt | ||
// Set of wrappers for easier definition of different kinds of classes | ||
// v1.0.0 | ||
// Copyright (c) 2016 Valerii Zinchenko | ||
// License: MIT http://valerii-zinchenko.github.io/class-wrapper/LICENSE.txt | ||
// All source files are available at: http://github.com/valerii-zinchenko/class-wrapper | ||
!function(a,b){"function"==typeof define&&define.amd?define([],b):"object"==typeof module&&module.exports?module.exports=b():a.classWrappers=b()}(this,function(){"use strict";function ClassBuilder(Constructor,Parent,props){props=arguments[arguments.length-1],Parent==props&&(Parent=Object);var encapsulations=Array.prototype.slice.call(arguments,2,-1);if(arguments.length<2||"function"!=typeof Constructor||"[object Function]"!==Object.prototype.toString.call(Parent)||"[object Object]"!==Object.prototype.toString.call(props)||encapsulations.some(function(a){var b=Object.prototype.toString.call(a);return"[object Function]"!==b&&"[object Object]"!==b}))throw new Error("Incorrect input arguments. It should be: ClassBuilder(Function, [Function], [Function | Object]*, Object)");var Class;eval("Class = "+Constructor.toString()),Class.parent=Parent.prototype;var CoreClass=function(){};CoreClass.prototype=Parent.prototype,Class.prototype=new CoreClass,Class.prototype.constructor=Class,Class.prototype._defaults={},props.Encapsulate&&("[object Array]"==Object.prototype.toString.call(props.Encapsulate)?encapsulations=encapsulations.concat(props.Encapsulate):encapsulations.push(props.Encapsulate),delete props.Encapsulate),Parent.prototype._defaults&&encapsulations.unshift(Parent.prototype._defaults),encapsulations.push(props);for(var n=0,N=encapsulations.length;n<N;n++)utils.encapsulate(encapsulations[n],Class);return Class}function CoreConstructor(){utils.deepExtend(this,this.constructor.prototype._defaults),function a(b,c,d){var e=c.constructor.parent;e&&a(b,e,d),c.hasOwnProperty("initialize")&&c.initialize.apply(b,d)}(this,this.constructor.parent,arguments),this.constructor.prototype.hasOwnProperty("initialize")&&this.constructor.prototype.initialize.apply(this,arguments)}var utils={deepCopy:function(a,b){var c,d;for(c in b)switch(d=b[c],Object.prototype.toString.call(d)){case"[object Object]":a[c]||(a[c]={}),utils.deepCopy(a[c],d);break;default:a[c]=d}return a},deepExtend:function(a,b){var c,d;for(c in b)if(d=b[c],a.hasOwnProperty(c))"object"==typeof a[c]&&utils.deepExtend(a[c],d);else switch(Object.prototype.toString.call(d)){case"[object Object]":a[c]={},utils.deepExtend(a[c],d);break;case"[object Array]":a[c]=d.map(function(a){return a});break;default:a[c]=d}return a},encapsulate:function(a,b){"[object Function]"==Object.prototype.toString.call(a)&&(a=a.prototype);for(var c in a)if(a.hasOwnProperty(c)&&"constructor"!=c){var d=a[c];switch(Object.prototype.toString.call(d)){case"[object Function]":b.prototype[c]=d;break;case"[object Object]":"_defaults"===c?utils.deepCopy(b.prototype._defaults,d):(b.prototype._defaults[c]||(b.prototype._defaults[c]={}),utils.deepCopy(b.prototype._defaults[c],d));break;default:b.prototype._defaults[c]=d}}}},Class=ClassBuilder.bind(null,CoreConstructor),SingletonClass=ClassBuilder.bind(null,function(){return this.constructor.instance?this.constructor.instance:(this.constructor.instance=this,void CoreConstructor.apply(this,arguments))});return{utils:utils,ClassBuilder:ClassBuilder,Class:Class,SingletonClass:SingletonClass}}); | ||
!function(a,b){"function"==typeof define&&define.amd?define([],b):"object"==typeof module&&module.exports?module.exports=b():a["class-wrapper"]=b()}(this,function(){"use strict";function ClassBuilder(InstanceBuilder,Parent,Constructor,props){if(props=arguments[arguments.length-1],Constructor=arguments[arguments.length-2],3===arguments.length&&(Parent=Object),arguments.length<3||"function"!=typeof InstanceBuilder||"[object Function]"!==Object.prototype.toString.call(Parent)||null!==Constructor&&"function"!=typeof Constructor||"[object Object]"!==Object.prototype.toString.call(props))throw new Error("Incorrect input arguments. It should be: ClassBuilder(Function, [Function], Function | null, Object)");var encapsulations=[];if(props.Encapsulate&&("[object Array]"===Object.prototype.toString.call(props.Encapsulate)?encapsulations=encapsulations.concat(props.Encapsulate):encapsulations.push(props.Encapsulate),delete props.Encapsulate),Parent.prototype.__defaults&&encapsulations.unshift(Parent.prototype.__defaults),encapsulations.push(props),encapsulations.some(function(a){var b=Object.prototype.toString.call(a);return"[object Function]"!==b&&"[object Object]"!==b}))throw new Error("Some of the items for encapsulation is incorrect. An item can be: Object, Function, Class");var Class;eval("Class = "+InstanceBuilder.toString()),Class.prototype=Object.create(Parent.prototype),Class.prototype.constructor=Class,Constructor&&(Class.prototype.__constructor=Constructor),Class.prototype.__defaults={},Class.__parent=Parent.prototype;for(var n=0,N=encapsulations.length;n<N;n++)ClassBuilder.encapsulate(encapsulations[n],Class);return Class}function ParentConstructorFirst(){utils.deepExtend(this,this.constructor.prototype.__defaults),function a(b,c,d){var e=c.constructor.__parent;e&&a(b,e,d),c.hasOwnProperty("__constructor")&&c.__constructor.apply(b,d)}(this,this.constructor.__parent,arguments),this.constructor.prototype.hasOwnProperty("__constructor")&&this.constructor.prototype.__constructor.apply(this,arguments)}var utils={deepCopy:function(a,b){var c,d;for(c in b)switch(d=b[c],Object.prototype.toString.call(d)){case"[object Object]":a[c]||(a[c]={}),utils.deepCopy(a[c],d);break;default:a[c]=d}return a},deepExtend:function(a,b){var c,d;for(c in b)if(d=b[c],a.hasOwnProperty(c))"object"==typeof a[c]&&utils.deepExtend(a[c],d);else switch(Object.prototype.toString.call(d)){case"[object Object]":a[c]={},utils.deepExtend(a[c],d);break;case"[object Array]":a[c]=d.map(function(a){return a});break;default:a[c]=d}return a}};ClassBuilder.encapsulate=function(a,b){"[object Function]"===Object.prototype.toString.call(a)&&(a=a.prototype);for(var c in a)if(a.hasOwnProperty(c)&&"constructor"!==c&&"__constructor"!==c&&"__parent"!==c){var d=a[c];switch(Object.prototype.toString.call(d)){case"[object Function]":b.prototype[c]=d;break;case"[object Object]":"__defaults"===c?utils.deepCopy(b.prototype.__defaults,d):(b.prototype.__defaults[c]||(b.prototype.__defaults[c]={}),utils.deepCopy(b.prototype.__defaults[c],d));break;default:b.prototype.__defaults[c]=d}}};var Class=ClassBuilder.bind(null,function(){ParentConstructorFirst.apply(this,arguments)}),SingletonClass=ClassBuilder.bind(null,function(){return this.constructor.instance?this.constructor.instance:(this.constructor.instance=this,void ParentConstructorFirst.apply(this,arguments))});return{utils:utils,ClassBuilder:ClassBuilder,Class:Class,SingletonClass:SingletonClass}}); |
@@ -6,4 +6,4 @@ module.exports = function(grunt) { | ||
'// v<%= pkg.version %>\n' + | ||
'// Copyright (c) 2016 Valerii Zinchenko\n' + | ||
'// License: http://valerii-zinchenko.github.io/<%= pkg.name %>/LICENSE.txt\n' + | ||
'// Copyright (c) 2016 <%= pkg.author %>\n' + | ||
'// License: <%= pkg.license %> http://valerii-zinchenko.github.io/<%= pkg.name %>/LICENSE.txt\n' + | ||
'// All source files are available at: http://github.com/<%= pkg.repository %>\n'; | ||
@@ -26,3 +26,3 @@ | ||
wrap: { | ||
amd: { | ||
pkg: { | ||
src: ['dest/<%= pkg.name %>.js'], | ||
@@ -38,3 +38,3 @@ dest: 'dest/<%= pkg.name %>.js', | ||
' } else {\n' + | ||
' root.classWrappers = factory();\n' + | ||
' root["<%= pkg.name %>"] = factory();\n' + | ||
' }\n' + | ||
@@ -70,2 +70,3 @@ '})(this, function() {', | ||
data: { | ||
isPROD: false, | ||
jsFolder: '../lib' | ||
@@ -81,2 +82,3 @@ } | ||
data: { | ||
isPROD: false, | ||
jsFolder: '../js-cov' | ||
@@ -88,2 +90,12 @@ } | ||
} | ||
}, | ||
'prod-test': { | ||
options: { | ||
data: { | ||
isPROD: true | ||
} | ||
}, | ||
files: { | ||
'test/index.html': ['test/index.tpl.html'] | ||
} | ||
} | ||
@@ -127,8 +139,15 @@ }, | ||
jsdoc: { | ||
options: { | ||
configure: 'jsdoc.conf.json', | ||
}, | ||
doc: { | ||
src: ['./lib/*.js'], | ||
options: { | ||
destination: 'doc', | ||
readme: 'README.md' | ||
package: "package.json", | ||
} | ||
}, | ||
nightly: { | ||
src: ['./lib/*.js'], | ||
} | ||
@@ -163,5 +182,5 @@ }, | ||
[ | ||
['build', ['clean', 'concat', 'wrap', 'uglify', 'template:test']], | ||
['build', ['clean:build', 'concat', 'wrap', 'uglify', 'template:test']], | ||
['test', ['template:test', 'mocha:test']], | ||
['coverage', ['prepareForCoverage', 'template:coverage', 'mocha:coverage', 'clean:coverage']], | ||
['coverage', ['prepareForCoverage', 'template:coverage', 'mocha:coverage', 'clean:coverage', 'template:test']], | ||
['doc', ['jsdoc']] | ||
@@ -168,0 +187,0 @@ ].forEach(function(registry){ |
@@ -6,7 +6,7 @@ /* | ||
All source files are available at: http://github.com/valerii-zinchenko/cpp-class | ||
All source files are available at: http://github.com/valerii-zinchenko/class-wrapper | ||
*/ | ||
/** | ||
* @file Implementation of a C++-like [class]{@link Class} | ||
* @file Implementation of a simple [class]{@link Class} wrapper | ||
* | ||
@@ -17,4 +17,2 @@ * @see {@link ClassBuilder} | ||
* @author Valerii Zinchenko | ||
* | ||
* @version 1.1.2 | ||
*/ | ||
@@ -25,12 +23,13 @@ | ||
/** | ||
* Core class constructor wrapper. | ||
* This constructor function simulates the behavior of a constructor from C++ () - all parent constructors are executing first, starting from the root parent constructor and finishing with the constructor for the new class. | ||
* Before the constructor's chain will be executed the new instance will be extended by "_default" properties. | ||
* Execute a parent's constructor before the current constructor. | ||
* The behavior of this builder is similar to C++ - all parent constructors are executing first, starting from the root parent constructor and finishing with the constructor of a new class. | ||
* Before the constructor's chain will be executed the new instance will be extended by "__defaults" properties. | ||
*/ | ||
function CoreConstructor() { | ||
utils.deepExtend(this, this.constructor.prototype._defaults); | ||
function ParentConstructorFirst() { | ||
// Extend this.__defaults from a __defaults of a constructor's prototype, because this.__defaults is searching through the whole prototype chain | ||
utils.deepExtend(this, this.constructor.prototype.__defaults); | ||
// Recursively call all parent's constructors, started from the top parent class | ||
// Recursively call all parent's constructors, started from the top most parent node | ||
(function constructParentStack(context, child, args) { | ||
var parent = child.constructor.parent; | ||
var parent = child.constructor.__parent; | ||
// dive to the root parent | ||
@@ -41,12 +40,12 @@ if (parent) { | ||
// execute parent's specific constructor if it explicitly defined | ||
if (child.hasOwnProperty('initialize')) { | ||
child.initialize.apply(context, args); | ||
// execute parent's constructor if it was defined | ||
if (child.hasOwnProperty('__constructor')) { | ||
child.__constructor.apply(context, args); | ||
} | ||
})(this, this.constructor.parent, arguments); | ||
})(this, this.constructor.__parent, arguments); | ||
// Call constructur function of a new class if it was explicitly defined | ||
// If it was not defined then the parent's constructor were already execited | ||
if (this.constructor.prototype.hasOwnProperty('initialize')) { | ||
this.constructor.prototype.initialize.apply(this, arguments); | ||
// Call constructor of a new class if ir is defined | ||
// It is checking the __constructor from a constructor's prototype, because this.__constructor is searching throug the whole prototype chain | ||
if (this.constructor.prototype.hasOwnProperty('__constructor')) { | ||
this.constructor.prototype.__constructor.apply(this, arguments); | ||
} | ||
@@ -57,26 +56,18 @@ } | ||
* Class | ||
* This binds {@link Coreconstructor} function into ClassBuilder function as the first argument, so it will accept the other arguments. | ||
* This sets a simple wrapper under {@link ParentConstructorFirst} function as default instance builder function of {@link ClassBuilder}. | ||
* Simple wrapper function, not {@link ParentConstructorFirst} function directly, is used to not clone {@link ParentConstructorFirst} function. This allows the debugging of instance builder function. | ||
* | ||
* @param {Function | null} Constructor - Class constructor. The second last argument | ||
* @param {Object} props - Defines the properties and methods for a new class. The last input argument | ||
* @param {Object | Function | Class | Array} [props.Encapsulate] - Define which object/function/class or an array of classes/functions/objects should be encapsulated into the new class | ||
* @returns {Function} Class | ||
* | ||
* @throws {Error} Incorrect input arguments. It should be: ClassBuilder(Function, [Function], Function | null, Object) | ||
* @throws {Error} Some of the items for encapsulation is incorrect. An item can be: Object, Function, Class | ||
* | ||
* @see {@link ClassBuilder} | ||
* | ||
* @param {Function} [Parent = Object] - Parent class. Built-in 'Object' will be used if this argument will be omitted | ||
* @param {Function | Object} [...rest] - Classes/function's/object's properties and methods of which will be encapsulated | ||
* @param {Object} props - The last input argument. Defines the properties and methods for a new class | ||
* @param {Object | Array} [props.Encapsulate] - Define which object or an array of objects should be encapsulated into the new class | ||
* @returns {Function} Class constructor | ||
*/ | ||
var Class = ClassBuilder.bind(null, CoreConstructor); | ||
/* | ||
new Class({ | ||
private: { | ||
}, | ||
protected: { | ||
}, | ||
public: { | ||
} | ||
var Class = ClassBuilder.bind(null, function() { | ||
// simple wrapper is used here in order to not clone the ParentConstructorFirst function | ||
ParentConstructorFirst.apply(this, arguments); | ||
}); | ||
*/ |
@@ -6,3 +6,3 @@ /* | ||
All source files are available at: http://github.com/valerii-zinchenko/cpp-class | ||
All source files are available at: http://github.com/valerii-zinchenko/class-wrapper | ||
*/ | ||
@@ -17,4 +17,2 @@ | ||
* @author Valerii Zinchenko | ||
* | ||
* @version 1.0.2 | ||
*/ | ||
@@ -34,74 +32,52 @@ | ||
* - inherited methods are stored in class prototype object | ||
* - store default class properties in '_default' object where the objects will be copied, not shared | ||
* - store default class properties in '__default' object where the objects will be copied, not shared | ||
* | ||
* @param {Function} Constructor - Main class constructor subroutine. | ||
* @param {Function} [Parent = Object] - Parent class. Built-in 'Object' will be used if this argument will be omitted | ||
* @param {Function | Object} [...rest] - Classes/function's/object's properties and methods of which will be encapsulated | ||
* @param {Object} props - The last input argument. Defines the properties and methods for a new class | ||
* @param {Object | Array} [props.Encapsulate] - Define which object or an array of objects should be encapsulated into the new class | ||
* @returns {Function} Class constructor | ||
* @param {Function} InstanceBuilder - Function that defines how instances will be created, how constructor(s) will be executed | ||
* @param {Function} [Parent = Object] - Parent class | ||
* @param {Function | null} Constructor - Cconstructor function | ||
* @param {Object} props - Object of properties and methods for a new class. Property names that are used internally and will be ignored by encapsulation: | ||
* - __constructor | ||
* - __parent | ||
* | ||
* @throws {Error} Incorrect input arguments. It should be: ClassBuilder(Function, [Function], [Function | Object]*, Object) | ||
* If some of the object has "__defaults" object, then all of it's properties will be treated as an object of default properties that a new class should have. | ||
* @param {Object | Function | Class | Array} [props.Encapsulate] - Define which object/function/class or an array of objects/functions/classes should be encapsulated into the new class | ||
* @returns {Function} Class | ||
* | ||
* @throws {Error} Incorrect input arguments. It should be: ClassBuilder(Function, [Function], Function | null, Object) | ||
* @throws {Error} Some of the items for encapsulation is incorrect. An item can be: Object, Function, Class | ||
* | ||
* @see {@link Class} | ||
* @see {@link SingletonClass} | ||
*/ | ||
function ClassBuilder(Constructor, Parent, props) { | ||
function ClassBuilder(InstanceBuilder, Parent, Constructor, props) { | ||
// Last input argument is an object of properties for a new class | ||
props = arguments[arguments.length - 1]; | ||
// Second last input argument is a constructor function | ||
Constructor = arguments[arguments.length - 2]; | ||
// Set default Parent class if it is not provided | ||
if (Parent == props) { | ||
if (arguments.length === 3) { | ||
Parent = Object; | ||
} | ||
// An array of an classes, functions and objects properties and methods of which will be incapsulated into a new class | ||
var encapsulations = Array.prototype.slice.call(arguments, 2, -1); | ||
// Validate input arguments | ||
// -------------------------------------------------- | ||
if (arguments.length < 2 | ||
|| typeof Constructor !== 'function' | ||
if (arguments.length < 3 | ||
|| typeof InstanceBuilder !== 'function' | ||
|| Object.prototype.toString.call(Parent) !== '[object Function]' | ||
|| Object.prototype.toString.call(props) !== '[object Object]' | ||
|| encapsulations.some(function(item) { | ||
var type = Object.prototype.toString.call(item); | ||
return type !== '[object Function]' && type !== '[object Object]'; | ||
})) | ||
|| (Constructor !== null && typeof Constructor !== 'function') | ||
|| Object.prototype.toString.call(props) !== '[object Object]') | ||
{ | ||
throw new Error('Incorrect input arguments. It should be: ClassBuilder(Function, [Function], [Function | Object]*, Object)'); | ||
throw new Error('Incorrect input arguments. It should be: ClassBuilder(Function, [Function], Function | null, Object)'); | ||
} | ||
// todo: Validate proprties for a usage of reserverd locally variable names to avoid the interference | ||
// -------------------------------------------------- | ||
// Clone class constructor function | ||
// Prepare an array of what is going to be encapsulated into a new class | ||
// -------------------------------------------------- | ||
var Class; | ||
eval('Class = ' + Constructor.toString()); | ||
// Create reference to a parent's prototype object for internal usage | ||
Class.parent = Parent.prototype; | ||
// -------------------------------------------------- | ||
// Inheritance chain | ||
// -------------------------------------------------- | ||
// Create proxy prototype, in order to not change the parent's prototype | ||
var CoreClass = function(){}; | ||
CoreClass.prototype = Parent.prototype; | ||
Class.prototype = new CoreClass(); | ||
// Revert back the reseted reference to the constructor function | ||
Class.prototype.constructor = Class; | ||
// Create storage for a default properties | ||
Class.prototype._defaults = {}; | ||
// -------------------------------------------------- | ||
// Encapsulate properties and methods of provided objects | ||
// -------------------------------------------------- | ||
var encapsulations = []; | ||
// Collect objects properties and methods of which will be encapsulated into a new class | ||
if (props.Encapsulate) { | ||
if (Object.prototype.toString.call(props.Encapsulate) == '[object Array]') { | ||
if (Object.prototype.toString.call(props.Encapsulate) === '[object Array]') { | ||
encapsulations = encapsulations.concat(props.Encapsulate); | ||
@@ -115,13 +91,51 @@ } else { | ||
} | ||
// Put parent's defaults into an encapsulation chain | ||
if (Parent.prototype._defaults) { | ||
encapsulations.unshift(Parent.prototype._defaults); | ||
// Put parent's defaults into an encapsulation stack | ||
if (Parent.prototype.__defaults) { | ||
encapsulations.unshift(Parent.prototype.__defaults); | ||
} | ||
// Put properties and methods of a new clas into the encapsilation chain | ||
// Put properties and methods for a new class into the encapsulation stack | ||
encapsulations.push(props); | ||
// Setup input properties to the new class | ||
// Encapsulate methods and properties from other classes/objects | ||
// Validate what is going to be encapsulated | ||
if (encapsulations.some(function(item) { | ||
var type = Object.prototype.toString.call(item); | ||
return type !== '[object Function]' && type !== '[object Object]'; | ||
})) | ||
{ | ||
throw new Error('Some of the items for encapsulation is incorrect. An item can be: Object, Function, Class'); | ||
} | ||
// -------------------------------------------------- | ||
// Clone class constructor function to prevent a sharing of instance builder function | ||
// -------------------------------------------------- | ||
var Class; | ||
eval('Class = ' + InstanceBuilder.toString()); | ||
// -------------------------------------------------- | ||
// Inheritance chain | ||
// -------------------------------------------------- | ||
// Derive a new class from a Parent class | ||
Class.prototype = Object.create(Parent.prototype); | ||
// Revert back the reference to the instance builder function | ||
Class.prototype.constructor = Class; | ||
// Store the reference to the constructor function | ||
if (Constructor) { | ||
Class.prototype.__constructor = Constructor; | ||
} | ||
// Create a storage for default properties | ||
Class.prototype.__defaults = {}; | ||
// Store a reference to a parent's prototype object for internal usage | ||
Class.__parent = Parent.prototype; | ||
// -------------------------------------------------- | ||
// Encapsulate properties and methods | ||
// -------------------------------------------------- | ||
for (var n = 0, N = encapsulations.length; n < N; n++) { | ||
utils.encapsulate(encapsulations[n], Class); | ||
ClassBuilder.encapsulate(encapsulations[n], Class); | ||
} | ||
@@ -134,1 +148,45 @@ // -------------------------------------------------- | ||
/** | ||
* Encapsulate methods and properties from 'what' into 'to'. | ||
* If 'what' is a function then its prototype will be encapsulated. | ||
* | ||
* @param {Class | Object | Function} what - Object or Class that will be encapsulated. | ||
* @param {Class} to - Class where the methods and properties will be encapsulated. | ||
*/ | ||
ClassBuilder.encapsulate = function(what, to) { | ||
if (Object.prototype.toString.call(what) === '[object Function]') { | ||
what = what.prototype; | ||
} | ||
for (var key in what) { | ||
// Note. 'constructor' is excluded to not override the real class constructor. | ||
if (what.hasOwnProperty(key) | ||
&& (key !== 'constructor' && key !== '__constructor' && key !== '__parent')) | ||
{ | ||
var value = what[key]; | ||
switch (Object.prototype.toString.call(value)) { | ||
// Store functions into "prototype" | ||
case '[object Function]': | ||
to.prototype[key] = value; | ||
break; | ||
// Clone objects and store the copies into "__defaults" | ||
case '[object Object]': | ||
if (key === '__defaults') { | ||
// NOTE. This is only for cases when some instance of ClassBuilder will be encapsulated. | ||
utils.deepCopy(to.prototype.__defaults, value); | ||
} else { | ||
if (!to.prototype.__defaults[key]) { | ||
to.prototype.__defaults[key] = {}; | ||
} | ||
utils.deepCopy(to.prototype.__defaults[key], value); | ||
} | ||
break; | ||
// Store evererything else into "__defaults" container | ||
default: | ||
to.prototype.__defaults[key] = value; | ||
} | ||
} | ||
} | ||
}; |
@@ -6,7 +6,7 @@ /* | ||
All source files are available at: http://github.com/valerii-zinchenko/cpp-class | ||
All source files are available at: http://github.com/valerii-zinchenko/class-wrapper | ||
*/ | ||
/** | ||
* @file Implementation of [singleton class]{@link SingletonClass} | ||
* @file Implementation of [singleton class]{@link SingletonClass} wrapper | ||
* | ||
@@ -17,4 +17,2 @@ * @see {@link ClassBuilder} | ||
* @author Valerii Zinchenko | ||
* | ||
* @version 1.1.1 | ||
*/ | ||
@@ -25,13 +23,15 @@ | ||
/** | ||
* Singleton Class | ||
* This additionally wraps the {@link CoreConstructor} to store and return already created instance. | ||
* This binds addtional wrapper into ClassBuilder function as the first argument, so it will accept the other arguments. | ||
* Singleton class | ||
* This sets a default instance builder function of {@link ClassBuilder} to achieve the behaviour of a singleton class. | ||
* A creation of a first instance is controlled by {@link ParentConstructorFirst} function. | ||
* | ||
* @param {Function | null} Constructor - Class constructor. The second last argument | ||
* @param {Object} props - Defines the properties and methods for a new class. The last input argument | ||
* @param {Object | Function | Class | Array} [props.Encapsulate] - Define which object/function/class or an array of classes/functions/objects should be encapsulated into the new class | ||
* @returns {Function} Class | ||
* | ||
* @throws {Error} Incorrect input arguments. It should be: ClassBuilder(Function, [Function], Function | null, Object) | ||
* @throws {Error} Some of the items for encapsulation is incorrect. An item can be: Object, Function, Class | ||
* | ||
* @see {@link ClassBuilder} | ||
* | ||
* @param {Function} [Parent = Object] - Parent class. Built-in 'Object' will be used if this argument will be omitted | ||
* @param {Function | Object} [...rest] - Classes/function's/object's properties and methods of which will be encapsulated | ||
* @param {Object} props - The last input argument. Defines the properties and methods for a new class | ||
* @param {Object | Array} [props.Encapsulate] - Define which object or an array of objects should be encapsulated into the new class | ||
* @returns {Function} Class constructor | ||
*/ | ||
@@ -47,3 +47,3 @@ var SingletonClass = ClassBuilder.bind(null, function() { | ||
CoreConstructor.apply(this, arguments); | ||
ParentConstructorFirst.apply(this, arguments); | ||
}); |
@@ -6,3 +6,3 @@ /* | ||
All source files are available at: http://github.com/valerii-zinchenko/cpp-class | ||
All source files are available at: http://github.com/valerii-zinchenko/class-wrapper | ||
*/ | ||
@@ -14,4 +14,2 @@ | ||
* @author Valerii Zinchenko | ||
* | ||
* @version 1.1.0 | ||
*/ | ||
@@ -91,45 +89,3 @@ | ||
return target; | ||
}, | ||
/** | ||
* Encapsulate methods and properties from 'what' object or Class into 'to' Class. | ||
* | ||
* @param {Object | Class} what - Object or Class that will be encapsulated. | ||
* @param {Class} to - Class where the methods and properties will be encapsulated. | ||
*/ | ||
encapsulate: function (what, to) { | ||
if (Object.prototype.toString.call(what) == '[object Function]') { | ||
what = what.prototype; | ||
} | ||
for (var key in what) { | ||
// Note. 'constructor' is excluded to not override the real class constructor. | ||
if (what.hasOwnProperty(key) && key != 'constructor') { | ||
var value = what[key]; | ||
switch (Object.prototype.toString.call(value)) { | ||
// Store functions into "prototype" | ||
case '[object Function]': | ||
to.prototype[key] = value; | ||
break; | ||
// Clone objects and store the copies into "_defaults" | ||
case '[object Object]': | ||
if (key === '_defaults') { | ||
// NOTE. This is only for cases when some instance of ClassBuilder will be encapsulated. | ||
utils.deepCopy(to.prototype._defaults, value); | ||
} else { | ||
if (!to.prototype._defaults[key]) { | ||
to.prototype._defaults[key] = {}; | ||
} | ||
utils.deepCopy(to.prototype._defaults[key], value); | ||
} | ||
break; | ||
// Store evererything else into "_defaults" container | ||
default: | ||
to.prototype._defaults[key] = value; | ||
} | ||
} | ||
} | ||
} | ||
}; |
{ | ||
"name": "class-wrapper", | ||
"version": "0.9.3", | ||
"description": "Set of wrappers for easier creation of different kinds of classes", | ||
"version": "1.0.0", | ||
"description": "Set of wrappers for easier definition of different kinds of classes", | ||
"main": "lib/ClassBuilder.js", | ||
@@ -10,2 +10,3 @@ "author": "Valerii Zinchenko", | ||
"scripts": { | ||
"preversion": "grunt test", | ||
"prepublish": "grunt build" | ||
@@ -12,0 +13,0 @@ }, |
@@ -1,18 +0,19 @@ | ||
# class-wrapper | ||
# {class} | ||
Set of wrappers for easier constructing of different kind of classes. Currently there are three kinds of wrappers: | ||
Set of wrappers for easier definition of different kind of classes. Currently there are three kinds of wrappers: | ||
1. `ClassBuilder` - the main wrapper that realize the inheritance and data encapsulation. It requires a function that defines how the instances will be created. It returns the clone of defined constructor with special features and properties. | ||
1. `Class` - this has predefined wrapper constructor function for `ClassBuilder` for creating an instances, that calls all parent's constructors first before calling the constructor of current class. For example there is `GrandParent` class, `Parent` class that is derived from `GrandParent` class and `Child` class that if derived from the `Parent` class. So when `new Child` will be called then the constructor of `GrandParent` class will be executed, then constructor from Parent class and finally the constructor of Child class. | ||
1. `SingletonClass` - this has predefined wrapper constructor function for `ClassBuilder` for creating an instances, that by any `new` always returns the same instance. It uses the same constructing routine as `Class` to create the first instance. | ||
* `ClassBuilder` - the main wrapper that realize the inheritance and data encapsulation. It requires a function that defines how the instances will be created. It returns the clone of defined instance builder function with special features and properties. | ||
* `Class` - it has predefined instance builder function for `ClassBuilder`, that calls all parent's constructors before calling the constructor of a new class | ||
* `SingletonClass` - it has predefined instance builder function for `ClassBuilder`, that by any `new` always returns the same instance. The first instance will be created in the same way as `Class` | ||
Each wrapper accepts: | ||
* the parent class from which a new class should be derived | ||
* classes, functions and objects, properties and methods of which a new class should encapsulate | ||
* the parent class from which a new class is going to be derived | ||
* constructor function for a new class | ||
* object of properties and methods for a new class | ||
Defined class properties are treated as default values for a new instance and they are isolated between instances, i.e. if some class has an object in properties, then each instance will have its own copy of that default object. Only methods are shared. | ||
Defined class properties are treated as default values for a new instance and they are isolated between instances. For example if some class has an object in properties then each instance will have its own copy of that default object. Only methods are shared. | ||
## Requirements | ||
* [Object.create](http://kangax.github.io/compat-table/es5/#test-Object.create) | ||
* [Function.prototype.bind](http://caniuse.com/#feat=es5) | ||
@@ -35,3 +36,8 @@ * [Array.prototype.forEach](http://caniuse.com/#feat=es5) | ||
The destination library files are surrouned with the [universal module definition](https://github.com/umdjs/umd/). So it can be loaded | ||
- as a module for NodeJS | ||
- as an AMD module | ||
- or can be stored into the global variable under the name `"class-wapper"` | ||
## Simple usage examples | ||
@@ -41,8 +47,5 @@ | ||
// Define a Figure class: | ||
var Figure = Class({ | ||
// this is a constructor | ||
initialize: function() { | ||
console.log('Figure::initialize()'); | ||
}, | ||
var Figure = Class(function() { | ||
console.log('Figure::initialize()'); | ||
}, { | ||
// abstract function for a calculating a suqare of a figure | ||
@@ -53,12 +56,11 @@ calcSquare: function() {} | ||
// Define Rectangle class derived from a Figure class: | ||
var Rectangle = Class(Figure, { | ||
var Rectangle = Class(Figure, function(width, height) { | ||
console.log('Rectangle::initialize()'); | ||
this._width = width; | ||
this._height = height; | ||
}, { | ||
_width: 0, | ||
_height: 0, | ||
initialize: function(width, height) { | ||
console.log('Rectangle::initialize()'); | ||
this._width = width; | ||
this._height = height; | ||
}, | ||
@@ -72,8 +74,6 @@ // abstract function for a calculating a suqare of a figure | ||
// Define Square class as a special case of Rectangle: | ||
var Square = Class(Rectangle, { | ||
initialize: function(length) { | ||
console.log('Square::initialize()'); | ||
var Square = Class(Rectangle, function(length) { | ||
console.log('Square::initialize()'); | ||
this._height = length; | ||
} | ||
this._height = length; | ||
}); | ||
@@ -103,4 +103,5 @@ | ||
## Links | ||
* [wiki](https://github.com/valerii-zinchenko/class-wrapper/wiki) | ||
* [API](http://valerii-zinchenko.github.io/class-wrapper/doc/index.html) | ||
* [Code coverage](http://valerii-zinchenko.github.io/class-wrapper/coverage/index.html) | ||
* [Run unit tests](http://valerii-zinchenko.github.io/class-wrapper/test/index.html) |
@@ -6,10 +6,10 @@ /* | ||
All source files are available at: http://github.com/valerii-zinchenko/cpp-class | ||
All source files are available at: http://github.com/valerii-zinchenko/class-wrapper | ||
*/ | ||
suite('Class', function() { | ||
suite('Instance from a Class', function() { | ||
test('creating an instance without any specified constructor', function(){ | ||
assert.doesNotThrow(function(){ | ||
new (Class({})); | ||
new (Class(null, {})); | ||
}); | ||
@@ -21,8 +21,6 @@ }); | ||
assert.doesNotThrow(function() { | ||
new (Class({ | ||
initialize: spy | ||
}))(); | ||
new (Class(spy, {}))(); | ||
}); | ||
assert.isTrue(spy.calledOnce, 'initialize() is treated as a specific class constructor and it should be called by creating new class instance'); | ||
assert.isTrue(spy.calledOnce, 'constructor is treated as a specific class constructor and it should be called by creating new class instance'); | ||
}); | ||
@@ -35,3 +33,3 @@ | ||
assert.doesNotThrow(function(){ | ||
var Obj = Class({}); | ||
var Obj = Class(null, {}); | ||
@@ -50,3 +48,3 @@ inst1 = new Obj(); | ||
assert.doesNotThrow(function(){ | ||
var Obj = Class({ | ||
var Obj = Class(null, { | ||
obj: {} | ||
@@ -59,3 +57,3 @@ }); | ||
assert.notEqual(obj1.obj, obj2.obj, 'Object under property name "obj" should clonned'); | ||
assert.notEqual(obj1.obj, obj2.obj, 'Object under property name "obj" should not be shared between instances'); | ||
}); | ||
@@ -72,12 +70,6 @@ | ||
assert.doesNotThrow(function(){ | ||
var GrandParentClass = Class({ | ||
initialize: grandParentConstructor | ||
}); | ||
var ParentClass = Class(GrandParentClass, { | ||
initialize: parentConstructor | ||
}); | ||
var ClassWithoutSpecificConstructor = Class(ParentClass, {}); | ||
var ChildClass = Class(ClassWithoutSpecificConstructor, { | ||
initialize: childConstructor | ||
}); | ||
var GrandParentClass = Class(grandParentConstructor, {}); | ||
var ParentClass = Class(GrandParentClass, parentConstructor, {}); | ||
var ClassWithoutSpecificConstructor = Class(ParentClass, null, {}); | ||
var ChildClass = Class(ClassWithoutSpecificConstructor, childConstructor, {}); | ||
@@ -106,5 +98,5 @@ result = new ChildClass(arg0, arg1); | ||
assert.doesNotThrow(function(){ | ||
GrandParentClass = Class({}); | ||
ParentClass = Class(GrandParentClass, {}); | ||
ChildClass = Class(ParentClass, {}); | ||
GrandParentClass = Class(function(){}, {}); | ||
ParentClass = Class(GrandParentClass, function(){}, {}); | ||
ChildClass = Class(ParentClass, function(){}, {}); | ||
@@ -111,0 +103,0 @@ result = new ChildClass(); |
@@ -6,3 +6,3 @@ /* | ||
All source files are available at: http://github.com/valerii-zinchenko/cpp-class | ||
All source files are available at: http://github.com/valerii-zinchenko/class-wrapper | ||
*/ | ||
@@ -15,3 +15,3 @@ | ||
suite('incorrect when', function() { | ||
[].concat([ | ||
[ | ||
{ | ||
@@ -24,31 +24,26 @@ title: 'No arguments', | ||
input: [1] | ||
}], | ||
} | ||
].concat( | ||
[undefined, null, false, 1, '', [], {}].map(function(type){ | ||
return { | ||
title: 'type of Constructor argument: ' + Object.prototype.toString.call(type), | ||
title: 'type of instance builder function argument: ' + Object.prototype.toString.call(type), | ||
input: [type, {}] | ||
} | ||
}), | ||
[undefined, null, false, 1, '', [], function(){}].map(function(type){ | ||
[undefined, false, 0, '', [], {}].map(function(type){ | ||
return { | ||
title: 'type of class properties: ' + Object.prototype.toString.call(type), | ||
input: [function(){}, type] | ||
} | ||
}), | ||
[undefined, null, false, 1, '', [], {}].map(function(type){ | ||
return { | ||
title: 'type of parent class: ' + Object.prototype.toString.call(type), | ||
title: 'type of constructor: ' + Object.prototype.toString.call(type), | ||
input: [function(){}, type, {}] | ||
} | ||
}), | ||
[undefined, null, false, 1, '', []].map(function(type){ | ||
[undefined, null, false, 1, '', [], function(){}].map(function(type){ | ||
return { | ||
title: 'type of being encapsulated class: ' + Object.prototype.toString.call(type), | ||
input: [function(){}, function(){}, type, {}] | ||
title: 'type of class properties: ' + Object.prototype.toString.call(type), | ||
input: [function(){}, null, type] | ||
} | ||
}), | ||
[undefined, null, false, 1, '', []].map(function(type){ | ||
[undefined, null, false, 1, '', [], {}].map(function(type){ | ||
return { | ||
title: 'type of a third from four being encapsulated classes: ' + Object.prototype.toString.call(type), | ||
input: [function(){}, function(){}, {}, function(){}, type, {}, {}] | ||
title: 'type of a parent class: ' + Object.prototype.toString.call(type), | ||
input: [function(){}, type, null, {}] | ||
} | ||
@@ -60,3 +55,3 @@ }) | ||
ClassBuilder.apply(null, testCase.input); | ||
}, Error, 'Incorrect input arguments. It should be: ClassBuilder(Function, [Function], [Function | Object]*, Object)'); | ||
}, Error, 'Incorrect input arguments. It should be: ClassBuilder(Function, [Function], Function | null, Object)'); | ||
}); | ||
@@ -69,12 +64,24 @@ }); | ||
{ | ||
title: 'constructor function and object of properties and methods', | ||
input: [function(){}, {}] | ||
title: 'constructor function, without current class constructor function and object of properties and methods', | ||
input: [function(){}, null, {}] | ||
}, | ||
{ | ||
title: 'constructor function, parent class and object of properties and methods', | ||
title: 'constructor function, current class constructor function and object of properties and methods', | ||
input: [function(){}, function(){}, {}] | ||
}, | ||
{ | ||
title: 'constructor function, parent class, objects/functions being encapsulated and object of properties and methods', | ||
input: [function(){}, function(){}, {}, function(){}, {}, {}, {}] | ||
title: 'constructor function, parent class, no current class constructor function and object of properties and methods', | ||
input: [function(){}, function(){}, null, {}] | ||
}, | ||
{ | ||
title: 'constructor function, parent class, current class constructor function and object of properties and methods', | ||
input: [function(){}, function(){}, function(){}, {}] | ||
}, | ||
{ | ||
title: 'constructor function, parent class, objects/functions being encapsulated, no current class constructor function and object of properties and methods', | ||
input: [function(){}, function(){}, {}, function(){}, {}, {}, null, {}] | ||
}, | ||
{ | ||
title: 'constructor function, parent class, objects/functions being encapsulated, current class constructor function and object of properties and methods', | ||
input: [function(){}, function(){}, {}, function(){}, {}, {}, function(){}, {}] | ||
} | ||
@@ -91,2 +98,58 @@ ].forEach(function(testCase){ | ||
suite('Encapsulated item is', function() { | ||
suite('incorrect', function(){ | ||
[].concat( | ||
[true, 1, 'a'].map(function(type){ | ||
return { | ||
title: 'type of an "Encapsulate" property: ' + Object.prototype.toString.call(type), | ||
input: type | ||
} | ||
}), | ||
[undefined, null, false, 1, '', []].map(function(type){ | ||
return { | ||
title: 'type of some item in an array: ' + Object.prototype.toString.call(type), | ||
input: [function(){}, type, {}] | ||
} | ||
}) | ||
).forEach(function(testCase){ | ||
test(testCase.title, function(){ | ||
assert.throw(function(){ | ||
ClassBuilder.call(null, function(){}, null, {Encapsulate: testCase.input}); | ||
}, Error, 'Some of the items for encapsulation is incorrect. An item can be: Object, Function, Class'); | ||
}); | ||
}); | ||
}); | ||
suite('correct or ignored', function(){ | ||
[].concat( | ||
[undefined, null, false, 0, ''].map(function(type){ | ||
return { | ||
title: 'type of an "Encapsulate" property that should be ignored: ' + Object.prototype.toString.call(type), | ||
input: type | ||
} | ||
}), | ||
[function(){}, {}].map(function(type){ | ||
return { | ||
title: 'type of an "Encapsulate" property: ' + Object.prototype.toString.call(type), | ||
input: type | ||
} | ||
}), | ||
{ | ||
title: 'an empty array of items', | ||
input: [] | ||
}, | ||
{ | ||
title: 'an array of allowed types', | ||
input: [function(){}, {}] | ||
} | ||
).forEach(function(testCase){ | ||
test(testCase.title, function(){ | ||
assert.doesNotThrow(function(){ | ||
ClassBuilder.call(null, function(){}, null, {Encapsulate: testCase.input}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
suite('Resulting class constructor', function(){ | ||
@@ -96,13 +159,14 @@ test('Cloning of a constructor function', function(){ | ||
var Parent = function(){}; | ||
var classConstrucor = function(){}; | ||
var result; | ||
assert.doesNotThrow(function(){ | ||
result = ClassBuilder(constructorFn, Parent, {}); | ||
result = ClassBuilder(constructorFn, Parent, classConstrucor, {}); | ||
}); | ||
assert.notEqual(result, constructorFn, 'Resulting constructor function should not be equal to the input constructor function to avoid data sharing.'); | ||
assert.equal(result.parent, Parent.prototype, 'Reference to the prototype of a parent class is lost'); | ||
assert.equal(result.prototype.constructor, result, 'Class constructor function should be saved and used as constructor for a new class instead of a parent\'s constructor function'); | ||
assert.equal(result.prototype.constructor.__parent, Parent.prototype, 'Reference to the prototype of a parent class is lost'); | ||
assert.equal(result.prototype.__constructor, classConstrucor, 'Class constructor function should be saved and used as constructor for a new class instead of a parent\'s constructor function'); | ||
assert.instanceOf(result.prototype, Parent, 'New class prototype should be an instance of Parent class to save the inheritance chain'); | ||
assert.isObject(result.prototype._defaults, '"_defaults" should be created to store there the default values of own variables'); | ||
assert.isObject(result.prototype.__defaults, '"__defaults" should be created in scope of class constructor to store there the default values of own variables'); | ||
}); | ||
@@ -128,22 +192,23 @@ | ||
assert.doesNotThrow(function(){ | ||
result = ClassBuilder(function(){}, properties); | ||
result = ClassBuilder(function(){}, function(){}, properties); | ||
}); | ||
assert.equal(result.prototype._defaults.number, properties.number, 'Simple Number was incorrectly copied'); | ||
assert.equal(result.prototype._defaults.string, properties.string, 'Simple String was incorrectly copied'); | ||
assert.equal(result.prototype._defaults.bool, properties.bool, 'Simple boolean was incorrectly copied'); | ||
assert.isNull(result.prototype._defaults.nullValue, 'Null type was not copied'); | ||
var ref = result.prototype.constructor.prototype; | ||
assert.equal(ref.__defaults.number, properties.number, 'Simple Number was incorrectly copied'); | ||
assert.equal(ref.__defaults.string, properties.string, 'Simple String was incorrectly copied'); | ||
assert.equal(ref.__defaults.bool, properties.bool, 'Simple boolean was incorrectly copied'); | ||
assert.isNull(ref.__defaults.nullValue, 'Null type was not copied'); | ||
assert.isArray(result.prototype._defaults.array, 'Array type was not copied'); | ||
assert.isTrue(result.prototype._defaults.array[0] === properties.array[0] && result.prototype._defaults.array[1] === properties.array[1], 'Array items was incorrectly copied'); | ||
assert.isArray(ref.__defaults.array, 'Array type was not copied'); | ||
assert.isTrue(ref.__defaults.array[0] === properties.array[0] && ref.__defaults.array[1] === properties.array[1], 'Array items was incorrectly copied'); | ||
assert.isObject(result.prototype._defaults.nestedObj, 'Object type was not saved'); | ||
assert.notEqual(result.prototype._defaults.nestedObj, properties.nestedObj, 'Object from a properties should be shared'); | ||
assert.isObject(result.prototype._defaults.nestedObj.innerObj, 'Inner object was not saved'); | ||
assert.notEqual(result.prototype._defaults.nestedObj.innerObj, properties.nestedObj.innerObj, 'Inner nested object from a properties should be shared'); | ||
assert.equal(result.prototype._defaults.nestedObj.innerObj.v, properties.nestedObj.innerObj.v, 'Value of most inner object was not copied'); | ||
assert.equal(result.prototype._defaults.nestedObj.prop, properties.nestedObj.prop, 'Object properties was incorrectly copied'); | ||
assert.isObject(ref.__defaults.nestedObj, 'Object type was not saved'); | ||
assert.notEqual(ref.__defaults.nestedObj, properties.nestedObj, 'Object from a properties should be shared'); | ||
assert.isObject(ref.__defaults.nestedObj.innerObj, 'Inner object was not saved'); | ||
assert.notEqual(ref.__defaults.nestedObj.innerObj, properties.nestedObj.innerObj, 'Inner nested object from a properties should be shared'); | ||
assert.equal(ref.__defaults.nestedObj.innerObj.v, properties.nestedObj.innerObj.v, 'Value of most inner object was not copied'); | ||
assert.equal(ref.__defaults.nestedObj.prop, properties.nestedObj.prop, 'Object properties was incorrectly copied'); | ||
assert.isFunction(result.prototype.fn, 'All functions should be saved in prototype for desired reuse'); | ||
assert.equal(result.prototype.fn, properties.fn, 'Functions should be shared'); | ||
assert.isFunction(ref.fn, 'All functions should be saved in prototype for desired reuse'); | ||
assert.equal(ref.fn, properties.fn, 'Functions should be shared'); | ||
}); | ||
@@ -159,34 +224,34 @@ | ||
{ | ||
title: 'one simple object', | ||
input: [{ | ||
prop: 'prop', | ||
method: fns.method | ||
}, {}], | ||
title: '"constructor", "__constructor" and "__parent" should be ignored', | ||
input: [null, { | ||
constructor: function(){}, | ||
__constructor: function(){}, | ||
__parent: {}, | ||
p0: 'p0' | ||
}], | ||
expected: { | ||
properties: { | ||
prop: 'prop' | ||
p0: 'p0' | ||
}, | ||
methods: { | ||
method: fns.method | ||
} | ||
methods: {} | ||
} | ||
}, | ||
{ | ||
title: 'two simple objects', | ||
input: [ | ||
{ | ||
title: 'one simple object', | ||
input: [null, { | ||
Encapsulate: { | ||
prop: 'prop', | ||
method: fns.method | ||
}, | ||
{ | ||
prop2: 'PROP' | ||
}, | ||
{}], | ||
p0: 'p0', | ||
method2: fns.method2 | ||
}], | ||
expected: { | ||
properties: { | ||
prop: 'prop', | ||
prop2: 'PROP' | ||
p0: 'p0', | ||
prop: 'prop' | ||
}, | ||
methods: { | ||
method: fns.method | ||
method: fns.method, | ||
method2: fns.method2 | ||
} | ||
@@ -196,61 +261,25 @@ } | ||
{ | ||
title: 'two simple objects with different properties of inner object', | ||
input: [ | ||
{ | ||
prop: 'prop', | ||
obj: { | ||
prp: 'prp' | ||
title: 'two simple objects', | ||
input: [null, { | ||
Encapsulate: [ | ||
{ | ||
prop: 'prop', | ||
method: fns.method | ||
}, | ||
method: fns.method | ||
}, | ||
{ | ||
prop2: 'PROP', | ||
obj: { | ||
prp2: 'prp2' | ||
}, | ||
}, | ||
{}], | ||
expected: { | ||
properties: { | ||
prop: 'prop', | ||
prop2: 'PROP', | ||
obj: { | ||
prp: 'prp', | ||
prp2: 'prp2' | ||
{ | ||
prop2: 'PROP' | ||
} | ||
}, | ||
methods: { | ||
method: fns.method | ||
} | ||
} | ||
}, | ||
{ | ||
title: 'one class created by ClassBuilder', | ||
input: [ClassBuilder(function(){}, { | ||
prop: 'prop', | ||
method: fns.method | ||
}), {}], | ||
], | ||
p0: 'p0', | ||
method2: fns.method2 | ||
}], | ||
expected: { | ||
properties: { | ||
prop: 'prop' | ||
}, | ||
methods: { | ||
method: fns.method | ||
} | ||
} | ||
}, | ||
{ | ||
title: 'one object from "Encapsulate" property', | ||
input: [{ | ||
Encapsulate: { | ||
p0: 'p0', | ||
prop: 'prop', | ||
method: fns.method | ||
} | ||
}], | ||
expected: { | ||
properties: { | ||
prop: 'prop' | ||
prop2: 'PROP' | ||
}, | ||
methods: { | ||
method: fns.method | ||
method: fns.method, | ||
method2: fns.method2 | ||
} | ||
@@ -260,23 +289,37 @@ } | ||
{ | ||
title: 'two objects from "Encapsulate" property', | ||
input: [{ | ||
title: 'two simple objects with different properties of inner object', | ||
input: [null, { | ||
Encapsulate: [ | ||
{ | ||
prop: 'prop', | ||
obj: { | ||
prp: 'prp' | ||
}, | ||
method: fns.method | ||
}, | ||
{ | ||
prop2: 'prop2', | ||
method2: fns.method2 | ||
prop2: 'PROP', | ||
obj: { | ||
prp2: 'prp2' | ||
}, | ||
} | ||
] | ||
], | ||
p0: 'p0', | ||
obj: { | ||
p1: 'p1' | ||
} | ||
}], | ||
expected: { | ||
properties: { | ||
p0: 'p0', | ||
prop: 'prop', | ||
prop2: 'prop2' | ||
prop2: 'PROP', | ||
obj: { | ||
p1: 'p1', | ||
prp: 'prp', | ||
prp2: 'prp2' | ||
} | ||
}, | ||
methods: { | ||
method: fns.method, | ||
method2: fns.method2 | ||
method: fns.method | ||
} | ||
@@ -286,35 +329,17 @@ } | ||
{ | ||
title: 'two objects over input arguments and two objects from "Encapsulate" property with interference (the last one should have a precedence)', | ||
input: [ | ||
{ | ||
prop: 'v1', | ||
title: 'one class created by ClassBuilder', | ||
input: [null, { | ||
Encapsulate: ClassBuilder(function(){}, null, { | ||
prop: 'prop', | ||
method: fns.method | ||
}, | ||
{ | ||
prop: 'v2', | ||
prop2: 'vv1', | ||
method2: fns.method2 | ||
}, | ||
{Encapsulate: [ | ||
{ | ||
prop: 'v3', | ||
prop3: 'vvv1', | ||
method2: fns.method | ||
}, | ||
{ | ||
prop2: 'vv2', | ||
method: fns.method2, | ||
method2: fns.method | ||
} | ||
]} | ||
], | ||
}), | ||
p0: 'p0' | ||
}], | ||
expected: { | ||
properties: { | ||
prop: 'v3', | ||
prop2: 'vv2', | ||
prop3: 'vvv1' | ||
p0: 'p0', | ||
prop: 'prop' | ||
}, | ||
methods: { | ||
method: fns.method2, | ||
method2: fns.method | ||
method: fns.method | ||
} | ||
@@ -325,2 +350,4 @@ } | ||
test(testCase.title, function(){ | ||
// Add instance builder function and parent function. | ||
// Parent function is added in order to not interpret any input cases as parent class | ||
testCase.input.unshift(function(){}, function(){}); | ||
@@ -333,7 +360,8 @@ | ||
assert.deepEqual(result.prototype._defaults, testCase.expected.properties, 'Properties were incorrectly encapsulated'); | ||
var ref = result.prototype; | ||
assert.deepEqual(ref.__defaults, testCase.expected.properties, 'Properties were incorrectly encapsulated'); | ||
for (var method in testCase.expected.methods) { | ||
assert.isFunction(result.prototype[method], method + ' was not encapsulated'); | ||
assert.equal(result.prototype[method], testCase.expected.methods[method], method + ' was incorrectly encapsulated'); | ||
assert.isFunction(ref[method], method + ' was not encapsulated'); | ||
assert.equal(ref[method], testCase.expected.methods[method], method + ' was incorrectly encapsulated'); | ||
}; | ||
@@ -352,5 +380,5 @@ }); | ||
assert.doesNotThrow(function(){ | ||
GrandParent = ClassBuilder(function(){}, {}); | ||
Parent = ClassBuilder(function(){}, GrandParent, {}); | ||
Child = ClassBuilder(function(){}, Parent, {}); | ||
GrandParent = ClassBuilder(function(){}, function(){}, {}); | ||
Parent = ClassBuilder(function(){}, GrandParent, function(){}, {}); | ||
Child = ClassBuilder(function(){}, Parent, function(){}, {}); | ||
@@ -357,0 +385,0 @@ result = new Child(); |
@@ -6,10 +6,10 @@ /* | ||
All source files are available at: http://github.com/valerii-zinchenko/cpp-class | ||
All source files are available at: http://github.com/valerii-zinchenko/class-wrapper | ||
*/ | ||
suite('SingletonClass', function() { | ||
suite('Instance from a SingletonClass', function() { | ||
test('creating an instance without any specified constructor', function(){ | ||
assert.doesNotThrow(function(){ | ||
new (SingletonClass({})); | ||
new (SingletonClass(null, {})); | ||
}); | ||
@@ -21,8 +21,6 @@ }); | ||
assert.doesNotThrow(function() { | ||
new (SingletonClass({ | ||
initialize: spy | ||
}))(); | ||
new (SingletonClass(spy, {}))(); | ||
}); | ||
assert.isTrue(spy.calledOnce, 'initialize() is treated as a specific class constructor and it should be called by creating new class instance'); | ||
assert.isTrue(spy.calledOnce, 'constructor is treated as a specific class constructor and it should be called by creating new class instance'); | ||
}); | ||
@@ -36,5 +34,3 @@ | ||
assert.doesNotThrow(function(){ | ||
var Obj = SingletonClass({ | ||
initialize: constructorFn | ||
}); | ||
var Obj = SingletonClass(constructorFn, {}); | ||
@@ -49,16 +45,12 @@ inst1 = new Obj(); | ||
test('Calling of parent initialize()', function() { | ||
test('Calling of parent constructor', function() { | ||
var value = 11, | ||
k = 4; | ||
var Parent = new SingletonClass({ | ||
initialize: function() { | ||
this.value = value; | ||
} | ||
}); | ||
var Child = new SingletonClass(Parent, { | ||
initialize: function() { | ||
this.value *= k; | ||
} | ||
}); | ||
var Parent = new SingletonClass(function() { | ||
this.value = value; | ||
}, {}); | ||
var Child = new SingletonClass(Parent, function() { | ||
this.value *= k; | ||
}, {}); | ||
@@ -75,5 +67,5 @@ assert.equal((new Child()).value, value*k); | ||
assert.doesNotThrow(function(){ | ||
GrandParentClass = SingletonClass({}); | ||
ParentClass = Class(GrandParentClass, {}); | ||
ChildClass = Class(ParentClass, {}); | ||
GrandParentClass = SingletonClass(null, {}); | ||
ParentClass = Class(GrandParentClass, null, {}); | ||
ChildClass = Class(ParentClass, null, {}); | ||
@@ -93,4 +85,4 @@ result = new ChildClass(); | ||
assert.doesNotThrow(function(){ | ||
var Parent = SingletonClass({}); | ||
var Child = SingletonClass(Parent, {}); | ||
var Parent = SingletonClass(null, {}); | ||
var Child = SingletonClass(Parent, null, {}); | ||
@@ -97,0 +89,0 @@ parentInst = new Parent(); |
@@ -6,3 +6,3 @@ /* | ||
All source files are available at: http://github.com/valerii-zinchenko/cpp-class | ||
All source files are available at: http://github.com/valerii-zinchenko/class-wrapper | ||
*/ | ||
@@ -9,0 +9,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
66055
18
1425
1
103