Method builder wraps overrides in an override function
parent
e03d5861bb
commit
96d2f74dae
|
@ -22,7 +22,8 @@
|
|||
* @package core
|
||||
*/
|
||||
|
||||
var visibility = [ 'public', 'protected', 'private' ];
|
||||
var util = require( './util' ),
|
||||
visibility = [ 'public', 'protected', 'private' ];
|
||||
|
||||
|
||||
/**
|
||||
|
@ -74,7 +75,7 @@ exports.buildMethod = function( members, meta, name, value, keywords )
|
|||
}
|
||||
|
||||
// ensure parameter list is at least the length of its supertype
|
||||
if ( prev && (value.length < prev.length ) )
|
||||
if ( prev && ( value.length < ( prev.__length || prev.length ) ) )
|
||||
{
|
||||
throw new TypeError(
|
||||
"Declaration of method '" + name + "' must be compatiable " +
|
||||
|
@ -82,7 +83,19 @@ exports.buildMethod = function( members, meta, name, value, keywords )
|
|||
);
|
||||
}
|
||||
|
||||
getMemberVisibility( members, keywords )[ name ] = value;
|
||||
var dest = getMemberVisibility( members, keywords );
|
||||
|
||||
// we might be overriding an existing method
|
||||
if ( prev )
|
||||
{
|
||||
// override the method
|
||||
dest[ name ] = overrideMethod( prev, value );
|
||||
}
|
||||
else
|
||||
{
|
||||
// we are not overriding the method, so simply copy it over
|
||||
dest[ name ] = value;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -220,3 +233,46 @@ function scanMembers( members, name )
|
|||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates a method override function
|
||||
*
|
||||
* The override function simply wraps the method so that its invocation will
|
||||
* pass a __super property. This property may be used to invoke the overridden
|
||||
* method.
|
||||
*
|
||||
* @param {function()} super_method method to override
|
||||
* @param {function()} new_method method to override with
|
||||
*
|
||||
* @return {function()} override method
|
||||
*/
|
||||
function overrideMethod( super_method, new_method )
|
||||
{
|
||||
// return a function that permits referencing the super method via the
|
||||
// __super property
|
||||
var override = function()
|
||||
{
|
||||
var tmp = this.__super;
|
||||
|
||||
// assign _super temporarily for the method invocation so
|
||||
// that the method can call the parent method
|
||||
this.__super = super_method;
|
||||
var retval = new_method.apply( this, arguments );
|
||||
this.__super = tmp;
|
||||
|
||||
return retval;
|
||||
};
|
||||
|
||||
// This is a trick to work around the fact that we cannot set the length
|
||||
// property of a function. Instead, we define our own property - __length.
|
||||
// This will store the expected number of arguments from the super method.
|
||||
// This way, when a method is being overridden, we can check to ensure its
|
||||
// compatibility with its super method.
|
||||
util.defineSecureProp( override,
|
||||
'__length',
|
||||
( super_method.__length || super_method.length )
|
||||
);
|
||||
|
||||
return override;
|
||||
}
|
||||
|
||||
|
|
|
@ -89,3 +89,48 @@ mb_common.assertCommon();
|
|||
}, TypeError, "Method cannot have lesser number of parameters" );
|
||||
} )();
|
||||
|
||||
|
||||
/**
|
||||
* The __super property is defined for method overrides and permits invoking the
|
||||
* overridden method (method of the supertype).
|
||||
*
|
||||
* In this test, we are not looking to assert that __super matches the super
|
||||
* method. Rather, we want to ensure it /invokes/ it. This is because the super
|
||||
* method may be wrapped to provide additional functionality. We don't know, we
|
||||
* don't care. We just want to make sure it's functioning properly.
|
||||
*/
|
||||
( function testOverridenMethodShouldContainReferenceToSuperMethod()
|
||||
{
|
||||
var orig_called = false;
|
||||
|
||||
// "super" method
|
||||
mb_common.value = function()
|
||||
{
|
||||
orig_called = true;
|
||||
};
|
||||
|
||||
mb_common.buildMemberQuick();
|
||||
|
||||
// override method
|
||||
mb_common.value = function()
|
||||
{
|
||||
assert.notEqual(
|
||||
this.__super,
|
||||
undefined,
|
||||
"__super is defined for overridden method"
|
||||
);
|
||||
|
||||
this.__super();
|
||||
assert.equal(
|
||||
orig_called,
|
||||
true,
|
||||
"Invoking __super calls super method"
|
||||
);
|
||||
};
|
||||
|
||||
mb_common.buildMemberQuick( {}, true );
|
||||
|
||||
// invoke the method
|
||||
mb_common.members[ 'public' ][ mb_common.name ]();
|
||||
} )();
|
||||
|
||||
|
|
Loading…
Reference in New Issue