lotrointerface.com
Search Downloads

LoTROInterface SVN Reminders

[/] [trunk/] [Thurallor/] [Common/] [Turbine/] [Class.lua] - Rev 2

Compare with Previous | Blame | View Log

-- Table the stores the class information objects.
local classInfoTable = { };

-- Table that caches the class type objects.
local classTypesTable = { };

-- Define an IsA method that will be attached to all classes.
local function IsA( self, target )
        return Type.StaticIsA( self.GetType(), target );
end

function _G.static_class( ... )
        local args = { ... };
        local baseClass;
        local mixins = { };
        local baseObjects = 0;

        local i;
        local object;

        -- Validate that there is at most one base class and that the base class is
        -- not marked as final.
        for i, object in pairs( args ) do
                local type = Type.StaticGetType( object );
                
                if ( type:IsClass() ) then
                        if ( baseClass ~= nil ) then
                                error( "A class can only have a single base class. More than one base class was specified." );
                        end
                        
                        if ( type:IsFinal() ) then
                                error( "Unable to inherit from final class." );
                        end
                        
                        baseClass = object;
                        baseObjects = baseObjects + 1;
                elseif ( type:IsMixin() ) then
                        table.insert( mixins, object );
                        baseObjects = baseObjects + 1;
                else
                        error( "Invalid base object specified in class declaration." );
                end
        end

        local className = "";
        local environmentTable = getfenv( 0 );

        -- Try to determine the class name.
        if (
                ( environmentTable ~= nil ) and
                ( environmentTable._ ~= nil ) and
                ( type( environmentTable._ ) == "table" ) and
                ( environmentTable._.Name ~= nil ) and 
                ( type( environmentTable._.Name ) == "string" ) )
        then
                className = getfenv( 0 )._.Name;
        end

        -- Define type information.
        local classTypeInfo = {
                Class = true,
                Static = true,
                Base = baseClass,
                Mixins = mixins,
                FullName = className
        };

        -- Define the metatable for the class table that is used to link
        -- base classes and mixins.
        local classTableMetaTable = { };

        if ( baseObjects == 0 ) then
                -- No base class to associate.
        elseif ( baseObjects == 1 ) then
                -- Only once base class so just associate the index directly to the class
                -- or mixin.
                classTableMetaTable.__index = baseClass or unpack( mixins ); 
        else
                -- Multiple inheritance will require a search.
                classTableMetaTable.__index = function( table, key )
                        local i;
                        local mixin;
                        
                        if ( baseClass and baseClass[key] ) then
                                return baseClass[key];
                        end
                        
                        for i, mixin in pairs( mixins ) do
                                if ( mixin[key] ) then
                                        return mixin[key];
                                end
                        end
                end
        end

        -- Define the class definition table.
        local classTable = { };
        setmetatable( classTable, classTableMetaTable );

        classInfoTable[classTable] = classTypeInfo;

        if ( not classTable.GetUniqueID ) then
                local idTable = { };
                local weakKeysTable = { __mode = "k" };
                setmetatable( idTable, weakKeysTable );

                classTable.GetUniqueID = function( self )
                        if ( idTable[self] ~= nil ) then
                                return idTable[self];
                        end

                        local metatable = getmetatable( self );
                        setmetatable( self, nil );
                        local tostringValue = tostring( self );
                        setmetatable( self, metatable );
                        
                        local id = string.sub( tostringValue, 8 );
                        idTable[self] = id;
                        return id;

                end
        end

        -- Define a ToString method for the class table if one does not already
        -- exist.
        if ( not classTable.ToString ) then
                -- The default ToString method.
                classTable.ToString = function( self )
                        local target = self;
                        
                        -- If self is the class, this is not an instance.
                        if ( self == self.GetType():GetClass() ) then
                                self = nil;
                        end
                        
                        local id = target:GetUniqueID();
                        local className = target.GetType():GetName() or "";
                        local value = "<";
                        
                        if ( string.len( className ) > 0 ) then
                                 value =  value .. className .. " ";
                        end
                        
                        if ( self ) then
                                value =  value .. "Instance";
                        else
                                value =  value .. "Class";
                        end
                        
                        value = value .. ": " .. id .. ">";
                        
                        return value;
                end             
        end

        classTableMetaTable.__tostring = function( self )
                return self:ToString();
        end

        -- Attach the IsA method to the class.
        if ( not classTable.IsA ) then
                classTable.IsA = IsA;
        end

        -- Create the accessor for the type information. This function is always
        -- overriden since it is dependent on local variables.
        classTable.GetType = function()
                local classType = classTypesTable[classTable];

                if ( classType == nil ) then
                        classType = Type( classTable, classTypeInfo );
                        classTypesTable[classTable] = classType;
                end

                return classType;
        end

        return classTable, classTableMetaTable, classTypeInfo;
end

function _G.class( ... )
        local staticClass, staticClassMetaTable, staticClassInfo = static_class( ... );

        local classInstanceMetaTable = {
                __index = staticClass,
                __tostring = function( self )
                        return self:ToString();
                end
        };

        -- No longer static. Giving it a constructor.
        staticClassInfo.Static = nil;

        staticClassMetaTable.__call = function( classTable, ... )
                -- Create the new class instance.
                local instance = { };
                setmetatable( instance, classInstanceMetaTable );
                
                -- Invoke the constructor if it exists.
                if ( ( instance.Constructor ~= nil ) and ( type( instance.Constructor ) == 'function' ) ) then
                        instance:Constructor( ... );
                end
                
                return instance;
        end

        return staticClass, staticClassMetaTable, staticClassInfo, classInstanceMetaTable;
end

function _G.abstract_class( ... )
        local staticClass, staticClassMetaTable, staticClassInfo = static_class( ... );
        
        -- No longer static. Giving it a constructor.
        staticClassInfo.Static = nil;
        staticClassInfo.Abstract = true;

        staticClassMetaTable.__call = function( classTable, ... )
                error( "Cannot instantiate an abstract class. " );
        end

        return staticClass, staticClassMetaTable, staticClassInfo;
end

function _G.final_class( ... )
        local classClass, classMetaTable, classInfo, classInstanceMetaTable = class( ... );

        -- Class that cannot be inherited from.
        classInfo.Final = true;

        return classClass, classMetaTable, classInfo, classInstanceMetaTable;
end

local importPath = getfenv(1)._.Name;
local turbinePath = string.gsub(importPath, "%.Class$", "");
import (turbinePath .. ".Type");

Compare with Previous | Blame


All times are GMT -5. The time now is 12:30 PM.


Our Network
EQInterface | EQ2Interface | Minion | WoWInterface | ESOUI | LoTROInterface | MMOUI | Swtorui