Doing Tricks Without Lua Method Notation
From WoWWiki
Lua has a trick for creating something that acts a little bit like Java classes, and a little less like C procedures. This can be used at various places to create simple, elegant bits of code that do precisely what you want. But you can also do these same tricks without method notation.
Tricks
Trick #1: OnEvent Handling
We can have our OnEvent handler redirect the event call to an appropriate routine.
function MyAddonOnEvent(event, ...)
local fcn = getglobal('MyAddon_' .. event);
if (type(fcn) == 'function') then
fcn(event, ...);
else
MyAddonLog("Unhandled event: ", event);
end
end
function MyAddon_PLAYER_ENTERING_WORLD(event, ...)
...
end
function MyAddon_PLAYER_LEAVING_WORLD(event, ...)
...
end
function MyAddonOnLoad()
this:RegisterEvent('PLAYER_ENTERING_WORLD');
this:RegisterEvent('PLAYER_LEAVING_WORLD');
end
Let's see how this plays out. The xml script contains
<OnEvent>MyAddonOnEvent(event,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9)</OnEvent>
so when a PLAYER_ENTERING_WORLD event is generated, it calls MyAddonOnEvent, and calls it as a function, with arguments event and arg1 through arg9. When MyAddonOnEvent receives the call, it tries to see if there's a global variable of the form MyAddon_PLAYER_ENTERING_WORLD, and if it's a function, calls it. It passes event as the first arg. The '...' tells Lua to pass on any additional args that the function got origionaly and pass it to the function "MyAddon_PLAYER_ENTERING_WORLD", so this is just a fancy way to pass arg1 to arg2 on down. So control passes to MyAddon_PLAYER_ENTERING_WORLD.
This may seem rather messy if you're only catching two or three events, but if you're catching 5 or 10, it avoids the huge sawtooth if-then-elseif mess if checking all the events.
Trick #2: Code Reuse
There are lots of ways to get code reuse, including using method notation. But method notation is not necessary. We can also use a closure. One twin goals are to have a single set of procedures underneath, with a little bit of customization available, as needed. For our example, let's assume that we have several packages that want to do a bit of logging or sending of messages to the chat frame, but each package will use a different color for its message, and a different prefix (i.e. the package name) when logging.
Here are the functions that are permanent and fixed. We'll only ever create one copy of these. In a real setting, they might be much larger and more complex, and call subfunctions themselves.
local function Utils_Log(r, g, b, prefix, ...)
self:Msg(prefix, ...);
end
local function Utils_Msg(r, g, b, prefix, ...)
local line = ' ';
for i=1, select('#', ...) do
line = line .. tostring(select(i, ...));
end
local chatFrame = DEFAULT_CHAT_FRAME or error('No chat frame found');
chatFrame:AddMessage(line, self.logR, self.logG, self.logB);
end
Note: select() calls single out variables with in the "..." pass. Calling select('#',...) returns the number of variables in the '...', and replacing it with a number returns that numbered arg.
We will use another function to create functions which inject the parameters, in this case the prefix and the color.
Utils_CreateLogMsgFunctions(prefix, r, g, b)
prefix = prefix or ' '; --Set prefix to if nil
r,g,b = r or 0.5,g or 0.5,b or 0.5; --Each defaults to 0.5
local function log(...)
Utils_Log(r, g, b, prefix, ...);
end
local function msg(...)
Utils_Msg(r, g, b, prefix, ...);
end
return log,msg;
end
--Create Utils' Log and Msg fcns, with grey color
Utils_Log,Utils_Msg = Utils_CreateLogMsgFunctions('Utils0.8: ', 0.5, 0.5, 0.5);
function Utils_OnLoad()
Utils_Log('Loaded.');
end
Assuming a chat frame was there when the addon loaded, there would be a gray load message put into the chat frame.
But if we have two or three other addons that want logging, then. For example, in MyFirstAddon,lua we might have
MyFirstAddonLog,MyFirstAddonMsg = Utils_CreateLogMsgFunctions('Hyper Addon 0.8: ', 1, 0, 0);
function MyFirstAddon:OnLoad()
MyFirstAddonLog('Loaded.');
end
When this addon loads there will be a bright red chat line announcing 'Hyper Addon 0.8: Loaded.'
What's happening here? There is only one copy of Utils_Log and Utils_Msg in the address space, but Utils_CreateLogMsgFunctions creates pairs of delegate functions which contain the prefixes and colors unique to each application. (This is possible because the delegate functions, although small, retain a link to the surrounding frame, from which they can extract the prefix and r,g,b when needed.)
(Still under construction.)
