වික්ෂනරි:Scribunto/Converting templates
Many editors have some understanding of templates, and have built up a repertoire of "coding idioms". But as Scribunto is only new, we don't yet have a good set of established practices for Lua. This page is an attempt to gather up our experiences with converting templates to Lua, by explaining how to conceptually "translate" certain common practices.
Using libraries and modules from within Lua
[සංස්කරණය]If your code needs to use a function or table from another module or a built-in library, you can import it with the require
function. This function returns the value that the imported module or library itself returns (that is, the table of functions), which you must then store in a variable to use it later. Libraries that are part of Scribunto can be imported directly (except for the "mw" library, which is always available), but to import a module that is in the Module: namespace on Wiktionary, you have to include the Module: prefix in the require
call. For example:
local languages = require("Module:languages")
local p = {}
function p.test(frame)
return languages["en"].names[1] -- returns "English"
end
return p
Expanding wiki code
[සංස්කරණය]Lua scripts are much faster to run than template code. They are also more flexible and have more possibilities than templates. This means that it's best to try to delegate as much of the work to the module, and leave the template to do as little as possible. The template, ideally, would act as nothing more than "glue" between the wiki and Scribunto. Nevertheless, it may sometimes be desirable to transclude a template or a magic word. Scribunto provides two functions that allow you to access "wikispace" from within a module: frame:preprocess
and frame:expandTemplate
.
The main use of this is to allow you to convert templates to Scribunto without having to convert all the templates it uses first. However, expanding wiki code is slow; much slower than just writing Lua code. So this should not be done if it's at all possible. If you find that a Scribunto module needs to use a template, then you could consider passing the result of that template to the invocation as a parameter. Or better yet, convert that template to a Scribunto module itself!
Page names and other magic words
[සංස්කරණය]The Scribunto library includes a collection of functions that are geared specifically towards wiki usage, and are intended to replace magic words such as {{PAGENAME}}
. Here is an overview of some of the more important ones that are available, with their magic word equivalents:
Wikicode | Lua equivalent |
---|---|
{{PAGENAME}}
|
mw.title.getCurrentTitle().text
|
{{FULLPAGENAME}}
|
mw.title.getCurrentTitle().prefixedText
|
{{SUBPAGENAME}}
|
mw.title.getCurrentTitle().subpageText
|
{{BASEPAGENAME}}
|
mw.title.getCurrentTitle().baseText
|
{{NAMESPACE}}
|
mw.title.getCurrentTitle().nsText
|
Keep in mind that if you need to access mw.title.getCurrentTitle()
multiple times, it's probably a good idea to store it in a variable the first time, and then re-use that variable for any subsequent uses. When you need to check whether a page is in a particular namespace, you can use if mw.title.getCurrentTitle():inNamespace("name") then ...
instead, which is probably faster.
Ifexist
[සංස්කරණය]Among the parser functions that are available in templates is {{#ifexist:}}
, which allows you to check whether a page exists or not. Lua has an equivalent that is a bit different, but also more flexible: mw.title.new(title).exists
.
Just like {{#ifexist:}}
, the function makeTitle
is considered an "expensive function". This means that there is a limit to how many times it and other expensive functions can be used altogether on a page; this limit is 500 as of February 2013. Like its template-code counterpart, it should therefore be used sparingly.
Empty parameters
[සංස්කරණය]In templates, you can use {{{param|def}}}
to indicate that you want to use the parameter named param
if it was given in the template call, or the string "def"
if it was not. In Lua you use the following equivalent (assuming you stored the arguments in the variable args
):
local param = args["param"] or "def"
This will set the variable param
to whatever was passed to the template, but if the parameter was not passed at all it is set to "def"
by default. Of course, if you want to use an empty string as the default, just use ""
instead.
Often, you want to use the same behavior if the parameter was missing as if it was blank; for example, in wikitext you might write {{#if:{{{param|}}}|...}}
. In Lua, you would write:
local param = args["param"] or ""
if param ~= "" then
...
end
As a special case, if you want your default to be used whenever a parameter is missing or blank, you can write:
local param = args["param"] or "" ; if param == "" then param = "def" end
which sets param
to the equivalent of {{#if:{{{param|}}}|{{{param}}}|def}}
.
Conditionals, switches and the ternary operator
[සංස්කරණය]Template parser functions are functional and value-based, in that they evaluate expressions which result in a value (text) to return as a result, and do not store anything. Lua, however, is imperative: it is based on statements (commands) that are executed one at a time, and it allows you to store values in variables. Lua also has expressions, but while in wikitext everything is an expression (has a value), in Lua not everything is.
Unfortunately, Lua has no exact equivalent to a wikitext expression like {{#if:condition|then_value|else_value}}
. In Lua, the only true if-then-else construct is a statement, not an expression, so it does not return a value and cannot be embedded in a larger expression. However, there are a number of expression-level constructs, detailed in the "TernaryOperator" article on the lua-users wiki, that can approximate the effect of an if-then-else construct. One of the most popular is this notation:
condition and then_value or else_value -- Syntactically, this is: (condition and then_value) or else_value
This works because if the condition is true, it will (because of the and
) then evaluate the then_value
, and if not, it will evaluate else_value
. Unlike in templates and in Lua if-statements, the else_value
is required, because if it's left out, when the condition is false
, the expression as a whole evaluates literally to false
, which will trigger an error if you then use that result within a larger expression (because you can't concatenate false
to a string, for example). This method code will also break down if then_value
is either false
or nil
, because condition and false
and condition and nil
both evaluate to false
, so the else_value
will be used. You can avoid that by changing the condition around so that the then and else values are swapped (else_value
can be false
or nil
).
For example, consider {{l}}
, where the second parameter specifies the entry to link to, and the third specifies the word to be displayed — but where the third parameter is optional, and if it's missing or blank, we want to display the name of the entry (i.e., the second parameter). In wikitext, we might write {{#if:{{{3|}}}|{{{3}}}|{{{2}}}}}
. In Lua, that could be expressed this way:
local entry = args[2] or error("Second parameter missing!")
local display = args[3] or ""
return "[[" .. entry .. "|" .. (display ~= "" and display or entry) .. "]]" -- you can't use "display or entry" here because the empty string evaluates to true
However, it might be clearer to take advantage of the fact that Lua variables, unlike template parameters, are mutable; so, we can write this instead:
local entry = args[2] or error("Second parameter missing!")
local display = args[3] or "" ; if display == "" then display = entry end
return "[[" .. entry .. "|" .. display .. "]]"
You can also mimic a {{#switch:}}
expression in this way, although there may be better ways to do that.