1
0
Fork 0

Corrected bug whereby multiple override calls would clear __super too early

Before this change, __super was set to undefined. However, consider that we have two
method overrides---foo and bar---and the code for bar is:

  this.foo();
  this.__super();

foo() would set __super to undefined and so bar cannot invoke its super method
unless it stores a reference to __super before invoking foo(). This patch fixes
this issue.
perfodd
Mike Gerwitz 2013-04-20 21:54:29 -04:00
parent ae172a7a34
commit daae0c6843
No known key found for this signature in database
GPG Key ID: F22BB8158EE30EAB
2 changed files with 28 additions and 7 deletions

View File

@ -34,17 +34,18 @@ exports.standard = {
retval = undefined retval = undefined
; ;
// the _super property will contain the parent method (we don't // the _super property will contain the parent method (store the
// store the previous value for performance reasons and because, // previous value to ensure that calls to multiple overrides will
// during conventional use, it's completely unnecessary) // be supported)
var psup = context.__super;
context.__super = super_method; context.__super = super_method;
retval = method.apply( context, arguments ); retval = method.apply( context, arguments );
// prevent sneaky bastards from breaking encapsulation by stealing // prevent sneaky bastards from breaking encapsulation by stealing
// method references (we set to undefined rather than deleting it // method references and ensure that __super is properly restored
// because deletion causes performance degradation within V8) // for nested/multiple override invocations
context.__super = undefined; context.__super = psup;
// if the value returned from the method was the context that we // if the value returned from the method was the context that we
// passed in, return the actual instance (to ensure we do not break // passed in, return the actual instance (to ensure we do not break

View File

@ -29,6 +29,7 @@ var common = require( './common' ),
// get in the way of our assertions // get in the way of our assertions
hitMethod = false, hitMethod = false,
hitMethod2 = false, hitMethod2 = false,
hitDouble = false,
method2Arg = null, method2Arg = null,
Foo = Class.extend( Foo = Class.extend(
@ -46,6 +47,11 @@ var common = require( './common' ),
return this; return this;
}, },
'virtual double': function()
{
hitDouble = true;
}
}), }),
SubFoo = Foo.extend( SubFoo = Foo.extend(
@ -59,6 +65,14 @@ var common = require( './common' ),
{ {
return this.__super( arg ); return this.__super( arg );
}, },
'override double': function()
{
this.myMethod();
this.__super();
return this;
}
}), }),
foo = new Foo(), foo = new Foo(),
@ -81,7 +95,7 @@ assert.equal(
hitMethod = hitMethod2 = false; hitMethod = hitMethod2 = false;
var arg = 'foobar'; var arg = 'foobar';
sub_foo.myMethod().myMethod2( arg ); sub_foo.myMethod().myMethod2( arg ).double();
// myMethod overrides without calling parent // myMethod overrides without calling parent
assert.equal( assert.equal(
@ -112,3 +126,9 @@ assert['throws']( function()
}); });
}, TypeError, "Methods must be overridden with a Function" ); }, TypeError, "Methods must be overridden with a Function" );
// ensure that __super is not cleared after a call to an override
assert.equal(
hitDouble,
true,
"__super is maintained in a stack-like manner"
);