1
0
Fork 0

__super() method is now properly set on context

closure/master
Mike Gerwitz 2011-03-29 22:02:42 -04:00
parent f43959640c
commit 5cb0b8355f
2 changed files with 65 additions and 5 deletions

View File

@ -22,7 +22,8 @@
* @package core
*/
var util = require( './util' ),
var util = require( __dirname + '/util' ),
fallback = util.definePropertyFallback(),
visibility = [ 'public', 'protected', 'private' ];
@ -361,11 +362,18 @@ function overrideMethod( super_method, new_method, instCallback, cid )
retval = undefined
;
// the _super property will contain the parent method
this.__super = super_method;
// the _super property will contain the parent method (we don't
// store the previous value for performance reasons and because,
// during conventional use, it's completely unnecessary)
context.__super = super_method;
retval = new_method.apply( context, arguments );
// prevent sneaky bastards from breaking encapsulation by stealing
// method references (we set to undefined rather than deleting it
// because deletion causes performance degradation within V8)
context.__super = undefined;
// if the value returned from the method was the context that we
// passed in, return the actual instance (to ensure we do not break
// encapsulation)

View File

@ -24,12 +24,13 @@
var common = require( './common' ),
assert = require( 'assert' ),
mb_common = require( __dirname + '/inc-member_builder-common' )
mb_common = require( __dirname + '/inc-member_builder-common' ),
builder = common.require( 'member_builder' )
;
mb_common.funcVal = 'foobar';
mb_common.value = function() { return mb_common.funcVal; };
mb_common.buildMember = common.require( 'member_builder' ).buildMethod;
mb_common.buildMember = builder.buildMethod;
// do assertions common to all member builders
mb_common.assertCommon();
@ -137,6 +138,57 @@ mb_common.assertCommon();
} )();
/**
* If the method is called when bound to a different context (e.g. for
* protected/private members), __super may not be properly bound.
*
* This test is in response to a bug found after implementing visibility
* support. The __super() method was previously defined on 'this', which may or
* may not be the context that is actually used. Likely, it's not.
*/
( function testSuperMethodWorksProperlyWhenContextDiffers()
{
var members = builder.initMembers(),
super_called = false,
retobj = {},
instCallback = function()
{
return retobj;
},
// the overriding method
newfunc = function()
{
this.__super();
}
;
// super method to be overridden
members[ 'public' ].foo = function()
{
super_called = true;
};
// override
builder.buildMethod( members, {}, 'foo', newfunc, {}, instCallback );
// call the overriding method
members[ 'public' ].foo();
// ensure that the super method was called
assert.equal( super_called, true,
"__super() method is called even when context differs"
);
// finally, ensure that __super is no longer set on the returned object
// after the call to ensure that the caller cannot break encapsulation by
// stealing a method reference (sneaky, sneaky)
assert.equal( retobj.__super, undefined,
"__super() method is unset after being called"
);
} )();
/**
* Once a concrete implementation has been defined for a method, a subtype
* cannot make it abstract.