Difference between revisions of "Simple Educative Class Library"

(Remove source)
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.
  

Revision as of 12:14, 7 March 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 SECS.