Difference between revisions of "Simple Educative Class Library"
(Add common.instance) |
|||
Line 128: | Line 128: | ||
</source> | </source> | ||
+ | {{notice|It's likely versions below this are bugged. Sorry about that!}} | ||
==Advanced version== | ==Advanced version== | ||
<source lang="lua"> | <source lang="lua"> |
Revision as of 10:00, 1 August 2014
Also known as SECS (pronounce as 'sex'). 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.
Contents
Basic version
--[[
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
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
Class Commons enabled basic version
--[[
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
It's likely versions below this are bugged. Sorry about that! |
Advanced version
--[[
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
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 (AKA overcomplicated)
--[[
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
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
Warning, this might update more than the others.
--[[
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
Example
Same as full.
See also
Bartbes, creator and maintainer of SECS.