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