You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
101 lines
3.6 KiB
101 lines
3.6 KiB
-------------------------------------------------------------------------------
|
|
---------------------------------- NAMESPACE ----------------------------------
|
|
-------------------------------------------------------------------------------
|
|
local _, ns = ...
|
|
|
|
-------------------------------------------------------------------------------
|
|
------------------------------------ CLASS ------------------------------------
|
|
-------------------------------------------------------------------------------
|
|
|
|
ns.Class = function(name, parent, attrs)
|
|
if type(name) ~= 'string' then error('name param must be a string') end
|
|
if parent and not ns.IsClass(parent) then
|
|
error('parent param must be a class')
|
|
end
|
|
|
|
local Class = attrs or {}
|
|
Class.getters = Class.getters or {}
|
|
Class.setters = Class.setters or {}
|
|
|
|
local instance_metatable = {
|
|
__tostring = function(self)
|
|
return '<' .. name .. ' instance at ' .. self.__address .. '>'
|
|
end,
|
|
|
|
__index = function(self, index)
|
|
-- Walk up the class hierarchy and check for a static value
|
|
-- followed by a getter function on each parent class
|
|
local _Class = Class
|
|
repeat
|
|
-- Use rawget to skip __index on Class, we want to
|
|
-- check each class object individually
|
|
local value = rawget(_Class, index)
|
|
if value ~= nil then return value end
|
|
local getter = _Class.getters[index]
|
|
if getter then return getter(self) end
|
|
_Class = _Class.__parent
|
|
until _Class == nil
|
|
end,
|
|
|
|
__newindex = function(self, index, value)
|
|
local setter = Class.setters[index]
|
|
if setter then
|
|
setter(self, value)
|
|
else
|
|
rawset(self, index, value)
|
|
end
|
|
end
|
|
}
|
|
|
|
setmetatable(Class, {
|
|
__call = function(self, ...)
|
|
local instance = {}
|
|
instance.__class = Class
|
|
instance.__address = tostring(instance):gsub('table: ', '', 1)
|
|
setmetatable(instance, instance_metatable)
|
|
instance:Initialize(...)
|
|
return instance
|
|
end,
|
|
|
|
__tostring = function() return '<class "' .. name .. '">' end,
|
|
|
|
-- Make parent class attributes accessible on child class objects
|
|
__index = parent
|
|
})
|
|
|
|
if parent then
|
|
-- Set parent class and allow parent class setters to be used
|
|
Class.__parent = parent
|
|
setmetatable(Class.setters, {__index = parent.setters})
|
|
elseif not Class.Initialize then
|
|
-- Add default Initialize() method for base class
|
|
Class.Initialize = function(self) end
|
|
end
|
|
|
|
return Class
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
----------------------------------- HELPERS -----------------------------------
|
|
-------------------------------------------------------------------------------
|
|
|
|
ns.IsClass = function(class)
|
|
return type(class) == 'table' and class.getters and class.setters
|
|
end
|
|
|
|
ns.IsInstance = function(instance, class)
|
|
if type(instance) ~= 'table' then return false end
|
|
local function compare(c1, c2)
|
|
if c2 == nil then return false end
|
|
if c1 == c2 then return true end
|
|
return compare(c1, c2.__parent)
|
|
end
|
|
return compare(class, instance.__class)
|
|
end
|
|
|
|
ns.Clone = function(instance, newattrs)
|
|
local clone = {}
|
|
for k, v in pairs(instance) do clone[k] = v end
|
|
if newattrs then for k, v in pairs(newattrs) do clone[k] = v end end
|
|
return instance.__class(clone)
|
|
end
|
|
|