Overview | File | Class | Tree | Index | Help
| The Gravey 2.5 Framework
PREV NEXT | FRAMES NO FRAMES

## grvClass.js

#### Summary

Collection of routines to emulate Java-like classes in JavaScript. A detailed explanation of the functionality of this file can be found in the AJAX from Scratch series of articles.
Version: 2.5
Requires:

- grvUtils.js (only for compile tracing)
- grvValidate.js (optional; only required if validating constructor args)

Author: Bruce Wallace (PolyGlotInc.com)

Method Summary
`static Function` | `Class( <Function> theClass, <StringArray> optConstructorArgDescArray )` Declare a class and create the glue objects and code to allow "pretty" source; A mechanism is set up to insure that required constructor parameters each have a defined value; This function also defines the "name" attribute of the specified class and initializes it with the class name.
`static Function` | `grvExtends( <Function> superClass )` This utility function takes (via "THIS") a "class" and (re)sets its superClass.
`static String` | `grvFuncName(<Function> f)` This function returns the name of a given function; It does this by using a regular expression to extract the function name from the function source code.

    // This file uses JSDoc-friendly comments [ http://jsdoc.sourceforge.net/ ]

    /**
     * @file         grvClass.js
     * @fileoverview Collection of routines to emulate Java-like classes in JavaScript.
     * A detailed explanation of the functionality of this file can
     * be found in the <a target="_blank"
     * href="http://www.polyglotinc.com/AJAXscratch/Class">AJAX from Scratch</a>
     * series of articles.
     *
     * @author       Bruce Wallace  (PolyGlotInc.com)
     * @version      2.5
     * @requires     grvUtils.js (only for compile tracing)
     * @requires     grvValidate.js (optional; only required if validating constructor args)
     */

    //////////////////////////////////////////////////////////////////
    // GRAVEY LEXICAL CODING CONVENTIONS:
    // (*) All private variables or functions start with "_"
    // (*) All variables and functions start with a lowercase letter
    // (*) All Classes start with an uppercase letter
    // (*) All Class methods and instance variables start with lowercase
    // (*) All Class "static" methods and variables start with uppercase
    // (*) All constants start with "k"
    // (*) All global variables start with "g"
    // (*) All event handler functions start with "on"
    //
    // (*) All Gravey utility global variables start with "gGrv"
    // (*) All Gravey MVC     global variables start with "gMVC"
    // (*) All Gravey EDO     global variables start with "gEDO"
    // (*) All Gravey utility functions start with "grv"
    // (*) All Gravey MVC     functions start with "mvc"
    // (*) All Gravey MVC event handler functions start with "onMVC"
    // (*) All Gravey EDO event handler functions start with "onEDO"
    // (*) All Gravey MVC classes start with "MVC"
    // (*) All Gravey EDO classes start with "EDO"
    //////////////////////////////////////////////////////////////////

    grvTraceCmp("grvClass.js: Begin");

    /**
     * This function returns the name of a given function; It does this by
     * using a regular expression to extract the function name from the
     * function source code.
     * @param {Function} f reference to a function
     * @return name of given function
     * @type String
     * @author Bruce Wallace (PolyGlotInc.com)
     * @version 2.0
     */
    function grvFuncName(f)
    {
    	var s = f.toString().match(/function\s*(\S*)\s*\(/)[1];
    	return s ? s : "anonymous";
    }

    Class(GrvObject);
    /**
     * @class This is the root class for all "classes" implemented
     * via the {@link GLOBALS#Class} function (ala Java "Object").
     * Class replaces the normal Javascript "constructor" function
     * with a new wrapper function that implements a robust
     * inheritence mechanism.
     * This mechanism supports "pretty" source code whereby
     * "methods" are declared inline, but the source code of
     * those methods are not copied into every object instance
     * as would otherwise be the case.<p>
     * The wrapper function also sets up a real "constructor"
     * that can use {@link GLOBALS#grvValidateArgs} to insure
     * that the required parameters are passed to it, throwing
     * an exception if not.<p>
     * The design pattern implemented by Class/Extends corrects
     * several problems that occur with the naive inheritence
     * mechanisms often used with Javascript.
     *<pre>
     *  The required coding convention for "GrvObject":
     *  (1) the "class" is declared via the utility
     *      function {@link GLOBALS#Class}
     *  (2) the "superclass" (if any) is declared via the
     *      .Extends method {@link GLOBALS#grvExtends}
     *  (3) the "constructor" logic for the class is placed
     *      in a "method" named "konstructor"
     *  (4) the konstructor method invokes the "super" constructor
     *      via its class name [rather than literally "super()"]
     *</pre>
     * @throws grvMissingArgException thrown by constructor wrapper
     * @see GLOBALS#Class
     * @see GLOBALS#grvExtends
     * @author Bruce Wallace  (PolyGlotInc.com)
     * @version 2.0
     */
    function GrvObject()
    {
    	/** Invokes the "super" version of whatever method that is calling souper.
    	 * @return either the return value of the super method or null if no super exists
    	 */
    	this.souper = function() {
        var superMethod = this.souper.caller.souper;
    		return (superMethod) ? superMethod.apply( this, arguments ) : null;
    	}
    }

    /**
     * This utility function takes (via "THIS") a "class" and
     * (re)sets its superClass.
     * THIS VERSION SETS UP "super" ACCESS TO OVERRIDDEN METHODS.
     * @param {Function} superClass the "superclass constructor" function
     * @return a reference to the "class object"
     * @type Function
     * @see #Class
     * @see GrvObject
     * @author Bruce Wallace  (PolyGlotInc.com)
     * @version 2.0
     */
    function grvExtends( superClass )
    {
    	///////////////////////////////////////////////////////////////////
    	// NOTE: At this point superClass should have already had its own
    	// Class and Extends calls performed. I.E. "declare" superclasses
    	// BEFORE those classes that extend them.
    	///////////////////////////////////////////////////////////////////
    	if (!superClass.baseClass) throw "Undeclared Super Class in .Extends";

    	//get superclass exemplar but avoid infinite recursion on implied root class
    	var superexemplar = (this==GrvObject) ? null
    					  : (superClass ? superClass.prototype : null);

    	//Recall that one can't change the exemplar.__proto__ property directly
    	//SO, one must create a new exemplar instance after baseClass.prototype is set.
    	this.baseClass.prototype = superexemplar;
    	var exemplar = new this.baseClass();

    	//for each method in exemplar, if there is a different method with the
    	//same name in superexemplar, setup the .souper link between them.
    	var s,m;
    	if (superexemplar)
    	  for (var property in exemplar)// iterate over all properties
    	  {
        	m =      exemplar[property];
        	s = superexemplar[property];

    		if (s && (s!=m) && (m instanceof Function) && (s instanceof Function))
    		  m.souper = s;
    	  }

    	//Note that it would normally be a problem if Extends were called after
    	//someone has already created an instance of "this" class (via new).
    	//However, that situation should never occur since all the calls to Class()
    	//and Extends() are normally done at web page load time, and application
    	//logic should only start after the page "onload" event, hence all these
    	//exemplars should be stable.
    	this.prototype             = exemplar;
    	this.prototype.name        = this.cname;//default value

    	// while "souper" works with konstructor, some may still prefer to
    	// use the superclass name explicitly when invoking its constructor
    	// so we leave this in to continue support for that.
    	this.prototype[this.cname] = this.prototype.konstructor;
    	return this;
    }

    /**
     * Declare a class and create the glue objects and code
     * to allow "pretty" source; A mechanism is set up to insure
     * that required constructor parameters each have a defined value;
     * This function also defines the "name" attribute of the specified
     * class and initializes it with the class name.
     * @param {Function} theClass the "class constructor" function
     * @param {StringArray} optConstructorArgDescArray optional array
     * of strings describing required parameters for this class'
     * "constructor"; Note: Optional constructor parameters should
     * not be included in this array.
     * @return the "class object" (an extended Function object)
     * @type Function
     * @see #Extends
     * @see #grvValidateArgs
     * @see GrvObject
     * @author Bruce Wallace  (PolyGlotInc.com)
     * @version 2.0
     */
    function Class( theClass, optConstructorArgDescArray )
    {
    	// The "class" as passed in will really be an abstract base class. We
    	// will squirrel that away and replace theClass with a wrapper function
    	// so that method source code is not copied into each object instance
    	// as would otherwise be the case.
    	var baseClass = theClass;

    	// create the new wrapper function to replace theClass
    	var  className  = grvFuncName( theClass );
    	self[className] = theClass = function(){
    		var C = arguments.callee;
    		if (C.required && self["grvValidateArgs"]!==void 0)
    		  grvValidateArgs( C.cname, C.required, arguments );
    		C.prototype.konstructor.apply( this, arguments );
    	}
    	theClass.required  = optConstructorArgDescArray;
    	theClass.cname     = className;//FYI,netscape&firefox break with ".name"
    	theClass.baseClass = baseClass;
    	theClass.Extends   = grvExtends;	//so we can call grvExtends as a method
    	return theClass.Extends(GrvObject);	//required here even if overridden later
    }

    grvTraceCmp("grvClass.js: End");

Overview | File | Class | Tree | Index | Help
| The Gravey 2.5 Framework
PREV NEXT | FRAMES NO FRAMES

Documentation generated by JSDoc on Thu Jan 6 12:47:09 2011