AceLibrary Tutorial
From WowAce Wiki
Note: for full API documentation, see AceLibrary API Documentation
Contents |
Libraries
Generally speaking, libraries should have certain characteristics:
- They should encapsulate code that promotes code reuse. Don't write libraries that only one addon will ever use.
- They should be as efficient as possible. More than one addon will be using your library, don't bog them down with unnecessary function calls, table usage, etc. If you put out a badly coded library, you're not just inconveniencing yourself, but everyone else who uses the library, and their users.
Before you dive into writing a library, ask yourself:
- Will this library ever be used by anything else?
- Am I writing this library for the sake of a library? Will I be better off just adding it as a common code file in my addon without incurring the extra overhead the library call will make?
The Ace philosophy has always been about small, efficient code. About addons that do what they are specced to do and do it well without unnecessary bloat. Memory efficient, CPU efficient code. Always keep that in mind when writing libraries to be used with the Ace Framework.
Creating the library
Libraries are traditionally one lua file in a folder which is self-contained. It may require other libraries as dependencies, but should not require whole addons.
Header
To start off your library, you'd make a lua file. For this tutorial, I'll be calling it Monkey-1.0.
In this file (Monkey-1.0.lua), you would start off with the Library Header.
--[[ Name: Monkey-1.0 Revision: $Rev: 1 $ Author(s): John Doe (jdoe@gmail.com) Website: http://www.wowace.com/ Documentation: http://wiki.wowace.com/index.php/Monkey-1.0_API_Documentation SVN: http://svn.wowace.com/root/trunk/Monkey/Monkey-1.0/ Description: Library that can act an awful lot like a monkey Dependencies: AceLibrary ]]
The SVN part can point to your own SVN server if you want. If you don't have an SVN server or an SVN account with wowace. For more info, see What is the SVN?
For libraries, you should have some sort of documentation. Feel free to get a wiki account and add a page for your project.
Notice how the Revision is wrapped in the funny "$Rev: 1 $" thing. That is an svn:keyword. It will automatically update every time you commit your file to an SVN.
Version
local MAJOR_VERSION = "Monkey-1.0" local MINOR_VERSION = "$Revision: 1 $"
This will set you up so you can easily refer to these variables later when registering and such.
Your major version is the name of your library, in the form of "Name-#.#". Although it can technically be any string you want, this is the standard form. Your major version should match the name of the file and folder your library is in.
Your minor version will increase with every release. The simplest thing to do is have it be a revision string, that increases with every commit. This can either be a revision string in the form of "$Revision: ### $" or just an integer.
Check for AceLibrary
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end
This makes sure that AceLibrary is properly loaded and ready to go. If not, it raises an error that makes sense.
Check for obscelesence
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
This checks to see if the current major and minor versions are either already out-of-date or already registered. If this is the case it returns out of the file, saving valuable CPU cycles and memory.
Localization/Internationalization (optional)
You should (optionally) do your localizations here. By having it as close to the top as possible, you make it easy on your translators. Feel free to use AceLocale-2.0 or use your own method to do your translations.
Here, I will use a haphazard way to do my own localizations:
local TEXT_MONKEY
if GetLocale() == "deDE" then
TEXT_MONKEY = "Affe"
else -- enUS
TEXT_MONKEY = "Monkey"
end
Create the library object
local Monkey = {}
Difficult, I know. You'll get the hang of it.
Note: If you were to use AceOO and want this to be a mixin or class or an instance, you'd have no trouble registering that instead of just a simple table.
Methods
Here all your assorted methods for your library can be defined.
Let's define some monkey-esque methods now.
function Monkey:FlingPoop()
self.poopFlung = self.poopFlung 1
DEFAULT_CHAT_FRAME:AddMessage(string.format("You have had poop flung at you %d times.", self.poopFlung))
end
function Monkey:GroomOther()
DEFAULT_CHAT_FRAME:AddMessage("You see one monkey groom another monkey")
end
function Monkey:EatBanana()
local totalBananas = (time() - self.startTime) / (60 * 5)
-- you get 1 banana every 5 minutes
local currentBananas = totalBananas - self.bananasEaten
if currentBananas >= 1 then
self.bananasEaten = self.bananasEaten 1
DEFAULT_CHAT_FRAME:AddMessage("The monkey eats a banana. Yum")
return true
else
DEFAULT_CHAT_FRAME:AddMessage("The monkey looks sad, like it wants a banana but has none")
return false
end
end
Gotta love them monkeys. They're like little people (unless you're from Kentucky, where they're just monkeys and nothing else).
Activation function
local function activate(self, oldLib, oldDeactivate)
if oldLib then -- if upgrading
self.bananasEaten = oldLib.bananasEaten
self.poopFlung = oldLib.poopFlung
self.startTime = oldLib.startTime
end
-- make sure all the basic values are available
if not self.bananasEaten then
self.bananasEaten = 0
end
if not self.poopFlung then
self.poopFlung = 0
end
if not self.startTime then
self.startTime = time()
end
if oldDeactivate then -- clean up the old library
oldDeactivate(oldLib)
end
end
The activation function is important, as it is called whenever your library updates itself or is initially registered. Your values should go in this place.
Registration
AceLibrary:Register(Monkey, MAJOR_VERSION, MINOR_VERSION, activate) Monkey = nil
This registers your Monkey table with AceLibrary, to be accessed through MAJOR_VERSION, which is "Monkey-1.0". This will also cause activate to be called, with the appropriate arguments fed into it.
Note: you could also supply a deactivate function, but it's typically not needed.
Registration with AceLibrary destroys the contents of the table registered as a safety measure, thus it is in your best interest to just nil out the table, letting garbage collection take its course. Alternatively, you could do Monkey = AceLibrary (MAJOR_VERSION) to get the proper library into the Monkey reference, also causing the garbage collection to occur.
Done
Feel free to run your tests, commit to SVN, talk about it on IRC, release it on the wowace forums, and/or release to your favorite Addon site.
Using the library
Firstly, you should copy the library folder to your addon's folder. Alternatively, you could set up an svn:external to the folder, which would automatically update whenever the author updates his library.
In the TOC
In your TOC, be sure to add the following lines to the top of your files:
AceLibrary\AceLibrary.lua Monkey-1.0\Monkey-1.0.lua
In the LUA
In your .lua file, somewhere near the top, put
local monkey = AceLibrary("Monkey-1.0")
Now you have a reference to the Monkey-1.0 library, all fine and dandy.
Note: you do not need to call it monkey, you can call it whatever you want (even baboon).
Using the library's methods
if not monkey:EatBanana() then
monkey:FlingPoop()
end
Hooray, now when that code is run, if the monkey eats a banana, it'll be content, if not, it'll do its admirable duty and fling poop.

