1
0
Fork 0

Refactored Traits to use propParse hooks

perfodd
Mike Gerwitz 2014-03-11 06:36:45 -04:00
parent 3d47443046
commit 316a7dd703
2 changed files with 80 additions and 22 deletions

View File

@ -487,14 +487,47 @@ exports.prototype.buildMembers = function buildMembers(
virtual_members: memberdest['virtual'],
};
util.propParse( props, {
// default member handlers for parser
var handlers = {
each: _parseEach,
property: _parseProp,
getset: _parseGetSet,
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 );
}

View File

@ -86,6 +86,12 @@ Trait.extend = function( dfn )
// just in case DFN does not contain any abstract members itself
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
dfn.__name = '#AbstractTrait#';
@ -112,16 +118,6 @@ Trait.extend = function( dfn )
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
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
*
* 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}
*/
function validateProps( props )
function _parseProps( name, value, keywords, h )
{
for ( var f in props )
{
// ignore internal properties
if ( f.substr( 0, 3 ) === '___' )
if ( name.substr( 0, 3 ) === '___' )
{
continue;
return;
}
if ( !( keywords['private'] ) )
{
throw Error(
"Cannot define property `" + f + "'; only private " +
"Cannot define property `" + name + "'; only private " +
"properties are permitted within Trait definitions"
);
}
// apply original handler
h.apply( this, arguments );
}