diff --git a/lua-guidelines.md b/lua-guidelines.md index 0159cec..16ee7be 100644 --- a/lua-guidelines.md +++ b/lua-guidelines.md @@ -1,26 +1,26 @@ -#Lua coding guidelines +# Lua coding guidelines -##Приоритеты +## Приоритеты * Читаемость кода (в том числе единообразие). * Уменьшение вероятности возникновения ошибок. * Минимизация числа изменённых строк с точки зрения системы контроля версий при модификации кода. * Производительность кода. -##Старый код +## Старый код Старый код, не соответствующий гайдлайнам, должен по возможности исправляться по ходу дела. Такие исправления оформляются отдельными коммитами. -#Code conventions +# Code conventions -##Именование переменных +## Именование переменных Никакой "венгерской нотации". (Имеется в виду запрет на формальную Systems Hungarian нотацию, в противовес содержательной Apps Hungarian. http://en.wikipedia.org/wiki/Hungarian_notation#Systems_vs._Apps_Hungarian) -Имена переменных не должны перекрывать стандартное пространство имен (table, string, os и т.д.) +Имена переменных не должны перекрывать стандартное пространство имен (`table`, `string`, `os` и т.д.) В именах переменных не рекомендуется использовать неустоявшиеся сокращения. Рекомендуется использовать идиоматические имена переменных в подходящих случаях. @@ -39,13 +39,13 @@ http://en.wikipedia.org/wiki/Hungarian_notation#Systems_vs._Apps_Hungarian) Имя переменной, обычно, существительное. -Имя переменной, содержащей объект должно содержать название этого объекта +Имя переменной, содержащей объект, должно содержать название этого объекта (см. XIV.3. Фабрики). (Обычно такая переменная — таблица.) -Имя переменной (таблицы), содержащей в себе коллекцию объектов обычно содержит -существительное во множественном числе (foos — коллекция объектов foo). +Имя переменной (таблицы), содержащей в себе коллекцию объектов, обычно содержит +существительное во множественном числе (`foos` — коллекция объектов `foo`). -Линейные коллекции (в смысле ipairs) допускается называть с суффиксом _list в +Линейные коллекции (в смысле `ipairs`) допускается называть с суффиксом _list в случаях, когда нужно особо подчеркнуть линейность. Имя булевой переменной, обычно, is_* (are_*, has_* и проч. формы to be), have_*, @@ -53,7 +53,7 @@ need_*, should_*, must_*, in_*, not_* и т.п. Количество объектов: num_*. -##Именование функций +## Именование функций Имя функции должно заключать в себе глагол либо заканчиваться на существительное с окончанием -er (чаще всего когда подразумевается "функтор"), кроме специальных @@ -66,12 +66,12 @@ need_*, should_*, must_*, in_*, not_* и т.п. для функций, не имеющих отношения к созданию объектов. Для таких функций рекомендуется префикс create_. -##Кавычки +## Кавычки -Рекомендуемые кавычки по-умолчанию - апострофы. Если в строке содержатся -апострофы - использовать для данной строки кавычки по своему усмотрению. +Рекомендуемые кавычки по-умолчанию — апострофы. Если в строке содержатся +апострофы — использовать для данной строки кавычки по своему усмотрению. -##Пробельные символы +## Пробельные символы В коде **нельзя использовать символы табуляции** (кроме мэйкфайлов). Если в строковом литерале нужен символ табуляции, используйте @@ -80,7 +80,7 @@ need_*, should_*, must_*, in_*, not_* и т.п. В коде **нужно использовать отступы шириной два пробела** (**"единичный отступ"**), кроме кода, который будет использоваться внутри Metalua. Такой код нужно -обозначить в комментариях в начале файла, и использовать отступы в три пробела. +обозначить в комментариях в начале файла и использовать отступы в три пробела. **В конце строки не должно быть пробельных символов**. @@ -97,20 +97,20 @@ need_*, should_*, must_*, in_*, not_* и т.п. a, b, c -Все бинарные операторы (=, ~=, <, >, +, -, *, /, and, or, ..) должны отделяться +Все бинарные операторы (`=, ~=, <, >, +, -, *, /, and, or`, ..) должны отделяться пробелами слева и справа. a = b a > b a .. b -Оператор # и унарный минус не отделяются пробелом от операнда, но отделяются +Оператор `#` и унарный минус не отделяются пробелом от операнда, но отделяются пробелом слева. a > #b a = -b -Оператор not отделяется пробелами слева и справа. +Оператор `not` отделяется пробелами слева и справа. a = not b @@ -123,22 +123,22 @@ need_*, should_*, must_*, in_*, not_* и т.п. a(b) -После открывающей фигурной скобки и перед закрывающей фигурной -- ставится. +После открывающей фигурной скобки и перед закрывающей фигурной — ставится. a({ b }) { a, b } Файл должен завершаться символом перевода строки. -###Пустые строки +### Пустые строки Нельзя делать подряд больше одной пустой строки. -Тело и заголовок неанонимной функции, занимающие вместе более одной строки +Тело и заголовок неанонимной функции, занимающие вместе более одной строки, должны отделяться пустыми строками до и после. -Настоятельно рекомендуется пустая строка до и после begin-end-подобных -конструкций, исключая случаи, когда begin-ы или end-ы идут подряд: +Настоятельно рекомендуется пустая строка до и после `begin-end`-подобных +конструкций, исключая случаи, когда `begin`-ы или `end`-ы идут подряд: if alpha then if beta then @@ -160,7 +160,7 @@ need_*, should_*, must_*, in_*, not_* и т.п. end end -##Правила расстановки отступов +## Правила расстановки отступов По умолчанию следует избегать разницы в отступах на соседних непустых строках большей чем в один отступ (кроме специально оговорённых случаев). @@ -183,8 +183,8 @@ need_*, should_*, must_*, in_*, not_* и т.п. ... last_key = "some_typical_value_4" -При многострочной записи код внутри, function-end, do-end, then-end, -repeat-until и подобных конструкций сдвигается вправо на один отступ. +При многострочной записи код внутри `function-end`, `do-end`, `then-end`, +`repeat-until` и подобных конструкций сдвигается вправо на один отступ. while some_long_name_operand == @@ -193,7 +193,7 @@ repeat-until и подобных конструкций сдвигается в some_stuff() end -При многострочной записи конструктора таблицы, открывающая и закрывающая +При многострочной записи конструктора таблицы открывающая и закрывающая фигурные скобки пишутся на новых строках с отступом, равным отступу первой непустой строки перед открывающей скобкой. @@ -207,11 +207,11 @@ repeat-until и подобных конструкций сдвигается в } Допускается сдвиг вправо на один отступ кода, находящегося между -begin()-end()-подобными парными конструкциями. +`begin()-end()`-подобными парными конструкциями. TODO: example -При разделении вызова функции на несколько строк, аргументы функции сдвигаются +При разделении вызова функции на несколько строк аргументы функции сдвигаются на ДВА отступа, закрывающая скобка — на один относительно строки с открывающей. Открывающую скобку желательно ставить на той же строке, что и имя функции. Желательно в этом случае писать каждый аргумент функции на новой @@ -225,12 +225,12 @@ begin()-end()-подобными парными конструкциями. ) Если при вызове функции ей передаётся единственный аргумент, и этот аргумент — -анонимная функция, создаваемая конструкцией function-end непосредственно в +анонимная функция, создаваемая конструкцией `function-end` непосредственно в момент вызова, тело функции сдвигается на ОДИН отступ (а не на два). Ключевое -слово function пишется непосредственно после открывающей скобки вызова, без -пробела между ними. Соответствующее ключевому слову function ключевое слово end +слово `function` пишется непосредственно после открывающей скобки вызова, без +пробела между ними. Соответствующее ключевому слову `function` ключевое слово `end` пишется с тем же отступом, что и строка, на которой написано -function. Закрывающая скобка вызова ставится непосредственно после end-а, без +`function`. Закрывающая скобка вызова ставится непосредственно после `end`-а, без пробела между ними. Допускается запись в одну строку. fn(function(args) @@ -264,13 +264,13 @@ function. Закрывающая скобка вызова ставится не ) ) -3) Допускается свешивание `..` при переносах - - writeln_flush( - "-> blablablablablablablablablabla " - .. blabla_blabla - .. "': blablablablablablablablablabla" - ) +3) Допускается свешивание `..` при переносах: + + writeln_flush( + "-> blablablablablablablablablabla " + .. blabla_blabla + .. "': blablablablablablablablablabla" + ) 4) @@ -303,19 +303,19 @@ function. Закрывающая скобка вызова ставится не body end -###Директива import +### Директива import -Для разбиения по строкам директивы import применяется специальное +Для разбиения по строкам директивы `import` применяется специальное форматирование, сложившееся исторически. -Каждая присваемая переменная пишется на отдельной строке. Список переменных +Каждая присваиваемая переменная пишется на отдельной строке. Список переменных выравнивается по имени первой переменной. -Сама директива import пишется на отдельной строке вместе с именем импортируемой +Сама директива `import` пишется на отдельной строке вместе с именем импортируемой библиотеки. Открывающая и закрывающая фигурные скобки для списка импорта располагаются на -отдельных строках с отступом пердыдущей строки. +отдельных строках с отступом предыдущей строки. Список импорта разбивается по строкам с дополнительным отступом от фигурных скобок. Элементы списка разделяются запятыми, не точкой с запятой (по аналогии @@ -333,7 +333,7 @@ function. Закрывающая скобка вызова ставится не 'method_arguments' } -Если список импорта состоит из одного элемента, то директива import может +Если список импорта состоит из одного элемента, то директива `import` может форматироваться либо в одну строку, с соблюдением всех общих правил, либо разбиваться по строкам, как описано выше. @@ -346,7 +346,7 @@ function. Закрывающая скобка вызова ставится не { 'is_table' -###Многострочные константы +### Многострочные константы Для строк, заключенных в long brackets, правила для отступов **не действуют**. Отступы расставляются так, чтобы при выводе строка выглядела так, как нужно. @@ -361,9 +361,9 @@ function. Закрывающая скобка вызова ставится не io.stdout:flush() -###Другие многострочные конструкции +### Другие многострочные конструкции -Многострочный return с конструкцией (... and ... or ...) выравнивается одним +Многострочный `return` с конструкцией `... and ... or ...` выравнивается одним из двух способов: Правильно: @@ -378,7 +378,7 @@ function. Закрывающая скобка вызова ставится не and bar or baz -Многострочные условия if-then, while-do и for-do оформляются либо с одинарным +Многострочные условия `if-then`, `while-do` и `for-do` оформляются либо с одинарным отступом, либо с выравниванием по пробелу после логического оператора: Правильно: @@ -399,7 +399,7 @@ function. Закрывающая скобка вызова ставится не ... end -При переносе конкатенации (..) допускается нестандартный сдвиг с выравниванием +При переносе конкатенации `..` допускается нестандартный сдвиг с выравниванием по аргументам: log( @@ -407,9 +407,9 @@ function. Закрывающая скобка вызова ставится не .. " baz" ) -##Избыточный синтаксис +## Избыточный синтаксис -Нельзя ставить скобки вокруг условия в if-then, while-do, for-do, repeat-until. +Нельзя ставить скобки вокруг условия в `if-then`, `while-do`, `for-do`, `repeat-until`. if(a == b) then -> if a == b then @@ -422,21 +422,21 @@ function. Закрывающая скобка вызова ставится не f(foo BOOLOP bar, baz) -##Синтаксический сахар +## Синтаксический сахар -Если функция не рекурсивная, используется форма определения a = function() end. +Если функция не рекурсивная, используется форма определения `a = function() end`. local a = function(args) ... end -Если функция рекурсивная -- function a() end. +Если функция рекурсивная — `function a() end`. local function a(args) ... end -При вызове методов нужно пользоваться оператором ":". +При вызове методов нужно пользоваться оператором `:`. t.method(t, args) -> t:method(args) @@ -447,17 +447,17 @@ function. Закрывающая скобка вызова ставится не В коде, написанном в декларативном стиле, желательно опускать скобки при передаче строковых литералов и конструкторов таблиц в качестве аргументов -функций. (В т. ч. "import".) +функций. (В т. ч. `import`.) Скобки при вызове функции с табличным литералом рекомендуется опускать в следующих случаях 1. При декларативной записи. -2. Когда функция трансформирует таблицу в другую таблицу (пример: tset()) -3. Когда функция сериализует таблицу (пример: luabins.save()) +2. Когда функция трансформирует таблицу в другую таблицу (пример: `tset()`) +3. Когда функция сериализует таблицу (пример: `luabins.save()`) -Нельзя опускать, когда функция просто что-то делает с таблицей -(например какой-нибудь count_number_of_keys()). +Нельзя опускать скобки, когда функция просто что-то делает с таблицей +(например какой-нибудь `count_number_of_keys()`). Правильно: @@ -472,7 +472,7 @@ function. Закрывающая скобка вызова ставится не api:input { }; -##Циклы +## Циклы * Запрещается использовать `ipairs()`. Вместо него — numeric for. @@ -535,11 +535,11 @@ function. Закрывающая скобка вызова ставится не Избавление от дублирования кода не признаётся обоснованием для использования `repeat ... until`. -##Функции +## Функции -###Проверка аргументов +### Проверка аргументов -####Штатная проверка аргументов +#### Штатная проверка аргументов local is_log_enabled_raw = function( modules_config, @@ -556,7 +556,7 @@ function. Закрывающая скобка вызова ставится не ... end -####Аргументы по умолчанию +#### Аргументы по умолчанию local foo = function(bar) bar = bar or BAZ @@ -564,7 +564,7 @@ function. Закрывающая скобка вызова ставится не "quo", bar ) -##Конструкторы таблиц +## Конструкторы таблиц Если таблица создаётся на одной строке, желательно отделять её элементы запятыми. Если список разделён запятыми, в конце списка "висящая" запятая @@ -573,7 +573,7 @@ function. Закрывающая скобка вызова ставится не local ks = { "k1", "k2", "k3" } Если таблица создаётся на нескольких строках, желательно отделять её элементы -точками с запятой, и располагать по одному элементу на строке. +точками с запятой и располагать по одному элементу на строке. Если список разделён точками с запятой, в конце списка также ставится точка с запятой. @@ -610,7 +610,7 @@ function. Закрывающая скобка вызова ставится не ["true"] = true, ["until"] = true, ["while"] = true; } -##Видимость переменных +## Видимость переменных Область видимости переменных должна быть максимально ограничена, насколько позволяет здравый смысл в каждой конкретной ситуации. @@ -620,7 +620,7 @@ function. Закрывающая скобка вызова ставится не документироватья в коде. Видимость переменных в глобальном scope файла следует максимально ограничивать -блоками do-end. +блоками `do-end`. local some_stuff do @@ -642,8 +642,8 @@ function. Закрывающая скобка вызова ставится не (допускаются обоснованные исключения, например в случаях, когда это улучшает читаемость кода). -Стандартные глобальные переменные (например, print, error) желательно -"кешировать" в локальные в начале файла: local print, error = print, error. Это +Стандартные глобальные переменные (например, `print`, `error`) желательно +"кешировать" в локальные в начале файла: `local print, error = print, error`. Это позволяет создать код, который будет без "из коробки" работать внутри sandbox'а с заменённым глобальным окружением. @@ -653,7 +653,7 @@ function. Закрывающая скобка вызова ставится не local os_time, os_date = os.time, os.date -##Описание объектов +## Описание объектов Для создания объектов с однотипным поведением (методами) cледует использовать фабрики, которые должны быть написаны по следующему формату: @@ -673,7 +673,7 @@ function. Закрывающая скобка вызова ставится не end end -Поля таблицы с подчеркиванием в конце - приватные данные. +Поля таблицы с подчеркиванием в конце — приватные данные. В особых случаях, с разрешения техлида допускаются способы с использованием метатаблиц или upvalue. @@ -720,14 +720,14 @@ function. Закрывающая скобка вызова ставится не end end -##FFI +## FFI -###Основы +### Основы -- [[http://luajit.org/ext_ffi.html]] -- [[http://stackoverflow.com/questions/7167566/luajit-2-optimization-guide]] +- http://luajit.org/ext_ffi.html +- http://stackoverflow.com/questions/7167566/luajit-2-optimization-guide -###Объявление +### Объявление Введение @@ -765,7 +765,7 @@ function. Закрывающая скобка вызова ставится не myfoo = myfoo; } -###Использование +### Использование local myfoo = import 'ffi/myfoo.lua' { 'myfoo' } myfoo.foofunc(...) @@ -776,21 +776,21 @@ function. Закрывающая скобка вызова ставится не Этот документ пока не определяет, как быть с низкоуровневыми функциями FFI, такими как `ffi.string`, `ffi.copy` и т.п. -##Модули +## Модули **TODO** -##Разделение кода на файлы +## Разделение кода на файлы **TODO** -##Общая культура программирования +## Общая культура программирования * В коде следует избегать использования безымянных "магических констант": http://en.wikipedia.org/wiki/Magic_number_(programming)#Unnamed_numerical_constants * Запрещается пренебрегать штатными средствами экранирования при динамическом - составлегии запросов в базу. + составлении запросов в базу. ### Статические переменные и объекты @@ -798,15 +798,15 @@ function. Закрывающая скобка вызова ставится не Нежелательно: - local state - ... - local foo = function(bar) - state = bar - end - ... - local baz = function() - print(state) - end + local state + ... + local foo = function(bar) + state = bar + end + ... + local baz = function() + print(state) + end Исключение — для системных объектов-синглтонов, с соответствующим комментарием, при наличии разрешения техлида. @@ -817,21 +817,21 @@ function. Закрывающая скобка вызова ставится не Нежелательно: - local fooer - do - fooer = - { - bar_ = 42; - } - end + local fooer + do + fooer = + { + bar_ = 42; + } + end У объекта в обязательном порядке должна быть фабрика. Мотивация — вредит реюзу кода, усложняет рефакторинг. -##Тесты +## Тесты -###Именование тестов +### Именование тестов Имя теста должно описывать, что проверяет тест. Имя должно писаться без пробелов; отдельные слова в имени разделяются дефисом. @@ -860,10 +860,10 @@ function. Закрывающая скобка вызова ставится не local test = (...)("apigen") -Имена файлов с тестами начинаются с порядкового четырехзначного номера, вида +Имена файлов с тестами начинаются с порядкового четырехзначного номера вида `NNNM`, в котором старшие три разряда `NNN` используются для упорядочивания групп тестов, а младший `M` — для задания порядка тестов в одной группе. -(в большинстве случаев используется один файл в группе, и фактически идет +(В большинстве случаев используется один файл в группе, и фактически идет нумерация с шагом 10. В случае сомнений лучше спросить лида). Номера вида `000N` зарезервированы для "does it work" тестов. @@ -874,10 +874,10 @@ function. Закрывающая скобка вызова ставится не test/cases/0020-first-test-in-group.lua test/cases/0021-second-test-in-group.lua -###Отступы при оформлении тестов +### Отступы при оформлении тестов -Если у теста очень длинное имя, и `(function()` не помещается на той же строке, -рекоммендуется как-нибудь сократить имя, чтобы `function()` всё-таки уместилось. +Если у теста очень длинное имя и `function()` не помещается на той же строке, +рекомендуется как-нибудь сократить имя, чтобы `function()` всё-таки уместилось. Не рекомендуется: @@ -927,7 +927,7 @@ function. Закрывающая скобка вызова ставится не ... end) -###Тестовые значения и сообщения об ошибках +### Тестовые значения и сообщения об ошибках В коде тестов рекомендуется вместо `assert()` использовать специализированные функции из `lua-nucleo/ensure.lua`. @@ -972,24 +972,24 @@ function. Закрывающая скобка вызова ставится не ) ) -##Устаревшие и запрещенные выражения языка +## Устаревшие и запрещенные выражения языка Текущим стандартом языка является Lua 5.1. Нельзя использовать в коде выражения и методы, которые были объявлены в нем устаревшими, даже если они еще работают. К таким в частности относятся: * `arg` (таблица переменных, переданных в функцию открытым списком) — - вместо неё надо использовать select(n, ...) -* `string.len` - вместо него надо использовать оператор длины # -* `table.getn` - вместо него надо использовать оператор длины # -* `ipairs` - вместо него следует использовать numeric for + вместо неё надо использовать `select(n, ...)` +* `string.len` — вместо него надо использовать оператор длины `#` +* `table.getn` — вместо него надо использовать оператор длины `#` +* `ipairs` — вместо него следует использовать numeric for Некоторые выражения и методы нельзя использовать в коде по соображениям его безопасности. К таким в частности относятся: * `os.tmpname` (см. http://www.lua.org/manual/5.1/manual.html#pdf-os.tmpname) -##Подключение логгеров +## Подключение логгеров Логгеры должны присутствовать в каждом файле каждой библиотеки ниже lua-aplicado. @@ -1008,13 +1008,13 @@ function. Закрывающая скобка вызова ставится не "test/config_dsl", "T001" ) -Вместо LIBRARY подставьте имя библиотеки с нужным вариантом make_loggers. +Вместо LIBRARY подставьте имя библиотеки с нужным вариантом `make_loggers`. Если правите файл, в котором они подключены по старой схеме (с отдельным импортом `make_loggers`), желательно отдельным коммитом привести его в современный вид. -###Использование логгеров +### Использование логгеров В логгерах нет необходимости использовать функции преобразования к строке. Это происходит автоматически @@ -1045,8 +1045,8 @@ function. Закрывающая скобка вызова ставится не log("values: b =", b, "; c =", c) -Используйте адекватные ситуации логгеры, для ошибок - log_error, для рутиннной -информации - log, для отладки - dbg. +Используйте адекватные ситуации логгеры, для ошибок — `log_error`, для рутиннной +информации — `log`, для отладки — `dbg`. Неверно: @@ -1081,11 +1081,11 @@ function. Закрывающая скобка вызова ставится не log("values: b =", b, "; c =", c) -###Обязательное логирование +### Обязательное логирование -1. math.randomseed при его установке в какое-либо значение +1. `math.randomseed` при его установке в какое-либо значение -##Обработка ошибок +## Обработка ошибок При вызове ошибки стоит использовать `error(...)`, а не `assert(nil, ...)`. Данная рекомендация введена для улучшения читаемости кода и не имеет иного @@ -1121,7 +1121,7 @@ error message, необходимо в обязательном порядке error("a not equal b") end -##luarocks rockspecs +## luarocks rockspecs Пустой сорс разрешен только с комментарием: @@ -1133,7 +1133,7 @@ error message, необходимо в обязательном порядке Для форматирования рокспеков использовать те же стандарты, что используются для прочего луашного кода. -##Пути к файлам/директориям и работа с ними +## Пути к файлам/директориям и работа с ними * Пути к файлам/директориям записываются без финального слэша. @@ -1145,10 +1145,10 @@ error message, необходимо в обязательном порядке Неправильно: - doc_md_filename = PROJECT_PATH .. "doc/apigen/client_api.md" + doc_md_filename = PROJECT_PATH .. "doc/apigen/client_api.md" Правильно: - doc_md_filename = join_path(PROJECT_PATH, "doc/apigen/client_api.md") + doc_md_filename = join_path(PROJECT_PATH, "doc/apigen/client_api.md") Мотивация: избавляемся от проблем, связанных с ожиданием финального слэша в путях.