Created
May 24, 2015 14:35
-
-
Save Elmuti/76af9f55ac1cba475f26 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
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