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
parent
d84b86b21b
commit
e67c14e8c3
|
@ -133,7 +133,12 @@ exports.buildMethod = function(
|
||||||
// we might be overriding an existing method
|
// we might be overriding an existing method
|
||||||
if ( keywords[ 'proxy' ] )
|
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 )
|
else if ( prev )
|
||||||
{
|
{
|
||||||
|
@ -375,13 +380,14 @@ function hideMethod( super_method, new_method, instCallback, cid )
|
||||||
*
|
*
|
||||||
* @param {number} cid class id
|
* @param {number} cid class id
|
||||||
* @param {string} mname name of method to invoke on destination object
|
* @param {string} mname name of method to invoke on destination object
|
||||||
|
* @param {Object} keywords method keywords
|
||||||
*
|
*
|
||||||
* @return {Function} proxy method
|
* @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(
|
return this._wrapProxy.wrapMethod(
|
||||||
proxy_to, null, cid, instCallback, mname
|
proxy_to, null, cid, instCallback, mname, keywords
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -56,11 +56,12 @@ module.exports = exports = function MethodWrapperFactory( factory )
|
||||||
* @param {function()} getInst function to determine instance and return
|
* @param {function()} getInst function to determine instance and return
|
||||||
* associated visibility object
|
* associated visibility object
|
||||||
* @param {string=} name name of method
|
* @param {string=} name name of method
|
||||||
|
* @param {Object=} keywords method keywords
|
||||||
*/
|
*/
|
||||||
exports.prototype.wrapMethod = function(
|
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 );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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()
|
return function()
|
||||||
{
|
{
|
||||||
var context = getInst( this, cid ) || this,
|
var context = getInst( this, cid ) || this,
|
||||||
retval = undefined,
|
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
|
// rather than allowing a cryptic error to be thrown, attempt to
|
||||||
// detect when the proxy call will fail and provide a useful error
|
// detect when the proxy call will fail and provide a useful error
|
||||||
// message
|
// message
|
||||||
if ( ( typeof dest !== 'object' )
|
if ( !( ( dest !== null ) && ( typeof dest === 'object' )
|
||||||
|| ( typeof dest[ name ] !== 'function' )
|
&& ( typeof dest[ name ] === 'function' )
|
||||||
)
|
) )
|
||||||
{
|
{
|
||||||
throw TypeError(
|
throw TypeError(
|
||||||
"Unable to proxy " + name + "() call to '" + proxy_to +
|
"Unable to proxy " + name + "() call to '" + proxy_to +
|
||||||
|
|
|
@ -170,7 +170,7 @@ require( 'common' ).testCase(
|
||||||
);
|
);
|
||||||
|
|
||||||
this.assertDeepEqual(
|
this.assertDeepEqual(
|
||||||
[ value, null, cid, instCallback, name ],
|
[ value, null, cid, instCallback, name, keywords ],
|
||||||
this.proxyFactoryCall,
|
this.proxyFactoryCall,
|
||||||
"Proxy factory should be called with proper arguments"
|
"Proxy factory should be called with proper arguments"
|
||||||
);
|
);
|
||||||
|
|
|
@ -65,11 +65,13 @@ var common = require( './common' ),
|
||||||
cid = 55,
|
cid = 55,
|
||||||
getInst = function() {},
|
getInst = function() {},
|
||||||
name = 'someMethod',
|
name = 'someMethod',
|
||||||
|
keywords = { 'static': true, 'public': true },
|
||||||
retval = 'foobar';
|
retval = 'foobar';
|
||||||
|
|
||||||
var result = Sut(
|
var result = Sut(
|
||||||
function(
|
function(
|
||||||
given_method, given_super, given_cid, givenGetInst, givenName
|
given_method, given_super, given_cid, givenGetInst, given_name,
|
||||||
|
given_keywords
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
called = true;
|
called = true;
|
||||||
|
@ -90,13 +92,17 @@ var common = require( './common' ),
|
||||||
"Factory method should be provided with proper inst function"
|
"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"
|
"Factory method should be provided with proper method name"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assert.equal( given_keywords, keywords,
|
||||||
|
"Factory method should be provided with proper keywords"
|
||||||
|
);
|
||||||
|
|
||||||
return retval;
|
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
|
// we'll include this in addition to the following assertion (which is
|
||||||
// redundant) to make debugging more clear
|
// redundant) to make debugging more clear
|
||||||
|
|
|
@ -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"
|
||||||
|
);
|
||||||
|
} )();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue