Joose.Manual.Unsweetened - Joose code, de-sugared.
Lets imagine we have two simple classes in Joose:
Class('Person', {
has : {
firstName : { is : 'rw', required : true },
lastName : { is : 'rw', required : true }
},
methods : {
eat : function () {
}
}
})
Class('Person.Tidy', {
isa : Person,
has : {
teethBrush : {
is : 'rw',
required : true
}
},
before : {
eat : function () {
this.washHands()
}
},
after : {
eat : function () {
this.brushTeeths()
}
},
methods : {
washHands : function () {
...
},
brushTeeths : function () {
...
}
}
})
Now the same classes are rewritten in "raw" javascript (the functionality is strictly the same).
if (typeof Person != 'undefined') throw "Namespace 'Person' is already allocated"
Person = function (firstName, lastName) {
if (!firstName) throw "Required attribute 'firstName' was not provided to constructor"
if (!lastName) throw "Required attribute 'lastName' was not provided to constructor"
this.firstName = firstName
this.lastName = lastName
}
Person.prototype = {
getFirstName : function () {
return this.firstName
},
setFirstName : function (firstName) {
this.firstName = firstName
return this
},
getLastName : function () {
return this.lastName
},
setLastName : function (lastName) {
this.lastName = lastName
return this
},
eat : function () {
...
}
}
//eof Person
(function(){
if (typeof Person == 'undefined') throw "Parent class 'Person' is not defined"
if (typeof Person.Tidy != 'undefined') throw "Namespace 'Person.Tidy' is already allocated"
//establishing inheritance chain
var temp = function () {}
temp.prototype = Person.prototype
Person.Tidy = function (firstName, lastName, teethBrush) {
Person.call(this, firstName, lastName)
if (!teethBrush) throw "Required attribute 'teethBrush' was not provided to constructor"
this.teethBrush = teethBrush
}
var proto = Person.Tidy.prototype = new temp()
proto.setTeethBrush = function (teethBrush) {
this.teethBrush = teethBrush
return this
}
proto.washHands = function () {
...
}
proto.brushTeeths = function () {
...
}
proto.eat = function () {
this.washHands()
var res = Person.eat.apply(this, arguments)
this.brushTeeths()
return res
}
})()
Wow, that was a mouthful! One thing to note is that in "raw" JavaScript the inheritance hierarchy is hard-coded -
if you'll change the superclass of Person.Tidy
you'll have to manually scan through the code and replace all call to Person
.
Of course, there are several JavaScript frameworks that do some of what Joose does, like ExtJS, Dojo, Prototype, and so on. But none of them put together all of Joose's features along with a layer of declarative sugar, nor are these other modules designed for extensibility in the same way as Joose. With Joose, it's easy to write a JooseX module to replace or extend a piece of built-in functionality.
Joose is a complete OO package in and of itself, and is part of a rich ecosystem of extensions. It also has an enthusiastic community of users, and is being actively maintained and developed.
Nickolay Platonov nickolay8@gmail.com
Copyright (c) 2008-2011, Malte Ubl, Nickolay Platonov
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.