flickerstreak@1
|
1 --[[
|
flickerstreak@1
|
2 Name: AceOO-2.0
|
flickerstreak@1
|
3 Revision: $Rev: 18708 $
|
flickerstreak@1
|
4 Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
|
flickerstreak@1
|
5 Inspired By: Ace 1.x by Turan (turan@gryphon.com)
|
flickerstreak@1
|
6 Website: http://www.wowace.com/
|
flickerstreak@1
|
7 Documentation: http://www.wowace.com/index.php/AceOO-2.0
|
flickerstreak@1
|
8 SVN: http://svn.wowace.com/root/trunk/Ace2/AceOO-2.0
|
flickerstreak@1
|
9 Description: Library to provide an object-orientation framework.
|
flickerstreak@1
|
10 Dependencies: AceLibrary
|
flickerstreak@1
|
11 ]]
|
flickerstreak@1
|
12
|
flickerstreak@1
|
13 local MAJOR_VERSION = "AceOO-2.0"
|
flickerstreak@1
|
14 local MINOR_VERSION = "$Revision: 18708 $"
|
flickerstreak@1
|
15
|
flickerstreak@1
|
16 -- This ensures the code is only executed if the libary doesn't already exist, or is a newer version
|
flickerstreak@1
|
17 if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end
|
flickerstreak@1
|
18 if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
|
flickerstreak@1
|
19
|
flickerstreak@1
|
20 local AceOO = {
|
flickerstreak@1
|
21 error = AceLibrary.error,
|
flickerstreak@1
|
22 argCheck = AceLibrary.argCheck
|
flickerstreak@1
|
23 }
|
flickerstreak@1
|
24
|
flickerstreak@1
|
25 -- @function getuid
|
flickerstreak@1
|
26 -- @brief Obtain a unique string identifier for the object in question.
|
flickerstreak@1
|
27 -- @param t The object to obtain the uid for.
|
flickerstreak@1
|
28 -- @return The uid string.
|
flickerstreak@1
|
29 local function pad(cap)
|
flickerstreak@1
|
30 return string.rep('0', 8 - string.len(cap)) .. cap
|
flickerstreak@1
|
31 end
|
flickerstreak@1
|
32 local function getuid(t)
|
flickerstreak@1
|
33 local mt = getmetatable(t)
|
flickerstreak@1
|
34 setmetatable(t, nil)
|
flickerstreak@1
|
35 local str = tostring(t)
|
flickerstreak@1
|
36 setmetatable(t, mt)
|
flickerstreak@1
|
37 local _,_,cap = string.find(str, '[^:]*: 0x(.*)$')
|
flickerstreak@1
|
38 if cap then return pad(cap) end
|
flickerstreak@1
|
39 _,_,cap = string.find(str, '[^:]*: (.*)$')
|
flickerstreak@1
|
40 if cap then return pad(cap) end
|
flickerstreak@1
|
41 end
|
flickerstreak@1
|
42
|
flickerstreak@1
|
43 local function getlibrary(o)
|
flickerstreak@1
|
44 if type(o) == "table" then
|
flickerstreak@1
|
45 return o
|
flickerstreak@1
|
46 elseif type(o) == "string" then
|
flickerstreak@1
|
47 if not AceLibrary:HasInstance(o) then
|
flickerstreak@1
|
48 AceOO:error("Library %q does not exist.", o)
|
flickerstreak@1
|
49 end
|
flickerstreak@1
|
50 return AceLibrary(o)
|
flickerstreak@1
|
51 end
|
flickerstreak@1
|
52 end
|
flickerstreak@1
|
53
|
flickerstreak@1
|
54 -- @function Factory
|
flickerstreak@1
|
55 -- @brief Construct a factory for the creation of objects.
|
flickerstreak@1
|
56 -- @param obj The object whose init method will be called on the new factory
|
flickerstreak@1
|
57 -- object.
|
flickerstreak@1
|
58 -- @param newobj The object whose init method will be called on the new
|
flickerstreak@1
|
59 -- objects that the Factory creates, to initialize them.
|
flickerstreak@1
|
60 -- @param (...) Arguments which will be passed to obj.init() in addition
|
flickerstreak@1
|
61 -- to the Factory object.
|
flickerstreak@1
|
62 -- @return The new factory which creates a newobj when its new method is called,
|
flickerstreak@1
|
63 -- or when it is called directly (__call metamethod).
|
flickerstreak@1
|
64 local Factory
|
flickerstreak@1
|
65 do
|
flickerstreak@1
|
66 local arg = {}
|
flickerstreak@1
|
67 local function new(obj, ...)
|
flickerstreak@1
|
68 local t = {}
|
flickerstreak@1
|
69 local uid = getuid(t)
|
flickerstreak@1
|
70 for i = 1, select('#', ...) do
|
flickerstreak@1
|
71 arg[i] = getlibrary(select(i, ...))
|
flickerstreak@1
|
72 end
|
flickerstreak@1
|
73 obj:init(t, unpack(arg))
|
flickerstreak@1
|
74 for i = 1, select('#', ...) do
|
flickerstreak@1
|
75 arg[i] = nil
|
flickerstreak@1
|
76 end
|
flickerstreak@1
|
77 t.uid = uid
|
flickerstreak@1
|
78 return t
|
flickerstreak@1
|
79 end
|
flickerstreak@1
|
80
|
flickerstreak@1
|
81 local function createnew(self, ...)
|
flickerstreak@1
|
82 local o = self.prototype
|
flickerstreak@1
|
83 for i = 1, select('#', ...) do
|
flickerstreak@1
|
84 arg[i] = getlibrary(select(i, ...))
|
flickerstreak@1
|
85 end
|
flickerstreak@1
|
86 local x = new(o, unpack(arg))
|
flickerstreak@1
|
87 for i = 1, select('#', ...) do
|
flickerstreak@1
|
88 arg[i] = nil
|
flickerstreak@1
|
89 end
|
flickerstreak@1
|
90 return x
|
flickerstreak@1
|
91 end
|
flickerstreak@1
|
92
|
flickerstreak@1
|
93 function Factory(obj, newobj, ...)
|
flickerstreak@1
|
94 local t = new(obj, ...)
|
flickerstreak@1
|
95 t.prototype = newobj
|
flickerstreak@1
|
96 t.new = createnew
|
flickerstreak@1
|
97 getmetatable(t).__call = t.new
|
flickerstreak@1
|
98 return t
|
flickerstreak@1
|
99 end
|
flickerstreak@1
|
100 end
|
flickerstreak@1
|
101
|
flickerstreak@1
|
102
|
flickerstreak@1
|
103 local function objtostring(self)
|
flickerstreak@1
|
104 if self.ToString then
|
flickerstreak@1
|
105 return self:ToString()
|
flickerstreak@1
|
106 elseif self.GetLibraryVersion then
|
flickerstreak@1
|
107 return (self:GetLibraryVersion())
|
flickerstreak@1
|
108 elseif self.super then
|
flickerstreak@1
|
109 local s = "Sub-" .. tostring(self.super)
|
flickerstreak@1
|
110 local first = true
|
flickerstreak@1
|
111 if self.interfaces then
|
flickerstreak@1
|
112 for interface in pairs(self.interfaces) do
|
flickerstreak@1
|
113 if first then
|
flickerstreak@1
|
114 s = s .. "(" .. tostring(interface)
|
flickerstreak@1
|
115 first = false
|
flickerstreak@1
|
116 else
|
flickerstreak@1
|
117 s = s .. ", " .. tostring(interface)
|
flickerstreak@1
|
118 end
|
flickerstreak@1
|
119 end
|
flickerstreak@1
|
120 end
|
flickerstreak@1
|
121 if self.mixins then
|
flickerstreak@1
|
122 for mixin in pairs(self.mixins) do
|
flickerstreak@1
|
123 if first then
|
flickerstreak@1
|
124 s = s .. tostring(mixin)
|
flickerstreak@1
|
125 first = false
|
flickerstreak@1
|
126 else
|
flickerstreak@1
|
127 s = s .. ", " .. tostring(mixin)
|
flickerstreak@1
|
128 end
|
flickerstreak@1
|
129 end
|
flickerstreak@1
|
130 end
|
flickerstreak@1
|
131 if first then
|
flickerstreak@1
|
132 if self.uid then
|
flickerstreak@1
|
133 return s .. ":" .. self.uid
|
flickerstreak@1
|
134 else
|
flickerstreak@1
|
135 return s
|
flickerstreak@1
|
136 end
|
flickerstreak@1
|
137 else
|
flickerstreak@1
|
138 return s .. ")"
|
flickerstreak@1
|
139 end
|
flickerstreak@1
|
140 else
|
flickerstreak@1
|
141 return self.uid and 'Subclass:' .. self.uid or 'Subclass'
|
flickerstreak@1
|
142 end
|
flickerstreak@1
|
143 end
|
flickerstreak@1
|
144
|
flickerstreak@1
|
145 -- @table Object
|
flickerstreak@1
|
146 -- @brief Base of all objects, including Class.
|
flickerstreak@1
|
147 --
|
flickerstreak@1
|
148 -- @method init
|
flickerstreak@1
|
149 -- @brief Initialize a new object.
|
flickerstreak@1
|
150 -- @param newobject The object to initialize
|
flickerstreak@1
|
151 -- @param class The class to make newobject inherit from
|
flickerstreak@1
|
152 local Object
|
flickerstreak@1
|
153 do
|
flickerstreak@1
|
154 Object = {}
|
flickerstreak@1
|
155 function Object:init(newobject, class)
|
flickerstreak@1
|
156 local parent = class or self
|
flickerstreak@1
|
157 if not rawget(newobject, 'uid') then
|
flickerstreak@1
|
158 newobject.uid = getuid(newobject)
|
flickerstreak@1
|
159 end
|
flickerstreak@1
|
160 local mt = {
|
flickerstreak@1
|
161 __index = parent,
|
flickerstreak@1
|
162 __tostring = objtostring,
|
flickerstreak@1
|
163 }
|
flickerstreak@1
|
164 setmetatable(newobject, mt)
|
flickerstreak@1
|
165 end
|
flickerstreak@1
|
166 Object.uid = getuid(Object)
|
flickerstreak@1
|
167 setmetatable(Object, { __tostring = function() return 'Object' end })
|
flickerstreak@1
|
168 end
|
flickerstreak@1
|
169
|
flickerstreak@1
|
170 local Interface
|
flickerstreak@1
|
171
|
flickerstreak@1
|
172 local function validateInterface(object, interface)
|
flickerstreak@1
|
173 if not object.class and object.prototype then
|
flickerstreak@1
|
174 object = object.prototype
|
flickerstreak@1
|
175 end
|
flickerstreak@1
|
176 for k,v in pairs(interface.interface) do
|
flickerstreak@1
|
177 if tostring(type(object[k])) ~= v then
|
flickerstreak@1
|
178 return false
|
flickerstreak@1
|
179 end
|
flickerstreak@1
|
180 end
|
flickerstreak@1
|
181 if interface.superinterfaces then
|
flickerstreak@1
|
182 for superinterface in pairs(interface.superinterfaces) do
|
flickerstreak@1
|
183 if not validateInterface(object, superinterface) then
|
flickerstreak@1
|
184 return false
|
flickerstreak@1
|
185 end
|
flickerstreak@1
|
186 end
|
flickerstreak@1
|
187 end
|
flickerstreak@1
|
188 if type(object.class) == "table" and rawequal(object.class.prototype, object) then
|
flickerstreak@1
|
189 if not object.class.interfaces then
|
flickerstreak@1
|
190 rawset(object.class, 'interfaces', {})
|
flickerstreak@1
|
191 end
|
flickerstreak@1
|
192 object.class.interfaces[interface] = true
|
flickerstreak@1
|
193 elseif type(object.class) == "table" and type(object.class.prototype) == "table" then
|
flickerstreak@1
|
194 validateInterface(object.class.prototype, interface)
|
flickerstreak@1
|
195 -- check if class is proper, thus preventing future checks.
|
flickerstreak@1
|
196 end
|
flickerstreak@1
|
197 return true
|
flickerstreak@1
|
198 end
|
flickerstreak@1
|
199
|
flickerstreak@1
|
200 -- @function inherits
|
flickerstreak@1
|
201 -- @brief Return whether an Object or Class inherits from a given
|
flickerstreak@1
|
202 -- parent.
|
flickerstreak@1
|
203 -- @param object Object or Class to check
|
flickerstreak@1
|
204 -- @param parent Parent to test inheritance from
|
flickerstreak@1
|
205 -- @return whether an Object or Class inherits from a given
|
flickerstreak@1
|
206 -- parent.
|
flickerstreak@1
|
207 local function inherits(object, parent)
|
flickerstreak@1
|
208 object = getlibrary(object)
|
flickerstreak@1
|
209 if type(parent) == "string" then
|
flickerstreak@1
|
210 if not AceLibrary:HasInstance(parent) then
|
flickerstreak@1
|
211 return false
|
flickerstreak@1
|
212 else
|
flickerstreak@1
|
213 parent = AceLibrary(parent)
|
flickerstreak@1
|
214 end
|
flickerstreak@1
|
215 end
|
flickerstreak@1
|
216 AceOO:argCheck(parent, 2, "table")
|
flickerstreak@1
|
217 if type(object) ~= "table" then
|
flickerstreak@1
|
218 return false
|
flickerstreak@1
|
219 end
|
flickerstreak@1
|
220 local current
|
flickerstreak@1
|
221 if object.class then
|
flickerstreak@1
|
222 current = object.class
|
flickerstreak@1
|
223 else
|
flickerstreak@1
|
224 current = object
|
flickerstreak@1
|
225 end
|
flickerstreak@1
|
226 if type(current) ~= "table" then
|
flickerstreak@1
|
227 return false
|
flickerstreak@1
|
228 end
|
flickerstreak@1
|
229 if rawequal(current, parent) then
|
flickerstreak@1
|
230 return true
|
flickerstreak@1
|
231 end
|
flickerstreak@1
|
232 if parent.class then
|
flickerstreak@1
|
233 while true do
|
flickerstreak@1
|
234 if rawequal(current, Object) then
|
flickerstreak@1
|
235 break
|
flickerstreak@1
|
236 end
|
flickerstreak@1
|
237 if current.mixins then
|
flickerstreak@1
|
238 for mixin in pairs(current.mixins) do
|
flickerstreak@1
|
239 if rawequal(mixin, parent) then
|
flickerstreak@1
|
240 return true
|
flickerstreak@1
|
241 end
|
flickerstreak@1
|
242 end
|
flickerstreak@1
|
243 end
|
flickerstreak@1
|
244 if current.interfaces then
|
flickerstreak@1
|
245 for interface in pairs(current.interfaces) do
|
flickerstreak@1
|
246 if rawequal(interface, parent) then
|
flickerstreak@1
|
247 return true
|
flickerstreak@1
|
248 end
|
flickerstreak@1
|
249 end
|
flickerstreak@1
|
250 end
|
flickerstreak@1
|
251 current = current.super
|
flickerstreak@1
|
252 if type(current) ~= "table" then
|
flickerstreak@1
|
253 break
|
flickerstreak@1
|
254 end
|
flickerstreak@1
|
255 end
|
flickerstreak@1
|
256
|
flickerstreak@1
|
257 local isInterface = false
|
flickerstreak@1
|
258 local curr = parent.class
|
flickerstreak@1
|
259 while true do
|
flickerstreak@1
|
260 if rawequal(curr, Object) then
|
flickerstreak@1
|
261 break
|
flickerstreak@1
|
262 elseif rawequal(curr, Interface) then
|
flickerstreak@1
|
263 isInterface = true
|
flickerstreak@1
|
264 break
|
flickerstreak@1
|
265 end
|
flickerstreak@1
|
266 curr = curr.super
|
flickerstreak@1
|
267 if type(curr) ~= "table" then
|
flickerstreak@1
|
268 break
|
flickerstreak@1
|
269 end
|
flickerstreak@1
|
270 end
|
flickerstreak@1
|
271 return isInterface and validateInterface(object, parent)
|
flickerstreak@1
|
272 else
|
flickerstreak@1
|
273 while true do
|
flickerstreak@1
|
274 if rawequal(current, parent) then
|
flickerstreak@1
|
275 return true
|
flickerstreak@1
|
276 elseif rawequal(current, Object) then
|
flickerstreak@1
|
277 return false
|
flickerstreak@1
|
278 end
|
flickerstreak@1
|
279 current = current.super
|
flickerstreak@1
|
280 if type(current) ~= "table" then
|
flickerstreak@1
|
281 return false
|
flickerstreak@1
|
282 end
|
flickerstreak@1
|
283 end
|
flickerstreak@1
|
284 end
|
flickerstreak@1
|
285 end
|
flickerstreak@1
|
286
|
flickerstreak@1
|
287 -- @table Class
|
flickerstreak@1
|
288 -- @brief An object factory which sets up inheritence and supports
|
flickerstreak@1
|
289 -- 'mixins'.
|
flickerstreak@1
|
290 --
|
flickerstreak@1
|
291 -- @metamethod Class call
|
flickerstreak@1
|
292 -- @brief Call ClassFactory:new() to create a new class.
|
flickerstreak@1
|
293 --
|
flickerstreak@1
|
294 -- @method Class new
|
flickerstreak@1
|
295 -- @brief Construct a new object.
|
flickerstreak@1
|
296 -- @param (...) Arguments to pass to the object init function.
|
flickerstreak@1
|
297 -- @return The new object.
|
flickerstreak@1
|
298 --
|
flickerstreak@1
|
299 -- @method Class init
|
flickerstreak@1
|
300 -- @brief Initialize a new class.
|
flickerstreak@1
|
301 -- @param parent Superclass.
|
flickerstreak@1
|
302 -- @param (...) Mixins.
|
flickerstreak@1
|
303 --
|
flickerstreak@1
|
304 -- @method Class ToString
|
flickerstreak@1
|
305 -- @return A string representing the object, in this case 'Class'.
|
flickerstreak@1
|
306 local initStatus
|
flickerstreak@1
|
307 local Class
|
flickerstreak@1
|
308 local Mixin
|
flickerstreak@1
|
309 local autoEmbed = false
|
flickerstreak@1
|
310 local function traverseInterfaces(bit, total)
|
flickerstreak@1
|
311 if bit.superinterfaces then
|
flickerstreak@1
|
312 for interface in pairs(bit.superinterfaces) do
|
flickerstreak@1
|
313 if not total[interface] then
|
flickerstreak@1
|
314 total[interface] = true
|
flickerstreak@1
|
315 traverseInterfaces(interface, total)
|
flickerstreak@1
|
316 end
|
flickerstreak@1
|
317 end
|
flickerstreak@1
|
318 end
|
flickerstreak@1
|
319 end
|
flickerstreak@1
|
320 local class_new
|
flickerstreak@1
|
321 do
|
flickerstreak@1
|
322 Class = Factory(Object, setmetatable({}, {__index = Object}), Object)
|
flickerstreak@1
|
323 Class.super = Object
|
flickerstreak@1
|
324
|
flickerstreak@1
|
325 local function protostring(t)
|
flickerstreak@1
|
326 return '<' .. tostring(t.class) .. ' prototype>'
|
flickerstreak@1
|
327 end
|
flickerstreak@1
|
328 local function classobjectstring(t)
|
flickerstreak@1
|
329 if t.ToString then
|
flickerstreak@1
|
330 return t:ToString()
|
flickerstreak@1
|
331 elseif t.GetLibraryVersion then
|
flickerstreak@1
|
332 return (t:GetLibraryVersion())
|
flickerstreak@1
|
333 else
|
flickerstreak@1
|
334 return '<' .. tostring(t.class) .. ' instance>'
|
flickerstreak@1
|
335 end
|
flickerstreak@1
|
336 end
|
flickerstreak@1
|
337 local function classobjectequal(self, other)
|
flickerstreak@1
|
338 if type(self) == "table" and self.Equals then
|
flickerstreak@1
|
339 return self:Equals(other)
|
flickerstreak@1
|
340 elseif type(other) == "table" and other.Equals then
|
flickerstreak@1
|
341 return other:Equals(self)
|
flickerstreak@1
|
342 elseif type(self) == "table" and self.CompareTo then
|
flickerstreak@1
|
343 return self:CompareTo(other) == 0
|
flickerstreak@1
|
344 elseif type(other) == "table" and other.CompareTo then
|
flickerstreak@1
|
345 return other:CompareTo(self) == 0
|
flickerstreak@1
|
346 else
|
flickerstreak@1
|
347 return rawequal(self, other)
|
flickerstreak@1
|
348 end
|
flickerstreak@1
|
349 end
|
flickerstreak@1
|
350 local function classobjectlessthan(self, other)
|
flickerstreak@1
|
351 if type(self) == "table" and self.IsLessThan then
|
flickerstreak@1
|
352 return self:IsLessThan(other)
|
flickerstreak@1
|
353 elseif type(other) == "table" and other.IsLessThanOrEqualTo then
|
flickerstreak@1
|
354 return not other:IsLessThanOrEqualTo(self)
|
flickerstreak@1
|
355 elseif type(self) == "table" and self.CompareTo then
|
flickerstreak@1
|
356 return self:CompareTo(other) < 0
|
flickerstreak@1
|
357 elseif type(other) == "table" and other.CompareTo then
|
flickerstreak@1
|
358 return other:CompareTo(self) > 0
|
flickerstreak@1
|
359 elseif type(other) == "table" and other.IsLessThan and other.Equals then
|
flickerstreak@1
|
360 return other:Equals(self) or other:IsLessThan(self)
|
flickerstreak@1
|
361 else
|
flickerstreak@1
|
362 AceOO:error("cannot compare two objects")
|
flickerstreak@1
|
363 end
|
flickerstreak@1
|
364 end
|
flickerstreak@1
|
365 local function classobjectlessthanequal(self, other)
|
flickerstreak@1
|
366 if type(self) == "table" and self.IsLessThanOrEqualTo then
|
flickerstreak@1
|
367 return self:IsLessThanOrEqualTo(other)
|
flickerstreak@1
|
368 elseif type(other) == "table" and other.IsLessThan then
|
flickerstreak@1
|
369 return not other:IsLessThan(self)
|
flickerstreak@1
|
370 elseif type(self) == "table" and self.CompareTo then
|
flickerstreak@1
|
371 return self:CompareTo(other) <= 0
|
flickerstreak@1
|
372 elseif type(other) == "table" and other.CompareTo then
|
flickerstreak@1
|
373 return other:CompareTo(self) >= 0
|
flickerstreak@1
|
374 elseif type(self) == "table" and self.IsLessThan and self.Equals then
|
flickerstreak@1
|
375 return self:Equals(other) or self:IsLessThan(other)
|
flickerstreak@1
|
376 else
|
flickerstreak@1
|
377 AceOO:error("cannot compare two incompatible objects")
|
flickerstreak@1
|
378 end
|
flickerstreak@1
|
379 end
|
flickerstreak@1
|
380 local function classobjectadd(self, other)
|
flickerstreak@1
|
381 if type(self) == "table" and self.Add then
|
flickerstreak@1
|
382 return self:Add(other)
|
flickerstreak@1
|
383 else
|
flickerstreak@1
|
384 AceOO:error("cannot add two incompatible objects")
|
flickerstreak@1
|
385 end
|
flickerstreak@1
|
386 end
|
flickerstreak@1
|
387 local function classobjectsub(self, other)
|
flickerstreak@1
|
388 if type(self) == "table" and self.Subtract then
|
flickerstreak@1
|
389 return self:Subtract(other)
|
flickerstreak@1
|
390 else
|
flickerstreak@1
|
391 AceOO:error("cannot subtract two incompatible objects")
|
flickerstreak@1
|
392 end
|
flickerstreak@1
|
393 end
|
flickerstreak@1
|
394 local function classobjectunm(self, other)
|
flickerstreak@1
|
395 if type(self) == "table" and self.UnaryNegation then
|
flickerstreak@1
|
396 return self:UnaryNegation(other)
|
flickerstreak@1
|
397 else
|
flickerstreak@1
|
398 AceOO:error("attempt to negate an incompatible object")
|
flickerstreak@1
|
399 end
|
flickerstreak@1
|
400 end
|
flickerstreak@1
|
401 local function classobjectmul(self, other)
|
flickerstreak@1
|
402 if type(self) == "table" and self.Multiply then
|
flickerstreak@1
|
403 return self:Multiply(other)
|
flickerstreak@1
|
404 else
|
flickerstreak@1
|
405 AceOO:error("cannot multiply two incompatible objects")
|
flickerstreak@1
|
406 end
|
flickerstreak@1
|
407 end
|
flickerstreak@1
|
408 local function classobjectdiv(self, other)
|
flickerstreak@1
|
409 if type(self) == "table" and self.Divide then
|
flickerstreak@1
|
410 return self:Divide(other)
|
flickerstreak@1
|
411 else
|
flickerstreak@1
|
412 AceOO:error("cannot divide two incompatible objects")
|
flickerstreak@1
|
413 end
|
flickerstreak@1
|
414 end
|
flickerstreak@1
|
415 local function classobjectpow(self, other)
|
flickerstreak@1
|
416 if type(self) == "table" and self.Exponent then
|
flickerstreak@1
|
417 return self:Exponent(other)
|
flickerstreak@1
|
418 else
|
flickerstreak@1
|
419 AceOO:error("cannot exponentiate two incompatible objects")
|
flickerstreak@1
|
420 end
|
flickerstreak@1
|
421 end
|
flickerstreak@1
|
422 local function classobjectconcat(self, other)
|
flickerstreak@1
|
423 if type(self) == "table" and self.Concatenate then
|
flickerstreak@1
|
424 return self:Concatenate(other)
|
flickerstreak@1
|
425 else
|
flickerstreak@1
|
426 AceOO:error("cannot concatenate two incompatible objects")
|
flickerstreak@1
|
427 end
|
flickerstreak@1
|
428 end
|
flickerstreak@1
|
429 function class_new(self, ...)
|
flickerstreak@1
|
430 if self.virtual then
|
flickerstreak@1
|
431 AceOO:error("Cannot instantiate a virtual class.")
|
flickerstreak@1
|
432 end
|
flickerstreak@1
|
433
|
flickerstreak@1
|
434 local o = self.prototype
|
flickerstreak@1
|
435 local newobj = {}
|
flickerstreak@1
|
436 if o.class and o.class.instancemeta then
|
flickerstreak@1
|
437 setmetatable(newobj, o.class.instancemeta)
|
flickerstreak@1
|
438 else
|
flickerstreak@1
|
439 Object:init(newobj, o)
|
flickerstreak@1
|
440 end
|
flickerstreak@1
|
441
|
flickerstreak@1
|
442 if self.interfaces and not self.interfacesVerified then
|
flickerstreak@1
|
443 -- Verify the interfaces
|
flickerstreak@1
|
444
|
flickerstreak@1
|
445 for interface in pairs(self.interfaces) do
|
flickerstreak@1
|
446 for field,kind in pairs(interface.interface) do
|
flickerstreak@1
|
447 if tostring(type(newobj[field])) ~= kind then
|
flickerstreak@1
|
448 AceOO:error("Class did not satisfy all interfaces. %q is required to be a %s. It is a %s", field, kind, tostring(type(newobj[field])))
|
flickerstreak@1
|
449 end
|
flickerstreak@1
|
450 end
|
flickerstreak@1
|
451 end
|
flickerstreak@1
|
452 self.interfacesVerified = true
|
flickerstreak@1
|
453 end
|
flickerstreak@1
|
454 local tmp = initStatus
|
flickerstreak@1
|
455 initStatus = newobj
|
flickerstreak@1
|
456 newobj:init(...)
|
flickerstreak@1
|
457 if initStatus then
|
flickerstreak@1
|
458 initStatus = tmp
|
flickerstreak@1
|
459 AceOO:error("Initialization not completed, be sure to call the superclass's init method.")
|
flickerstreak@1
|
460 return
|
flickerstreak@1
|
461 end
|
flickerstreak@1
|
462 initStatus = tmp
|
flickerstreak@1
|
463 return newobj
|
flickerstreak@1
|
464 end
|
flickerstreak@1
|
465 local classmeta = {
|
flickerstreak@1
|
466 __tostring = objtostring,
|
flickerstreak@1
|
467 __call = function(self, ...)
|
flickerstreak@1
|
468 return self:new(...)
|
flickerstreak@1
|
469 end,
|
flickerstreak@1
|
470 }
|
flickerstreak@1
|
471 function Class:init(newclass, parent, ...)
|
flickerstreak@1
|
472 parent = parent or self
|
flickerstreak@1
|
473
|
flickerstreak@1
|
474 local total
|
flickerstreak@1
|
475
|
flickerstreak@1
|
476 if parent.class then
|
flickerstreak@1
|
477 total = { parent, ... }
|
flickerstreak@1
|
478 parent = self
|
flickerstreak@1
|
479 else
|
flickerstreak@1
|
480 total = { ... }
|
flickerstreak@1
|
481 end
|
flickerstreak@1
|
482 if not inherits(parent, Class) then
|
flickerstreak@1
|
483 AceOO:error("Classes must inherit from a proper class")
|
flickerstreak@1
|
484 end
|
flickerstreak@1
|
485 if parent.sealed then
|
flickerstreak@1
|
486 AceOO:error("Cannot inherit from a sealed class")
|
flickerstreak@1
|
487 end
|
flickerstreak@1
|
488 for i,v in ipairs(total) do
|
flickerstreak@1
|
489 if inherits(v, Mixin) and v.class then
|
flickerstreak@1
|
490 if v.__deprecated then
|
flickerstreak@1
|
491 AceOO:error(v.__deprecated)
|
flickerstreak@1
|
492 end
|
flickerstreak@1
|
493 if not newclass.mixins then
|
flickerstreak@1
|
494 newclass.mixins = {}
|
flickerstreak@1
|
495 end
|
flickerstreak@1
|
496 if newclass.mixins[v] then
|
flickerstreak@1
|
497 AceOO:error("Cannot explicitly inherit from the same mixin twice")
|
flickerstreak@1
|
498 end
|
flickerstreak@1
|
499 newclass.mixins[v] = true
|
flickerstreak@1
|
500 elseif inherits(v, Interface) and v.class then
|
flickerstreak@1
|
501 if not newclass.interfaces then
|
flickerstreak@1
|
502 newclass.interfaces = {}
|
flickerstreak@1
|
503 end
|
flickerstreak@1
|
504 if newclass.interfaces[v] then
|
flickerstreak@1
|
505 AceOO:error("Cannot explicitly inherit from the same interface twice")
|
flickerstreak@1
|
506 end
|
flickerstreak@1
|
507 newclass.interfaces[v] = true
|
flickerstreak@1
|
508 else
|
flickerstreak@1
|
509 AceOO:error("Classes can only inherit from one or zero classes and any number of mixins or interfaces")
|
flickerstreak@1
|
510 end
|
flickerstreak@1
|
511 end
|
flickerstreak@1
|
512 if parent.interfaces then
|
flickerstreak@1
|
513 if not newclass.interfaces then
|
flickerstreak@1
|
514 newclass.interfaces = {}
|
flickerstreak@1
|
515 end
|
flickerstreak@1
|
516 for interface in pairs(parent.interfaces) do
|
flickerstreak@1
|
517 newclass.interfaces[interface] = true
|
flickerstreak@1
|
518 end
|
flickerstreak@1
|
519 end
|
flickerstreak@1
|
520 for k in pairs(total) do
|
flickerstreak@1
|
521 total[k] = nil
|
flickerstreak@1
|
522 end
|
flickerstreak@1
|
523
|
flickerstreak@1
|
524 newclass.super = parent
|
flickerstreak@1
|
525
|
flickerstreak@1
|
526 newclass.prototype = setmetatable(total, {
|
flickerstreak@1
|
527 __index = parent.prototype,
|
flickerstreak@1
|
528 __tostring = protostring,
|
flickerstreak@1
|
529 })
|
flickerstreak@1
|
530 total = nil
|
flickerstreak@1
|
531
|
flickerstreak@1
|
532 newclass.instancemeta = {
|
flickerstreak@1
|
533 __index = newclass.prototype,
|
flickerstreak@1
|
534 __tostring = classobjectstring,
|
flickerstreak@1
|
535 __eq = classobjectequal,
|
flickerstreak@1
|
536 __lt = classobjectlessthan,
|
flickerstreak@1
|
537 __le = classobjectlessthanequal,
|
flickerstreak@1
|
538 __add = classobjectadd,
|
flickerstreak@1
|
539 __sub = classobjectsub,
|
flickerstreak@1
|
540 __unm = classobjectunm,
|
flickerstreak@1
|
541 __mul = classobjectmul,
|
flickerstreak@1
|
542 __div = classobjectdiv,
|
flickerstreak@1
|
543 __pow = classobjectpow,
|
flickerstreak@1
|
544 __concat = classobjectconcat,
|
flickerstreak@1
|
545 }
|
flickerstreak@1
|
546
|
flickerstreak@1
|
547 setmetatable(newclass, classmeta)
|
flickerstreak@1
|
548
|
flickerstreak@1
|
549 newclass.new = class_new
|
flickerstreak@1
|
550
|
flickerstreak@1
|
551 if newclass.mixins then
|
flickerstreak@1
|
552 -- Fold in the mixins
|
flickerstreak@1
|
553 local err, msg
|
flickerstreak@1
|
554 for mixin in pairs(newclass.mixins) do
|
flickerstreak@1
|
555 local ret
|
flickerstreak@1
|
556 autoEmbed = true
|
flickerstreak@1
|
557 ret, msg = pcall(mixin.embed, mixin, newclass.prototype)
|
flickerstreak@1
|
558 autoEmbed = false
|
flickerstreak@1
|
559 if not ret then
|
flickerstreak@1
|
560 err = true
|
flickerstreak@1
|
561 break
|
flickerstreak@1
|
562 end
|
flickerstreak@1
|
563 end
|
flickerstreak@1
|
564
|
flickerstreak@1
|
565 if err then
|
flickerstreak@1
|
566 local pt = newclass.prototype
|
flickerstreak@1
|
567 for k,v in pairs(pt) do
|
flickerstreak@1
|
568 pt[k] = nil
|
flickerstreak@1
|
569 end
|
flickerstreak@1
|
570
|
flickerstreak@1
|
571 -- method conflict
|
flickerstreak@1
|
572 AceOO:error(msg)
|
flickerstreak@1
|
573 end
|
flickerstreak@1
|
574 end
|
flickerstreak@1
|
575
|
flickerstreak@1
|
576 newclass.prototype.class = newclass
|
flickerstreak@1
|
577
|
flickerstreak@1
|
578 if newclass.interfaces then
|
flickerstreak@1
|
579 for interface in pairs(newclass.interfaces) do
|
flickerstreak@1
|
580 traverseInterfaces(interface, newclass.interfaces)
|
flickerstreak@1
|
581 end
|
flickerstreak@1
|
582 end
|
flickerstreak@1
|
583 if newclass.mixins then
|
flickerstreak@1
|
584 for mixin in pairs(newclass.mixins) do
|
flickerstreak@1
|
585 if mixin.interfaces then
|
flickerstreak@1
|
586 if not newclass.interfaces then
|
flickerstreak@1
|
587 newclass.interfaces = {}
|
flickerstreak@1
|
588 end
|
flickerstreak@1
|
589 for interface in pairs(mixin.interfaces) do
|
flickerstreak@1
|
590 newclass.interfaces[interface] = true
|
flickerstreak@1
|
591 end
|
flickerstreak@1
|
592 end
|
flickerstreak@1
|
593 end
|
flickerstreak@1
|
594 end
|
flickerstreak@1
|
595 end
|
flickerstreak@1
|
596 function Class:ToString()
|
flickerstreak@1
|
597 if type(self.GetLibraryVersion) == "function" then
|
flickerstreak@1
|
598 return (self:GetLibraryVersion())
|
flickerstreak@1
|
599 else
|
flickerstreak@1
|
600 return "Class"
|
flickerstreak@1
|
601 end
|
flickerstreak@1
|
602 end
|
flickerstreak@1
|
603
|
flickerstreak@1
|
604 local tmp
|
flickerstreak@1
|
605 function Class.prototype:init()
|
flickerstreak@1
|
606 if rawequal(self, initStatus) then
|
flickerstreak@1
|
607 initStatus = nil
|
flickerstreak@1
|
608 else
|
flickerstreak@1
|
609 AceOO:error("Improper self passed to init. You must do MyClass.super.prototype.init(self, ...)", 2)
|
flickerstreak@1
|
610 end
|
flickerstreak@1
|
611 self.uid = getuid(self)
|
flickerstreak@1
|
612 local current = self.class
|
flickerstreak@1
|
613 while true do
|
flickerstreak@1
|
614 if current == Class then
|
flickerstreak@1
|
615 break
|
flickerstreak@1
|
616 end
|
flickerstreak@1
|
617 if current.mixins then
|
flickerstreak@1
|
618 for mixin in pairs(current.mixins) do
|
flickerstreak@1
|
619 if type(mixin.OnInstanceInit) == "function" then
|
flickerstreak@1
|
620 mixin:OnInstanceInit(self)
|
flickerstreak@1
|
621 end
|
flickerstreak@1
|
622 end
|
flickerstreak@1
|
623 end
|
flickerstreak@1
|
624 current = current.super
|
flickerstreak@1
|
625 end
|
flickerstreak@1
|
626 end
|
flickerstreak@1
|
627 end
|
flickerstreak@1
|
628
|
flickerstreak@1
|
629
|
flickerstreak@1
|
630 -- @object ClassFactory
|
flickerstreak@1
|
631 -- @brief A factory for creating classes. Rarely used directly.
|
flickerstreak@1
|
632 local ClassFactory = Factory(Object, Class, Object)
|
flickerstreak@1
|
633
|
flickerstreak@1
|
634 function Class:new(...)
|
flickerstreak@1
|
635 local x = ClassFactory:new(...)
|
flickerstreak@1
|
636 if AceOO.classes then
|
flickerstreak@1
|
637 AceOO.classes[x] = true
|
flickerstreak@1
|
638 end
|
flickerstreak@1
|
639 return x
|
flickerstreak@1
|
640 end
|
flickerstreak@1
|
641 getmetatable(Class).__call = Class.new
|
flickerstreak@1
|
642
|
flickerstreak@1
|
643 -- @class Mixin
|
flickerstreak@1
|
644 -- @brief A class to create mixin objects, which contain methods that get
|
flickerstreak@1
|
645 -- "mixed in" to class prototypes.
|
flickerstreak@1
|
646 --
|
flickerstreak@1
|
647 -- @object Mixin prototype
|
flickerstreak@1
|
648 -- @brief The prototype that mixin objects inherit their methods from.
|
flickerstreak@1
|
649 --
|
flickerstreak@1
|
650 -- @method Mixin prototype embed
|
flickerstreak@1
|
651 -- @brief Mix in the methods of our object which are listed in our interface
|
flickerstreak@1
|
652 -- to the supplied target table.
|
flickerstreak@1
|
653 --
|
flickerstreak@1
|
654 -- @method Mixin prototype init
|
flickerstreak@1
|
655 -- @brief Initialize the mixin object.
|
flickerstreak@1
|
656 -- @param newobj The new object we're initializing.
|
flickerstreak@1
|
657 -- @param interface The interface we implement (the list of methods our
|
flickerstreak@1
|
658 -- prototype provides which should be mixed into the target
|
flickerstreak@1
|
659 -- table by embed).
|
flickerstreak@1
|
660 do
|
flickerstreak@1
|
661 Mixin = Class()
|
flickerstreak@1
|
662 function Mixin:ToString()
|
flickerstreak@1
|
663 if self.GetLibraryVersion then
|
flickerstreak@1
|
664 return (self:GetLibraryVersion())
|
flickerstreak@1
|
665 else
|
flickerstreak@1
|
666 return 'Mixin'
|
flickerstreak@1
|
667 end
|
flickerstreak@1
|
668 end
|
flickerstreak@1
|
669 local function _Embed(state, field, target)
|
flickerstreak@1
|
670 field = next(state.export, field)
|
flickerstreak@1
|
671 if field == nil then
|
flickerstreak@1
|
672 return
|
flickerstreak@1
|
673 end
|
flickerstreak@1
|
674
|
flickerstreak@1
|
675 if rawget(target, field) or (target[field] and target[field] ~= state[field]) then
|
flickerstreak@1
|
676 AceOO:error("Method conflict in attempt to mixin. Field %q", field)
|
flickerstreak@1
|
677 end
|
flickerstreak@1
|
678
|
flickerstreak@1
|
679 target[field] = state[field]
|
flickerstreak@1
|
680
|
flickerstreak@1
|
681 local ret,msg = pcall(_Embed, state, field, target)
|
flickerstreak@1
|
682 if not ret then
|
flickerstreak@1
|
683 -- Mix in the next method according to the defined interface. If that
|
flickerstreak@1
|
684 -- fails due to a conflict, re-raise to back out the previous mixed
|
flickerstreak@1
|
685 -- methods.
|
flickerstreak@1
|
686
|
flickerstreak@1
|
687 target[field] = nil
|
flickerstreak@1
|
688 AceOO:error(msg)
|
flickerstreak@1
|
689 end
|
flickerstreak@1
|
690 end
|
flickerstreak@1
|
691 function Mixin.prototype:embed(target)
|
flickerstreak@1
|
692 if self.__deprecated then
|
flickerstreak@1
|
693 AceOO:error(self.__deprecated)
|
flickerstreak@1
|
694 end
|
flickerstreak@1
|
695 local mt = getmetatable(target)
|
flickerstreak@1
|
696 setmetatable(target, nil)
|
flickerstreak@1
|
697 local err, msg = pcall(_Embed, self, nil, target)
|
flickerstreak@1
|
698 if not err then
|
flickerstreak@1
|
699 setmetatable(target, mt)
|
flickerstreak@1
|
700 AceOO:error(msg)
|
flickerstreak@1
|
701 return
|
flickerstreak@1
|
702 end
|
flickerstreak@1
|
703 if type(self.embedList) == "table" then
|
flickerstreak@1
|
704 self.embedList[target] = true
|
flickerstreak@1
|
705 end
|
flickerstreak@1
|
706 if type(target.class) ~= "table" then
|
flickerstreak@1
|
707 target[self] = true
|
flickerstreak@1
|
708 end
|
flickerstreak@1
|
709 if not autoEmbed and type(self.OnManualEmbed) == "function" then
|
flickerstreak@1
|
710 self:OnManualEmbed(target)
|
flickerstreak@1
|
711 end
|
flickerstreak@1
|
712 setmetatable(target, mt)
|
flickerstreak@1
|
713 end
|
flickerstreak@1
|
714
|
flickerstreak@1
|
715 function Mixin.prototype:activate(oldLib, oldDeactivate)
|
flickerstreak@1
|
716 if oldLib and oldLib.embedList then
|
flickerstreak@1
|
717 for target in pairs(oldLib.embedList) do
|
flickerstreak@1
|
718 local mt = getmetatable(target)
|
flickerstreak@1
|
719 setmetatable(target, nil)
|
flickerstreak@1
|
720 for field in pairs(oldLib.export) do
|
flickerstreak@1
|
721 target[field] = nil
|
flickerstreak@1
|
722 end
|
flickerstreak@1
|
723 setmetatable(target, mt)
|
flickerstreak@1
|
724 end
|
flickerstreak@1
|
725 self.embedList = oldLib.embedList
|
flickerstreak@1
|
726 for target in pairs(self.embedList) do
|
flickerstreak@1
|
727 self:embed(target)
|
flickerstreak@1
|
728 end
|
flickerstreak@1
|
729 else
|
flickerstreak@1
|
730 self.embedList = setmetatable({}, {__mode="k"})
|
flickerstreak@1
|
731 end
|
flickerstreak@1
|
732 end
|
flickerstreak@1
|
733
|
flickerstreak@1
|
734 function Mixin.prototype:init(export, ...)
|
flickerstreak@1
|
735 AceOO:argCheck(export, 2, "table")
|
flickerstreak@1
|
736 for k,v in pairs(export) do
|
flickerstreak@1
|
737 if type(k) ~= "number" then
|
flickerstreak@1
|
738 AceOO:error("All keys to argument #2 must be numbers.")
|
flickerstreak@1
|
739 elseif type(v) ~= "string" then
|
flickerstreak@1
|
740 AceOO:error("All values to argument #2 must be strings.")
|
flickerstreak@1
|
741 end
|
flickerstreak@1
|
742 end
|
flickerstreak@1
|
743 local num = #export
|
flickerstreak@1
|
744 for i = 1, num do
|
flickerstreak@1
|
745 local v = export[i]
|
flickerstreak@1
|
746 export[i] = nil
|
flickerstreak@1
|
747 export[v] = true
|
flickerstreak@1
|
748 end
|
flickerstreak@1
|
749
|
flickerstreak@1
|
750 local interfaces
|
flickerstreak@1
|
751 if select('#', ...) >= 1 then
|
flickerstreak@1
|
752 interfaces = { ... }
|
flickerstreak@1
|
753 for i,v in ipairs(interfaces) do
|
flickerstreak@1
|
754 v = getlibrary(v)
|
flickerstreak@1
|
755 interfaces[i] = v
|
flickerstreak@1
|
756 if not v.class or not inherits(v, Interface) then
|
flickerstreak@1
|
757 AceOO:error("Mixins can inherit only from interfaces")
|
flickerstreak@1
|
758 end
|
flickerstreak@1
|
759 end
|
flickerstreak@1
|
760 local num = #interfaces
|
flickerstreak@1
|
761 for i = 1, num do
|
flickerstreak@1
|
762 local v = interfaces[i]
|
flickerstreak@1
|
763 interfaces[i] = nil
|
flickerstreak@1
|
764 interfaces[v] = true
|
flickerstreak@1
|
765 end
|
flickerstreak@1
|
766 for interface in pairs(interfaces) do
|
flickerstreak@1
|
767 traverseInterfaces(interface, interfaces)
|
flickerstreak@1
|
768 end
|
flickerstreak@1
|
769 for interface in pairs(interfaces) do
|
flickerstreak@1
|
770 for field,kind in pairs(interface.interface) do
|
flickerstreak@1
|
771 if kind ~= "nil" then
|
flickerstreak@1
|
772 local good = false
|
flickerstreak@1
|
773 for bit in pairs(export) do
|
flickerstreak@1
|
774 if bit == field then
|
flickerstreak@1
|
775 good = true
|
flickerstreak@1
|
776 break
|
flickerstreak@1
|
777 end
|
flickerstreak@1
|
778 end
|
flickerstreak@1
|
779 if not good then
|
flickerstreak@1
|
780 AceOO:error("Mixin does not fully accommodate field %q", field)
|
flickerstreak@1
|
781 end
|
flickerstreak@1
|
782 end
|
flickerstreak@1
|
783 end
|
flickerstreak@1
|
784 end
|
flickerstreak@1
|
785 end
|
flickerstreak@1
|
786 self.super = Mixin.prototype
|
flickerstreak@1
|
787 Mixin.super.prototype.init(self)
|
flickerstreak@1
|
788 self.export = export
|
flickerstreak@1
|
789 self.interfaces = interfaces
|
flickerstreak@1
|
790 end
|
flickerstreak@1
|
791 end
|
flickerstreak@1
|
792
|
flickerstreak@1
|
793 -- @class Interface
|
flickerstreak@1
|
794 -- @brief A class to create interfaces, which contain contracts that classes
|
flickerstreak@1
|
795 -- which inherit from this must comply with.
|
flickerstreak@1
|
796 --
|
flickerstreak@1
|
797 -- @object Interface prototype
|
flickerstreak@1
|
798 -- @brief The prototype that interface objects must adhere to.
|
flickerstreak@1
|
799 --
|
flickerstreak@1
|
800 -- @method Interface prototype init
|
flickerstreak@1
|
801 -- @brief Initialize the mixin object.
|
flickerstreak@1
|
802 -- @param interface The interface we contract (the hash of fields forced).
|
flickerstreak@1
|
803 -- @param (...) Superinterfaces
|
flickerstreak@1
|
804 do
|
flickerstreak@1
|
805 Interface = Class()
|
flickerstreak@1
|
806 function Interface:ToString()
|
flickerstreak@1
|
807 if self.GetLibraryVersion then
|
flickerstreak@1
|
808 return (self:GetLibraryVersion())
|
flickerstreak@1
|
809 else
|
flickerstreak@1
|
810 return 'Instance'
|
flickerstreak@1
|
811 end
|
flickerstreak@1
|
812 end
|
flickerstreak@1
|
813 function Interface.prototype:init(interface, ...)
|
flickerstreak@1
|
814 Interface.super.prototype.init(self)
|
flickerstreak@1
|
815 AceOO:argCheck(interface, 2, "table")
|
flickerstreak@1
|
816 for k,v in pairs(interface) do
|
flickerstreak@1
|
817 if type(k) ~= "string" then
|
flickerstreak@1
|
818 AceOO:error("All keys to argument #2 must be numbers.")
|
flickerstreak@1
|
819 elseif type(v) ~= "string" then
|
flickerstreak@1
|
820 AceOO:error("All values to argument #2 must be strings.")
|
flickerstreak@1
|
821 elseif v ~= "nil" and v ~= "string" and v ~= "number" and v ~= "table" and v ~= "function" then
|
flickerstreak@1
|
822 AceOO:error('All values to argument #2 must either be "nil", "string", "number", "table", or "function".')
|
flickerstreak@1
|
823 end
|
flickerstreak@1
|
824 end
|
flickerstreak@1
|
825 if select('#', ...) >= 1 then
|
flickerstreak@1
|
826 self.superinterfaces = { ... }
|
flickerstreak@1
|
827 for i,v in ipairs(self.superinterfaces) do
|
flickerstreak@1
|
828 v = getlibrary(v)
|
flickerstreak@1
|
829 self.superinterfaces[i] = v
|
flickerstreak@1
|
830 if not inherits(v, Interface) or not v.class then
|
flickerstreak@1
|
831 AceOO:error('Cannot provide a non-Interface to inherit from')
|
flickerstreak@1
|
832 end
|
flickerstreak@1
|
833 end
|
flickerstreak@1
|
834 local num = #self.superinterfaces
|
flickerstreak@1
|
835 for i = 1, num do
|
flickerstreak@1
|
836 local v = self.superinterfaces[i]
|
flickerstreak@1
|
837 self.superinterfaces[i] = nil
|
flickerstreak@1
|
838 self.superinterfaces[v] = true
|
flickerstreak@1
|
839 end
|
flickerstreak@1
|
840 end
|
flickerstreak@1
|
841 self.interface = interface
|
flickerstreak@1
|
842 end
|
flickerstreak@1
|
843 end
|
flickerstreak@1
|
844
|
flickerstreak@1
|
845 -- @function Classpool
|
flickerstreak@1
|
846 -- @brief Obtain a read only class from our pool of classes, indexed by the
|
flickerstreak@1
|
847 -- superclass and mixins.
|
flickerstreak@1
|
848 -- @param sc The superclass of the class we want.
|
flickerstreak@1
|
849 -- @param (m1..m20) Mixins of the class we want's objects.
|
flickerstreak@1
|
850 -- @return A read only class from the class pool.
|
flickerstreak@1
|
851 local Classpool
|
flickerstreak@1
|
852 do
|
flickerstreak@1
|
853 local pool = setmetatable({}, {__mode = 'v'})
|
flickerstreak@1
|
854 local function newindex(k, v)
|
flickerstreak@1
|
855 AceOO:error('Attempt to modify a read-only class.')
|
flickerstreak@1
|
856 end
|
flickerstreak@1
|
857 local function protonewindex(k, v)
|
flickerstreak@1
|
858 AceOO:error('Attempt to modify a read-only class prototype.')
|
flickerstreak@1
|
859 end
|
flickerstreak@1
|
860 local function ts(bit)
|
flickerstreak@1
|
861 if type(bit) ~= "table" then
|
flickerstreak@1
|
862 return tostring(bit)
|
flickerstreak@1
|
863 elseif getmetatable(bit) and bit.__tostring then
|
flickerstreak@1
|
864 return tostring(bit)
|
flickerstreak@1
|
865 elseif type(bit.GetLibraryVersion) == "function" then
|
flickerstreak@1
|
866 return bit:GetLibraryVersion()
|
flickerstreak@1
|
867 else
|
flickerstreak@1
|
868 return tostring(bit)
|
flickerstreak@1
|
869 end
|
flickerstreak@1
|
870 end
|
flickerstreak@1
|
871 local t = {}
|
flickerstreak@1
|
872 local function getcomplexuid(sc, ...)
|
flickerstreak@1
|
873 if sc then
|
flickerstreak@1
|
874 if sc.uid then
|
flickerstreak@1
|
875 table.insert(t, sc.uid)
|
flickerstreak@1
|
876 else
|
flickerstreak@1
|
877 AceOO:error("%s is not an appropriate class/mixin", ts(sc))
|
flickerstreak@1
|
878 end
|
flickerstreak@1
|
879 end
|
flickerstreak@1
|
880 for i = 1, select('#', ...) do
|
flickerstreak@1
|
881 local m = select(i, ...)
|
flickerstreak@1
|
882 if m.uid then
|
flickerstreak@1
|
883 table.insert(t, m.uid)
|
flickerstreak@1
|
884 else
|
flickerstreak@1
|
885 AceOO:error("%s is not an appropriate mixin", ts(m))
|
flickerstreak@1
|
886 end
|
flickerstreak@1
|
887 end
|
flickerstreak@1
|
888 table.sort(t)
|
flickerstreak@1
|
889 local uid = table.concat(t, '')
|
flickerstreak@1
|
890 local num = #t
|
flickerstreak@1
|
891 for i = 1, num do
|
flickerstreak@1
|
892 t[i] = nil
|
flickerstreak@1
|
893 end
|
flickerstreak@1
|
894 return uid
|
flickerstreak@1
|
895 end
|
flickerstreak@1
|
896 local classmeta
|
flickerstreak@1
|
897 local arg = {}
|
flickerstreak@1
|
898 function Classpool(superclass, ...)
|
flickerstreak@1
|
899 local l = getlibrary
|
flickerstreak@1
|
900 superclass = getlibrary(superclass)
|
flickerstreak@1
|
901 arg = { ... }
|
flickerstreak@1
|
902 for i, v in ipairs(arg) do
|
flickerstreak@1
|
903 arg[i] = getlibrary(v)
|
flickerstreak@1
|
904 end
|
flickerstreak@1
|
905 if superclass then
|
flickerstreak@1
|
906 if superclass.class then -- mixin
|
flickerstreak@1
|
907 table.insert(arg, 1, superclass)
|
flickerstreak@1
|
908 superclass = Class
|
flickerstreak@1
|
909 end
|
flickerstreak@1
|
910 else
|
flickerstreak@1
|
911 superclass = Class
|
flickerstreak@1
|
912 end
|
flickerstreak@1
|
913 local key = getcomplexuid(superclass, unpack(arg))
|
flickerstreak@1
|
914 if not pool[key] then
|
flickerstreak@1
|
915 local class = Class(superclass, unpack(arg))
|
flickerstreak@1
|
916 if not classmeta then
|
flickerstreak@1
|
917 classmeta = {}
|
flickerstreak@1
|
918 local mt = getmetatable(class)
|
flickerstreak@1
|
919 for k,v in pairs(mt) do
|
flickerstreak@1
|
920 classmeta[k] = v
|
flickerstreak@1
|
921 end
|
flickerstreak@1
|
922 classmeta.__newindex = newindex
|
flickerstreak@1
|
923 end
|
flickerstreak@1
|
924 -- Prevent the user from adding methods to this class.
|
flickerstreak@1
|
925 -- NOTE: I'm not preventing modifications of existing class members,
|
flickerstreak@1
|
926 -- but it's likely that only a truly malicious user will be doing so.
|
flickerstreak@1
|
927 class.sealed = true
|
flickerstreak@1
|
928 setmetatable(class, classmeta)
|
flickerstreak@1
|
929 getmetatable(class.prototype).__newindex = protonewindex
|
flickerstreak@1
|
930 pool[key] = class
|
flickerstreak@1
|
931 end
|
flickerstreak@1
|
932 return pool[key]
|
flickerstreak@1
|
933 end
|
flickerstreak@1
|
934 end
|
flickerstreak@1
|
935
|
flickerstreak@1
|
936 AceOO.Factory = Factory
|
flickerstreak@1
|
937 AceOO.Object = Object
|
flickerstreak@1
|
938 AceOO.Class = Class
|
flickerstreak@1
|
939 AceOO.Mixin = Mixin
|
flickerstreak@1
|
940 AceOO.Interface = Interface
|
flickerstreak@1
|
941 AceOO.Classpool = Classpool
|
flickerstreak@1
|
942 AceOO.inherits = inherits
|
flickerstreak@1
|
943
|
flickerstreak@1
|
944 -- Library handling bits
|
flickerstreak@1
|
945
|
flickerstreak@1
|
946 local function activate(self, oldLib, oldDeactivate)
|
flickerstreak@1
|
947 AceOO = self
|
flickerstreak@1
|
948 Factory = self.Factory
|
flickerstreak@1
|
949 Object = self.Object
|
flickerstreak@1
|
950 Class = self.Class
|
flickerstreak@1
|
951 ClassFactory.prototype = Class
|
flickerstreak@1
|
952 Mixin = self.Mixin
|
flickerstreak@1
|
953 Interface = self.Interface
|
flickerstreak@1
|
954 Classpool = self.Classpool
|
flickerstreak@1
|
955
|
flickerstreak@1
|
956 if oldLib then
|
flickerstreak@1
|
957 self.classes = oldLib.classes
|
flickerstreak@1
|
958 end
|
flickerstreak@1
|
959 if not self.classes then
|
flickerstreak@1
|
960 self.classes = setmetatable({}, {__mode="k"})
|
flickerstreak@1
|
961 else
|
flickerstreak@1
|
962 for class in pairs(self.classes) do
|
flickerstreak@1
|
963 class.new = class_new
|
flickerstreak@1
|
964 end
|
flickerstreak@1
|
965 end
|
flickerstreak@1
|
966
|
flickerstreak@1
|
967 if oldDeactivate then
|
flickerstreak@1
|
968 oldDeactivate(oldLib)
|
flickerstreak@1
|
969 end
|
flickerstreak@1
|
970 end
|
flickerstreak@1
|
971
|
flickerstreak@1
|
972 AceLibrary:Register(AceOO, MAJOR_VERSION, MINOR_VERSION, activate)
|
flickerstreak@1
|
973 AceOO = AceLibrary(MAJOR_VERSION)
|