Implement ve.NodeFactory and add tests

Change-Id: I34fdf24c0099072fe5f7178400abbc323be975d4
This commit is contained in:
Catrope 2012-04-23 11:46:13 -07:00
parent a239b73746
commit 69df3eefbc
3 changed files with 75 additions and 4 deletions

View file

@ -1,15 +1,44 @@
/**
* Data model node factory.
* Generic node factory.
*
* @class
* @constructor
*/
ve.NodeFactory = function() {
//
this.registry = [];
};
/* Methods */
ve.NodeFactory.prototype.register = function( name, constructor ) {
//
/**
* Register a node type with the factory.
*
* The constructor will be called as constructor( contents, attributes ), see createNode().
*
* @param {String} type Node type
* @param {Function} constructor Node constructor subclassing ve.Node
*/
ve.NodeFactory.prototype.register = function( type, constructor ) {
if ( typeof constructor !== 'function' ) {
throw 'Constructor must be a function, cannot be a ' + typeof constructor;
}
this.registry[type] = constructor;
};
/**
* Create a node based on a type. type is used to look up the constructor to use, contents and
* attributes are passed to the constructor.
*
* @param {String} type Node type
* @param {Array|Number} contents Either an array of child nodes (for non-leaf nodes)
* or the length (for leaf nodes)
* @param {Object} [attributes] Attribute key/value pairs
* @returns {ve.Node|null} The node object, or null if type is not a registered node type.
*/
ve.NodeFactory.prototype.createNode = function( type, contents, attributes ) {
if ( type in this.registry ) {
return new this.registry[type]( contents, attributes );
} else {
return null;
}
};

View file

@ -23,6 +23,7 @@
<script src="../../modules/ve2/ve.BranchNode.js"></script>
<script src="../../modules/ve2/ve.TwigNode.js"></script>
<script src="../../modules/ve2/ve.LeafNode.js"></script>
<script src="../../modules/ve2/ve.NodeFactory.js"></script>
<!-- VisualEditor DataModel -->
<script src="../../modules/ve2/dm/ve.dm.js"></script>
@ -37,6 +38,7 @@
<script src="ve.BranchNode.test.js"></script>
<script src="ve.TwigNode.test.js"></script>
<script src="ve.LeafNode.test.js"></script>
<script src="ve.NodeFactory.test.js"></script>
<script src="dm/ve.dm.Node.test.js"></script>
<script src="dm/ve.dm.BranchNode.test.js"></script>
<script src="dm/ve.dm.TwigNode.test.js"></script>

View file

@ -0,0 +1,40 @@
module( 've.NodeFactory' );
/* Stubs */
ve.NodeStub1 = function( content, attributes ) {
this.content = content;
this.attributes = attributes;
this.type = 'nodestub1';
};
ve.NodeStub2 = function( content, attributes ) {
this.content = content;
this.attributes = attributes;
this.type = 'nodestub2';
};
/* Tests */
test( 've.NodeFactory', function() {
var factory = new ve.NodeFactory();
factory.register( 'nodestub1', ve.NodeStub1 );
var ns1 = factory.createNode( 'nodestub1', 42, { 'foo': 'bar' } );
deepEqual( ns1, new ve.NodeStub1( 42, { 'foo': 'bar' } ), 'createNode creates a node ' +
'using the registered constructor and passes through arguments' );
deepEqual( factory.createNode( 'nodestub2', 23, { 'bar': 'baz' } ), null, 'createNode ' +
'returns null for unregistered node types' );
factory.register( 'nodestub2', ve.NodeStub2 );
var ns2 = factory.createNode( 'nodestub2', 16, { 'baz': 'quux' } );
deepEqual( ns2, new ve.NodeStub2( 16, { 'baz': 'quux' } ), 'createNode creates a node ' +
'with a previously unregistered type' );
raises( function() {
factory.register( 'nodestub3', 'nodestub3' );
},
/^Constructor must be a function, cannot be a string$/,
'register throws an exception when trying to register a string as a constructor'
);
} );