Refactored Traits to use propParse hooks
parent
3d47443046
commit
316a7dd703
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
59
lib/Trait.js
59
lib/Trait.js
|
@ -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 );
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue