From a246dd67e0207c75ee05debca3669f78b71e55c9 Mon Sep 17 00:00:00 2001 From: Mike Gerwitz Date: Mon, 9 May 2011 23:09:32 -0400 Subject: [PATCH] Began adding protected static members (supported for instance methods) - No inheritance support yet --- lib/class_builder.js | 36 ++++++++++++++++++++++++++++--- test/test-class_builder-static.js | 36 ++++++++++++++++++++++++++++++- 2 files changed, 68 insertions(+), 4 deletions(-) diff --git a/lib/class_builder.js b/lib/class_builder.js index 39c18de..e2f2808 100644 --- a/lib/class_builder.js +++ b/lib/class_builder.js @@ -234,7 +234,7 @@ exports.build = function extend() } staticInit( new_class, false ); - attachPropInit( prototype, prop_init, members, class_id ); + attachPropInit( prototype, prop_init, members, static_members, class_id ); new_class.prototype = prototype; new_class.constructor = new_class; @@ -533,12 +533,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 {number} cid class id * * @return {undefined} */ -function attachPropInit( prototype, properties, members, cid ) +function attachPropInit( prototype, properties, members, static_members, cid ) { util.defineSecureProp( prototype, '__initProps', function( inherit ) { @@ -573,6 +574,9 @@ function attachPropInit( prototype, properties, members, cid ) inst_props, properties, members ); + // give internal methods access to protected/private static members + initStaticVisibilityObj.call( this, vis, static_members ); + // provide a means to access the actual instance (rather than the // property/visibility object) internally (this will translate to // this.__inst from within a method), but only if we're on our final @@ -585,6 +589,32 @@ function attachPropInit( prototype, properties, members, cid ) } +/** + * Creates and populates the static visibility object + * + * This function should be called in the context of the 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 ) +{ + // 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; + + 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; +} + + /** * Attaches static members to a constructor (class) * diff --git a/test/test-class_builder-static.js b/test/test-class_builder-static.js index 7afac76..69b6093 100644 --- a/test/test-class_builder-static.js +++ b/test/test-class_builder-static.js @@ -43,7 +43,9 @@ var common = require( './common' ), }, } ); - assert.deepEqual( Foo().test(), Foo, + // we must use instanceof here because the __self object has the class in + // its prototype chain + assert.ok( Foo().test() instanceof Foo, "__self property references class definition" ); } )(); @@ -427,3 +429,35 @@ var common = require( './common' ), ); } )(); + +/** + * Protected members should be available from within the class but shouldn't be + * exposed to the world + */ +( function testProtectedStaticMembersAreAvailableInsideClassOnly() +{ + var val = 'foo', + Foo = builder.build( + { + // the same rules should apply to methods + 'protected static baz': function() + { + return val; + }, + + // ensure method is accessible to instance methods + 'public instBaz': function() + { + return this.__self.baz(); + }, + } ); + + assert.equal( Foo.baz, undefined, + "Protected methods should not be accessible outside the class" + ); + + assert.equal( Foo().instBaz(), val, + "Protected methods are accessible to instance methods" + ); +} )(); +