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