Refactored Traits to use propParse hooks
parent
3d47443046
commit
316a7dd703
|
@ -487,14 +487,47 @@ exports.prototype.buildMembers = function buildMembers(
|
||||||
virtual_members: memberdest['virtual'],
|
virtual_members: memberdest['virtual'],
|
||||||
};
|
};
|
||||||
|
|
||||||
util.propParse( props, {
|
// default member handlers for parser
|
||||||
|
var handlers = {
|
||||||
each: _parseEach,
|
each: _parseEach,
|
||||||
property: _parseProp,
|
property: _parseProp,
|
||||||
getset: _parseGetSet,
|
getset: _parseGetSet,
|
||||||
method: _parseMethod,
|
method: _parseMethod,
|
||||||
}, context );
|
};
|
||||||
|
|
||||||
// process accumulated member state
|
// a custom parser may be provided to hook the below property parser;
|
||||||
|
// this can be done to save time on post-processing, or alter the
|
||||||
|
// default behavior of the parser
|
||||||
|
if ( props.___$$parser$$ )
|
||||||
|
{
|
||||||
|
// this isn't something that we actually want to parse
|
||||||
|
var parser = props.___$$parser$$;
|
||||||
|
delete props.___$$parser$$;
|
||||||
|
|
||||||
|
function hjoin( name, orig )
|
||||||
|
{
|
||||||
|
handlers[ name ] = function()
|
||||||
|
{
|
||||||
|
var args = Array.prototype.slice.call( arguments );
|
||||||
|
|
||||||
|
// invoke the custom handler with the original handler as
|
||||||
|
// its last argument (which the custom handler may choose
|
||||||
|
// not to invoke at all)
|
||||||
|
args.push( orig );
|
||||||
|
parser[ name ].apply( context, args );
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// this avoids a performance penalty unless the above property is
|
||||||
|
// set
|
||||||
|
parser.each && hjoin( 'each', handlers.each );
|
||||||
|
parser.property && hjoin( 'property', handlers.property );
|
||||||
|
parser.getset && hjoin( 'getset', handlers.getset );
|
||||||
|
parser.method && hjoin( 'method', handlers.method );
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse members and process accumulated member state
|
||||||
|
util.propParse( props, handlers, context );
|
||||||
this._memberBuilder.end( context.state );
|
this._memberBuilder.end( context.state );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
63
lib/Trait.js
63
lib/Trait.js
|
@ -86,6 +86,12 @@ Trait.extend = function( dfn )
|
||||||
// just in case DFN does not contain any abstract members itself
|
// just in case DFN does not contain any abstract members itself
|
||||||
dfn[ 'abstract protected ___$$trait$$' ] = [];
|
dfn[ 'abstract protected ___$$trait$$' ] = [];
|
||||||
|
|
||||||
|
// augment the parser to handle our own oddities
|
||||||
|
dfn.___$$parser$$ = {
|
||||||
|
each: _parseMember,
|
||||||
|
property: _parseProps,
|
||||||
|
};
|
||||||
|
|
||||||
// give the abstract trait class a distinctive name for debugging
|
// give the abstract trait class a distinctive name for debugging
|
||||||
dfn.__name = '#AbstractTrait#';
|
dfn.__name = '#AbstractTrait#';
|
||||||
|
|
||||||
|
@ -112,16 +118,6 @@ Trait.extend = function( dfn )
|
||||||
return ''+name;
|
return ''+name;
|
||||||
};
|
};
|
||||||
|
|
||||||
// traits are not permitted to define constructors
|
|
||||||
if ( tclass.___$$methods$$['public'].__construct !== undefined )
|
|
||||||
{
|
|
||||||
throw Error( "Traits may not define __construct" );
|
|
||||||
}
|
|
||||||
|
|
||||||
// traits have property restrictions
|
|
||||||
validateProps( tclass.___$$props$$['public'] );
|
|
||||||
validateProps( tclass.___$$props$$['protected'] );
|
|
||||||
|
|
||||||
// invoked to trigger mixin
|
// invoked to trigger mixin
|
||||||
TraitType.__mixin = function( dfn, tc, base )
|
TraitType.__mixin = function( dfn, tc, base )
|
||||||
{
|
{
|
||||||
|
@ -138,30 +134,59 @@ Trait.extend = function( dfn )
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies trait member restrictions
|
||||||
|
*
|
||||||
|
* @param {string} name property name
|
||||||
|
* @param {*} value property value
|
||||||
|
* @param {Object} keywords property keywords
|
||||||
|
* @param {Function} h original handler that we replaced
|
||||||
|
*
|
||||||
|
* @return {undefined}
|
||||||
|
*/
|
||||||
|
function _parseMember( name, value, keywords, h )
|
||||||
|
{
|
||||||
|
// traits are not permitted to define constructors
|
||||||
|
if ( name === '__construct' )
|
||||||
|
{
|
||||||
|
throw Error( "Traits may not define __construct" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply original handler
|
||||||
|
h.apply( this, arguments );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Throws error if non-internal property is found within PROPS
|
* Throws error if non-internal property is found within PROPS
|
||||||
*
|
*
|
||||||
* For details and rationale, see the Trait/PropertyTest case.
|
* For details and rationale, see the Trait/PropertyTest case.
|
||||||
*
|
*
|
||||||
* @param {Object} props properties to prohibit
|
* @param {string} name property name
|
||||||
|
* @param {*} value property value
|
||||||
|
* @param {Object} keywords property keywords
|
||||||
|
* @param {Function} h original handler that we replaced
|
||||||
*
|
*
|
||||||
* @return {undefined}
|
* @return {undefined}
|
||||||
*/
|
*/
|
||||||
function validateProps( props )
|
function _parseProps( name, value, keywords, h )
|
||||||
{
|
{
|
||||||
for ( var f in props )
|
// ignore internal properties
|
||||||
|
if ( name.substr( 0, 3 ) === '___' )
|
||||||
{
|
{
|
||||||
// ignore internal properties
|
return;
|
||||||
if ( f.substr( 0, 3 ) === '___' )
|
}
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if ( !( keywords['private'] ) )
|
||||||
|
{
|
||||||
throw Error(
|
throw Error(
|
||||||
"Cannot define property `" + f + "'; only private " +
|
"Cannot define property `" + name + "'; only private " +
|
||||||
"properties are permitted within Trait definitions"
|
"properties are permitted within Trait definitions"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// apply original handler
|
||||||
|
h.apply( this, arguments );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue