From 47d51fd5da809c5b1e842557a99dcbc4b3457785 Mon Sep 17 00:00:00 2001 From: Mike Gerwitz Date: Sun, 25 Oct 2015 22:15:34 -0400 Subject: [PATCH] Provide useful error on attempt to mix in non-trait Before this change, mixin attempts would fail at the time of mixin when easejs attempts to invoke the `__mixin` method on the object. This is both cryptic and void of any useful information on the stack. --- lib/class.js | 28 ++++++++++++++++++++++++++++ test/Trait/DefinitionTest.js | 26 ++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/lib/class.js b/lib/class.js index 8096f02..1fc788c 100644 --- a/lib/class.js +++ b/lib/class.js @@ -486,9 +486,13 @@ function createImplement( base, ifaces, cname ) * with implicit extend) * * @return {Function} staging object for mixin + * + * @throws {TypeError} when object is not a trait */ function createUse( basef, traits, nonbase ) { + _validateTraits( traits ); + // invoking the partially applied class will immediately complete its // definition and instantiate it with the provided constructor arguments var partial = function() @@ -575,6 +579,30 @@ function createUse( basef, traits, nonbase ) } +/** + * Verify that each object in TRAITS will be able to be mixed in + * + * TODO: Use Trait.isTrait; we have circular dependency issues at the moment + * preventing that; refactoring is needed. + * + * @param {Array} traits objects to validate + * + * @return {undefined} + * + * @throws {TypeError} when object is not a trait + */ +function _validateTraits( traits ) +{ + for ( var t in traits ) + { + if ( typeof traits[ t ].__mixin !== 'function' ) + { + throw TypeError( "Cannot mix in non-trait " + t ); + } + } +} + + function createMixedClass( base, traits ) { // generated definition for our [abstract] class that will mix in each diff --git a/test/Trait/DefinitionTest.js b/test/Trait/DefinitionTest.js index 0402924..e3ffe53 100644 --- a/test/Trait/DefinitionTest.js +++ b/test/Trait/DefinitionTest.js @@ -475,4 +475,30 @@ require( 'common' ).testCase( this.Class.isClass( this.Class( {} ).use( T ) ) ); }, + + + /** + * Attempts to mix in non-traits should immediately trigger an error + * during the declaration. It is important not to defer this until the + * time of actual mix in---which is lazy---since the stack will not + * provide useful information on how to correct it. + */ + 'Throws error when object to mix in is not a trait': function() + { + var _self = this; + + // one of one + this.assertThrows( function() + { + // this should error immediately; it should not wait until + // the actual mix in (which is lazy) + _self.Class( {} ).use( {} ); + }, TypeError ); + + // one of many + this.assertThrows( function() + { + _self.Class( {} ).use( _self.Trait( {} ), {} ); + }, TypeError ); + }, } );