1
0
Fork 0

Subtypes of prototype subtypes now work correctly

protolib
Mike Gerwitz 2014-04-29 10:47:12 -04:00
parent ddf1d5918e
commit 8b8a08b7dc
3 changed files with 61 additions and 5 deletions

View File

@ -365,7 +365,8 @@ exports.prototype.build = function extend( _, __ )
// if we are inheriting from a prototype, we must make sure that all
// properties initialized by the ctor are implicitly public; otherwise,
// proxying will fail to take place
if ( !( prototype instanceof exports.ClassBase ) )
// TODO: see Class.isA TODO
if ( prototype.___$$vis$$ === undefined )
{
this._discoverProtoProps( prototype, prop_init );
}

View File

@ -148,6 +148,9 @@ module.exports.use = function( traits )
};
var _dummyclass = { prototype: {} };
var _dummyinst = { constructor: { prototype: {} } };
/**
* Determines whether the provided object is a class created through ease.js
*
@ -157,9 +160,18 @@ module.exports.use = function( traits )
*/
module.exports.isClass = function( obj )
{
obj = obj || {};
obj = obj || _dummyclass;
return ( obj.prototype instanceof ClassBuilder.ClassBase )
if ( !obj.prototype )
{
return false;
}
// TODO: this just checks one of many internal fields; we need something
// more formal (cannot use a strict ClassBase check because it will fail
// when extending prototypes)
return ( ( obj.prototype.___$$vis$$ !== undefined )
|| ( obj.prototype instanceof ClassBuilder.ClassBase ) )
? true
: false
;
@ -177,9 +189,16 @@ module.exports.isClass = function( obj )
*/
module.exports.isClassInstance = function( obj )
{
obj = obj || {};
obj = obj || _dummyinst;
return ( obj instanceof ClassBuilder.ClassBase )
if ( !obj.constructor || !obj.constructor.prototype )
{
return false;
}
// TODO: see isClass TODO
return ( ( obj.constructor.prototype.___$$vis$$ !== undefined )
|| ( obj instanceof ClassBuilder.ClassBase ) )
? true
: false;
};

View File

@ -319,6 +319,42 @@ require( 'common' ).testCase(
},
/**
* This is a regression test for an interesting (and particularily
* nasty) bug for a situation that is probably reasonably rare. The
* original check for a non-class supertype checked whether the
* supertype was an instance of the internal base class. While this
* works, it unforunately causes problems for subtypes of the class that
* extended the prototype---the check will fail, since there is no
* ClassBase in the prototype chain.
*
* This resulted in it processing the class fields, which ended up
* overwriting ___$$vis$$, which clobbered all the methods. Doh.
*/
'Subtypes of prototype subtypes yield stable classes': function()
{
function P() {};
// sub-subtype of P
var expected = {};
var C = this.Class.extend( P, {} ).extend(
{
foo: function() { return expected; }
} );
var inst = C();
// this should be recognized as a class (prior to the fix, it was
// not), and inst should be an instance of a class
this.assertOk( this.Class.isClass( C ) );
this.assertOk( this.Class.isClassInstance( inst ) );
this.assertOk( this.Class.isA( C, inst ) );
// before the fix, foo is undefined since ___$$vis$$ was clobbered
this.assertStrictEqual( inst.foo(), expected );
},
/**
* When prototypally extending a class, it is not wise to invoke the
* constructor (just like ease.js does not invoke the constructor of