Merge branch 'master' into visibility/master
commit
dca7653adf
80
lib/class.js
80
lib/class.js
|
@ -53,52 +53,60 @@ var class_instance = {};
|
|||
* use the class's extend() method. If unavailable (or extending a non-ease.js
|
||||
* class/object), use the module's extend() method.
|
||||
*
|
||||
* @param {Object} def class definition
|
||||
* @param {string=} name optional name
|
||||
* @param {Object} def class definition
|
||||
*
|
||||
* @return {Class} new class
|
||||
*/
|
||||
module.exports = function()
|
||||
{
|
||||
var def = {},
|
||||
name = '';
|
||||
name = '',
|
||||
type = typeof arguments[ 0 ]
|
||||
;
|
||||
|
||||
// anonymous class
|
||||
if ( typeof arguments[ 0 ] === 'object' )
|
||||
switch ( type )
|
||||
{
|
||||
def = arguments[ 0 ];
|
||||
// anonymous class
|
||||
case 'object':
|
||||
def = arguments[ 0 ];
|
||||
|
||||
// ensure we have the proper number of arguments (if they passed in too
|
||||
// many, it may signify that they don't know what they're doing, and likely
|
||||
// they're not getting the result they're looking for)
|
||||
if ( arguments.length > 1 )
|
||||
{
|
||||
throw Error(
|
||||
"Expecting one argument for Class definition; " +
|
||||
arguments.length + " given."
|
||||
// ensure we have the proper number of arguments (if they passed in
|
||||
// too many, it may signify that they don't know what they're doing,
|
||||
// and likely they're not getting the result they're looking for)
|
||||
if ( arguments.length > 1 )
|
||||
{
|
||||
throw Error(
|
||||
"Expecting one argument for Class definition; " +
|
||||
arguments.length + " given."
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// named class
|
||||
case 'string':
|
||||
name = arguments[ 0 ];
|
||||
def = arguments[ 1 ];
|
||||
|
||||
// add the name to the definition
|
||||
def.__name = name;
|
||||
|
||||
// the definition must be an object
|
||||
if ( typeof def !== 'object' )
|
||||
{
|
||||
throw TypeError(
|
||||
"Unexpected value for named class definition"
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
// we don't know what to do!
|
||||
throw TypeError(
|
||||
"Expecting anonymous class definition or named class definition"
|
||||
);
|
||||
}
|
||||
}
|
||||
// named class
|
||||
else if ( typeof arguments[ 0 ] === 'string' )
|
||||
{
|
||||
name = arguments[ 0 ];
|
||||
def = arguments[ 1 ];
|
||||
|
||||
// add the name to the definition
|
||||
def.__name = name;
|
||||
|
||||
// the definition must be an object
|
||||
if ( typeof def !== 'object' )
|
||||
{
|
||||
throw TypeError( "Unexpected value for named class definition" );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// we don't know what to do!
|
||||
throw TypeError(
|
||||
"Expecting anonymous class definition or named class definition"
|
||||
);
|
||||
}
|
||||
|
||||
return extend( def );
|
||||
|
|
105
lib/interface.js
105
lib/interface.js
|
@ -35,29 +35,53 @@ var util = require( './util' ),
|
|||
* extended. To extend an existing interface, call its extend() method, or use
|
||||
* the extend() method of this module.
|
||||
*
|
||||
* @param {Object} def interface definition
|
||||
* @param {string=} name optional name
|
||||
* @param {Object} def interface definition
|
||||
*
|
||||
* @return {Interface} new interface
|
||||
*/
|
||||
module.exports = function( def )
|
||||
module.exports = function()
|
||||
{
|
||||
// if the first argument is an object, then we are declaring an interface
|
||||
if ( typeof def !== 'object' )
|
||||
{
|
||||
throw TypeError(
|
||||
"Must provide interface definition when declaring interface"
|
||||
);
|
||||
}
|
||||
var def = {},
|
||||
name = '',
|
||||
type = typeof arguments[ 0 ]
|
||||
;
|
||||
|
||||
// ensure we have the proper number of arguments (if they passed in too
|
||||
// many, it may signify that they don't know what they're doing, and likely
|
||||
// they're not getting the result they're looking for)
|
||||
if ( arguments.length > 1 )
|
||||
switch ( type )
|
||||
{
|
||||
throw Error(
|
||||
"Expecting one argument for Interface definition; " +
|
||||
arguments.length + " given."
|
||||
);
|
||||
// anonymous interface
|
||||
case 'object':
|
||||
def = arguments[ 0 ];
|
||||
|
||||
// ensure we have the proper number of arguments (if they passed in
|
||||
// too many, it may signify that they don't know what they're doing,
|
||||
// and likely they're not getting the result they're looking for)
|
||||
if ( arguments.length > 1 )
|
||||
{
|
||||
throw Error(
|
||||
"Expecting one argument for Interface definition; " +
|
||||
arguments.length + " given."
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// named class
|
||||
case 'string':
|
||||
name = arguments[ 0 ];
|
||||
def = arguments[ 1 ];
|
||||
|
||||
// add the name to the definition
|
||||
def.__name = name;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
// we don't know what to do!
|
||||
throw TypeError(
|
||||
"Expecting anonymous interface definition or named " +
|
||||
"interface definition"
|
||||
);
|
||||
}
|
||||
|
||||
return extend( def );
|
||||
|
@ -75,6 +99,26 @@ module.exports.extend = function()
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determines whether the provided object is an interface created through
|
||||
* ease.js
|
||||
*
|
||||
* @param {Object} obj object to test
|
||||
*
|
||||
* @return {boolean} true if interface (created through ease.js), otherwise
|
||||
* false
|
||||
*/
|
||||
module.exports.isInterface = function( obj )
|
||||
{
|
||||
obj = obj || {};
|
||||
|
||||
return ( obj.prototype instanceof Interface )
|
||||
? true
|
||||
: false
|
||||
;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Default interface implementation
|
||||
*
|
||||
|
@ -94,12 +138,20 @@ var extend = ( function( extending )
|
|||
props = args.pop() || {},
|
||||
base = args.pop() || Interface,
|
||||
prototype = new base(),
|
||||
iname = '',
|
||||
|
||||
members = member_builder.initMembers(
|
||||
prototype, prototype, prototype
|
||||
)
|
||||
;
|
||||
|
||||
// grab the name, if one was provided
|
||||
if ( iname = props.__name )
|
||||
{
|
||||
// we no longer need it
|
||||
delete props.__name;
|
||||
}
|
||||
|
||||
// sanity check
|
||||
inheritCheck( prototype );
|
||||
|
||||
|
@ -145,6 +197,8 @@ var extend = ( function( extending )
|
|||
} );
|
||||
|
||||
attachExtend( new_interface );
|
||||
attachStringMethod( new_interface, iname );
|
||||
|
||||
new_interface.prototype = prototype;
|
||||
new_interface.constructor = new_interface;
|
||||
|
||||
|
@ -238,3 +292,20 @@ function attachExtend( func )
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Provides more sane/useful output when interface is converted to a string
|
||||
*
|
||||
* @param {Object} func interface
|
||||
* @param {string=} iname interface name
|
||||
*
|
||||
* @return {undefined}
|
||||
*/
|
||||
function attachStringMethod( func, iname )
|
||||
{
|
||||
func.toString = ( iname )
|
||||
? function() { return '[object Interface <' + iname + '>]'; }
|
||||
: function() { return '[object Interface]'; }
|
||||
;
|
||||
}
|
||||
|
||||
|
|
|
@ -105,6 +105,12 @@ for ( var i = 0; i < base_types.length; i++ )
|
|||
"Interface contains defined abstract methods"
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
Interface.isInterface( BaseType ),
|
||||
true,
|
||||
"Interface is considered to be an interface"
|
||||
);
|
||||
|
||||
|
||||
var SubType = Interface.extend( BaseType,
|
||||
{
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
/**
|
||||
* Tests interface naming
|
||||
*
|
||||
* Copyright (C) 2010 Mike Gerwitz
|
||||
*
|
||||
* This file is part of ease.js.
|
||||
*
|
||||
* ease.js is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser 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 Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @author Mike Gerwitz
|
||||
* @package test
|
||||
*/
|
||||
|
||||
var common = require( './common' ),
|
||||
assert = require( 'assert' ),
|
||||
Interface = common.require( 'interface' )
|
||||
;
|
||||
|
||||
|
||||
/**
|
||||
* Interfaces may be named by passing the name as the first argument to the
|
||||
* module
|
||||
*/
|
||||
( function testInterfaceAcceptsName()
|
||||
{
|
||||
assert.doesNotThrow( function()
|
||||
{
|
||||
var iface = Interface( 'Foo', {} );
|
||||
|
||||
assert.equal(
|
||||
Interface.isInterface( iface ),
|
||||
true,
|
||||
"Interface defined with name is returned as a valid interface"
|
||||
);
|
||||
}, Error, "Interface accepts name" );
|
||||
|
||||
// the second argument must be an object
|
||||
assert.throws( function()
|
||||
{
|
||||
Interface( 'Foo', 'Bar' );
|
||||
}, TypeError, "Second argument to named interface must be the definition" );
|
||||
} )();
|
||||
|
||||
|
||||
/**
|
||||
* By default, anonymous interfacees should simply state that they are a
|
||||
* interface when they are converted to a string
|
||||
*/
|
||||
( function testConvertingAnonymousInterfaceToStringYieldsInterfaceString()
|
||||
{
|
||||
assert.equal(
|
||||
Interface( {} ).toString(),
|
||||
'[object Interface]',
|
||||
"Converting anonymous interface to string yields interface string"
|
||||
);
|
||||
} )();
|
||||
|
||||
|
||||
/**
|
||||
* If the interface is named, then the name should be presented when it is
|
||||
* converted to a string
|
||||
*/
|
||||
( function testConvertingNamedInterfaceToStringYieldsInterfaceStringContainingName()
|
||||
{
|
||||
var name = 'Foo';
|
||||
|
||||
assert.equal(
|
||||
Interface( name, {} ).toString(),
|
||||
'[object Interface <' + name + '>]',
|
||||
"Converting named interface to string yields string with name of " +
|
||||
"interface"
|
||||
);
|
||||
} )();
|
||||
|
Loading…
Reference in New Issue