1
0
Fork 0

Now properly handling extending from objects and properly throwing errors for scalars

perfodd
Mike Gerwitz 2011-12-15 22:58:23 -05:00
parent d5ef3eb221
commit 2136ebedd5
2 changed files with 56 additions and 9 deletions

View File

@ -294,7 +294,7 @@ exports.prototype.build = function extend( _, __ )
var args = Array.prototype.slice.call( arguments ), var args = Array.prototype.slice.call( arguments ),
props = args.pop() || {}, props = args.pop() || {},
base = args.pop() || exports.ClassBase, base = args.pop() || exports.ClassBase,
prototype = new base(), prototype = this._getBase( base ),
cname = '', cname = '',
prop_init = this._memberBuilder.initMembers(), prop_init = this._memberBuilder.initMembers(),
@ -309,12 +309,6 @@ exports.prototype.build = function extend( _, __ )
|| { __length: 0 } || { __length: 0 }
; ;
// must extend from constructor or class
if ( typeof base !== 'function' )
{
throw TypeError( "Must extend from class or constructor");
}
// prevent extending final classes // prevent extending final classes
if ( base.___$$final$$ === true ) if ( base.___$$final$$ === true )
{ {
@ -424,6 +418,27 @@ exports.prototype.build = function extend( _, __ )
}; };
exports.prototype._getBase = function( base )
{
var type = ( typeof base );
switch ( type )
{
// constructor (we could also check to ensure that the return value of
// the constructor is an object, but that is not our concern)
case 'function':
return new base();
// we can use objects as the prototype directly
case 'object':
return base;
}
// scalars
throw TypeError( 'Must extend from Class, constructor or object' );
};
exports.prototype.buildMembers = function buildMembers( exports.prototype.buildMembers = function buildMembers(
props, class_id, base, prop_init, abstract_methods, members, props, class_id, base, prop_init, abstract_methods, members,
static_members, staticInstLookup static_members, staticInstLookup
@ -758,11 +773,12 @@ exports.prototype._attachPropInit = function(
// defaults to false // defaults to false
inherit = !!inherit; inherit = !!inherit;
var iid = this.__iid; var iid = this.__iid,
parent = prototype.___$$parent$$;
// first initialize the parent's properties, so that ours will overwrite // first initialize the parent's properties, so that ours will overwrite
// them // them
var parent_init = prototype.___$$parent$$.__initProps; var parent_init = parent && parent.__initProps;
if ( typeof parent_init === 'function' ) if ( typeof parent_init === 'function' )
{ {
// call the parent prop_init, letting it know that it's been // call the parent prop_init, letting it know that it's been

View File

@ -432,3 +432,34 @@ for ( var i = 0; i < class_count; i++ )
assert.fail( "Should not be permitted to override non-virtual method" ); assert.fail( "Should not be permitted to override non-virtual method" );
} )(); } )();
/**
* If we attempt to extend an object (rather than a constructor), we should
* simply use that as the prototype directly rather than attempting to
* instantiate it.
*/
( function testExtendingObjectWillNotAttemptInstantiation()
{
var obj = { foo: 'bar' };
assert.equal( obj.foo, Class.extend( obj, {} )().foo,
'Should be able to use object as prototype'
);
} )();
/**
* It only makes sense to extend from an object or function (constructor, more
* specifically)
*
* We could also test to ensure that the return value of the constructor is an
* object, but that is unnecessary for the time being.
*/
( function testWillThrowExceptionIfNonObjectOrCtorIsProvided()
{
assert['throws']( function()
{
Class.extend( 'foo', {} );
}, TypeError, 'Should not be able to extend from non-object or non-ctor' );
} )();