jsolait core functionality
jsolait exposes a number of global objects to the script environment. The number of global objects has been limited to a minimum.
module construction
Module(name, version, scope) is a function to create module objects. It is called with exactly 3 parameters.
- name - The name of the module.
- version - The version of the module.
- scope - A function which is called when Module creates a new module object.
When called, Module creates a new object with some preset properties:
- name - The name specified (see above).
- version - The version specified (see above).
- __sourceURI__ - If the module is loaded using jsolait's import functionality it will contain the URI form which the source code for the module was loaded. Otherwise it will be undefined
- Exception - A module specific exception class. All exceptions raised inside the module should inherit from this class.
In the next step Module calls the scope function with exactly one parameter usually called mod. This represents the module's public interface. If running the module scope fails Module will raise a Module.ModuleScopeExecFailed exception. Once the scope is run successfully the new module object will be registered with jsolait for import functionality. As last action Module iterates over all public objects and sets the __name__ property for all methods and classes.
For jsolait's import functionality to work the name of a module should be the same as its file name without the extension.
module exceptions
Each module has its own exception class (i.e. mod.Exception(msg, trace)). All Exceptions thrown inside a module should inherit from this class. Its constructor expects exactly 2 parameters:
- msg - The message for the exception being raised.
- trace - The exception/error that caused the exception to be raised or null if no error is present.
Each instance of an exception will have the following properties:
- module - The module the exception was raised in.
- message- The error message.
- trace - The causing exception/error.
The idea is that a caught exception might be rethrown depending on the circumstances as a new exception. The new exception will contain a link to the caught exception, thus creating a trace of errors. For example import() throws an jsolait.ImportFailed exception because it could not load the required module. Maybe it could not get the modules source so the causing error for jsoalit.ImportFailed will be a jsolait.LoadURIFailed exception. This causing error is saved in the trace object of the jsolait.ImportFailed object. If properly followed through with this way of exception handling it is possible to easily find out what went wrong in a call without having to use a debugger which provides stack traces and such.
You can easily see a string representation of an exception trace using e.g. alert(e) in a catch statement.
module import functionality
Modules can be imported using imprt(moduleName). jsolait will first check if the module is already loaded and return it if it is. If the module is not yet loaded jsolait will look into the modules it already knows about. I.e. it checks if it can find the module name in the jsolait.knownModuleURIs map. If it finds a match it will create a URL based on the jsolait.baseURI and the information found in the jsolait.knownModuleURIs map. It will then try load the that URL. If loading that URL fails it will iterate through the jsolait.moduleSearchURIs and create URLs by appending each search URI with the module name replacing all '.' with '/' and appending '.js' at the end. If a URL was loaded successfully then its content will be evaluated. If that content contains a module the Module function will register it with jsolait. If no errors occurred so far jsolait will use the module name to look up the registered module and return it. In case any errors occurred a jsolait.ImportFailed exception will be raised containing information about all URLs which were tried to load the module from.
For the import functionality to load module files on demand jsolait needs access to a synchronous HTTP connection. It will first look for Mozilla's XMLHttpRequest() (also available in Opera and Safari and compatible browsers). If it cannot find it it will try IE's XMLHTTP objects. After that it will fail and an Exception is thrown.
In case your target platform does not provide any of the above HTTP connection objects you will need to include the module files and all dependent files in your HTML file using script tags. Make sure the order is correct and no dependencies are unresolved.
class construction
Class([name], [base1, ...], scope) is used to create classes in jsolait. Classes created with jsolait are very much the same as 'normal JavaScript?' classes. There are some optional arguments:
- name - The name of the class. This is not needed if the class is a public property of a module.
- base1, ... - The base classes the new class inherits from.
If now base class is specified then Object is used as the only base class. To create a new class Class first creates a new prototype which is used for JavaScript?'s prototyping mechanism. It will look at the first(most left hand) base class and check if it has a __createProto__ method. If so it will use it to create an object. If not it will just create an instance of the base class passing Class as a first parameter to let the base class know it is used for prototyping. Class will then iterate over all base classes and extend the prototype with any new objects found in the base class prototype. It will also extend the new class' class members the same way. Then the scope is run with the following parameters:
- publ - The public interface of the new class (i.e. the class' prototype)
- priv - A string containing a class-unique id which can be used to store private/protected objects in an instance object.
- supr, ... - All following parameters are the public interfaces of the base classes (i.e. the base classes prototypes) which can be used to call methods of base classes.
Once the scope is run successfully a constructor function for the new class is created. Depending on if the new class inherits from Array, implements the __call__ method or is just a plain class different constructors are used to optimize construction performance. The prototype of the constructor is set using the prototype created and all class members are applied. The class constructor is then returned.
The common functionality of the class constructor is to check whether or not it was called for prototyping, i.e. the first parameter passed to the constructor is Class in case of prototyping or if it is called for object construction. In the first case nothing special happens. In the second case a private object is added to the new instance (using the id stored in priv) and then the __init__ method of the new instance is called if it exists to let the new instance initialize itself.
For classes inheriting from Array the constructor actually creates a new Array, copies all public members to the new object and returns it. For classes having a __call__ method the constructor creates a new function which will call the __call__ method, copies all public members to the new function and returns it.
other global objects
Besides Module, Class and imprt jsolait's core script exposes a number of other global objects.
- bind(thisObject, fn) - Returns a function which calls fn with the this - object always being the thisObject
- hash(obj) - Returns a unique ID for an object (see __hash__()).
- isinstance(obj, class) - Returns true if obj is an instance of class or a direct or indirect subclass thereof. false otherwise.
- issubclass(class1, class2) - Returns true if class1 is a direct or indirect subclass of class2. false otherwise. A class is always a subclass of itself.
- jsolait - The jsolait module object.
- str(obj) - Returns a string representation of the object passed in.
- repr(obj) - Returns a string representation of the object which can be evaluated using eval. This works similar to python's repr() function. Currently it returns a JSON - compatible string for objects. repr() will return a custom value from the object's __repr__() method if the object provides that method.
Although it is discouraged, other modules may expose additional global objects. See their documentation for more information.
special object properties and methods
jsolait adds a number of special properties to classes and objects to implement certain features. In some cases it also extends existing classes (e.g. String::format()).
To be compatible with other frameworks, jsolait and its modules will never extend the Object class, i.e. any object created using new Object() or the shorthand {} will be empty objects containing no additional properties.
All jsolait specific objects will be named using a python-like notation __foo__. This way the likelihood of name conflicts is lowered.
All classes created by jsolait will contain the following class-members:
- __name__ - The name of the class.
- __bases__ - An Array containing the base classes for the class.
- __id__ - A unique number identifying the class.
- __hash__() - A function which will return the class' __id__
- __str__() - A function returning a string representation of the class.
- __isArray__ - Used internally to check if a class is an Array or not.
All objects created from a class will contain the following instance-members:
- __class__ - Points to the constructor of the object.
- __hash__() - A function returning the object's __id__ property, generating it if it does not exist.
- __id__ - A unique ID for the object. This property only exists after __hash__ been called at least once.
- __str__() - A function returning a string representation of the object. Can be overwritten by subclasses.
There are other names used which have special meaning to jsolait and its modules.
- __call__ - Any class adding a function with that name to its public interfaces marks the class as callable. A special constructor is used for these classes which creates a function object which if called calls that __call__ function. This is similar to python's __call__ interface.
- __createProto__ - Any object implementing this function will be able to hook into the prototyping implementation of jsolait.
Some modules also use special names to implement certain features. E.g. the iter module expects iterable objects to implement an __iter__ method. The operators module implements python's operators module functionality expecting objects to implement functions like __eq__, __neq__, .... See the module's documentation for more information.
string formatting
Python's string formating operator % or the similar sprintf() found in C/C++ is a nice feature for formating strings. jsolait implements string formating by extending the String class with a format() method. You can pretty much use it the same way python uses the % operator.
String::format(value1,[value2, ...]) formats a string replacing formatting specifiers with values provided as arguments which are formatted according to the specifier. Each string can contain any number of formatting specifiers which are replaced with the formated values.
A formatting specifier looks as follows: "%[(key)][flag][sign][min][precision]typeOfValue"
[...] are optional.
- (key) If specified the first argument is treated as an object/associative array and the formating values are retrieved from that object using the key.
- flag:
0 Use zeros for padding.
- Left justify result, padding it with spaces.
(a space) Use spaces for padding.
- sign:
+ Numeric values will contain a positive or negative sign in front of the number. - min:
l The string will be padded with the padding character until it has a minimum length of l. - precision:
.x Where x is the precision for floating point numbers and the length for 0 padding for integers. - typeOfValue:
d Signed integer decimal.
i Signed integer decimal.
b Unsigned binary. This does not exist in python.
o Unsigned octal.
u Unsigned decimal.
x Unsigned hexadecimal (lowercase).
X Unsigned hexadecimal (uppercase).
e Floating point exponential format (lowercase).
E Floating point exponential format (uppercase).
f Floating point decimal format.
F Floating point decimal format.
c Single character (accepts byte or single character string).
s String (converts any object using object.toString()).
Examples:
"%02d".format(8) == "08" "%05.2f".format(1.234) == "01.23" "123 in binary is: %08b".format(123) == "123 in binary is: 01111011"
