Skip to content

Commit

Permalink
Version 0.2.0
Browse files Browse the repository at this point in the history
* Changed syntax such that new classes are returned on creation and can
be stored in any variable.

* Classes no longer toString to a nice name of themselves. Rather they
toString to what a JavaScript developer would expect.

* Speed has been improved by about 30% for both initialisation and
method calls

* Total code size has been reduced by about 20%

* Code can now be compressed with uglify without the compressed code
needing changes to work.
  • Loading branch information
Benjaminsen committed Sep 27, 2013
1 parent 6dcfa44 commit 1b9de62
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 82 deletions.
5 changes: 2 additions & 3 deletions bin/extend.min.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
ExtendJS 0.1.1
ExtendJS 0.2.0
More info at http://extendjs.org
Copyright (c) 2013 ChrisBenjaminsen.com
Expand All @@ -9,5 +9,4 @@ http://extendjs.org/licence.txt
This notice shall be included in all copies or substantial portions of the Software.
*/

!function(){var a={constructor:!0,toString:!0,"super":!0},b=this;this.Class=function(){},Class.extend=function(c){function d(a){if(a.parent){d.apply(this,[a.parent]);var b=f(this,this.constructor);e(this,b),this.super=b}a.apply(this,arguments)}function e(b,c){for(var d in b)!b.__lookupGetter__(d)&&b[d]instanceof Function&&!a[d]&&(c[d]=b[d].super||f(b,b[d]))}function f(a,b){var c=a.super;return b.super=function(){return a.super=c,a.super=b.apply(a,arguments),a.super},b.super}var g=function(){a!==arguments[0]&&(d.apply(this,[c]),e(this,this),this.initializer&&this.initializer.apply(this),this.constructor.apply(this,arguments))},h=c.toString().match(/function\s+(\w+)/i);if(!h||0==h.length)throw"You must declare a classname for "+c;var i=h[1]||"Unknown";g.prototype=new this(a),g.prototype.constructor=g,g.prototype.inheritancePath=c.inheritancePath=c.inheritancePath?c.inheritancePath+"->"+i:i,g.toString=function(){return"[Class "+i+"]"},g.prototype.toString=function(){return"[Instance "+i+"]"};var j=arguments.callee;g.extend=function(a){return a.parent=c,a.inheritancePath=c.inheritancePath,j.apply(g,arguments)},b[i]=g},Class.extend(function(){this.constructor=function Class(){}})}();
!function(){function a(d){void 0!==d.parent&&(a.apply(this,[d.parent]),this.super=b(this,c(this,this.constructor))),d.apply(this,arguments)}function b(a,b){for(var d in a)"constructor"!=d&&"toString"!=d&&"super"!=d&&!a.__lookupGetter__(d)&&a[d]instanceof Function&&(b[d]=a[d].super||c(a,a[d]));return b}function c(a,b){var c=a.super;return b.super=function(){return a.super=c,b.apply(a,arguments)}}this.Class=function(){},Class.extend=function(c){function d(){a!==arguments[0]&&(a.apply(this,[c]),b(this,this),void 0!==this.initializer&&this.initializer.apply(this),this.constructor.apply(this,arguments))}d.prototype=new this(a),d.prototype.constructor=d,d.toString=function(){return c.toString()};var e=arguments.callee;return d.extend=function(a){return a.parent=c,e.apply(d,arguments)},d},Class=Class.extend(function(){this.constructor=function(){}})}();
87 changes: 35 additions & 52 deletions src/extend.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,87 +23,70 @@
THE SOFTWARE.
*/
(function(){
var skip = {constructor:true, toString:true, super:true};
var base = this;
this.Class = function(){};
Class.extend = function(to){
function initialize(method){
//Recursivly execute parent methods.
if(method.parent){
initialize.apply(this,[method.parent]);
var ns = superCopy(this,this.constructor);
cloneCopy(this,ns);
this.super = ns;
}
method.apply(this, arguments);
//Helper method for creating an super copied object clone
function initialize(method){
//Recursivly execute parent methods.
if(method.parent !== undefined){
initialize.apply(this,[method.parent]);
this.super = cloneCopy(this,
superCopy(this,this.constructor)
);
}
method.apply(this, arguments);
}

//Helper method for creating an super copied object clone
function cloneCopy(from, to){
for(var x in from){
if(!from.__lookupGetter__(x) && from[x] instanceof Function && !skip[x] ){
//Never create circular super referances.
to[x] = from[x].super || superCopy(from, from[x]);
}
//Helper method which allows for super referances.
function cloneCopy(from, to){
for(var x in from){
if(x != "constructor" && x != "toString" && x != "super" && !from.__lookupGetter__(x) && from[x] instanceof Function ){
//Never create circular super referances.
to[x] = from[x].super || superCopy(from, from[x]);
}
}
return to
}

//Helper method which allows for super referances.
function superCopy(scope, method){
var scopeSuper = scope.super;
method.super = function(){
scope.super = scopeSuper;
scope.super = method.apply(scope, arguments);
return scope.super;
}
return method.super;
function superCopy(scope, method){
var scopeSuper = scope.super;
return method.super = function(){
scope.super = scopeSuper;
return method.apply(scope, arguments);
}
}

var child = function(){
//Create Class object
this.Class = function(){};
Class.extend = function(to){
function child(){
//Prevent the prototype scope set executing the constructor.
if(skip === arguments[0]) return;
if(initialize === arguments[0]) return;
//Create inhereted object
initialize.apply(this,[to]);
//Setup scope for class instance method calls
cloneCopy(this,this);
if(this.initializer) this.initializer.apply(this);
if(this.initializer !== undefined) this.initializer.apply(this);
this.constructor.apply(this,arguments);
}


//Validate that we defined a constructor.
var rt = to.toString().match(/function\s+(\w+)/i);//to.toString().match(/this\.constructor[^=]?=[^f]?function\s?(\w+)/i)
if(!rt || rt.length == 0) throw "You must declare a classname for " + to;

var type = rt[1] || "Unknown";

//Set prototype and constructor enabeling propper type checking.
child.prototype = new this(skip);
child.prototype = new this(initialize);
child.prototype.constructor = child;

//Setup inherentence path.
child.prototype.inheritancePath = to.inheritancePath = to.inheritancePath ? to.inheritancePath + "->" + type : type;

//Fix tostrings
child.toString = function(){
return "[Class "+type+"]";
}
child.prototype.toString = function(){
return "[Instance "+type+"]";
return to.toString()
}

//Allow the child to be extended.
var ext = arguments.callee;
child.extend = function(target){
//Create parent referance and inherentence path.
target.parent = to;
target.inheritancePath = to.inheritancePath;
return ext.apply(child,arguments);
}

base[type] = child;
//return child

return child
}
//Bootstrap Class by inheriting itself with empty constructor.
Class.extend(function Class(){this.constructor=function(){}});
Class = Class.extend(function(){this.constructor=function(){}});
})()
5 changes: 2 additions & 3 deletions tests/extend.min.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
ExtendJS 0.1.1
ExtendJS 0.2.0
More info at http://extendjs.org
Copyright (c) 2013 ChrisBenjaminsen.com
Expand All @@ -9,5 +9,4 @@ http://extendjs.org/licence.txt
This notice shall be included in all copies or substantial portions of the Software.
*/

!function(){var a={constructor:!0,toString:!0,"super":!0},b=this;this.Class=function(){},Class.extend=function(c){function d(a){if(a.parent){d.apply(this,[a.parent]);var b=f(this,this.constructor);e(this,b),this.super=b}a.apply(this,arguments)}function e(b,c){for(var d in b)!b.__lookupGetter__(d)&&b[d]instanceof Function&&!a[d]&&(c[d]=b[d].super||f(b,b[d]))}function f(a,b){var c=a.super;return b.super=function(){return a.super=c,a.super=b.apply(a,arguments),a.super},b.super}var g=function(){a!==arguments[0]&&(d.apply(this,[c]),e(this,this),this.initializer&&this.initializer.apply(this),this.constructor.apply(this,arguments))},h=c.toString().match(/function\s+(\w+)/i);if(!h||0==h.length)throw"You must declare a classname for "+c;var i=h[1]||"Unknown";g.prototype=new this(a),g.prototype.constructor=g,g.prototype.inheritancePath=c.inheritancePath=c.inheritancePath?c.inheritancePath+"->"+i:i,g.toString=function(){return"[Class "+i+"]"},g.prototype.toString=function(){return"[Instance "+i+"]"};var j=arguments.callee;g.extend=function(a){return a.parent=c,a.inheritancePath=c.inheritancePath,j.apply(g,arguments)},b[i]=g},Class.extend(function(){this.constructor=function Class(){}})}();
!function(){function a(d){void 0!==d.parent&&(a.apply(this,[d.parent]),this.super=b(this,c(this,this.constructor))),d.apply(this,arguments)}function b(a,b){for(var d in a)"constructor"!=d&&"toString"!=d&&"super"!=d&&!a.__lookupGetter__(d)&&a[d]instanceof Function&&(b[d]=a[d].super||c(a,a[d]));return b}function c(a,b){var c=a.super;return b.super=function(){return a.super=c,b.apply(a,arguments)}}this.Class=function(){},Class.extend=function(c){function d(){a!==arguments[0]&&(a.apply(this,[c]),b(this,this),void 0!==this.initializer&&this.initializer.apply(this),this.constructor.apply(this,arguments))}d.prototype=new this(a),d.prototype.constructor=d,d.toString=function(){return c.toString()};var e=arguments.callee;return d.extend=function(a){return a.parent=c,e.apply(d,arguments)},d},Class=Class.extend(function(){this.constructor=function(){}})}();
41 changes: 17 additions & 24 deletions tests/test.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
//UNIT TESTS!
//They are ugly but they work

Class.extend(function myClass(){
var myClass = Class.extend(function(){
this.test = 2;
this.constructor = function(){
this.myfunction("----");
Expand All @@ -30,13 +30,13 @@
}
})

myClass.extend(function myClass2(){
var myClass2 = myClass.extend(function(){
this.toptest = function(passed){
return this.super.toptest(passed) + "*";
}
})

myClass2.extend(function myClass3(){
var myClass3 = myClass2.extend(function(){
this.myfunction = function(passed){
return "123" + this.super.myfunction(passed);
}
Expand All @@ -45,57 +45,57 @@
}
})

myClass2.extend(function myClass4(){
var myClass4 = myClass2.extend(function(){
this.test = 4;
this.myfunction = function(passed){
return "1234" + this.super.myfunction(passed);
}
})

myClass3.extend(function myClass5(){
var myClass5 = myClass3.extend(function(){
})

Class.extend(function newClass(){
var newClass = Class.extend(function(){
this.constructor = function (){
var that = this
setTimeout(function(){that.testMethod("[Instance newClass]")},1)
setTimeout(function(){that.testMethod(that)},1)
}
this.testMethod = function(compare){
WriteUnitTest(this.toString() == compare, "Testing that scope is reset for global scope execution of class methods for " + compare)
WriteUnitTest(this == compare, "Testing that scope is reset for global scope execution")
}
})

newClass.extend(function newClass2(){
var newClass2 = newClass.extend(function(){
this.constructor = function (){
var that = this
setTimeout(function(){that.testMethod("[Instance newClass2]")},1)
setTimeout(function(){that.testMethod(that)},1)
}
})

var didExecute = false
Class.extend(function PrototypeTestClass(){
var PrototypeTestClass = Class.extend(function(){
this.constructor = function(value){
didExecute = value
}
})
PrototypeTestClass.extend(function PrototypeTestClass2(){
var PrototypeTestClass2 = PrototypeTestClass.extend(function(){
})
PrototypeTestClass2.extend(function PrototypeTestClass3(){
var PrototypeTestClass3 = PrototypeTestClass2.extend(function(){
this.constructor = function(){
this.super("Success")
}
})


Class.extend(function RootClass(){
var RootClass = Class.extend(function(){
this.test = function(){
return "--" + this.inner()
}
this.inner = function(){
return "ERROR"
}
})
RootClass.extend(function MidClass(){
var MidClass = RootClass.extend(function(){
this.test = function(){
return "||" + this.super.test();
}
Expand All @@ -104,7 +104,7 @@
}
})
var shouldNotBeCalled = true;
MidClass.extend(function ChildClass(){
var ChildClass = MidClass.extend(function(){
this.inner = function(){
return "**"
}
Expand All @@ -113,15 +113,10 @@
});
})



new newClass()
new newClass2()
WriteUnitTest(myClass.toString() == "[Class myClass]", "Testing myClass toString")
WriteUnitTest(myClass3.toString() == "[Class myClass3]", "Testing myClass3 toString")
WriteUnitTest(new myClass().toString() == "[Instance myClass]", "Testing instance of myClass toString")
WriteUnitTest(new myClass2().toString() == "[Instance myClass2]", "Testing instance of myClass toString lvl 2")
WriteUnitTest(new myClass3().toString() == "[Instance myClass3]", "Testing instance of myClass toString lvl 3")

WriteUnitTest(new myClass() != new myClass(), "Testing that two instances of same object is not the same")
WriteUnitTest(new myClass().myfunction("test") == "test", "Testing that we can call a sub method")
WriteUnitTest(new myClass2().myfunction("test") == "test", "Testing that level 1 inherited value is correctly inherited")
Expand All @@ -143,7 +138,5 @@
WriteUnitTest(didExecute == "Success", "Testing if we can call constructor via non existing constructor overwrite")//*/
WriteUnitTest(new ChildClass().test() == "||--**", "Secound validation for complex scopes")
WriteUnitTest(shouldNotBeCalled, "Testing that getters are not being called during class cloning")


</script>
</html>

0 comments on commit 1b9de62

Please sign in to comment.