rendered paste body#!/usr/bin/env lua5.0-- @file obj.lua: Object/Class modellocal function getuid(t) local str = tostring(t) local _,_,cap = string.find(str, '[^:]*: 0x(.*)$') return string.rep('0', 8 - string.len(cap)) .. capendlocal Factorydo local function new(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) local t = {} obj:init(t, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) return t end local function createnew(self, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) local o = self.prototype return new(o, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) end function Factory(obj, newobj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) local t = new(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) t.prototype = newobj t.new = createnew getmetatable(t).__call = t.new return t endendlocal function objtostring(obj) return obj.tostring and obj:tostring()endlocal Objectdo Object = {} function Object:init(newobject, class) local parent = class or self if not rawget(newobject, 'uid') then newobject.uid = getuid(newobject) end local mt = { __index = parent, __tostring = objtostring, } setmetatable(newobject, mt) end -- function Object:tostring() -- return 'Object' -- end -- Object:init(Object) Object.uid = getuid(Object) setmetatable(Object, { __tostring = function() return 'Object' end })endlocal Classdo Class = Factory(Object, setmetatable({}, {__index = Object}), Object) assert(Class ~= Object) assert(Class ~= Class.prototype) assert(getmetatable(Class).__index == Object) assert(getmetatable(Class.prototype).__index == Object) local function protostring(t) if t.tostring then return t:tostring() else return '<' .. tostring(t.class) .. ' prototype>' end end local function classobjectstring(t) if t.tostring then return t:tostring() else return '<' .. tostring(t.class) .. ' instance>' end end function Class:new(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) local o = self.prototype local newobj = {} if o.class and o.class.instancemeta then setmetatable(newobj, o.class.instancemeta) else Object:init(newobj, o) end o:init(newobj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) return newobj end function Class:init(newclass, parent, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) parent = parent or self -- Object:init(newclass, parent) newclass.protometa = { __index = parent.prototype, __tostring = protostring, } newclass.prototype = {class = newclass} setmetatable(newclass.prototype, newclass.protometa) -- Object:init(newclass.prototype, parent.prototype) newclass.instancemeta = { __index = newclass.prototype, __tostring = classobjectstring, } -- setmetatable(newclass, {__index = parent, __tostring = objtostring}) newclass.mixins = {a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20} newclass.mixinmethods = setmetatable({}, {__index = parent}) setmetatable(newclass, {__index = newclass.mixinmethods, __tostring = objtostring}) -- Fold in the mixins local err for k,v in ipairs(newclass.mixins) do local i = rawget(v, 'init') if i and type(i) == 'function' then i(newclass) end for _,k2,v2 in v:mixinpairs() do if newclass[k2] then err = true else newclass[k2] = v2 end end end if err == true then local mm = newclass.mixinmethods for k,v in pairs(mm) do mm[k] = nil end -- method conflict error('Method conflict in attempt to mix in.', 4) end end function Class:tostring() return 'Class' end function Class.prototype:init(newobj) end local testobj = Class:new() assert(testobj ~= Class) assert(getmetatable(testobj).__index == Class.prototype)endlocal ClassFactorydo ClassFactory = Factory(Object, Class, Object) assert(ClassFactory ~= Object) assert(ClassFactory ~= Class) assert(ClassFactory.prototype == Class) assert(getmetatable(ClassFactory).__index == Object) assert(getmetatable(ClassFactory.prototype).__index == Object)endlocal Mixindo Mixin = ClassFactory:new() local function mixinpairs(self) return function(s, k) local n = next(self.interface, k) return n, self[n] end, self.interface, nil end local function mixinpairs(self) return function(s, k) local n = next(s, k) -- print(s,k,n,s[n],self[s[n]]) return n, s[n], self[s[n]] end, self.interface, nil end function Mixin.prototype:init(newobj, interface) Class.prototype:init(newobj) newobj.interface = interface newobj.mixinpairs = mixinpairs endendlocal testclass = ClassFactory:new()assert(testclass ~= ClassFactory)-- assert(getmetatable(testclass).__index == Class)assert(getmetatable(testclass.prototype).__index == Class.prototype)assert(testclass.init == Class.init)assert(testclass.prototype.class == testclass)function testclass:tostring() return 'testclass'endfunction testclass.prototype:tostring() return '<testclass prototype>'endlocal testobj = testclass:new()assert(testobj ~= testclass)assert(getmetatable(testobj).__index == testclass.prototype)Rectangle = ClassFactory:new()function Rectangle:tostring() return 'Rectangle'endfunction Rectangle.prototype:init(newobj, arg) Class.prototype:init(newobj) if arg then newobj.w = arg.w or arg[1] newobj.h = arg.h or arg[2] endendfunction Rectangle.prototype:tostring() return string.format('<%s h=%s w=%s>', tostring(self.class), tostring(self.h), tostring(self.w))endlocal rect = Rectangle:new({w = 5, h = 6})assert(Rectangle.protometa.__index == Class.prototype)assert(getmetatable(rect).__index == Rectangle.prototype)assert(tostring(rect) == '<Rectangle h=6 w=5>')Square = ClassFactory:new(Rectangle)-- assert(getmetatable(Square).__index == Rectangle)assert(getmetatable(Square.prototype).__index == Rectangle.prototype)function Square:tostring() return 'Square'endfunction Square.prototype:init(newobj, arg) Rectangle.prototype:init(newobj, {h=arg, w=arg})endassert(Square.prototype.class == Square)assert(Square.prototype.tostring == Rectangle.prototype.tostring)local sq = Square:new(5)assert(Square.protometa.__index == Rectangle.prototype)assert(getmetatable(sq) == Square.instancemeta)assert(tostring(Square) == 'Square')assert(tostring(sq) == '<Square h=5 w=5>')local a = Mixin:new({'a'})function a:init() print('a:init()')endfunction a:a()endlocal b = Mixin:new({'b'})function b:init() print('b:init()')endfunction b:b()endlocal c = Mixin:new({'c'})function c:init() print('c:init()')endfunction c:c()endlocal e = ClassFactory:new()e.e = truelocal f = ClassFactory:new(e, a, b, c)assert(f.a == a.a)assert(f.b == b.b)assert(f.c == c.c)assert(f.e == true)local d = Mixin:new({'c'})function d.c()endlocal g = ClassFactory:new(e, a, b, c, d)