Lua templating/Style guide

This article gives coding conventions for the creation and management of global Lua modules. For an introduction to Lua, please see our getting started guide.
==What is this?==
This article is a style guide, a set of standards and best practices created to help developers write better code. It encourages consistency between modules, which makes them easier to read, test, and maintain. That said, you should always use your best judgement when coding, and avoid the cargo cult.
== Documentation ==
Document all methods, and all potentially confusing parameters as well as the purpose of the module itself. There are multiple ways to document code inline such as using the conventions JSDoc conventions. Using Codedoc format is one possible alternative that has the benefit of coming with its own parser that can generate documentation on a page. Generally code should be documented for other developers inline, and separately for end-users on a documentation page and / or template.
-- Good:
--% Shows a listing of books
--@ books (string) A comma separated list of books
--: (string) A listing of all books
function showBooks(books)
 -- Adds a suffix to the returned string
 local suffix = "."
 return books .. suffix
end
-- Bad (no description):
function showStuff(books)
 local something = "." 
 return books .. something
end
==Page structure==
Each module (e.g. Module:Do something) should be accompanied by the following pages:
Full page name 	Purpose
Global Lua Modules/Do Something 	Documentation page for the module
Module:Do something/testcases 	Unit tests for the module
Module talk:Do something/testcases	Results of said unit tests
==Code structure==
===Escaping wikitext===
Did you know that modules are parsed for wikitext? For example, this innocent-looking bit of code...
function addCategory(name)
 return '[[Category:' .. name .. ']]'
end
...will put its module in a bizarre category called ' .. name .. ' (quotes and all). To avoid this problem, always wrap your module in <nowiki>, <pre>, or <syntaxhighlight> (a.k.a. <source>) tags.
===Indentation===
Use four spaces per indentation level. Pressing the "tab" key in Fandom's code editor results in four spaces, so the only way to get a tab character is to paste it from somewhere else.
-- Good:
function helloWorld()
 return 'Hello, World!'
end
-- Bad (two spaces):
function helloWorld()
 return 'Hello, World!'
end
-- Bad (tab character):
function helloWorld()
	return 'Hello, World!'
end
===Line length===
Each line should be no longer than 80 characters. If a single line would be too long, you can split a large statement over multiple lines with a hanging indent that aligns with the opening delimiter. For if statements, the conditions should be placed on the next line with an extra level of indentation.
-- Example:
hello = long_function_name(var_one, var_two,
 var_three, var_four)
if (condition1 or condition2)
 and condition3
 and condition4 then
 foo()
 bar()
 baz()
end
===Semicolons===
Don't use semicolons; they are completely optional in Lua, and only add visual clutter. As a corollary—use one expression per line.
-- Good:
doSomething()
if 1 then
 foo()
 bar()
else
 baz()
end
bread()
eggs()
milk()
-- Bad:
doSomething();
if 1 then foo(); bar(); else baz(); end
bread(); eggs(); milk();
===Parallel assignment===
Avoid parallel assignment when defining variables. It is allowed when all values are nil, when all values are returned from a single function, and when swapping variables. Parallel assignment is harder to read than separate assignment.
-- Good:
local foo = 'first value'
local bar = 'second value'
-- Okay:
local empty1, empty2
local value1, value2, value3 = multiReturn()
foo, bar = bar, foo
-- Bad:
local foo, bar = 'first value', 'second value'
===Whitespace===
====Functions====
Place one space after the keyword function, but do not place any after the function name.
-- Good:
function doSomething()
 -- Do something
end
return function ()
 -- Do something else
end
-- Bad:
function doSomething ()
 -- Do something
end
return function()
 -- Do something else
end
====Operators====
Place one space on either side of operators.
-- Good:
if type(foo) == 'number' then
 foo = foo + 1
end
-- Bad:
if type(foo)=='number' then
 foo=foo+1
end
====Bracketing characters====
Do not place any space after [, (, and {; or before ], ), and }.
-- Good:
function doSomething(arg1, arg2)
 local myTable = {'one', 'two', 'three', 'four', 'five'}
 return myTable[1 + 1]
end
-- Bad:
function doSomething( arg1, arg2 )
 local myTable = { 'one', 'two', 'three', 'four', 'five' }
 return myTable[ 1 + 1 ]
end
==== Comments ====
Comments should be indented to the same level as the underlying code, and may be separated by a blank new line if this makes the code more readable, but this is not a requirement.
====Commas====
Place one space after a comma.
-- Good:
function doSomething(arg1, arg2)
 -- Do something
end
-- Bad:
function doSomething(arg1,arg2)
 -- Do something
end
====Blank lines====
Place an empty line after every until and end keyword, unless the next line has less indentation. Empty lines should also be used to break the module into logical "paragraphs."
-- Good:
function first()
 -- Do something
end
function second()
 -- Do something else
 if true then
 -- Do a third thing
 end
end
-- Bad:
function first()
 -- Do something
end
function second()
 -- Do something else
 if true then
 -- Do a third thing
 end
end
====Trailing whitespace====
Remove extra whitespace from the end of each line.
===Functions===
Have descriptive function names that identify the action:
local p = {}
-- Bad:
function p.doStuff(frame)
-- Code goes here
end
-- Good:
function p.loadUsers(frame)
-- Code goes here
end
return p
==== Invoked functions ====
Make sure invoked function names are short, lower case, and descriptive.
Bad:
{{#invoke:A_module_FOR_characters}}
Good:
{{#invoke:characters}}
==== Parameters ====
Avoid long lists of parameters for invoked functions, using fewer than 7 parameters whenever possible. Also, consider using named parameters.
== Module structure ==
Separate utility functions from the main p table, especially those functions that will not need to be directly accessible from templates or articles. If there are too many utility functions, consider creating a new meta-module and storing them there to reduce complexity.
local p = {}
function getArgumentNames()
 -- Code goes here
end
return p
Try not to have too many functions as the entry points for a module:
local p = {}
function p.loadtable(frame)
 -- Code goes here
end
function p.main(frame)
 -- Code goes here
end
function p.url(frame)
 -- Code goes here
end
return p
==Naming conventions==
Define the entry method as simply unpacking the parameters from the frame, and then passing those through a function with the same name prefixed with a single underscore. This can be disregarded if the function is short and simple.
In the standard library, function names consisting of multiple words are simply put together (e.g. setmetatable). camelCase is the preferred way to name functions, in order to avoid potential garden path function names. It might also be a good idea to follow some guide, e.g. a good guide to naming variables.
Whenever possible try to name the main entry point to invoke the package p.main, e.g. {{#invoke:url|main}}.
-- See https://en.wikipedia.org/w/index.php?oldid=540791109 for code
local p = {}
function p._url(url, text)
 -- Code goes here
end
function p.url(frame)
 -- Take parameters out of the frame and pass them to p._url(). Return the result.
 -- Code goes here
 return p._url(url, text)
end
return p
P.S. Avoid overly long names and being a citizen of the kingdom of nouns http://web.archive.org/web/20160421155215/http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html.
==References==
Style guide