Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- This is a guide for 'Class.lua' which was created by Raiu and can be downloaded
- from https://pastebin.com/t2TvSiSU
- 'Class.lua' is a script that attempts to emulate the creation of class based
- objects used in object-oriented programming languages.
- C++ is the inspiration for the design of this script.
- If you are running this in ComputerCraft, use the following command to download
- it: pastebin get t2TvSiSU "/API/Class.lua"
- In ComputerCraft, this file should be in "/API/" in the root directory to ensure
- all programs that use this script function properly.
- This script uses metatables to do what it does, but knowledge of metatables
- is not needed to understand how to use this script. However, you can optionally
- use metamethods in your Classes. If you want to learn about metatables and
- metamethods, I made a reference guide with links to the Lua manual to help out a
- bit: https://pastebin.com/Kf8LxzE9
- ]]
- --[[
- Lua Terminology:
- • Variable: A piece of information, also called a value, that is stored in
- memory.
- • Declaration: The part in your code where a variable's identity is created.
- • Definition: The specific value that is stored in a variable.
- • Number: A value that is defined as a number.
- • String: A value that is defined as text.
- • Boolean: A value that is defined as 'true' or 'false'.
- • Function: A variable that is defined as a block of code that can run any time
- the variable is called.
- • Nil: The keyword that represents nothing, or the absence of a value. This is
- Lua's version of null.
- • Table: A variable that is defined as a container for multiple values.
- • Element: Another name for a value within a table or object.
- • Member: Another name for an element.
- • Index: An element that is identified with a number.
- • Key: An element that is identified with a string.
- • Method: An element that is defined as a function.
- • Metatable: A table that changes the way another table behaves.
- • Metamethod: A function within a metatable that controls the table's behavior.
- ]]
- --[[
- Class.lua Terminology:
- • Class: A table of keys formatted a specific way to emulate classes, which is
- essentially the blueprint to creating an object.
- • Header: A function that returns the definitions of a class.
- • Class Constructor: The 'Class' function in 'Class.lua' that uses a "header"
- as a blueprint to create a class that can be used to create objects.
- • Object: A table constructed from a Class using the object constructor.
- • Object Constructor: The 'Object' function in 'Class.lua' that uses a class as
- a blueprint to create objects. A class can be manually created as a table and
- inserted directly into the object constructor as the 'class' argument.
- However, the class constuctor is required for inheritance. Additional
- arguments are used in the constructor method.
- • Constructor Method: The method that runs when the object is created. This
- method can be ran again by calling the object as if it were a function.
- • Property: Another name for a member of an object.
- • Inheritance: The ability for a class to "inherit" properties from another
- class (see below for more info).
- ]]
- --[[
- 'Object(class, ...)' is the object constructor that takes a "Class" as the first
- argument and constructor method arguments after that. You will need to
- understand classes and object-oriented programming in order to use this script.
- These are the keys that can be in your Class table. Any other keys or indexes
- will be ignored when creating the object. All of these keys are optional. Some
- have a default state if ommitted:
- ]]
- local class = {
- ctor = function() end,
- -- The object's constructor method.
- -- Default: An empty function.
- protected = true or false,
- -- Boolean that, when true, protects the public table from having new data added
- -- with 'table.insert' or the assignment operator. It also prevents elements
- -- from being removed with 'table.remove'. This does not stop existing elements
- -- from being changed, and elements can be removed by assigning them to 'nil'.
- -- This also will not automatically protect tables within the public table.
- -- Default: nil, which is the same as false.
- public = {},
- -- Table of the object's properties that are completely exposed to the user and
- -- can be edited outside the object.
- -- Default: An empty table.
- readOnly = {},
- -- Table of the object's read-only properties that are otherwise completely
- -- inaccessible to the user. You don't have to worry about these properties
- -- being changed, regardless if the object is protected or not. This does not
- -- automatically protect tables within the readOnly table.
- -- Default: nil
- meta = {},
- -- Table of custom metamethods (see below for more info).
- -- Default: An empty table.
- }
- --[[
- In the 'meta' table, you can set your own metamethods. Keep in mind, some
- metamethods will be overwritten depending on what you put in your class. These
- are the default states of all the metamethods used in this script:
- ]]
- class.meta.__index = class.readOnly or class.meta.__index
- -- This is the container for read-only properties.
- -- • Default: nil
- -- • The class definition for this metamethod will be overwritten by
- -- 'class.readOnly'.
- class.meta.__len = class.meta.__len or function()
- local size = 0
- for k, v in ipairs(class.public) do
- size = size + 1
- end
- return size
- end
- -- This function runs when getting the size of the object.
- -- • Default: Returns the size (in indecies) of the object. If the read-only
- -- table has indecies, they will be counted along with the public table as if
- -- they were one table. Either table must start at 1 and the indecies must
- -- count up by 1 with no gaps in between.
- -- • The default function will be overwritten by the class definition.
- class.meta.__call = class.ctor or class.meta.__call or function() end
- -- This is the container for the object's constructor method. This runs when
- -- creating the object or by calling the object as if it were a function.
- -- • Default: An empty function.
- -- • The default function will be overwritten by the class definition, both of
- -- which will be overwritten by 'class.ctor'.
- if class.protected then
- class.meta.__newindex = function() error("attempt to update a protected object", 2) end
- end
- -- '__newindex' runs when adding elements to the public table by assignment or
- -- with 'table.insert'. It also runs when removing elements with 'table.remove',
- -- but not when changing existing elements or removing them by assigning them to
- -- nil.
- -- • Default: Throws an error, preventing the public table from changing.
- -- • The class definition will be overwritten by the default if 'protected' ==
- -- true. Otherwise it will be nil if there's no definition in the class.
- class.meta.__metatable = class.meta.__metatable or false
- -- Setting this to anything other than nil is what makes the entire metatable
- -- read-only. This is the value returned by getmetatable() instead of the actual
- -- metatable. This value can't be changed, but it may be manipulated if it's set
- -- to something like a table.
- -- • Default: false
- -- • The default will be overwritten by the class definition.
- class.meta.__pairs = class.meta.__pairs or function()
- local keys = {}
- for _, o in pairs({class.public, class.readOnly}) do
- for k, v in next, o do
- keys[k] = v
- end
- end
- return next, keys
- end
- -- When you use the 'pairs' function in a for loop, this metamethod controls how
- -- the loop iterates.
- -- • Default: Iterates over both the public and read-only tables.
- -- • The default function will be overwritten by the class definition.
- -- As a side note, the elements within 'class.public' and 'class.readOnly' may
- -- change, so that's why the 'keys' table will need to be recreated and the for
- -- loops need to run whenever this metamethod is used.
- --[[
- 'Class(header)' is the class constructor which takes a "header" function and
- uses it as a blueprint to construct a Class. The "header" should contain the
- definitions of your class, and at the end should return a table using the format
- shown above. Your header should look something like this:
- ]]
- require("/API/Class") or dofile("/API/Class.lua")
- local header = function()
- -- Class declarations goes here:
- local class = {
- ctor = function() end,
- protected = true,
- public = {test = "test"},
- readOnly = {},
- meta = {},
- }
- -- This is a private variable that can't be inherited or accessed outside of
- -- the object:
- local var3 = true
- -- Class definitions go here:
- class.public.var1 = "Hello World"
- class.readOnly.var2 = 123
- -- etc...
- return class
- end
- --[[
- Technically all variables can be named whatever you want, however the keys in
- the 'class' table need to be named appropriately so the object constructor can
- build the object correctly.
- Definitions can also be made in the delcaration of the 'class' table, but you
- should avoid doing this because if you create methods that try to use other
- members in the class, it will throw nil value errors. Make a habit of defining
- most if not all of your members after the class declaration. You can also make
- your functions and variables first, and then return them in the appropriately
- formatted table afterwards.
- After your header has been defined you pass it into the 'Class' function, and
- assign the return value to a variable like so:
- ]]
- ClassDemo = Class(header)
- --[[
- Alternatively you can also pass the header definition by itself as the argument
- to 'Class' instead of creating a variable for the function. So it would look
- something like this:
- ClassDemo = Class(function()
- Some code...
- end)
- This variable can be global if you're loading this class from a separate file,
- or it can be local if it's in the same file as whatever code you're using it
- with. The variable 'ClassDemo' is now a class. If you call 'ClassDemo()' it will
- create and return an object built from the object constructor.
- If you call 'ClassDemo.h()' it will return the definitions of your class. This
- allows you to create another class that inherits every property that is in
- ClassDemo's 'class' table. Inheritance means that a class can "inherit" the
- properties of another class, meaning it can essentially copy the properties of
- another class on top of having its own. If you want to create a class with
- inheritance, you should build your header like this:
- ]]
- local inherit = function()
- local class = ClassDemo.h()
- class.ctor = function(text)
- text = text or ""
- print("This object has inheritance. " .. tostring(text))
- end
- class.readOnly.var4 = class.public.var1 .. class.readOnly.var2
- return class
- end
- InheritDemo = Class(inherit)
- --[[
- Now we have 'ClassDemo' with all its properties, and 'InheritDemo' with the same
- properties and an additional read-only property, 'var4', which is just a
- concatenation of var1 and var2. In addition we have redefined the constructor
- method which now prints text saying "This object has inheritance. "
- concattenated with whatever text is passed as an argument upon creation.
- And now, finally, to create objects, you do this:
- ]]
- local mainObject = ClassDemo()
- local inheritedObject = InheritDemo("Make more text!")
- --[[
- Calling the class as a function constructs an object, and if you have code in
- your constructor method, that code will be executed immediately upon creation of
- the object.
- ]]
- --[[
- This concludes my guide on how to do object oriented programing in lua using
- my Class script.
- If you want, you can make an object like this manually with metatables, but the
- object constructor makes it a lot easier by streamlining it, and it removes the
- repetitive parts of setting it up.
- Furthermore you can remove the middle man and not use the class constructor by
- setting up your class manually; i.e. you can create your class definition and
- pass that definition directly into the object constructor. But having the class
- constructor makes inheritance so much easier, plus it allows object-oriented
- programming to work much more similarly to actual OOP languages.
- And all of this also ensures that no matter what you do, your clases and your
- objects are completely immutable outside the scope of where you define them.
- ]]
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement