-
Notifications
You must be signed in to change notification settings - Fork 108
Coding style
- Indentation - 4 spaces
- Line Length - 80 characters
- Classnames - UpperCamelCase
- Functions - lowerCamelCase
- Variables - all_lower_case_with_underscores
- Constants - ALL_UPPER_CASE_WITH_UNDERSCORES
- Filenames - shortnouns
- global variables should be prefixed with
G_
:G_width
- boolean variables should be prefixed as predicates:
is_directory
- i, k, v, and t are often used as follows:
for k,v in pairs(t) ... end
for i,v in ipairs(t) ... end
mt.__newindex = function(t, k, v) ... end
UI irrelevant features should be covered by test cases. We are using busted (https://olivinelabs.com/busted/) Lua test framework. You may find samples at https://github.com/koreader/koreader/tree/master/spec/unit (front) or https://github.com/koreader/koreader-base/tree/master/spec/unit (base).
We are lacking test cases heavily. So if you would like to help with source code, but cannot find an interesting feature to work on, adding test cases for existing components is really appreciated.
Lua provides both error() and assert() functions. (https://www.lua.org/pil/8.3.html) Though we do not use it too often, they are still very useful tools to help track unexpected situations and also to save other developers time of debugging. Assertions should be avoided in following situations.
-- Checking the input parameters of a function. Usually this should be covered by the return value of a function.
-- System IO Do not expect a file can always be opened.
-- loadfile / loadstring An external source file may be edited unexpectedly, and causes trouble.
Assertions are suggested in the following situations.
-- Unreasonable values in the middle of some logic. E.g.
local x = 100
local y = min(1, x)
assert(y <= 1, "Any reason y could be larger than 1?")
-- Delay referred variables. E.g.
function C:setConfig(config)
self.config = config
end
function C:loadConfig()
assert(self.config ~= nil, "Have you forgotten to call setConfig?")
end
or
local D = C:new{}
function D:makeChoice(p)
if p then
return D:doSomething()
else
return D:doSomethingElse()
end
end
function D:doSomething() end
function D:doSomethingElse()
assert(self.default_value, "Once makeChoice(false) is called, default_value is expected")
end
Please order the requires according to the following rules:
local Class = require("class") -- Uppercase class
local Device = require("device") -- Uppercase class
local func = require("func") -- Lowercase function
local glob = require("glob") -- Lowercase function
local _ = require("gettext") -- Symbol
local T = require("ffi/util").template -- One of the functions in a file
local V = require("utils2").version -- The other function, ordered by ASCII.
The benefit of ordering requires is obvious: developers can easily find whether a dependency has been required already even when not using an advanced editor or on the web page, and reduces the possibility to redundantly require a dependency. Keeping the requires ordered is also not a heavy duty except for the first time.
-
Use locals rather than globals whenever possible.
-
End terminator
Because "end" is a terminator for many different constructs, it can help the reader (especially in a large block) if a comment is used to clarify which construct is being terminated:
for i,v in ipairs(t) do
if type(v) == "string" then
...lots of code here...
end -- if string
end -- for each t
- Check empty table
Determine if a table t is empty (including non-integer keys, which #t ignores):
if next(t) == nil then ...
Reference: http://lua-users.org/wiki/LuaStyleGuide