From 95fb8893360a601ee8285d162a87bd846fa90396 Mon Sep 17 00:00:00 2001 From: nieyong Date: Mon, 20 Jul 2020 21:55:30 +0800 Subject: [PATCH 1/3] Adding CODE_STYLE.md and CODE_STYLE_CN.md --- CODE_STYLE.md | 419 +++++++++++++++++++++++++++++++++++++++++++ CODE_STYLE_CN.md | 425 ++++++++++++++++++++++++++++++++++++++++++++ Contributing.md | 2 +- doc/zh-cn/README.md | 2 +- 4 files changed, 846 insertions(+), 2 deletions(-) create mode 100644 CODE_STYLE.md create mode 100644 CODE_STYLE_CN.md diff --git a/CODE_STYLE.md b/CODE_STYLE.md new file mode 100644 index 000000000000..8c6eafdeb6b1 --- /dev/null +++ b/CODE_STYLE.md @@ -0,0 +1,419 @@ + + +# APISIX Lua Coding Style Guide + +## indentation + +Use 4 spaces as an indent: + +```lua +--No +if a then +ngx.say("hello") +end +``` + +```lua +--Yes +if a then + ngx.say("hello") +end +``` + +You can simplify the operation by changing the tab to 4 spaces in the editor you are using. + +## Space + +On both sides of the operator, you need to use a space to separate: + +```lua +--No +local i=1 +local s = "apisix" +``` + +```lua +--Yes +local i = 1 +local s = "apisix" +``` + +## Blank line + +Many developers will add a semicolon at the end of the line: + +```lua +--No +if a then +    ngx.say("hello"); +end; +``` + +Adding a semicolon will make the Lua code look ugly and unnecessary. Also, don't want to save the number of lines in the code, the latter turns the multi-line code into one line in order to appear "simple". This will not know when the positioning error is in the end of the code: + +```lua +--No +if a then ngx.say("hello") end +``` + +```lua +--Yes +if a then + ngx.say("hello") +end +``` + +The functions needs to be separated by two blank lines: + +```lua +--No +local function foo() +end +local function bar() +end +``` + +```lua +--Yes +local function foo() +end + + +local function bar() +end +``` + +If there are multiple if elseif branches, they need a blank line to separate them: + +```lua +--No +if a == 1 then + foo() +elseif a== 2 then + bar() +elseif a == 3 then + run() +else + error() +end +``` + +```lua +--Yes +if a == 1 then + foo() + +elseif a== 2 then + bar() + +elseif a == 3 then + run() + +else + error() +end +``` + +## Maximum length per line + +Each line cannot exceed 80 characters. If it exceeds, you need to wrap and align: + +```lua +--No +return limit_conn_new("plugin-limit-conn", conf.conn, conf.burst, conf.default_conn_delay) +``` + +```lua +--Yes +return limit_conn_new("plugin-limit-conn", conf.conn, conf.burst, + conf.default_conn_delay) +``` + +When the linefeed is aligned, the correspondence between the upper and lower lines should be reflected. For the example above, the parameters of the second line of functions are to the right of the left parenthesis of the first line. + +If it is a string stitching alignment, you need to put `..` in the next line: + +```lua +--No +return limit_conn_new("plugin-limit-conn" .. "plugin-limit-conn" .. + "plugin-limit-conn") +``` + +```lua +--Yes +return limit_conn_new("plugin-limit-conn" .. "plugin-limit-conn" + .. "plugin-limit-conn") +``` + +```lua +--Yes +return "param1", "plugin-limit-conn" + .. "plugin-limit-conn") +``` + +## Variable + +Local variables should always be used, not global variables: + +```lua +--No +i = 1 +s = "apisix" +``` + +```lua +--Yes +local i = 1 +local s = "apisix" +``` + +Variable naming uses the `snake_case` style: + +```lua +--No +local IndexArr = 1 +local str_Name = "apisix" +``` + +```lua +--Yes +local index_arr = 1 +local str_name = "apisix" +``` + +Use all capitalization for constants: + +```lua +--No +local max_int = 65535 +local server_name = "apisix" +``` + +```lua +--Yes +local MAX_INT = 65535 +local SERVER_NAME = "apisix" +``` + +## Table + +Use `table.new` to pre-allocate the table: + +```lua +--No +local t = {} +for i = 1, 100 do + t[i] = i +end +``` + +```lua +--Yes +local new_tab = require "table.new" +local t = new_tab(100, 0) +for i = 1, 100 do + t[i] = i +end +``` + +Don't use `nil` in an array: + +```lua +--No +local t = {1, 2, nil, 3} +``` + +If you must use null values, use `ngx.null` to indicate: + +```lua +--Yes +local t = {1, 2, ngx.null, 3} +``` + +## String + +Do not splicing strings on the hot code path: + +```lua +--No +local s = "" +for i = 1, 100000 do + s = s .. "a" +end +``` + +```lua +--Yes +local t = {} +for i = 1, 100000 do + t[i] = "a" +end +local s = table.concat(t, "") +``` + +## Function + +The naming of functions also follows `snake_case`: + +```lua +--No +local function testNginx() +end +``` + +```lua +--Yes +local function test_nginx() +end +``` + +The function should return as early as possible: + +```lua +--No +local function check(age, name) + local ret = true + if age < 20 then + ret = false + end + + if name == "a" then + ret = false + end + -- do something else + return ret +end +``` + +```lua +--Yes +local function check(age, name) + if age < 20 then + return false + end + + if name == "a" then + return false + end + -- do something else + return true +end +``` + +## Module + +All require libraries must be localized: + +```lua +--No +local function foo() + local ok, err = ngx.timer.at(delay, handler) +end +``` + +```lua +--Yes +local timer_at = ngx.timer.at + +local function foo() + local ok, err = timer_at(delay, handler) +end +``` + +For style unification, `require` and `ngx` also need to be localized: + +```lua +--No +local core = require("apisix.core") +local timer_at = ngx.timer.at + +local function foo() + local ok, err = timer_at(delay, handler) +end +``` + +```lua +--Yes +local ngx = ngx +local require = require +local core = require("apisix.core") +local timer_at = ngx.timer.at + +local function foo() + local ok, err = timer_at(delay, handler) +end +``` + +## Error handling + +For functions that return with error information, the error information must be judged and processed: + +```lua +--No +local sock = ngx.socket.tcp() +local ok = sock:connect("www.google.com", 80) +ngx.say("successfully connected to google!") +``` + +```lua +--Yes +local sock = ngx.socket.tcp() +local ok, err = sock:connect("www.google.com", 80) +if not ok then + ngx.say("failed to connect to google: ", err) + return +end +ngx.say("successfully connected to google!") +``` + +The function you wrote yourself, the error message is to be returned as a second parameter in the form of a string: + +```lua +--No +local function foo() + local ok, err = func() + if not ok then + return false + end + return true +end +``` + +```lua +--No +local function foo() + local ok, err = func() + if not ok then + return false, {msg = err} + end + return true +end +``` + +```lua +--Yes +local function foo() + local ok, err = func() + if not ok then + return false, "failed to call func(): " .. err + end + return true +end +``` diff --git a/CODE_STYLE_CN.md b/CODE_STYLE_CN.md new file mode 100644 index 000000000000..a35f4b0f5415 --- /dev/null +++ b/CODE_STYLE_CN.md @@ -0,0 +1,425 @@ + + +# APISIX Lua 编码风格指南 + +## 缩进 + +使用 4 个空格作为缩进的标记: + +```lua +--No +if a then +ngx.say("hello") +end +``` + +```lua +--Yes +if a then + ngx.say("hello") +end +``` + +你可以在使用的编辑器中把 tab 改为 4 个空格来简化操作。 + +## 空格 + +在操作符的两边,都需要用一个空格来做分隔: + +```lua +--No +local i=1 +local s = "apisix" +``` + +```lua +--Yes +local i = 1 +local s = "apisix" +``` + +## 空行 + +不少开发者会在行尾增加一个分号: + +```lua +--No +if a then +    ngx.say("hello"); +end; +``` + +增加分号会让 Lua 代码显得非常丑陋,也是没有必要的。 + +另外,不要为了显得“简洁”节省代码行数,而把多行代码变为一行。这样会在定位错误的时候不知道到底哪一段代码出了问题: + +```lua +--No +if a then ngx.say("hello") end +``` + +```lua +--Yes +if a then + ngx.say("hello") +end +``` + +函数之间需要用两个空行来做分隔: + +```lua +--No +local function foo() +end +local function bar() +end +``` + +```lua +--Yes +local function foo() +end + + +local function bar() +end +``` + +如果有多个 if elseif 的分支,它们之间需要一个空行来做分隔: + +```lua +--No +if a == 1 then + foo() +elseif a== 2 then + bar() +elseif a == 3 then + run() +else + error() +end +``` + +```lua +--Yes +if a == 1 then + foo() + +elseif a== 2 then + bar() + +elseif a == 3 then + run() + +else + error() +end +``` + +## 每行最大长度 + +每行不能超过 80 个字符,超过的话,需要换行并对齐: + +```lua +--No +return limit_conn_new("plugin-limit-conn", conf.conn, conf.burst, conf.default_conn_delay) +``` + +```lua +--Yes +return limit_conn_new("plugin-limit-conn", conf.conn, conf.burst, + conf.default_conn_delay) +``` + +在换行对齐的时候,要体现出上下两行的对应关系。 + +就上面示例而言,第二行函数的参数,要在第一行左括号的右边。 + +如果是字符串拼接的对齐,需要把 `..` 放到下一行中: + +```lua +--No +return limit_conn_new("plugin-limit-conn" .. "plugin-limit-conn" .. + "plugin-limit-conn") +``` + +```lua +--Yes +return limit_conn_new("plugin-limit-conn" .. "plugin-limit-conn" + .. "plugin-limit-conn") +``` + +```lua +--Yes +return "param1", "plugin-limit-conn" + .. "plugin-limit-conn") +``` + +## 变量 + +应该永远使用局部变量,不要使用全局变量: + +```lua +--No +i = 1 +s = "apisix" +``` + +```lua +--Yes +local i = 1 +local s = "apisix" +``` + +变量命名使用 `snake_case`(蛇形命名法) 风格: + +```lua +--No +local IndexArr = 1 +local str_Name = "apisix" +``` + +```lua +--Yes +local index_arr = 1 +local str_name = "apisix" +``` + +对于常量要使用全部大写: + +```lua +--No +local max_int = 65535 +local server_name = "apisix" +``` + +```lua +--Yes +local MAX_INT = 65535 +local SERVER_NAME = "apisix" +``` + +## 表格/数组 + +使用 `table.new` 来预先分配数组: + +```lua +--No +local t = {} +for i = 1, 100 do + t[i] = i +end +``` + +```lua +--Yes +local new_tab = require "table.new" +local t = new_tab(100, 0) +for i = 1, 100 do + t[i] = i +end +``` + +不要在数组中使用 `nil`: + +```lua +--No +local t = {1, 2, nil, 3} +``` + +如果一定要使用空值,请用 `ngx.null` 来表示: + +```lua +--Yes +local t = {1, 2, ngx.null, 3} +``` + +## 字符串 + +不要在热代码路径上拼接字符串: + +```lua +--No +local s = "" +for i = 1, 100000 do + s = s .. "a" +end +``` + +```lua +--Yes +local t = {} +for i = 1, 100000 do + t[i] = "a" +end +local s = table.concat(t, "") +``` + +## 函数 + +函数的命名也同样遵循 `snake_case`(蛇形命名法): + +```lua +--No +local function testNginx() +end +``` + +```lua +--Yes +local function test_nginx() +end +``` + +函数应该尽可能早的返回: + +```lua +--No +local function check(age, name) + local ret = true + if age < 20 then + ret = false + end + + if name == "a" then + ret = false + end + -- do something else + return ret +end +``` + +```lua +--Yes +local function check(age, name) + if age < 20 then + return false + end + + if name == "a" then + return false + end + -- do something else + return true +end +``` + +## 模块 + +所有 `require` 的库都要 `local` 化: + +```lua + +```lua +--No +local function foo() + local ok, err = ngx.timer.at(delay, handler) +end +``` + +```lua +--Yes +local timer_at = ngx.timer.at + +local function foo() + local ok, err = timer_at(delay, handler) +end +``` + +为了风格的统一,`require` 和 `ngx` 也需要 `local` 化: + +```lua +--No +local core = require("apisix.core") +local timer_at = ngx.timer.at + +local function foo() + local ok, err = timer_at(delay, handler) +end +``` + +```lua +--Yes +local ngx = ngx +local require = require +local core = require("apisix.core") +local timer_at = ngx.timer.at + +local function foo() + local ok, err = timer_at(delay, handler) +end +``` + +## 错误处理 + +对于有错误信息返回的函数,必须对错误信息进行判断和处理: + +```lua +--No +local sock = ngx.socket.tcp() +local ok = sock:connect("www.google.com", 80) +ngx.say("successfully connected to google!") +``` + +```lua +--Yes +local sock = ngx.socket.tcp() +local ok, err = sock:connect("www.google.com", 80) +if not ok then + ngx.say("failed to connect to google: ", err) + return +end +ngx.say("successfully connected to google!") +``` + +自己编写的函数,错误信息要作为第二个参数,用字符串的格式返回: + +```lua +--No +local function foo() + local ok, err = func() + if not ok then + return false + end + return true +end +``` + +```lua +--No +local function foo() + local ok, err = func() + if not ok then + return false, {msg = err} + end + return true +end +``` + +```lua +--Yes +local function foo() + local ok, err = func() + if not ok then + return false, "failed to call func(): " .. err + end + return true +end +``` diff --git a/Contributing.md b/Contributing.md index cca0bfe37cd2..fdb53d225178 100644 --- a/Contributing.md +++ b/Contributing.md @@ -94,7 +94,7 @@ Once we've discussed your changes and you've got your code ready, make sure that ## Check code style and test case style * code style - * Please take a look at [OpenResty Lua Coding Style Guide](CODE_STYLE.md). + * Please take a look at [APISIX Lua Coding Style Guide](CODE_STYLE.md). * Use tool to check your code statically by command: `make lint`. ```shell # install `luacheck` first before run it diff --git a/doc/zh-cn/README.md b/doc/zh-cn/README.md index 88966ee4f177..b2612b7fa6ed 100644 --- a/doc/zh-cn/README.md +++ b/doc/zh-cn/README.md @@ -31,7 +31,7 @@ * [TCP/UDP 动态代理](stream-proxy.md) * [管理 API](admin-api.md) * [变更日志](../../CHANGELOG_CN.md) -* [代码风格](../CODE_STYLE.md) +* [代码风格](../../CODE_STYLE_CN.md) * [常见问答](../../FAQ_CN.md) 插件 From a0ae4c1574aa1b7373c85e4794867f808c089eeb Mon Sep 17 00:00:00 2001 From: nieyong Date: Tue, 21 Jul 2020 15:17:50 +0800 Subject: [PATCH 2/3] fix CODE_STYLE_CN.md line 20 has trailing whitespace bug --- CODE_STYLE_CN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODE_STYLE_CN.md b/CODE_STYLE_CN.md index a35f4b0f5415..9ba59c1ee2a9 100644 --- a/CODE_STYLE_CN.md +++ b/CODE_STYLE_CN.md @@ -17,7 +17,7 @@ # --> -# APISIX Lua 编码风格指南 +# APISIX Lua 编码风格指南 ## 缩进 From dd1b44dce16d6165e69d88e1a4b6bf1b98d5c82c Mon Sep 17 00:00:00 2001 From: nieyong Date: Wed, 22 Jul 2020 14:19:35 +0800 Subject: [PATCH 3/3] add chinaese/english switch for CODE_STYLE*.md --- CODE_STYLE.md | 2 ++ CODE_STYLE_CN.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/CODE_STYLE.md b/CODE_STYLE.md index 8c6eafdeb6b1..f31992ea0583 100644 --- a/CODE_STYLE.md +++ b/CODE_STYLE.md @@ -17,6 +17,8 @@ # --> +[Chinese](CODE_STYLE_CN.md) + # APISIX Lua Coding Style Guide ## indentation diff --git a/CODE_STYLE_CN.md b/CODE_STYLE_CN.md index 9ba59c1ee2a9..ed69fe1ba1a2 100644 --- a/CODE_STYLE_CN.md +++ b/CODE_STYLE_CN.md @@ -17,6 +17,8 @@ # --> +[English](CODE_STYLE.md) + # APISIX Lua 编码风格指南 ## 缩进