1
0
Fork 0

Initial concept for protected static property access

closure/master
Mike Gerwitz 2011-05-12 00:05:50 -04:00
parent 9067bbf0cf
commit 9b20cdff48
2 changed files with 73 additions and 6 deletions

View File

@ -52,6 +52,15 @@ var util = require( __dirname + '/util' ),
*/ */
extending = false, extending = false,
/**
* A flag to let the system know that we are currently attempting to access
* a static property from within a method. This means that the caller should
* be given access to additional levels of visibility.
*
* @type {boolean}
*/
sprop_internal = false,
/** /**
* Hash of reserved members * Hash of reserved members
* *
@ -619,6 +628,19 @@ function initStaticVisibilityObj( ctor, static_members )
// override __self on the instance's visibility object, giving internal // override __self on the instance's visibility object, giving internal
// methods access to the restricted static methods // methods access to the restricted static methods
ctor.___$$svis$$ = sobji; ctor.___$$svis$$ = sobji;
// Override the class-level accessor method to allow the system to know we
// are within a method. An internal flag is necessary, rather than using an
// argument or binding, because those two options are exploitable. An
// internal flag cannot be modified by conventional means.
sobji.$ = function()
{
sprop_internal = true;
var val = ctor.$.apply( ctor, arguments );
sprop_internal = false;
return val;
};
} }
@ -666,17 +688,26 @@ function attachStatic( ctor, members, base, inheriting )
// we use hasOwnProperty to ensure that undefined values will not // we use hasOwnProperty to ensure that undefined values will not
// cause us to continue checking the parent, thereby potentially // cause us to continue checking the parent, thereby potentially
// failing to set perfectly legal values // failing to set perfectly legal values
var has = Object.prototype.hasOwnProperty.call( var has = Object.prototype.hasOwnProperty,
props[ 'public' ], prop found = false,
),
// Determine if we were invoked in the context of a class. If // Determine if we were invoked in the context of a class. If
// so, use that. Otherwise, use ourself. // so, use that. Otherwise, use ourself.
context = ( this.___$$sprops$$ ) ? this : ctor context = ( this.___$$sprops$$ ) ? this : ctor
; ;
// Attempt to locate the property. First, we check public. If not
// available and we are internal (within a method), we can move on
// to check other levels of visibility. `found` will contain the
// visibility level the property was found in, or false.
found = has.call( props[ 'public' ], prop ) && 'public';
if ( !found && sprop_internal )
{
found = has.call( props[ 'protected' ], prop ) && 'protected';
}
// if we don't own the property, let the parent(s) handle it // if we don't own the property, let the parent(s) handle it
if ( !has ) if ( found === false )
{ {
return base.$.apply( context, arguments ); return base.$.apply( context, arguments );
} }
@ -686,13 +717,13 @@ function attachStatic( ctor, members, base, inheriting )
// arguments.length to ensure that setting to undefined works) // arguments.length to ensure that setting to undefined works)
if ( arguments.length > 1 ) if ( arguments.length > 1 )
{ {
props[ 'public' ][ prop ] = val; props[ found ][ prop ] = val;
return context; return context;
} }
else else
{ {
// return the value // return the value
return props[ 'public' ][ prop ]; return props[ found ][ prop ];
} }
} ); } );
} }

View File

@ -464,6 +464,9 @@ var common = require( './common' ),
var val = 'foo', var val = 'foo',
Foo = builder.build( Foo = builder.build(
{ {
'protected static prop': val,
// the same rules should apply to methods // the same rules should apply to methods
'protected static baz': function() 'protected static baz': function()
{ {
@ -481,6 +484,16 @@ var common = require( './common' ),
{ {
return this.__self.baz(); return this.__self.baz();
}, },
'public static staticGetProp': function()
{
return this.$('prop');
},
'public instGetProp': function()
{
return this.__self.$('prop');
},
} ); } );
assert.equal( Foo.baz, undefined, assert.equal( Foo.baz, undefined,
@ -494,6 +507,14 @@ var common = require( './common' ),
assert.equal( Foo().instBaz(), val, assert.equal( Foo().instBaz(), val,
"Protected methods are accessible to instance methods" "Protected methods are accessible to instance methods"
); );
assert.equal( Foo.staticGetProp(), val,
"Protected static properties are accessible to static methods"
);
assert.equal( Foo().instGetProp(), val,
"Protected static properties are accessible to instance methods"
);
} )(); } )();
@ -507,6 +528,8 @@ var common = require( './common' ),
val2 = 'bazbaz', val2 = 'bazbaz',
Foo = builder.build( Foo = builder.build(
{ {
'protected static prop': val,
'protected static foo': function() 'protected static foo': function()
{ {
return val; return val;
@ -529,6 +552,11 @@ var common = require( './common' ),
{ {
return this.foo2(); return this.foo2();
}, },
'public static getProp': function()
{
return this.$('prop');
},
} ), } ),
SubSubFoo = builder.build( SubFoo, {} ) SubSubFoo = builder.build( SubFoo, {} )
@ -546,6 +574,14 @@ var common = require( './common' ),
assert.equal( SubSubFoo.bar(), val, assert.equal( SubSubFoo.bar(), val,
"Sub-subtypes inherit parents' protected static methods" "Sub-subtypes inherit parents' protected static methods"
); );
assert.equal( SubFoo.getProp(), val,
"Subtypes inherit parents' protected static properties"
);
assert.equal( SubSubFoo.getProp(), val,
"Sub-subtypes inherit parents' protected static properties"
);
} )(); } )();