annotate lib/AceOO-2.0/AceOO-2.0.lua @ 24:9e1984088124

added *more* missing files from 1.0 dev tree...
author Flick <flickerstreak@gmail.com>
date Fri, 07 Mar 2008 22:18:23 +0000
parents 1b9323256a1b
children
rev   line source
flickerstreak@1 1 --[[
flickerstreak@1 2 Name: AceOO-2.0
flickerstreak@22 3 Revision: $Rev: 38641 $
flickerstreak@1 4 Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
flickerstreak@1 5 Inspired By: Ace 1.x by Turan (turan@gryphon.com)
flickerstreak@1 6 Website: http://www.wowace.com/
flickerstreak@1 7 Documentation: http://www.wowace.com/index.php/AceOO-2.0
flickerstreak@1 8 SVN: http://svn.wowace.com/root/trunk/Ace2/AceOO-2.0
flickerstreak@1 9 Description: Library to provide an object-orientation framework.
flickerstreak@1 10 Dependencies: AceLibrary
flickerstreak@22 11 License: MIT
flickerstreak@1 12 ]]
flickerstreak@1 13
flickerstreak@1 14 local MAJOR_VERSION = "AceOO-2.0"
flickerstreak@22 15 local MINOR_VERSION = "$Revision: 38641 $"
flickerstreak@1 16
flickerstreak@1 17 -- This ensures the code is only executed if the libary doesn't already exist, or is a newer version
flickerstreak@1 18 if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end
flickerstreak@1 19 if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
flickerstreak@1 20
flickerstreak@1 21 local AceOO = {
flickerstreak@1 22 error = AceLibrary.error,
flickerstreak@1 23 argCheck = AceLibrary.argCheck
flickerstreak@1 24 }
flickerstreak@1 25
flickerstreak@1 26 -- @function getuid
flickerstreak@1 27 -- @brief Obtain a unique string identifier for the object in question.
flickerstreak@1 28 -- @param t The object to obtain the uid for.
flickerstreak@1 29 -- @return The uid string.
flickerstreak@1 30 local function getuid(t)
flickerstreak@1 31 local mt = getmetatable(t)
flickerstreak@1 32 setmetatable(t, nil)
flickerstreak@1 33 local str = tostring(t)
flickerstreak@1 34 setmetatable(t, mt)
flickerstreak@22 35 local cap = str:match("[^:]*: 0x(.*)$") or str:match("[^:]*: (.*)$")
flickerstreak@22 36 if cap then
flickerstreak@22 37 return ("0"):rep(8 - #cap) .. cap
flickerstreak@22 38 end
flickerstreak@1 39 end
flickerstreak@1 40
flickerstreak@1 41 local function getlibrary(o)
flickerstreak@1 42 if type(o) == "table" then
flickerstreak@1 43 return o
flickerstreak@1 44 elseif type(o) == "string" then
flickerstreak@1 45 if not AceLibrary:HasInstance(o) then
flickerstreak@1 46 AceOO:error("Library %q does not exist.", o)
flickerstreak@1 47 end
flickerstreak@1 48 return AceLibrary(o)
flickerstreak@1 49 end
flickerstreak@1 50 end
flickerstreak@1 51
flickerstreak@22 52 local function deeprawget(self, k)
flickerstreak@22 53 while true do
flickerstreak@22 54 local v = rawget(self, k)
flickerstreak@22 55 if v ~= nil then
flickerstreak@22 56 return v
flickerstreak@22 57 end
flickerstreak@22 58 local mt = getmetatable(self)
flickerstreak@22 59 if not mt or type(mt.__index) ~= "table" then
flickerstreak@22 60 return nil
flickerstreak@22 61 end
flickerstreak@22 62 self = mt.__index
flickerstreak@22 63 end
flickerstreak@22 64 end
flickerstreak@22 65
flickerstreak@1 66 -- @function Factory
flickerstreak@1 67 -- @brief Construct a factory for the creation of objects.
flickerstreak@1 68 -- @param obj The object whose init method will be called on the new factory
flickerstreak@1 69 -- object.
flickerstreak@1 70 -- @param newobj The object whose init method will be called on the new
flickerstreak@1 71 -- objects that the Factory creates, to initialize them.
flickerstreak@1 72 -- @param (...) Arguments which will be passed to obj.init() in addition
flickerstreak@1 73 -- to the Factory object.
flickerstreak@1 74 -- @return The new factory which creates a newobj when its new method is called,
flickerstreak@1 75 -- or when it is called directly (__call metamethod).
flickerstreak@1 76 local Factory
flickerstreak@1 77 do
flickerstreak@22 78 local function getlibraries(...)
flickerstreak@22 79 if select('#', ...) == 0 then
flickerstreak@22 80 return
flickerstreak@22 81 end
flickerstreak@22 82 return getlibrary((select(1, ...))), getlibraries(select(2, ...))
flickerstreak@22 83 end
flickerstreak@1 84 local arg = {}
flickerstreak@1 85 local function new(obj, ...)
flickerstreak@1 86 local t = {}
flickerstreak@1 87 local uid = getuid(t)
flickerstreak@22 88 obj:init(t, getlibraries(...))
flickerstreak@1 89 t.uid = uid
flickerstreak@1 90 return t
flickerstreak@1 91 end
flickerstreak@1 92
flickerstreak@1 93 local function createnew(self, ...)
flickerstreak@1 94 local o = self.prototype
flickerstreak@22 95 local x = new(o, getlibraries(...))
flickerstreak@1 96 return x
flickerstreak@1 97 end
flickerstreak@1 98
flickerstreak@1 99 function Factory(obj, newobj, ...)
flickerstreak@1 100 local t = new(obj, ...)
flickerstreak@1 101 t.prototype = newobj
flickerstreak@1 102 t.new = createnew
flickerstreak@1 103 getmetatable(t).__call = t.new
flickerstreak@1 104 return t
flickerstreak@1 105 end
flickerstreak@1 106 end
flickerstreak@1 107
flickerstreak@1 108
flickerstreak@1 109 local function objtostring(self)
flickerstreak@1 110 if self.ToString then
flickerstreak@1 111 return self:ToString()
flickerstreak@1 112 elseif self.GetLibraryVersion then
flickerstreak@1 113 return (self:GetLibraryVersion())
flickerstreak@1 114 elseif self.super then
flickerstreak@1 115 local s = "Sub-" .. tostring(self.super)
flickerstreak@1 116 local first = true
flickerstreak@1 117 if self.interfaces then
flickerstreak@1 118 for interface in pairs(self.interfaces) do
flickerstreak@1 119 if first then
flickerstreak@1 120 s = s .. "(" .. tostring(interface)
flickerstreak@1 121 first = false
flickerstreak@1 122 else
flickerstreak@1 123 s = s .. ", " .. tostring(interface)
flickerstreak@1 124 end
flickerstreak@1 125 end
flickerstreak@1 126 end
flickerstreak@1 127 if self.mixins then
flickerstreak@1 128 for mixin in pairs(self.mixins) do
flickerstreak@1 129 if first then
flickerstreak@1 130 s = s .. tostring(mixin)
flickerstreak@1 131 first = false
flickerstreak@1 132 else
flickerstreak@1 133 s = s .. ", " .. tostring(mixin)
flickerstreak@1 134 end
flickerstreak@1 135 end
flickerstreak@1 136 end
flickerstreak@1 137 if first then
flickerstreak@1 138 if self.uid then
flickerstreak@1 139 return s .. ":" .. self.uid
flickerstreak@1 140 else
flickerstreak@1 141 return s
flickerstreak@1 142 end
flickerstreak@1 143 else
flickerstreak@1 144 return s .. ")"
flickerstreak@1 145 end
flickerstreak@1 146 else
flickerstreak@1 147 return self.uid and 'Subclass:' .. self.uid or 'Subclass'
flickerstreak@1 148 end
flickerstreak@1 149 end
flickerstreak@1 150
flickerstreak@1 151 -- @table Object
flickerstreak@1 152 -- @brief Base of all objects, including Class.
flickerstreak@1 153 --
flickerstreak@1 154 -- @method init
flickerstreak@1 155 -- @brief Initialize a new object.
flickerstreak@1 156 -- @param newobject The object to initialize
flickerstreak@1 157 -- @param class The class to make newobject inherit from
flickerstreak@1 158 local Object
flickerstreak@1 159 do
flickerstreak@1 160 Object = {}
flickerstreak@1 161 function Object:init(newobject, class)
flickerstreak@1 162 local parent = class or self
flickerstreak@1 163 if not rawget(newobject, 'uid') then
flickerstreak@1 164 newobject.uid = getuid(newobject)
flickerstreak@1 165 end
flickerstreak@1 166 local mt = {
flickerstreak@1 167 __index = parent,
flickerstreak@1 168 __tostring = objtostring,
flickerstreak@1 169 }
flickerstreak@1 170 setmetatable(newobject, mt)
flickerstreak@1 171 end
flickerstreak@1 172 Object.uid = getuid(Object)
flickerstreak@1 173 setmetatable(Object, { __tostring = function() return 'Object' end })
flickerstreak@1 174 end
flickerstreak@1 175
flickerstreak@1 176 local Interface
flickerstreak@1 177
flickerstreak@1 178 local function validateInterface(object, interface)
flickerstreak@1 179 if not object.class and object.prototype then
flickerstreak@1 180 object = object.prototype
flickerstreak@1 181 end
flickerstreak@1 182 for k,v in pairs(interface.interface) do
flickerstreak@1 183 if tostring(type(object[k])) ~= v then
flickerstreak@1 184 return false
flickerstreak@1 185 end
flickerstreak@1 186 end
flickerstreak@1 187 if interface.superinterfaces then
flickerstreak@1 188 for superinterface in pairs(interface.superinterfaces) do
flickerstreak@1 189 if not validateInterface(object, superinterface) then
flickerstreak@1 190 return false
flickerstreak@1 191 end
flickerstreak@1 192 end
flickerstreak@1 193 end
flickerstreak@1 194 if type(object.class) == "table" and rawequal(object.class.prototype, object) then
flickerstreak@1 195 if not object.class.interfaces then
flickerstreak@1 196 rawset(object.class, 'interfaces', {})
flickerstreak@1 197 end
flickerstreak@1 198 object.class.interfaces[interface] = true
flickerstreak@1 199 elseif type(object.class) == "table" and type(object.class.prototype) == "table" then
flickerstreak@1 200 validateInterface(object.class.prototype, interface)
flickerstreak@1 201 -- check if class is proper, thus preventing future checks.
flickerstreak@1 202 end
flickerstreak@1 203 return true
flickerstreak@1 204 end
flickerstreak@1 205
flickerstreak@1 206 -- @function inherits
flickerstreak@1 207 -- @brief Return whether an Object or Class inherits from a given
flickerstreak@1 208 -- parent.
flickerstreak@1 209 -- @param object Object or Class to check
flickerstreak@1 210 -- @param parent Parent to test inheritance from
flickerstreak@1 211 -- @return whether an Object or Class inherits from a given
flickerstreak@1 212 -- parent.
flickerstreak@1 213 local function inherits(object, parent)
flickerstreak@1 214 object = getlibrary(object)
flickerstreak@1 215 if type(parent) == "string" then
flickerstreak@1 216 if not AceLibrary:HasInstance(parent) then
flickerstreak@1 217 return false
flickerstreak@1 218 else
flickerstreak@1 219 parent = AceLibrary(parent)
flickerstreak@1 220 end
flickerstreak@1 221 end
flickerstreak@1 222 AceOO:argCheck(parent, 2, "table")
flickerstreak@1 223 if type(object) ~= "table" then
flickerstreak@1 224 return false
flickerstreak@1 225 end
flickerstreak@1 226 local current
flickerstreak@22 227 local class = deeprawget(object, 'class')
flickerstreak@22 228 if class then
flickerstreak@22 229 current = class
flickerstreak@1 230 else
flickerstreak@1 231 current = object
flickerstreak@1 232 end
flickerstreak@1 233 if type(current) ~= "table" then
flickerstreak@1 234 return false
flickerstreak@1 235 end
flickerstreak@1 236 if rawequal(current, parent) then
flickerstreak@1 237 return true
flickerstreak@1 238 end
flickerstreak@1 239 if parent.class then
flickerstreak@1 240 while true do
flickerstreak@1 241 if rawequal(current, Object) then
flickerstreak@1 242 break
flickerstreak@1 243 end
flickerstreak@1 244 if current.mixins then
flickerstreak@1 245 for mixin in pairs(current.mixins) do
flickerstreak@1 246 if rawequal(mixin, parent) then
flickerstreak@1 247 return true
flickerstreak@1 248 end
flickerstreak@1 249 end
flickerstreak@1 250 end
flickerstreak@1 251 if current.interfaces then
flickerstreak@1 252 for interface in pairs(current.interfaces) do
flickerstreak@1 253 if rawequal(interface, parent) then
flickerstreak@1 254 return true
flickerstreak@1 255 end
flickerstreak@1 256 end
flickerstreak@1 257 end
flickerstreak@22 258 current = deeprawget(current, 'super')
flickerstreak@1 259 if type(current) ~= "table" then
flickerstreak@1 260 break
flickerstreak@1 261 end
flickerstreak@1 262 end
flickerstreak@1 263
flickerstreak@1 264 local isInterface = false
flickerstreak@1 265 local curr = parent.class
flickerstreak@1 266 while true do
flickerstreak@1 267 if rawequal(curr, Object) then
flickerstreak@1 268 break
flickerstreak@1 269 elseif rawequal(curr, Interface) then
flickerstreak@1 270 isInterface = true
flickerstreak@1 271 break
flickerstreak@1 272 end
flickerstreak@22 273 curr = deeprawget(curr, 'super')
flickerstreak@1 274 if type(curr) ~= "table" then
flickerstreak@1 275 break
flickerstreak@1 276 end
flickerstreak@1 277 end
flickerstreak@1 278 return isInterface and validateInterface(object, parent)
flickerstreak@1 279 else
flickerstreak@1 280 while true do
flickerstreak@1 281 if rawequal(current, parent) then
flickerstreak@1 282 return true
flickerstreak@1 283 elseif rawequal(current, Object) then
flickerstreak@1 284 return false
flickerstreak@1 285 end
flickerstreak@22 286 current = deeprawget(current, 'super')
flickerstreak@1 287 if type(current) ~= "table" then
flickerstreak@1 288 return false
flickerstreak@1 289 end
flickerstreak@1 290 end
flickerstreak@1 291 end
flickerstreak@1 292 end
flickerstreak@1 293
flickerstreak@1 294 -- @table Class
flickerstreak@1 295 -- @brief An object factory which sets up inheritence and supports
flickerstreak@1 296 -- 'mixins'.
flickerstreak@1 297 --
flickerstreak@1 298 -- @metamethod Class call
flickerstreak@1 299 -- @brief Call ClassFactory:new() to create a new class.
flickerstreak@1 300 --
flickerstreak@1 301 -- @method Class new
flickerstreak@1 302 -- @brief Construct a new object.
flickerstreak@1 303 -- @param (...) Arguments to pass to the object init function.
flickerstreak@1 304 -- @return The new object.
flickerstreak@1 305 --
flickerstreak@1 306 -- @method Class init
flickerstreak@1 307 -- @brief Initialize a new class.
flickerstreak@1 308 -- @param parent Superclass.
flickerstreak@1 309 -- @param (...) Mixins.
flickerstreak@1 310 --
flickerstreak@1 311 -- @method Class ToString
flickerstreak@1 312 -- @return A string representing the object, in this case 'Class'.
flickerstreak@1 313 local initStatus
flickerstreak@1 314 local Class
flickerstreak@1 315 local Mixin
flickerstreak@1 316 local autoEmbed = false
flickerstreak@1 317 local function traverseInterfaces(bit, total)
flickerstreak@1 318 if bit.superinterfaces then
flickerstreak@1 319 for interface in pairs(bit.superinterfaces) do
flickerstreak@1 320 if not total[interface] then
flickerstreak@1 321 total[interface] = true
flickerstreak@1 322 traverseInterfaces(interface, total)
flickerstreak@1 323 end
flickerstreak@1 324 end
flickerstreak@1 325 end
flickerstreak@1 326 end
flickerstreak@1 327 local class_new
flickerstreak@1 328 do
flickerstreak@1 329 Class = Factory(Object, setmetatable({}, {__index = Object}), Object)
flickerstreak@1 330 Class.super = Object
flickerstreak@1 331
flickerstreak@1 332 local function protostring(t)
flickerstreak@1 333 return '<' .. tostring(t.class) .. ' prototype>'
flickerstreak@1 334 end
flickerstreak@1 335 local function classobjectstring(t)
flickerstreak@1 336 if t.ToString then
flickerstreak@1 337 return t:ToString()
flickerstreak@1 338 elseif t.GetLibraryVersion then
flickerstreak@1 339 return (t:GetLibraryVersion())
flickerstreak@1 340 else
flickerstreak@1 341 return '<' .. tostring(t.class) .. ' instance>'
flickerstreak@1 342 end
flickerstreak@1 343 end
flickerstreak@1 344 local function classobjectequal(self, other)
flickerstreak@1 345 if type(self) == "table" and self.Equals then
flickerstreak@1 346 return self:Equals(other)
flickerstreak@1 347 elseif type(other) == "table" and other.Equals then
flickerstreak@1 348 return other:Equals(self)
flickerstreak@1 349 elseif type(self) == "table" and self.CompareTo then
flickerstreak@1 350 return self:CompareTo(other) == 0
flickerstreak@1 351 elseif type(other) == "table" and other.CompareTo then
flickerstreak@1 352 return other:CompareTo(self) == 0
flickerstreak@1 353 else
flickerstreak@1 354 return rawequal(self, other)
flickerstreak@1 355 end
flickerstreak@1 356 end
flickerstreak@1 357 local function classobjectlessthan(self, other)
flickerstreak@1 358 if type(self) == "table" and self.IsLessThan then
flickerstreak@1 359 return self:IsLessThan(other)
flickerstreak@1 360 elseif type(other) == "table" and other.IsLessThanOrEqualTo then
flickerstreak@1 361 return not other:IsLessThanOrEqualTo(self)
flickerstreak@1 362 elseif type(self) == "table" and self.CompareTo then
flickerstreak@1 363 return self:CompareTo(other) < 0
flickerstreak@1 364 elseif type(other) == "table" and other.CompareTo then
flickerstreak@1 365 return other:CompareTo(self) > 0
flickerstreak@1 366 elseif type(other) == "table" and other.IsLessThan and other.Equals then
flickerstreak@1 367 return other:Equals(self) or other:IsLessThan(self)
flickerstreak@1 368 else
flickerstreak@1 369 AceOO:error("cannot compare two objects")
flickerstreak@1 370 end
flickerstreak@1 371 end
flickerstreak@1 372 local function classobjectlessthanequal(self, other)
flickerstreak@1 373 if type(self) == "table" and self.IsLessThanOrEqualTo then
flickerstreak@1 374 return self:IsLessThanOrEqualTo(other)
flickerstreak@1 375 elseif type(other) == "table" and other.IsLessThan then
flickerstreak@1 376 return not other:IsLessThan(self)
flickerstreak@1 377 elseif type(self) == "table" and self.CompareTo then
flickerstreak@1 378 return self:CompareTo(other) <= 0
flickerstreak@1 379 elseif type(other) == "table" and other.CompareTo then
flickerstreak@1 380 return other:CompareTo(self) >= 0
flickerstreak@1 381 elseif type(self) == "table" and self.IsLessThan and self.Equals then
flickerstreak@1 382 return self:Equals(other) or self:IsLessThan(other)
flickerstreak@1 383 else
flickerstreak@1 384 AceOO:error("cannot compare two incompatible objects")
flickerstreak@1 385 end
flickerstreak@1 386 end
flickerstreak@1 387 local function classobjectadd(self, other)
flickerstreak@1 388 if type(self) == "table" and self.Add then
flickerstreak@1 389 return self:Add(other)
flickerstreak@1 390 else
flickerstreak@1 391 AceOO:error("cannot add two incompatible objects")
flickerstreak@1 392 end
flickerstreak@1 393 end
flickerstreak@1 394 local function classobjectsub(self, other)
flickerstreak@1 395 if type(self) == "table" and self.Subtract then
flickerstreak@1 396 return self:Subtract(other)
flickerstreak@1 397 else
flickerstreak@1 398 AceOO:error("cannot subtract two incompatible objects")
flickerstreak@1 399 end
flickerstreak@1 400 end
flickerstreak@1 401 local function classobjectunm(self, other)
flickerstreak@1 402 if type(self) == "table" and self.UnaryNegation then
flickerstreak@1 403 return self:UnaryNegation(other)
flickerstreak@1 404 else
flickerstreak@1 405 AceOO:error("attempt to negate an incompatible object")
flickerstreak@1 406 end
flickerstreak@1 407 end
flickerstreak@1 408 local function classobjectmul(self, other)
flickerstreak@1 409 if type(self) == "table" and self.Multiply then
flickerstreak@1 410 return self:Multiply(other)
flickerstreak@1 411 else
flickerstreak@1 412 AceOO:error("cannot multiply two incompatible objects")
flickerstreak@1 413 end
flickerstreak@1 414 end
flickerstreak@1 415 local function classobjectdiv(self, other)
flickerstreak@1 416 if type(self) == "table" and self.Divide then
flickerstreak@1 417 return self:Divide(other)
flickerstreak@1 418 else
flickerstreak@1 419 AceOO:error("cannot divide two incompatible objects")
flickerstreak@1 420 end
flickerstreak@1 421 end
flickerstreak@1 422 local function classobjectpow(self, other)
flickerstreak@1 423 if type(self) == "table" and self.Exponent then
flickerstreak@1 424 return self:Exponent(other)
flickerstreak@1 425 else
flickerstreak@1 426 AceOO:error("cannot exponentiate two incompatible objects")
flickerstreak@1 427 end
flickerstreak@1 428 end
flickerstreak@1 429 local function classobjectconcat(self, other)
flickerstreak@1 430 if type(self) == "table" and self.Concatenate then
flickerstreak@1 431 return self:Concatenate(other)
flickerstreak@1 432 else
flickerstreak@1 433 AceOO:error("cannot concatenate two incompatible objects")
flickerstreak@1 434 end
flickerstreak@1 435 end
flickerstreak@1 436 function class_new(self, ...)
flickerstreak@1 437 if self.virtual then
flickerstreak@1 438 AceOO:error("Cannot instantiate a virtual class.")
flickerstreak@1 439 end
flickerstreak@1 440
flickerstreak@1 441 local o = self.prototype
flickerstreak@1 442 local newobj = {}
flickerstreak@1 443 if o.class and o.class.instancemeta then
flickerstreak@1 444 setmetatable(newobj, o.class.instancemeta)
flickerstreak@1 445 else
flickerstreak@1 446 Object:init(newobj, o)
flickerstreak@1 447 end
flickerstreak@1 448
flickerstreak@1 449 if self.interfaces and not self.interfacesVerified then
flickerstreak@1 450 -- Verify the interfaces
flickerstreak@1 451
flickerstreak@1 452 for interface in pairs(self.interfaces) do
flickerstreak@1 453 for field,kind in pairs(interface.interface) do
flickerstreak@1 454 if tostring(type(newobj[field])) ~= kind then
flickerstreak@1 455 AceOO:error("Class did not satisfy all interfaces. %q is required to be a %s. It is a %s", field, kind, tostring(type(newobj[field])))
flickerstreak@1 456 end
flickerstreak@1 457 end
flickerstreak@1 458 end
flickerstreak@1 459 self.interfacesVerified = true
flickerstreak@1 460 end
flickerstreak@1 461 local tmp = initStatus
flickerstreak@1 462 initStatus = newobj
flickerstreak@1 463 newobj:init(...)
flickerstreak@1 464 if initStatus then
flickerstreak@1 465 initStatus = tmp
flickerstreak@1 466 AceOO:error("Initialization not completed, be sure to call the superclass's init method.")
flickerstreak@1 467 return
flickerstreak@1 468 end
flickerstreak@1 469 initStatus = tmp
flickerstreak@1 470 return newobj
flickerstreak@1 471 end
flickerstreak@1 472 local classmeta = {
flickerstreak@1 473 __tostring = objtostring,
flickerstreak@1 474 __call = function(self, ...)
flickerstreak@1 475 return self:new(...)
flickerstreak@1 476 end,
flickerstreak@1 477 }
flickerstreak@1 478 function Class:init(newclass, parent, ...)
flickerstreak@1 479 parent = parent or self
flickerstreak@1 480
flickerstreak@1 481 local total
flickerstreak@1 482
flickerstreak@1 483 if parent.class then
flickerstreak@1 484 total = { parent, ... }
flickerstreak@1 485 parent = self
flickerstreak@1 486 else
flickerstreak@1 487 total = { ... }
flickerstreak@1 488 end
flickerstreak@1 489 if not inherits(parent, Class) then
flickerstreak@1 490 AceOO:error("Classes must inherit from a proper class")
flickerstreak@1 491 end
flickerstreak@1 492 if parent.sealed then
flickerstreak@1 493 AceOO:error("Cannot inherit from a sealed class")
flickerstreak@1 494 end
flickerstreak@1 495 for i,v in ipairs(total) do
flickerstreak@1 496 if inherits(v, Mixin) and v.class then
flickerstreak@1 497 if v.__deprecated then
flickerstreak@1 498 AceOO:error(v.__deprecated)
flickerstreak@1 499 end
flickerstreak@1 500 if not newclass.mixins then
flickerstreak@1 501 newclass.mixins = {}
flickerstreak@1 502 end
flickerstreak@1 503 if newclass.mixins[v] then
flickerstreak@1 504 AceOO:error("Cannot explicitly inherit from the same mixin twice")
flickerstreak@1 505 end
flickerstreak@1 506 newclass.mixins[v] = true
flickerstreak@1 507 elseif inherits(v, Interface) and v.class then
flickerstreak@1 508 if not newclass.interfaces then
flickerstreak@1 509 newclass.interfaces = {}
flickerstreak@1 510 end
flickerstreak@1 511 if newclass.interfaces[v] then
flickerstreak@1 512 AceOO:error("Cannot explicitly inherit from the same interface twice")
flickerstreak@1 513 end
flickerstreak@1 514 newclass.interfaces[v] = true
flickerstreak@1 515 else
flickerstreak@1 516 AceOO:error("Classes can only inherit from one or zero classes and any number of mixins or interfaces")
flickerstreak@1 517 end
flickerstreak@1 518 end
flickerstreak@1 519 if parent.interfaces then
flickerstreak@1 520 if not newclass.interfaces then
flickerstreak@1 521 newclass.interfaces = {}
flickerstreak@1 522 end
flickerstreak@1 523 for interface in pairs(parent.interfaces) do
flickerstreak@1 524 newclass.interfaces[interface] = true
flickerstreak@1 525 end
flickerstreak@1 526 end
flickerstreak@1 527 for k in pairs(total) do
flickerstreak@1 528 total[k] = nil
flickerstreak@1 529 end
flickerstreak@1 530
flickerstreak@1 531 newclass.super = parent
flickerstreak@1 532
flickerstreak@1 533 newclass.prototype = setmetatable(total, {
flickerstreak@1 534 __index = parent.prototype,
flickerstreak@1 535 __tostring = protostring,
flickerstreak@1 536 })
flickerstreak@1 537 total = nil
flickerstreak@1 538
flickerstreak@1 539 newclass.instancemeta = {
flickerstreak@1 540 __index = newclass.prototype,
flickerstreak@1 541 __tostring = classobjectstring,
flickerstreak@1 542 __eq = classobjectequal,
flickerstreak@1 543 __lt = classobjectlessthan,
flickerstreak@1 544 __le = classobjectlessthanequal,
flickerstreak@1 545 __add = classobjectadd,
flickerstreak@1 546 __sub = classobjectsub,
flickerstreak@1 547 __unm = classobjectunm,
flickerstreak@1 548 __mul = classobjectmul,
flickerstreak@1 549 __div = classobjectdiv,
flickerstreak@1 550 __pow = classobjectpow,
flickerstreak@1 551 __concat = classobjectconcat,
flickerstreak@1 552 }
flickerstreak@1 553
flickerstreak@1 554 setmetatable(newclass, classmeta)
flickerstreak@1 555
flickerstreak@1 556 newclass.new = class_new
flickerstreak@1 557
flickerstreak@1 558 if newclass.mixins then
flickerstreak@1 559 -- Fold in the mixins
flickerstreak@1 560 local err, msg
flickerstreak@1 561 for mixin in pairs(newclass.mixins) do
flickerstreak@1 562 local ret
flickerstreak@1 563 autoEmbed = true
flickerstreak@1 564 ret, msg = pcall(mixin.embed, mixin, newclass.prototype)
flickerstreak@1 565 autoEmbed = false
flickerstreak@1 566 if not ret then
flickerstreak@1 567 err = true
flickerstreak@1 568 break
flickerstreak@1 569 end
flickerstreak@1 570 end
flickerstreak@1 571
flickerstreak@1 572 if err then
flickerstreak@1 573 local pt = newclass.prototype
flickerstreak@1 574 for k,v in pairs(pt) do
flickerstreak@1 575 pt[k] = nil
flickerstreak@1 576 end
flickerstreak@1 577
flickerstreak@1 578 -- method conflict
flickerstreak@1 579 AceOO:error(msg)
flickerstreak@1 580 end
flickerstreak@1 581 end
flickerstreak@1 582
flickerstreak@1 583 newclass.prototype.class = newclass
flickerstreak@1 584
flickerstreak@1 585 if newclass.interfaces then
flickerstreak@1 586 for interface in pairs(newclass.interfaces) do
flickerstreak@1 587 traverseInterfaces(interface, newclass.interfaces)
flickerstreak@1 588 end
flickerstreak@1 589 end
flickerstreak@1 590 if newclass.mixins then
flickerstreak@1 591 for mixin in pairs(newclass.mixins) do
flickerstreak@1 592 if mixin.interfaces then
flickerstreak@1 593 if not newclass.interfaces then
flickerstreak@1 594 newclass.interfaces = {}
flickerstreak@1 595 end
flickerstreak@1 596 for interface in pairs(mixin.interfaces) do
flickerstreak@1 597 newclass.interfaces[interface] = true
flickerstreak@1 598 end
flickerstreak@1 599 end
flickerstreak@1 600 end
flickerstreak@1 601 end
flickerstreak@1 602 end
flickerstreak@1 603 function Class:ToString()
flickerstreak@1 604 if type(self.GetLibraryVersion) == "function" then
flickerstreak@1 605 return (self:GetLibraryVersion())
flickerstreak@1 606 else
flickerstreak@1 607 return "Class"
flickerstreak@1 608 end
flickerstreak@1 609 end
flickerstreak@1 610
flickerstreak@1 611 local tmp
flickerstreak@1 612 function Class.prototype:init()
flickerstreak@1 613 if rawequal(self, initStatus) then
flickerstreak@1 614 initStatus = nil
flickerstreak@1 615 else
flickerstreak@1 616 AceOO:error("Improper self passed to init. You must do MyClass.super.prototype.init(self, ...)", 2)
flickerstreak@1 617 end
flickerstreak@1 618 self.uid = getuid(self)
flickerstreak@1 619 local current = self.class
flickerstreak@1 620 while true do
flickerstreak@1 621 if current == Class then
flickerstreak@1 622 break
flickerstreak@1 623 end
flickerstreak@1 624 if current.mixins then
flickerstreak@1 625 for mixin in pairs(current.mixins) do
flickerstreak@1 626 if type(mixin.OnInstanceInit) == "function" then
flickerstreak@1 627 mixin:OnInstanceInit(self)
flickerstreak@1 628 end
flickerstreak@1 629 end
flickerstreak@1 630 end
flickerstreak@1 631 current = current.super
flickerstreak@1 632 end
flickerstreak@1 633 end
flickerstreak@1 634 end
flickerstreak@1 635
flickerstreak@1 636
flickerstreak@1 637 -- @object ClassFactory
flickerstreak@1 638 -- @brief A factory for creating classes. Rarely used directly.
flickerstreak@1 639 local ClassFactory = Factory(Object, Class, Object)
flickerstreak@1 640
flickerstreak@1 641 function Class:new(...)
flickerstreak@1 642 local x = ClassFactory:new(...)
flickerstreak@1 643 if AceOO.classes then
flickerstreak@1 644 AceOO.classes[x] = true
flickerstreak@1 645 end
flickerstreak@1 646 return x
flickerstreak@1 647 end
flickerstreak@1 648 getmetatable(Class).__call = Class.new
flickerstreak@1 649
flickerstreak@1 650 -- @class Mixin
flickerstreak@1 651 -- @brief A class to create mixin objects, which contain methods that get
flickerstreak@1 652 -- "mixed in" to class prototypes.
flickerstreak@1 653 --
flickerstreak@1 654 -- @object Mixin prototype
flickerstreak@1 655 -- @brief The prototype that mixin objects inherit their methods from.
flickerstreak@1 656 --
flickerstreak@1 657 -- @method Mixin prototype embed
flickerstreak@1 658 -- @brief Mix in the methods of our object which are listed in our interface
flickerstreak@1 659 -- to the supplied target table.
flickerstreak@1 660 --
flickerstreak@1 661 -- @method Mixin prototype init
flickerstreak@1 662 -- @brief Initialize the mixin object.
flickerstreak@1 663 -- @param newobj The new object we're initializing.
flickerstreak@1 664 -- @param interface The interface we implement (the list of methods our
flickerstreak@1 665 -- prototype provides which should be mixed into the target
flickerstreak@1 666 -- table by embed).
flickerstreak@1 667 do
flickerstreak@1 668 Mixin = Class()
flickerstreak@1 669 function Mixin:ToString()
flickerstreak@1 670 if self.GetLibraryVersion then
flickerstreak@1 671 return (self:GetLibraryVersion())
flickerstreak@1 672 else
flickerstreak@1 673 return 'Mixin'
flickerstreak@1 674 end
flickerstreak@1 675 end
flickerstreak@1 676 local function _Embed(state, field, target)
flickerstreak@1 677 field = next(state.export, field)
flickerstreak@1 678 if field == nil then
flickerstreak@1 679 return
flickerstreak@1 680 end
flickerstreak@1 681
flickerstreak@1 682 if rawget(target, field) or (target[field] and target[field] ~= state[field]) then
flickerstreak@1 683 AceOO:error("Method conflict in attempt to mixin. Field %q", field)
flickerstreak@1 684 end
flickerstreak@1 685
flickerstreak@1 686 target[field] = state[field]
flickerstreak@1 687
flickerstreak@1 688 local ret,msg = pcall(_Embed, state, field, target)
flickerstreak@1 689 if not ret then
flickerstreak@1 690 -- Mix in the next method according to the defined interface. If that
flickerstreak@1 691 -- fails due to a conflict, re-raise to back out the previous mixed
flickerstreak@1 692 -- methods.
flickerstreak@1 693
flickerstreak@1 694 target[field] = nil
flickerstreak@1 695 AceOO:error(msg)
flickerstreak@1 696 end
flickerstreak@1 697 end
flickerstreak@1 698 function Mixin.prototype:embed(target)
flickerstreak@1 699 if self.__deprecated then
flickerstreak@1 700 AceOO:error(self.__deprecated)
flickerstreak@1 701 end
flickerstreak@1 702 local mt = getmetatable(target)
flickerstreak@1 703 setmetatable(target, nil)
flickerstreak@1 704 local err, msg = pcall(_Embed, self, nil, target)
flickerstreak@1 705 if not err then
flickerstreak@1 706 setmetatable(target, mt)
flickerstreak@1 707 AceOO:error(msg)
flickerstreak@1 708 return
flickerstreak@1 709 end
flickerstreak@1 710 if type(self.embedList) == "table" then
flickerstreak@1 711 self.embedList[target] = true
flickerstreak@1 712 end
flickerstreak@1 713 if type(target.class) ~= "table" then
flickerstreak@1 714 target[self] = true
flickerstreak@1 715 end
flickerstreak@1 716 if not autoEmbed and type(self.OnManualEmbed) == "function" then
flickerstreak@1 717 self:OnManualEmbed(target)
flickerstreak@1 718 end
flickerstreak@1 719 setmetatable(target, mt)
flickerstreak@1 720 end
flickerstreak@1 721
flickerstreak@1 722 function Mixin.prototype:activate(oldLib, oldDeactivate)
flickerstreak@1 723 if oldLib and oldLib.embedList then
flickerstreak@1 724 for target in pairs(oldLib.embedList) do
flickerstreak@1 725 local mt = getmetatable(target)
flickerstreak@1 726 setmetatable(target, nil)
flickerstreak@1 727 for field in pairs(oldLib.export) do
flickerstreak@1 728 target[field] = nil
flickerstreak@1 729 end
flickerstreak@1 730 setmetatable(target, mt)
flickerstreak@1 731 end
flickerstreak@1 732 self.embedList = oldLib.embedList
flickerstreak@1 733 for target in pairs(self.embedList) do
flickerstreak@1 734 self:embed(target)
flickerstreak@1 735 end
flickerstreak@1 736 else
flickerstreak@1 737 self.embedList = setmetatable({}, {__mode="k"})
flickerstreak@1 738 end
flickerstreak@1 739 end
flickerstreak@1 740
flickerstreak@1 741 function Mixin.prototype:init(export, ...)
flickerstreak@1 742 AceOO:argCheck(export, 2, "table")
flickerstreak@1 743 for k,v in pairs(export) do
flickerstreak@1 744 if type(k) ~= "number" then
flickerstreak@1 745 AceOO:error("All keys to argument #2 must be numbers.")
flickerstreak@1 746 elseif type(v) ~= "string" then
flickerstreak@1 747 AceOO:error("All values to argument #2 must be strings.")
flickerstreak@1 748 end
flickerstreak@1 749 end
flickerstreak@1 750 local num = #export
flickerstreak@1 751 for i = 1, num do
flickerstreak@1 752 local v = export[i]
flickerstreak@1 753 export[i] = nil
flickerstreak@1 754 export[v] = true
flickerstreak@1 755 end
flickerstreak@1 756
flickerstreak@1 757 local interfaces
flickerstreak@1 758 if select('#', ...) >= 1 then
flickerstreak@1 759 interfaces = { ... }
flickerstreak@1 760 for i,v in ipairs(interfaces) do
flickerstreak@1 761 v = getlibrary(v)
flickerstreak@1 762 interfaces[i] = v
flickerstreak@1 763 if not v.class or not inherits(v, Interface) then
flickerstreak@1 764 AceOO:error("Mixins can inherit only from interfaces")
flickerstreak@1 765 end
flickerstreak@1 766 end
flickerstreak@1 767 local num = #interfaces
flickerstreak@1 768 for i = 1, num do
flickerstreak@1 769 local v = interfaces[i]
flickerstreak@1 770 interfaces[i] = nil
flickerstreak@1 771 interfaces[v] = true
flickerstreak@1 772 end
flickerstreak@1 773 for interface in pairs(interfaces) do
flickerstreak@1 774 traverseInterfaces(interface, interfaces)
flickerstreak@1 775 end
flickerstreak@1 776 for interface in pairs(interfaces) do
flickerstreak@1 777 for field,kind in pairs(interface.interface) do
flickerstreak@1 778 if kind ~= "nil" then
flickerstreak@1 779 local good = false
flickerstreak@1 780 for bit in pairs(export) do
flickerstreak@1 781 if bit == field then
flickerstreak@1 782 good = true
flickerstreak@1 783 break
flickerstreak@1 784 end
flickerstreak@1 785 end
flickerstreak@1 786 if not good then
flickerstreak@1 787 AceOO:error("Mixin does not fully accommodate field %q", field)
flickerstreak@1 788 end
flickerstreak@1 789 end
flickerstreak@1 790 end
flickerstreak@1 791 end
flickerstreak@1 792 end
flickerstreak@1 793 self.super = Mixin.prototype
flickerstreak@1 794 Mixin.super.prototype.init(self)
flickerstreak@1 795 self.export = export
flickerstreak@1 796 self.interfaces = interfaces
flickerstreak@1 797 end
flickerstreak@1 798 end
flickerstreak@1 799
flickerstreak@1 800 -- @class Interface
flickerstreak@1 801 -- @brief A class to create interfaces, which contain contracts that classes
flickerstreak@1 802 -- which inherit from this must comply with.
flickerstreak@1 803 --
flickerstreak@1 804 -- @object Interface prototype
flickerstreak@1 805 -- @brief The prototype that interface objects must adhere to.
flickerstreak@1 806 --
flickerstreak@1 807 -- @method Interface prototype init
flickerstreak@1 808 -- @brief Initialize the mixin object.
flickerstreak@1 809 -- @param interface The interface we contract (the hash of fields forced).
flickerstreak@1 810 -- @param (...) Superinterfaces
flickerstreak@1 811 do
flickerstreak@1 812 Interface = Class()
flickerstreak@1 813 function Interface:ToString()
flickerstreak@1 814 if self.GetLibraryVersion then
flickerstreak@1 815 return (self:GetLibraryVersion())
flickerstreak@1 816 else
flickerstreak@1 817 return 'Instance'
flickerstreak@1 818 end
flickerstreak@1 819 end
flickerstreak@1 820 function Interface.prototype:init(interface, ...)
flickerstreak@1 821 Interface.super.prototype.init(self)
flickerstreak@1 822 AceOO:argCheck(interface, 2, "table")
flickerstreak@1 823 for k,v in pairs(interface) do
flickerstreak@1 824 if type(k) ~= "string" then
flickerstreak@1 825 AceOO:error("All keys to argument #2 must be numbers.")
flickerstreak@1 826 elseif type(v) ~= "string" then
flickerstreak@1 827 AceOO:error("All values to argument #2 must be strings.")
flickerstreak@1 828 elseif v ~= "nil" and v ~= "string" and v ~= "number" and v ~= "table" and v ~= "function" then
flickerstreak@1 829 AceOO:error('All values to argument #2 must either be "nil", "string", "number", "table", or "function".')
flickerstreak@1 830 end
flickerstreak@1 831 end
flickerstreak@1 832 if select('#', ...) >= 1 then
flickerstreak@1 833 self.superinterfaces = { ... }
flickerstreak@1 834 for i,v in ipairs(self.superinterfaces) do
flickerstreak@1 835 v = getlibrary(v)
flickerstreak@1 836 self.superinterfaces[i] = v
flickerstreak@1 837 if not inherits(v, Interface) or not v.class then
flickerstreak@1 838 AceOO:error('Cannot provide a non-Interface to inherit from')
flickerstreak@1 839 end
flickerstreak@1 840 end
flickerstreak@1 841 local num = #self.superinterfaces
flickerstreak@1 842 for i = 1, num do
flickerstreak@1 843 local v = self.superinterfaces[i]
flickerstreak@1 844 self.superinterfaces[i] = nil
flickerstreak@1 845 self.superinterfaces[v] = true
flickerstreak@1 846 end
flickerstreak@1 847 end
flickerstreak@1 848 self.interface = interface
flickerstreak@1 849 end
flickerstreak@1 850 end
flickerstreak@1 851
flickerstreak@1 852 -- @function Classpool
flickerstreak@1 853 -- @brief Obtain a read only class from our pool of classes, indexed by the
flickerstreak@1 854 -- superclass and mixins.
flickerstreak@1 855 -- @param sc The superclass of the class we want.
flickerstreak@1 856 -- @param (m1..m20) Mixins of the class we want's objects.
flickerstreak@1 857 -- @return A read only class from the class pool.
flickerstreak@1 858 local Classpool
flickerstreak@1 859 do
flickerstreak@1 860 local pool = setmetatable({}, {__mode = 'v'})
flickerstreak@1 861 local function newindex(k, v)
flickerstreak@1 862 AceOO:error('Attempt to modify a read-only class.')
flickerstreak@1 863 end
flickerstreak@1 864 local function protonewindex(k, v)
flickerstreak@1 865 AceOO:error('Attempt to modify a read-only class prototype.')
flickerstreak@1 866 end
flickerstreak@1 867 local function ts(bit)
flickerstreak@1 868 if type(bit) ~= "table" then
flickerstreak@1 869 return tostring(bit)
flickerstreak@1 870 elseif getmetatable(bit) and bit.__tostring then
flickerstreak@1 871 return tostring(bit)
flickerstreak@1 872 elseif type(bit.GetLibraryVersion) == "function" then
flickerstreak@1 873 return bit:GetLibraryVersion()
flickerstreak@1 874 else
flickerstreak@1 875 return tostring(bit)
flickerstreak@1 876 end
flickerstreak@1 877 end
flickerstreak@1 878 local t = {}
flickerstreak@1 879 local function getcomplexuid(sc, ...)
flickerstreak@1 880 if sc then
flickerstreak@1 881 if sc.uid then
flickerstreak@1 882 table.insert(t, sc.uid)
flickerstreak@1 883 else
flickerstreak@1 884 AceOO:error("%s is not an appropriate class/mixin", ts(sc))
flickerstreak@1 885 end
flickerstreak@1 886 end
flickerstreak@1 887 for i = 1, select('#', ...) do
flickerstreak@1 888 local m = select(i, ...)
flickerstreak@1 889 if m.uid then
flickerstreak@1 890 table.insert(t, m.uid)
flickerstreak@1 891 else
flickerstreak@1 892 AceOO:error("%s is not an appropriate mixin", ts(m))
flickerstreak@1 893 end
flickerstreak@1 894 end
flickerstreak@1 895 table.sort(t)
flickerstreak@1 896 local uid = table.concat(t, '')
flickerstreak@1 897 local num = #t
flickerstreak@1 898 for i = 1, num do
flickerstreak@1 899 t[i] = nil
flickerstreak@1 900 end
flickerstreak@1 901 return uid
flickerstreak@1 902 end
flickerstreak@1 903 local classmeta
flickerstreak@1 904 local arg = {}
flickerstreak@1 905 function Classpool(superclass, ...)
flickerstreak@1 906 local l = getlibrary
flickerstreak@1 907 superclass = getlibrary(superclass)
flickerstreak@1 908 arg = { ... }
flickerstreak@1 909 for i, v in ipairs(arg) do
flickerstreak@1 910 arg[i] = getlibrary(v)
flickerstreak@1 911 end
flickerstreak@1 912 if superclass then
flickerstreak@1 913 if superclass.class then -- mixin
flickerstreak@1 914 table.insert(arg, 1, superclass)
flickerstreak@1 915 superclass = Class
flickerstreak@1 916 end
flickerstreak@1 917 else
flickerstreak@1 918 superclass = Class
flickerstreak@1 919 end
flickerstreak@1 920 local key = getcomplexuid(superclass, unpack(arg))
flickerstreak@1 921 if not pool[key] then
flickerstreak@1 922 local class = Class(superclass, unpack(arg))
flickerstreak@1 923 if not classmeta then
flickerstreak@1 924 classmeta = {}
flickerstreak@1 925 local mt = getmetatable(class)
flickerstreak@1 926 for k,v in pairs(mt) do
flickerstreak@1 927 classmeta[k] = v
flickerstreak@1 928 end
flickerstreak@1 929 classmeta.__newindex = newindex
flickerstreak@1 930 end
flickerstreak@1 931 -- Prevent the user from adding methods to this class.
flickerstreak@1 932 -- NOTE: I'm not preventing modifications of existing class members,
flickerstreak@1 933 -- but it's likely that only a truly malicious user will be doing so.
flickerstreak@1 934 class.sealed = true
flickerstreak@1 935 setmetatable(class, classmeta)
flickerstreak@1 936 getmetatable(class.prototype).__newindex = protonewindex
flickerstreak@1 937 pool[key] = class
flickerstreak@1 938 end
flickerstreak@1 939 return pool[key]
flickerstreak@1 940 end
flickerstreak@1 941 end
flickerstreak@1 942
flickerstreak@1 943 AceOO.Factory = Factory
flickerstreak@1 944 AceOO.Object = Object
flickerstreak@1 945 AceOO.Class = Class
flickerstreak@1 946 AceOO.Mixin = Mixin
flickerstreak@1 947 AceOO.Interface = Interface
flickerstreak@1 948 AceOO.Classpool = Classpool
flickerstreak@1 949 AceOO.inherits = inherits
flickerstreak@1 950
flickerstreak@1 951 -- Library handling bits
flickerstreak@1 952
flickerstreak@1 953 local function activate(self, oldLib, oldDeactivate)
flickerstreak@1 954 AceOO = self
flickerstreak@1 955 Factory = self.Factory
flickerstreak@1 956 Object = self.Object
flickerstreak@1 957 Class = self.Class
flickerstreak@1 958 ClassFactory.prototype = Class
flickerstreak@1 959 Mixin = self.Mixin
flickerstreak@1 960 Interface = self.Interface
flickerstreak@1 961 Classpool = self.Classpool
flickerstreak@1 962
flickerstreak@1 963 if oldLib then
flickerstreak@1 964 self.classes = oldLib.classes
flickerstreak@1 965 end
flickerstreak@1 966 if not self.classes then
flickerstreak@1 967 self.classes = setmetatable({}, {__mode="k"})
flickerstreak@1 968 else
flickerstreak@1 969 for class in pairs(self.classes) do
flickerstreak@1 970 class.new = class_new
flickerstreak@1 971 end
flickerstreak@1 972 end
flickerstreak@1 973
flickerstreak@1 974 if oldDeactivate then
flickerstreak@1 975 oldDeactivate(oldLib)
flickerstreak@1 976 end
flickerstreak@1 977 end
flickerstreak@1 978
flickerstreak@1 979 AceLibrary:Register(AceOO, MAJOR_VERSION, MINOR_VERSION, activate)
flickerstreak@1 980 AceOO = AceLibrary(MAJOR_VERSION)