Subtype mixin support
parent
451ec48a5c
commit
999c10c3bf
33
lib/Trait.js
33
lib/Trait.js
|
@ -294,7 +294,7 @@ function mixMethods( src, dest, vis, iname )
|
|||
function addTraitInst( T, dfn )
|
||||
{
|
||||
var tc = ( dfn.___$$tc$$ = ( dfn.___$$tc$$ || [] ) ),
|
||||
iname = '___$to$' + tc.length;
|
||||
iname = '___$to$' + T.__acls.__cid;
|
||||
|
||||
// the trait object array will contain two values: the destination field
|
||||
// and the trait to instantiate
|
||||
|
@ -307,7 +307,11 @@ function addTraitInst( T, dfn )
|
|||
// create internal trait ctor if not available
|
||||
if ( dfn.___$$tctor$$ === undefined )
|
||||
{
|
||||
dfn.___$$tctor$$ = tctor;
|
||||
// TODO: let's check for inheritance or something to avoid this weak
|
||||
// definition (this prevents warnings if there is not a supertype
|
||||
// that defines the trait ctor)
|
||||
dfn[ 'weak virtual ___$$tctor$$' ] = function() {};
|
||||
dfn[ 'virtual override ___$$tctor$$' ] = createTctor( tc );
|
||||
}
|
||||
|
||||
return iname;
|
||||
|
@ -327,11 +331,10 @@ function addTraitInst( T, dfn )
|
|||
*
|
||||
* @return {undefined}
|
||||
*/
|
||||
function tctor()
|
||||
function tctor( tc )
|
||||
{
|
||||
// instantiate all traits and assign the object to their
|
||||
// respective fields
|
||||
var tc = this.___$$tc$$;
|
||||
for ( var t in tc )
|
||||
{
|
||||
var f = tc[ t ][ 0 ],
|
||||
|
@ -345,7 +348,29 @@ function tctor()
|
|||
// the intimate relationship
|
||||
this[ f ] = C( this.___$$vis$$ ).___$$vis$$;
|
||||
}
|
||||
|
||||
// if we are a subtype, be sure to initialize our parent's traits
|
||||
this.__super && this.__super();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create trait constructor
|
||||
*
|
||||
* This binds the generic trait constructor to a reference to the provided
|
||||
* trait class list.
|
||||
*
|
||||
* @param {Object} tc trait class list
|
||||
*
|
||||
* @return {function()} trait constructor
|
||||
*/
|
||||
function createTctor( tc )
|
||||
{
|
||||
return function()
|
||||
{
|
||||
return tctor.call( this, tc );
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
module.exports = Trait;
|
||||
|
|
|
@ -71,4 +71,69 @@ require( 'common' ).testCase(
|
|||
// o's supertype mixes in T
|
||||
this.assertOk( this.Class.isA( T, o ) );
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Subtyping should impose no limits on mixins (except for the obvious
|
||||
* API compatibility restrictions inherent in OOP).
|
||||
*/
|
||||
'Subtype can mix in additional traits': function()
|
||||
{
|
||||
var a = false,
|
||||
b = false;
|
||||
|
||||
var Ta = this.Sut(
|
||||
{
|
||||
'public ta': function() { a = true; },
|
||||
} ),
|
||||
Tb = this.Sut(
|
||||
{
|
||||
'public tb': function() { b = true; },
|
||||
} ),
|
||||
C = null;
|
||||
|
||||
var _self = this;
|
||||
this.assertDoesNotThrow( function()
|
||||
{
|
||||
var sup = _self.Class.use( Ta ).extend( {} );
|
||||
|
||||
// mixes in Tb; supertype already mixed in Ta
|
||||
C = _self.Class.use( Tb ).extend( sup, {} );
|
||||
} );
|
||||
|
||||
this.assertDoesNotThrow( function()
|
||||
{
|
||||
// ensures that instantiation does not throw an error and that
|
||||
// the methods both exist
|
||||
var o = C();
|
||||
o.ta();
|
||||
o.tb();
|
||||
} );
|
||||
|
||||
// ensure both were properly called
|
||||
this.assertOk( a );
|
||||
this.assertOk( b );
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* As a sanity check, ensure that subtyping does not override parent
|
||||
* type data with respect to traits.
|
||||
*
|
||||
* Note that this test makes the preceding test redundant, but the
|
||||
* separation is useful for debugging any potential regressions.
|
||||
*/
|
||||
'Subtype trait types do not overwrite supertype types': function()
|
||||
{
|
||||
var Ta = this.Sut( {} ),
|
||||
Tb = this.Sut( {} ),
|
||||
C = this.Class.use( Ta ).extend( {} ),
|
||||
o = this.Class.use( Tb ).extend( C, {} )();
|
||||
|
||||
// o's supertype mixes in Ta
|
||||
this.assertOk( this.Class.isA( Ta, o ) );
|
||||
|
||||
// o mixes in Tb
|
||||
this.assertOk( this.Class.isA( Tb, o ) );
|
||||
},
|
||||
} );
|
||||
|
|
Loading…
Reference in New Issue