diff --git a/lib/ClassBuilder.js b/lib/ClassBuilder.js index 8947f11..c736808 100644 --- a/lib/ClassBuilder.js +++ b/lib/ClassBuilder.js @@ -338,7 +338,7 @@ exports.prototype.build = function extend( _, __ ) // increment class identifier this._classId++; - // build the various class components (xxx: this is temporary; needs + // build the various class components (XXX: this is temporary; needs // refactoring) try { @@ -464,8 +464,11 @@ exports.prototype.buildMembers = function buildMembers( } // if a member was defined multiple times in the same class - // declaration, throw an error - if ( hasOwn.call( defs, name ) ) + // declaration, throw an error (unless the `weak' keyword is + // provided, which exists to accomodate this situation) + if ( hasOwn.call( defs, name ) + && !( keywords['weak'] || defs[ name ].weak ) + ) { throw Error( "Cannot redefine method '" + name + "' in same declaration" @@ -474,7 +477,7 @@ exports.prototype.buildMembers = function buildMembers( // keep track of the definitions (only during class declaration) // to catch duplicates - defs[ name ] = 1; + defs[ name ] = keywords; }, property: function( name, value, keywords ) diff --git a/lib/prop_parser.js b/lib/prop_parser.js index 3c36b0a..c3f3bbb 100644 --- a/lib/prop_parser.js +++ b/lib/prop_parser.js @@ -33,6 +33,7 @@ var _keywords = { 'virtual': true, 'override': true, 'proxy': true, + 'weak': true, }; diff --git a/test/ClassBuilder/MemberRestrictionTest.js b/test/ClassBuilder/MemberRestrictionTest.js index 7643249..5cf7020 100644 --- a/test/ClassBuilder/MemberRestrictionTest.js +++ b/test/ClassBuilder/MemberRestrictionTest.js @@ -23,8 +23,18 @@ require( 'common' ).testCase( { caseSetUp: function() { - this.Class = this.require( 'class' ); - this.Sut = this.require( 'ClassBuilder' ); + // XXX: the Sut is not directly tested; get rid of these! + this.Class = this.require( 'class' ); + this.AbstractClass = this.require( 'class_abstract' ); + + this.Sut = this.require( 'ClassBuilder' ); + + // weak flag test data + this.weak = [ + [ 'weak foo', 'foo' ], // former weak + [ 'foo', 'weak foo' ], // latter weak + [ 'weak foo', 'weak foo' ], // both weak + ]; }, @@ -227,4 +237,55 @@ require( 'common' ).testCase( }, Error, "Forced-public methods must be declared as public" ); } }, + + + /** + * If different keywords are used, then a definition object could + * contain two members of the same name. This is probably a bug in the + * user's implementation, so we should flip our shit. + * + * But, see the next test. + */ + 'Cannot define two members of the same name': function() + { + var _self = this; + this.assertThrows( function() + { + // duplicate foos + _self.Class( + { + 'public foo': function() {}, + 'protected foo': function() {}, + } ); + } ); + }, + + + /** + * Code generation tools may find it convenient to declare a duplicate + * member without knowing whether or not a duplicate will exist; this + * may save time and complexity when ease.js has been designed to handle + * certain situations. If at least one of the conflicting members has + * been flagged as `weak', then we should ignore the error. + * + * As an example, this is used interally with ease.js to inherit + * abstract members from traits while still permitting concrete + * definitions. + */ + '@each(weak) Can define members of the same name if one is weak': + function( weak ) + { + // TODO: this makes assumptions about how the code works; the code + // needs to be refactored to permit more sane testing (since right + // now it'd be a clusterfuck) + var dfn = {}; + dfn[ 'abstract ' + weak[ 0 ] ] = []; + dfn[ 'abstract ' + weak[ 1 ] ] = []; + + var _self = this; + this.assertDoesNotThrow( function() + { + _self.AbstractClass( dfn ); + } ); + }, } ); diff --git a/test/PropParserKeywordsTest.js b/test/PropParserKeywordsTest.js index 0225d21..0680660 100644 --- a/test/PropParserKeywordsTest.js +++ b/test/PropParserKeywordsTest.js @@ -100,7 +100,7 @@ require( 'common' ).testCase( parse( 'public protected private ' + 'virtual abstract override ' + - 'static const proxy ' + + 'static const proxy weak ' + 'var' ); }, Error );