Fail intelligently if provided class in place of definition object
This is intended mainly to handle cases where the user forgets the second argument when extending a class: Class.extend( Base ) // missing second argument (definition object) * lib/ClassBuilder.js (exports.isClass): Move from lib/class.js. (exports.prototype.build): Throw error if definition object is a class. * lib/class.js (module.exports.isClass): Reference `ClassBuilder.isClass'. * test/Class/ExtendTest.js: Add respective test case.master
parent
55f47a3c5a
commit
60920f18a6
|
@ -305,6 +305,30 @@ exports.isInstanceOf = function( type, instance )
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines whether the provided object is a class created through ease.js
|
||||
*
|
||||
* @param {Object} obj object to test
|
||||
*
|
||||
* @return {boolean} true if class (created through ease.js), otherwise
|
||||
* false
|
||||
*/
|
||||
module.exports.isClass = function( obj )
|
||||
{
|
||||
obj = obj || _dummyclass;
|
||||
|
||||
var meta = module.exports.getMeta( obj );
|
||||
|
||||
// TODO: we're checking a random field on the meta object; do something
|
||||
// proper
|
||||
return ( ( ( meta !== null ) && meta.implemented )
|
||||
|| ( obj.prototype instanceof module.exports.ClassBase ) )
|
||||
? true
|
||||
: false
|
||||
;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper around ECMAScript instanceof check
|
||||
*
|
||||
|
@ -383,6 +407,15 @@ exports.prototype.build = function extend( _, __ )
|
|||
|| {}
|
||||
;
|
||||
|
||||
// respond intelligently if the definition object is mistakenly a class
|
||||
if ( module.exports.isClass( props ) )
|
||||
{
|
||||
throw TypeError( ( an > 1 )
|
||||
? "Expected class definition, but found class " + props.toString()
|
||||
: "Missing second argument to extend class " + props.toString()
|
||||
);
|
||||
}
|
||||
|
||||
// prevent extending final classes (TODO: abstract this check)
|
||||
if ( base.___$$final$$ === true )
|
||||
{
|
||||
|
|
17
lib/class.js
17
lib/class.js
|
@ -171,26 +171,11 @@ var _dummyinst = { constructor: { prototype: {} } };
|
|||
/**
|
||||
* Determines whether the provided object is a class created through ease.js
|
||||
*
|
||||
* TODO: delegate to ClassBuilder
|
||||
*
|
||||
* @param {Object} obj object to test
|
||||
*
|
||||
* @return {boolean} true if class (created through ease.js), otherwise false
|
||||
*/
|
||||
module.exports.isClass = function( obj )
|
||||
{
|
||||
obj = obj || _dummyclass;
|
||||
|
||||
var meta = ClassBuilder.getMeta( obj );
|
||||
|
||||
// TODO: we're checking a random field on the meta object; do something
|
||||
// proper
|
||||
return ( ( ( meta !== null ) && meta.implemented )
|
||||
|| ( obj.prototype instanceof ClassBuilder.ClassBase ) )
|
||||
? true
|
||||
: false
|
||||
;
|
||||
};
|
||||
module.exports.isClass = ClassBuilder.isClass;
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -468,4 +468,36 @@ require( 'common' ).testCase(
|
|||
// protected foo was recognized
|
||||
this.assertOk( called );
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* When a single argument is provided to `#extend' in the form
|
||||
* `C.extend(o)', it is assumed that `o' is the definition
|
||||
* object. However, it's also possible that the user provided the class
|
||||
* to extend but _forgot_ the definition object.
|
||||
*
|
||||
* In this case, prior to this change, the supertype was treated as the
|
||||
* definition object, which yielded some pretty confusing results. It's
|
||||
* better to help the user out and provide a clear indication of what
|
||||
* went wrong.
|
||||
*/
|
||||
'Extending with one argument that is a class yields an error': function()
|
||||
{
|
||||
var _self = this;
|
||||
|
||||
// missing second argument
|
||||
this.assertThrows( function()
|
||||
{
|
||||
_self.Sut.extend( _self.Sut( 'Whoops', {} ) );
|
||||
}, TypeError );
|
||||
|
||||
// class provided as second argument (>_>)
|
||||
this.assertThrows( function()
|
||||
{
|
||||
_self.Sut.extend(
|
||||
_self.Sut( 'Base', {} ),
|
||||
_self.Sut( 'Wth', {} )
|
||||
);
|
||||
}, TypeError );
|
||||
}
|
||||
} );
|
||||
|
|
Loading…
Reference in New Issue