1
0
Fork 0

Added support for final subtypes

closure/master
Mike Gerwitz 2011-05-22 21:35:29 -04:00
parent a67d704837
commit 8c62ee021c
2 changed files with 91 additions and 6 deletions

View File

@ -24,18 +24,79 @@
var Class = require( __dirname + '/class' ); 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 // the last argument _should_ be the definition
var dfn = arguments[ arguments.length - 1 ]; var dfn = args[ args.length - 1 ];
if ( typeof dfn === 'object' ) if ( typeof dfn === 'object' )
{ {
// mark it as final // mark as abstract
dfn.___$$final$$ = true; 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 );
}; };
}

View File

@ -157,3 +157,27 @@ var common = require( './common' ),
assert.fail( "Should not be able to extend final classes" ); 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" );
} )();