LiquidProxy Lua Edition
1local table = require 'ext.table'
2
3-- classes
4
5local function newmember(class, ...)
6 local obj = setmetatable({}, class)
7 if obj.init then return obj, obj:init(...) end
8 return obj
9end
10
11local classmeta = {
12 __call = function(self, ...)
13-- [[ normally:
14 return self:new(...)
15--]]
16--[[ if you want to keep track of all instances
17 local results = table.pack(self:new(...))
18 local obj = results[1]
19 self.instances[obj] = true
20 return results:unpack()
21--]]
22 end,
23}
24
25-- usage: class:isa(obj)
26-- so it's not really a member method, since the object doesn't come first, but this way we can use it as Class:isa(obj) and not worry about nils or local closures
27local function isa(cl, obj)
28 assert(cl, "isa: argument 1 is nil, should be the class object") -- isa(nil, anything) errors, because it should always have a class in the 1st arg
29 if type(obj) ~= 'table' then return false end -- class:isa(not a table) will return false
30 if not obj.isaSet then return false end -- not an object generated by class(), so it doesn't have a set of all classes that it "is-a"
31 return obj.isaSet[cl] or false -- returns true if the 'isaSet' of the object's metatable (its class) holds the calling class
32end
33
34local function class(...)
35 local cl = table(...)
36 cl.class = cl
37
38 cl.super = ... -- .super only stores the first. the rest can be accessed by iterating .isaSet's keys
39
40 -- I was thinking of calling this '.superSet', but it is used for 'isa' which is true for its own class, so this is 'isaSet'
41 cl.isaSet = {[cl] = true}
42 for i=1,select('#', ...) do
43 local parent = select(i, ...)
44 if parent ~= nil then
45 cl.isaSet[parent] = true
46 if parent.isaSet then
47 for grandparent,_ in pairs(parent.isaSet) do
48 cl.isaSet[grandparent] = true
49 end
50 end
51 end
52 end
53
54 -- store 'descendantSet' as well that gets appended when we call class() on this obj?
55 for ancestor,_ in pairs(cl.isaSet) do
56 ancestor.descendantSet = ancestor.descendantSet or {}
57 ancestor.descendantSet[cl] = true
58 end
59
60 cl.__index = cl
61 cl.new = newmember
62 cl.isa = isa -- usage: Class:isa(obj)
63 cl.subclass = class -- such that cl:subclass() or cl:subclass{...} will return a subclass of 'cl'
64
65--[[ if you want to keep track of all instances
66 cl.instances = setmetatable({}, {__mode = 'k'})
67--]]
68
69 setmetatable(cl, classmeta)
70 return cl
71end
72
73return class