diff --git a/lib/class_abstract.js b/lib/class_abstract.js index 5e04c6a..90adbe8 100644 --- a/lib/class_abstract.js +++ b/lib/class_abstract.js @@ -107,11 +107,19 @@ function markAbstract( args ) * * @param {Object} obj object to override * - * @return {undefined} + * @return {Object} obj */ function abstractOverride( obj ) { - var extend = obj.extend; + var extend = obj.extend, + impl = obj.implement; + + // wrap and apply the abstract flag, only if the method is defined (it may + // not be under all circumstances, e.g. after an implement()) + impl && ( obj.implement = function() + { + return abstractOverride( impl.apply( this, arguments ) ); + } ); // wrap extend, applying the abstract flag obj.extend = function() @@ -119,5 +127,7 @@ function abstractOverride( obj ) markAbstract( arguments ); return extend.apply( this, arguments ); }; + + return obj; } diff --git a/test/test-class-abstract.js b/test/test-class-abstract.js index 9ba4085..e33c8d2 100644 --- a/test/test-class-abstract.js +++ b/test/test-class-abstract.js @@ -26,7 +26,8 @@ var common = require( './common' ), util = common.require( 'util' ), Class = common.require( 'class' ), - AbstractClass = common.require( 'class_abstract' ) + AbstractClass = common.require( 'class_abstract' ), + Interface = common.require( 'interface' ) ; @@ -451,3 +452,22 @@ var ConcreteFoo = Class.extend( AbstractFoo, ); } )(); + +/** + * Extending an abstract class after an implement() should still result in an + * abstract class. Essentially, we are testing to ensure that the extend() + * method is properly wrapped to flag the resulting class as abstract. This was + * a bug. + */ +( function testImplementingInterfacesWillPreserveAbstractClassDeclaration() +{ + assert.doesNotThrow( function() + { + // if not considered abstract, extend() will fail, as it will contain + // abstract member foo + AbstractClass( 'TestImplExtend' ) + .implement( Interface( { foo: [] } ) ) + .extend( {} ); + }, Error, 'Class should still be abstract after implement().extend()' ); +} )() +