1
0
Fork 0

Added support for static proxy methods

When the static keyword is provided, the proxy will use the static accessor
method to look up the requested member.
perfodd
Mike Gerwitz 2012-05-03 14:13:47 -04:00
parent d84b86b21b
commit e67c14e8c3
No known key found for this signature in database
GPG Key ID: F22BB8158EE30EAB
6 changed files with 76 additions and 16 deletions

View File

@ -133,7 +133,12 @@ exports.buildMethod = function(
// we might be overriding an existing method
if ( keywords[ 'proxy' ] )
{
dest[ name ] = this._createProxy( value, instCallback, cid, name );
// TODO: Note that this is not compatible with method hiding, due to its
// positioning (see hideMethod() below); address once method hiding is
// implemented (the validators currently handle everything else)
dest[ name ] = this._createProxy(
value, instCallback, cid, name, keywords
);
}
else if ( prev )
{
@ -375,13 +380,14 @@ function hideMethod( super_method, new_method, instCallback, cid )
*
* @param {number} cid class id
* @param {string} mname name of method to invoke on destination object
* @param {Object} keywords method keywords
*
* @return {Function} proxy method
*/
exports._createProxy = function( proxy_to, instCallback, cid, mname )
exports._createProxy = function( proxy_to, instCallback, cid, mname, keywords )
{
return this._wrapProxy.wrapMethod(
proxy_to, null, cid, instCallback, mname
proxy_to, null, cid, instCallback, mname, keywords
);
};

View File

@ -56,11 +56,12 @@ module.exports = exports = function MethodWrapperFactory( factory )
* @param {function()} getInst function to determine instance and return
* associated visibility object
* @param {string=} name name of method
* @param {Object=} keywords method keywords
*/
exports.prototype.wrapMethod = function(
method, super_method, cid, getInst, name
method, super_method, cid, getInst, name, keywords
)
{
return this._factory( method, super_method, cid, getInst, name );
return this._factory( method, super_method, cid, getInst, name, keywords );
};

View File

@ -83,21 +83,29 @@ exports.standard = {
},
wrapProxy: function( proxy_to, _, cid, getInst, name )
wrapProxy: function( proxy_to, _, cid, getInst, name, keywords )
{
// it is important that we store only a boolean value as to whether or
// not this method is static *outside* of the returned closure, so as
// not to keep an unnecessary reference to the keywords object
var is_static = keywords && keywords[ 'static' ];
return function()
{
var context = getInst( this, cid ) || this,
retval = undefined,
dest = context[ proxy_to ]
dest = ( ( is_static )
? context.$( proxy_to )
: context[ proxy_to ]
)
;
// rather than allowing a cryptic error to be thrown, attempt to
// detect when the proxy call will fail and provide a useful error
// message
if ( ( typeof dest !== 'object' )
|| ( typeof dest[ name ] !== 'function' )
)
if ( !( ( dest !== null ) && ( typeof dest === 'object' )
&& ( typeof dest[ name ] === 'function' )
) )
{
throw TypeError(
"Unable to proxy " + name + "() call to '" + proxy_to +

View File

@ -170,7 +170,7 @@ require( 'common' ).testCase(
);
this.assertDeepEqual(
[ value, null, cid, instCallback, name ],
[ value, null, cid, instCallback, name, keywords ],
this.proxyFactoryCall,
"Proxy factory should be called with proper arguments"
);

View File

@ -65,11 +65,13 @@ var common = require( './common' ),
cid = 55,
getInst = function() {},
name = 'someMethod',
keywords = { 'static': true, 'public': true },
retval = 'foobar';
var result = Sut(
function(
given_method, given_super, given_cid, givenGetInst, givenName
given_method, given_super, given_cid, givenGetInst, given_name,
given_keywords
)
{
called = true;
@ -90,13 +92,17 @@ var common = require( './common' ),
"Factory method should be provided with proper inst function"
);
assert.equal( givenName, name,
assert.equal( given_name, name,
"Factory method should be provided with proper method name"
);
assert.equal( given_keywords, keywords,
"Factory method should be provided with proper keywords"
);
return retval;
}
).wrapMethod( method, super_method, cid, getInst, name );
).wrapMethod( method, super_method, cid, getInst, name, keywords );
// we'll include this in addition to the following assertion (which is
// redundant) to make debugging more clear

View File

@ -342,3 +342,42 @@ function proxyErrorAssertCommon( e, prop, method )
);
} )();
/**
* If the `static' keyword is provided, then the proxy mustn't operate on
* instance properties. Instead, the static accessor method $() must be used.
*/
( function testCanProxyToStaticMembers()
{
var getInst = function()
{
// pretend that we're a static class with a static accessor method
return {
$: function( name )
{
// implicitly tests that the argument is properly passed
// (would otherwise return `undefined`)
return s[ name ];
},
};
},
keywords = { 'static': true };
val = [ 'value' ],
s = {
// destination object
foo: {
method: function()
{
return val;
},
}
};
assert.strictEqual( val,
sut.standard.wrapProxy( 'foo', null, 0, getInst, 'method', keywords )(),
"Should properly proxy to static membesr via static accessor method"
);
} )();