From 13b0bd2fb323a6623ec9d8526f4595ea511878e9 Mon Sep 17 00:00:00 2001 From: Mike Gerwitz Date: Mon, 7 Jul 2014 00:11:58 -0400 Subject: [PATCH] Visibility object is now encapsulated in symbol key Note that this patch temporarily breaks encapsulation via ClassBuilder.___$$privsym$$ to expose necessary internal details to Trait; this will be resolved. --- lib/ClassBuilder.js | 30 ++++++++++++++++++++---------- lib/Trait.js | 5 ++++- lib/class.js | 25 +++++++++++-------------- lib/interface.js | 5 ++++- 4 files changed, 39 insertions(+), 26 deletions(-) diff --git a/lib/ClassBuilder.js b/lib/ClassBuilder.js index d7d1361..2657e8b 100644 --- a/lib/ClassBuilder.js +++ b/lib/ClassBuilder.js @@ -233,11 +233,11 @@ exports.getForcedPublicMethods = function() * * @param {Function|Object} cls class from which to retrieve metadata * - * @return {__class_meta} + * @return {__class_meta} or null if unavailable */ exports.getMeta = function( cls ) { - return ( cls[ _priv ] || {} ).meta || {}; + return ( cls[ _priv ] || {} ).meta || null; } @@ -338,7 +338,7 @@ exports.prototype.build = function extend( _, __ ) props: this._memberBuilder.initMembers(), }, - meta = exports.getMeta( base ), + meta = exports.getMeta( base ) || {}, abstract_methods = util.clone( meta.abstractMethods ) @@ -387,7 +387,7 @@ exports.prototype.build = function extend( _, __ ) // properties initialized by the ctor are implicitly public; otherwise, // proxying will fail to take place // TODO: see Class.isA TODO - if ( prototype.___$$vis$$ === undefined ) + if ( ( prototype[ _priv ] || {} ).vis === undefined ) { this._discoverProtoProps( prototype, prop_init ); } @@ -1006,7 +1006,8 @@ exports.prototype._attachPropInit = function( inherit = !!inherit; var iid = this.__iid, - parent = prototype.___$$parent$$; + parent = prototype.___$$parent$$, + vis = this[ _priv ].vis; // first initialize the parent's properties, so that ours will overwrite // them @@ -1022,7 +1023,7 @@ exports.prototype._attachPropInit = function( // this will return our property proxy, if supported by our environment, // otherwise just a normal object with everything merged in var inst_props = _self._visFactory.createPropProxy( - this, this.___$$vis$$, properties[ 'public' ] + this, vis, properties[ 'public' ] ); // Copies all public and protected members into inst_props and stores @@ -1030,7 +1031,7 @@ exports.prototype._attachPropInit = function( // chain and is returned. This is stored in a property referenced by the // class id, so that the private members can be swapped on each method // request, depending on calling context. - var vis = this.___$$vis$$[ cid ] = _self._visFactory.setup( + var vis = vis[ cid ] = _self._visFactory.setup( inst_props, properties, members ); @@ -1232,6 +1233,10 @@ exports.prototype.attachStatic = function( ctor, members, base, inheriting ) } +// FIXME: this is *temporary* during refactoring! +module.exports.___$$privsym$$ = _priv; + + /** * Initializes class metadata for the given class * @@ -1325,8 +1330,12 @@ function initInstance( instance ) var prot = function() {}; prot.prototype = instance; + // initialize our *own* private metadata store; do not use the + // prototype's + instance[ _priv ] = {}; + // add the visibility objects to the data object for this class instance - instance.___$$vis$$ = new prot(); + instance[ _priv ].vis = new prot(); } @@ -1380,9 +1389,10 @@ exports.getMethodInstance = function( inst, cid ) } var iid = inst.__iid, - data = inst.___$$vis$$; + priv = inst[ _priv ], + data; - return ( iid && data ) + return ( iid && priv && ( data = priv.vis ) ) ? data[ cid ] : null ; diff --git a/lib/Trait.js b/lib/Trait.js index febefb9..cec7875 100644 --- a/lib/Trait.js +++ b/lib/Trait.js @@ -680,6 +680,9 @@ function addTraitInst( T, dfn, tc, base ) */ function tctor( tc, base ) { + // FIXME: this is temporary during refactoring! + var cbpriv = ClassBuilder.___$$privsym$$; + // instantiate all traits and assign the object to their // respective fields for ( var t in tc ) @@ -693,7 +696,7 @@ function tctor( tc, base ) // (but not private); in return, we will use its own protected // visibility object to gain access to its protected members...quite // the intimate relationship - this[ f ] = C( base, this.___$$vis$$ ).___$$vis$$; + this[ f ] = C( base, this[ cbpriv ].vis )[ cbpriv ].vis; } // if we are a subtype, be sure to initialize our parent's traits diff --git a/lib/class.js b/lib/class.js index cb80559..d7b3884 100644 --- a/lib/class.js +++ b/lib/class.js @@ -169,6 +169,8 @@ var _dummyinst = { constructor: { prototype: {} } }; /** * Determines whether the provided object is a class created through ease.js * + * TODO: delegate to ClassBuilder + * * @param {Object} obj object to test * * @return {boolean} true if class (created through ease.js), otherwise false @@ -182,10 +184,11 @@ module.exports.isClass = function( obj ) return false; } - // TODO: this just checks one of many internal fields; we need something - // more formal (cannot use a strict ClassBase check because it will fail - // when extending prototypes) - return ( ( obj.prototype.___$$vis$$ !== undefined ) + var meta = ClassBuilder.getMeta( obj ); + + // TODO: we're checking a random field on the meta object; do something + // proper + return ( ( ( meta !== null ) && meta.implemented ) || ( obj.prototype instanceof ClassBuilder.ClassBase ) ) ? true : false @@ -197,6 +200,8 @@ module.exports.isClass = function( obj ) * Determines whether the provided object is an instance of a class created * through ease.js * + * TODO: delegate to ClassBuilder + * * @param {Object} obj object to test * * @return {boolean} true if instance of class (created through ease.js), @@ -206,16 +211,8 @@ module.exports.isClassInstance = function( obj ) { obj = obj || _dummyinst; - if ( !obj.constructor || !obj.constructor.prototype ) - { - return false; - } - - // TODO: see isClass TODO - return ( ( obj.constructor.prototype.___$$vis$$ !== undefined ) - || ( obj instanceof ClassBuilder.ClassBase ) ) - ? true - : false; + // if the constructor is a class, then we must be an instance! + return module.exports.isClass( obj.constructor ); }; diff --git a/lib/interface.js b/lib/interface.js index e7a7dff..a8225c0 100644 --- a/lib/interface.js +++ b/lib/interface.js @@ -492,10 +492,13 @@ function attachInstanceOf( iface ) */ function _isInstanceOf( type, instance ) { + // we are interested in the class's metadata, not the instance's + var proto = instance.constructor; + // if no metadata are available, then our remaining checks cannot be // performed var meta; - if ( !instance.__cid || !( meta = ClassBuilder.getMeta( instance ) ) ) + if ( !instance.__cid || !( meta = ClassBuilder.getMeta( proto ) ) ) { return false; }