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 11: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.
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.