Guidelines:Modules/Exercises
The following exercises are designed to help editors learn to make contributions in the Module namespace. The only prerequisite is an understanding of how templates are used.
The exercises have assigned readings from the book Programming in Lua as well as other documentation. The readings explain the concepts covered in the exercise. Read them once before starting the exercise and refer back to them if you get stuck.
If you have any questions or feedback about these exercises, or have suggestions for exercises to add, send us a message in the #wiki-tech
on Discord.
Exercises
Getting Started
Readings
- Extension:Scribunto/Lua reference manual#Getting started
- Guidelines:Modules#Scribunto, for a distilled version of the above with Zelda Wiki-specific examples
Setup
-
Create the page User:YourUsername/Sandbox/Exercises with the following contents:
{{Sandbox/YourUsername/Exercises|Hello world!}}
-
Create the page Template:Sandbox/YourUsername/Exercises with the following contents:
{{#invoke:Sandbox/YourUsername|Main}}
-
Create the page Module:Sandbox/YourUsername with the following contents, but don't save the page yet.
local p = {} function p.Main(frame) return p.main(frame:getParent().args) end function p.main(args) local msg = args[1] return msg end return p
-
In the Preview page with this form beneath the main text area, input
User:YourUsername/Sandbox/Exercises
in the Page title field and click Show preview. This displays the page as it would appear if you were to save the module changes. You should see the following text on the previewed page:- Hello world!
-
Scroll past the edit form to the black and green Debug console. In the text field, type the following, then press the Enter key.
p.main({"Kooloo Limpah"})
You should see the text
Kooloo Limpah
appear in the console. - Save the module page.
Recap
This exercise covered:
- How articles use modules.
- Your sandbox page uses a template but has no notion of modules per se. The template uses the
#invoke
parser function to invoke the functionMain
on your module. The process is the same for real modules. The Link page uses Template:Term which invokes a function on Module:Term.
- How modules use template arguments.
- Your sandbox page passes the argument
Hello world
to the template. The module retrieves that argument from theframe
object. (More on that later.)
- How to make sure your module works before saving.
- The preview form and the debug console are the two main tools for debugging modules. Never submit code without doing at least a bare minimum of debugging/testing.
Game Links 1
Objective: Recreate the functionality of game code templates using Lua.
Readings
- Local Variables and Blocks (until third paragraph)
- Types and Values
- Strings
- Concatenation
- Logical Operators
- if then else
Setup
-
Replace the content of User:YourUsername/Sandbox/Exercises with five invocations, each time with a different canon Zelda game of your choosing. Like so:
{{Sandbox/YourUsername/Exercises|Breath of the Wild}}
{{Sandbox/YourUsername/Exercises|The Wind Waker}}
{{Sandbox/YourUsername/Exercises|Majora's Mask}}
{{Sandbox/YourUsername/Exercises|Spirit Tracks}}
{{Sandbox/YourUsername/Exercises|Oracle of Ages}}
- Breath of the Wild The Wind Waker Majora's Mask Spirit Tracks Oracle of Ages
-
On the page Module:Sandbox/YourUsername, put
mw.logObject(msg)
on line 9. Yourmain
function should look like this:function p.main(args) local msg = args[1] mw.logObject(msg) return msg end
Preview User:YourUsername/Sandbox/Exercises with these changes. Scroll past the edit box to the very bottom of the page until you see the section Parser profiling data (it may be collapsed by default). At the bottom of that table, uncollapse the the Lua logs section. You should see the following:
"Breath of the Wild" "The Wind Waker" "Majora's Mask" "Spirit Tracks" "Oracle of Ages"
mw.logObject
allows you to inspect the value assigned to a variable for a given invocation. In this case, each of the five times your module was invoked when loading the preview, the value assigned to the variablemsg
was printed in the logs. They are shown in quotes because they are values of typestring
. -
Move the
mw.logObject(msg)
call to just before thereturn p
line, outside of themain
block, and preview the page again:function p.main(args) ... end mw.logObject(msg) return p
You should the following logs:
nil nil nil nil nil
nil
represents the absence of a value. Becausemsg
is declared as a local variable in themain
function, it is lexically scoped to that function and has no value outside it. In other words, only themain
function "knows" that the variable exists.Main
could declare its ownmsg
variable and it would be considered completely different. Likewise, the variablep
in our module is unrelated to thep
in any other module. -
Leave the edit form without saving.
mw.logObject
is meant for debugging only and should not be left on a module.
Problems
-
Using concatenation, change the return value to a string like
"* game"
so that your user sandbox looks like so:- Breath of the Wild
- The Wind Waker
- Majora's Mask
- Spirit Tracks
- Oracle of Ages
-
Change the return value to a string like
* ''game''
, so that your user sandbox looks like this:- Breath of the Wild
- The Wind Waker
- Majora's Mask
- Spirit Tracks
- Oracle of Ages
-
Change the return value to a string like
* [[The Legend of Zelda: game|''game'']]
, so that your sandbox looks like this: -
Add
The Adventure of Link
(if you haven't already) or some other game whose full title doesn't start withThe Legend of Zelda:
. Use anif
statement to ensure the proper link is returned for that game: -
Bonus: Rewrite the function to use
string.format
instead of concatenation.
Recap
This exercise covered:
- Variables and lexical scope
- Local variables only have meaning in the block (function, if statement, for loop, etc.) or chunk (module) in which they are declared. Attempting to use one outside its scope produces
nil
. This is a good thing, as it prevents other parts of the code from changing data unintentionally. - Global variables are almost always a bad idea.
- Data types
- The data types relevant to Scribunto are
nil
,boolean
,string
,number
,table
, andfunction
. At a given point in time, a variable will have any one of these types. A variable's type can change when it it is re-assigned—Lua is a dynamically typed language like JavaScript or Python, as opposed to a statically typed one like C or Java.
- String manipulation
- Most modules boil down to being string manipulators. They take as input some string(s) and output some other string (usually wikitext).
- Control flow
- This exercise involved using
if
statements with the relational operator===
. There are other relational operators such as~=
and<
, as well as the logical operatorsand
,or
, andnot
.
Game Links 2
Objective: Rewrite the template from the previous exercise using Module:Franchise.
This exercise has not been written up yet. If this exercise interests you, please let us know in the #wiki-tech
on Discord.
Readings
Game Links 3
Objective: Create a template spec for the template from the previous exercise. Use this spec to document template parameters and validate what editors are providing as input.
This exercise has not been written up yet. If this exercise interests you, please let us know in the #wiki-tech
on Discord.
Readings
- Module:Documentation documentation
- Module:UtilsArg documentation
Game Ratings 1
Objective: Recreate Template:Game Rating from scratch.
This exercise has not been written up yet. If this exercise interests you, please let us know in the #wiki-tech
on Discord.
Game Ratings 2
Objective: Recreate Module:Game Rating/Data/Documentation.
This exercise has not been written up yet. If this exercise interests you, please let us know in the #wiki-tech
on Discord.
Game Ratings 3
Objective: Create a data table extension for game rating data.
This exercise has not been written up yet. If this exercise interests you, please let us know in the #wiki-tech
on Discord.
Solutions
Solutions for the above exercises may be found at Module:Exercises.
Though there are many ways to solve each problem, some solutions are better than others in terms of programming style. When writing real modules, take the time to think about what you can do to make the code easier to understand for the next person who needs to change it.