Added support for final subtypes
parent
a67d704837
commit
8c62ee021c
|
@ -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 );
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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" );
|
||||||
|
} )();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue