Classes now contain implement() method
parent
ec9f24a926
commit
7fb0f6a820
34
lib/class.js
34
lib/class.js
|
@ -60,7 +60,7 @@ exports.implement = function()
|
||||||
var args = Array.prototype.slice.call( arguments );
|
var args = Array.prototype.slice.call( arguments );
|
||||||
|
|
||||||
// apply to an empty (new) object
|
// apply to an empty (new) object
|
||||||
args.unshift( {} );
|
args.unshift( exports.extend() );
|
||||||
|
|
||||||
return implement.apply( this, args );
|
return implement.apply( this, args );
|
||||||
};
|
};
|
||||||
|
@ -347,10 +347,10 @@ var extend = ( function( extending )
|
||||||
/**
|
/**
|
||||||
* Implements interface(s) into an object
|
* Implements interface(s) into an object
|
||||||
*
|
*
|
||||||
* This will copy all of the abstract methods from the interface into the
|
* This will copy all of the abstract methods from the interface and merge it
|
||||||
* destination object.
|
* into the given object.
|
||||||
*
|
*
|
||||||
* @param {Object} dest destination object
|
* @param {Object} base base object
|
||||||
* @param {...Interface} interfaces interfaces to implement into dest
|
* @param {...Interface} interfaces interfaces to implement into dest
|
||||||
*
|
*
|
||||||
* @return {Object} destination object with interfaces implemented
|
* @return {Object} destination object with interfaces implemented
|
||||||
|
@ -358,7 +358,8 @@ var extend = ( function( extending )
|
||||||
var implement = function()
|
var implement = function()
|
||||||
{
|
{
|
||||||
var args = Array.prototype.slice.call( arguments ),
|
var args = Array.prototype.slice.call( arguments ),
|
||||||
dest = args.shift(),
|
dest = {},
|
||||||
|
base = args.shift(),
|
||||||
len = args.length,
|
len = args.length,
|
||||||
arg = null,
|
arg = null,
|
||||||
|
|
||||||
|
@ -375,7 +376,8 @@ var implement = function()
|
||||||
implemented.push( arg );
|
implemented.push( arg );
|
||||||
}
|
}
|
||||||
|
|
||||||
var class_new = exports.extend( dest );
|
// create a new class with the implemented abstract methods
|
||||||
|
var class_new = exports.extend( base, dest );
|
||||||
getMeta( class_new.__cid ).implemented = implemented;
|
getMeta( class_new.__cid ).implemented = implemented;
|
||||||
|
|
||||||
return class_new;
|
return class_new;
|
||||||
|
@ -395,6 +397,7 @@ function setupProps( func, abstract_methods, class_id )
|
||||||
{
|
{
|
||||||
attachAbstract( func, abstract_methods );
|
attachAbstract( func, abstract_methods );
|
||||||
attachExtend( func );
|
attachExtend( func );
|
||||||
|
attachImplement( func );
|
||||||
attachId( func, class_id );
|
attachId( func, class_id );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,6 +498,25 @@ function attachExtend( func )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attaches implement method to the given function (class)
|
||||||
|
*
|
||||||
|
* @param {function()} func function (class) to attach method to
|
||||||
|
*
|
||||||
|
* @return {undefined}
|
||||||
|
*/
|
||||||
|
function attachImplement( func )
|
||||||
|
{
|
||||||
|
util.defineSecureProp( func, 'implement', function()
|
||||||
|
{
|
||||||
|
var args = Array.prototype.slice.call( arguments );
|
||||||
|
args.unshift( func );
|
||||||
|
|
||||||
|
return implement.apply( this, args );
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attaches the unique id to the class and its prototype
|
* Attaches the unique id to the class and its prototype
|
||||||
*
|
*
|
||||||
|
|
|
@ -42,23 +42,47 @@ assert.ok(
|
||||||
"Class provides method to implement interfaces"
|
"Class provides method to implement interfaces"
|
||||||
);
|
);
|
||||||
|
|
||||||
var Foo = {},
|
var Foo = {},
|
||||||
PlainFoo = Class.extend();
|
PlainFoo = Class.extend(),
|
||||||
|
PlainFoo2 = {};
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
( PlainFoo.implement instanceof Function ),
|
||||||
|
"Classes contain an implement() method"
|
||||||
|
);
|
||||||
|
|
||||||
assert.doesNotThrow( function()
|
assert.doesNotThrow( function()
|
||||||
{
|
{
|
||||||
Foo = Class.implement( Type, Type2 );
|
Foo = Class.implement( Type, Type2 );
|
||||||
}, Error, "Class can implement interfaces" );
|
}, Error, "Class can implement interfaces" );
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
( Class.isClass( Foo ) ),
|
||||||
|
"Class returned from implementing interfaces on an empty base is a " +
|
||||||
|
"valid class"
|
||||||
|
);
|
||||||
|
|
||||||
assert.ok(
|
assert.ok(
|
||||||
( ( Foo.prototype.foo instanceof Function )
|
( ( Foo.prototype.foo instanceof Function )
|
||||||
&& ( Foo.prototype.foo2 instanceof Function )
|
&& ( Foo.prototype.foo2 instanceof Function )
|
||||||
),
|
),
|
||||||
"Abstract methods are copied into the new class prototype"
|
"Abstract methods are copied into the new class prototype (empty base)"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.doesNotThrow( function()
|
||||||
|
{
|
||||||
|
PlainFoo2 = PlainFoo.implement( Type, Type2 );
|
||||||
|
}, Error, "Concrete classes can implement interfaces" );
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
( ( PlainFoo2.prototype.foo instanceof Function )
|
||||||
|
&& ( PlainFoo2.prototype.foo2 instanceof Function )
|
||||||
|
),
|
||||||
|
"Abstract methods are copied into the new class prototype (concrete base)"
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
Foo.isAbstract(),
|
( Foo.isAbstract() && PlainFoo2.isAbstract() ),
|
||||||
true,
|
true,
|
||||||
"Classes that implements interface(s) are considered abstract if the " +
|
"Classes that implements interface(s) are considered abstract if the " +
|
||||||
"implemented methods have no concrete implementations"
|
"implemented methods have no concrete implementations"
|
||||||
|
@ -67,12 +91,23 @@ assert.equal(
|
||||||
assert.equal(
|
assert.equal(
|
||||||
Foo.abstractMethods.length,
|
Foo.abstractMethods.length,
|
||||||
2,
|
2,
|
||||||
"Abstract methods list is updated when interface is implemented"
|
"Abstract methods list is updated when interface is implemented " +
|
||||||
|
"(empty base)"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
PlainFoo2.abstractMethods.length,
|
||||||
|
2,
|
||||||
|
"Abstract methods list is updated when interface is implemented " +
|
||||||
|
"(concrete base)"
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.ok(
|
assert.ok(
|
||||||
( ( Foo.abstractMethods[ 0 ] == 'foo' )
|
( ( Foo.abstractMethods[ 0 ] == 'foo' )
|
||||||
&& ( Foo.abstractMethods[ 1 ] == 'foo2' )
|
&& ( Foo.abstractMethods[ 1 ] == 'foo2' )
|
||||||
|
)
|
||||||
|
&& ( ( PlainFoo2.abstractMethods[ 0 ] == 'foo' )
|
||||||
|
&& ( PlainFoo2.abstractMethods[ 1 ] == 'foo2' )
|
||||||
),
|
),
|
||||||
"Abstract methods list contains names of implemented methods"
|
"Abstract methods list contains names of implemented methods"
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue