{"id":24631141,"url":"https://github.com/svenmarcus/lua-pie","last_synced_at":"2025-05-08T00:49:59.426Z","repository":{"id":117465390,"uuid":"154592045","full_name":"SvenMarcus/lua-pie","owner":"SvenMarcus","description":"A class library for Lua","archived":false,"fork":false,"pushed_at":"2019-04-08T08:23:56.000Z","size":99,"stargazers_count":23,"open_issues_count":1,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-05-08T00:49:50.912Z","etag":null,"topics":["lua","lua-pie","oop"],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SvenMarcus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-10-25T01:29:46.000Z","updated_at":"2025-03-08T01:29:15.000Z","dependencies_parsed_at":null,"dependency_job_id":"ae8c42b4-63bd-432f-953e-6187136d0139","html_url":"https://github.com/SvenMarcus/lua-pie","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SvenMarcus%2Flua-pie","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SvenMarcus%2Flua-pie/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SvenMarcus%2Flua-pie/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SvenMarcus%2Flua-pie/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SvenMarcus","download_url":"https://codeload.github.com/SvenMarcus/lua-pie/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252978686,"owners_count":21834913,"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":["lua","lua-pie","oop"],"created_at":"2025-01-25T07:14:46.529Z","updated_at":"2025-05-08T00:49:59.401Z","avatar_url":"https://github.com/SvenMarcus.png","language":"Lua","readme":"# lua-pie\n\n## Table of contents\n\n- [lua-pie](#lua-pie)\n  - [Table of contents](#table-of-contents)\n  - [Overview](#overview)\n  - [Installation](#installation)\n  - [Usage](#usage)\n    - [Writing classes](#writing-classes)\n    - [Instantiating objects](#instantiating-objects)\n    - [Inheritance](#inheritance)\n    - [Interfaces](#interfaces)\n    - [Polymorphism](#polymorphism)\n    - [Operators](#operators)\n    - [Utilities](#utilities)\n  - [Important Notes](#important-notes)\n\n## Overview\n\nlua-pie (polymorphism, ineritance and encapsulation) is a class library for Lua.\nCurrently lua-pie supports interfaces with abstract methods and classes with private, public and static methods as well as inheritance with polymorphism via the respective keywords. Private member variables can be declared with the `self` keyword in the constructor. Classes may also contain metamethods using the operator keyword.\n\n## Installation\n\nYou can download lua-pie from luarocks with\n\n```\nluarocks install lua-pie\n```\n\nOr you can just clone or download this repository from github and use `lua-pie.lua` in your project.\n\n## Usage\n\n### Writing classes\n\nClasses are created with the `class` keyword followed by the name of the class and a table containing method definitions. Method definitions are wrappend in a public, private or static block.\nCurrently the static block is the only one allowed to contain non-function values.\n\n```lua\nlocal pie = require \"lua-pie\"\nlocal class = pie.class\nlocal public = pie.public\nlocal private = pie.private\n\n\nclass \"Greeter\" {\n\n    public {\n        say_hello = function(self, name)\n            self:private_hello(name)\n        end\n    };\n\n    private {\n        private_hello = function(self, name)\n            print(\"Hello \"..name)\n        end\n    }\n}\n```\n\n### Instantiating objects\n\nClasses are imported via the `import` function. After that they can be called to create a new instance. If a `constructor` function is defined in the `public` block it will be called when creating the object.\n\n```lua\nlocal pie = require \"lua-pie\"\nlocal import = pie.import\n\nlocal Greeter = import(\"Greeter\")\nlocal greeter = Greeter()\n\ngreeter:say_hello(\"World\")\n-- Output: Hello World\n\ngreeter:private_hello(\"World\")\n-- Output: Error. Trying to access private member private_hello\n```\n\n### Inheritance\n\nlua-pie allows single inheritance. A class can extend another class by using the `extends` function within the class definition.\n\n```lua\nlocal pie = require \"lua-pie\"\nlocal class = pie.class\nlocal public = pie.public\nlocal private = pie.private\n\n\nclass \"Person\" {\n\n    extends \"Greeter\";\n\n    public {\n        constructor = function(self, name)\n            self.name = name\n        end;\n\n        introduce = function(self)\n            print(\"Hi! My name is \"..self.name)\n        end;\n    };\n}\n\nlocal Person = import(\"Person\")\n\nlocal slim = Person(\"Slim Shady\")\n\nslim:introduce()\n-- Output: Hi! My name is Slim Shady\n\nslim:say_hello(\"World\")\n-- Output: Hello World\n```\n\n### Interfaces\n\nlua-pie also provides support for interfaces. Interfaces may only contain abstract functions. All functions are public by default.\nA class can implement an interface by using the `implements` function within the class definition. The argument to the `implements` function can either be a single class name as string or a table of class names.\nIf a class does not implement all functions defined by an interface an error will be thrown.\n\n```lua\nlocal pie = require \"lua-pie\"\nlocal interface = pie.interface\nlocal implements = pie.implements\nlocal abstract_function = pie.abstract_function\nlocal class = pie.class\nlocal public = pie.public\nlocal private = pie.private\n\ninterface \"IGreeter\" {\n\n    say_hello = abstract_function(\"self\", \"name\")\n}\n\ninterface \"IShouter\" {\n    shout = abstract_function()\n}\n\nclass \"Greeter\" {\n\n    implements {\n        \"IGreeter\",\n        \"IShouter\"\n    };\n\n    public {\n        say_hello = function(self, name)\n            self:private_hello(name)\n        end;\n\n        shout = function(self)\n            print(\"I CAN SHOUT REALLY LOUD!\")\n        end\n    };\n\n    private {\n        private_hello = function(self, name)\n            print(\"Hello \"..name)\n        end;\n    }\n}\n```\n\n### Polymorphism\n\nMethods can be overriden in subclasses, thus enabling polymorphism. Moreover every derived class has a field `self.super` which is an instance of the super class.\nThe super class instance will be created using the same arguments passed into the derived class constructor.\n\n```lua\nclass \"Person\" {\n\n    extends \"Greeter\";\n\n    public {\n        constructor = function(self, name)\n            self.name = name\n        end;\n\n        introduce = function(self)\n            print(\"Hi! My name is \"..self.name)\n        end;\n\n        say_hello = function(self, name)\n            self.super:say_hello(name)\n            print(\"Hello Override\")\n        end;\n    };\n\n}\n\nlocal Person = import(\"Person\")\n\nlocal slim = Person(\"Slim Shady\")\n\nslim:say_hello(\"World\")\n-- Output: \n-- Hello World\n-- Hello Override\n\n```\n\n### Operators\n\nOperators (metamethods) are defined within the `operators` block. Currently the following operators are supported:\n\n- __add\n- __sub\n- __mul\n- __div\n- __pow\n- __concat\n- __unm\n- __tostring\n- __call\n\n\n```lua\n-- Number has to be declared first, so we can use it within the class\nlocal Number\nNumber = class \"Number\" {\n\tpublic {\n\t\tconstructor = function(self, value)\n\t\t\tself.value = value\n\t\tend;\n\n\t\tgetValue = function(self)\n\t\t\treturn self.value\n\t\tend;\n\t};\n\n\toperators {\n\t\t__add = function(self, n2)\n\t\t\treturn Number(self.value + n2:getValue())\n\t\tend;\n\n\t\t__tostring = function(self)\n\t\t\treturn tostring(self.value)\n\t\tend\n\t}\n}\n```\n\n### Utilities\n\nlua-pie also provides a few simple utility functions, the first being the function `is`.\n`is` takes an object and a class or type name as string and will return true if the given object is an instance of the specified type or class.\n\n```lua\nlocal slim = Person(\"Slim Shady\")\n\nprint(is(slim, \"Person\"))\n-- true\nprint(is(\"string\", \"string\"))\n-- true\n```\n\nIn general lua-pie does not allow writing new indices to object. However this behavior can be turned off to enable working with test frameworks like `busted`.\n\n```lua\nrequire 'busted.runner'()\nrequire \"examples\"\n\nlocal pie = require(\"lua-pie\")\nlocal import = pie.import\n\n\ndescribe(\"When testing busted spies\", function()\n\tit(\"should work\", function()\n\t\tpie.allow_writing_to_objects(true)\n\t\tpie.show_warnings(false) -- if not turned off, lue-pie will warn the user about writing to objects\n\n\t\tlocal Person = import(\"Person\")\n\n\t\tlocal slim = Person(\"Slim Shady\")\n\n\t\tlocal s = spy.on(slim, \"introduce\")\n\t\tslim:introduce()\n\n\t\tassert.spy(s).was.called()\n\tend)\nend)\n```\n\n## Important Notes\n\nDue to the way the module is written, class methods can not be passed around like usual functions. In lua-pie when functions are called they are wrapped in a special wrapper function to pass in the private object table that is hidden from the user. When simply retrieving a function from an object it will always return the wrapper function. Below is a simple example:\n\n```lua\nlocal Greeter = import \"Greeter\"\nlocal Person = import \"Person\"\n\ngreeter = Greeter()\n\nperson = Person(\"A\")\n\nlocal func = greeter.say_hello\nlocal func2 = person.introduce\n\nprint(func == func2)\n-- true\n```\n\nTherefore if you want to pass functions around, always wrap them in another function first:\n\n```lua\nlocal Greeter = import \"Greeter\"\n\ngreeter = Greeter()\n\nlocal func = function(name) greeter:say_hello(name) end\n\nfunc(\"World\")\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsvenmarcus%2Flua-pie","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsvenmarcus%2Flua-pie","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsvenmarcus%2Flua-pie/lists"}