From f39eeeeb80cef82fc65e805946f4b4b8a9c8e4de Mon Sep 17 00:00:00 2001 From: James Whitehead II Date: Thu, 11 Jan 2007 02:43:53 +0000 Subject: [PATCH] Updated to Dongle-Beta0 --- Dongle.lua | 264 +++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 172 insertions(+), 92 deletions(-) diff --git a/Dongle.lua b/Dongle.lua index 321fb22..a3a9b48 100644 --- a/Dongle.lua +++ b/Dongle.lua @@ -28,8 +28,8 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------]] -local major = "DongleStub" -local minor = tonumber(string.match("$Revision: 173 $", "(%d+)") or 1) +local major = "DongleStub-Beta0" +local minor = tonumber(string.match("$Revision: 221 $", "(%d+)") or 1) local g = getfenv(0) @@ -37,7 +37,7 @@ if not g.DongleStub or g.DongleStub:IsNewerVersion(major, minor) then local lib = setmetatable({}, { __call = function(t,k) if type(t.versions) == "table" and t.versions[k] then - return t.versions[k] + return t.versions[k].instance else error("Cannot find a library with name '"..tostring(k).."'", 2) end @@ -45,60 +45,92 @@ if not g.DongleStub or g.DongleStub:IsNewerVersion(major, minor) then }) function lib:IsNewerVersion(major, minor) - local entry = self.versions and self.versions[major] + local versionData = self.versions and self.versions[major] - if not entry then return true end - local oldmajor,oldminor = entry:GetVersion() + if not versionData then return true end + local oldmajor,oldminor = versionData.instance:GetVersion() return minor > oldminor end - function lib:Register(new) - local major,minor = new:GetVersion() + local function NilCopyTable(src, dest) + for k,v in pairs(dest) do dest[k] = nil end + for k,v in pairs(src) do dest[k] = v end + end + + function lib:Register(newInstance, activate, deactivate) + local major,minor = newInstance:GetVersion() if not self:IsNewerVersion(major, minor) then return false end - local old = self.versions and self.versions[major] - -- Run the new libraries activation - if type(new.Activate) == "function" then - new:Activate(old) + if not self.versions then self.versions = {} end + + local versionData = self.versions[major] + if not versionData then + -- New major version + versionData = { + ["instance"] = newInstance, + ["deactivate"] = deactivate, + } + + self.versions[major] = versionData + if type(activate) == "function" then + activate(newInstance) + end + return newInstance end + local oldDeactivate = versionData.deactivate + local oldInstance = versionData.instance + + versionData.deactivate = deactivate + + local skipCopy + if type(activate) == "function" then + skipCopy = activate(newInstance, oldInstance) + end + -- Deactivate the old libary if necessary - if old and type(old.Deactivate) == "function" then - old:Deactivate(new) + if type(oldDeactivate) == "function" then + oldDeactivate(oldInstance, newInstance) end - - self.versions[major] = new + + -- Re-use the old table, and discard the new one + if not skipCopy then + NilCopyTable(newInstance, oldInstance) + end + return oldInstance end function lib:GetVersion() return major,minor end - function lib:Activate(old) - if old then - self.versions = old.versions - else - self.versions = {} + local function Activate(new, old) + if old then + new.versions = old.versions end - g.DongleStub = self + g.DongleStub = new end -- Actually trigger libary activation here local stub = g.DongleStub or lib - stub:Register(lib) + stub:Register(lib, Activate) end --[[------------------------------------------------------------------------- Begin Library Implementation ---------------------------------------------------------------------------]] -local major = "Dongle" -local minor = tonumber(string.match("$Revision: 194 $", "(%d+)") or 1) +local major = "Dongle-Beta0" +local minor = tonumber(string.match("$Revision: 224 $", "(%d+)") or 1) + +assert(DongleStub, string.format("Dongle requires DongleStub.", major)) +assert(DongleStub and DongleStub:GetVersion() == "DongleStub-Beta0", + string.format("Dongle requires DongleStub-Beta0. You are using an older version.", major)) -assert(DongleStub, string.format("%s requires DongleStub.", major)) if not DongleStub:IsNewerVersion(major, minor) then return end -Dongle = {} +local Dongle = {} local methods = { - "RegisterEvent", "UnregisterEvent", "UnregisterAllEvents", "TriggerEvent", + "RegisterEvent", "UnregisterEvent", "UnregisterAllEvents", + "RegisterMessage", "UnregisterMessage", "UnregisterAllMessages", "TriggerMessage", "EnableDebug", "Print", "PrintF", "Debug", "DebugF", "InitializeDB", "InitializeSlashCommand", @@ -112,6 +144,8 @@ local loadorder = {} local events = {} local databases = {} local commands = {} +local messages = {} + local frame local function assert(level,condition,message) @@ -193,24 +227,25 @@ function Dongle:HasModule(module) return reg.modules[module] end -local NIL_FUNC = function() end +local function ModuleIterator(t, name) + if not t then return end + local module + repeat + name,module = next(t, name) + until type(name) == "string" or not name + + if not name then return end + return name, module +end function Dongle:IterateModules() local reg = lookup[self] assert(3, reg, "You must call 'IterateModules' from a registered Dongle.") - - if not reg.modules or not next(reg.modules) then return NIL_FUNC end - local i=1 - return function() - local name = reg.modules[i] - if not name then return end - i = i + 1 - return name, reg.modules[name] - end + return ModuleIterator, reg.modules end -function Dongle:ADDON_LOADED(event, ...) +local function ADDON_LOADED(event, ...) for i=1, #loadqueue do local obj = loadqueue[i] table.insert(loadorder, obj) @@ -219,48 +254,42 @@ function Dongle:ADDON_LOADED(event, ...) safecall(obj.Initialize, obj) end - if self.initialized and type(obj.Enable) == "function" then + if Dongle.initialized and type(obj.Enable) == "function" then safecall(obj.Enable, obj) end loadqueue[i] = nil end end -function Dongle:PLAYER_LOGIN() - self.initialized = true - for i,obj in ipairs(loadorder) do - if type(obj.Enable) == "function" then - safecall(obj.Enable, obj) +local function PLAYER_LOGOUT(event) + self:ClearDBDefaults() + for k,v in pairs(registry) do + local obj = v.obj + if type(obj["Disable"]) == "function" then + safecall(obj["Disable"], obj) end end end -function Dongle:TriggerEvent(event, ...) - argcheck(event, 2, "string") - local eventTbl = events[event] - if eventTbl then - for obj,func in pairs(eventTbl) do - if type(func) == "string" then - if type(obj[func]) == "function" then - safecall(obj[func], obj, event, ...) - end - else - safecall(func,event,...) - end +local function PLAYER_LOGIN() + Dongle.initialized = true + for i,obj in ipairs(loadorder) do + if type(obj.Enable) == "function" then + safecall(obj.Enable, obj) end end end -function Dongle:OnEvent(frame, event, ...) +local function OnEvent(frame, event, ...) local eventTbl = events[event] if eventTbl then for obj,func in pairs(eventTbl) do if type(func) == "string" then if type(obj[func]) == "function" then - obj[func](obj, event, ...) + safecall(obj[func], obj, event, ...) end else - func(event, ...) + safecall(func, event, ...) end end end @@ -308,21 +337,57 @@ function Dongle:UnregisterAllEvents() end end -function Dongle:AdminEvents(event) - local method - if event == "PLAYER_LOGOUT" then - Dongle:ClearDBDefaults() - method = "Disable" - elseif event == "PLAYER_REGEN_DISABLED" then - method = "CombatLockdown" - elseif event == "PLAYER_REGEN_ENABLED" then - method = "CombatUnlock" +function Dongle:RegisterMessage(msg, func) + local reg = lookup[self] + assert(3, reg, "You must call 'RegisterMessage' from a registered Dongle.") + argcheck(msg, 2, "string") + argcheck(func, 3, "string", "function", "nil") + + -- Name the method the same as the event if necessary + if not func then func = msg end + + if not messages[msg] then + messages[msg] = {} end + messages[msg][self] = func +end - if method then - for k,v in pairs(registry) do - local obj = v.obj - if obj[method] then obj[method](obj) end +function Dongle:UnregisterMessage(msg) + local reg = lookup[self] + assert(3, reg, "You must call 'UnregisterMessage' from a registered Dongle.") + argcheck(msg, 2, "string") + + if messages[msg] then + messages[msg][self] = nil + if not next(messages[msg]) then + messages[msg] = nil + end + end +end + +function Dongle:UnregisterAllMessages() + assert(3, lookup[self], "You must call 'UnregisterAllMessages' from a registered Dongle.") + + for msg,tbl in pairs(messages) do + tbl[self] = nil + if not next(tbl) then + messages[msg] = nil + end + end +end + +function Dongle:TriggerMessage(msg, ...) + argcheck(msg, 2, "string") + local msgTbl = messages[msg] + if not msgTbl then return end + + for obj,func in pairs(msgTbl) do + if type(func) == "string" then + if type(obj[func]) == "function" then + safecall(obj[func], obj, msg, ...) + end + else + safecall(func, msg, ...) end end end @@ -497,7 +562,7 @@ function Dongle:InitializeDB(name, defaults, defaultProfile) local db,profileCreated = initdb(self, name, defaults, defaultProfile) if profileCreated then - Dongle:TriggerEvent("DONGLE_PROFILE_CREATED", db, self, db.sv_name, db.profileKey) + Dongle:TriggerMessage("DONGLE_PROFILE_CREATED", db, self, db.sv_name, db.profileKey) end return db end @@ -603,10 +668,10 @@ function Dongle.SetProfile(db, name) db.profileKey = name if profileCreated then - Dongle:TriggerEvent("DONGLE_PROFILE_CREATED", db, db.parent, db.sv_name, db.profileKey) + Dongle:TriggerMessage("DONGLE_PROFILE_CREATED", db, db.parent, db.sv_name, db.profileKey) end - Dongle:TriggerEvent("DONGLE_PROFILE_CHANGED", db, db.parent, db.sv_name, db.profileKey) + Dongle:TriggerMessage("DONGLE_PROFILE_CHANGED", db, db.parent, db.sv_name, db.profileKey) end function Dongle.GetProfiles(db, t) @@ -631,7 +696,7 @@ function Dongle.DeleteProfile(db, name) end db.sv.profiles[name] = nil - Dongle:TriggerEvent("DONGLE_PROFILE_DELETED", db, db.parent, db.sv_name, name) + Dongle:TriggerMessage("DONGLE_PROFILE_DELETED", db, db.parent, db.sv_name, name) end function Dongle.CopyProfile(db, name) @@ -645,7 +710,7 @@ function Dongle.CopyProfile(db, name) local source = db.sv.profiles[name] copyDefaults(profile, source, true) - Dongle:TriggerEvent("DONGLE_PROFILE_COPIED", db, db.parent, db.sv_name, name, db.profileKey) + Dongle:TriggerMessage("DONGLE_PROFILE_COPIED", db, db.parent, db.sv_name, name, db.profileKey) end function Dongle.ResetProfile(db) @@ -659,7 +724,7 @@ function Dongle.ResetProfile(db) if db.defaults and db.defaults.profile then copyDefaults(profile, db.defaults.profile) end - Dongle:TriggerEvent("DONGLE_PROFILE_RESET", db, db.parent, db.sv_name, db.profileKey) + Dongle:TriggerMessage("DONGLE_PROFILE_RESET", db, db.parent, db.sv_name, db.profileKey) end @@ -675,9 +740,9 @@ function Dongle.ResetDB(db, defaultProfile) local parent = db.parent initdb(parent, db.sv_name, db.defaults, defaultProfile, db) - Dongle:TriggerEvent("DONGLE_DATABASE_RESET", db, parent, db.sv_name, db.profileKey) - Dongle:TriggerEvent("DONGLE_PROFILE_CREATED", db, db.parent, db.sv_name, db.profileKey) - Dongle:TriggerEvent("DONGLE_PROFILE_CHANGED", db, db.parent, db.sv_name, db.profileKey) + Dongle:TriggerMessage("DONGLE_DATABASE_RESET", db, parent, db.sv_name, db.profileKey) + Dongle:TriggerMessage("DONGLE_PROFILE_CREATED", db, db.parent, db.sv_name, db.profileKey) + Dongle:TriggerMessage("DONGLE_PROFILE_CHANGED", db, db.parent, db.sv_name, db.profileKey) return db end @@ -693,7 +758,7 @@ local function OnSlashCommand(cmd, cmd_line) if type(tbl.handler) == "string" then cmd.parent[tbl.handler](cmd.parent, string.match(cmd_line, pattern)) else - tbl.handler(cmd.parent, string.match(cmd_line, pattern)) + tbl.handler(string.match(cmd_line, pattern)) end return end @@ -728,10 +793,15 @@ function Dongle:InitializeSlashCommand(desc, name, ...) end genv.SlashCmdList[name] = function(...) OnSlashCommand(cmd, ...) end + + commands[cmd] = true + return cmd end function Dongle.RegisterSlashHandler(cmd, desc, pattern, handler) + assert(3, commands[cmd], "You must call 'RegisterSlashHandler' from a Dongle slash command object.") + argcheck(desc, 2, "string") argcheck(pattern, 3, "string") argcheck(handler, 4, "function", "string") @@ -746,6 +816,8 @@ function Dongle.RegisterSlashHandler(cmd, desc, pattern, handler) end function Dongle.PrintUsage(cmd) + assert(3, commands[cmd], "You must call 'PrintUsage' from a Dongle slash command object.") + local usage = cmd.desc.."\n".."/"..table.concat(cmd.slashes, ", /")..":\n" if cmd.patterns then local descs = {} @@ -766,7 +838,7 @@ end function Dongle:GetVersion() return major,minor end -function Dongle:Activate(old) +local function Activate(self, old) if old then self.registry = old.registry or registry self.lookup = old.lookup or lookup @@ -775,6 +847,7 @@ function Dongle:Activate(old) self.events = old.events or events self.databases = old.databases or databases self.commands = old.commands or commands + self.messages = old.messages or messages registry = self.registry lookup = self.lookup @@ -783,6 +856,7 @@ function Dongle:Activate(old) events = self.events databases = self.databases commands = self.commands + messages = self.messages frame = old.frame self.registry[major].obj = self @@ -794,6 +868,7 @@ function Dongle:Activate(old) self.events = events self.databases = databases self.commands = commands + self.messages = messages local reg = {obj = self, name = "Dongle"} registry[major] = reg @@ -806,14 +881,12 @@ function Dongle:Activate(old) end self.frame = frame - frame:SetScript("OnEvent", function(...) self:OnEvent(...) end) + frame:SetScript("OnEvent", OnEvent) -- Register for events using Dongle itself - self:RegisterEvent("ADDON_LOADED") - self:RegisterEvent("PLAYER_LOGIN") - self:RegisterEvent("PLAYER_LOGOUT", "AdminEvents") - self:RegisterEvent("PLAYER_REGEN_ENABLED", "AdminEvents") - self:RegisterEvent("PLAYER_REGEN_DISABLED", "AdminEvents") + self:RegisterEvent("ADDON_LOADED", ADDON_LOADED) + self:RegisterEvent("PLAYER_LOGIN", PLAYER_LOGIN) + self:RegisterEvent("PLAYER_LOGOUT", PLAYER_LOGOUT) -- Convert all the modules handles for name,obj in pairs(registry) do @@ -828,11 +901,18 @@ function Dongle:Activate(old) db[method] = self[method] end end + + -- Convert all slash command methods + for cmd in pairs(commands) do + for idx,method in ipairs(slashCmdMethods) do + cmd[method] = self[method] + end + end end -function Dongle:Deactivate(new) +local function Deactivate(self, new) lookup[self] = nil self:UnregisterAllEvents() end -DongleStub:Register(Dongle) +DongleStub:Register(Dongle, Activate, Deactivate) -- 1.7.9.5