117 lines
2.7 KiB
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
|
||
|
|