factory

Background
AbstractComponentFactory() constructor
AbstractComponentFactory.createDefaultFileName()
AbstractComponentFactory.prototype.nextComponent()
AbstractComponentFactory.prototype.setField( component, field, value )
RecordReaderFactory( recordReader ) : AbstractComponentFactory constructor
RecordReaderFactory.nextRecord()
RecordReaderFactory.runScripts( record, gc )
RecordReaderFactory.setBaseFile( file )
RecordReaderFactory.prototype.createPrototype( record )
RecordReaderFactory.prototype.initializeHeaderRow( record )
RecordReaderFactory.prototype.fillInComponent( record, gc, header, prevRecord )
RecordReaderFactory.prototype.fieldValue( fieldName, record )
AbstractComponentFilter( source ) : AbstractComponentFactory constructor
AbstractComponentFilter.filter( gc )
AbstractComponentFilter.nextComponent()
AbstractRecordReader() constructor
AbstractRecordReader.prototype.nextRecord()
AbstractRecordReader.prototype.close()
AbstractRecordReader.createReader( input, [encoding] ) static
AbstractRecordReader.prototype.toString()
Subclasses may call this function to throw an error
AbstractRecordReader.prototype.debugPrint()
CSVRecordReader( input, [encoding] ) : AbstractRecordReader constructor
ArrayRecordReader( input, encoding ) : AbstractRecordReader constructor

Background

This library provides support for the automated creation and processing of game components. Note: You only need to work with this library if you want to do something unusual with the factory system, like write a custom batch processing script or add support for creating components from a new data sources. If all you want to do is create cards in batch, you can probably so everything you want by creating a new Project and adding a Factory task.

The library defines several different types of objects:

Component Sources
A component source is any object that provides a method named nextComponent. This method returns a finite sequence of zero or more game components. Each time it is called, the next component in the sequence is returned. Once the sequence runs out, subsequent calls to the method must return null.

Component Factories
A component factory is a component source that creates new game components. Typically, the components are created using data taken from some external source. For example, instead of maintaining a bunch of .eon files yourself, you can create a spreadsheet that describes an entire deck. Using a component factory, you can then produce actual game components from the spreadsheet data by running them through a factory. These can be saved to disk, printed, or otherwise batch processed.

