Skip to content

Instantly share code, notes, and snippets.

@Elmuti
Created May 24, 2015 14:35
Show Gist options
  • Save Elmuti/76af9f55ac1cba475f26 to your computer and use it in GitHub Desktop.
Save Elmuti/76af9f55ac1cba475f26 to your computer and use it in GitHub Desktop.
--[[
OBJECT MODULE
v1.4
(C) Jonathan Holmes 2014
Edits by Elmeri Ferm:
added metamethod overriding
Usage:
ModObject:NewClass(ClassName, ParentClass, ClassTable)
->returns LuaObject
To use custom metamethods over the default ones, you must have functions
named "operator_metamethodname" in the class table.
Example:
function TestClass.operator_add(self, a, b)
return a + b
end
function TestClass.operator_index(self, index)
return rawget(self, index)
end
All overloadable operators:
operation_tostring
operator_index
operator_newindex
operator_add
operator_multiply
operator_subtract
operator_modulus
operator_divide
operator_equals
operator_lessthan
operator_greaterthan
operator_lessthanequal
]]
ModObject = {
Version = 1.5;
EnableStructConstructor = true;
};
CustomObjects = {
};
CustomObjectsFullName = {
};
Object = {
ClassName = "Object";
ParentClass = nil;
IsClass = true;
}
function TableCopy(old) -- %.Copy( Table )
local _new = {};
for index,value in pairs(old) do
if (type(value) == 'table') then
_new[index] = TableCopy(value);
elseif (value ~= nil) then
_new[index] = value;
end
end
return _new;
end
Object.__index = Object
Object.__eq = (function(self, other)
return self == other;
end);
if (ModObject.EnableStructConstructor) then
Object.__call = (function(self, ...) -- Constructor{}
--[[
Person("John Doe", 20)
&&
Person{
"John Doe", -- required constructor arguments (if needed)
20,
Address = "123 Example Street"; -- Assigning properties within the constructor
City = "SomeCity";
}
]]
local params = {...};
local tbl = unpack(params);
local obj;
if (#params == 1 and type(tbl) == 'table') then
obj = self.new( unpack(tbl) );
for i,v in pairs(tbl) do
if (type(i) == 'string' and rawget(obj,i) == nil) then
warn(obj.ClassName .. " does not contain a member '" .. i .. "'");
elseif (type(i) == 'string') then
obj[i] = v;
end
end
else
obj = self.new(...);
end
return obj;
end);
else
Object.__call = (function(self, ...)
return self.new(...);
end);
end
Object.__tostring = (function(self, ...)
return "LuaClass: " .. self.ClassName;
end);
--- Object.new()
-- Creates a new instance of superclass Object
function Object.new()
local newobj = {}
newobj.IsClass = false;
newobj.LuaObject = true;
setmetatable(newobj, Object)
return newobj
end
--- Object::Create(string objName, ...constructor_args)
-- Creates the object if it exists, and uses the constructor args if specified.
function Object:Create(objName, ...)
if (self ~= Object) then
error("Cannot call static member 'Create' (Object::Create) from object " .. self.ClassName); end
local t = CustomObjects[objName];
if (t and t.new) then
return t.new(...);
end
error("Could not instantiate type " .. objName);
end
--- Object:IsType(string className)
-- Checks to see if the object is of the class, or inherits the class.
function Object:IsType(str)
if (str == self.ClassName) then
return true, self.ClassName;
elseif (self.ParentClass ~= nil) then
return self.ParentClass:IsType(str);
else
return false, self.ClassName;
end
end
--- Object:GetInheritance()
-- Shows the object's inheritance
function Object:GetInheritance()
local t = self.ParentClass;
local str = self.ClassName;
while (t ~= nil and (t ~= Object)) do
str = str .. "." .. t.ClassName;
t = t.ParentClass;
end
return str;
end
function Object:Copy(obj, ...)
if (not self.IsClass) then
error("Cannot call static member Object::Copy() from class "..self.ClassName); end
local _type = Object:GetTypeByName(obj.ClassName);
local newObj = _type.new(...);
for i,v in pairs(obj) do
if (i ~= "Id" and i ~= "Name") then
if (type(v) == 'table') then
newObj[i] = TableCopy(v);
else
newObj[i] = v;
end
end
end
return newObj;
end
function Object:GetTypeByName(name)
if (not self.IsClass) then
error("Cannot call static member Object::GetTypeByName() from class "..self.ClassName); end
return CustomObjectsFullName[name] or CustomObjects[name];
end
--- object:GetMembers();
-- Puts all the members into a table
function Object:GetMembers()
local t = {};
for i,v in pairs(self) do
t[self.ClassName .. "::" .. i] = v;
end
return t;
end
--- static Object::NewType(Table obj, string className)
-- Turns the table into a type with the specified className.
--- ::->Extends(Type obj)
-- Makes the object inherit the specified type.
function Object:NewType(obj, className, inherits)
if (self ~= Object) then
error("Cannot call static member 'NewType' (Object::NewType) from object " .. self.ClassName); end
inherits = inherits or Object;
obj.__index = function(self, index)
local operator = rawget(obj, "operator_index")
if operator then
return operator(self, index)
else
return rawget(obj, index)
end
end
obj.__tostring = (function(self)
if (self.operation_tostring) then
return "LuaObject: " .. self:operation_tostring();
else
return "LuaObject: "..self.ClassName.."";
end
end);
obj.__add = (function(lhs, rhs)
if (self.operator_add) then
return self.operator_add(lhs, rhs);
else
return false;
end
end);
obj.__mul = (function(lhs, rhs)
if (self.operator_multiply) then
return self.operator_multiply(lhs, rhs);
else
return false;
end
end);
obj.__sub = (function(lhs, rhs)
if (self.operator_subtract) then
return self.operator_subtract(lhs, rhs);
else
return false;
end
end);
obj.__mod = (function(lhs, rhs)
if (self.operator_modulus) then
return self.operator_modulus(lhs, rhs);
else
return false;
end
end);
obj.__div = (function(lhs, rhs)
if (self.operator_divide) then
return self.operator_divide(lhs, rhs);
else
return false;
end
end);
obj.__eq = (function(lhs, rhs)
if (self.operator_equals) then
return self.operator_equals(lhs, rhs);
else
return false;
end
end);
obj.__lt = (function(lhs, rhs)
if (self.operator_lessthan) then
return self.operator_lessthan(lhs, rhs);
else
return false;
end
end);
obj.__le = (function(lhs, rhs)
if (self.operator_lessthanequal) then
return self.operator_lessthanequal(lhs, rhs);
else
return false;
end
end);
obj.__gt = (function(lhs, rhs)
if (self.operator_greaterthan) then
return self.operator_greaterthan(lhs, rhs);
else
return false;
end
end);
obj.__newindex = (function(self, i, v)
if (i ~= 'ClassName' and i ~= 'ParentClass' and i ~= 'LuaObject') then
if (self.operator_newindex) then
self.operator_newindex(self, i, v)
else
rawset(self, i, v);
end
else
error("Cannot set read-only property " .. i);
end
end);
-- obj.__call = (function(self, ...)
-- if (self.operator_call) then
--self.operator_call(self, ...)
-- end
--end);
obj.ClassName = className or 'Object';
obj.ParentClass = inherits;
setmetatable(obj, inherits);
local spec = {};
function spec:__ExtendsObject(inherits)
for i,v in pairs(inherits) do
if (i ~= 'ClassName' and i ~= 'ParentClass' and i ~= '__index' and i ~= 'new') then
obj[i] = type(v) == 'table' and TableCopy(v) or v;
end
end
end
function spec:Extends(inherits)
obj.ParentClass = inherits;
if (inherits.__inheritable and inherits.__inheritable == false) then
error("Cannot inherit class " .. inherits.ClassName .. ", it is not inheritable."); end
if (inherits.__extend and type(inherits.__extend) == 'function') then
inherits.__extend(obj, inherits);
else
spec:__ExtendsObject(inherits);
end
CustomObjectsFullName[obj:GetInheritance()] = obj;
end
CustomObjects[className] = obj;
return spec;
end
function Object:BaseCall(name, ...)
self.ParentClass[name](self, ...);
end
function Object:NewClass(className, inheritance, classT)
local _class = classT or {};
if (inheritance ~= nil) then
Object:NewType(_class, className):Extends(
type(inheritance) == 'string'
and Object:GetTypeByName(inheritance)
or inheritance
);
else
Object:NewType(_class, className);
end
return _class;
end
--- Object:Init( ... )
-- Calls the parent's constructor
function Object:Init(...)
if (self == Object) then
error("Cannot call static member 'Init' (Object::Init) from SuperClass 'Object'"); end
if (self.ParentClass ~= nil) then
local obj = self.ParentClass.new(...);
setmetatable(obj, self);
return obj;
else
error("Class '" .. self.ClassName .. " does not inherit an object.");
end
end
function Object:IsObject(val)
if (self ~= Object) then
error("Cannot call static member 'IsObject' (Object::IsObject) from object " .. self.ClassName); end
return (tostring(val):sub(1, 9) == "LuaObject");
end
function Object:PureVirtual(name)
assert(self ~= Object, "Object::PureVirtual is not a static method!");
self[name] = (function() error("Method " .. self.ClassName .. "::" .. name .. " is purely virtual, it must be overriden by the child class.") end);
end
Object.Super = Object.Init;
return Object;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment