Added support for final subtypes
parent
a67d704837
commit
8c62ee021c
|
@ -24,18 +24,79 @@
|
|||
|
||||
var Class = require( __dirname + '/class' );
|
||||
|
||||
module.exports = function()
|
||||
|
||||
/**
|
||||
* Creates a final class
|
||||
*
|
||||
* @return {Class} final class
|
||||
*/
|
||||
exports = module.exports = function()
|
||||
{
|
||||
markFinal( arguments );
|
||||
|
||||
// forward everything to Class
|
||||
var result = Class.apply( this, arguments );
|
||||
|
||||
if ( !Class.isClass( result ) )
|
||||
{
|
||||
finalOverride( result );
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a final class from a class extend operation
|
||||
*
|
||||
* @return {Class} final class
|
||||
*/
|
||||
exports.extend = function()
|
||||
{
|
||||
markFinal( arguments );
|
||||
return Class.extend.apply( this, arguments );
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Causes a definition to be flagged as final
|
||||
*
|
||||
* This function assumes the last argument to be the definition, which is the
|
||||
* common case, and modifies the object referenced by that argument.
|
||||
*
|
||||
* @param {arguments} args arguments to parse
|
||||
*
|
||||
* @return {undefined}
|
||||
*/
|
||||
function markFinal( args )
|
||||
{
|
||||
// the last argument _should_ be the definition
|
||||
var dfn = arguments[ arguments.length - 1 ];
|
||||
var dfn = args[ args.length - 1 ];
|
||||
|
||||
if ( typeof dfn === 'object' )
|
||||
{
|
||||
// mark it as final
|
||||
// mark as abstract
|
||||
dfn.___$$final$$ = true;
|
||||
}
|
||||
}
|
||||
|
||||
// forward everything to Class
|
||||
return Class.apply( this, arguments );
|
||||
};
|
||||
|
||||
/**
|
||||
* Overrides object members to permit final classes
|
||||
*
|
||||
* @param {Object} obj object to override
|
||||
*
|
||||
* @return {undefined}
|
||||
*/
|
||||
function finalOverride( obj )
|
||||
{
|
||||
var extend = obj.extend;
|
||||
|
||||
// wrap extend, applying the abstract flag
|
||||
obj.extend = function()
|
||||
{
|
||||
markFinal( arguments );
|
||||
return extend.apply( this, arguments );
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -157,3 +157,27 @@ var common = require( './common' ),
|
|||
assert.fail( "Should not be able to extend final classes" );
|
||||
} )();
|
||||
|
||||
|
||||
/**
|
||||
* Ensure we're able to create final classes by extending existing classes.
|
||||
*/
|
||||
( function testCanCreateFinalSubtypes()
|
||||
{
|
||||
var Foo = builder.build( {} ),
|
||||
FinalNamed = FinalClass( 'FinalNamed' ).extend( Foo, {} ),
|
||||
FinalAnon = FinalClass.extend( Foo, {} )
|
||||
;
|
||||
|
||||
// named
|
||||
assert.throws( function()
|
||||
{
|
||||
FinalNamed.extend( {} );
|
||||
}, Error, "Cannot extend final named subtype" );
|
||||
|
||||
// anonymous
|
||||
assert.throws( function()
|
||||
{
|
||||
FinalAnon.extend( {} );
|
||||
}, Error, "Cannot extend final anonymous subtype" );
|
||||
} )();
|
||||
|
||||
|
|
Loading…
Reference in New Issue