comp-tg/etc/class.lua

117 lines
2.7 KiB
Lua

-- Class library
-- (c) Er2 2022 <er2@dismail.de>
-- Zlib License
-- (Not) Virtual classes table
local vtable = {}
-- Metamethods
local cls = {}
cls.__index = cls
-- :__tostring() - Calls when using Lua tostring() or error occurs.
function cls:__tostring()
local str = 'Class <'.. self.__name ..'>'
while self.__super do
str = str.. ' inherits '.. self.__super.__name
self = self.__super
end
return str
end
-- :__call(table) - Calls when defining class body
function cls:__call(t)
for k, v in pairs(t) do
self[k] = v
end
if self.__init
then self:__init()
end
end
-- :new(...) - Creates new instance of class. Please use new(...) function instead.
-- Can throw error if no constructor defined in class or subclasses.
function cls:new(...)
local cl = self
local cons
repeat cons = rawget(cl, 1) or rawget(cl, 'new')
cl = cl.__super
until cons or not cl
assert(cons, 'No constructor found in class')
--self.__index = self.__index or cls.__index
self = setmetatable({}, self)
cons(self, ...)
return self
end
-- :super(...) - Call parent constructor.
function cls:super(...)
return cls.superM(self, 1, ...)
or cls.superM(self, 'new', ...)
end
-- :superM(method, ...) - Call method from parent class.
-- Can throw error if class is not inherited.
function cls:superM(meth, ...)
local cl = self.__super
local fn
while not fn and cl do
fn = cl[meth]
if cl.__sup then fn = nil end
cl = cl.__super
end
if not fn then return nil end
if cl then cl.__sup = true end
local v = {fn(self, ...)}
if cl then cl.__sup = nil end
return table.unpack(v)
end
-- :clone() - Make clone of class.
function cls:clone()
local cl = {}
for k, v in pairs(cls)
do cl[k] = v end
for k, v in pairs(self)
do cl[k] = v end
cl.__index = cl
cl.__super = self
return setmetatable(cl, self)
end
-- :inherits(className) - Make this class inherits from another.
-- Can throw error if class is already inherited.
function cls:inherits(name)
-- assert(self.__super, 'no')
local cl = vtable[name]
assert(cl, 'Class is not exists')
return setmetatable(self, cl:clone())
end
-- :extends(className) - Same as :inherits(className).
cls.extends = cls.inherits
-- class(className) - Make new class.
-- Can throw error if class already exists with this name.
function class(name)
assert(not vtable[name], 'Cannot override defined class')
local cl = setmetatable({__name = name, __tostring = cls.__tostring}, cls)
cl.__index = cl
vtable[name] = cl
return cl
end
-- new(className) - Make new instance of class. Use this instead of :new(class).
-- Can throw error if class by name was not found.
function new(name)
local cl = vtable[name]
assert(cl, 'No class found')
return function(...)
return cls.new(cl, ...)
end
end