{"id":13896955,"url":"https://github.com/hslua/lua-style-guide","last_synced_at":"2025-03-06T08:29:19.664Z","repository":{"id":49822354,"uuid":"314864568","full_name":"hslua/lua-style-guide","owner":"hslua","description":"Lua style guide","archived":false,"fork":false,"pushed_at":"2021-06-09T15:32:06.000Z","size":17,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-01-16T19:47:15.218Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hslua.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-11-21T17:20:22.000Z","updated_at":"2025-01-05T15:03:50.000Z","dependencies_parsed_at":"2022-09-19T08:40:55.680Z","dependency_job_id":null,"html_url":"https://github.com/hslua/lua-style-guide","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hslua%2Flua-style-guide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hslua%2Flua-style-guide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hslua%2Flua-style-guide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hslua%2Flua-style-guide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hslua","download_url":"https://codeload.github.com/hslua/lua-style-guide/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242175046,"owners_count":20084317,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-06T18:03:15.447Z","updated_at":"2025-03-06T08:29:19.633Z","avatar_url":"https://github.com/hslua.png","language":null,"readme":"# Lua Style Guide\n\nThis style guide contains a list of guidelines that we try to follow\nfor our projects. It does not attempt to make arguments for the\nstyles; its goal is to provide consistency across projects.\n\nFeel free to fork this style guide and change to your own liking,\nand file issues / pull requests if you have questions, comments, or\nif you find any mistakes or typos.\n\n\n## \u003ca name='TOC'\u003eTable of Contents\u003c/a\u003e\n\n   1. [Types](#types)\n   2. [Tables](#tables)\n   3. [Strings](#strings)\n   4. [Functions](#functions)\n   5. [Properties](#properties)\n   6. [Variables](#variables)\n   7. [Conditional Expressions \u0026 Equality](#conditional-expressions--equality)\n   8. [Blocks](#blocks)\n   9. [Whitespace](#whitespace)\n  10. [Commas](#commas)\n  11. [Semicolons](#semicolons)\n  12. [Type Casting \u0026 Coercion](#type-casting--coercion)\n  13. [Naming Conventions](#naming-conventions)\n  14. [Modules](#modules)\n  15. [File Structure](#file-structure)\n  16. [Testing](#testing)\n  17. [Contributors](#contributors)\n  18. [License](#license)\n\n## Types\n\n  - **Primitives**: When you access a primitive type you work\n    directly on its value\n\n    + `string`\n    + `number`\n    + `boolean`\n    + `nil`\n\n    ```lua\n    local foo = 1\n    local bar = foo\n\n    bar = 9\n\n    print(foo, bar) -- =\u003e 1\t9\n    ```\n\n  - **Complex**: When you access a complex type you work on a\n    reference to its value\n\n    + `table`\n    + `function`\n    + `userdata`\n\n    ```lua\n    local foo = { 1, 2 }\n    local bar = foo\n\n    bar[0] = 9\n    foo[1] = 3\n\n    print(foo[0], bar[0]) -- =\u003e 9   9\n    print(foo[1], bar[1]) -- =\u003e 3   3\n    print(foo[2], bar[2]) -- =\u003e 2   2\n    ```\n\n    **[[⬆]](#TOC)**\n\n## Tables\n\n  - Use the constructor syntax for table property creation where\n    possible.\n\n    ```lua\n    -- bad\n    local player = {}\n    player.name = 'Jack'\n    player.class = 'Rogue'\n\n    -- good\n    local player = {\n      name = 'Jack',\n      class = 'Rogue'\n    }\n    ```\n\n  - Define functions externally to table definition.\n\n    ```lua\n    -- bad\n    local player = {\n      attack = function()\n      -- ...stuff...\n      end\n    }\n\n    -- good\n    local function attack()\n    end\n\n    local player = {\n      attack = attack\n    }\n    ```\n\n  - Consider `nil` properties when selecting lengths. A good idea is\n    to store an `n` property on lists that contain the length (as\n    noted in [Storing Nils in\n    Tables](http://lua-users.org/wiki/StoringNilsInTables))\n\n    ```lua\n    -- nils don't count\n    local list = {}\n    list[0] = nil\n    list[1] = 'item'\n\n    print(#list) -- 0\n    print(select('#', list)) -- 1\n    ```\n\n  - When tables have functions, use `self` when referring to itself.\n\n    ```lua\n    -- bad\n    local me = {\n      fullname = function(this)\n        return this.first_name + ' ' + this.last_name\n      end\n    }\n\n    -- good\n    local me = {\n      fullname = function(self)\n        return self.first_name + ' ' + self.last_name\n      end\n    }\n    ```\n\n    **[[⬆]](#TOC)**\n\n## Strings\n\n  - Use single quotes `''` for strings.\n\n    ```lua\n    -- bad\n    local name = \"Bob Parr\"\n\n    -- good\n    local name = 'Bob Parr'\n\n    -- bad\n    local full_name = \"Bob \" .. self.last_name\n\n    -- good\n    local full_name = 'Bob ' .. self.last_name\n    ```\n\n  - Strings longer than 80 characters should be written across\n    multiple lines using concatenation. This allows you to indent\n    nicely.\n\n    ```lua\n    -- bad\n    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.'\n\n    -- bad\n    local error_message = 'This is a super long error that \\\n    was thrown because of Batman. \\\n    When you stop to think about \\\n    how Batman had anything to do \\\n    with this, you would get nowhere \\\n    fast.'\n\n\n    -- bad\n    local error_message = [[This is a super long error that\n      was thrown because of Batman.\n      When you stop to think about\n      how Batman had anything to do\n      with this, you would get nowhere\n      fast.]]\n\n    -- good\n    local error_message = 'This is a super long error that ' ..\n      'was thrown because of Batman. ' ..\n      'When you stop to think about ' ..\n      'how Batman had anything to do ' ..\n      'with this, you would get nowhere ' ..\n      'fast.'\n    ```\n\n    **[[⬆]](#TOC)**\n\n\n## Functions\n  - Prefer lots of small functions to large, complex functions.\n    [Smalls Functions Are Good For The\n    Universe](http://kikito.github.io/blog/2012/03/16/small-functions-are-good-for-the-universe/).\n\n  - Prefer function syntax over variable syntax at the top level.\n\n    ```lua\n    -- AVOID\n    local nope = function(name, options)\n      -- ...stuff...\n    end\n\n    -- BETTER\n    local function yup(name, options)\n      -- ...stuff...\n    end\n    ```\n\n  - Never name a parameter `arg`, this will take precendence over\n    the `arg` object that is given to every function scope in older\n    versions of Lua.\n\n    ```lua\n    -- bad\n    local function nope(name, options, arg)\n      -- ...stuff...\n    end\n\n    -- good\n    local function yup(name, options, ...)\n      -- ...stuff...\n    end\n    ```\n\n  - Perform validation early and return as early as possible.\n\n    ```lua\n    -- bad\n    local is_good_name = function(name, options, arg)\n      local is_good = #name \u003e 3\n      is_good = is_good and #name \u003c 30\n\n      -- ...stuff...\n\n      return is_bad\n    end\n\n    -- good\n    local is_good_name = function(name, options, args)\n      if #name \u003c 3 or #name \u003e 30 then return false end\n\n      -- ...stuff...\n\n      return true\n    end\n    ```\n\n  **[[⬆]](#TOC)**\n\n\n## Properties\n\n  - Use dot notation when accessing known properties.\n\n    ```lua\n    local luke = {\n      jedi = true,\n      age = 28\n    }\n\n    -- bad\n    local is_jedi = luke['jedi']\n\n    -- good\n    local is_jedi = luke.jedi\n    ```\n\n  - Use subscript notation `[]` when accessing properties with a\n    variable or if using a table as a list.\n\n    ```lua\n    local luke = {\n      jedi = true,\n      age = 28\n    }\n\n    local function get_prop(prop)\n      return luke[prop]\n    end\n\n    local is_jedi = get_prop('jedi')\n    ```\n\n    **[[⬆]](#TOC)**\n\n\n## Variables\n\n  - Always use `local` to declare variables. Not doing so will\n    result in global variables to avoid polluting the global\n    namespace.\n\n    ```lua\n    -- bad\n    superPower = SuperPower()\n\n    -- good\n    local superPower = SuperPower()\n    ```\n\n  - Assign variables at the top of their scope where possible. This\n    makes it easier to check for existing variables.\n\n    ```lua\n    -- bad\n    local bad = function()\n      test()\n      print('doing stuff..')\n\n      //..other stuff..\n\n      local name = get_name()\n\n      if name == 'test' then\n        return false\n      end\n\n      return name\n    end\n\n    -- good\n    local function good()\n      local name = get_name()\n\n      test()\n      print('doing stuff..')\n\n      //..other stuff..\n\n      if name == 'test' then\n        return false\n      end\n\n      return name\n    end\n    ```\n\n    **[[⬆]](#TOC)**\n\n\n## Conditional Expressions \u0026 Equality\n\n  - False and nil are *falsy* in conditional expressions. All else\n    is true.\n\n    ```lua\n    local str = ''\n\n    if str then\n      -- true\n    end\n    ```\n\n  - Use shortcuts when you can, unless you need to know the\n    difference between false and nil.\n\n    ```lua\n    -- bad\n    if name ~= nil then\n      -- ...stuff...\n    end\n\n    -- good\n    if name then\n      -- ...stuff...\n    end\n    ```\n\n  - Prefer *true* statements over *false* statements where it makes\n    sense. Prioritize truthy conditions when writing multiple\n    conditions.\n\n    ```lua\n    --bad\n    if not thing then\n      -- ...stuff...\n    else\n      -- ...stuff...\n    end\n\n    --good\n    if thing then\n      -- ...stuff...\n    else\n      -- ...stuff...\n    end\n    ```\n\n  - Prefer defaults to `else` statements where it makes sense. This\n    results in less complex and safer code at the expense of\n    variable reassignment, so situations may differ.\n\n    ```lua\n    --bad\n    local function full_name(first, last)\n      local name\n\n      if first and last then\n        name = first .. ' ' .. last\n      else\n        name = 'John Smith'\n      end\n\n      return name\n    end\n\n    --good\n    local function full_name(first, last)\n      local name = 'John Smith'\n\n      if first and last then\n        name = first .. ' ' .. last\n      end\n\n      return name\n    end\n    ```\n\n  - Short ternaries are okay.\n\n    ```lua\n    local function default_name(name)\n      -- return the default 'Waldo' if name is nil\n      return name or 'Waldo'\n    end\n\n    local function brew_coffee(machine)\n      return machine and machine.is_loaded\n        and 'coffee brewing' or 'fill your water'\n    end\n    ```\n\n\n    **[[⬆]](#TOC)**\n\n\n## Blocks\n\n  - Single line blocks are okay for *small* statements. Try to keep\n    lines to 80 characters. Indent lines if they overflow past the\n    limit.\n\n    ```lua\n    -- good\n    if test then return false end\n\n    -- good\n    if test then\n      return false\n    end\n\n    -- bad\n    if test \u003c 1 and do_complicated_function(test) == false or seven == 8 and nine == 10 then do_other_complicated_function()end\n\n    -- good\n    if test \u003c 1 and do_complicated_function(test) == false or\n        seven == 8 and nine == 10 then\n\n      do_other_complicated_function()\n      return false\n    end\n    ```\n\n    **[[⬆]](#TOC)**\n\n\n## Whitespace\n\n  - Use two spaces for indentation.\n\n    ```lua\n    -- bad\n    function()\n    ∙∙∙∙local name\n    end\n\n    -- bad\n    function()\n    ∙local name\n    end\n\n    -- good\n    function()\n    ∙∙local name\n    end\n    ```\n\n  - Place 1 space before opening and closing braces. Place no spaces\n    around parens.\n\n    ```lua\n    -- bad\n    local test = {one=1}\n\n    -- good\n    local test = { one = 1 }\n\n    -- bad\n    dog.set('attr',{\n      age = '1 year',\n      breed = 'Bernese Mountain Dog'\n    })\n\n    -- good\n    dog.set('attr', {\n      age = '1 year',\n      breed = 'Bernese Mountain Dog'\n    })\n    ```\n\n  - Place an empty newline at the end of the file.\n\n    ```lua\n    -- bad\n    (function(global)\n      -- ...stuff...\n    end)(self)\n    ```\n\n    ```lua\n    -- good\n    (function(global)\n      -- ...stuff...\n    end)(self)\n\n    ```\n\n  - Surround operators with spaces.\n\n    ```lua\n    -- bad\n    local thing=1\n    thing = thing-1\n    thing = thing*1\n    thing = 'string'..'s'\n\n    -- good\n    local thing = 1\n    thing = thing - 1\n    thing = thing * 1\n    thing = 'string' .. 's'\n    ```\n\n  - Use one space after commas.\n\n    ```lua\n    --bad\n    local thing = {1,2,3}\n    thing = {1 , 2 , 3}\n    thing = {1 ,2 ,3}\n\n    --good\n    local thing = {1, 2, 3}\n    ```\n\n  - Add a line break after multiline blocks.\n\n    ```lua\n    --bad\n    if thing then\n      -- ...stuff...\n    end\n    function derp()\n      -- ...stuff...\n    end\n    local wat = 7\n\n    --good\n    if thing then\n      -- ...stuff...\n    end\n\n    function derp()\n      -- ...stuff...\n    end\n\n    local wat = 7\n    ```\n\n  - Delete unnecessary whitespace at the end of lines.\n\n    **[[⬆]](#TOC)**\n\n## Commas\n\n  - Leading commas aren't okay. An ending comma on the last item is\n    okay but discouraged.\n\n    ```lua\n    -- bad\n    local thing = {\n      once = 1\n    , upon = 2\n    , aTime = 3\n    }\n\n    -- good\n    local thing = {\n      once = 1,\n      upon = 2,\n      aTime = 3\n    }\n\n    -- okay\n    local thing = {\n      once = 1,\n      upon = 2,\n      aTime = 3,\n    }\n    ```\n\n    **[[⬆]](#TOC)**\n\n\n## Semicolons\n\n  - **Nope.** Separate statements onto multiple lines.\n\n    ```lua\n    -- bad\n    local whatever = 'sure';\n    a = 1; b = 2\n\n    -- good\n    local whatever = 'sure'\n    a = 1\n    b = 2\n    ```\n\n    **[[⬆]](#TOC)**\n\n\n## Type Casting \u0026 Coercion\n\n  - Perform type coercion at the beginning of the statement. Use the\n    built-in functions. (`tostring`, `tonumber`, etc.)\n\n  - Use `tostring` for strings if you need to cast without string\n    concatenation.\n\n    ```lua\n    -- bad\n    local total_score = review_score .. ''\n\n    -- good\n    local total_score = tostring(review_score)\n    ```\n\n  - Use `tonumber` for Numbers.\n\n    ```lua\n    local input_value = '4'\n\n    -- bad\n    local val = input_value * 1\n\n    -- good\n    local val = tonumber(input_value)\n    ```\n\n    **[[⬆]](#TOC)**\n\n\n## Naming Conventions\n\n  - Avoid single letter names. Be descriptive with your naming. You\n    can get away with single-letter names when they are variables in\n    loops.\n\n    ```lua\n    -- bad\n    local function q()\n      -- ...stuff...\n    end\n\n    -- good\n    local function query()\n      -- ..stuff..\n    end\n    ```\n\n  - Use underscores for ignored variables in loops.\n\n    ```lua\n    --good\n    for _, name in pairs(names) do\n      -- ...stuff...\n    end\n    ```\n\n  - Use snake_case when naming objects, functions, and instances.\n    Tend towards verbosity if unsure about naming.\n\n    ```lua\n    -- bad\n    local OBJEcttsssss = {}\n    local thisIsMyObject = {}\n    local this-is-my-object = {}\n\n    local c = function()\n      -- ...stuff...\n    end\n\n    -- good\n    local this_is_my_object = {}\n\n    local function do_that_thing()\n      -- ...stuff...\n    end\n    ```\n\n  - Use PascalCase for factories.\n\n    ```lua\n    -- bad\n    local player = require('player')\n\n    -- good\n    local Player = require('player')\n    local me = Player({ name = 'Jack' })\n    ```\n\n    **[[⬆]](#TOC)**\n\n  - Use `is` or `has` for boolean-returning functions that are part\n    of tables.\n\n    ```lua\n    --bad\n    local function evil(alignment)\n      return alignment \u003c 100\n    end\n\n    --good\n    local function is_evil(alignment)\n      return alignment \u003c 100\n    end\n    ```\n\n## Modules\n\n  - The module should return a table or function.\n  - The module should not use the global namespace for anything\n    ever. The module should be a closure.\n  - The file should be named like the module.\n\n    ```lua\n    -- thing.lua\n    local thing = { }\n\n    local meta = {\n      __call = function(self, key, vars)\n        print key\n      end\n    }\n\n\n    return setmetatable(thing, meta)\n    ```\n\n  - Note that modules are [loaded as\n    singletons](http://lua-users.org/wiki/TheEssenceOfLoadingCode)\n    and therefore should usually be factories (a function returning\n    a new instance of a table) unless static (like utility\n    libraries.)\n\n  **[[⬆]](#TOC)**\n\n## File Structure\n\n  - Files should be named in all lowercase.\n  - Lua files should be in a top-level `src` folder. The main\n    library file should be called `modulename.lua`.\n  - Rockspecs, license, readme, etc should be in the top level.\n  - Tests should be in a top-level spec folder.\n  - Executables should be in a top-level bin folder.\n  - Example:\n\n    ```\n    ./my_module\n      bin/\n        script.sh\n\n      spec/\n        my_module_spec.lua\n        some_file.lua\n\n      src/\n        my_module.lua\n        some_file.lua\n\n      README.md\n      LICENSE.md\n    ```\n\n## Testing\n\n  - Use [busted](http://olivinelabs.com/busted) and write lots of\n    tests in a /spec folder. Separate tests by module.\n  - Use descriptive `describe` and `it` blocks so it's obvious to\n    see what precisely is failing.\n  - Test interfaces. Don't test private methods. If you need to test\n    something that is private, it probably shouldn't be private in\n    the first place.\n  - Example:\n\n    ```\n    ./my_module\n      bin/\n        script.sh\n\n      spec/\n        my_module_spec.lua\n\n        util/\n          formatters_spec.lua\n\n      src/\n        my_module.lua\n\n        util/\n          formatters.lua\n\n      README.md\n      LICENSE.md\n    ```\n\n    **[[⬆]](#TOC)**\n\n## Contributors\n\n  - [View contributors](https://github.com/hslua/lua-style-guide/graphs/contributors)\n\n    **[[⬆]](#TOC)**\n\n## License\n\n  - Released under CC0 (Public Domain). Information can be found at\n    \u003chttp://creativecommons.org/publicdomain/zero/1.0/\u003e.\n\n**[[⬆]](#TOC)**\n","funding_links":[],"categories":["Others"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhslua%2Flua-style-guide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhslua%2Flua-style-guide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhslua%2Flua-style-guide/lists"}