diff libs/AceOO-2.0/AceOO-2.0.lua @ 1:c11ca1d8ed91

Version 0.1
author Flick <flickerstreak@gmail.com>
date Tue, 20 Mar 2007 21:03:57 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libs/AceOO-2.0/AceOO-2.0.lua	Tue Mar 20 21:03:57 2007 +0000
@@ -0,0 +1,973 @@
+--[[
+Name: AceOO-2.0
+Revision: $Rev: 18708 $
+Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
+Inspired By: Ace 1.x by Turan (turan@gryphon.com)
+Website: http://www.wowace.com/
+Documentation: http://www.wowace.com/index.php/AceOO-2.0
+SVN: http://svn.wowace.com/root/trunk/Ace2/AceOO-2.0
+Description: Library to provide an object-orientation framework.
+Dependencies: AceLibrary
+]]
+
+local MAJOR_VERSION = "AceOO-2.0"
+local MINOR_VERSION = "$Revision: 18708 $"
+
+-- This ensures the code is only executed if the libary doesn't already exist, or is a newer version
+if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end
+if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
+
+local AceOO = {
+	error = AceLibrary.error,
+	argCheck = AceLibrary.argCheck
+}
+
+-- @function	getuid
+-- @brief		Obtain a unique string identifier for the object in question.
+-- @param t		The object to obtain the uid for.
+-- @return		The uid string.
+local function pad(cap)
+	return string.rep('0', 8 - string.len(cap)) .. cap
+end
+local function getuid(t)
+	local mt = getmetatable(t)
+	setmetatable(t, nil)
+	local str = tostring(t)
+	setmetatable(t, mt)
+	local _,_,cap = string.find(str, '[^:]*: 0x(.*)$')
+	if cap then return pad(cap) end
+	_,_,cap = string.find(str, '[^:]*: (.*)$')
+	if cap then return pad(cap) end
+end
+
+local function getlibrary(o)
+	if type(o) == "table" then
+		return o
+	elseif type(o) == "string" then
+		if not AceLibrary:HasInstance(o) then
+			AceOO:error("Library %q does not exist.", o)
+		end
+		return AceLibrary(o)
+	end
+end
+
+-- @function		Factory
+-- @brief			Construct a factory for the creation of objects.
+-- @param obj		The object whose init method will be called on the new factory
+--					object.
+-- @param newobj	The object whose init method will be called on the new
+--					objects that the Factory creates, to initialize them.
+-- @param (...) Arguments which will be passed to obj.init() in addition
+--					to the Factory object.
+-- @return			The new factory which creates a newobj when its new method is called,
+--					or when it is called directly (__call metamethod).
+local Factory
+do
+	local arg = {}
+	local function new(obj, ...)
+		local t = {}
+		local uid = getuid(t)
+		for i = 1, select('#', ...) do
+			arg[i] = getlibrary(select(i, ...))
+		end
+		obj:init(t, unpack(arg))
+		for i = 1, select('#', ...) do
+			arg[i] = nil
+		end
+		t.uid = uid
+		return t
+	end
+	
+	local function createnew(self, ...)
+		local o = self.prototype
+		for i = 1, select('#', ...) do
+			arg[i] = getlibrary(select(i, ...))
+		end
+		local x = new(o, unpack(arg))
+		for i = 1, select('#', ...) do
+			arg[i] = nil
+		end
+		return x
+	end
+
+	function Factory(obj, newobj, ...)
+		local t = new(obj, ...)
+		t.prototype = newobj
+		t.new = createnew
+		getmetatable(t).__call = t.new
+		return t
+	end
+end
+
+
+local function objtostring(self)
+	if self.ToString then
+		return self:ToString()
+	elseif self.GetLibraryVersion then
+		return (self:GetLibraryVersion())
+	elseif self.super then
+		local s = "Sub-" .. tostring(self.super)
+		local first = true
+		if self.interfaces then
+			for interface in pairs(self.interfaces) do
+				if first then
+					s = s .. "(" .. tostring(interface)
+					first = false
+				else
+					s = s .. ", " .. tostring(interface)
+				end
+			end
+		end
+		if self.mixins then
+			for mixin in pairs(self.mixins) do
+				if first then
+					s = s .. tostring(mixin)
+					first = false
+				else
+					s = s .. ", " .. tostring(mixin)
+				end
+			end
+		end
+		if first then
+			if self.uid then
+				return s .. ":" .. self.uid
+			else
+				return s
+			end
+		else
+			return s .. ")"
+		end
+	else
+		return self.uid and 'Subclass:' .. self.uid or 'Subclass'
+	end
+end
+
+-- @table			Object
+-- @brief			Base of all objects, including Class.
+--
+-- @method			init
+-- @brief			Initialize a new object.
+-- @param newobject The object to initialize
+-- @param class		The class to make newobject inherit from
+local Object
+do
+	Object = {}
+	function Object:init(newobject, class)
+		local parent = class or self
+		if not rawget(newobject, 'uid') then
+			newobject.uid = getuid(newobject)
+		end
+		local mt = {
+			__index = parent,
+			__tostring = objtostring,
+		}
+		setmetatable(newobject, mt)
+	end
+	Object.uid = getuid(Object)
+	setmetatable(Object, { __tostring = function() return 'Object' end })
+end
+
+local Interface
+
+local function validateInterface(object, interface)
+	if not object.class and object.prototype then
+		object = object.prototype
+	end
+	for k,v in pairs(interface.interface) do
+		if tostring(type(object[k])) ~= v then
+			return false
+		end
+	end
+	if interface.superinterfaces then
+		for superinterface in pairs(interface.superinterfaces) do
+			if not validateInterface(object, superinterface) then
+				return false
+			end
+		end
+	end
+	if type(object.class) == "table" and rawequal(object.class.prototype, object) then
+		if not object.class.interfaces then
+			rawset(object.class, 'interfaces', {})
+		end
+		object.class.interfaces[interface] = true
+	elseif type(object.class) == "table" and type(object.class.prototype) == "table" then
+		validateInterface(object.class.prototype, interface)
+		-- check if class is proper, thus preventing future checks.
+	end
+	return true
+end
+
+-- @function		inherits
+-- @brief			Return whether an Object or Class inherits from a given
+--					parent.
+-- @param object	Object or Class to check
+-- @param parent	Parent to test inheritance from
+-- @return			whether an Object or Class inherits from a given
+--					parent.
+local function inherits(object, parent)
+	object = getlibrary(object)
+	if type(parent) == "string" then
+		if not AceLibrary:HasInstance(parent) then
+			return false
+		else
+			parent = AceLibrary(parent)
+		end
+	end
+	AceOO:argCheck(parent, 2, "table")
+	if type(object) ~= "table" then
+		return false
+	end
+	local current
+	if object.class then
+		current = object.class
+	else
+		current = object
+	end
+	if type(current) ~= "table" then
+		return false
+	end
+	if rawequal(current, parent) then
+		return true
+	end
+	if parent.class then
+		while true do
+			if rawequal(current, Object) then
+				break
+			end
+			if current.mixins then
+				for mixin in pairs(current.mixins) do
+					if rawequal(mixin, parent) then
+						return true
+					end
+				end
+			end
+			if current.interfaces then
+				for interface in pairs(current.interfaces) do
+					if rawequal(interface, parent) then
+						return true
+					end
+				end
+			end
+			current = current.super
+			if type(current) ~= "table" then
+				break
+			end
+		end
+		
+		local isInterface = false
+		local curr = parent.class
+		while true do
+			if rawequal(curr, Object) then
+				break
+			elseif rawequal(curr, Interface) then
+				isInterface = true
+				break
+			end
+			curr = curr.super
+			if type(curr) ~= "table" then
+				break
+			end
+		end
+		return isInterface and validateInterface(object, parent)
+	else
+		while true do
+			if rawequal(current, parent) then
+				return true
+			elseif rawequal(current, Object) then
+				return false
+			end
+			current = current.super
+			if type(current) ~= "table" then
+				return false
+			end
+		end
+	end
+end
+
+-- @table			Class
+-- @brief			An object factory which sets up inheritence and supports
+--					'mixins'.
+--
+-- @metamethod		Class call
+-- @brief			Call ClassFactory:new() to create a new class.
+--
+-- @method			Class new
+-- @brief			Construct a new object.
+-- @param (...) Arguments to pass to the object init function.
+-- @return			The new object.
+--
+-- @method			Class init
+-- @brief			Initialize a new class.
+-- @param parent	Superclass.
+-- @param (...) Mixins.
+--
+-- @method			Class ToString
+-- @return			A string representing the object, in this case 'Class'.
+local initStatus
+local Class
+local Mixin
+local autoEmbed = false
+local function traverseInterfaces(bit, total)
+	if bit.superinterfaces then
+		for interface in pairs(bit.superinterfaces) do
+			if not total[interface] then
+				total[interface] = true
+				traverseInterfaces(interface, total)
+			end
+		end
+	end
+end
+local class_new
+do
+	Class = Factory(Object, setmetatable({}, {__index = Object}), Object)
+	Class.super = Object
+	
+	local function protostring(t)
+		return '<' .. tostring(t.class) .. ' prototype>'
+	end
+	local function classobjectstring(t)
+		if t.ToString then
+			return t:ToString()
+		elseif t.GetLibraryVersion then
+			return (t:GetLibraryVersion())
+		else
+			return '<' .. tostring(t.class) .. ' instance>'
+		end
+	end
+	local function classobjectequal(self, other)
+		if type(self) == "table" and self.Equals then
+			return self:Equals(other)
+		elseif type(other) == "table" and other.Equals then
+			return other:Equals(self)
+		elseif type(self) == "table" and self.CompareTo then
+			return self:CompareTo(other) == 0
+		elseif type(other) == "table" and other.CompareTo then
+			return other:CompareTo(self) == 0
+		else
+			return rawequal(self, other)
+		end
+	end
+	local function classobjectlessthan(self, other)
+		if type(self) == "table" and self.IsLessThan then
+			return self:IsLessThan(other)
+		elseif type(other) == "table" and other.IsLessThanOrEqualTo then
+			return not other:IsLessThanOrEqualTo(self)
+		elseif type(self) == "table" and self.CompareTo then
+			return self:CompareTo(other) < 0
+		elseif type(other) == "table" and other.CompareTo then
+			return other:CompareTo(self) > 0
+		elseif type(other) == "table" and other.IsLessThan and other.Equals then
+			return other:Equals(self) or other:IsLessThan(self)
+		else
+			AceOO:error("cannot compare two objects")
+		end
+	end
+	local function classobjectlessthanequal(self, other)
+		if type(self) == "table" and self.IsLessThanOrEqualTo then
+			return self:IsLessThanOrEqualTo(other)
+		elseif type(other) == "table" and other.IsLessThan then
+			return not other:IsLessThan(self)
+		elseif type(self) == "table" and self.CompareTo then
+			return self:CompareTo(other) <= 0
+		elseif type(other) == "table" and other.CompareTo then
+			return other:CompareTo(self) >= 0
+		elseif type(self) == "table" and self.IsLessThan and self.Equals then
+			return self:Equals(other) or self:IsLessThan(other)
+		else
+			AceOO:error("cannot compare two incompatible objects")
+		end
+	end
+	local function classobjectadd(self, other)
+		if type(self) == "table" and self.Add then
+			return self:Add(other)
+		else
+			AceOO:error("cannot add two incompatible objects")
+		end
+	end
+	local function classobjectsub(self, other)
+		if type(self) == "table" and self.Subtract then
+			return self:Subtract(other)
+		else
+			AceOO:error("cannot subtract two incompatible objects")
+		end
+	end
+	local function classobjectunm(self, other)
+		if type(self) == "table" and self.UnaryNegation then
+			return self:UnaryNegation(other)
+		else
+			AceOO:error("attempt to negate an incompatible object")
+		end
+	end
+	local function classobjectmul(self, other)
+		if type(self) == "table" and self.Multiply then
+			return self:Multiply(other)
+		else
+			AceOO:error("cannot multiply two incompatible objects")
+		end
+	end
+	local function classobjectdiv(self, other)
+		if type(self) == "table" and self.Divide then
+			return self:Divide(other)
+		else
+			AceOO:error("cannot divide two incompatible objects")
+		end
+	end
+	local function classobjectpow(self, other)
+		if type(self) == "table" and self.Exponent then
+			return self:Exponent(other)
+		else
+			AceOO:error("cannot exponentiate two incompatible objects")
+		end
+	end
+	local function classobjectconcat(self, other)
+		if type(self) == "table" and self.Concatenate then
+			return self:Concatenate(other)
+		else
+			AceOO:error("cannot concatenate two incompatible objects")
+		end
+	end
+	function class_new(self, ...)
+		if self.virtual then
+			AceOO:error("Cannot instantiate a virtual class.")
+		end
+		
+		local o = self.prototype
+		local newobj = {}
+		if o.class and o.class.instancemeta then
+			setmetatable(newobj, o.class.instancemeta)
+		else
+			Object:init(newobj, o)
+		end
+		
+		if self.interfaces and not self.interfacesVerified then
+			-- Verify the interfaces
+			
+			for interface in pairs(self.interfaces) do
+				for field,kind in pairs(interface.interface) do
+					if tostring(type(newobj[field])) ~= kind then
+						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])))
+					end
+				end
+			end
+			self.interfacesVerified = true
+		end
+		local tmp = initStatus
+		initStatus = newobj
+		newobj:init(...)
+		if initStatus then
+			initStatus = tmp
+			AceOO:error("Initialization not completed, be sure to call the superclass's init method.")
+			return
+		end
+		initStatus = tmp
+		return newobj
+	end
+	local classmeta = {
+		__tostring = objtostring,
+		__call = function(self, ...)
+			return self:new(...)
+		end,
+	}
+	function Class:init(newclass, parent, ...)
+		parent = parent or self
+		
+		local total
+		
+		if parent.class then
+			total = { parent, ... }
+			parent = self
+		else
+			total = { ... }
+		end
+		if not inherits(parent, Class) then
+			AceOO:error("Classes must inherit from a proper class")
+		end
+		if parent.sealed then
+			AceOO:error("Cannot inherit from a sealed class")
+		end
+		for i,v in ipairs(total) do
+			if inherits(v, Mixin) and v.class then
+				if v.__deprecated then
+					AceOO:error(v.__deprecated)
+				end
+				if not newclass.mixins then
+					newclass.mixins = {}
+				end
+				if newclass.mixins[v] then
+					AceOO:error("Cannot explicitly inherit from the same mixin twice")
+				end
+				newclass.mixins[v] = true
+			elseif inherits(v, Interface) and v.class then
+				if not newclass.interfaces then
+					newclass.interfaces = {}
+				end
+				if newclass.interfaces[v] then
+					AceOO:error("Cannot explicitly inherit from the same interface twice")
+				end
+				newclass.interfaces[v] = true
+			else
+				AceOO:error("Classes can only inherit from one or zero classes and any number of mixins or interfaces")
+			end
+		end
+		if parent.interfaces then
+			if not newclass.interfaces then
+				newclass.interfaces = {}
+			end
+			for interface in pairs(parent.interfaces) do
+				newclass.interfaces[interface] = true
+			end
+		end
+		for k in pairs(total) do
+			total[k] = nil
+		end
+		
+		newclass.super = parent
+		
+		newclass.prototype = setmetatable(total, {
+			__index = parent.prototype,
+			__tostring = protostring,
+		})
+		total = nil
+		
+		newclass.instancemeta = {
+			__index = newclass.prototype,
+			__tostring = classobjectstring,
+			__eq = classobjectequal,
+			__lt = classobjectlessthan,
+			__le = classobjectlessthanequal,
+			__add = classobjectadd,
+			__sub = classobjectsub,
+			__unm = classobjectunm,
+			__mul = classobjectmul,
+			__div = classobjectdiv,
+			__pow = classobjectpow,
+			__concat = classobjectconcat,
+		}
+		
+		setmetatable(newclass, classmeta)
+		
+		newclass.new = class_new
+		
+		if newclass.mixins then
+			-- Fold in the mixins
+			local err, msg
+			for mixin in pairs(newclass.mixins) do
+				local ret
+				autoEmbed = true
+				ret, msg = pcall(mixin.embed, mixin, newclass.prototype)
+				autoEmbed = false
+				if not ret then
+					err = true
+					break
+				end
+			end
+	
+			if err then
+				local pt = newclass.prototype
+				for k,v in pairs(pt) do
+					pt[k] = nil
+				end
+	
+				-- method conflict
+				AceOO:error(msg)
+			end
+		end
+		
+		newclass.prototype.class = newclass
+		
+		if newclass.interfaces then
+			for interface in pairs(newclass.interfaces) do
+				traverseInterfaces(interface, newclass.interfaces)
+			end
+		end
+		if newclass.mixins then
+			for mixin in pairs(newclass.mixins) do
+				if mixin.interfaces then
+					if not newclass.interfaces then
+						newclass.interfaces = {}
+					end
+					for interface in pairs(mixin.interfaces) do
+						newclass.interfaces[interface] = true
+					end
+				end
+			end
+		end
+	end
+	function Class:ToString()
+		if type(self.GetLibraryVersion) == "function" then
+			return (self:GetLibraryVersion())
+		else
+			return "Class"
+		end
+	end
+	
+	local tmp
+	function Class.prototype:init()
+		if rawequal(self, initStatus) then
+			initStatus = nil
+		else
+			AceOO:error("Improper self passed to init. You must do MyClass.super.prototype.init(self, ...)", 2)
+		end
+		self.uid = getuid(self)
+		local current = self.class
+		while true do
+			if current == Class then
+				break
+			end
+			if current.mixins then
+				for mixin in pairs(current.mixins) do
+					if type(mixin.OnInstanceInit) == "function" then
+						mixin:OnInstanceInit(self)
+					end
+				end
+			end
+			current = current.super
+		end
+	end
+end
+
+
+-- @object	ClassFactory
+-- @brief	A factory for creating classes.	Rarely used directly.
+local ClassFactory = Factory(Object, Class, Object)
+
+function Class:new(...)
+	local x = ClassFactory:new(...)
+	if AceOO.classes then
+		AceOO.classes[x] = true
+	end
+	return x
+end
+getmetatable(Class).__call = Class.new
+
+-- @class	Mixin
+-- @brief	A class to create mixin objects, which contain methods that get
+-- "mixed in" to class prototypes.
+--
+-- @object	Mixin prototype
+-- @brief	The prototype that mixin objects inherit their methods from.
+--
+-- @method	Mixin prototype embed
+-- @brief	Mix in the methods of our object which are listed in our interface
+--		 to the supplied target table.
+--
+-- @method	Mixin prototype init
+-- @brief	Initialize the mixin object.
+-- @param	newobj	 The new object we're initializing.
+-- @param	interface	The interface we implement (the list of methods our
+--					prototype provides which should be mixed into the target
+--					table by embed).
+do
+	Mixin = Class()
+	function Mixin:ToString()
+		if self.GetLibraryVersion then
+			return (self:GetLibraryVersion())
+		else
+			return 'Mixin'
+		end
+	end
+	local function _Embed(state, field, target)
+		field = next(state.export, field)
+		if field == nil then
+			return
+		end
+
+		if rawget(target, field) or (target[field] and target[field] ~= state[field]) then
+			AceOO:error("Method conflict in attempt to mixin. Field %q", field)
+		end
+
+		target[field] = state[field]
+
+		local ret,msg = pcall(_Embed, state, field, target)
+		if not ret then
+			-- Mix in the next method according to the defined interface.	If that
+			-- fails due to a conflict, re-raise to back out the previous mixed
+			-- methods.
+
+			target[field] = nil
+			AceOO:error(msg)
+		end
+	end
+	function Mixin.prototype:embed(target)
+		if self.__deprecated then
+			AceOO:error(self.__deprecated)
+		end
+		local mt = getmetatable(target)
+		setmetatable(target, nil)
+		local err, msg = pcall(_Embed, self, nil, target)
+		if not err then
+			setmetatable(target, mt)
+			AceOO:error(msg)
+			return
+		end
+		if type(self.embedList) == "table" then
+			self.embedList[target] = true
+		end
+		if type(target.class) ~= "table" then
+			target[self] = true
+		end
+		if not autoEmbed and type(self.OnManualEmbed) == "function" then
+			self:OnManualEmbed(target)
+		end
+		setmetatable(target, mt)
+	end
+	
+	function Mixin.prototype:activate(oldLib, oldDeactivate)
+		if oldLib and oldLib.embedList then
+			for target in pairs(oldLib.embedList) do
+				local mt = getmetatable(target)
+				setmetatable(target, nil)
+				for field in pairs(oldLib.export) do
+					target[field] = nil
+				end
+				setmetatable(target, mt)
+			end
+			self.embedList = oldLib.embedList
+			for target in pairs(self.embedList) do
+				self:embed(target)
+			end
+		else
+			self.embedList = setmetatable({}, {__mode="k"})
+		end
+	end
+	
+	function Mixin.prototype:init(export, ...)
+		AceOO:argCheck(export, 2, "table")
+		for k,v in pairs(export) do
+			if type(k) ~= "number" then
+				AceOO:error("All keys to argument #2 must be numbers.")
+			elseif type(v) ~= "string" then
+				AceOO:error("All values to argument #2 must be strings.")
+			end
+		end
+		local num = #export
+		for i = 1, num do
+			local v = export[i]
+			export[i] = nil
+			export[v] = true
+		end
+		
+		local interfaces
+		if select('#', ...) >= 1 then
+			interfaces = { ... }
+			for i,v in ipairs(interfaces) do
+				v = getlibrary(v)
+				interfaces[i] = v
+				if not v.class or not inherits(v, Interface) then
+					AceOO:error("Mixins can inherit only from interfaces")
+				end
+			end
+			local num = #interfaces
+			for i = 1, num do
+				local v = interfaces[i]
+				interfaces[i] = nil
+				interfaces[v] = true
+			end
+			for interface in pairs(interfaces) do
+				traverseInterfaces(interface, interfaces)
+			end
+			for interface in pairs(interfaces) do
+				for field,kind in pairs(interface.interface) do
+					if kind ~= "nil" then
+						local good = false
+						for bit in pairs(export) do
+							if bit == field then
+								good = true
+								break
+							end
+						end
+						if not good then
+							AceOO:error("Mixin does not fully accommodate field %q", field)
+						end
+					end
+				end
+			end
+		end
+		self.super = Mixin.prototype
+		Mixin.super.prototype.init(self)
+		self.export = export
+		self.interfaces = interfaces
+	end
+end
+
+-- @class Interface
+-- @brief A class to create interfaces, which contain contracts that classes
+--			which inherit from this must comply with.
+--
+-- @object Interface prototype
+-- @brief	The prototype that interface objects must adhere to.
+--
+-- @method Interface prototype init
+-- @brief	Initialize the mixin object.
+-- @param	interface	The interface we contract (the hash of fields forced).
+-- @param	(...)	Superinterfaces
+do
+	Interface = Class()
+	function Interface:ToString()
+		if self.GetLibraryVersion then
+			return (self:GetLibraryVersion())
+		else
+			return 'Instance'
+		end
+	end
+	function Interface.prototype:init(interface, ...)
+		Interface.super.prototype.init(self)
+		AceOO:argCheck(interface, 2, "table")
+		for k,v in pairs(interface) do
+			if type(k) ~= "string" then
+				AceOO:error("All keys to argument #2 must be numbers.")
+			elseif type(v) ~= "string" then
+				AceOO:error("All values to argument #2 must be strings.")
+			elseif v ~= "nil" and v ~= "string" and v ~= "number" and v ~= "table" and v ~= "function" then
+				AceOO:error('All values to argument #2 must either be "nil", "string", "number", "table", or "function".')
+			end
+		end
+		if select('#', ...) >= 1 then
+			self.superinterfaces = { ... }
+			for i,v in ipairs(self.superinterfaces) do
+				v = getlibrary(v)
+				self.superinterfaces[i] = v
+				if not inherits(v, Interface) or not v.class then
+					AceOO:error('Cannot provide a non-Interface to inherit from')
+				end
+			end
+			local num = #self.superinterfaces
+			for i = 1, num do
+				local v = self.superinterfaces[i]
+				self.superinterfaces[i] = nil
+				self.superinterfaces[v] = true
+			end
+		end
+		self.interface = interface
+	end
+end
+
+-- @function Classpool
+-- @brief	Obtain a read only class from our pool of classes, indexed by the
+--		 superclass and mixins.
+-- @param	sc		 The superclass of the class we want.
+-- @param	(m1..m20)	Mixins of the class we want's objects.
+-- @return A read only class from the class pool.
+local Classpool
+do
+	local pool = setmetatable({}, {__mode = 'v'})
+	local function newindex(k, v)
+		AceOO:error('Attempt to modify a read-only class.')
+	end
+	local function protonewindex(k, v)
+		AceOO:error('Attempt to modify a read-only class prototype.')
+	end
+	local function ts(bit)
+		if type(bit) ~= "table" then
+			return tostring(bit)
+		elseif getmetatable(bit) and bit.__tostring then
+			return tostring(bit)
+		elseif type(bit.GetLibraryVersion) == "function" then
+			return bit:GetLibraryVersion()
+		else
+			return tostring(bit)
+		end
+	end
+	local t = {}
+	local function getcomplexuid(sc, ...)
+		if sc then
+			if sc.uid then
+				table.insert(t, sc.uid)
+			else
+				AceOO:error("%s is not an appropriate class/mixin", ts(sc))
+			end
+		end
+		for i = 1, select('#', ...) do
+			local m = select(i, ...)
+			if m.uid then
+				table.insert(t, m.uid)
+			else
+				AceOO:error("%s is not an appropriate mixin", ts(m))
+			end
+		end
+		table.sort(t)
+		local uid = table.concat(t, '')
+		local num = #t
+		for i = 1, num do
+			t[i] = nil
+		end
+		return uid
+	end
+	local classmeta
+	local arg = {}
+	function Classpool(superclass, ...)
+		local l = getlibrary
+		superclass = getlibrary(superclass)
+		arg = { ... }
+		for i, v in ipairs(arg) do
+			arg[i] = getlibrary(v)
+		end
+		if superclass then
+			if superclass.class then -- mixin
+				table.insert(arg, 1, superclass)
+				superclass = Class
+			end
+		else
+			superclass = Class
+		end
+		local key = getcomplexuid(superclass, unpack(arg))
+		if not pool[key] then
+			local class = Class(superclass, unpack(arg))
+			if not classmeta then
+				classmeta = {}
+				local mt = getmetatable(class)
+				for k,v in pairs(mt) do
+					classmeta[k] = v
+				end
+				classmeta.__newindex = newindex
+			end
+			-- Prevent the user from adding methods to this class.
+			-- NOTE: I'm not preventing modifications of existing class members,
+			-- but it's likely that only a truly malicious user will be doing so.
+			class.sealed = true
+			setmetatable(class, classmeta)
+			getmetatable(class.prototype).__newindex = protonewindex
+			pool[key] = class
+		end
+		return pool[key]
+	end
+end
+
+AceOO.Factory = Factory
+AceOO.Object = Object
+AceOO.Class = Class
+AceOO.Mixin = Mixin
+AceOO.Interface = Interface
+AceOO.Classpool = Classpool
+AceOO.inherits = inherits
+
+-- Library handling bits
+
+local function activate(self, oldLib, oldDeactivate)
+	AceOO = self
+	Factory = self.Factory
+	Object = self.Object
+	Class = self.Class
+	ClassFactory.prototype = Class
+	Mixin = self.Mixin
+	Interface = self.Interface
+	Classpool = self.Classpool
+	
+	if oldLib then
+		self.classes = oldLib.classes
+	end
+	if not self.classes then
+		self.classes = setmetatable({}, {__mode="k"})
+	else
+		for class in pairs(self.classes) do
+			class.new = class_new
+		end
+	end
+	
+	if oldDeactivate then
+		oldDeactivate(oldLib)
+	end
+end
+
+AceLibrary:Register(AceOO, MAJOR_VERSION, MINOR_VERSION, activate)
+AceOO = AceLibrary(MAJOR_VERSION)