Advertisement
Xetrill

middleclass.lua

May 26th, 2014
343
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 6.62 KB | None | 0 0
  1. local _G
  2.     = _G
  3. local setmetatable, assert, type, tostring, pairs, sprintf
  4.     = setmetatable, assert, type, tostring, pairs, string.format
  5.  
  6. local middleclass = {
  7.     _VERSION        = 'middleclass v3.0.0',
  8.     _DESCRIPTION    = 'Object Orientation for Lua',
  9.     _LICENSE        = [[
  10.         MIT LICENSE
  11.  
  12.         Copyright (c) 2011 Enrique García Cota
  13.  
  14.         Permission is hereby granted, free of charge, to any person obtaining a
  15.         copy of this software and associated documentation files (the
  16.         "Software"), to deal in the Software without restriction, including
  17.         without limitation the rights to use, copy, modify, merge, publish,
  18.         distribute, sublicense, and/or sell copies of the Software, and to
  19.         permit persons to whom the Software is furnished to do so, subject to
  20.         the following conditions:
  21.  
  22.         The above copyright notice and this permission notice shall be included
  23.         in all copies or substantial portions of the Software.
  24.  
  25.         THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  26.         OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  27.         MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  28.         IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  29.         CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  30.         TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  31.         SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.]]
  32. }
  33.  
  34. local function _setClassDictionariesMetatables(aClass)
  35.     local dict = aClass.__instanceDict
  36.     dict.__index = dict
  37.  
  38.     local super = aClass.super
  39.     if super then
  40.         local superStatic = super.static
  41.         setmetatable(dict, super.__instanceDict)
  42.         setmetatable(aClass.static, { __index = function(_, k) return dict[k] or superStatic[k] end })
  43.     else
  44.         setmetatable(aClass.static, { __index = function(_, k) return dict[k] end })
  45.     end
  46. end
  47.  
  48. local function _setClassMetatable(aClass)
  49.     setmetatable(aClass, {
  50.         __tostring = function() return sprintf("class %s", aClass.name) end,
  51.         __index    = aClass.static,
  52.         __newindex = aClass.__instanceDict,
  53.         __call     = function(self, ...) return self:new(...) end
  54.     })
  55. end
  56.  
  57. local function _createClass(name, super)
  58.     local aClass = {
  59.         name           = name,
  60.         super          = super,
  61.         static         = {},
  62.         __mixins       = {},
  63.         __instanceDict = {}
  64.     }
  65.     aClass.subclasses = setmetatable({}, { __mode = 'k' })
  66.  
  67.     _setClassDictionariesMetatables(aClass)
  68.     _setClassMetatable(aClass)
  69.  
  70.     return aClass
  71. end
  72.  
  73. local function _createLookupMetaMethod(aClass, name)
  74.     return function(...)
  75.         local method = aClass.super[name]
  76.         assert(type(method) == 'function',
  77.                sprintf("class '%s' doesn't implement metamethod '%s'", tostring(aClass), name))
  78.         return method(...)
  79.     end
  80. end
  81.  
  82. local function _setClassMetamethods(aClass)
  83.     for _, m in ipairs(aClass.__metamethods) do
  84.         aClass[m]= _createLookupMetaMethod(aClass, m)
  85.     end
  86. end
  87.  
  88. local function _setDefaultInitializeMethod(aClass, super)
  89.     aClass.__init = function(instance, ...)
  90.         return super.__init(instance, ...)
  91.     end
  92. end
  93.  
  94. local function _includeMixin(aClass, mixin)
  95.     assert(type(mixin) == 'table',
  96.            "mixin must be a table")
  97.  
  98.     for name, method in pairs(mixin) do
  99.         if name ~= 'included' and name ~= 'static' then
  100.             aClass[name] = method
  101.         end
  102.     end
  103.  
  104.     if mixin.static then
  105.         for name, method in pairs(mixin.static) do
  106.             aClass.static[name] = method
  107.         end
  108.     end
  109.  
  110.     if type(mixin.included) == 'function' then
  111.         mixin:included(aClass)
  112.     end
  113.  
  114.     aClass.__mixins[mixin] = true
  115. end
  116.  
  117.  
  118. local Object = _createClass("Object", nil)
  119.  
  120. Object.static.__metamethods = {
  121.     '__add',
  122.     '__call',
  123.     '__concat',
  124.     '__div',
  125.     '__le',
  126.     '__lt',
  127.     '__mod',
  128.     '__mul',
  129.     '__pow',
  130.     '__sub',
  131.     '__tostring',
  132.     '__unm'
  133. }
  134.  
  135. function Object.static:allocate()
  136.     assert(type(self) == 'table',
  137.            "Make sure that you are using 'Class:allocate' instead of 'Class.allocate'")
  138.  
  139.     return setmetatable({ class = self }, self.__instanceDict)
  140. end
  141.  
  142. function Object.static:new(...)
  143.     local instance = self:allocate()
  144.     instance:__init(...)
  145.     return instance
  146. end
  147.  
  148. function Object.static:subclass(name)
  149.     assert(type(self) == 'table',
  150.            "Make sure that you are using 'Class:subclass' instead of 'Class.subclass'")
  151.     assert(type(name) == "string",
  152.            "You must provide a name(string) for your class")
  153.  
  154.     local subclass = _createClass(name, self)
  155.     _setClassMetamethods(subclass)
  156.     _setDefaultInitializeMethod(subclass, self)
  157.     self.subclasses[subclass] = true
  158.     self:subclassed(subclass)
  159.  
  160.     return subclass
  161. end
  162.  
  163. function Object.static:subclassed(other)
  164. end
  165.  
  166. function Object.static:isSubclassOf(other)
  167.     return (
  168.         type(other)      == 'table' and
  169.         type(self)       == 'table' and
  170.         type(self.super) == 'table' and
  171.         (
  172.             self.super == other
  173.             or
  174.             type(self.super.isSubclassOf) == 'function' and
  175.             self.super:isSubclassOf(other)
  176.         )
  177.     )
  178. end
  179.  
  180. function Object.static:include(...)
  181.     assert(type(self) == 'table',
  182.            "Make sure you that you are using 'Class:include' instead of 'Class.include'")
  183.  
  184.     local l = select('#', ...)
  185.     for i = 1, l do
  186.         _includeMixin(self, select(i, ...))
  187.     end
  188.     return self
  189. end
  190.  
  191. function Object.static:includes(mixin)
  192.     return (
  193.         type(mixin)         == 'table' and
  194.         type(self)          == 'table' and
  195.         type(self.__mixins) == 'table' and
  196.         (
  197.             self.__mixins[mixin]
  198.             or
  199.             type(self.super) == 'table' and
  200.             type(self.super.includes) == 'function' and
  201.             self.super:includes(mixin)
  202.         )
  203.     )
  204. end
  205.  
  206. function Object:__init()
  207. end
  208.  
  209. function Object:__tostring()
  210.     return sprintf("instance of %s", tostring(self.class))
  211. end
  212.  
  213. function Object:isInstanceOf(aClass)
  214.     return (
  215.         type(aClass)     == 'table' and
  216.         type(self)       == 'table' and
  217.         type(self.class) == 'table' and
  218.         (
  219.             aClass == self.class
  220.             or
  221.             type(aClass.isSubclassOf) == 'function' and
  222.             self.class:isSubclassOf(aClass)
  223.         )
  224.     )
  225. end
  226.  
  227. function Object:_areFieldsEqual(other, ...)
  228.     local l = select('#', ...)
  229.     for i = 1, l do
  230.         if self[select(i, ...)] ~= other[select(i, ...)] then
  231.             return false
  232.         end
  233.     end
  234.     return true
  235. end
  236.  
  237. function Object:_isEquatableTo(other)
  238.     return (
  239.         type(other)       == 'table' and
  240.         type(other.class) == 'table' and
  241.         (
  242.             other.class == self.class
  243.             or
  244.             type(other.isSubclassOf) == 'function' and
  245.             other:isSubclassOf(self.class)
  246.         )
  247.     )
  248. end
  249.  
  250. function Object:_isEqualTo(other, ...)
  251.     return (
  252.         self:_isEquatableTo(other) and
  253.         self:_areFieldsEqual(other, ...)
  254.     )
  255. end
  256.  
  257.  
  258. function middleclass.class(name, super, ...)
  259.     super = super or Object
  260.     return super:subclass(name, ...)
  261. end
  262.  
  263. middleclass.Object = Object
  264.  
  265. setmetatable(middleclass, {
  266.     __call = function(_, ...)
  267.         return middleclass.class(...)
  268.     end
  269. })
  270.  
  271. return middleclass
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement