{"id":"cens-r/classylua","name":"classylua","scope":"cens-r","platform":"roblox","description":"Pythonic Class implementation for Luau!","version":"0.1.0","latest":"0.1.0","versions":["0.1.0"],"license":"MIT","licenseRating":"safe","licenseCaveats":[],"licenseVerified":true,"dependencies":{},"integrity":"5193694bd911136e1e240c029c911d7ad119911d759f4b1ea2d815374ca28861","likes":0,"downloads":0,"install":"forest install cens-r/classylua","url":"https://forest.dev/p/roblox/cens-r/classylua","files":"https://api.forest.dev/ai/package/roblox/cens-r/classylua/files","readme":"# ClassyLua\r\nClassyLua is a module created to offer an alternative to the standard object-oriented programming (OOP) approach in Lua/Luau. It was designed after Python's class system, while still feeling like Lua/Luau.\r\n\r\n***Note**: The explanation of the module below is based on the assumption you have a basic understanding of OOP. It's suggested you have a solid grasp of this concept in Lua, Python, or any other language with OOP capabilities.*\r\n\r\n## Purpose and Reasoning\r\nLua lacks a proper class system and there are very few modules built to offer a proper solution to this issue. We are left to abuse metatables which is fine for simple classes that only inherit a single class,\r\nbut not for more complex classes that need to inherit multiple classes. Mixins become seemingly out of the question as there's no proper way to inherit them all at once to a single class, and index shadowing can\r\nbe a pain to deal with if you're trying to keep a proper order.\r\n\r\nClassyLua abstracts away all of that, letting you deal with implementing your classes while it takes care of the hassle of inheritance for you. Using [C3 Linearization](https://en.wikipedia.org/wiki/C3_linearization)\r\nthe module will construct a method resolution order (MRO) that keeps all the inherited classes in a predictable and well-defined order.\r\n\r\nWith the use of this MRO, ClassyLua offers you a handful of useful features such as:\r\n* `super()` - Access inherited classes directly\r\n* `is()` - Identify if a class or object is equivalent to or a subclass of a given class\r\n* `typeof()` - A more robust typeof method with support for ClassyLua\r\n* `from()` - Convert a Roblox instance class to a ClassyLua class\r\n* Metamethod inheritance from inherited classes\r\n\r\n## Fundamentals\r\nCreating and implementing classes in most programming languages fall under the same action. However, these are two separate actions in ClassyLua for typing purposes. Due to this, there are two types of classes:\r\n\r\n- **NeglectedClass**: The class has yet to be implemented, and awaits such an action.\r\n- **Class**: The class is implemented and functional.\r\n\r\nAll classes start as a **NeglectedClass** at creation and will transition to a **Class** once fully implemented. To do these two actions there are two core methods within the module:\r\n- `Class.new(name: string?)` : Used to construct a new class. If the name is left blank a UUID will be generated in its place.\r\n\r\n- `Class.configure(class: Class, bypass: boolean?)` : Used to implement or configure a given class. Ideally, you should only be using the method as a first-time implementation of a class and it will warn you if the class has already been implemented. An optional second argument, \"bypass\" which is a boolean, acts as a means to silence this warning if you wish. \r\n\r\nThe two will likely be used together for most, if not all, class declarations so you should get comfortable with them.\r\n\r\n## Basic Usage\r\nThrough the use of the two methods mentioned above, we can create a class. Through this demonstration, you should get an understanding of how the two methods work together to form the class.\r\nIt will also provide an example of the layout of the implementation table which will be provided to `Class.configure()`, so you can get familiar with how that works.\r\n\r\n### Construction\r\nAs explained before, to construct a class it's as simple as calling `Class.new()` and providing it with a name. It's important to note that currently the class is considered a **NeglectedClass** which means it has not been implemented yet and will need to be implemented before you can start using/indexing it.\r\n```lua\r\nlocal Class = require(PATH.TO.ClassyLua)\r\nlocal MyClass = Class.new(\"MyClass\") --> Provide a name to identify your class\r\n```\r\n### Implementation\r\nTo implement your class you will make use of the `Class.configure()` method. This stages your class as **ConfigureInfo** which is just used internally, and returns an \"overloaded\" function, which takes care of either inheritance or implementation depending on the argument(s) passed. For this example, we will just be implementing:\r\n\r\n```lua\r\nClass.configure(MyClass) {\r\n\r\n  -- Define methods, static values, and metamethods here\r\n  -- They will be stored within the class\r\n  count = 0,\r\n  foo = function ()\r\n    print(\"Hello World\")\r\n  end,\r\n\r\n  -- The __init metamethod is called every time an object is constructed\r\n  __init = function (self, value)\r\n    -- The object is always passed as the first argument here\r\n    -- You can store your attributes inside the object\r\n    self.value = value\r\n    -- Change static values by using the class itself\r\n    MyClass.count += 1\r\n  end,\r\n\r\n  -- The __new method is the universal object constructor\r\n  -- for all of ClassyLua's classes.\r\n  new = MyClass.__new\r\n}\r\n```\r\n\r\n### Objects\r\n```lua\r\n-- Constructing an object from MyClass\r\nlocal object = MyClass.new(5)\r\n\r\n-- Accessing that object's value attribute\r\nprint(object.value) -- Output: 5\r\n\r\n-- Accessing our static variable\r\nprint(MyClass.count)\r\n-- OR:                } Output: 1\r\nprint(object.count)\r\n```\r\n\r\n### Inheritance\r\n```lua\r\nlocal Example = Class.new(\"Example\")\r\n\r\n-- Inherited classes are provided as arguments to\r\n-- the function returned from `Class.configure()`\r\n--                        [ HERE ]\r\nClass.configure(Example) (MyClass) {\r\n  __init = function (self, value)\r\n    -- The method `Class.super()` can be used to get\r\n    -- superclass of a given class. Since Example has its\r\n    -- own `__init` we need to call MyClass's `__init` this way\r\n    Class.super(Example, self):__init(value)\r\n  end,\r\n  new = Example.__new\r\n}\r\n\r\n-- OUTPUT EXAMPLES:\r\nlocal object = Example.new(52)\r\nprint(object.value) -- Output: 52\r\nprint(Example.count) -- Output: 52\r\nExample.foo() -- Output: \"Hello World\"\r\n```\r\n","readmeTruncated":false}