All pastes #53453 Raw Edit

kergoth

public lua v1 · immutable
#53453 ·published 2006-05-04 06:27 UTC
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)