Difference between revisions of "Simple Educative Class Library"

m (See also: "SECS is now SECL")
 
(One intermediate revision by one other user not shown)
Line 1: Line 1:
Also known as SECS (pronounce as 'sex').
+
Also known as SECL.
 
This is a simple implementation of classes that works, it's not commented, so it's a nice test of your lua skills.
 
This is a simple implementation of classes that works, it's not commented, so it's a nice test of your lua skills.
  
Remember to check here once in a while, it might have updated.
+
The current version can always be found [https://github.com/bartbes/love-misc-libs in the love-misc-libs repository]
  
==Basic version==
+
==Basic version example==
<source lang="lua">
 
--[[
 
Copyright (c) 2009 Bart van Strien
 
 
 
Permission is hereby granted, free of charge, to any person
 
obtaining a copy of this software and associated documentation
 
files (the "Software"), to deal in the Software without
 
restriction, including without limitation the rights to use,
 
copy, modify, merge, publish, distribute, sublicense, and/or sell
 
copies of the Software, and to permit persons to whom the
 
Software is furnished to do so, subject to the following
 
conditions:
 
 
 
The above copyright notice and this permission notice shall be
 
included in all copies or substantial portions of the Software.
 
 
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 
OTHER DEALINGS IN THE SOFTWARE.
 
]]
 
 
 
__HAS_SECS_COMPATIBLE_CLASSES__ = true
 
 
 
local class_mt = {}
 
 
 
function class_mt:__index(key)
 
return self.__baseclass[key]
 
end
 
 
 
class = setmetatable({ __baseclass = {} }, class_mt)
 
 
 
function class:new(...)
 
local c = {}
 
c.__baseclass = self
 
setmetatable(c, getmetatable(self))
 
if c.init then
 
c:init(...)
 
end
 
return c
 
end
 
</source>
 
 
 
===Example===
 
 
<source lang="lua">
 
<source lang="lua">
 
require "class" --this assumes you've saved the code above in class.lua
 
require "class" --this assumes you've saved the code above in class.lua
Line 68: Line 20:
 
</source>
 
</source>
  
==Class Commons enabled basic version==
+
==Advanced version example==
<source lang="lua">
 
--[[
 
Copyright (c) 2009-2011 Bart van Strien
 
 
 
Permission is hereby granted, free of charge, to any person
 
obtaining a copy of this software and associated documentation
 
files (the "Software"), to deal in the Software without
 
restriction, including without limitation the rights to use,
 
copy, modify, merge, publish, distribute, sublicense, and/or sell
 
copies of the Software, and to permit persons to whom the
 
Software is furnished to do so, subject to the following
 
conditions:
 
 
 
The above copyright notice and this permission notice shall be
 
included in all copies or substantial portions of the Software.
 
 
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 
OTHER DEALINGS IN THE SOFTWARE.
 
]]
 
 
 
local class_mt = {}
 
 
 
function class_mt:__index(key)
 
    return self.__baseclass[key]
 
end
 
 
 
class = setmetatable({ __baseclass = {} }, class_mt)
 
 
 
function class:new(...)
 
    local c = {}
 
    c.__baseclass = self
 
    setmetatable(c, getmetatable(self))
 
    if c.init then
 
        c:init(...)
 
    end
 
    return c
 
end
 
 
 
if class_commons ~= false then --on by default
 
common = {}
 
 
 
function common.class(name, t, parent)
 
parent = parent or class
 
t.__baseclass = parent
 
return setmetatable(t, getmetatable(parent))
 
end
 
 
 
function common.instance(class, ...)
 
return class:new(...)
 
end
 
end
 
</source>
 
 
 
{{notice|It's likely versions below this are bugged. Sorry about that!}}
 
==Advanced version==
 
<source lang="lua">
 
--[[
 
Copyright (c) 2009 Bart van Strien
 
 
 
Permission is hereby granted, free of charge, to any person
 
obtaining a copy of this software and associated documentation
 
files (the "Software"), to deal in the Software without
 
restriction, including without limitation the rights to use,
 
copy, modify, merge, publish, distribute, sublicense, and/or sell
 
copies of the Software, and to permit persons to whom the
 
Software is furnished to do so, subject to the following
 
conditions:
 
 
 
The above copyright notice and this permission notice shall be
 
included in all copies or substantial portions of the Software.
 
 
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 
OTHER DEALINGS IN THE SOFTWARE.
 
]]
 
 
 
__HAS_SECS_COMPATIBLE_CLASSES__ = true
 
 
 
local class_mt = {}
 
 
 
function class_mt:__index(key)
 
if rawget(self, "__baseclass") then
 
return self.__baseclass[key]
 
end
 
return nil
 
end
 
 
 
class = setmetatable({ __baseclass = {} }, class_mt)
 
 
 
function class:new(...)
 
local c = {}
 
c.__baseclass = self
 
setmetatable(c, getmetatable(self))
 
if c.init then
 
c:init(...)
 
end
 
return c
 
end
 
 
 
function class:convert(t)
 
t.__baseclass = self
 
setmetatable(t, getmetatable(self))
 
return t
 
end
 
 
 
function class:addparent(...)
 
if not rawget(self.__baseclass, "__isparenttable") then
 
local t = {__isparenttable = true, self.__baseclass, ...}
 
local mt = {}
 
function mt:__index(key)
 
for i, v in pairs(self) do
 
if i ~= "__isparenttable" and v[key] then
 
return v[key]
 
end
 
end
 
return nil
 
end
 
self.__baseclass = setmetatable(t, mt)
 
else
 
for i, v in ipairs{...} do
 
table.insert(self.__baseclass, v)
 
end
 
end
 
return self
 
end
 
 
 
function class:setmetamethod(name, value)
 
local mt = getmetatable(self)
 
local newmt = {}
 
for i, v in pairs(mt) do
 
newmt[i] = v
 
end
 
newmt[name] = value
 
setmetatable(self, newmt)
 
end
 
</source>
 
 
 
===Example===
 
 
<source lang="lua">
 
<source lang="lua">
 
--NOTE: this example only contains features the basic version doesn't, if you want to see those functions see the basic example
 
--NOTE: this example only contains features the basic version doesn't, if you want to see those functions see the basic example
Line 246: Line 49:
 
</source>
 
</source>
  
==Full version (AKA overcomplicated)==
+
==Full version example==
<source lang="lua">
 
--[[
 
Copyright (c) 2009 Bart van Strien
 
 
 
Permission is hereby granted, free of charge, to any person
 
obtaining a copy of this software and associated documentation
 
files (the "Software"), to deal in the Software without
 
restriction, including without limitation the rights to use,
 
copy, modify, merge, publish, distribute, sublicense, and/or sell
 
copies of the Software, and to permit persons to whom the
 
Software is furnished to do so, subject to the following
 
conditions:
 
 
 
The above copyright notice and this permission notice shall be
 
included in all copies or substantial portions of the Software.
 
 
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 
OTHER DEALINGS IN THE SOFTWARE.
 
]]
 
 
 
__HAS_SECS_COMPATIBLE_CLASSES__ = true
 
 
 
local class_mt = {}
 
 
 
function class_mt:__index(key)
 
if rawget(self, "__baseclass") then
 
return self.__baseclass[key]
 
end
 
return nil
 
end
 
 
 
function class_mt:__call(...)
 
return self:new(...)
 
end
 
 
 
function class_mt:__add(parent)
 
return self:addparent(parent)
 
end
 
 
 
function class_mt:__eq(other)
 
if not other.__baseclass or other.__baseclass ~= self.__baseclass then return false end
 
for i, v in pairs(self) do
 
if not other[i] then
 
return false
 
end
 
end
 
for i, v in pairs(other) do
 
if not self[i] then
 
return false
 
end
 
end
 
return true
 
end
 
 
 
function class_mt:__lt(other)
 
if not other.__baseclass then return false end
 
if rawget(other.__baseclass, "__isparenttable") then
 
for i, v in pairs(other.__baseclass) do
 
if self == v or getmetatable(self).__lt(self, v) then return true end
 
end
 
else
 
if self == other.__baseclass or getmetatable(self).__lt(self, other.__baseclass) then return true end
 
end
 
return false
 
end
 
 
 
function class_mt:__le(other)
 
return (self < other or self == other)
 
end
 
 
 
local pt_mt = {}
 
function pt_mt:__index(key)
 
for i, v in pairs(self) do
 
if i ~= "__isparenttable" and v[key] then
 
return v[key]
 
end
 
end
 
return nil
 
end
 
 
 
class = setmetatable({ __baseclass = {} }, class_mt)
 
 
 
function class:new(...)
 
local c = {}
 
c.__baseclass = self
 
setmetatable(c, getmetatable(self))
 
if c.init then
 
c:init(...)
 
end
 
return c
 
end
 
 
 
function class:convert(t)
 
t.__baseclass = self
 
setmetatable(t, getmetatable(self))
 
return t
 
end
 
 
 
function class:addparent(...)
 
if not rawget(self.__baseclass, "__isparenttable") then
 
local t = {__isparenttable = true, self.__baseclass, ...}
 
self.__baseclass = setmetatable(t, pt_mt)
 
else
 
for i, v in ipairs{...} do
 
table.insert(self.__baseclass, v)
 
end
 
end
 
return self
 
end
 
 
 
function class:setmetamethod(name, value)
 
local mt = getmetatable(self)
 
local newmt = {}
 
for i, v in pairs(mt) do
 
newmt[i] = v
 
end
 
newmt[name] = value
 
setmetatable(self, newmt)
 
end
 
</source>
 
 
 
 
 
===Example===
 
 
<source lang="lua">
 
<source lang="lua">
 
--NOTE: This example only contains features the advanced version doesn't have
 
--NOTE: This example only contains features the advanced version doesn't have
Line 404: Line 78:
 
</source>
 
</source>
  
==Revised version==
+
==Revised version example ==
Warning, this might update more than the others.
 
<source lang="lua">
 
--[[
 
Copyright (c) 2010 Bart van Strien
 
 
 
Permission is hereby granted, free of charge, to any person
 
obtaining a copy of this software and associated documentation
 
files (the "Software"), to deal in the Software without
 
restriction, including without limitation the rights to use,
 
copy, modify, merge, publish, distribute, sublicense, and/or sell
 
copies of the Software, and to permit persons to whom the
 
Software is furnished to do so, subject to the following
 
conditions:
 
 
 
The above copyright notice and this permission notice shall be
 
included in all copies or substantial portions of the Software.
 
 
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 
OTHER DEALINGS IN THE SOFTWARE.
 
]]
 
 
 
__HAS_SECS_COMPATIBLE_CLASSES__ = true
 
 
 
local class_mt = {}
 
 
 
function class_mt:__index(key)
 
if key == "__private" or (rawget(self, "__private") and self.__private[key]) then
 
return nil
 
end
 
if rawget(self, "__baseclass") then
 
return self.__baseclass[key]
 
end
 
return nil
 
end
 
 
 
function class_mt:__call(...)
 
return self:new(...)
 
end
 
 
 
function class_mt:__add(parent)
 
return self:addparent(parent)
 
end
 
 
 
function class_mt:__eq(other)
 
if not other.__baseclass or other.__baseclass ~= self.__baseclass then return false end
 
for i, v in pairs(self) do
 
if not other[i] then
 
return false
 
end
 
end
 
for i, v in pairs(other) do
 
if not self[i] then
 
return false
 
end
 
end
 
return true
 
end
 
 
 
function class_mt:__lt(other)
 
if not other.__baseclass then return false end
 
if rawget(other.__baseclass, "__isparenttable") then
 
for i, v in pairs(other.__baseclass) do
 
if self == v or getmetatable(self).__lt(self, v) then return true end
 
end
 
else
 
if self == other.__baseclass or getmetatable(self).__lt(self, other.__baseclass) then return true end
 
end
 
return false
 
end
 
 
 
function class_mt:__le(other)
 
return (self < other or self == other)
 
end
 
 
 
local pt_mt = {}
 
function pt_mt:__index(key)
 
for i, v in pairs(self) do
 
if i ~= "__isparenttable" and v[key] then
 
return v[key]
 
end
 
end
 
return nil
 
end
 
 
 
class = setmetatable({ __baseclass = {} }, class_mt)
 
 
 
function class:new(...)
 
local c = {}
 
c.__baseclass = self
 
setmetatable(c, getmetatable(self))
 
c:__init(...)
 
return c
 
end
 
 
 
function class:__init(...)
 
local args = {...}
 
if rawget(self, "init") then
 
args = {self:init(...) or ...}
 
end
 
if self.__baseclass.__init then
 
self.__baseclass:__init(unpack(args))
 
end
 
end
 
 
 
function class:convert(t)
 
t.__baseclass = self
 
setmetatable(t, getmetatable(self))
 
return t
 
end
 
 
 
function class:addparent(...)
 
if not rawget(self.__baseclass, "__isparenttable") then
 
local t = {__isparenttable = true, self.__baseclass, ...}
 
self.__baseclass = setmetatable(t, pt_mt)
 
else
 
for i, v in ipairs{...} do
 
table.insert(self.__baseclass, v)
 
end
 
end
 
return self
 
end
 
 
 
function class:setmetamethod(name, value)
 
local mt = getmetatable(self)
 
local newmt = {}
 
for i, v in pairs(mt) do
 
newmt[i] = v
 
end
 
newmt[name] = value
 
setmetatable(self, newmt)
 
end
 
</source>
 
 
 
===Example===
 
 
Same as full.
 
Same as full.
  
 
==See also==
 
==See also==
[[User:Bartbes|Bartbes]], creator and maintainer of SECS.
+
[[User:Bartbes|Bartbes]], creator and maintainer of SECL.
  
 
{{#set:LOVE Version=Any}}
 
{{#set:LOVE Version=Any}}

Latest revision as of 12:04, 16 August 2015

Also known as SECL. This is a simple implementation of classes that works, it's not commented, so it's a nice test of your lua skills.

The current version can always be found in the love-misc-libs repository

Basic version example

require "class" --this assumes you've saved the code above in class.lua

myclass = class:new()
myclass.value = 13
function myclass:setvalue(v)
    self.value = v
end
object = myclass:new()
object:setvalue(128)
--myclass.value is still 13 and object.value is now 128
anotherObject = object:new()
--anotherObject.value is 128

Advanced version example

--NOTE: this example only contains features the basic version doesn't, if you want to see those functions see the basic example
--require it here

--create the tables/classes
cl1 = class:new()
cl2 = class:new()
cl3 = {}

--fill the tables/classes
cl1.val1 = 12
cl2.val2 = 24
cl3.val3 = 48

--create the new merged class
merged = cl1:new()
print(merged.val1, merged.val2, merged.val3) --> 12  nil  nil
merged:addparent(cl2)
print(merged.val1, merged.val2, merged.val3) --> 12  24  nil
--remember cl3 is a normal table, not a class?
class:convert(cl3) --converts the table in place and returns it, so you can use it in expressions
merged:addparent(cl3) --could also be merged:addparent(class:convert(cl3))
print(merged.val1, merged.val2, merged.val3) --> 12  24  48

--convert is part of any class, the parent of the converted class is the class where convert is called from
--NOTE: addparent supports multiple parents at once, the way that it's done here is to serve as an example

Full version example

--NOTE: This example only contains features the advanced version doesn't have
--require it here

cl1 = class() --new is implied
cl2 = class()

cl1.val1 = 12
cl2.val2 = 24

merged = cl1() + cl2 --yes, we can just add cl2 as if we were doing math
print(merged.val1, merged.val2) --> 12  24

if merged > cl1 then
    print("Merged is a derivative of cl1") --which it is, so this is printed
end
if merged > cl2 then
    print("Merged is a derivative of cl2") --it's that as well, so print
end

merged2 = cl1() + cl2  --create another derivative with the same parents
merged2.val1 = 36  --we change one value

if merged == merged2 then
    print("Merged2 is of the same type as merged") --they are the same type, note this only works when changing, when you add or remove values it is considered as a new class
end

Revised version example

Same as full.

See also

Bartbes, creator and maintainer of SECL.