Method builder wraps overrides in an override function
parent
e03d5861bb
commit
96d2f74dae
|
@ -22,7 +22,8 @@
|
||||||
* @package core
|
* @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
|
// 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(
|
throw new TypeError(
|
||||||
"Declaration of method '" + name + "' must be compatiable " +
|
"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;
|
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" );
|
}, 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