|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733 |
- # Lua Style Guide
-
- This style guide contains a list of guidelines that we try to follow for Rspamd.
-
- This guide is forked from https://github.com/Olivine-Labs/lua-style-guide
-
-
- ## <a name='TOC'>Table of Contents</a>
-
- 1. [Types](#types)
- 1. [Tables](#tables)
- 1. [Strings](#strings)
- 1. [Functions](#functions)
- 1. [Properties](#properties)
- 1. [Variables](#variables)
- 1. [Conditional Expressions & Equality](#conditionals)
- 1. [Blocks](#blocks)
- 1. [Whitespace](#whitespace)
- 1. [Commas](#commas)
- 1. [Semicolons](#semicolons)
- 1. [Type Casting & Coercion](#type-coercion)
- 1. [Naming Conventions](#naming-conventions)
- 1. [Accessors](#accessors)
- 1. [Constructors](#constructors)
- 1. [Modules](#modules)
- 1. [Testing](#testing)
- 1. [License](#license)
-
- ## <a name='types'>Types</a>
-
- - **Primitives**: When you access a primitive type you work directly on its value
-
- + `string`
- + `number`
- + `boolean`
- + `nil`
-
- ```lua
- local foo = 1
- local bar = foo
-
- bar = 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 = foo
-
- bar[0] = 9
- foo[1] = 3
-
- print(foo[0], bar[0]) -- => 9 9
- print(foo[1], bar[1]) -- => 3 3
- print(foo[2], bar[2]) -- => 2 2
- ```
-
- **[[⬆]](#TOC)**
-
- ## <a name='tables'>Tables</a>
-
- - 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()
- end
-
- local player = {
- attack = attack
- }
- ```
-
- **[[⬆]](#TOC)**
-
- ## <a name='strings'>Strings</a>
-
- - Use single quotes `''` for strings.
-
- ```lua
- -- bad
- local name = "Bob Parr"
-
- -- good
- local name = 'Bob Parr'
-
- -- bad
- local fullName = "Bob " .. self.lastName
-
- -- good
- local fullName = 'Bob ' .. self.lastName
- ```
-
- - Strings longer than 80 characters should be written across multiple lines
- using concatenation. This allows you to indent nicely.
-
- ```lua
- -- bad
- local errorMessage = '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 errorMessage = '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 errorMessage = [[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 errorMessage = '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)**
-
-
- ## <a name='functions'>Functions</a>
- - 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. This helps differentiate
- between named and anonymous functions.
-
- ```lua
- -- bad
- local nope = function(name, options)
- -- ...stuff...
- end
-
- -- good
- 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)**
-
-
- ## <a name='properties'>Properties</a>
-
- - Use dot notation when accessing known properties.
-
- ```lua
- local luke = {
- jedi = true,
- age = 28
- }
-
- -- bad
- local isJedi = luke['jedi']
-
- -- good
- local isJedi = 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 getProp(prop)
- return luke[prop]
- end
-
- local isJedi = getProp('jedi')
- ```
-
- **[[⬆]](#TOC)**
-
-
- ## <a name='variables'>Variables</a>
-
- - 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 = getName()
-
- if name == 'test' then
- return false
- end
-
- return name
- end
-
- -- good
- local function good()
- local name = getName()
-
- test()
- print('doing stuff..')
-
- //..other stuff..
-
- if name == 'test' then
- return false
- end
-
- return name
- end
- ```
-
- **[[⬆]](#TOC)**
-
-
- ## <a name='conditionals'>Conditional Expressions & Equality</a>
-
- - 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 name
-
- if first and last then
- name = first .. ' ' .. last
- else
- name = 'John Smith'
- end
-
- return name
- end
-
- --good
- local function full_name(first, last)
- local name = 'John Smith'
-
- if first and last then
- name = first .. ' ' .. last
- end
-
- return name
- end
- ```
-
- - Short ternaries are okay.
-
- ```lua
- local function default_name(name)
- -- return the default 'Waldo' if name is nil
- return name or 'Waldo'
- end
-
- local function brew_coffee(machine)
- return machine and machine.is_loaded and 'coffee brewing' or 'fill your water'
- end
- ```
-
-
- **[[⬆]](#TOC)**
-
-
- ## <a name='blocks'>Blocks</a>
-
- - 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 then
-
- do_other_complicated_function()
- return false
- end
- ```
-
- **[[⬆]](#TOC)**
-
-
- ## <a name='whitespace'>Whitespace</a>
-
- - Use soft tabs set to 2 spaces.
-
- ```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...
- end
-
- function derp()
- -- ...stuff...
- end
-
- local wat = 7
- ```
-
- - Delete unnecessary whitespace at the end of lines.
-
- **[[⬆]](#TOC)**
-
- ## <a name='commas'>Commas</a>
-
- - 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)**
-
-
- ## <a name='semicolons'>Semicolons</a>
-
- - **Nope.** Separate statements onto multiple lines.
-
- ```lua
- -- bad
- local whatever = 'sure';
- a = 1; b = 2
-
- -- good
- local whatever = 'sure'
- a = 1
- b = 2
- ```
-
- **[[⬆]](#TOC)**
-
-
- ## <a name='type-coercion'>Type Casting & Coercion</a>
-
- - 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 totalScore = reviewScore .. ''
-
- -- good
- local totalScore = tostring(reviewScore)
- ```
-
- - Use `tonumber` for Numbers.
-
- ```lua
- local inputValue = '4'
-
- -- bad
- local val = inputValue * 1
-
- -- good
- local val = tonumber(inputValue)
- ```
-
- **[[⬆]](#TOC)**
-
-
- ## <a name='naming-conventions'>Naming Conventions</a>
-
- - 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 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
- ```
-
- ## <a name='modules'>Modules</a>
-
- - 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)**
-
- ## <a name='testing'>Testing</a>
-
- - Use [telescope](https://github.com/norman/telescope) for unit tests and Robot framework for functional testing.
- Unit tests can rely on LuaJIT ffi module if C function testing is required.
-
- **[[⬆]](#TOC)**
-
- ## <a name='license'>License</a>
-
- - Released under CC0 (Public Domain).
- Information can be found at [http://creativecommons.org/publicdomain/zero/1.0/](http://creativecommons.org/publicdomain/zero/1.0/).
-
- **[[⬆]](#TOC)**
|