Added support for named abstract subclasses
parent
db9de2712e
commit
a67d704837
|
@ -39,7 +39,16 @@ module.exports = exports = function()
|
|||
markAbstract( arguments );
|
||||
|
||||
// forward everything to Class
|
||||
return Class.apply( this, arguments );
|
||||
var result = Class.apply( this, arguments );
|
||||
|
||||
// if we're using the temporary object, then override its methods to permit
|
||||
// abstract classes
|
||||
if ( !Class.isClass( result ) )
|
||||
{
|
||||
abstractOverride( result );
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
|
@ -64,16 +73,9 @@ exports.extend = function()
|
|||
*/
|
||||
exports.implement = function()
|
||||
{
|
||||
var impl = Class.implement.apply( this, arguments ),
|
||||
extend = impl.extend;
|
||||
|
||||
// wrap extend, applying the abstract flag
|
||||
impl.extend = function()
|
||||
{
|
||||
markAbstract( arguments );
|
||||
return extend.apply( this, arguments );
|
||||
};
|
||||
var impl = Class.implement.apply( this, arguments );
|
||||
|
||||
abstractOverride( impl );
|
||||
return impl;
|
||||
};
|
||||
|
||||
|
@ -100,3 +102,23 @@ function markAbstract( args )
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overrides object members to permit abstract classes
|
||||
*
|
||||
* @param {Object} obj object to override
|
||||
*
|
||||
* @return {undefined}
|
||||
*/
|
||||
function abstractOverride( obj )
|
||||
{
|
||||
var extend = obj.extend;
|
||||
|
||||
// wrap extend, applying the abstract flag
|
||||
obj.extend = function()
|
||||
{
|
||||
markAbstract( arguments );
|
||||
return extend.apply( this, arguments );
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1004,7 +1004,7 @@ exports.isInstanceOf = function( type, instance )
|
|||
|
||||
try
|
||||
{
|
||||
// check prototype chain (with throw an error if type is not a
|
||||
// check prototype chain (will throw an error if type is not a
|
||||
// constructor (function)
|
||||
if ( instance instanceof type )
|
||||
{
|
||||
|
|
|
@ -106,14 +106,27 @@ var common = require( './common' ),
|
|||
} )();
|
||||
|
||||
|
||||
( function testAbstractClassContainsExtendMethod()
|
||||
/**
|
||||
* Just as Class contains an extend method, so should AbstractClass.
|
||||
*/
|
||||
( function testAbstractClassExtendMethodReturnsNewClass()
|
||||
{
|
||||
assert.ok( typeof AbstractClass.extend === 'function',
|
||||
"AbstractClass contains extend method"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
Class.isClass(
|
||||
AbstractClass.extend( { 'abstract foo': [] } )
|
||||
),
|
||||
"Abstract class extend method returns class"
|
||||
);
|
||||
} )();
|
||||
|
||||
|
||||
/**
|
||||
* Just as Class contains an implement method, so should AbstractClass.
|
||||
*/
|
||||
( function testAbstractClassContainsImplementMethod()
|
||||
{
|
||||
assert.ok( typeof AbstractClass.implement === 'function',
|
||||
|
@ -363,3 +376,51 @@ var ConcreteFoo = Class.extend( AbstractFoo,
|
|||
}, Error, "Should not throw error if overriding a prototype method" );
|
||||
} )();
|
||||
|
||||
|
||||
/**
|
||||
* Ensure we support named abstract class extending
|
||||
*/
|
||||
( function testCanCreateNamedAbstractSubtypes()
|
||||
{
|
||||
assert.doesNotThrow( function()
|
||||
{
|
||||
var cls = AbstractClass( 'NamedSubFoo' ).extend( AbstractFoo, {} );
|
||||
}, Error, "Can create named abstract subtypes" );
|
||||
} )();
|
||||
|
||||
|
||||
/**
|
||||
* Abstract classes, when extended, should yield a concrete class by default.
|
||||
* Otherwise, the user should once again use AbstractClass to clearly state that
|
||||
* the subtype is abstract.
|
||||
*/
|
||||
( function testExtendingAbstractClassIsNotAbstractByDefault()
|
||||
{
|
||||
var cls_named = AbstractClass( 'NamedSubFoo' ).extend( AbstractFoo, {} ),
|
||||
anon_named = AbstractClass.extend( AbstractFoo, {} );
|
||||
|
||||
// named
|
||||
assert.throws(
|
||||
function()
|
||||
{
|
||||
// should throw an error, since we're not declaring it as abstract
|
||||
// and we're not providing a concrete impl
|
||||
Class.isAbstract( cls_named.extend( {} ) );
|
||||
},
|
||||
TypeError,
|
||||
"Extending named abstract classes should be concrete by default"
|
||||
);
|
||||
|
||||
// anonymous
|
||||
assert.throws(
|
||||
function()
|
||||
{
|
||||
// should throw an error, since we're not declaring it as abstract
|
||||
// and we're not providing a concrete impl
|
||||
Class.isAbstract( AbstractFoo.extend( {} ) );
|
||||
},
|
||||
TypeError,
|
||||
"Extending anonymous abstract classes should be concrete by default"
|
||||
);
|
||||
} )();
|
||||
|
||||
|
|
Loading…
Reference in New Issue