first green version using unified method/metamethod resolver

This commit is contained in:
kikito 2015-12-27 15:42:49 +01:00
parent 13173150de
commit fc61416c81

View File

@ -28,16 +28,9 @@ local middleclass = {
]]
}
local _metamethods = {}
for m in ([[ add band bor bxor bnot call concat div eq
gc index ipairs idiv le len lt metatable mod mode
mul newindex pairs pow shl shr sub tostring unm ]]):gmatch("%S+") do
_metamethods['__' .. m] = true
end
local function _setClassDictionariesMetatables(aClass)
local dict = aClass.__instanceDict
aClass.__instanceMeta.__index = dict
aClass.__instanceDict.__index = dict
local super = aClass.super
if super then
@ -53,63 +46,51 @@ local function _createIndexWrapper(aClass, f)
if f == nil then
return aClass.__instanceDict
else
return function(self, key)
local value = aClass.__instanceDict[key]
return function(self, name)
local value = aClass.__instanceDict[name]
if value ~= nil then
return value
elseif type(f) == "function" then
return (f(self, key))
return (f(self, name))
else
return f[key]
return f[name]
end
end
end
end
local function _setMetamethod(aClass, name, f)
if name == "__index" then
f = _createIndexWrapper(aClass, f)
end
aClass.__instanceMeta[name] = f
end
local function _propagateMetamethod(aClass, name, f)
_setMetamethod(aClass, name, f)
local function _propagateInstanceMethod(aClass, name, f)
aClass.__instanceDict[name] = name == "__index" and _createIndexWrapper(aClass, f) or f
for subclass in pairs(aClass.subclasses) do
if rawget(subclass.__instanceDict, name) == nil then
_propagateMetamethod(subclass, name, f)
if rawget(subclass.__declaredMethods, name) == nil then
_propagateInstanceMethod(subclass, name, f)
end
end
end
local function _updateClassDict(aClass, key, value)
aClass.__instanceDict[key] = value
local function _declareInstanceMethod(aClass, name, f)
aClass.__declaredMethods[name] = f
if _metamethods[key] then
if value == nil then
if aClass.super then
value = aClass.super.__instanceDict[key]
end
if f == nil and aClass.super then
f = aClass.super.__instanceDict[name]
end
_propagateMetamethod(aClass, key, value)
end
_propagateInstanceMethod(aClass, name, f)
end
local function _setClassMetatable(aClass)
setmetatable(aClass, {
__tostring = function() return "class " .. aClass.name end,
__index = aClass.static,
__newindex = _updateClassDict,
__newindex = _declareInstanceMethod,
__call = function(self, ...) return self:new(...) end
})
end
local function _createClass(name, super)
local aClass = { name = name, super = super, static = {}, __instanceDict = {}, __instanceMeta = {} }
local aClass = { name = name, super = super, static = {}, __instanceDict = {}, __declaredMethods = {} }
aClass.subclasses = setmetatable({}, {__mode = "k"})
_setClassDictionariesMetatables(aClass)
@ -118,18 +99,6 @@ local function _createClass(name, super)
return aClass
end
local function _setSubclassMetamethods(aClass, subclass)
for m in pairs(_metamethods) do
_setMetamethod(subclass, m, aClass.__instanceDict[m])
end
end
local function _setDefaultInitializeMethod(aClass, super)
aClass.initialize = function(instance, ...)
return super.initialize(instance, ...)
end
end
local function _includeMixin(aClass, mixin)
assert(type(mixin)=='table', "mixin must be a table")
for name,method in pairs(mixin) do
@ -145,7 +114,9 @@ end
local Object = {
__tostring = function(self) return "instance of " .. tostring(self.class) end,
initialize = function(self) end,
initialize = function(self, ...) end,
isInstanceOf = function(self, aClass)
return type(self) == 'table' and
type(self.class) == 'table' and
@ -160,7 +131,7 @@ local Object = {
allocate = function(self)
assert(type(self) == 'table', "Make sure that you are using 'Class:allocate' instead of 'Class.allocate'")
return setmetatable({ class = self }, self.__instanceMeta)
return setmetatable({ class = self }, self.__instanceDict)
end,
new = function(self, ...)
@ -174,8 +145,12 @@ local Object = {
assert(type(name) == "string", "You must provide a name(string) for your class")
local subclass = _createClass(name, self)
_setSubclassMetamethods(self, subclass)
_setDefaultInitializeMethod(subclass, self)
for name, f in pairs(self.__instanceDict) do
_propagateInstanceMethod(subclass, name, f)
end
subclass.initialize = function(instance, ...) return self.initialize(instance, ...) end
self.subclasses[subclass] = true
self:subclassed(subclass)