Merge branch 'master' of git://cams.pavlovian.net/questhelper
[QuestHelper.git] / AstrolabeQH / DongleStub.lua
blob099416447e92e4ed97d13dfb7bbabfd89191df29
1 --[[------------------------------------------------------------------
2 -- $Id: DongleStub.lua 466 2007-06-23 19:17:46Z jnwhiteh $
3 --
4 -- DongleStub is a simple versioning stub that allows different
5 -- major versions of a library to exist alongside each other, while
6 -- providing a mechanism for library upgrades through minor version
7 -- differences.
8 --
9 -- The implementation of DongleStub, including the source code,
10 -- documentation and related data, is placed into the public domain.
12 -- The original author is James N. Whitehead II
14 -- THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND, NOT
15 -- EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR OF THIS
16 -- SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY CONSEQUENCE RESULTING
17 -- FROM THE USE, MODIFICATION, OR REDISTRIBUTION OF THIS SOFTWARE.
18 ------------------------------------------------------------------]]--
20 local major = "DongleStub"
21 local minor = tonumber(string.match("$Revision: 466 $", "(%d+)") or 1)
23 local g = getfenv(0)
25 if not g.DongleStub or g.DongleStub:IsNewerVersion(major, minor) then
26 local lib = setmetatable({}, {
27 __call = function(t,k)
28 if type(t.versions) == "table" and t.versions[k] then
29 return t.versions[k].instance
30 else
31 error("Cannot find a library with name '"..tostring(k).."'", 2)
32 end
33 end
36 function lib:HasVersion(major)
37 if type(major) ~= "string" then
38 error("bad argument #2 to 'HasVersion' (string expected, got " .. type(major) .. ")", 2)
39 end
41 local instance = self.versions and self.versions[major]
42 return instance ~= nil
43 end
45 function lib:IsNewerVersion(major, minor)
46 local versionData = self.versions and self.versions[major]
47 if not versionData then return true end
48 local oldmajor,oldminor = versionData.instance:GetVersion()
49 return minor > oldminor
50 end
52 local function NilCopyTable(src, dest)
53 for k,v in pairs(dest) do dest[k] = nil end
54 for k,v in pairs(src) do dest[k] = v end
55 end
57 function lib:Register(newInstance, activate, deactivate)
58 if type(newInstance) ~= "table" then
59 error("bad argument #2 to 'Register' (table expected, got " .. type(newInstance) .. ")", 2)
60 end
62 if type(newInstance.GetVersion) ~= "function" then
63 error("Attempt to register a library with DongleStub that does not have a 'GetVersion' method.", 2)
64 end
66 local major,minor = newInstance:GetVersion()
67 if type(major) ~= "string" then
68 error("Attempt to register a library with DongleStub that does not have a proper major version.", 2)
69 end
71 if type(minor) ~= "number" then
72 error("Attempt to register a library with DongleStub that does not have a proper minor version.", 2)
73 end
75 -- Generate a log of all library registrations
76 if not self.log then self.log = {} end
77 table.insert(self.log, string.format("Register: %s, %s", major, minor))
79 if not self:IsNewerVersion(major, minor) then return false end
80 if not self.versions then self.versions = {} end
82 local versionData = self.versions[major]
83 if not versionData then
84 -- New major version
85 versionData = {
86 ["instance"] = newInstance,
87 ["deactivate"] = deactivate,
90 self.versions[major] = versionData
91 if type(activate) == "function" then
92 table.insert(self.log, string.format("Activate: %s, %s", major, minor))
93 activate(newInstance)
94 end
95 return newInstance
96 end
98 local oldDeactivate = versionData.deactivate
99 local oldInstance = versionData.instance
101 versionData.deactivate = deactivate
103 local skipCopy
104 if type(activate) == "function" then
105 table.insert(self.log, string.format("Activate: %s, %s", major, minor))
106 skipCopy = activate(newInstance, oldInstance)
109 -- Deactivate the old libary if necessary
110 if type(oldDeactivate) == "function" then
111 local major, minor = oldInstance:GetVersion()
112 table.insert(self.log, string.format("Deactivate: %s, %s", major, minor))
113 oldDeactivate(oldInstance, newInstance)
116 -- Re-use the old table, and discard the new one
117 if not skipCopy then
118 NilCopyTable(newInstance, oldInstance)
120 return oldInstance
123 function lib:GetVersion() return major,minor end
125 local function Activate(new, old)
126 -- This code ensures that we'll move the versions table even
127 -- if the major version names are different, in the case of
128 -- DongleStub
129 if not old then old = g.DongleStub end
131 if old then
132 new.versions = old.versions
133 new.log = old.log
135 g.DongleStub = new
138 -- Actually trigger libary activation here
139 local stub = g.DongleStub or lib
140 lib = stub:Register(lib, Activate)