Skip to content

Commit

Permalink
Class Making fixed WITH INHERITANCE \!
Browse files Browse the repository at this point in the history
  • Loading branch information
kane-thornwyrd committed Feb 8, 2016
1 parent 8ea1aeb commit 6c9f3de
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 102 deletions.
131 changes: 49 additions & 82 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,110 +105,77 @@
return _return;
};

etho.x = function ethoX(nameForNewClass /*, parentClass , customConstructor*/){


var
baseMeta = {
name : '',
version : '0.0.1-dev'
},
product = {},
_inheritance = false
;

if(!etho.isA('string', nameForNewClass)){
nameForNewClass = etho.merge(baseMeta, nameForNewClass );
} else {
nameForNewClass = etho.merge(baseMeta, {
name : nameForNewClass
});
etho.inherit = function ethoInherit(child, parent) {
for (var key in parent) {
if ({}.hasOwnProperty.call(parent, key)){
child[key] = parent[key];
}
}

var args = etho.toArraySliced(arguments);

switch(args.length){
case 1:
_minimal.apply(this, args);
break;
case 2:
_customConstructor.apply(this, args);
break;
case 3:
_fullFledged.apply(this, args);
break;
default:
throw new Error('Wrong arguments in etho.x !');
}
var wrapper = function wrapper() { this.constructor = child; }

try{
wrapper.prototype = parent.prototype;
child.prototype = new wrapper();
child.__super__ = parent.prototype;
}catch(e){
console.log(e, child);
}
return child;
};

etho.x = function ethoX(classname, customConstructor, parentClass){
var args = etho.toArraySliced(arguments, 1);

function parentInvoke(method){
if(typeof this.parent[method] !== 'undefined'){
return this.parent[method].apply(this, etho.toArraySliced(arguments, 1));
}
return null;
};
if(args.length === 0){
parentClass = function Lambda(){};
}

var CHILD = this[classname] = customConstructor || etho.x.minimalConstructor();

function _minimal(nameForNewClass){
product = etho.x.minimalConstructor;
product.prototype.parent = {};
product.prototype.constructor = etho.x.minimalConstructor;
product.prototype.parentMethod = parentInvoke;

if(etho.isA('undefined', classname)){
throw 'classname is missing !';
}


function _customConstructor(nameForNewClass, customConstructor){
product = customConstructor;
product.prototype.parent = {};
product.prototype.constructor = customConstructor;
product.prototype.parentMethod = parentInvoke;
if(etho.isA('undefined', parentClass)){
parentClass = function Lambda(){};
}

return function protoCreation(proto){

function _fullFledged(nameForNewClass, parentClass, customConstructor){
product = customConstructor;
var _t = Object.create(parentClass);
product.prototype = _t;
product.prototype.parent = parentClass.prototype;
product.prototype.constructor = customConstructor;
product.prototype.parentMethod = parentInvoke;
}

return (function(parent){
etho.inherit(CHILD, parent);

var prototypeEnrichment = function _prototypeEnrichment(newMethods){
for(var attr in newMethods){
if( newMethods.hasOwnProperty( attr ) ) {
product.prototype[attr] = newMethods[attr];
for(var attr in proto){
if( proto.hasOwnProperty( attr ) ) {
CHILD.prototype[attr] = proto[attr];
}
}
}

var _functionFilter = function(val, k, obj){return etho.isA('function',val);};
var autoSuper = function autoSuper(method){
if(
!etho.isA('undefined', CHILD.__super__) &&
!etho.isA('undefined', CHILD.__super__[method])
){
return CHILD.__super__[method];
}
return undefined;
};

for(var meth in product.prototype.parent){
if(product.prototype.parent.hasOwnProperty(meth)){
if(typeof product.prototype[meth] === 'undefined'){
product.prototype[meth] = function autoInheritedMethod(){
var args = etho.toArraySliced(arguments);
args.unshift(meth);
return parentInvoke.apply(this, args);
};
for(var oldattr in parent){
if( parent.hasOwnProperty( oldattr ) ) {
CHILD.prototype[oldattr] = autoSuper(oldattr);
}
}
}
return product;
};
product.prototype.meta = nameForNewClass;


return CHILD;


return prototypeEnrichment;
})(parentClass);
}
};

etho.x.minimalConstructor = function ethoGenericConstructor(options){
etho.x.minimalConstructor = function(){ return function ethoGenericConstructor(options){
if(this.defaultOptions){
this.options = etho.merge(this.defaultOptions, options);
}else{
Expand All @@ -217,7 +184,7 @@
if( this.init ){ this.init(); }
if( this.listen ){ this.listen(); }
return this;
}
};};

return etho;
}));
37 changes: 17 additions & 20 deletions test/main.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -203,40 +203,37 @@ describe 'x',->

staticOutput = getARandomString()
testValue = getARandomString()
ancestorClassName = 'TestAncestorClass'
ancestorClassPrototype =
foo: (@bar)->
baz: ()-> 'ancestor'
# baz: sinon.spy()
father : (val)-> "father:#{val}"

minimalClassName = 'TestMinimalClass'
minimalClassPrototype =
init: ->
@
test : (@attr)-> staticOutput
baz : ()-> 'child'
trans: (val)-> "child:#{@parentMethod 'father', val}:child"
trans: (val)->
console.log ChildClass.__super__.father val
val

ancestorClass = etho.x(ancestorClassName, ->) ancestorClassPrototype
childClass = etho.x(minimalClassName,ancestorClass, -> ) minimalClassPrototype
newObject = new childClass()
try
AncestorClass = etho.x('AncestorClass') ancestorClassPrototype
ChildClass = etho.x('ChildClass', undefined, AncestorClass) minimalClassPrototype
newObject = new ChildClass()
catch e
console.log e

it 'should return a function that serve to populate the prototype of a new Class',->
newObject.test.should.be.a 'function'
newObject.test(testValue).should.be.equal staticOutput
newObject.attr.should.be.equal testValue

it 'should give the new Class a meta attribute containing at least his name',->
newObject.should.be.an.instanceof childClass
newObject.should.have.property 'meta'
newObject.meta.name.should.be.equal minimalClassName
it 'should return a function that serve to populate the prototype of a new Class',->
etho.x('AnotherClass').should.be.a 'function'

it 'should allow to specify an ancestor class',->
newObject.prototype.should.have.property 'meta'
newObject.meta.name.should.be.equal minimalClassName
newObject.parent.meta.name.should.not.be.equal minimalClassName
newObject.should.be.an.instanceof AncestorClass

it 'should allow the new Class to call specific method from his ancestor',->
newObject.trans(testValue).should.be.equal "child:father:#{testValue}:child"
newObject.father.should.be.a 'function'

it 'should allow to call a method from the ancestor class, even if it hasn\'t been re-implemented', ->
newObject.father(testValue).should.be.equal "father:#{testValue}"
newObject.father.should.be.a 'function'

0 comments on commit 6c9f3de

Please sign in to comment.