1
0
Fork 0

Began named trait implementation

Does not yet support staging object like classes
perfodd
Mike Gerwitz 2014-02-13 05:21:26 -05:00
parent 26bd6b88dd
commit 8d81373ef8
2 changed files with 136 additions and 3 deletions

View File

@ -30,12 +30,54 @@ function Trait()
case 1: case 1:
return Trait.extend.apply( this, arguments ); return Trait.extend.apply( this, arguments );
break; break;
case 2:
return createNamedTrait.apply( this, arguments );
break;
default:
throw Error( "Missing trait name or definition" );
} }
}; };
/**
* Create a named trait
*
* @param {string} name trait name
* @param {Object} def trait definition
*
* @return {Function} named trait
*/
function createNamedTrait( name, dfn )
{
if ( arguments.length > 2 )
{
throw Error(
"Expecting at most two arguments for definition of named " +
"Trait " + name + "'; " + arguments.length + " given"
);
}
if ( typeof name !== 'string' )
{
throw Error(
"First argument of named class definition must be a string"
);
}
dfn.__name = name;
return Trait.extend( dfn );
}
Trait.extend = function( dfn ) Trait.extend = function( dfn )
{ {
// store any provided name, since we'll be clobbering it (the definition
// object will be used to define the hidden abstract class)
var name = dfn.__name || '(Trait)';
// we need at least one abstract member in order to declare a class as // we need at least one abstract member in order to declare a class as
// abstract (in this case, our trait class), so let's create a dummy one // abstract (in this case, our trait class), so let's create a dummy one
// just in case DFN does not contain any abstract members itself // just in case DFN does not contain any abstract members itself
@ -52,9 +94,13 @@ Trait.extend = function( dfn )
// and here we can see that traits are quite literally abstract classes // and here we can see that traits are quite literally abstract classes
var tclass = AbstractClass( dfn ); var tclass = AbstractClass( dfn );
TraitType.__trait = true; TraitType.__trait = true;
TraitType.__acls = tclass; TraitType.__acls = tclass;
TraitType.__ccls = null; TraitType.__ccls = null;
TraitType.toString = function()
{
return ''+name;
};
// traits are not permitted to define constructors // traits are not permitted to define constructors
if ( tclass.___$$methods$$['public'].__construct !== undefined ) if ( tclass.___$$methods$$['public'].__construct !== undefined )

View File

@ -0,0 +1,87 @@
/**
* Tests named trait definitions
*
* 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 <http://www.gnu.org/licenses/>.
*/
require( 'common' ).testCase(
{
caseSetUp: function()
{
this.Sut = this.require( 'Trait' );
this.Class = this.require( 'class' );
},
/**
* If a trait is not given a name, then converting it to a string should
* indicate that it is anonymous. Further, to disambiguate from
* anonymous classes, we should further indicate that it is a trait.
*
* This test is fragile in the sense that it tests for an explicit
* string: this is intended, since some developers may rely on this
* string (even though they really should use Trait.isTrait), and so it
* should be explicitly documented.
*/
'Anonymous trait is properly indicated when converted to string':
function()
{
var given = this.Sut( {} ).toString();
this.assertEqual( given, '(Trait)' );
},
/**
* Analagous to named classes: we should provide the name when
* converting to a string to aid in debugging.
*/
'Named trait contains name when converted to string': function()
{
var name = 'FooTrait',
T = this.Sut( name, {} );
this.assertOk( T.toString().match( name ) );
},
/**
* We assume that, if two or more arguments are provided, that the
* definition is named.
*/
'Named trait definition cannot contain zero or more than two arguments':
function()
{
var Sut = this.Sut;
this.assertThrows( function() { Sut(); } );
this.assertThrows( function() { Sut( 1, 2, 3 ); } );
},
/**
* Operating on the same assumption as the above test.
*/
'First argument in named trait definition must be a string':
function()
{
var Sut = this.Sut;
this.assertThrows( function()
{
Sut( {}, {} );
} );
},
} );