1
0
Fork 0

Preparing to remove abstractMethods from public prototype; now uses hash for performance since it no longer needs to be referenced cleanly externally

- It will be later referenced via reflection
closure/master
Mike Gerwitz 2011-01-25 00:13:47 -05:00
parent 069ef6717f
commit 881edc0cc6
3 changed files with 21 additions and 77 deletions

View File

@ -217,16 +217,10 @@ var extend = ( function( extending )
members = member_builder.initMembers(
prototype, prototype, prototype
),
abstract_methods = ( base.abstractMethods || [] ).slice();
// it's much faster to lookup a hash than it is to iterate through an
// entire array each time we need to find an existing abstract method
var abstract_map = {};
for ( var i = 0, len = abstract_methods.length; i < len; i++ )
{
var method = abstract_methods[ i ];
abstract_map[ method ] = i;
}
abstract_methods = util.clone( base.abstractMethods )
|| { __length: 0 }
;
util.propParse( props, {
each: function( name, value, keywords )
@ -269,15 +263,17 @@ var extend = ( function( extending )
if ( is_abstract )
{
abstract_methods.push( name );
abstract_methods[ name ] = true;
abstract_methods.__length++;
}
else if ( ( abstract_map[ name ] !== undefined )
else if ( ( abstract_methods[ name ] )
&& ( is_abstract === false )
)
{
// if this was a concrete method, then it should no longer
// be marked as abstract
delete abstract_methods[ abstract_map[ name ] ];
delete abstract_methods[ name ];
abstract_methods.__length--;
}
},
@ -289,8 +285,6 @@ var extend = ( function( extending )
},
} );
abstract_methods = util.arrayShrink( abstract_methods );
// reference to the parent prototype (for more experienced users)
prototype.parent = base.prototype;
@ -332,7 +326,7 @@ var extend = ( function( extending )
function createCtor( abstract_methods )
{
// concrete class
if ( abstract_methods.length === 0 )
if ( abstract_methods.__length === 0 )
{
var args = null;
@ -507,7 +501,7 @@ function attachPropInit( prototype, properties )
*/
function attachAbstract( func, methods )
{
var is_abstract = ( methods.length > 0 ) ? true: false;
var is_abstract = ( methods.__length > 0 ) ? true: false;
/**
* Returns whether the class contains abstract methods (and is therefore

View File

@ -72,11 +72,6 @@ assert.ok(
"All classes should have an isAbstract() method"
);
assert.ok(
( Foo.abstractMethods instanceof Array ),
"All classes should provide a list of their abstract methods as an array"
);
assert.equal(
Foo.isAbstract(),
false,
@ -96,28 +91,6 @@ assert.equal(
"concrete implementation for all abstract methods"
);
assert.ok(
( ( AbstractFoo.abstractMethods[ 0 ] == 'method' )
&& ( AbstractFoo.abstractMethods[ 1 ] == 'second' )
),
"Abstract classes should provide a list of their abstract methods' names"
);
assert.ok(
( ( SubAbstractFoo.abstractMethods[ 0 ] == 'method' )
&& ( SubAbstractFoo.abstractMethods[ 1 ] == undefined )
),
"Abstract subclasses should not have their concrete methods within the " +
"the abstract method list if the concrete method was abstract in " +
"its supertype"
);
assert.equal(
ConcreteFoo.abstractMethods.length,
0,
"Concrete classes should not have any abstract methods listed"
);
assert.equal(
ConcreteFoo.isAbstract(),
false,

View File

@ -112,6 +112,11 @@ var Type = Interface.extend( {
} )();
/**
* Since interfaces can contain only abstract methods, it stands to reason that
* any class implementing an interface without providing any concrete methods
* should be abstract by default.
*/
( function testClassesImplementingInterfacesAreConsideredAbstractByDefault()
{
assert.equal(
@ -123,40 +128,6 @@ var Type = Interface.extend( {
} ) ();
( function testAbstractMethodListUpdatedWhenInterfaceImplemented()
{
// no base
assert.equal(
Foo.abstractMethods.length,
2,
"Abstract methods list is updated when interface is implemented " +
"(empty base)"
);
// PlainFoo base
assert.equal(
PlainFoo2.abstractMethods.length,
2,
"Abstract methods list is updated when interface is implemented " +
"(concrete base)"
);
} )();
( function testProperAbstractMethodsAreCopiedFromInterface()
{
assert.ok(
( ( Foo.abstractMethods[ 0 ] == 'foo' )
&& ( Foo.abstractMethods[ 1 ] == 'foo2' )
)
&& ( ( PlainFoo2.abstractMethods[ 0 ] == 'foo' )
&& ( PlainFoo2.abstractMethods[ 1 ] == 'foo2' )
),
"Abstract methods list contains names of implemented methods"
);
} )();
( function testInstancesOfClassesAreInstancesOfTheirImplementedInterfaces()
{
// concrete implementation so that we can instantiate it
@ -175,5 +146,11 @@ var Type = Interface.extend( {
"Instances of classes implementing interfaces are considered to be " +
"instances of the implemented interfaces"
);
assert.equal(
ConcreteFoo.isAbstract(),
false,
"Concrete implementations are not considered to be abstract"
);
} )();