Mercurial > wow > reaction
comparison libs/AceLibrary/AceLibrary.lua @ 7:f920db5fc6b1
version 0.3
| author | Flick <flickerstreak@gmail.com> |
|---|---|
| date | Tue, 20 Mar 2007 21:25:29 +0000 |
| parents | c11ca1d8ed91 |
| children |
comparison
equal
deleted
inserted
replaced
| 6:2da5089ab7ff | 7:f920db5fc6b1 |
|---|---|
| 1 --[[ | 1 --[[ |
| 2 Name: AceLibrary | 2 Name: AceLibrary |
| 3 Revision: $Rev: 19062 $ | 3 Revision: $Rev$ |
| 4 Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) | 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) | 5 Inspired By: Iriel (iriel@vigilance-committee.org) |
| 6 Tekkub (tekkub@gmail.com) | 6 Tekkub (tekkub@gmail.com) |
| 7 Revision: $Rev: 19062 $ | 7 Revision: $Rev$ |
| 8 Website: http://www.wowace.com/ | 8 Website: http://www.wowace.com/ |
| 9 Documentation: http://www.wowace.com/index.php/AceLibrary | 9 Documentation: http://www.wowace.com/index.php/AceLibrary |
| 10 SVN: http://svn.wowace.com/root/trunk/Ace2/AceLibrary | 10 SVN: http://svn.wowace.com/root/trunk/Ace2/AceLibrary |
| 11 Description: Versioning library to handle other library instances, upgrading, | 11 Description: Versioning library to handle other library instances, upgrading, |
| 12 and proper access. | 12 and proper access. |
| 13 It also provides a base for libraries to work off of, providing | 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 | 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. | 15 file that called it, not in the library file itself. |
| 16 Dependencies: None | 16 Dependencies: None |
| 17 License: LGPL v2.1 | |
| 17 ]] | 18 ]] |
| 18 | 19 |
| 19 local ACELIBRARY_MAJOR = "AceLibrary" | 20 local ACELIBRARY_MAJOR = "AceLibrary" |
| 20 local ACELIBRARY_MINOR = "$Revision: 19062 $" | 21 local ACELIBRARY_MINOR = "$Revision: 20000 $" |
| 21 | 22 |
| 22 local _G = getfenv(0) | 23 local _G = getfenv(0) |
| 23 local previous = _G[ACELIBRARY_MAJOR] | 24 local previous = _G[ACELIBRARY_MAJOR] |
| 24 if previous and not previous:IsNewVersion(ACELIBRARY_MAJOR, ACELIBRARY_MINOR) then return end | 25 if previous and not previous:IsNewVersion(ACELIBRARY_MAJOR, ACELIBRARY_MINOR) then return end |
| 25 | 26 |
| 26 local function safecall(func,...) | 27 local function safecall(func,...) |
| 27 local success, err = pcall(func,...) | 28 local success, err = pcall(func,...) |
| 28 if not success then geterrorhandler()(err) end | 29 if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("\n(.-: )in.-\n") or "") .. err) end |
| 29 end | 30 end |
| 30 | 31 |
| 31 -- @table AceLibrary | 32 -- @table AceLibrary |
| 32 -- @brief System to handle all versioning of libraries. | 33 -- @brief System to handle all versioning of libraries. |
| 33 local AceLibrary = {} | 34 local AceLibrary = {} |
| 34 local AceLibrary_mt = {} | 35 local AceLibrary_mt = {} |
| 35 setmetatable(AceLibrary, AceLibrary_mt) | 36 setmetatable(AceLibrary, AceLibrary_mt) |
| 36 | 37 |
| 37 local function error(self, message, ...) | 38 local function error(self, message, ...) |
| 38 if type(self) ~= "table" then | 39 if type(self) ~= "table" then |
| 39 return _G.error(string.format("Bad argument #1 to `error' (table expected, got %s)", type(self)), 2) | 40 return _G.error(("Bad argument #1 to `error' (table expected, got %s)"):format(type(self)), 2) |
| 40 end | 41 end |
| 41 | 42 |
| 42 local stack = debugstack() | 43 local stack = debugstack() |
| 43 if not message then | 44 if not message then |
| 44 local _,_,second = string.find(stack, "\n(.-)\n") | 45 local _,_,second = stack:find("\n(.-)\n") |
| 45 message = "error raised! " .. second | 46 message = "error raised! " .. second |
| 46 else | 47 else |
| 47 local arg = { ... } | 48 local arg = { ... } -- not worried about table creation, as errors don't happen often |
| 48 | 49 |
| 49 for i = 1, #arg do | 50 for i = 1, #arg do |
| 50 arg[i] = tostring(arg[i]) | 51 arg[i] = tostring(arg[i]) |
| 51 end | 52 end |
| 52 for i = 1, 10 do | 53 for i = 1, 10 do |
| 53 table.insert(arg, "nil") | 54 table.insert(arg, "nil") |
| 54 end | 55 end |
| 55 message = string.format(message, unpack(arg)) | 56 message = message:format(unpack(arg)) |
| 56 end | 57 end |
| 57 | 58 |
| 58 if getmetatable(self) and getmetatable(self).__tostring then | 59 if getmetatable(self) and getmetatable(self).__tostring then |
| 59 message = string.format("%s: %s", tostring(self), message) | 60 message = ("%s: %s"):format(tostring(self), message) |
| 60 elseif type(rawget(self, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self:GetLibraryVersion()) then | 61 elseif type(rawget(self, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self:GetLibraryVersion()) then |
| 61 message = string.format("%s: %s", self:GetLibraryVersion(), message) | 62 message = ("%s: %s"):format(self:GetLibraryVersion(), message) |
| 62 elseif type(rawget(self, 'class')) == "table" and type(rawget(self.class, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self.class:GetLibraryVersion()) then | 63 elseif type(rawget(self, 'class')) == "table" and type(rawget(self.class, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self.class:GetLibraryVersion()) then |
| 63 message = string.format("%s: %s", self.class:GetLibraryVersion(), message) | 64 message = ("%s: %s"):format(self.class:GetLibraryVersion(), message) |
| 64 end | 65 end |
| 65 | 66 |
| 66 local first = string.gsub(stack, "\n.*", "") | 67 local first = stack:gsub("\n.*", "") |
| 67 local file = string.gsub(first, ".*\\(.*).lua:%d+: .*", "%1") | 68 local file = first:gsub(".*\\(.*).lua:%d+: .*", "%1") |
| 68 file = string.gsub(file, "([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1") | 69 file = file:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1") |
| 69 | 70 |
| 70 | 71 |
| 71 local i = 0 | 72 local i = 0 |
| 72 for s in string.gmatch(stack, "\n([^\n]*)") do | 73 for s in stack:gmatch("\n([^\n]*)") do |
| 73 i = i + 1 | 74 i = i + 1 |
| 74 if not string.find(s, file .. "%.lua:%d+:") and not string.find(s, "%(tail call%)") then | 75 if not s:find(file .. "%.lua:%d+:") and not s:find("%(tail call%)") then |
| 75 file = string.gsub(s, "^.*\\(.*).lua:%d+: .*", "%1") | 76 file = s:gsub("^.*\\(.*).lua:%d+: .*", "%1") |
| 76 file = string.gsub(file, "([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1") | 77 file = file:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1") |
| 77 break | 78 break |
| 78 end | 79 end |
| 79 end | 80 end |
| 80 local j = 0 | 81 local j = 0 |
| 81 for s in string.gmatch(stack, "\n([^\n]*)") do | 82 for s in stack:gmatch("\n([^\n]*)") do |
| 82 j = j + 1 | 83 j = j + 1 |
| 83 if j > i and not string.find(s, file .. "%.lua:%d+:") and not string.find(s, "%(tail call%)") then | 84 if j > i and not s:find(file .. "%.lua:%d+:") and not s:find("%(tail call%)") then |
| 84 return _G.error(message, j+1) | 85 return _G.error(message, j+1) |
| 85 end | 86 end |
| 86 end | 87 end |
| 87 return _G.error(message, 2) | 88 return _G.error(message, 2) |
| 88 end | 89 end |
| 89 | 90 |
| 90 local function assert(self, condition, message, ...) | 91 local function assert(self, condition, message, ...) |
| 91 if not condition then | 92 if not condition then |
| 92 if not message then | 93 if not message then |
| 93 local stack = debugstack() | 94 local stack = debugstack() |
| 94 local _,_,second = string.find(stack, "\n(.-)\n") | 95 local _,_,second = stack:find("\n(.-)\n") |
| 95 message = "assertion failed! " .. second | 96 message = "assertion failed! " .. second |
| 96 end | 97 end |
| 97 return error(self, message, ...) | 98 return error(self, message, ...) |
| 98 end | 99 end |
| 99 return condition | 100 return condition |
| 106 return error(self, "Bad argument #4 to `argCheck' (string expected, got %s)", type(kind)) | 107 return error(self, "Bad argument #4 to `argCheck' (string expected, got %s)", type(kind)) |
| 107 end | 108 end |
| 108 local errored = false | 109 local errored = false |
| 109 arg = type(arg) | 110 arg = type(arg) |
| 110 if arg ~= kind and arg ~= kind2 and arg ~= kind3 and arg ~= kind4 and arg ~= kind5 then | 111 if arg ~= kind and arg ~= kind2 and arg ~= kind3 and arg ~= kind4 and arg ~= kind5 then |
| 111 local _,_,func = string.find(debugstack(), "`argCheck'.-([`<].-['>])") | 112 local stack = debugstack() |
| 113 local _,_,func = stack:find("`argCheck'.-([`<].-['>])") | |
| 112 if not func then | 114 if not func then |
| 113 _,_,func = string.find(debugstack(), "([`<].-['>])") | 115 _,_,func = stack:find("([`<].-['>])") |
| 114 end | 116 end |
| 115 if kind5 then | 117 if kind5 then |
| 116 return 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) | 118 return 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) |
| 117 elseif kind4 then | 119 elseif kind4 then |
| 118 return 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) | 120 return 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) |
| 128 | 130 |
| 129 local pcall | 131 local pcall |
| 130 do | 132 do |
| 131 local function check(self, ret, ...) | 133 local function check(self, ret, ...) |
| 132 if not ret then | 134 if not ret then |
| 133 return error(self, (string.gsub(..., ".-%.lua:%d-: ", ""))) | 135 local s = ... |
| 136 return error(self, (s:gsub(".-%.lua:%d-: ", ""))) | |
| 134 else | 137 else |
| 135 return ... | 138 return ... |
| 136 end | 139 end |
| 137 end | 140 end |
| 138 | 141 |
| 162 end | 165 end |
| 163 end | 166 end |
| 164 | 167 |
| 165 local function svnRevisionToNumber(text) | 168 local function svnRevisionToNumber(text) |
| 166 if type(text) == "string" then | 169 if type(text) == "string" then |
| 167 if string.find(text, "^%$Revision: (%d+) %$$") then | 170 if text:find("^%$Revision: (%d+) %$$") then |
| 168 return tonumber((string.gsub(text, "^%$Revision: (%d+) %$$", "%1"))) | 171 return tonumber((text:gsub("^%$Revision: (%d+) %$$", "%1"))) |
| 169 elseif string.find(text, "^%$Rev: (%d+) %$$") then | 172 elseif text:find("^%$Rev: (%d+) %$$") then |
| 170 return tonumber((string.gsub(text, "^%$Rev: (%d+) %$$", "%1"))) | 173 return tonumber((text:gsub("^%$Rev: (%d+) %$$", "%1"))) |
| 171 elseif string.find(text, "^%$LastChangedRevision: (%d+) %$$") then | 174 elseif text:find("^%$LastChangedRevision: (%d+) %$$") then |
| 172 return tonumber((string.gsub(text, "^%$LastChangedRevision: (%d+) %$$", "%1"))) | 175 return tonumber((text:gsub("^%$LastChangedRevision: (%d+) %$$", "%1"))) |
| 173 end | 176 end |
| 174 elseif type(text) == "number" then | 177 elseif type(text) == "number" then |
| 175 return text | 178 return text |
| 176 end | 179 end |
| 177 return nil | 180 return nil |
| 365 if type(minor) == "string" then | 368 if type(minor) == "string" then |
| 366 local m = svnRevisionToNumber(minor) | 369 local m = svnRevisionToNumber(minor) |
| 367 if m then | 370 if m then |
| 368 minor = m | 371 minor = m |
| 369 else | 372 else |
| 370 _G.error(string.format("Bad argument #3 to `IsNewVersion'. Must be a number or SVN revision string. %q is not appropriate", minor), 2) | 373 _G.error(("Bad argument #3 to `IsNewVersion'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2) |
| 371 end | 374 end |
| 372 end | 375 end |
| 373 argCheck(self, minor, 3, "number") | 376 argCheck(self, minor, 3, "number") |
| 374 local data = self.libs[major] | 377 local data = self.libs[major] |
| 375 if not data then | 378 if not data then |
| 391 if type(minor) == "string" then | 394 if type(minor) == "string" then |
| 392 local m = svnRevisionToNumber(minor) | 395 local m = svnRevisionToNumber(minor) |
| 393 if m then | 396 if m then |
| 394 minor = m | 397 minor = m |
| 395 else | 398 else |
| 396 _G.error(string.format("Bad argument #3 to `HasInstance'. Must be a number or SVN revision string. %q is not appropriate", minor), 2) | 399 _G.error(("Bad argument #3 to `HasInstance'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2) |
| 397 end | 400 end |
| 398 end | 401 end |
| 399 argCheck(self, minor, 3, "number") | 402 argCheck(self, minor, 3, "number") |
| 400 if not self.libs[major] then | 403 if not self.libs[major] then |
| 401 return | 404 return |
| 414 argCheck(self, major, 2, "string") | 417 argCheck(self, major, 2, "string") |
| 415 TryToLoadStandalone(major) | 418 TryToLoadStandalone(major) |
| 416 | 419 |
| 417 local data = self.libs[major] | 420 local data = self.libs[major] |
| 418 if not data then | 421 if not data then |
| 419 _G.error(string.format("Cannot find a library instance of %s.", major), 2) | 422 _G.error(("Cannot find a library instance of %s."):format(major), 2) |
| 420 return | 423 return |
| 421 end | 424 end |
| 422 if minor then | 425 if minor then |
| 423 if type(minor) == "string" then | 426 if type(minor) == "string" then |
| 424 local m = svnRevisionToNumber(minor) | 427 local m = svnRevisionToNumber(minor) |
| 425 if m then | 428 if m then |
| 426 minor = m | 429 minor = m |
| 427 else | 430 else |
| 428 _G.error(string.format("Bad argument #3 to `GetInstance'. Must be a number or SVN revision string. %q is not appropriate", minor), 2) | 431 _G.error(("Bad argument #3 to `GetInstance'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2) |
| 429 end | 432 end |
| 430 end | 433 end |
| 431 argCheck(self, minor, 2, "number") | 434 argCheck(self, minor, 2, "number") |
| 432 if data.minor ~= minor then | 435 if data.minor ~= minor then |
| 433 _G.error(string.format("Cannot find a library instance of %s, minor version %d.", major, minor), 2) | 436 _G.error(("Cannot find a library instance of %s, minor version %d."):format(major, minor), 2) |
| 434 end | 437 end |
| 435 end | 438 end |
| 436 return data.instance | 439 return data.instance |
| 437 end | 440 end |
| 438 | 441 |
| 461 argCheck(self, newInstance, 2, "table") | 464 argCheck(self, newInstance, 2, "table") |
| 462 argCheck(self, major, 3, "string") | 465 argCheck(self, major, 3, "string") |
| 463 if major ~= ACELIBRARY_MAJOR then | 466 if major ~= ACELIBRARY_MAJOR then |
| 464 for k,v in pairs(_G) do | 467 for k,v in pairs(_G) do |
| 465 if v == newInstance then | 468 if v == newInstance then |
| 466 geterrorhandler()(string.format("Cannot register library %q. It is part of the global table in _G[%q].", major, k)) | 469 geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k)) |
| 467 end | 470 end |
| 468 end | 471 end |
| 469 end | 472 end |
| 470 if major ~= ACELIBRARY_MAJOR and not string.find(major, "^[%a%-][%a%d%-]+[%a%-]%-%d+%.%d+$") and not string.find(major, "^[%a%-]+%-%d+%.%d+$") then | 473 if major ~= ACELIBRARY_MAJOR and not major:find("^[%a%-][%a%d%-]*%-%d+%.%d+$") then |
| 471 _G.error(string.format("Bad argument #3 to `Register'. Must be in the form of \"Name-1.0\". %q is not appropriate", major), 2) | 474 _G.error(string.format("Bad argument #3 to `Register'. Must be in the form of \"Name-1.0\". %q is not appropriate", major), 2) |
| 472 end | 475 end |
| 473 if type(minor) == "string" then | 476 if type(minor) == "string" then |
| 474 local m = svnRevisionToNumber(minor) | 477 local m = svnRevisionToNumber(minor) |
| 475 if m then | 478 if m then |
| 476 minor = m | 479 minor = m |
| 477 else | 480 else |
| 478 _G.error(string.format("Bad argument #4 to `Register'. Must be a number or SVN revision string. %q is not appropriate", minor), 2) | 481 _G.error(("Bad argument #4 to `Register'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2) |
| 479 end | 482 end |
| 480 end | 483 end |
| 481 argCheck(self, minor, 4, "number") | 484 argCheck(self, minor, 4, "number") |
| 482 if math.floor(minor) ~= minor or minor < 0 then | 485 if math.floor(minor) ~= minor or minor < 0 then |
| 483 error(self, "Bad argument #4 to `Register' (integer >= 0 expected, got %s)", minor) | 486 error(self, "Bad argument #4 to `Register' (integer >= 0 expected, got %s)", minor) |
| 524 safecall(activateFunc, instance, nil, nil) -- no old version, so explicit nil | 527 safecall(activateFunc, instance, nil, nil) -- no old version, so explicit nil |
| 525 | 528 |
| 526 --[[ if major ~= ACELIBRARY_MAJOR then | 529 --[[ if major ~= ACELIBRARY_MAJOR then |
| 527 for k,v in pairs(_G) do | 530 for k,v in pairs(_G) do |
| 528 if v == instance then | 531 if v == instance then |
| 529 geterrorhandler()(string.format("Cannot register library %q. It is part of the global table in _G[%q].", major, k)) | 532 geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k)) |
| 530 end | 533 end |
| 531 end | 534 end |
| 532 end]] | 535 end]] |
| 533 end | 536 end |
| 534 | 537 |
| 555 return instance | 558 return instance |
| 556 end | 559 end |
| 557 local instance = data.instance | 560 local instance = data.instance |
| 558 if minor <= data.minor then | 561 if minor <= data.minor then |
| 559 -- This one is already obsolete, raise an error. | 562 -- This one is already obsolete, raise an error. |
| 560 _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) | 563 _G.error(("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"):format(major, data.minor, minor, major, minor), 2) |
| 561 return | 564 return |
| 562 end | 565 end |
| 563 -- This is an update | 566 -- This is an update |
| 564 local oldInstance = {} | 567 local oldInstance = {} |
| 565 | 568 |
| 621 end | 624 end |
| 622 end | 625 end |
| 623 if activateFunc then | 626 if activateFunc then |
| 624 safecall(activateFunc, instance, oldInstance, oldDeactivateFunc) | 627 safecall(activateFunc, instance, oldInstance, oldDeactivateFunc) |
| 625 | 628 |
| 626 if major ~= ACELIBRARY_MAJOR then | 629 --[[ if major ~= ACELIBRARY_MAJOR then |
| 627 for k,v in pairs(_G) do | 630 for k,v in pairs(_G) do |
| 628 if v == instance then | 631 if v == instance then |
| 629 geterrorhandler()(string.format("Cannot register library %q. It is part of the global table in _G[%q].", major, k)) | 632 geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k)) |
| 630 end | 633 end |
| 631 end | 634 end |
| 632 end | 635 end]] |
| 633 else | 636 else |
| 634 safecall(oldDeactivateFunc, oldInstance) | 637 safecall(oldDeactivateFunc, oldInstance) |
| 635 end | 638 end |
| 636 oldInstance = nil | 639 oldInstance = nil |
| 637 | 640 |
