diff --git a/lib/class.js b/lib/class.js index 139ab71..c692b3b 100644 --- a/lib/class.js +++ b/lib/class.js @@ -23,27 +23,7 @@ */ var util = require( __dirname + '/util' ), - class_builder = require( __dirname + '/class_builder' ), - member_builder = require( __dirname + '/member_builder' ), - propobj = require( __dirname + '/propobj' ) -; - - -/* - * IE contains a nasty enumeration "bug" (poor implementation) that makes - * toString unenumerable. This means that, if you do obj.toString = foo, - * toString will NOT show up in `for` or hasOwnProperty(). This is a problem. - * - * This test will determine if this poor implementation exists. - */ -var enum_bug = ( - Object.prototype.propertyIsEnumerable.call( - { toString: function() {} }, - 'toString' - ) === false - ) - ? true - : false + class_builder = require( __dirname + '/class_builder' ) ; @@ -131,7 +111,7 @@ module.exports.isClass = function( obj ) { obj = obj || {}; - return ( obj.prototype instanceof Class ) + return ( obj.prototype instanceof class_builder.ClassBase ) ? true : false ; @@ -151,7 +131,7 @@ module.exports.isClassInstance = function( obj ) { obj = obj || {}; - return ( obj instanceof Class ) + return ( obj instanceof class_builder.ClassBase ) ? true : false; }; @@ -170,42 +150,7 @@ module.exports.isClassInstance = function( obj ) * * @return {boolean} true if instance is an instance of type, otherwise false */ -module.exports.isInstanceOf = function( type, instance ) -{ - var meta, implemented, i; - - try - { - // check prototype chain (with throw an error if type is not a - // constructor (function) - if ( instance instanceof type ) - { - return true; - } - } - catch ( e ) {} - - // if no metadata is available, then our remaining checks cannot be - // performed - if ( !instance.__cid || !( meta = getMeta( instance ) ) ) - { - return false; - } - - implemented = meta.implemented; - i = implemented.length; - - // check implemented interfaces - while ( i-- ) - { - if ( implemented[ i ] === type ) - { - return true; - } - } - - return false; -}; +module.exports.isInstanceOf = class_builder.isInstanceOf; /** @@ -218,14 +163,6 @@ module.exports.isInstanceOf = function( type, instance ) module.exports.isA = module.exports.isInstanceOf; -/** - * Default class implementation - * - * @return undefined - */ -function Class() {}; - - /** * Creates a new anonymous Class from the given class definition * @@ -402,227 +339,36 @@ function createImplement( base, ifaces, cname ) /** - * Creates extend function + * Mimics class inheritance * - * The 'extending' parameter is used to override the functionality of abstract - * class constructors, allowing them to be instantiated for use in a subclass's - * prototype. + * This method will mimic inheritance by setting up the prototype with the + * provided base class (or, by default, Class) and copying the additional + * properties atop of it. * - * @param {boolean} extending whether a class is currently being extended + * The class to inherit from (the first argument) is optional. If omitted, the + * first argument will be considered to be the properties list. * - * @return {Function} extend function + * @return {Object} extended class */ -var extend = ( function( extending ) +function extend() { - var class_id = 0, - instance_id = 0; + // set up the new class + var data = class_builder.build.apply( null, arguments ), - /** - * Mimics class inheritance - * - * This method will mimic inheritance by setting up the prototype with the - * provided base class (or, by default, Class) and copying the additional - * properties atop of it. - * - * The class to inherit from (the first argument) is optional. If omitted, the - * first argument will be considered to be the properties list. - * - * @return {Object} extended class - */ - return function extend() - { - // ensure we'll be permitted to instantiate abstract classes for the base - extending = true; + new_class = data[ 'class' ], + abstract_methods = data.abstractMethods, + class_id = data.classId + ; - var args = Array.prototype.slice.call( arguments ), - props = args.pop() || {}, - base = args.pop() || Class, - prototype = new base(), - cname = '', + // important: call after setting prototype + setupProps( new_class, abstract_methods, class_id ); - properties = {}, - prop_init = member_builder.initMembers(), - members = member_builder.initMembers( prototype ), + // lock down the new class (if supported) to ensure that we can't add + // members at runtime + util.freeze( new_class ); - abstract_methods = - util.clone( getMeta( base ).abstractMethods ) - || { __length: 0 } - ; - - // grab the name, if one was provided - if ( cname = props.__name ) - { - // we no longer need it - delete props.__name; - } - - // IE has problems with toString() - if ( enum_bug ) - { - if ( props.toString !== Object.prototype.toString ) - { - props.__toString = props.toString; - } - } - - // increment class identifier - class_id++; - - // build the various class components (xxx: this is temporary; needs - // refactoring) - class_builder.build( props, - class_id, - base, - prop_init, - abstract_methods, - properties, - members, - getMethodInstance - ); - - // reference to the parent prototype (for more experienced users) - prototype.___$$parent$$ = base.prototype; - - // set up the new class - var new_class = createCtor( cname, abstract_methods, members ); - - attachPropInit( prototype, prop_init, members, class_id ); - - new_class.prototype = prototype; - new_class.constructor = new_class; - new_class.___$$props$$ = prop_init; - new_class.___$$methods$$ = members; - - // important: call after setting prototype - setupProps( new_class, abstract_methods, class_id ); - - // create internal metadata for the new class - var meta = createMeta( new_class, base ); - meta.abstractMethods = abstract_methods; - meta.name = cname; - - // lock down the new class (if supported) to ensure that we can't add - // members at runtime - util.freeze( new_class ); - - // we're done with the extension process - extending = false; - - return new_class; - }; - - - /** - * Creates the constructor for a new class - * - * This constructor will call the __constructor method for concrete classes - * and throw an exception for abstract classes (to prevent instantiation). - * - * @param {string} cname class name (may be empty) - * @param {Array.} abstract_methods list of abstract methods - * @param {Object} members class members - * - * @return {Function} constructor - */ - function createCtor( cname, abstract_methods, members ) - { - // concrete class - if ( abstract_methods.__length === 0 ) - { - var args = null; - - // constructor function to be returned - var __self = function() - { - if ( !( this instanceof __self ) ) - { - // store arguments to be passed to constructor and - // instantiate new object - args = arguments; - return new __self(); - } - - // generate and store unique instance id - attachInstanceId( this, ++instance_id, __self ); - - initInstance( instance_id, this ); - this.__initProps(); - - // call the constructor, if one was provided - if ( this.__construct instanceof Function ) - { - // note that since 'this' refers to the new class (even - // subtypes), and since we're using apply with 'this', the - // constructor will be applied to subtypes without a problem - this.__construct.apply( this, ( args || arguments ) ); - args = null; - } - - // attach any instance properties/methods (done after - // constructor to ensure they are not overridden) - attachInstanceOf( this ); - - // Provide a more intuitive string representation of the class - // instance. If a toString() method was already supplied for us, - // use that one instead. - if ( !( Object.prototype.hasOwnProperty.call( - members[ 'public' ], 'toString' - ) ) ) - { - // use __toString if available (see enum_bug), otherwise use - // our own defaults - this.toString = members[ 'public' ].__toString - || ( ( cname ) - ? function() - { - return '#<' + cname + '>'; - } - : function() - { - return '#'; - } - ) - ; - } - }; - - // provide a more intuitive string representation - __self.toString = ( cname ) - ? function() { return cname; } - : function() { return '(Class)'; } - ; - - return __self; - } - // abstract class - else - { - var __abstract_self = function() - { - if ( !extending ) - { - throw Error( - "Abstract class " + ( cname || '(anonymous)' ) + - " cannot be instantiated" - ); - } - }; - - __abstract_self.toString = ( cname ) - ? function() - { - return cname; - } - : function() - { - return '(AbstractClass)'; - } - ; - - return __abstract_self; - } - } -} )( false ); + return new_class; +} /** @@ -664,7 +410,7 @@ var implement = function() // create a new class with the implemented abstract methods var class_new = module.exports.extend( base, dest ); - getMeta( class_new ).implemented = implemented; + class_builder.getMeta( class_new ).implemented = implemented; return class_new; } @@ -688,98 +434,6 @@ function setupProps( func, abstract_methods, class_id ) } -/** - * Initializes class instance - * - * This process will create the instance visibility object containing private - * and protected members. The class instance is part of the prototype chain. - * This will be passed to all methods when invoked, permitting them to access - * the private and protected members while keeping them encapsulated. - * - * For each instance, there is always a base. The base will contain a proxy to - * the public members on the instance itself. The base will also contain all - * protected members. - * - * Atop the base object is a private member object, with the base as its - * prototype. There exists a private member object for the instance itself and - * one for each supertype. This is stored by the class id (cid) as the key. This - * permits the private member object associated with the class of the method - * call to be bound to that method. For example, if a parent method is called, - * that call must be invoked in the context of the parent, so the private - * members of the parent must be made available. - * - * The resulting structure looks something like this: - * class_instance = { iid: { cid: {} } } - * - * @param {number} iid instance id - * @param {Object} instance instance to initialize - * - * @return {undefined} - */ -function initInstance( iid, instance ) -{ - var prot = function() {}; - prot.prototype = instance; - - // add the visibility objects to the data object for this class instance - instance.___$$vis$$ = new prot(); -} - - -/** - * Attaches __initProps() method to the class prototype - * - * The __initProps() method will initialize class properties for that instance, - * ensuring that their data is not shared with other instances (this is not a - * problem with primitive data types). - * - * The method will also initialize any parent properties (recursive) to ensure - * that subtypes do not have a referencing issue, and subtype properties take - * precedence over those of the parent. - * - * @param {Object} prototype prototype to attach method to - * @param {Object} properties properties to initialize - * @param {number} cid class id - * - * @param {{public: Object, protected: Object, private: Object}} members - * - * @return {undefined} - */ -function attachPropInit( prototype, properties, members, cid ) -{ - util.defineSecureProp( prototype, '__initProps', function( inherit ) - { - // defaults to false, sid = super identifier - inherit = !!inherit; - - var iid = this.__iid; - - // first initialize the parent's properties, so that ours will overwrite - // them - var parent_init = prototype.___$$parent$$.__initProps; - if ( parent_init instanceof Function ) - { - // call the parent prop_init, letting it know that it's been - // inherited so that it does not initialize private members or - // perform other unnecessary tasks - parent_init.call( this, true ); - } - - // this will return our property proxy, if supported by our environment, - // otherwise just a normal object with everything merged in - var inst_props = propobj.createPropProxy( - this, this.___$$vis$$, properties[ 'public' ] - ); - - // if we're inheriting, perform a setup that doesn't include everything - // that we don't want (e.g. private properties) - this.___$$vis$$[ cid ] = propobj.setup( - inst_props, properties, members - ); - }); -} - - /** * Attaches isAbstract() method to the class * @@ -870,116 +524,3 @@ function attachId( func, id ) util.defineSecureProp( func.prototype, '__cid', id ); } - -/** - * Attaches an instance identifier to a class instance - * - * @param {Object} instance class instance - * @param {number} iid instance id - * - * @return {undefined} - */ -function attachInstanceId( instance, iid ) -{ - util.defineSecureProp( instance, '__iid', iid ); -} - - -/** - * Attaches partially applied isInstanceOf() method to class instance - * - * @param {Object} instance class instance to attach method to - * - * @return {undefined} - */ -function attachInstanceOf( instance ) -{ - var method = function( type ) - { - return module.exports.isInstanceOf( type, instance ); - }; - - util.defineSecureProp( instance, 'isInstanceOf', method ); - util.defineSecureProp( instance, 'isA', method ); -} - - -/** - * Initializes class metadata for the given class - * - * @param {Class} func class to initialize metadata for - * @param {Class} cparent class parent - * - * @return {undefined} - */ -function createMeta( func, cparent ) -{ - var id = func.__cid, - parent_meta = ( ( cparent.__cid ) ? getMeta( cparent ) : undefined ); - - // copy the parent prototype's metadata if it exists (inherit metadata) - if ( parent_meta ) - { - func.___$$meta$$ = util.clone( parent_meta, true ); - } - else - { - // create empty - func.___$$meta$$ = { - implemented: [], - }; - } - - // store the metadata in the prototype as well (inconsiderable overhead; - // it's just a reference) - func.prototype.___$$meta$$ = func.___$$meta$$; - - return func.___$$meta$$; -} - - -/** - * Returns reference to metadata for the requested class - * - * Since a reference is returned (rather than a copy), the returned object can - * be modified to alter the metadata. - * - * @param {Class} cls class from which to retrieve metadata - * - * @return {Object} - */ -function getMeta( cls ) -{ - return cls.___$$meta$$ || {}; -} - - -/** - * Returns the instance object associated with the given method - * - * The instance object contains the protected members. This object can be passed - * as the context when calling a method in order to give that method access to - * those members. - * - * One level above the instance object on the prototype chain is the object - * containing the private members. This is swappable, depending on the class id - * associated with the provided method call. This allows methods that were not - * overridden by the subtype to continue to use the private members of the - * supertype. - * - * @param {function()} inst instance that the method is being called from - * @param {number} cid class id - * - * @return {Object,null} instance object if found, otherwise null - */ -function getMethodInstance( inst, cid ) -{ - var iid = inst.__iid, - data = inst.___$$vis$$; - - return ( iid && data ) - ? data[ cid ] - : null - ; -} - diff --git a/lib/class_builder.js b/lib/class_builder.js index d982647..0ec04fe 100644 --- a/lib/class_builder.js +++ b/lib/class_builder.js @@ -23,11 +23,257 @@ */ var util = require( __dirname + '/util' ), - member_builder = require( __dirname + '/member_builder' ) + member_builder = require( __dirname + '/member_builder' ), + propobj = require( __dirname + '/propobj' ), + + /** + * Class id counter, to be increment on each new definition + * @type {number} + */ + class_id = 0, + + /** + * Instance id counter, to be incremented on each new instance + * @type {number} + */ + instance_id = 0 ; -exports.build = function( +/** + * IE contains a nasty enumeration "bug" (poor implementation) that makes + * toString unenumerable. This means that, if you do obj.toString = foo, + * toString will NOT show up in `for` or hasOwnProperty(). This is a problem. + * + * This test will determine if this poor implementation exists. + */ +var enum_bug = ( + Object.prototype.propertyIsEnumerable.call( + { toString: function() {} }, + 'toString' + ) === false + ) + ? true + : false +; + + +/** + * Default class implementation + * + * @return undefined + */ +exports.ClassBase = function Class() {}; + + +exports.build = ( function( extending ) +{ + /** + * Mimics class inheritance + * + * This method will mimic inheritance by setting up the prototype with the + * provided base class (or, by default, Class) and copying the additional + * properties atop of it. + * + * The class to inherit from (the first argument) is optional. If omitted, the + * first argument will be considered to be the properties list. + * + * @return {Object} extended class + */ + return function extend() + { + // ensure we'll be permitted to instantiate abstract classes for the base + extending = true; + + var args = Array.prototype.slice.call( arguments ), + props = args.pop() || {}, + base = args.pop() || exports.ClassBase, + prototype = new base(), + cname = '', + + properties = {}, + prop_init = member_builder.initMembers(), + members = member_builder.initMembers( prototype ), + + abstract_methods = + util.clone( exports.getMeta( base ).abstractMethods ) + || { __length: 0 } + ; + + // grab the name, if one was provided + if ( cname = props.__name ) + { + // we no longer need it + delete props.__name; + } + + // IE has problems with toString() + if ( enum_bug ) + { + if ( props.toString !== Object.prototype.toString ) + { + props.__toString = props.toString; + } + } + + // increment class identifier + class_id++; + + // build the various class components (xxx: this is temporary; needs + // refactoring) + buildMembers( props, + class_id, + base, + prop_init, + abstract_methods, + properties, + members, + getMethodInstance + ); + + // reference to the parent prototype (for more experienced users) + prototype.___$$parent$$ = base.prototype; + + // set up the new class + var new_class = createCtor( cname, abstract_methods, members ); + + attachPropInit( prototype, prop_init, members, class_id ); + + new_class.prototype = prototype; + new_class.constructor = new_class; + new_class.___$$props$$ = prop_init; + new_class.___$$methods$$ = members; + + // create internal metadata for the new class + var meta = createMeta( new_class, base ); + meta.abstractMethods = abstract_methods; + meta.name = cname; + + // we're done with the extension process + extending = false; + + return { + 'class': new_class, + abstractMethods: abstract_methods, + classId: class_id, + }; + }; + + + /** + * Creates the constructor for a new class + * + * This constructor will call the __constructor method for concrete classes + * and throw an exception for abstract classes (to prevent instantiation). + * + * @param {string} cname class name (may be empty) + * @param {Array.} abstract_methods list of abstract methods + * @param {Object} members class members + * + * @return {Function} constructor + */ + function createCtor( cname, abstract_methods, members ) + { + // concrete class + if ( abstract_methods.__length === 0 ) + { + var args = null; + + // constructor function to be returned + var __self = function() + { + if ( !( this instanceof __self ) ) + { + // store arguments to be passed to constructor and + // instantiate new object + args = arguments; + return new __self(); + } + + // generate and store unique instance id + attachInstanceId( this, ++instance_id, __self ); + + initInstance( instance_id, this ); + this.__initProps(); + + // call the constructor, if one was provided + if ( this.__construct instanceof Function ) + { + // note that since 'this' refers to the new class (even + // subtypes), and since we're using apply with 'this', the + // constructor will be applied to subtypes without a problem + this.__construct.apply( this, ( args || arguments ) ); + args = null; + } + + // attach any instance properties/methods (done after + // constructor to ensure they are not overridden) + attachInstanceOf( this ); + + // Provide a more intuitive string representation of the class + // instance. If a toString() method was already supplied for us, + // use that one instead. + if ( !( Object.prototype.hasOwnProperty.call( + members[ 'public' ], 'toString' + ) ) ) + { + // use __toString if available (see enum_bug), otherwise use + // our own defaults + this.toString = members[ 'public' ].__toString + || ( ( cname ) + ? function() + { + return '#<' + cname + '>'; + } + : function() + { + return '#'; + } + ) + ; + } + }; + + // provide a more intuitive string representation + __self.toString = ( cname ) + ? function() { return cname; } + : function() { return '(Class)'; } + ; + + return __self; + } + // abstract class + else + { + var __abstract_self = function() + { + if ( !extending ) + { + throw Error( + "Abstract class " + ( cname || '(anonymous)' ) + + " cannot be instantiated" + ); + } + }; + + __abstract_self.toString = ( cname ) + ? function() + { + return cname; + } + : function() + { + return '(AbstractClass)'; + } + ; + + return __abstract_self; + } + } +} )( false ); + + +function buildMembers( props, class_id, base, prop_init, abstract_methods, properties, members, getMethodInstance ) @@ -118,4 +364,264 @@ exports.build = function( } }, } ); +} + + +/** + * Attaches __initProps() method to the class prototype + * + * The __initProps() method will initialize class properties for that instance, + * ensuring that their data is not shared with other instances (this is not a + * problem with primitive data types). + * + * The method will also initialize any parent properties (recursive) to ensure + * that subtypes do not have a referencing issue, and subtype properties take + * precedence over those of the parent. + * + * @param {Object} prototype prototype to attach method to + * @param {Object} properties properties to initialize + * @param {number} cid class id + * + * @param {{public: Object, protected: Object, private: Object}} members + * + * @return {undefined} + */ +function attachPropInit( prototype, properties, members, cid ) +{ + util.defineSecureProp( prototype, '__initProps', function( inherit ) + { + // defaults to false, sid = super identifier + inherit = !!inherit; + + var iid = this.__iid; + + // first initialize the parent's properties, so that ours will overwrite + // them + var parent_init = prototype.___$$parent$$.__initProps; + if ( parent_init instanceof Function ) + { + // call the parent prop_init, letting it know that it's been + // inherited so that it does not initialize private members or + // perform other unnecessary tasks + parent_init.call( this, true ); + } + + // this will return our property proxy, if supported by our environment, + // otherwise just a normal object with everything merged in + var inst_props = propobj.createPropProxy( + this, this.___$$vis$$, properties[ 'public' ] + ); + + // if we're inheriting, perform a setup that doesn't include everything + // that we don't want (e.g. private properties) + this.___$$vis$$[ cid ] = propobj.setup( + inst_props, properties, members + ); + }); +} + + +/** + * Initializes class metadata for the given class + * + * @param {Class} func class to initialize metadata for + * @param {Class} cparent class parent + * + * @return {undefined} + */ +function createMeta( func, cparent ) +{ + var id = func.__cid, + parent_meta = ( ( cparent.__cid ) + ? exports.getMeta( cparent ) + : undefined + ); + + // copy the parent prototype's metadata if it exists (inherit metadata) + if ( parent_meta ) + { + func.___$$meta$$ = util.clone( parent_meta, true ); + } + else + { + // create empty + func.___$$meta$$ = { + implemented: [], + }; + } + + // store the metadata in the prototype as well (inconsiderable overhead; + // it's just a reference) + func.prototype.___$$meta$$ = func.___$$meta$$; + + return func.___$$meta$$; +} + + +/** + * Returns reference to metadata for the requested class + * + * Since a reference is returned (rather than a copy), the returned object can + * be modified to alter the metadata. + * + * @param {Class} cls class from which to retrieve metadata + * + * @return {Object} + */ +exports.getMeta = function( cls ) +{ + return cls.___$$meta$$ || {}; +} + + +/** + * Attaches an instance identifier to a class instance + * + * @param {Object} instance class instance + * @param {number} iid instance id + * + * @return {undefined} + */ +function attachInstanceId( instance, iid ) +{ + util.defineSecureProp( instance, '__iid', iid ); +} + + +/** + * Initializes class instance + * + * This process will create the instance visibility object containing private + * and protected members. The class instance is part of the prototype chain. + * This will be passed to all methods when invoked, permitting them to access + * the private and protected members while keeping them encapsulated. + * + * For each instance, there is always a base. The base will contain a proxy to + * the public members on the instance itself. The base will also contain all + * protected members. + * + * Atop the base object is a private member object, with the base as its + * prototype. There exists a private member object for the instance itself and + * one for each supertype. This is stored by the class id (cid) as the key. This + * permits the private member object associated with the class of the method + * call to be bound to that method. For example, if a parent method is called, + * that call must be invoked in the context of the parent, so the private + * members of the parent must be made available. + * + * The resulting structure looks something like this: + * class_instance = { iid: { cid: {} } } + * + * @param {number} iid instance id + * @param {Object} instance instance to initialize + * + * @return {undefined} + */ +function initInstance( iid, instance ) +{ + var prot = function() {}; + prot.prototype = instance; + + // add the visibility objects to the data object for this class instance + instance.___$$vis$$ = new prot(); +} + + +/** + * Attaches partially applied isInstanceOf() method to class instance + * + * @param {Object} instance class instance to attach method to + * + * @return {undefined} + */ +function attachInstanceOf( instance ) +{ + var method = function( type ) + { + return module.exports.isInstanceOf( type, instance ); + }; + + util.defineSecureProp( instance, 'isInstanceOf', method ); + util.defineSecureProp( instance, 'isA', method ); +} + + +/** + * Returns the instance object associated with the given method + * + * The instance object contains the protected members. This object can be passed + * as the context when calling a method in order to give that method access to + * those members. + * + * One level above the instance object on the prototype chain is the object + * containing the private members. This is swappable, depending on the class id + * associated with the provided method call. This allows methods that were not + * overridden by the subtype to continue to use the private members of the + * supertype. + * + * @param {function()} inst instance that the method is being called from + * @param {number} cid class id + * + * @return {Object,null} instance object if found, otherwise null + */ +function getMethodInstance( inst, cid ) +{ + var iid = inst.__iid, + data = inst.___$$vis$$; + + return ( iid && data ) + ? data[ cid ] + : null + ; +} + + +/** + * Determines if the class is an instance of the given type + * + * The given type can be a class, interface, trait or any other type of object. + * It may be used in place of the 'instanceof' operator and contains additional + * enhancements that the operator is unable to provide due to prototypal + * restrictions. + * + * @param {Object} type expected type + * @param {Object} instance instance to check + * + * @return {boolean} true if instance is an instance of type, otherwise false + */ +exports.isInstanceOf = function( type, instance ) +{ + var meta, implemented, i; + + try + { + // check prototype chain (with throw an error if type is not a + // constructor (function) + if ( instance instanceof type ) + { + return true; + } + } + catch ( e ) {} + + // if no metadata is available, then our remaining checks cannot be + // performed + if ( !instance.__cid || !( meta = exports.getMeta( instance ) ) ) + { + return false; + } + + implemented = meta.implemented; + i = implemented.length; + + // check implemented interfaces + while ( i-- ) + { + if ( implemented[ i ] === type ) + { + return true; + } + } + + return false; }; + diff --git a/tools/combine b/tools/combine index 61df457..609192f 100755 --- a/tools/combine +++ b/tools/combine @@ -28,7 +28,7 @@ TPL_VAR='/**{CONTENT}**/' RMTRAIL="$PATH_TOOLS/rmtrail" # order matters -CAT_MODULES="prop_parser util member_builder class_builder propobj" +CAT_MODULES="prop_parser util propobj member_builder class_builder" CAT_MODULES="$CAT_MODULES class interface" ##