Guidelines:Modules
Overview
Modules are Lua scripts for making templates using a full-fledged programming language. You can ask questions about Zelda Wiki modules in the #modules
[Discord Discord] channel.
Getting Started
In order to contribute to modules, you'll need to learn basic programming in Lua. You'll also need to know the specifics of Lua scripting on MediaWiki.
Lua
Beginners
Developers
If you already have some programming experience in other languages, note the following particularities of Lua.
Particularities | Further reading |
---|---|
table s are the only built-in object type. Any use of the term "array" actually refers to a table with integer keys.
The language offers prototype-based inheritance through metatables. |
|
Generally tables are 1-indexed as opposed to 0-indexed.
local tbl = {"foo"}
tbl[1]
> "foo"
|
|
|
|
The length operator for a table is # .
|
|
Tables, nil , and the # operator don't interact the way similar constructs do in other languages.
#{ nil, nil, "foo" }
> 3
local tbl = {}
tbl[3] = "foo"
#tbl
> 0
tbl[1] = "bar"
#tbl
> 1
tbl[2] = "baz"
#tbl
> 3
|
Scribunto
- For a broader, more in-depth guide, see Gamepedia Help Wiki.
- See also the full Scribunto/Lua reference manual.
Scribunto is the name of the extension that enables modules. It is the term used for concepts that are Lua-related but specific to MediaWiki.
The Lua on you see on MediaWiki is almost the same as standard Lua except for some changes to library functions and packages. The main difference is in how Lua scripts are invoked.
#invoke
The #invoke
parser function is what bridges the gap between templates and module scripts.[note 1] For example, the transcluded content of Template:Figurine is as follows:
{{#invoke:Figurine|Main}}
This invokes Module:Figurine, which looks be something like:
local p = {}
local h = {}
local utilsGame = require("Module:UtilsGame")
...
function p.Main(frame)
local args = frame:getParent().args
local result = h.getFigurine(args[1], args[2])
return result
end
function h.getFigurine(game, name)
...
end
return p
A page can invoke any function that is a field on the module's export table. The export table is the table
object returned by the module, which is always named p
by convention. In this case, Main
is the only function in the export table.
args
Functions called via #invoke
are passed a Frame object. frame.args
is a table
of the arguments to #invoke
—there are none in the above example. However, frame:getParent().args
represents the template arguments. For example, if a page has {{Figurine|TMC|Minish Ezlo}}
, then frame:getParent().args[1]
evaluates to the string TMC
in that invocation.
The #
operator and most other table functions don't work on frame.args
.
require
A module can import another module and use its exported functions. This is done with the require
function, as shown in the above example with Module:UtilsGame.
mw
Scribunto adds several libraries that are pre-loaded on all modules as the mw
object. The following libraries are of note, in addition to the base functions:
Library | Usage example |
---|---|
mw.text
|
Module:List |
mw.title
|
Module:Subpage List |
mw.html
|
Module:Infobox2 |
Testing and Debugging
You should never be in a situation where you're blindly submitting code and hoping that it works. In the Preview page with this form just below the "Save changes" button, input a page name in the Page title field and click "Show preview" next to it. This will show you how that page will look with your changes to the module. A good page to preview is the module documentation page when it has use cases (as Module:UtilsMarkup/doc does, for example), or the corresponding template documentation when it has usage examples (e.g. Template:Term/Documentation). Consequently, creating documentation examples ahead of time and previewing them can be an effective way to develop modules.[note 2]
Exercises
Utility Modules
A utility module is a library-type module meant to be used by other modules, rather than being invoked by a template. Most template-facing modules use at least one of these:
A complete list of utility modules can be found here.
Leverage utility modules as much as possible so that the wiki's modules stay DRY.
Higher-Order Functions
In utility modules such as Module:UtilsTable, you'll often see functions like these:
utilsTable.isEqual({})({})
> true
You might've expected the usual function syntax utilsTable.isEqual({}, {})
instead. The above is an example of a higher-order function—a function that returns a function. The function call above is shorthand for:
local isEmpty = utilsTable.isEqual({})
isEmpty({})
> true
Functions are written this way for increased reusability. They are often composed with the other type of higher-order function—one that accepts a function as an argument:
local isEmpty = utilsTable.isEqual({})
local notEmpty = utilsFunction.negate(isEmpty)
local magicWords = utilsTable.filter(notEmpty)({ {}, {}, {"Kooloo"}, {"Limpah"} })
utilsTable.flatten(magicWords)
> { "Kooloo", "Limpah" }
Notes
- ↑ It is possible to invoke a module from any page, but it is almost always best to wrap the invocation in a template.
- ↑ This is in fact a form of test-driven development.