batteries/class.lua

88 lines
2.4 KiB
Lua
Raw Normal View History

2020-01-29 03:26:28 +00:00
--[[
barebones oop basics
supports basic inheritance and means you don't have to build/set your own metatable each time
todo: collect some stats on classes/optional global class registry
]]
2020-03-15 10:22:22 +00:00
local function class(inherits)
2020-01-29 03:26:28 +00:00
local c = {}
--class metatable
setmetatable(c, {
--wire up call as ctor
__call = function(self, ...)
return self:new(...)
end,
--handle single inheritence chain
__index = inherits,
})
--instance metatable
c.__mt = {
__index = c,
}
2020-01-29 03:26:28 +00:00
--common class functions
--internal initialisation
--sets up an initialised object with a default value table
--performing a super construction if necessary, and (re-)assigning the right metatable
2020-01-29 03:26:28 +00:00
function c:init(t, ...)
if inherits and inherits.new then
--construct superclass instance, then overlay args table
local ct = inherits:new(...)
for k,v in pairs(t) do
ct[k] = v
end
t = ct
2020-01-29 03:26:28 +00:00
end
--upgrade to this class and return
return setmetatable(t, self.__mt)
end
--constructor
--generally to be overridden
function c:new()
return self:init({})
end
--get the inherited class for super calls if/as needed
--allows overrides that still refer to superclass behaviour
function c:super()
return inherits
2020-01-29 03:26:28 +00:00
end
--delegate a call to the superclass, by name
--still a bit clumsy but much cleaner than the inline equivalent,
--plus handles heirarchical complications, and detects various mistakes
function c:super_call(func_name, ...)
--
if type(func_name) ~= "string" then
error("super_call requires a string function name to look up, got "..tostring(func_name))
end
--todo: memoize the below :)
local previous_impl = c:super()
--find the first superclass that actually has the method
while previous_impl and not rawget(previous_impl, func_name) do
previous_impl = previous_impl:super()
end
if not previous_impl then
error("failed super call - no superclass in the chain has an implementation of "..func_name)
end
-- get the function
local f = previous_impl[func_name]
if not f then -- this should never happen because we bail out earlier
error("failed super call - missing function "..func_name.." in superclass")
end
-- check if someone reuses that reference
if f == self[func_name] then
error("failed super call - function "..func_name.." is same in superclass as in derived; this will be a infinite recursion!")
end
-- call that function
return f(self, ...)
end
2020-01-29 03:26:28 +00:00
--done
return c
end
2020-03-15 10:22:22 +00:00
return class