From fc61416c81db4e236b95147d194d9738a90dba06 Mon Sep 17 00:00:00 2001 From: kikito Date: Sun, 27 Dec 2015 15:42:49 +0100 Subject: [PATCH] first green version using unified method/metamethod resolver --- middleclass.lua | 79 +++++++++++++++++-------------------------------- 1 file changed, 27 insertions(+), 52 deletions(-) diff --git a/middleclass.lua b/middleclass.lua index d9c37e2..dc1ff0b 100644 --- a/middleclass.lua +++ b/middleclass.lua @@ -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 - end - - _propagateMetamethod(aClass, key, value) + if f == nil and aClass.super then + f = aClass.super.__instanceDict[name] 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)