Quantcast Doing Tricks Without Lua Method Notation - WoWWiki - Your guide to the World of Warcraft
Recent changes Random page
GAMING
Gaming
 
StarCraft Wiki
Super Smash Wiki
Halopedia
Diablo Wiki
FFXIclopedia
Grand Theft Wiki
See more...

Doing Tricks Without Lua Method Notation

From WoWWiki

Jump to: navigation, search

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.)

Rate this article:
Share this article: