Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/hslua/lua-style-guide
Lua style guide
https://github.com/hslua/lua-style-guide
Last synced: about 2 months ago
JSON representation
Lua style guide
- Host: GitHub
- URL: https://github.com/hslua/lua-style-guide
- Owner: hslua
- Created: 2020-11-21T17:20:22.000Z (about 4 years ago)
- Default Branch: main
- Last Pushed: 2021-06-09T15:32:06.000Z (over 3 years ago)
- Last Synced: 2024-08-07T18:42:12.100Z (5 months ago)
- Size: 16.6 KB
- Stars: 8
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Lua Style Guide
This style guide contains a list of guidelines that we try to follow
for our projects. It does not attempt to make arguments for the
styles; its goal is to provide consistency across projects.Feel free to fork this style guide and change to your own liking,
and file issues / pull requests if you have questions, comments, or
if you find any mistakes or typos.1. [Types](#types)
2. [Tables](#tables)
3. [Strings](#strings)
4. [Functions](#functions)
5. [Properties](#properties)
6. [Variables](#variables)
7. [Conditional Expressions & Equality](#conditional-expressions--equality)
8. [Blocks](#blocks)
9. [Whitespace](#whitespace)
10. [Commas](#commas)
11. [Semicolons](#semicolons)
12. [Type Casting & Coercion](#type-casting--coercion)
13. [Naming Conventions](#naming-conventions)
14. [Modules](#modules)
15. [File Structure](#file-structure)
16. [Testing](#testing)
17. [Contributors](#contributors)
18. [License](#license)## Types
- **Primitives**: When you access a primitive type you work
directly on its value+ `string`
+ `number`
+ `boolean`
+ `nil````lua
local foo = 1
local bar = foobar = 9
print(foo, bar) -- => 1 9
```- **Complex**: When you access a complex type you work on a
reference to its value+ `table`
+ `function`
+ `userdata````lua
local foo = { 1, 2 }
local bar = foobar[0] = 9
foo[1] = 3print(foo[0], bar[0]) -- => 9 9
print(foo[1], bar[1]) -- => 3 3
print(foo[2], bar[2]) -- => 2 2
```**[[⬆]](#TOC)**
## Tables
- Use the constructor syntax for table property creation where
possible.```lua
-- bad
local player = {}
player.name = 'Jack'
player.class = 'Rogue'-- good
local player = {
name = 'Jack',
class = 'Rogue'
}
```- Define functions externally to table definition.
```lua
-- bad
local player = {
attack = function()
-- ...stuff...
end
}-- good
local function attack()
endlocal player = {
attack = attack
}
```- Consider `nil` properties when selecting lengths. A good idea is
to store an `n` property on lists that contain the length (as
noted in [Storing Nils in
Tables](http://lua-users.org/wiki/StoringNilsInTables))```lua
-- nils don't count
local list = {}
list[0] = nil
list[1] = 'item'print(#list) -- 0
print(select('#', list)) -- 1
```- When tables have functions, use `self` when referring to itself.
```lua
-- bad
local me = {
fullname = function(this)
return this.first_name + ' ' + this.last_name
end
}-- good
local me = {
fullname = function(self)
return self.first_name + ' ' + self.last_name
end
}
```**[[⬆]](#TOC)**
## Strings
- Use single quotes `''` for strings.
```lua
-- bad
local name = "Bob Parr"-- good
local name = 'Bob Parr'-- bad
local full_name = "Bob " .. self.last_name-- good
local full_name = 'Bob ' .. self.last_name
```- Strings longer than 80 characters should be written across
multiple lines using concatenation. This allows you to indent
nicely.```lua
-- bad
local error_message = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.'-- bad
local error_message = 'This is a super long error that \
was thrown because of Batman. \
When you stop to think about \
how Batman had anything to do \
with this, you would get nowhere \
fast.'-- bad
local error_message = [[This is a super long error that
was thrown because of Batman.
When you stop to think about
how Batman had anything to do
with this, you would get nowhere
fast.]]-- good
local error_message = 'This is a super long error that ' ..
'was thrown because of Batman. ' ..
'When you stop to think about ' ..
'how Batman had anything to do ' ..
'with this, you would get nowhere ' ..
'fast.'
```**[[⬆]](#TOC)**
## Functions
- Prefer lots of small functions to large, complex functions.
[Smalls Functions Are Good For The
Universe](http://kikito.github.io/blog/2012/03/16/small-functions-are-good-for-the-universe/).- Prefer function syntax over variable syntax at the top level.
```lua
-- AVOID
local nope = function(name, options)
-- ...stuff...
end-- BETTER
local function yup(name, options)
-- ...stuff...
end
```- Never name a parameter `arg`, this will take precendence over
the `arg` object that is given to every function scope in older
versions of Lua.```lua
-- bad
local function nope(name, options, arg)
-- ...stuff...
end-- good
local function yup(name, options, ...)
-- ...stuff...
end
```- Perform validation early and return as early as possible.
```lua
-- bad
local is_good_name = function(name, options, arg)
local is_good = #name > 3
is_good = is_good and #name < 30-- ...stuff...
return is_bad
end-- good
local is_good_name = function(name, options, args)
if #name < 3 or #name > 30 then return false end-- ...stuff...
return true
end
```**[[⬆]](#TOC)**
## Properties
- Use dot notation when accessing known properties.
```lua
local luke = {
jedi = true,
age = 28
}-- bad
local is_jedi = luke['jedi']-- good
local is_jedi = luke.jedi
```- Use subscript notation `[]` when accessing properties with a
variable or if using a table as a list.```lua
local luke = {
jedi = true,
age = 28
}local function get_prop(prop)
return luke[prop]
endlocal is_jedi = get_prop('jedi')
```**[[⬆]](#TOC)**
## Variables
- Always use `local` to declare variables. Not doing so will
result in global variables to avoid polluting the global
namespace.```lua
-- bad
superPower = SuperPower()-- good
local superPower = SuperPower()
```- Assign variables at the top of their scope where possible. This
makes it easier to check for existing variables.```lua
-- bad
local bad = function()
test()
print('doing stuff..')//..other stuff..
local name = get_name()
if name == 'test' then
return false
endreturn name
end-- good
local function good()
local name = get_name()test()
print('doing stuff..')//..other stuff..
if name == 'test' then
return false
endreturn name
end
```**[[⬆]](#TOC)**
## Conditional Expressions & Equality
- False and nil are *falsy* in conditional expressions. All else
is true.```lua
local str = ''if str then
-- true
end
```- Use shortcuts when you can, unless you need to know the
difference between false and nil.```lua
-- bad
if name ~= nil then
-- ...stuff...
end-- good
if name then
-- ...stuff...
end
```- Prefer *true* statements over *false* statements where it makes
sense. Prioritize truthy conditions when writing multiple
conditions.```lua
--bad
if not thing then
-- ...stuff...
else
-- ...stuff...
end--good
if thing then
-- ...stuff...
else
-- ...stuff...
end
```- Prefer defaults to `else` statements where it makes sense. This
results in less complex and safer code at the expense of
variable reassignment, so situations may differ.```lua
--bad
local function full_name(first, last)
local nameif first and last then
name = first .. ' ' .. last
else
name = 'John Smith'
endreturn name
end--good
local function full_name(first, last)
local name = 'John Smith'if first and last then
name = first .. ' ' .. last
endreturn name
end
```- Short ternaries are okay.
```lua
local function default_name(name)
-- return the default 'Waldo' if name is nil
return name or 'Waldo'
endlocal function brew_coffee(machine)
return machine and machine.is_loaded
and 'coffee brewing' or 'fill your water'
end
```**[[⬆]](#TOC)**
## Blocks
- Single line blocks are okay for *small* statements. Try to keep
lines to 80 characters. Indent lines if they overflow past the
limit.```lua
-- good
if test then return false end-- good
if test then
return false
end-- bad
if test < 1 and do_complicated_function(test) == false or seven == 8 and nine == 10 then do_other_complicated_function()end-- good
if test < 1 and do_complicated_function(test) == false or
seven == 8 and nine == 10 thendo_other_complicated_function()
return false
end
```**[[⬆]](#TOC)**
## Whitespace
- Use two spaces for indentation.
```lua
-- bad
function()
∙∙∙∙local name
end-- bad
function()
∙local name
end-- good
function()
∙∙local name
end
```- Place 1 space before opening and closing braces. Place no spaces
around parens.```lua
-- bad
local test = {one=1}-- good
local test = { one = 1 }-- bad
dog.set('attr',{
age = '1 year',
breed = 'Bernese Mountain Dog'
})-- good
dog.set('attr', {
age = '1 year',
breed = 'Bernese Mountain Dog'
})
```- Place an empty newline at the end of the file.
```lua
-- bad
(function(global)
-- ...stuff...
end)(self)
``````lua
-- good
(function(global)
-- ...stuff...
end)(self)```
- Surround operators with spaces.
```lua
-- bad
local thing=1
thing = thing-1
thing = thing*1
thing = 'string'..'s'-- good
local thing = 1
thing = thing - 1
thing = thing * 1
thing = 'string' .. 's'
```- Use one space after commas.
```lua
--bad
local thing = {1,2,3}
thing = {1 , 2 , 3}
thing = {1 ,2 ,3}--good
local thing = {1, 2, 3}
```- Add a line break after multiline blocks.
```lua
--bad
if thing then
-- ...stuff...
end
function derp()
-- ...stuff...
end
local wat = 7--good
if thing then
-- ...stuff...
endfunction derp()
-- ...stuff...
endlocal wat = 7
```- Delete unnecessary whitespace at the end of lines.
**[[⬆]](#TOC)**
## Commas
- Leading commas aren't okay. An ending comma on the last item is
okay but discouraged.```lua
-- bad
local thing = {
once = 1
, upon = 2
, aTime = 3
}-- good
local thing = {
once = 1,
upon = 2,
aTime = 3
}-- okay
local thing = {
once = 1,
upon = 2,
aTime = 3,
}
```**[[⬆]](#TOC)**
## Semicolons
- **Nope.** Separate statements onto multiple lines.
```lua
-- bad
local whatever = 'sure';
a = 1; b = 2-- good
local whatever = 'sure'
a = 1
b = 2
```**[[⬆]](#TOC)**
## Type Casting & Coercion
- Perform type coercion at the beginning of the statement. Use the
built-in functions. (`tostring`, `tonumber`, etc.)- Use `tostring` for strings if you need to cast without string
concatenation.```lua
-- bad
local total_score = review_score .. ''-- good
local total_score = tostring(review_score)
```- Use `tonumber` for Numbers.
```lua
local input_value = '4'-- bad
local val = input_value * 1-- good
local val = tonumber(input_value)
```**[[⬆]](#TOC)**
## Naming Conventions
- Avoid single letter names. Be descriptive with your naming. You
can get away with single-letter names when they are variables in
loops.```lua
-- bad
local function q()
-- ...stuff...
end-- good
local function query()
-- ..stuff..
end
```- Use underscores for ignored variables in loops.
```lua
--good
for _, name in pairs(names) do
-- ...stuff...
end
```- Use snake_case when naming objects, functions, and instances.
Tend towards verbosity if unsure about naming.```lua
-- bad
local OBJEcttsssss = {}
local thisIsMyObject = {}
local this-is-my-object = {}local c = function()
-- ...stuff...
end-- good
local this_is_my_object = {}local function do_that_thing()
-- ...stuff...
end
```- Use PascalCase for factories.
```lua
-- bad
local player = require('player')-- good
local Player = require('player')
local me = Player({ name = 'Jack' })
```**[[⬆]](#TOC)**
- Use `is` or `has` for boolean-returning functions that are part
of tables.```lua
--bad
local function evil(alignment)
return alignment < 100
end--good
local function is_evil(alignment)
return alignment < 100
end
```## Modules
- The module should return a table or function.
- The module should not use the global namespace for anything
ever. The module should be a closure.
- The file should be named like the module.```lua
-- thing.lua
local thing = { }local meta = {
__call = function(self, key, vars)
print key
end
}return setmetatable(thing, meta)
```- Note that modules are [loaded as
singletons](http://lua-users.org/wiki/TheEssenceOfLoadingCode)
and therefore should usually be factories (a function returning
a new instance of a table) unless static (like utility
libraries.)**[[⬆]](#TOC)**
## File Structure
- Files should be named in all lowercase.
- Lua files should be in a top-level `src` folder. The main
library file should be called `modulename.lua`.
- Rockspecs, license, readme, etc should be in the top level.
- Tests should be in a top-level spec folder.
- Executables should be in a top-level bin folder.
- Example:```
./my_module
bin/
script.shspec/
my_module_spec.lua
some_file.luasrc/
my_module.lua
some_file.luaREADME.md
LICENSE.md
```## Testing
- Use [busted](http://olivinelabs.com/busted) and write lots of
tests in a /spec folder. Separate tests by module.
- Use descriptive `describe` and `it` blocks so it's obvious to
see what precisely is failing.
- Test interfaces. Don't test private methods. If you need to test
something that is private, it probably shouldn't be private in
the first place.
- Example:```
./my_module
bin/
script.shspec/
my_module_spec.luautil/
formatters_spec.luasrc/
my_module.luautil/
formatters.luaREADME.md
LICENSE.md
```**[[⬆]](#TOC)**
## Contributors
- [View contributors](https://github.com/hslua/lua-style-guide/graphs/contributors)
**[[⬆]](#TOC)**
## License
- Released under CC0 (Public Domain). Information can be found at
.**[[⬆]](#TOC)**