Socket
Socket
Sign inDemoInstall

class-wrapper

Package Overview
Dependencies
Maintainers
1
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

class-wrapper - npm Package Compare versions

Comparing version 0.9.3 to 1.0.0

jsdoc.conf.json

329

dest/class-wrapper.js

@@ -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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc