Changeset 85 for trunk/jsolait

Show
Ignore:
Timestamp:
12/21/06 12:17:13 (2 years ago)
Author:
Jan-Klaas Kollhof
Message:

moving experimental branch to the trunk

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk

    • Property svn:ignore set to
      build
  • trunk/jsolait/jsolait.js

    r61 r85  
    11/* 
    2     Copyright (c) 2003-2005 Jan-Klaas Kollhof 
     2    Copyright (c) 2003-2006 Jan-Klaas Kollhof 
    33 
    44    This file is part of the JavaScript O Lait library(jsolait). 
     
    2424 
    2525    @author Jan-Klaas Kollhof 
    26     @version 2.0 
     26    @version 3.0 
    2727    @lastchangedby $LastChangedBy$ 
    2828    @lastchangeddate $Date$ 
     
    3030**/ 
    3131 
    32  
    33 /** 
    34     Creates a new class object which inherits from superClass. 
    35     @param name="anonymous"  The name of the new class. 
    36                                             If the created class is a public member of a module then 
    37                                             the __name__ property of that class is automatically set by Module(). 
    38     @param base1 *                  The base classes (not an array but one argument per base class). 
    39     @param classScope(-1)        A function which is executed for class construction. 
    40                                             As 1st parameter it will get the new class' protptype for 
    41                                             overrideing or extending the super class. As 2nd parameter it will get 
    42                                             the super class' wrapper for calling inherited methods. 
    43 **/ 
    44 Class=function(name, base1, classScope){ 
    45     var args=[]; 
    46     for(var i=0;i<arguments.length;i++){ 
    47         args[i] = arguments[i]; 
     32jsolait=(function(mod){ 
     33     
     34    mod.__name__='jsolait'; 
     35     
     36    mod.__version__="$Revision$"; 
     37     
     38    mod.__str__ =function(){ 
     39        return "[module '%s' version: %s]".format(this.__name__, (this.__version__+'').replace(/\$Revision:\s(\d+) \$/, "Rev.$1")); 
     40    }; 
     41    mod.toString=mod.__str__; 
     42     
     43    ///The location where jsolait is installed. 
     44    mod.baseURI="./jsolait"; 
     45     
     46    try{// to guess the location where jsolait is installed 
     47        var elems=document.getElementsByTagName('script'); 
     48        for(var i=0;i<elems.length;i++){ 
     49            var src=elems[i].getAttribute('src'); 
     50            var idx=src.indexOf('jsolait.js'); 
     51            if(idx>0){ 
     52                mod.baseURI=src.slice(0,idx-1); 
     53                break; 
     54            } 
     55        } 
     56    }catch(e){ 
    4857    } 
    4958 
    50     classScope = args.pop(); 
    51     var classID =  Class.__idcount__++; 
    52  
    53     if((args.length>0) && (typeof args[0] =='string')){ 
    54         name=args.shift(); 
    55     }else{ 
    56         name="anonymous" + classID; 
    57     } 
    58  
    59     var bases = args; 
    60  
    61     //set up the 'public static' fields of the class 
    62     var __class__={__isArray__ : false, 
    63                          __name__ : name, 
    64                          __bases__: bases, 
    65                          __id__: '@' + classID, 
    66                          __str__ : function(){ 
    67                             return "[class %s]".format(this.__name__); 
    68                          } 
    69                     }; 
    70  
    71     var baseProtos=[];//stores the prototypes of all the base classes 
    72     var proto; //the prototype to use for the new class 
    73     if(bases.length==0){//use Object as base 
    74         proto={}; 
    75         proto.__str__ = function(){ 
    76             return "[%s %s]".format(this.__class__.prototype.__call__ === undefined ? 'object' : 'callable', this.__class__.__name__); 
    77         }; 
    78         __class__.__bases__=[Object]; 
    79     }else{ //inherit from all base classes 
    80         var baseProto; 
    81         for(var i=0;i<bases.length;i++){ 
    82             var baseClass = bases[i]; 
    83             //remember the base prototypes 
    84             baseProtos.push(baseClass.prototype); 
    85             if(baseClass.__createProto__ !== undefined){ 
    86                 baseProto = baseClass.__createProto__(bases); 
    87             }else{ 
    88                 baseProto = new baseClass(Class); 
    89             } 
    90             __class__.__isArray__ = __class__.__isArray__ || baseClass.__isArray__; 
    91  
    92             if(i==0){//for the first base class just use it's proto as the final proto 
    93                 proto = baseProto; 
    94             }else{//for all others extend(do not overwrite) the final proto with the properties in the baseProto 
    95                 for(var key in baseProto){ 
    96                     if(proto[key] === undefined){ 
    97                         proto[key] = baseProto[key]; 
    98                     } 
    99                 } 
    100             } 
    101             //extend the new class' static interface 
    102             //todo: any props that should not be copied 
    103             for(var key in baseClass){ 
    104                 if((key != 'prototype') && (__class__[key] === undefined)){ 
    105                     __class__[key] = baseClass[key]; 
    106                 } 
    107             } 
    108         } 
    109     } 
    110     //make sure all jsolait objects have a id method 
    111     if(proto.__id__ === undefined){ 
    112         proto.__id__=function(){ 
    113             this.__id__ = '@' + (Class.__idcount__++); 
    114             return this.__id__; 
    115         }; 
    116     } 
    117     proto.__class__=__class__; 
    118  
    119     //run the class setup function provided as classScope 
    120     if(classScope.length-1 > baseProtos.length){ 
    121         var privId = '__priv__' + __class__.__id__; 
    122         classScope.apply(this,[proto, privId].concat(baseProtos)); 
    123     }else{ 
    124         classScope.apply(this,[proto].concat(baseProtos)); 
    125     } 
    126      
    127     //make sure the toString points to __str__, this will make overwriting __str__ after object construction impossible (todo ?) 
    128     //but will be faster than having toString call __str__, also overwriting methods unless they are ment to be overridden is not cool anyways. 
    129     proto.toString=proto.__str__; 
    130          
    131     //allthough a single constructor would suffice for generating normal objects, Arrays and callables, 
    132     //we use 3 different ones. This will minimize the code inside the constructor and therefore 
    133     //minimize object construction time 
    134     if(proto.__call__){ 
    135         //if the callable interface is implemented we need a class constructor 
    136         //which generates a function upon construction 
    137         var NewClass = function(calledBy){ 
    138             if(calledBy !== Class){ 
    139                 var rslt = function(){ 
    140                     return rslt.__call__.apply(rslt, arguments); 
    141                 }; 
    142                  
    143                 //this will only work for the current class but not create any priv objects for any base class  
    144                 var proto=arguments.callee.prototype; 
    145                 for(var n in proto){ 
    146                     rslt[n] = proto[n]; 
    147                 } 
    148                 rslt.constructor = proto.__class__; 
    149                 rslt.toString = proto.__str__; 
    150                 if(rslt.__init__){ 
    151                     rslt.__init__.apply(rslt, arguments); 
    152                 } 
    153                 return rslt; 
    154             } 
    155         }; 
    156     }else if(__class__.__isArray__){ 
    157         //Since we cannot inherit from Array directly we take the same approach as with the callable above 
    158         //and just have a constructor which creates an Array 
    159         var NewClass = function(calledBy){ 
    160             if(calledBy !== Class){ 
    161                 rslt=[]; 
    162  
    163                 var proto=arguments.callee.prototype; 
    164                 for(var n in proto){ 
    165                     rslt[n] = proto[n]; 
    166                 } 
    167                 rslt.constructor = proto.__class__; 
    168                 rslt.toString = proto.__str__; 
    169                 if(rslt.__init__){ 
    170                     rslt.__init__.apply(rslt, arguments); 
    171                 }else{//implement Array's default behavior 
    172                     if(arguments.length==1){ 
    173                         rslt.length=arguments[0]; 
    174                     }else{ 
    175                         for(var i=0;i<arguments.length;i++){ 
    176                             rslt.push(arguments[i]); 
    177                         } 
    178                     } 
    179                 } 
    180                 return rslt; 
    181             } 
    182         };  
    183     }else{ 
    184         //this is a 'normal' object constructor which does nothing but call the __init__ method 
    185         //unless it does not exsit or the constructor was used for prototyping 
    186         var NewClass = function(calledBy){ 
    187             if(calledBy !== Class){ 
    188                 if(this.__init__){ 
    189                     this.__init__.apply(this, arguments); 
    190                 } 
    191             } 
    192         }; 
    193     } 
    194  
    195     //reset the constructor for new objects to the actual constructor. 
    196     proto.constructor = NewClass; 
    197     proto.__class__= NewClass;//no, it is not needed, just like __str__ is not, but it is nicer than constructor 
    198          
    199     //this is where the inheritance realy happens 
    200     NewClass.prototype = proto; 
    201  
    202     //apply all the static fileds 
    203     for(var key in __class__){ 
    204         NewClass[key] = __class__[key]; 
    205     } 
    206     NewClass.toString=__class__.__str__; 
    207  
    208     return NewClass; 
    209 }; 
    210 Class.__idcount__=0; 
    211 Class.__str__=Class.toString = function(){return "[object Class]";}; 
    212 Class.__createProto__=function(){ throw "Can't use Class as a base class.";}; 
    213  
    214 Function.__createProto__ = function(){ throw "Cannot inherit from Function. implement the callable interface instead using YourClass::__call__.";}; 
    215 Array.__createProto__=function(){ var r =[]; r.__str__ = Array.prototype.toString;  return r; }; 
    216 Array.__isArray__=true; 
    217 Array.__str__=Array.toString=function(){return "[class Array]";}; 
    218 Object.__str__=Object.toString=function(){return "[class Object]";}; 
    219 Number.__str__ =Number.toString=function(){return "[class Number]";}; 
    220 String.__str__ =String.toString=function(){return "[class String]";}; 
    221  
    222 /** 
    223     Returns a string representation of an object. 
    224     @param obj  The object to return a string repr. of. 
    225     @return A string repr. the object. 
    226 **/ 
    227 str = String; 
    228  
    229 /** 
    230     Return a String containing a printable representation of an object which can be used with eval() to create an equal object. 
    231     Objects can cosutumize the the value being returned by repr(obj) by providing a obj.__repr__() method which is called by repr(obj). 
    232     @param obj  The object to create a repr. String from. 
    233     @return A representation of the object. 
    234 **/ 
    235 repr = function(obj){ 
    236     if(obj == null){ 
    237         return null; 
    238     }else if(obj.__repr__){ 
    239         return obj.__repr__(); 
    240     }else{ 
    241         switch(typeof obj){ 
    242             case "string": 
    243                 obj = obj.replace(/\\/g,"\\\\").replace(/\"/g,"\\\"").replace(/\n/g, "\\n").replace(/\r/g,"\\r"); 
    244                 return '"' + obj + '"'; 
    245             case "boolean":case"number": 
    246                 return "" + obj; 
    247             case "object": 
    248                 var out = []; 
    249                 if(obj == null){ 
    250                     return "null"; 
    251                 }else if(obj instanceof Array){ 
    252                     for(var i=0;i<obj.length;i++){ 
    253                         out.push(repr(obj[i])); 
    254                     } 
    255                     return "[" + out.join(",") + "]"; 
    256                 }else if(obj instanceof Object){ 
    257                     for(var key in obj){ 
    258                         out.push(repr(key) + ":" + repr(obj[key])); 
    259                     } 
    260                     return "{" + out.join(",") + "}"; 
    261                 } 
    262         } 
    263     } 
    264 }; 
    265  
    266 /** 
    267     Returns a unique id for an object. 
    268     The same object will always return the same id.  
    269     Most objects are id-able. The following steps are taken to find an id. 
    270     If the obj has an __id__ property that id will be returned. (all jsolait classes have an __id__ property) 
    271     If the obj has a __id__ method the return value of that method will be returned.(all jsolait objects have a __id__ method which sets an __id__ property) 
    272     If the obj is a String  the string prefixed with $ is returned. 
    273     If the obj is a Number the number prefixed with a # is returned as a string. 
    274     All other objects are not safely id-able and an exception is thrown unless forceId is true. In that case the object will get a unique __id__ property applied which is returned. 
    275      
    276     @param obj The object to get the id for. 
    277     @param forceId=false if true it forces id() to set an __id__ property onto a non id-able object, making it id-able. 
    278     @return A String containing a id value for the obj. 
    279 **/ 
    280 id = function(obj, forceId){ 
    281     switch(typeof obj.__id__){ 
    282          
    283         case "undefined": 
    284             if(obj instanceof String || typeof obj == 'string'){ 
    285                 return '$' + obj; 
    286             }else if(obj instanceof Number || typeof obj == 'number'){ 
    287                 return '#' + obj; 
    288             }else if(forceId){ 
    289                 obj.__id__ = '@' + (Class.__idcount__++); 
    290                 return obj.__id__; 
    291             }else{ 
    292                 throw new jsolait.Exception('Objec cannot be IDed: %s'.format(obj)); 
    293             } 
    294          
    295         case "function": 
    296             return obj.__id__(); 
    297          
    298         default: //string 
    299             return obj.__id__; 
    300     } 
    301 }; 
    302  
    303 /** 
    304     Returns a bound method. 
    305     A bound method is a function which is bound to a specific object. 
    306     Calling the bound method will call the given function with the this-object inside that function's scope being the object specified. 
    307      
    308     @param obj  The object the function should be bound to. 
    309     @param fn   A function object the obj will be bound to. 
    310     @return A method which when run executes the function with the this-object being the obj specified. 
    311 **/ 
    312 bind = function(obj, fn){ 
    313     return function(){ 
    314         return fn.apply(obj, arguments); 
    315     }; 
    316 }; 
    317  
    318 /** 
    319     Returns if an object is an instance of a specified class or of a direct or indirect subclass thereof. 
    320      
    321     It also works for traditional javascript inheritance(i.e. SomeClass=function(){}; SomeClass.prototype=new SuperClass(); ...). 
    322     Internaly it first checks using instanceof if that fails it uses isinstance(obj.constructor, cls). 
    323     There are some differences between using isinstance and instanceof. 
    324     i.e.  
    325     (123 instanceof Number) == false; 
    326     isinstance(123, Number) == true; 
    327     ('abc' instanceof String) == false; 
    328     isinstance('abc', String) == true; 
    329         
    330     @param obj   The object to test. 
    331     @param cls     The class to test against. 
    332     @return True if the object is an instance of cls. False otherwise. 
    333 **/ 
    334 isinstance=function(obj, cls){ 
    335     if(obj instanceof cls){ 
    336         return true; 
    337     }else{ 
    338         return issubclass(obj.constructor, cls); 
    339     } 
    340 }; 
    341  
    342 /** 
    343     Returns if a cls is a direct or indirect subclass of another. 
    344      
    345     A class is always a subclass of itself and Object is the base for all classes. 
    346     A class is a subclass of baseclass if it's prototype is an instance of baseclass. 
    347     A class is a subclass of baseclass if any of it's __bases__ is a subclass of baseclass. 
    348     If there are no __bases__ defined there is no way to findout about inheritance besides  
    349     the prototype chain which was checked by instanceof before, so false is returned. 
    350      
    351     @param cls  The class to test. 
    352     @param baseclass  The assumed superclass. 
    353     @return True if cls is a subclass of baseclass otherwise false. 
    354 **/ 
    355 issubclass=function(cls, baseclass){ 
    356     if(baseclass === Object || cls===baseclass || (cls.prototype instanceof baseclass)){ 
    357         return true; 
    358     }else{ 
    359         var bases = cls.__bases__; 
    360         if(bases != null){ 
    361             for(var i=0;i<bases.length;i++){ 
    362                 if(bases[i] === baseclass){ 
    363                     return true; 
    364                 } 
    365             } 
    366             for(var i=0;i<bases.length;i++){ 
    367                 if(issubclass(bases[i], baseclass)){ 
    368                     return true; 
    369                 } 
    370             } 
    371         } 
    372         return false; 
    373     } 
    374 }; 
    375  
    376  
    377 /** 
    378     Creates a new module and registers it. 
    379     @param name              The name of the module. 
    380     @param version            The version of a module. 
    381     @param moduleScope    A function which is executed for module creation. 
    382                                      As 1st parameter it will get the module variable. 
    383                                      The imported modules(imports) will be passed to the moduleScope starting with the 2nd parameter. 
    384 **/ 
    385 Module=function(name, version, moduleScope){ 
    386     var newMod = new Module.ModuleClass(name, version, Module.currentURI); 
    387      
    388     try{//to execute the scope of the module 
    389         moduleScope.call(newMod, newMod); 
    390     }catch(e){ 
    391         throw new Module.ModuleScopeExecFailed(newMod, e); 
    392     } 
    393      
    394     //set __name__  for methods and classes 
    395     for(var n in newMod){ 
    396         var obj = newMod[n]; 
    397         if(typeof obj == 'function'){ 
    398             obj.__name__ = n; 
    399         } 
    400     } 
    401      
    402     jsolait.registerModule(newMod); 
    403     return newMod; 
    404 }; 
    405  
    406 Module.ModuleClass=Class(function(publ){ 
    407     publ.name; 
    408     publ.version; 
    409     publ.__sourceURI__; 
    410     publ.Exception; 
    411      
    412     publ.__init__=function(name,version,sourceURI){ 
    413         this.name=name; 
    414         this.version=version; 
    415         this.__sourceURI__ = sourceURI; 
    416         this.Exception = Class(Module.Exception, function(){}); 
    417         this.Exception.prototype.module = this; 
    418     }; 
    419      
    420     publ.__str__=function(){ 
    421         //todo:SVN adaption 
    422         return "[module '%s' version: %s]".format(this.name, (this.version+'').replace(/\$Revision:\s(\d+) \$/, "rev.$1")); 
    423     }; 
    424 }); 
    425  
    426  
    427 Module.toString=function(){ 
    428     return "[object Module]"; 
    429 }; 
    430  
    431 Module.__createProto__=function(){ 
    432     throw "Can't use Module as a base class."; 
    433 }; 
    434  
    435  
    436 /** 
    437     Base class for all module-Exceptions. 
    438     This class should not be instaciated directly but rather 
    439     use the exception that is part of the module. 
    440 **/ 
    441 Module.Exception=Class("Exception", function(publ){ 
    442     /** 
    443         Initializes a new Exception. 
    444         @param msg           The error message for the user. 
    445         @param trace=undefined  The error causing this Exception if available. 
    446     **/ 
    447     publ.__init__=function(msg, trace){ 
    448         this.name = this.constructor.__name__; 
    449         this.message = ''+msg; 
    450         this.trace = trace; 
    451     }; 
    452  
    453     publ.__str__=function(){ 
    454         return this.toTraceString(); 
    455     }; 
    456      
    457     /** 
    458         Returns the complete trace of the exception. 
    459         @param indent=0  The indention to use for each line. 
    460         @return The error trace. 
    461     **/ 
    462     publ.toTraceString=function(indent){ 
    463         indent = indent==null ? 0 : indent; 
    464  
    465         //todo:use  constructor.__name__? 
    466         var s="%s in %s:\n%s".format(this.name, this.module, this.message.indent(4)).indent(indent); 
    467         if(this.trace){ 
    468             if(this.trace.toTraceString){ 
    469                 s+=('\n\nbecause:\n'+ this.trace.toTraceString(indent + 4)); 
    470             }else{ 
    471                 s+=(this.trace +'\n').indent(indent+4); 
    472             } 
    473         } 
    474         return s; 
    475     }; 
    476  
    477     ///The name of the Exception. 
    478     publ.name;//todo is that needed? 
    479     ///The error message. 
    480     publ.message; 
    481     ///The module the Exception belongs to. 
    482     publ.module="jsolait"; 
    483     ///The error which caused the Exception or undefined. 
    484     publ.trace; 
    485 }); 
    486  
    487 /** 
    488     Thrown if a module scope could not be run. 
    489 **/ 
    490 Module.ModuleScopeExecFailed=Class("ModuleScopeExecFailed", Module.Exception, function(publ, supr){ 
    491     /** 
    492         Initializes a new ModuleScopeExecFailed Exception. 
    493         @param module      The module. 
    494         @param trace      The error cousing this Exception. 
    495     **/ 
    496     publ.__init__=function(module, trace){ 
    497         supr.__init__.call(this, "Failed to run the module scope for %s".format(module), trace); 
    498         this.failedModule = module; 
    499     }; 
    500     ///The module that could not be createed. 
    501     publ.module; 
    502 }); 
    503  
    504  
    505 /** 
    506  
    507     @author                 Jan-Klaas Kollhof 
    508     @lastchangedby       $LastChangedBy$ 
    509     @lastchangeddate    $Date$ 
    510 **/ 
    511 Module("jsolait", "$Revision$", function(mod){ 
    512     jsolait=mod; 
    513      
    514     mod.modules={}; 
    515  
    516     ///The paths of  the modules that come with jsolait. 
     59    ///The paths to the modules that come with jsolait. 
    51760    //do not edit the following lines, it will be replaced by the build script 
    518     /*@moduleURIs begin*/ 
    519     mod.knownModuleURIs={"codecs":"%(baseURI)s/lib/codecs.js", 
    520                                         "crypto":"%(baseURI)s/lib/crypto.js", 
    521                                         "dom":"%(baseURI)s/lib/dom.js", 
    522                                         "forms":"%(baseURI)s/lib/forms.js", 
    523                                         "iter":"%(baseURI)s/lib/iter.js", 
    524                                         "jsonrpc":"%(baseURI)s/lib/jsonrpc.js", 
    525                                         "lang":"%(baseURI)s/lib/lang.js", 
    526                                         "net":"%(baseURI)s/lib/net", 
    527                                         "sets":"%(baseURI)s/lib/sets.js", 
    528                                         "testing":"%(baseURI)s/lib/testing.js", 
    529                                         "urllib":"%(baseURI)s/lib/urllib.js", 
    530                                         "xml":"%(baseURI)s/lib/xml.js", 
    531                                         "xmlrpc":"%(baseURI)s/lib/xmlrpc.js"}; 
    532     /*@moduleURIs end*/ 
    533  
     61    /*@moduleSourceURIs begin*/ 
     62    mod.moduleSourceURIs={}; 
     63    /*@moduleSourceURIs end*/ 
    53464     
    53565    /** 
     
    53868        they may contain StringFormating symbols e.g '%(baseURI)s/lib' 
    53969    **/ 
    540     mod.moduleSearchURIs = ["."]; 
    541  
    542     ///The location where jsolait is installed. 
    543     //do not edit the following lines, it will be replaced by the build script 
    544     /*@baseURI begin*/ 
    545     mod.baseURI="./jsolait"; 
    546     /*@baseURI end*/ 
    547      
     70    mod.moduleSearchURIs = [".", "%(baseURI)s/lib"]; 
     71    
    54872    mod.packagesURI = "%(baseURI)s/packages"; 
    54973     
     74    mod.modules={}; 
     75  
     76    /** 
     77        Returns a string representation of an object. 
     78        @param obj  The object to return a string repr. of. 
     79        @return A string repr. the object. 
     80    **/ 
     81    var str = String; 
     82 
     83    /** 
     84        Return a String containing a printable representation of an object which can be used with eval() to create an equal object. 
     85        Objects can cosutumize the the value being returned by repr(obj) by providing a obj.__repr__() method which is called by repr(obj). 
     86        @param obj  The object to create a repr. String from. 
     87        @return A representation of the object. 
     88    **/ 
     89    var repr = function(obj){ 
     90        if(obj == null){ 
     91            return null; 
     92        }else if(obj.__repr__){ 
     93            return obj.__repr__(); 
     94        }else{ 
     95            switch(typeof obj){ 
     96                case "string": 
     97                    obj = obj.replace(/\\/g,"\\\\").replace(/\"/g,"\\\"").replace(/\n/g, "\\n").replace(/\r/g,"\\r"); 
     98                    return '"' + obj + '"'; 
     99                case "boolean":case"number": 
     100                    return "" + obj; 
     101                case "object": 
     102                    var out = []; 
     103                    if(obj == null){ 
     104                        return "null"; 
     105                    }else if(obj instanceof Array){ 
     106                        for(var i=0;i<obj.length;i++){ 
     107                            out.push(repr(obj[i])); 
     108                        } 
     109                        return "[" + out.join(",") + "]"; 
     110                    }else if(obj instanceof Object){ 
     111                        for(var key in obj){ 
     112                            out.push(repr(key) + ":" + repr(obj[key])); 
     113                        } 
     114                        return "{" + out.join(",") + "}"; 
     115                    } 
     116            } 
     117        } 
     118    }; 
     119 
     120    /** 
     121        Returns a unique id for an object. 
     122        The same object will always return the same id.  
     123        Most objects are id-able. The following steps are taken to find an id. 
     124        If the obj has an __id__ property that id will be returned. (all jsolait classes have an __id__ property) 
     125        If the obj has a __id__ method the return value of that method will be returned.(all jsolait objects have a __id__ method which sets an __id__ property) 
     126        If the obj is a String  the string prefixed with $ is returned. 
     127        If the obj is a Number the number prefixed with a # is returned as a string. 
     128        All other objects are not safely id-able and an exception is thrown unless forceId is true. In that case the object will get a unique __id__ property applied which is returned. 
     129         
     130        @param obj The object to get the id for. 
     131        @param forceId=false if true it forces id() to set an __id__ property onto a non id-able object, making it id-able. 
     132        @return A String containing a id value for the obj. 
     133    **/ 
     134    var id = function(obj, forceId){ 
     135        switch(typeof obj.__id__){ 
     136             
     137            case "undefined": 
     138                if(obj instanceof String || typeof obj == 'string'){ 
     139                    return '$' + obj; 
     140                }else if(obj instanceof Number || typeof obj == 'number'){ 
     141                    return '#' + obj; 
     142                }else if(forceId){ 
     143                    obj.__id__ = '@' + (Class.__idcount__++); 
     144                    return obj.__id__; 
     145                }else{ 
     146                    throw new mod.Exception('Objec cannot be IDed: %s'.format(obj)); 
     147                } 
     148             
     149            case "function": 
     150                return obj.__id__(); 
     151             
     152            default: //string 
     153                return obj.__id__; 
     154        } 
     155    }; 
     156 
     157    /** 
     158        Returns a bound method. 
     159        A bound method is a function which is bound to a specific object. 
     160        Calling the bound method will call the given function with the this-object inside that function's scope being the object specified. 
     161         
     162        @param obj  The object the function should be bound to. 
     163        @param fn   A function object the obj will be bound to. 
     164        @return A method which when run executes the function with the this-object being the obj specified. 
     165    **/ 
     166    var bind = function(obj, fn){ 
     167        return function(){ 
     168            return fn.apply(obj, arguments); 
     169        }; 
     170    }; 
     171 
     172    /** 
     173        Returns if an object is an instance of a specified class or of a direct or indirect subclass thereof. 
     174         
     175        It also works for traditional javascript inheritance(i.e. SomeClass=function(){}; SomeClass.prototype=new SuperClass(); ...). 
     176        Internaly it first checks using instanceof if that fails it uses isinstance(obj.constructor, cls). 
     177        There are some differences between using isinstance and instanceof. 
     178        i.e.  
     179        (123 instanceof Number) == false; 
     180        isinstance(123, Number) == true; 
     181        ('abc' instanceof String) == false; 
     182        isinstance('abc', String) == true; 
     183            
     184        @param obj   The object to test. 
     185        @param cls     The class to test against. 
     186        @return True if the object is an instance of cls. False otherwise. 
     187    **/ 
     188    var isinstance=function(obj, cls){ 
     189        if(obj instanceof cls){ 
     190            return true; 
     191        }else{ 
     192            return issubclass(obj.constructor, cls); 
     193        } 
     194    }; 
     195 
     196    /** 
     197        Returns if a cls is a direct or indirect subclass of another. 
     198         
     199        A class is always a subclass of itself and Object is the base for all classes. 
     200        A class is a subclass of baseclass if it's prototype is an instance of baseclass. 
     201        A class is a subclass of baseclass if any of it's __bases__ is a subclass of baseclass. 
     202        If there are no __bases__ defined there is no way to findout about inheritance besides  
     203        the prototype chain which was checked by instanceof before, so false is returned. 
     204         
     205        @param cls  The class to test. 
     206        @param baseclass  The assumed superclass. 
     207        @return True if cls is a subclass of baseclass otherwise false. 
     208    **/ 
     209    var issubclass=function(cls, baseclass){ 
     210        if(baseclass === Object || cls===baseclass || (cls.prototype instanceof baseclass)){ 
     211            return true; 
     212        }else{ 
     213            var bases = cls.__bases__; 
     214            if(bases != null){ 
     215                for(var i=0;i<bases.length;i++){ 
     216                    if(bases[i] === baseclass){ 
     217                        return true; 
     218                    } 
     219                } 
     220                for(var i=0;i<bases.length;i++){ 
     221                    if(issubclass(bases[i], baseclass)){ 
     222                        return true; 
     223                    } 
     224                } 
     225            } 
     226            return false; 
     227        } 
     228    }; 
     229     
     230    /** 
     231        Creates a new class object which inherits from superClass. 
     232        @param name="anonymous"  The name of the new class. 
     233                                                If the created class is a public member of a module then 
     234                                                the __name__ property of that class is automatically set by Module(). 
     235        @param base1 *                  The base classes (not an array but one argument per base class). 
     236        @param classScope(-1)        A function which is executed for class construction. 
     237                                                As 1st parameter it will get the new class' protptype for 
     238                                                overrideing or extending the super class. As 2nd parameter it will get 
     239                                                the super class' wrapper for calling inherited methods. 
     240    **/ 
     241    var Class=function(name, base1, classScope){ 
     242        var args=[]; 
     243        for(var i=0;i<arguments.length;i++){ 
     244            args[i] = arguments[i]; 
     245        } 
     246 
     247        classScope = args.pop(); 
     248        var classID =  Class.__idcount__++; 
     249 
     250        if((args.length>0) && (typeof args[0] =='string')){ 
     251            name=args.shift(); 
     252        }else{ 
     253            name="anonymous" + classID; 
     254        } 
     255 
     256        var bases = args; 
     257 
     258        //set up the 'public static' fields of the class 
     259        var __class__={__isArray__ : false, 
     260                             __name__ : name, 
     261                             __bases__: bases, 
     262                             __id__: '@' + classID, 
     263                             __str__ : function(){ 
     264                                return "[class %s]".format(this.__name__); 
     265                             }, 
     266                             __create__:function(initArgs){ 
     267                                var obj = new this(Class); 
     268                                if(obj.__init__){ 
     269                                    obj.__init__.apply(obj, initArgs); 
     270                                } 
     271                                return obj; 
     272                             } 
     273                        }; 
     274 
     275        var baseProtos=[];//stores the prototypes of all the base classes 
     276        var proto; //the prototype to use for the new class 
     277        if(bases.length==0){//use Object as base 
     278            proto={}; 
     279            proto.__str__ = function(){ 
     280                return "[%s %s]".format(this.__class__.prototype.__call__ === undefined ? 'object' : 'callable', this.__class__.__name__); 
     281            }; 
     282            __class__.__bases__=[Object]; 
     283        }else{ //inherit from all base classes 
     284            var baseProto; 
     285            for(var i=0;i<bases.length;i++){ 
     286                var baseClass = bases[i]; 
     287                //remember the base prototypes 
     288                baseProtos.push(baseClass.prototype); 
     289                if(baseClass.__createProto__ !== undefined){ 
     290                    baseProto = baseClass.__createProto__(bases); 
     291                }else{ 
     292                    baseProto = new baseClass(Class); 
     293                } 
     294                __class__.__isArray__ = __class__.__isArray__ || baseClass.__isArray__; 
     295 
     296                if(i==0){//for the first base class just use it's proto as the final proto 
     297                    proto = baseProto; 
     298                }else{//for all others extend(do not overwrite) the final proto with the properties in the baseProto 
     299                    for(var key in baseProto){ 
     300                        if(proto[key] === undefined){ 
     301                            proto[key] = baseProto[key]; 
     302                        } 
     303                    } 
     304                } 
     305                //extend the new class' static interface 
     306                //todo: any props that should not be copied 
     307                for(var key in baseClass){ 
     308                    if((key != 'prototype') && (__class__[key] === undefined)){ 
     309                        __class__[key] = baseClass[key]; 
     310                    } 
     311                } 
     312            } 
     313        } 
     314        //make sure all jsolait objects have an id method 
     315        if(proto.__id__ === undefined){ 
     316            proto.__id__=function(){ 
     317                this.__id__ = '@' + (Class.__idcount__++); 
     318                return this.__id__; 
     319            }; 
     320        } 
     321        proto.__class__=__class__; 
     322 
     323        //run the class setup function provided as classScope 
     324        var privId = '__priv__' + __class__.__id__; 
     325        classScope.apply(this,[proto, privId].concat(baseProtos)); 
     326         
     327        //make sure the toString points to __str__, this will make overwriting __str__ after object construction impossible (todo ?) 
     328        //but will be faster than having toString call __str__, also overwriting methods unless they are ment to be overridden is not cool anyways. 
     329        proto.toString=proto.__str__; 
     330             
     331        //allthough a single constructor would suffice for generating normal objects, Arrays and callables, 
     332        //we use 3 different ones. This will minimize the code inside the constructor and therefore 
     333        //minimize object construction time 
     334        if(proto.__call__){ 
     335            //if the callable interface is implemented we need a class constructor 
     336            //which generates a function upon construction 
     337            var NewClass = function(calledBy){ 
     338                if(calledBy !== Class){ 
     339                    var rslt = function(){ 
     340                        return rslt.__call__.apply(rslt, arguments); 
     341                    }; 
     342                     
     343                    //this will only work for the current class but not create any priv objects for any base class  
     344                    var proto=arguments.callee.prototype; 
     345                    for(var n in proto){ 
     346                        rslt[n] = proto[n]; 
     347                    } 
     348                    rslt.constructor = proto.__class__; 
     349                    rslt.toString = proto.__str__; 
     350                    if(rslt.__init__){ 
     351                        rslt.__init__.apply(rslt, arguments); 
     352                    } 
     353                    return rslt; 
     354                } 
     355            }; 
     356        }else if(__class__.__isArray__){ 
     357            //Since we cannot inherit from Array directly we take the same approach as with the callable above 
     358            //and just have a constructor which creates an Array 
     359            var NewClass = function(calledBy){ 
     360                if(calledBy !== Class){ 
     361                    rslt=[]; 
     362                    var proto=arguments.callee.prototype; 
     363                    for(var n in proto){ 
     364                        rslt[n] = proto[n]; 
     365                    } 
     366                    rslt.constructor = proto.__class__; 
     367                    rslt.toString = proto.__str__; 
     368                    if(rslt.__init__){ 
     369                        rslt.__init__.apply(rslt, arguments); 
     370                    }else{//implement Array's default behavior 
     371                        if(arguments.length==1){ 
     372                            rslt.length=arguments[0]; 
     373                        }else{ 
     374                            for(var i=0;i<arguments.length;i++){ 
     375                                rslt.push(arguments[i]); 
     376                            } 
     377                        } 
     378                    } 
     379                    return rslt; 
     380                } 
     381            };  
     382        }else{ 
     383            //this is a 'normal' object constructor which does nothing but call the __init__ method 
     384            //unless it does not exsit or the constructor was used for prototyping 
     385            var NewClass = function(calledBy){ 
     386                if(calledBy !== Class){ 
     387                    if(this.__init__){ 
     388                        this.__init__.apply(this, arguments); 
     389                    } 
     390                } 
     391            }; 
     392        } 
     393 
     394        //reset the constructor for new objects to the actual constructor. 
     395        proto.constructor = NewClass; 
     396        proto.__class__= NewClass;//no, it is not needed, just like __str__ is not, but it is nicer than constructor 
     397             
     398        //this is where the inheritance realy happens 
     399        NewClass.prototype = proto; 
     400 
     401        //apply all the static fileds 
     402        for(var key in __class__){ 
     403            NewClass[key] = __class__[key]; 
     404        } 
     405        NewClass.toString=__class__.__str__; 
     406 
     407        return NewClass; 
     408    }; 
     409    Class.__idcount__=0; 
     410    Class.__str__=Class.toString = function(){return "[object Class]";}; 
     411    Class.__createProto__=function(){ throw "Can't use Class as a base class.";}; 
     412     
     413    mod.Class = Class; 
     414     
     415    Function.__createProto__ = function(){ throw "Cannot inherit from Function. implement the callable interface instead using YourClass::__ca