Module:Documentation/Documentation

This module is used to generate documentation for modules (e.g. Module:UtilsMarkup) and module-based templates (e.g. Template:Letter). The documentation is generated from a specification in the form of a Lua table. This specification can be re-used to parse and validate input, as well as generate. It can also be used to generate usage examples. For module functions, one can can specify what the expected output should be for a given example, turning it into an automated unit test.

The advantages of this design are as follows:
 * Documentation is standardized.
 * The documentation for a module/template is located on the same page as the module code, allowing for both to be edited together at the same time.
 * Template documentation is less likely to be incorrect or out of date. For example, there is no chance that the documentation says a parameter is optional when in fact it is required—the code that documents which parameters are required is the same code used to actually verify that required args are present when the template is used.

For documenting simple templates that are not module-based, see Template:Usage and Template:Examples.

Templates
To generate documentation for a module-based template, add this to the template page:

And add this to the module page:

Examples

 * Template:Franchise/Store Game
 * Template:Game Rating
 * Template:Letter
 * Template:Tabs
 * Template:Term

Performance Optimization
While it is convenient to define templates specs as a table in the module itself, it becomes a performance issue at scale. These tables, which can become quite large, are initialized each time the module is invoked. When a module is invoked hundreds of times on a page (e.g. Module:Term) this can add unacceptable computing time and memory overhead.

For modules which can be invoked hundreds of times on a single page, the  object should be moved to a subpage called. Module:Documentation will automatically pick up the object from the subpage instead of the module page. If the  object is needed over in the module itself for Module:UtilsArg, then import the subpage into the main module using   so that the tables are initialized only once.

This approach is more cumbersome for template/module developers and is recommended only for modules which have noticeable performance issues. You can usually tell if the documentation is causing performance issues by previewing the Link page and seeing if the following function appears in the Profiler data:

init  chunk 

Usage
To create module documentation, create the page  with the following contents

Then on the actual module page, at the end of the script just before the final return, add a  function to the export table.

Tests
The  property transforms documentation examples into actual test cases, using a deep equality assertion between the expected output and actual output. If the assertion fails, the page is added to Category:Modules with failing tests.

This module therefore rolls documentation and testing into one. This approach was chosen over ScribuntoUnit and Docbunto for the following reasons:
 * Module functionality that is worth testing is worth documenting too, and vice-versa. The specification should be written only once, in one place.
 * For modules like Module:UtilsLayout that render a ton of markup, it is not practical to test with coded assertions. In these cases it suffices for module developers to manually check that the examples are outputting correct visuals.
 * A module's code, tests, and documentation are tightly coupled. It's much more convenient that they all be on the same page so that they can be edited simultaneously.
 * We must sometimes forgo this convenience for performance reasons, however. See.

Data
Category:Module Data can be documented and validated by adding the following to the core module:

Schemas
A schema can be used to generate type documentation for function parameters or for module data. Without schemas, it can sometimes be difficult for others to know what input a module expects, given Lua's dynamic type system. This is especially true for functions with  arguments.

Note for example the parameter documentation for Module:UtilsLayout:





The above indicates that:
 * is expected to be a table with two keys:  and.
 * is required and of type string.
 * is optional and of type string.
 * is an optional number whose default value is 1.

Hovering over the key name indicates its expected type. The types defined in schemas generally correspond to the Lua types, with an additional  type. The  type, however, does not exist as a concept in schemas. Instead, there are more specific types which indicate the kind of table in question:


 * — A table with consecutive integer keys starting from 1.
 * — A table with fixed set of string keys.
 * — A table with any amount of keys, all of the same type. All values are of the same type, but possibly a different type from the keys.

Types may be marked with symbols:

Writing Schemas
Schemas are written for function parameters like so:

Schemas can also be made for Module Data as shown below. This generates a schema for the data (see Module:Script/Data/Documentation for example) and also validates that the data matches the schema. Any validation errors that occur will be shown as warnings in the edit preview. Data pages that fail validation are placed in Category:Modules with invalid data.

Combining Schemas
It is possible to combine schemas using  and.

The combination keywords are often used along with references to maximize reusability.

Schema References
References allow you to reuse parts of the schema in multiple places. There are two ways of referencing schema fragments: using  and using the   property.

Examples

 * Module:Language/Data/Documentation
 * Module:UtilsLayout/Tabs/Documentation
 * Module:UtilsTable/Documentation
 * Anything in Category:Module Documentation

Altogether the following modules use every available schema feature. Module:UtilsSchema has test cases that show how the validation works.
 * Module:Game Rating
 * Module:Documentation
 * Module:UtilsArg