From 3c774a7b160e520e11135933744156335caadb32 Mon Sep 17 00:00:00 2001 From: Mike Gerwitz Date: Tue, 10 May 2011 19:54:23 -0400 Subject: [PATCH] Implemented protected static members within static methods - Still not inheritence --- lib/class_builder.js | 24 +++++++++++++----------- test/test-class_builder-static.js | 31 ++++++++++++++++++++++--------- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/lib/class_builder.js b/lib/class_builder.js index e2f2808..171a57e 100644 --- a/lib/class_builder.js +++ b/lib/class_builder.js @@ -234,7 +234,8 @@ exports.build = function extend() } staticInit( new_class, false ); - attachPropInit( prototype, prop_init, members, static_members, class_id ); + initStaticVisibilityObj( new_class, static_members ); + attachPropInit( prototype, prop_init, members, new_class, class_id ); new_class.prototype = prototype; new_class.constructor = new_class; @@ -533,13 +534,13 @@ function buildMembers( * @param {Object} properties properties to initialize * * @param {{public: Object, protected: Object, private: Object}} members - * @param {{public: Object, protected: Object, private: Object}} static_members * - * @param {number} cid class id + * @param {function() ctor class + * @param {number} cid class id * * @return {undefined} */ -function attachPropInit( prototype, properties, members, static_members, cid ) +function attachPropInit( prototype, properties, members, ctor, cid ) { util.defineSecureProp( prototype, '__initProps', function( inherit ) { @@ -575,7 +576,7 @@ function attachPropInit( prototype, properties, members, static_members, cid ) ); // give internal methods access to protected/private static members - initStaticVisibilityObj.call( this, vis, static_members ); + vis.__self = ctor.___$$svis$$; // provide a means to access the actual instance (rather than the // property/visibility object) internally (this will translate to @@ -592,26 +593,25 @@ function attachPropInit( prototype, properties, members, static_members, cid ) /** * Creates and populates the static visibility object * - * This function should be called in the context of the class. + * @param {function()} class * - * @param {Object} vis class visibility object to attach to (override __self) * @param {{public: Object, protected: Object, private: Object}} static_members * * @return {undefined} */ -function initStaticVisibilityObj( vis, static_members ) +function initStaticVisibilityObj( ctor, static_members ) { // the object will simply be another layer in the prototype chain to // prevent protected/private members from being mixed in with the public var sobj = function() {}; - sobj.prototype = this; + sobj.prototype = ctor; var sobji = new sobj(); util.copyTo( sobji, static_members.methods[ 'protected' ] ); // override __self on the instance's visibility object, giving internal // methods access to the restricted static methods - vis.__self = sobji; + ctor.___$$svis$$ = sobji; } @@ -842,7 +842,9 @@ function getMethodInstance( inst, cid ) return ( iid && data ) ? data[ cid ] - : null + : ( inst.___$$svis$$ ) + ? inst.___$$svis$$ + : null ; } diff --git a/test/test-class_builder-static.js b/test/test-class_builder-static.js index 69b6093..32b97d9 100644 --- a/test/test-class_builder-static.js +++ b/test/test-class_builder-static.js @@ -35,17 +35,20 @@ var common = require( './common' ), */ ( function testSelfPropertyReferencesClassDefinition() { - var Foo = builder.build( - { - 'public function test': function() + var val = [ 'baz' ], + Foo = builder.build( { - return this.__self; - }, - } ); + 'public function test': function() + { + return this.__self; + }, + } ); + + Foo.bar = val; // we must use instanceof here because the __self object has the class in // its prototype chain - assert.ok( Foo().test() instanceof Foo, + assert.ok( ( Foo().test().bar === Foo.bar ), "__self property references class definition" ); } )(); @@ -198,7 +201,7 @@ var common = require( './common' ), * available for an instance, it falls back. This serves as a regression test to * ensure this functionality remains. */ -( function testStaticMethodsBoundToClassRatherThanInstance() +( function testStaticMethodsNotBoundToInstance() { var result = null, Foo = builder.build( @@ -212,7 +215,7 @@ var common = require( './common' ), // call the static method Foo.foo(); - assert.deepEqual( result, Foo, + assert.notEqual( result, Foo, "Static members are bound to class definition rather than instance" ); } )(); @@ -445,6 +448,12 @@ var common = require( './common' ), return val; }, + // ensure method is accessible to static methods + 'public static staticBaz': function() + { + return this.baz(); + }, + // ensure method is accessible to instance methods 'public instBaz': function() { @@ -456,6 +465,10 @@ var common = require( './common' ), "Protected methods should not be accessible outside the class" ); + assert.equal( Foo.staticBaz(), val, + "Protected methods are accessible to static methods" + ); + assert.equal( Foo().instBaz(), val, "Protected methods are accessible to instance methods" );