From 55e993a74d1d0a7657c9f3e8864a71ac04fa34da Mon Sep 17 00:00:00 2001 From: Mike Gerwitz Date: Fri, 7 Mar 2014 01:07:46 -0500 Subject: [PATCH] Non-private properties now expressly prohibited in trait dfns :O What?! See Trait/PropertyTest for more information on why this is the case, at least for now. --- lib/Trait.js | 31 ++++++++++++++++ test/Trait/PropertyTest.js | 73 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 test/Trait/PropertyTest.js diff --git a/lib/Trait.js b/lib/Trait.js index 279297e..31de351 100644 --- a/lib/Trait.js +++ b/lib/Trait.js @@ -118,6 +118,10 @@ Trait.extend = function( dfn ) throw Error( "Traits may not define __construct" ); } + // traits have property restrictions + validateProps( tclass.___$$props$$['public'] ); + validateProps( tclass.___$$props$$['protected'] ); + // invoked to trigger mixin TraitType.__mixin = function( dfn, tc, base ) { @@ -134,6 +138,33 @@ Trait.extend = function( dfn ) }; +/** + * Throws error if non-internal property is found within PROPS + * + * For details and rationale, see the Trait/PropertyTest case. + * + * @param {Object} props properties to prohibit + * + * @return {undefined} + */ +function validateProps( props ) +{ + for ( var f in props ) + { + // ignore internal properties + if ( f.substr( 0, 3 ) === '___' ) + { + continue; + } + + throw Error( + "Cannot define property `" + f + "'; only private " + + "properties are permitted within Trait definitions" + ); + } +} + + Trait.implement = function() { var ifaces = arguments; diff --git a/test/Trait/PropertyTest.js b/test/Trait/PropertyTest.js new file mode 100644 index 0000000..f288841 --- /dev/null +++ b/test/Trait/PropertyTest.js @@ -0,0 +1,73 @@ +/** + * Tests trait properties + * + * Copyright (C) 2014 Mike Gerwitz + * + * This file is part of GNU ease.js. + * + * ease.js is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Or, rather, lack thereof, at least for the time being---this is something + * that is complicated by pre-ES5 fallback and, while a solution is + * possible, it is not performant in the case of a fallback and would muddy + * up ease.js' code. + */ + +require( 'common' ).testCase( +{ + caseSetUp: function() + { + this.Sut = this.require( 'Trait' ); + }, + + + /** + * Since private properties cannot be accessed by anything besides the + * trait itself, they cannot interfere with anything else and should be + * permitted. Indeed, it would be obsurd to think otherwise, since the + * trait should be able to maintain its own local state. + */ + 'Private trait properties are permitted': function() + { + var Sut = this.Sut; + this.assertDoesNotThrow( function() + { + Sut( { 'private _foo': 'bar' } ); + } ); + }, + + + /** + * See the description at the top of this file. This is something that + * may be addressed in future releases. + * + * Rather than simply ignoring them, we should notify the user that + * their code is not going to work as intended and prevent bugs + * associated with it. + */ + 'Public and protected trait properties are prohibited': function() + { + var Sut = this.Sut; + + this.assertThrows( function() + { + Sut( { 'public foo': 'bar' } ); + } ); + + this.assertThrows( function() + { + Sut( { 'protected foo': 'bar' } ); + } ); + }, +} );