AceLibrary Tutorial

From WowAce Wiki
Jump to: navigation, search

Note: for full API documentation, see AceLibrary API Documentation


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.


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


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:

if GetLocale() == "deDE" then
    TEXT_MONKEY = "Affe"
else -- enUS
    TEXT_MONKEY = "Monkey"

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.


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

function Monkey:GroomOther()
    DEFAULT_CHAT_FRAME:AddMessage("You see one monkey groom another monkey")

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
        DEFAULT_CHAT_FRAME:AddMessage("The monkey looks sad, like it wants a banana but has none")
        return false

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

    -- make sure all the basic values are available
    if not self.bananasEaten then
        self.bananasEaten = 0
    if not self.poopFlung then
        self.poopFlung = 0
    if not self.startTime then
        self.startTime = time()

    if oldDeactivate then -- clean up the old library

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.


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.


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:


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

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.