Now properly handling extending from objects and properly throwing errors for scalars
parent
d5ef3eb221
commit
2136ebedd5
|
@ -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
|
||||||
|
|
|
@ -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' );
|
||||||
|
} )();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue