Protected trait methods are now mixed in
parent
3724b1bc0d
commit
e44ac3190b
47
lib/Trait.js
47
lib/Trait.js
|
@ -38,7 +38,7 @@ Trait.extend = function( dfn )
|
||||||
// we need at least one abstract member in order to declare a class as
|
// we need at least one abstract member in order to declare a class as
|
||||||
// abstract (in this case, our trait class), so let's create a dummy one
|
// abstract (in this case, our trait class), so let's create a dummy one
|
||||||
// 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$$' ] = [];
|
||||||
|
|
||||||
function TraitType()
|
function TraitType()
|
||||||
{
|
{
|
||||||
|
@ -88,7 +88,7 @@ function createConcrete( acls )
|
||||||
{
|
{
|
||||||
// start by providing a concrete implementation for our dummy method
|
// start by providing a concrete implementation for our dummy method
|
||||||
var dfn = {
|
var dfn = {
|
||||||
'protected __$$trait$$': function() {},
|
'protected ___$$trait$$': function() {},
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: everything else
|
// TODO: everything else
|
||||||
|
@ -111,44 +111,59 @@ function mixin( trait, dfn )
|
||||||
{
|
{
|
||||||
// the abstract class hidden within the trait
|
// the abstract class hidden within the trait
|
||||||
var acls = trait.__acls,
|
var acls = trait.__acls,
|
||||||
methods = acls.___$$methods$$,
|
methods = acls.___$$methods$$;
|
||||||
pub = methods['public'];
|
|
||||||
|
|
||||||
// retrieve the private member name that will contain this trait object
|
// retrieve the private member name that will contain this trait object
|
||||||
var iname = addTraitInst( trait.__ccls, dfn );
|
var iname = addTraitInst( trait.__ccls, dfn );
|
||||||
|
|
||||||
// TODO: protected; ignore abstract
|
mixMethods( methods['public'], dfn, 'public', iname );
|
||||||
for ( var f in pub )
|
mixMethods( methods['protected'], dfn, 'protected', iname );
|
||||||
|
|
||||||
|
return dfn;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mix methods from SRC into DEST using proxies
|
||||||
|
*
|
||||||
|
* @param {Object} src visibility object to scavenge from
|
||||||
|
* @param {Object} dest destination definition object
|
||||||
|
* @param {string} vis visibility modifier
|
||||||
|
* @param {string} ianem proxy destination (trait instance)
|
||||||
|
*
|
||||||
|
* @return {undefined}
|
||||||
|
*/
|
||||||
|
function mixMethods( src, dest, vis, iname )
|
||||||
|
{
|
||||||
|
// TODO: ignore abstract
|
||||||
|
for ( var f in src )
|
||||||
{
|
{
|
||||||
if ( !( Object.hasOwnProperty.call( pub, f ) ) )
|
if ( !( Object.hasOwnProperty.call( src, f ) ) )
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this is a kluge; we'll use proper reflection eventually,
|
// TODO: this is a kluge; we'll use proper reflection eventually,
|
||||||
// but for now, this is how we determine if this is an actual public
|
// but for now, this is how we determine if this is an actual method
|
||||||
// method vs. something that just happens to be on the public
|
// vs. something that just happens to be on the visibility object
|
||||||
// visibility object
|
if ( !( src[ f ].___$$keywords$$ ) || f === '___$$trait$$' )
|
||||||
if ( !( pub[ f ].___$$keywords$$ ) )
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var pname = 'public proxy ' + f;
|
var pname = vis + ' proxy ' + f;
|
||||||
|
|
||||||
// if we have already set up a proxy for a field of this name, then
|
// if we have already set up a proxy for a field of this name, then
|
||||||
// multiple traits have defined the same concrete member
|
// multiple traits have defined the same concrete member
|
||||||
if ( dfn[ pname ] !== undefined )
|
if ( dest[ pname ] !== undefined )
|
||||||
{
|
{
|
||||||
// TODO: between what traits?
|
// TODO: between what traits?
|
||||||
throw Error( "Trait member conflict: `" + f + "'" );
|
throw Error( "Trait member conflict: `" + f + "'" );
|
||||||
}
|
}
|
||||||
|
|
||||||
// proxy this method to what will be the encapsulated trait object
|
// proxy this method to what will be the encapsulated trait object
|
||||||
dfn[ pname ] = iname;
|
dest[ pname ] = iname;
|
||||||
}
|
}
|
||||||
|
|
||||||
return dfn;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -45,18 +45,17 @@ require( 'common' ).testCase(
|
||||||
],
|
],
|
||||||
|
|
||||||
// should (at least for the time being) be picked up by existing
|
// should (at least for the time being) be picked up by existing
|
||||||
// class error checks
|
// class error checks; TODO: but let's provide trait-specific
|
||||||
|
// error messages to avoid frustration and infuriation
|
||||||
[ 'foo', "varying keywords; same visibility",
|
[ 'foo', "varying keywords; same visibility",
|
||||||
{ 'virtual public foo': function() {} },
|
{ 'virtual public foo': function() {} },
|
||||||
{ 'public virtual foo': function() {} },
|
{ 'public virtual foo': function() {} },
|
||||||
],
|
],
|
||||||
|
|
||||||
/* TODO
|
|
||||||
[ 'foo', "different visibility",
|
[ 'foo', "different visibility",
|
||||||
{ 'public foo': function() {} },
|
{ 'public foo': function() {} },
|
||||||
{ 'protected foo': function() {} },
|
{ 'protected foo': function() {} },
|
||||||
],
|
],
|
||||||
*/
|
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -234,7 +233,7 @@ require( 'common' ).testCase(
|
||||||
// caused the error
|
// caused the error
|
||||||
this.assertOk(
|
this.assertOk(
|
||||||
e.message.match( '\\b' + fname + '\\b' ),
|
e.message.match( '\\b' + fname + '\\b' ),
|
||||||
"Missing field name"
|
"Error message missing field name: " + e.message
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: we can also make less people hate us if we include the
|
// TODO: we can also make less people hate us if we include the
|
||||||
|
|
Loading…
Reference in New Issue