vanilla-wow-addons – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 --[[
2 Name: AceLibrary
3 Revision: $Rev: 14130 $
4 Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
5 Inspired By: Iriel (iriel@vigilance-committee.org)
6 Tekkub (tekkub@gmail.com)
7 Revision: $Rev: 14130 $
8 Website: http://www.wowace.com/
9 Documentation: http://www.wowace.com/index.php/AceLibrary
10 SVN: http://svn.wowace.com/root/trunk/Ace2/AceLibrary
11 Description: Versioning library to handle other library instances, upgrading,
12 and proper access.
13 It also provides a base for libraries to work off of, providing
14 proper error tools. It is handy because all the errors occur in the
15 file that called it, not in the library file itself.
16 Dependencies: None
17 ]]
18  
19 local ACELIBRARY_MAJOR = "AceLibrary"
20 local ACELIBRARY_MINOR = "$Revision: 14130 $"
21  
22 local table_setn
23 do
24 local version = GetBuildInfo()
25 if string.find(version, "^2%.") then
26 -- 2.0.0
27 table_setn = function() end
28 else
29 table_setn = table.setn
30 end
31 end
32  
33 local string_gfind = string.gmatch or string.gfind
34  
35 local _G = getfenv(0)
36 local previous = _G[ACELIBRARY_MAJOR]
37 if previous and not previous:IsNewVersion(ACELIBRARY_MAJOR, ACELIBRARY_MINOR) then return end
38  
39 -- @table AceLibrary
40 -- @brief System to handle all versioning of libraries.
41 local AceLibrary = {}
42 local AceLibrary_mt = {}
43 setmetatable(AceLibrary, AceLibrary_mt)
44  
45 local tmp
46 local function error(self, message, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
47 if type(self) ~= "table" then
48 _G.error(string.format("Bad argument #1 to `error' (table expected, got %s)", type(self)), 2)
49 end
50 if not tmp then
51 tmp = {}
52 else
53 for k in pairs(tmp) do tmp[k] = nil end
54 table_setn(tmp, 0)
55 end
56  
57 table.insert(tmp, a1)
58 table.insert(tmp, a2)
59 table.insert(tmp, a3)
60 table.insert(tmp, a4)
61 table.insert(tmp, a5)
62 table.insert(tmp, a6)
63 table.insert(tmp, a7)
64 table.insert(tmp, a8)
65 table.insert(tmp, a9)
66 table.insert(tmp, a10)
67 table.insert(tmp, a11)
68 table.insert(tmp, a12)
69 table.insert(tmp, a13)
70 table.insert(tmp, a14)
71 table.insert(tmp, a15)
72 table.insert(tmp, a16)
73 table.insert(tmp, a17)
74 table.insert(tmp, a18)
75 table.insert(tmp, a19)
76 table.insert(tmp, a20)
77  
78 local stack = debugstack()
79 if not message then
80 local _,_,second = string.find(stack, "\n(.-)\n")
81 message = "error raised! " .. second
82 else
83 for i = 1,table.getn(tmp) do
84 tmp[i] = tostring(tmp[i])
85 end
86 for i = 1,10 do
87 table.insert(tmp, "nil")
88 end
89 message = string.format(message, unpack(tmp))
90 end
91  
92 if getmetatable(self) and getmetatable(self).__tostring then
93 message = string.format("%s: %s", tostring(self), message)
94 elseif type(rawget(self, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self:GetLibraryVersion()) then
95 message = string.format("%s: %s", self:GetLibraryVersion(), message)
96 elseif type(rawget(self, 'class')) == "table" and type(rawget(self.class, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self.class:GetLibraryVersion()) then
97 message = string.format("%s: %s", self.class:GetLibraryVersion(), message)
98 end
99  
100 local first = string.gsub(stack, "\n.*", "")
101 local file = string.gsub(first, ".*\\(.*).lua:%d+: .*", "%1")
102 file = string.gsub(file, "([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
103  
104 local i = 0
105 for s in string_gfind(stack, "\n([^\n]*)") do
106 i = i + 1
107 if not string.find(s, file .. "%.lua:%d+:") then
108 file = string.gsub(s, "^.*\\(.*).lua:%d+: .*", "%1")
109 file = string.gsub(file, "([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
110 break
111 end
112 end
113 local j = 0
114 for s in string_gfind(stack, "\n([^\n]*)") do
115 j = j + 1
116 if j > i and not string.find(s, file .. "%.lua:%d+:") then
117 _G.error(message, j + 1)
118 return
119 end
120 end
121 _G.error(message, 2)
122 return
123 end
124  
125 local function assert(self, condition, message, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
126 if not condition then
127 if not message then
128 local stack = debugstack()
129 local _,_,second = string.find(stack, "\n(.-)\n")
130 message = "assertion failed! " .. second
131 end
132 error(self, message, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
133 return
134 end
135 return condition
136 end
137  
138 local function argCheck(self, arg, num, kind, kind2, kind3, kind4, kind5)
139 if type(num) ~= "number" then
140 error(self, "Bad argument #3 to `argCheck' (number expected, got %s)", type(num))
141 elseif type(kind) ~= "string" then
142 error(self, "Bad argument #4 to `argCheck' (string expected, got %s)", type(kind))
143 end
144 local errored = false
145 arg = type(arg)
146 if arg ~= kind and arg ~= kind2 and arg ~= kind3 and arg ~= kind4 and arg ~= kind5 then
147 local _,_,func = string.find(debugstack(), "`argCheck'.-([`<].-['>])")
148 if not func then
149 _,_,func = string.find(debugstack(), "([`<].-['>])")
150 end
151 if kind5 then
152 error(self, "Bad argument #%s to %s (%s, %s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, kind5, arg)
153 elseif kind4 then
154 error(self, "Bad argument #%s to %s (%s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, arg)
155 elseif kind3 then
156 error(self, "Bad argument #%s to %s (%s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, arg)
157 elseif kind2 then
158 error(self, "Bad argument #%s to %s (%s or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, arg)
159 else
160 error(self, "Bad argument #%s to %s (%s expected, got %s)", tonumber(num) or 0/0, func, kind, arg)
161 end
162 end
163 end
164  
165 local function pcall(self, func, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
166 a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20 = _G.pcall(func, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
167 if not a1 then
168 error(self, string.gsub(a2, ".-%.lua:%d-: ", ""))
169 else
170 return a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20
171 end
172 end
173  
174 local recurse = {}
175 local function addToPositions(t, major)
176 if not AceLibrary.positions[t] or AceLibrary.positions[t] == major then
177 rawset(t, recurse, true)
178 AceLibrary.positions[t] = major
179 for k,v in pairs(t) do
180 if type(v) == "table" and not rawget(v, recurse) then
181 addToPositions(v, major)
182 end
183 if type(k) == "table" and not rawget(k, recurse) then
184 addToPositions(k, major)
185 end
186 end
187 local mt = getmetatable(t)
188 if mt and not rawget(mt, recurse) then
189 addToPositions(mt, major)
190 end
191 rawset(t, recurse, nil)
192 end
193 end
194  
195 local function svnRevisionToNumber(text)
196 if type(text) == "string" then
197 if string.find(text, "^%$Revision: (%d+) %$$") then
198 return tonumber((string.gsub(text, "^%$Revision: (%d+) %$$", "%1")))
199 elseif string.find(text, "^%$Rev: (%d+) %$$") then
200 return tonumber((string.gsub(text, "^%$Rev: (%d+) %$$", "%1")))
201 elseif string.find(text, "^%$LastChangedRevision: (%d+) %$$") then
202 return tonumber((string.gsub(text, "^%$LastChangedRevision: (%d+) %$$", "%1")))
203 end
204 elseif type(text) == "number" then
205 return text
206 end
207 return nil
208 end
209  
210 local crawlReplace
211 do
212 local recurse = {}
213 local function func(t, to, from)
214 if recurse[t] then
215 return
216 end
217 recurse[t] = true
218 local mt = getmetatable(t)
219 setmetatable(t, nil)
220 rawset(t, to, rawget(t, from))
221 rawset(t, from, nil)
222 for k,v in pairs(t) do
223 if v == from then
224 t[k] = to
225 elseif type(v) == "table" then
226 if not recurse[v] then
227 func(v, to, from)
228 end
229 end
230  
231 if type(k) == "table" then
232 if not recurse[k] then
233 func(k, to, from)
234 end
235 end
236 end
237 setmetatable(t, mt)
238 if mt then
239 if mt == from then
240 setmetatable(t, to)
241 elseif not recurse[mt] then
242 func(mt, to, from)
243 end
244 end
245 end
246 function crawlReplace(t, to, from)
247 func(t, to, from)
248 for k in pairs(recurse) do
249 recurse[k] = nil
250 end
251 end
252 end
253  
254 -- @function destroyTable
255 -- @brief remove all the contents of a table
256 -- @param t table to destroy
257 local function destroyTable(t)
258 setmetatable(t, nil)
259 for k,v in pairs(t) do t[k] = nil end
260 table_setn(t, 0)
261 end
262  
263 local function isFrame(frame)
264 return type(frame) == "table" and type(rawget(frame, 0)) == "userdata" and type(rawget(frame, 'IsFrameType')) == "function" and getmetatable(frame) and type(rawget(getmetatable(frame), '__index')) == "function"
265 end
266  
267 local new, del
268 do
269 local tables = setmetatable({}, {__mode = "k"})
270  
271 function new()
272 local t = next(tables)
273 if t then
274 tables[t] = nil
275 return t
276 else
277 return {}
278 end
279 end
280  
281 function del(t, depth)
282 if depth and depth > 0 then
283 for k,v in pairs(t) do
284 if type(v) == "table" and not isFrame(v) then
285 del(v, depth - 1)
286 end
287 end
288 end
289 destroyTable(t)
290 tables[t] = true
291 end
292 end
293  
294 -- @function copyTable
295 -- @brief Create a shallow copy of a table and return it.
296 -- @param from The table to copy from
297 -- @return A shallow copy of the table
298 local function copyTable(from)
299 local to = new()
300 for k,v in pairs(from) do to[k] = v end
301 table_setn(to, table.getn(from))
302 setmetatable(to, getmetatable(from))
303 return to
304 end
305  
306 -- @function deepTransfer
307 -- @brief Fully transfer all data, keeping proper previous table
308 -- backreferences stable.
309 -- @param to The table with which data is to be injected into
310 -- @param from The table whose data will be injected into the first
311 -- @param saveFields If available, a shallow copy of the basic data is saved
312 -- in here.
313 -- @param list The account of table references
314 -- @param list2 The current status on which tables have been traversed.
315 local deepTransfer
316 do
317 -- @function examine
318 -- @brief Take account of all the table references to be shared
319 -- between the to and from tables.
320 -- @param to The table with which data is to be injected into
321 -- @param from The table whose data will be injected into the first
322 -- @param list An account of the table references
323 local function examine(to, from, list, major)
324 list[from] = to
325 for k,v in pairs(from) do
326 if rawget(to, k) and type(from[k]) == "table" and type(to[k]) == "table" and not list[from[k]] then
327 if from[k] == to[k] then
328 list[from[k]] = to[k]
329 elseif AceLibrary.positions[from[v]] ~= major and AceLibrary.positions[from[v]] then
330 list[from[k]] = from[k]
331 elseif not list[from[k]] then
332 examine(to[k], from[k], list, major)
333 end
334 end
335 end
336 return list
337 end
338  
339 function deepTransfer(to, from, saveFields, major, list, list2)
340 setmetatable(to, nil)
341 local createdList
342 if not list then
343 createdList = true
344 list = new()
345 list2 = new()
346 examine(to, from, list, major)
347 end
348 list2[to] = to
349 for k,v in pairs(to) do
350 if type(rawget(from, k)) ~= "table" or type(v) ~= "table" or isFrame(v) then
351 if saveFields then
352 saveFields[k] = v
353 end
354 to[k] = nil
355 elseif v ~= _G then
356 if saveFields then
357 saveFields[k] = copyTable(v)
358 end
359 end
360 end
361 for k in pairs(from) do
362 if rawget(to, k) and to[k] ~= from[k] and AceLibrary.positions[to[k]] == major and from[k] ~= _G then
363 if not list2[to[k]] then
364 deepTransfer(to[k], from[k], nil, major, list, list2)
365 end
366 to[k] = list[to[k]] or list2[to[k]]
367 else
368 rawset(to, k, from[k])
369 end
370 end
371 table_setn(to, table.getn(from))
372 setmetatable(to, getmetatable(from))
373 local mt = getmetatable(to)
374 if mt then
375 if list[mt] then
376 setmetatable(to, list[mt])
377 elseif mt.__index and list[mt.__index] then
378 mt.__index = list[mt.__index]
379 end
380 end
381 destroyTable(from)
382 if createdList then
383 del(list)
384 del(list2)
385 end
386 end
387 end
388  
389 -- @method TryToLoadStandalone
390 -- @brief Attempt to find and load a standalone version of the requested library
391 -- @param major A string representing the major version
392 -- @return If library is found, return values from the call to LoadAddOn are returned
393 -- If the library has been requested previously, nil is returned.
394 local function TryToLoadStandalone(major)
395 if not AceLibrary.scannedlibs then AceLibrary.scannedlibs = {} end
396 if AceLibrary.scannedlibs[major] then return end
397  
398 AceLibrary.scannedlibs[major] = true
399  
400 local name, _, _, enabled, loadable = GetAddOnInfo(major)
401 if loadable then
402 return LoadAddOn(name)
403 end
404  
405 for i=1,GetNumAddOns() do
406 if GetAddOnMetadata(i, "X-AceLibrary-"..major) then
407 local name, _, _, enabled, loadable = GetAddOnInfo(i)
408 if loadable then
409 return LoadAddOn(name)
410 end
411 end
412 end
413 end
414  
415 -- @method IsNewVersion
416 -- @brief Obtain whether the supplied version would be an upgrade to the
417 -- current version. This allows for bypass code in library
418 -- declaration.
419 -- @param major A string representing the major version
420 -- @param minor An integer or an svn revision string representing the minor version
421 -- @return whether the supplied version would be newer than what is
422 -- currently available.
423 function AceLibrary:IsNewVersion(major, minor)
424 argCheck(self, major, 2, "string")
425 TryToLoadStandalone(major)
426  
427 if type(minor) == "string" then
428 local m = svnRevisionToNumber(minor)
429 if m then
430 minor = m
431 else
432 _G.error(string.format("Bad argument #3 to `IsNewVersion'. Must be a number or SVN revision string. %q is not appropriate", minor), 2)
433 end
434 end
435 argCheck(self, minor, 3, "number")
436 local data = self.libs[major]
437 if not data then
438 return true
439 end
440 return data.minor < minor
441 end
442  
443 -- @method HasInstance
444 -- @brief Returns whether an instance exists. This allows for optional support of a library.
445 -- @param major A string representing the major version.
446 -- @param minor (optional) An integer or an svn revision string representing the minor version.
447 -- @return Whether an instance exists.
448 function AceLibrary:HasInstance(major, minor)
449 argCheck(self, major, 2, "string")
450 TryToLoadStandalone(major)
451  
452 if minor then
453 if type(minor) == "string" then
454 local m = svnRevisionToNumber(minor)
455 if m then
456 minor = m
457 else
458 _G.error(string.format("Bad argument #3 to `HasInstance'. Must be a number or SVN revision string. %q is not appropriate", minor), 2)
459 end
460 end
461 argCheck(self, minor, 3, "number")
462 if not self.libs[major] then
463 return
464 end
465 return self.libs[major].minor == minor
466 end
467 return self.libs[major] and true
468 end
469  
470 -- @method GetInstance
471 -- @brief Returns the library with the given major/minor version.
472 -- @param major A string representing the major version.
473 -- @param minor (optional) An integer or an svn revision string representing the minor version.
474 -- @return The library with the given major/minor version.
475 function AceLibrary:GetInstance(major, minor)
476 argCheck(self, major, 2, "string")
477 TryToLoadStandalone(major)
478  
479 local data = self.libs[major]
480 if not data then
481 _G.error(string.format("Cannot find a library instance of %s.", major), 2)
482 return
483 end
484 if minor then
485 if type(minor) == "string" then
486 local m = svnRevisionToNumber(minor)
487 if m then
488 minor = m
489 else
490 _G.error(string.format("Bad argument #3 to `GetInstance'. Must be a number or SVN revision string. %q is not appropriate", minor), 2)
491 end
492 end
493 argCheck(self, minor, 2, "number")
494 if data.minor ~= minor then
495 _G.error(string.format("Cannot find a library instance of %s, minor version %d.", major, minor), 2)
496 return
497 end
498 end
499 return data.instance
500 end
501  
502 -- Syntax sugar. AceLibrary("FooBar-1.0")
503 AceLibrary_mt.__call = AceLibrary.GetInstance
504  
505 local donothing
506  
507 local AceEvent
508  
509 -- @method Register
510 -- @brief Registers a new version of a given library.
511 -- @param newInstance the library to register
512 -- @param major the major version of the library
513 -- @param minor the minor version of the library
514 -- @param activateFunc (optional) A function to be called when the library is
515 -- fully activated. Takes the arguments
516 -- (newInstance [, oldInstance, oldDeactivateFunc]). If
517 -- oldInstance is given, you should probably call
518 -- oldDeactivateFunc(oldInstance).
519 -- @param deactivateFunc (optional) A function to be called by a newer library's
520 -- activateFunc.
521 -- @param externalFunc (optional) A function to be called whenever a new
522 -- library is registered.
523 function AceLibrary:Register(newInstance, major, minor, activateFunc, deactivateFunc, externalFunc)
524 argCheck(self, newInstance, 2, "table")
525 argCheck(self, major, 3, "string")
526 if type(minor) == "string" then
527 local m = svnRevisionToNumber(minor)
528 if m then
529 minor = m
530 else
531 _G.error(string.format("Bad argument #4 to `Register'. Must be a number or SVN revision string. %q is not appropriate", minor), 2)
532 end
533 end
534 argCheck(self, minor, 4, "number")
535 if math.floor(minor) ~= minor or minor < 0 then
536 error(self, "Bad argument #4 to `Register' (integer >= 0 expected, got %s)", minor)
537 end
538 argCheck(self, activateFunc, 5, "function", "nil")
539 argCheck(self, deactivateFunc, 6, "function", "nil")
540 argCheck(self, externalFunc, 7, "function", "nil")
541 if not deactivateFunc then
542 if not donothing then
543 donothing = function() end
544 end
545 deactivateFunc = donothing
546 end
547 local data = self.libs[major]
548 if not data then
549 -- This is new
550 local instance = copyTable(newInstance)
551 crawlReplace(instance, instance, newInstance)
552 destroyTable(newInstance)
553 if AceLibrary == newInstance then
554 self = instance
555 AceLibrary = instance
556 end
557 self.libs[major] = {
558 instance = instance,
559 minor = minor,
560 deactivateFunc = deactivateFunc,
561 externalFunc = externalFunc,
562 }
563 rawset(instance, 'GetLibraryVersion', function(self)
564 return major, minor
565 end)
566 if not rawget(instance, 'error') then
567 rawset(instance, 'error', error)
568 end
569 if not rawget(instance, 'assert') then
570 rawset(instance, 'assert', assert)
571 end
572 if not rawget(instance, 'argCheck') then
573 rawset(instance, 'argCheck', argCheck)
574 end
575 if not rawget(instance, 'pcall') then
576 rawset(instance, 'pcall', pcall)
577 end
578 addToPositions(instance, major)
579 if activateFunc then
580 activateFunc(instance, nil, nil) -- no old version, so explicit nil
581 end
582  
583 if externalFunc then
584 for k,data in pairs(self.libs) do
585 if k ~= major then
586 externalFunc(instance, k, data.instance)
587 end
588 end
589 end
590  
591 for k,data in pairs(self.libs) do
592 if k ~= major and data.externalFunc then
593 data.externalFunc(data.instance, major, instance)
594 end
595 end
596 if major == "AceEvent-2.0" then
597 AceEvent = instance
598 end
599 if AceEvent then
600 AceEvent.TriggerEvent(self, "AceLibrary_Register", major, instance)
601 end
602  
603 return instance
604 end
605 local instance = data.instance
606 if minor <= data.minor then
607 -- This one is already obsolete, raise an error.
608 _G.error(string.format("Obsolete library registered. %s is already registered at version %d. You are trying to register version %d. Hint: if not AceLibrary:IsNewVersion(%q, %d) then return end", major, data.minor, minor, major, minor), 2)
609 return
610 end
611 -- This is an update
612 local oldInstance = new()
613  
614 addToPositions(newInstance, major)
615 local isAceLibrary = (AceLibrary == newInstance)
616 local old_error, old_assert, old_argCheck, old_pcall
617 if isAceLibrary then
618 self = instance
619 AceLibrary = instance
620  
621 old_error = instance.error
622 old_assert = instance.assert
623 old_argCheck = instance.argCheck
624 old_pcall = instance.pcall
625  
626 self.error = error
627 self.assert = assert
628 self.argCheck = argCheck
629 self.pcall = pcall
630 end
631 deepTransfer(instance, newInstance, oldInstance, major)
632 crawlReplace(instance, instance, newInstance)
633 local oldDeactivateFunc = data.deactivateFunc
634 data.minor = minor
635 data.deactivateFunc = deactivateFunc
636 data.externalFunc = externalFunc
637 rawset(instance, 'GetLibraryVersion', function(self)
638 return major, minor
639 end)
640 if not rawget(instance, 'error') then
641 rawset(instance, 'error', error)
642 end
643 if not rawget(instance, 'assert') then
644 rawset(instance, 'assert', assert)
645 end
646 if not rawget(instance, 'argCheck') then
647 rawset(instance, 'argCheck', argCheck)
648 end
649 if not rawget(instance, 'pcall') then
650 rawset(instance, 'pcall', pcall)
651 end
652 if isAceLibrary then
653 for _,v in pairs(self.libs) do
654 local i = type(v) == "table" and v.instance
655 if type(i) == "table" then
656 if not rawget(i, 'error') or i.error == old_error then
657 rawset(i, 'error', error)
658 end
659 if not rawget(i, 'assert') or i.assert == old_assert then
660 rawset(i, 'assert', assert)
661 end
662 if not rawget(i, 'argCheck') or i.argCheck == old_argCheck then
663 rawset(i, 'argCheck', argCheck)
664 end
665 if not rawget(i, 'pcall') or i.pcall == old_pcall then
666 rawset(i, 'pcall', pcall)
667 end
668 end
669 end
670 end
671 if activateFunc then
672 activateFunc(instance, oldInstance, oldDeactivateFunc)
673 else
674 oldDeactivateFunc(oldInstance)
675 end
676 del(oldInstance)
677  
678 if externalFunc then
679 for k,data in pairs(self.libs) do
680 if k ~= major then
681 externalFunc(instance, k, data.instance)
682 end
683 end
684 end
685  
686 return instance
687 end
688  
689 local iter
690 function AceLibrary:IterateLibraries()
691 if not iter then
692 local function iter(t, k)
693 k = next(t, k)
694 if not k then
695 return nil
696 else
697 return k, t[k].instance
698 end
699 end
700 end
701 return iter, self.libs, nil
702 end
703  
704 -- @function Activate
705 -- @brief The activateFunc for AceLibrary itself. Called when
706 -- AceLibrary properly registers.
707 -- @param self Reference to AceLibrary
708 -- @param oldLib (optional) Reference to an old version of AceLibrary
709 -- @param oldDeactivate (optional) Function to deactivate the old lib
710 local function activate(self, oldLib, oldDeactivate)
711 if not self.libs then
712 if oldLib then
713 self.libs = oldLib.libs
714 self.scannedlibs = oldLib.scannedlibs
715 end
716 if not self.libs then
717 self.libs = {}
718 end
719 if not self.scannedlibs then
720 self.scannedlibs = {}
721 end
722 end
723 if not self.positions then
724 if oldLib then
725 self.positions = oldLib.positions
726 end
727 if not self.positions then
728 self.positions = setmetatable({}, { __mode = "k" })
729 end
730 end
731  
732 -- Expose the library in the global environment
733 _G[ACELIBRARY_MAJOR] = self
734  
735 if oldDeactivate then
736 oldDeactivate(oldLib)
737 end
738 end
739  
740 if not previous then
741 previous = AceLibrary
742 end
743 if not previous.libs then
744 previous.libs = {}
745 end
746 AceLibrary.libs = previous.libs
747 if not previous.positions then
748 previous.positions = setmetatable({}, { __mode = "k" })
749 end
750 AceLibrary.positions = previous.positions
751 AceLibrary:Register(AceLibrary, ACELIBRARY_MAJOR, ACELIBRARY_MINOR, activate)