The following example script creates two Neighbourhood components by reading data from an array:

 uselibrary( "factory" );

 var array = [
     [ "neighbourhood" ],
     [ $_file", "name",         "_tint",                  "tinted", "comment" ],
     [ "park",  "Circle Park",  ":gc.setTint(0,0.7,0.6)", ":true",  "Watch for squirrels." ],
     [ "dark",  "The Darkness", ":gc.setTint(0,0,0)",     "",      " Dangerous. Very dangerous." ]
 ];

 var factory = new RecordReaderFactory( new ArrayRecordReader( array ) );

 var comp = factory.nextComponent();
 while( comp != null ) {
     var ed = comp.createDefaultEditor();
     ed.replaceEditedComponent( comp );
     Eons.addEditor( ed );
     comp = factory.nextComponent();
 }

Component Filters A component filter is a component source that modifies the components produced by another component source. For example, a component source might change the expansion of every card that passes through it.

Component Handlers A component handler does some processing on each of the components produced by a component source, but it differs from a component filter because it is not itself a component source. Typically, a component handler does the "finishing steps" needed to do something useful with the components produced a factory or other component source. For example, the component handler might save the components to files, print them, open editors for them, or build a deck from them.

AbstractComponentFactory() constructor

This is an abstract superclass for factories that can create game components automatically. It defines a standard interface and some helper methods.

AbstractComponentFactory.createDefaultFileName()

Returns a default file name for a component. This helper method creates a new file name that can be used to save a created component. Each call to this method must return a name that is different from any name that was previously returned by a call to this method on that instance. The default implementation simply returns 1.eon, 2.eon, etc.

AbstractComponentFactory.prototype.nextComponent()

This method returns an array that consists of two elements: the next game component object that is generated by this factory, and a suggested file name to use for the component if it is to be written to disk. If this factory has run through the complete set of components

When implementing a factory, if your implementation does not or cannot suggest a file name, you may call this.createDefaultFileName() to generate a default name automatically.

AbstractComponentFactory.prototype.setField( component, field, value )

Set the value of a game component field. If the name of the field starts with $, then it is taken to be the name of a private setting. If it starts with _, then it is taken to be a "pseudo-field", and this method will return without taking any action. Otherwise, it is taken to be the name of an object property.

Private setting fields are set according to the usual rules for $-notation in scripts. (The name of the private setting is determined by removing the leading $ and treating any _ characters as -.

Object properties are set as if by calling an appropriate setter method. For example, if field were name and value were "Jim", then calling this method would have the same result as executing the following Java code:

 component.setName( "Jim" );
The type of value will be coerced according to the usual rules for calling from JavaScript into Java. No other special processing of value is performed.

component the game component to modify
field the name of a field, or, if the first character is $, a private setting name
value the object to set the field's value to

RecordReaderFactory( recordReader ) : AbstractComponentFactory constructor

A component factory that creates game components by reading data from a record reader (such as one that reads data from a CSV spreadsheet file or from an array object).

The sequence of records returned by the reader must follow a few simple rules in order to be processed correctly. The first record, called the prototype record, must identify the type of component being created. The second record, called the header record, identifies attributes of the created component (such as name, comments, stamina, etc.). The third and subsequent records will each be converted into a component by setting its attributes from the field values. These three record types are described in detail below:

Prototype Record
The first field of the prototype record identifies the type of component to be created. The prototype component is created as if by executing the code PluginContext.createEditor( fieldValue ).gameComponent, where fieldValue is the string value of the first field in the record. Basically, this means that fieldValue is a class map key in one of the active class maps. Alternatively, the field can consist of script code (see below) that evaluates to the prototype to be used.

Header Record
The header record consists of one or more attribute names. These are basically the names of setter methods on the component of interest, without the "set" prefix and starting with a lowercase letter. A setter method is a method that takes a single parameter and starts with set. (The View Component plug-in can be used to identify setter methods.) If the name starts with a dollar sign ($), then it is treated as the name of a private setting (without the $) to be set on the component instead. If the name starts with an underscore (_), then it is treated as a placeholder name. Placeholder names are ignored when filling in fields, but they can contain script code to be executed when the field is processed. This can be used to modify aspects of the component that cannot be accessed through setters.

Component Record(s)
Each component record will be converted into a game component by setting the setter method identified by the field at this field's index in the header record with the value in this field. (Setters that take a parameter with a type other than string or a numeric type will generally need to define script code that evaluates to the value to be set.) If a field consists of a blank string, its value is taken from the last non-blank value in that column. (If the blank field occurs in the first component record, then it is treated as an empty string.) To specify a truly blank field, you can use the embedded code (see below): :"" or :''.

The factory will skip any records that are empty (contain no fields) or that are commented out. A record is commented out if the first character of the first field is a number sign (hash): #. Skipped records have no effect on processing (so, for example, there may be empty records between the prototype record and the header record).

Fields may contain embedded script code. This is indicated by starting the field value with a colon (:). When a field contains embedded script code, the actual value used by the field is determined by evaluating the embedded code. This can be used to set an attribute using a computed value, or to call setter functions that require more than one parameter. Because fields that start with a colon are treated as scripts, you cannot begin a normal field value with a colon. To get around this, write a snippet of script code that evaluates to the string you want to use for the field. For example, if you want the value of a field to be : this!, use the following embedded script: :': this!'. The same technique can be used if the first field of a record starts with a number sign.

Some processing tools will recognize the special private setting $_file to suggest file names for generated components. (If absent, the tools will use default file names.)

RecordReaderFactory.nextRecord()

Subclasses may call this function to get the next record from this object's record reader. It will silently skip empty records that are empty (contain no fields) or that are commented out (the first field starts with '#').

RecordReaderFactory.runScripts( record, gc )

Subclasses may call this function to execute any embedded script code in the fields of a record. After this function returns, any fields that contain embedded script code will be replaced with the result of evaluating that field. If the evaluation throws an exception, it will be dumped to the console and the field replaced with an error string. Fields that contain an embedded script are identifed by having type string and starting with :.

record the record to process scripts in
gc a component to be provided to scripts

RecordReaderFactory.setBaseFile( file )

Sets the absolute path that will be used as a base for file names when processing records. Embedded scripts will have access to a function, f( name ) that will generate File objects relative to the base file. Fields that take File arguments can use the f function to create data sets that are independent of location, e.g.:
 :f('portrait.jpg');

file the absolute path to the base folder

RecordReaderFactory.prototype.createPrototype( record )

This method is called by the factory to create a game component from the prototype record. Subclasses may override it to customize behaviour. It should either return a game component or throw an exception.
record the prototype row record
returns the game component created from the prototype record

RecordReaderFactory.prototype.initializeHeaderRow( record )

This method is called by the factory to preprocess the header row. The base implementation simply calls this.runScripts( record, null ) and returns. Subclasses may override this to customize behaviour.
record the header row record

RecordReaderFactory.prototype.fillInComponent( record, gc, header, prevRecord )

This method is called by the factory to fill in the state of a game component using the data from a record.

record the record to use to fill in the component
gc the component to modify
header the header row record
prevRecord a record to use to fill in missing values, or null if no other rows have been processed
returns the record that will be used to this as prevRecord the next time it is called

RecordReaderFactory.prototype.fieldValue( fieldName, record )

Returns the value of the record field in the same column as fieldName (in the header row). If no field in the header row has the value fieldName, returns null.
fieldName the name of the column to look up in record
record the record to be searched
returns the value of the field in record at the same index as fieldName in the header row

AbstractComponentFilter( source ) : AbstractComponentFactory constructor

An abstract superclass for component filters that filters components obtained from source.

AbstractComponentFilter.filter( gc )

Applies a filter to the component gc, returning the result. The filter may be applied in place to the original component (in which case gc is returned), or it may create a copy of the original with the filter applied. Implementations that create a copy should make this clear in their documentation.

gc the game component to be filtered

Returns a game component (possibly gc) created by applying the filter.

AbstractComponentFilter.nextComponent()

Returns the next filtered component. This implementation obtains the next component from the source set in the constructor, calls filter, and returns the result.

Returns the next filtered component, or null if there are no more.

AbstractRecordReader() constructor

An abstract superclass for record readers. A record reader parses input from some source and converts it into zero or more records. A record is an array of zero or more fields.

A set of records can be thought of as a table of data similar to that provided by a spreadsheet application. Each record describes one row of the table, and each field describes one column in that row. A Factory can use the data provided by a record reader to generate components automatically. For example, you could describe the properties of an entire deck of cards in a spreadsheet, and then use a CSVRecordReader to convert the spreadsheet into a matching set of .eon files.

In order to function, a reader subclass must override the nextRecord() function to return the next record from the source.

AbstractRecordReader.prototype.nextRecord()

Returns the next record from the data source, or null if there are no more records. The record is returned as an array, where each entry in the array contains the value of one field.

AbstractRecordReader.prototype.close()

Closes this reader, releasing any system resources that it may hold. Once a reader has been closed, calling nextRecord() must always return null.

AbstractRecordReader.createReader( input, [encoding] ) static

Creates a java.io.BufferedReader that can read text from a number of different sources. This is a helper method that can be used by record readers to convert common data sources into a reader suitable for use by a parser.

The input object can be any one of the following types of object (or a subclass): String (JavaScript), java.lang.String (Java), java.net.URL, java.io.File, java.io.InputStream, java.io.Reader.

input an object of one of the above types
encoding an optional encoding that will be used for input streams

Returns a java.io.BufferedReader capable of reading text from input. If input is not one of the types that can be converted, returns null.

AbstractRecordReader.prototype.toString()

Returns a string that describes which type of record reader this is.

Subclasses may call this function to throw an error

indicating that the input source is not valid for this RecordReader.

AbstractRecordReader.prototype.debugPrint()

Prints out all unread records to the console.

CSVRecordReader( input, [encoding] ) : AbstractRecordReader constructor

Creates a record reader that parses the comma-separated value (CSV) file format. This format can be exported by most spreadsheet applications. It is well-suited to describing tabular data and is easier to read and edit in raw form than XML. This reader uses AbstractRecordReader.createReader to convert input, so data can be obtained from files, strings, URLs, and other sources.

CSV files are plain text files that normally store one record per line. Commas are used to separate fields, and whitespace around commas is ignored. If a field contains a comma, newline, or quote, or if whitespace at the start or end of the field is significant, then the field must be surrounded by quote (") characters. To include a quote inside the field, it must be doubled (""). (Otherwise, the quote will end the field.)

For example, the following input:

Name, Gold, "Starting Location"
Biff, 7, Nirvana
Cuddles, 3, "A bar, ""The Silver Donkey"""

Would produce these records:

Field 1Field 2Field 3
Record 1NameGoldStarting Location
Record 2Biff7Nirvana
Record 3Cuddles3A bar, "The Silver Donkey"

ArrayRecordReader( input, encoding ) : AbstractRecordReader constructor

A record reader that parses records from an array. Each element in the array is an array of the fields that comprise that record. input may either be an actual array, or it may be an input stream, string, file, or other data source that contains code that defines an array.

Example:

 var array = [
     [ "Name", "Gold", "Starting Location" ],
     [ "Biff", 7, "Nirvana" ],
     [ "Cuddles", 3, 'A bar, "The Silver Donkey"' ]
 ];
 new ArrayRecordReader( array ).debugPrint();

Index    Contents