leef-class-cd2025/new_class.lua
2024-12-21 20:53:50 -08:00

111 lines
4.4 KiB
Lua

--- An instantiatable class to inherit for defining new instantiatble classes classes
-- the "base" class. To make a new class call `new_class:inherit(your_new_class)`.
-- Also note that these classes will not have the type `table` but instead `class` when `type(object)` is called.
--
-- @classmod new_class
local objects = {}
setmetatable(objects, {
__mode = 'kv' --allow garbage collection.
})
leef.class.new_class = {
instance = false,
--__no_copy = true
}
--- instance
-- @field instance defines wether the object is an instance, use this in construction to determine what changes to make
--- base_class
-- @field base_class only present for instances: the class from which this instance originates
--- parent_class
-- @field parent_class the class from which this class was inherited from
--- creates a new base class. Calls all constructors in the chain with def.instance=true
-- @param self the table which is being inherited (meaning variables that do not exist in the child, will read as the parent's). Be careful to remember that subtable values are NOT inherited, use the constructor to create subtables.
-- @param def the table containing the base definition of the class. This should contain a @{construct}
-- @return def a new base class
-- @function inherit(self)
function leef.class.new_class:inherit(def)
objects[def] = true
--construction chain for inheritance
--if not def then def = {} else def = table.shallow_copy(def) end
def.parent_class = self
def.instance = false
--def.__no_copy = true
def._construct_low = def.construct
--this effectively creates a construction chain by overwriting .construct
function def.construct(parameters)
--rawget because in a instance it may only be present in a hierarchy but not the table itself
if self.construct then
self.construct(parameters)
end
if rawget(def, "_construct_low") then
def._construct_low(parameters)
end
end
--iterate through table properties
setmetatable(def, {__index = self})
def.construct(def) --moved this to call after the setmetatable, it doesnt seem to break anything, and how it should be? I dont know when I changed it... hopefully not totally broken.
return def
end
--- Called when a child, grandchild, (and so on), instance or class is created. Check `self.instance` and `self.base_class` to determine what type of object it is.
-- every constructor from every parent is called in heirarchy (first to last).
-- use this to instantiate things like subtables or child class instances.
-- @param self the table (which would be def from new()).
-- @function construct(
--- creates an instance of the base class. Calls all constructors in the chain with def.instance=true
-- @param def field for the new instance of the class. If fields are not present they will refer to the base class's fields (if present in the base class).
-- @return self a new instance of the class.
-- @function new
function leef.class.new_class:new(def)
--if not def then def = {} else def = table.shallow_copy(def) end
def.base_class = self
def.instance = true
--def.__no_copy = true
function def:inherit()
assert(false, "cannot inherit instantiated object")
end
setmetatable(def, {__index = self})
--call the construct chain for inherited objects, also important this is called after meta changes
self.construct(def)
return def
end
--- (for printing) dumps the variables of this class
-- @param self
-- @tparam bool dump_classes whether to also print/dump classes.
-- @treturn string
-- @function dump
function leef.class.new_class:dump(dump_classes)
local str = "{"
for i, v in pairs(self) do
if type(i) == "string" then
str=str.."\n\t[\""..tostring(i).."\"] = "
else
str=str.."\n\t["..tostring(i).."] = "
end
if type(v) == "table" then
local dumptable = dump(v):gsub("\n", "\n\t")
str=str..dumptable
elseif type(v) == "class" then
if dump_classes then
str = str..v:dump():gsub("\n", "\n\t")
else
str = str..tostring(dump_classes)
end
else
str = str..tostring(v)
end
end
return str.."\n}"
end
local old_type = type
function type(a, ...)
if objects[a] then return "class" end
return old_type(a, ...)
end