Home | History | Annotate | Download | only in vendor
      1 local middleclass = {
      2   _VERSION     = 'middleclass v4.0.0',
      3   _DESCRIPTION = 'Object Orientation for Lua',
      4   _URL         = 'https://github.com/kikito/middleclass',
      5   _LICENSE     = [[
      6     MIT LICENSE
      7 
      8     Copyright (c) 2011 Enrique Garca Cota
      9 
     10     Permission is hereby granted, free of charge, to any person obtaining a
     11     copy of this software and associated documentation files (the
     12     "Software"), to deal in the Software without restriction, including
     13     without limitation the rights to use, copy, modify, merge, publish,
     14     distribute, sublicense, and/or sell copies of the Software, and to
     15     permit persons to whom the Software is furnished to do so, subject to
     16     the following conditions:
     17 
     18     The above copyright notice and this permission notice shall be included
     19     in all copies or substantial portions of the Software.
     20 
     21     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     22     OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     23     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     24     IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
     25     CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     26     TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     27     SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     28   ]]
     29 }
     30 
     31 local function _createIndexWrapper(aClass, f)
     32   if f == nil then
     33     return aClass.__instanceDict
     34   else
     35     return function(self, name)
     36       local value = aClass.__instanceDict[name]
     37 
     38       if value ~= nil then
     39         return value
     40       elseif type(f) == "function" then
     41         return (f(self, name))
     42       else
     43         return f[name]
     44       end
     45     end
     46   end
     47 end
     48 
     49 local function _propagateInstanceMethod(aClass, name, f)
     50   f = name == "__index" and _createIndexWrapper(aClass, f) or f
     51   aClass.__instanceDict[name] = f
     52 
     53   for subclass in pairs(aClass.subclasses) do
     54     if rawget(subclass.__declaredMethods, name) == nil then
     55       _propagateInstanceMethod(subclass, name, f)
     56     end
     57   end
     58 end
     59 
     60 local function _declareInstanceMethod(aClass, name, f)
     61   aClass.__declaredMethods[name] = f
     62 
     63   if f == nil and aClass.super then
     64     f = aClass.super.__instanceDict[name]
     65   end
     66 
     67   _propagateInstanceMethod(aClass, name, f)
     68 end
     69 
     70 local function _tostring(self) return "class " .. self.name end
     71 local function _call(self, ...) return self:new(...) end
     72 
     73 local function _createClass(name, super)
     74   local dict = {}
     75   dict.__index = dict
     76 
     77   local aClass = { name = name, super = super, static = {},
     78                    __instanceDict = dict, __declaredMethods = {},
     79                    subclasses = setmetatable({}, {__mode='k'})  }
     80 
     81   if super then
     82     setmetatable(aClass.static, { __index = function(_,k) return rawget(dict,k) or super.static[k] end })
     83   else
     84     setmetatable(aClass.static, { __index = function(_,k) return rawget(dict,k) end })
     85   end
     86 
     87   setmetatable(aClass, { __index = aClass.static, __tostring = _tostring,
     88                          __call = _call, __newindex = _declareInstanceMethod })
     89 
     90   return aClass
     91 end
     92 
     93 local function _includeMixin(aClass, mixin)
     94   assert(type(mixin) == 'table', "mixin must be a table")
     95 
     96   for name,method in pairs(mixin) do
     97     if name ~= "included" and name ~= "static" then aClass[name] = method end
     98   end
     99 
    100   for name,method in pairs(mixin.static or {}) do
    101     aClass.static[name] = method
    102   end
    103 
    104   if type(mixin.included)=="function" then mixin:included(aClass) end
    105   return aClass
    106 end
    107 
    108 local DefaultMixin = {
    109   __tostring   = function(self) return "instance of " .. tostring(self.class) end,
    110 
    111   initialize   = function(self, ...) end,
    112 
    113   isInstanceOf = function(self, aClass)
    114     return type(self)       == 'table' and
    115            type(self.class) == 'table' and
    116            type(aClass)     == 'table' and
    117            ( aClass == self.class or
    118              type(aClass.isSubclassOf) == 'function' and
    119              self.class:isSubclassOf(aClass) )
    120   end,
    121 
    122   static = {
    123     allocate = function(self)
    124       assert(type(self) == 'table', "Make sure that you are using 'Class:allocate' instead of 'Class.allocate'")
    125       return setmetatable({ class = self }, self.__instanceDict)
    126     end,
    127 
    128     new = function(self, ...)
    129       assert(type(self) == 'table', "Make sure that you are using 'Class:new' instead of 'Class.new'")
    130       local instance = self:allocate()
    131       instance:initialize(...)
    132       return instance
    133     end,
    134 
    135     subclass = function(self, name)
    136       assert(type(self) == 'table', "Make sure that you are using 'Class:subclass' instead of 'Class.subclass'")
    137       assert(type(name) == "string", "You must provide a name(string) for your class")
    138 
    139       local subclass = _createClass(name, self)
    140 
    141       for methodName, f in pairs(self.__instanceDict) do
    142         _propagateInstanceMethod(subclass, methodName, f)
    143       end
    144       subclass.initialize = function(instance, ...) return self.initialize(instance, ...) end
    145 
    146       self.subclasses[subclass] = true
    147       self:subclassed(subclass)
    148 
    149       return subclass
    150     end,
    151 
    152     subclassed = function(self, other) end,
    153 
    154     isSubclassOf = function(self, other)
    155       return type(other)      == 'table' and
    156              type(self)       == 'table' and
    157              type(self.super) == 'table' and
    158              ( self.super == other or
    159                type(self.super.isSubclassOf) == 'function' and
    160                self.super:isSubclassOf(other) )
    161     end,
    162 
    163     include = function(self, ...)
    164       assert(type(self) == 'table', "Make sure you that you are using 'Class:include' instead of 'Class.include'")
    165       for _,mixin in ipairs({...}) do _includeMixin(self, mixin) end
    166       return self
    167     end
    168   }
    169 }
    170 
    171 function middleclass.class(name, super)
    172   assert(type(name) == 'string', "A name (string) is needed for the new class")
    173   return super and super:subclass(name) or _includeMixin(_createClass(name), DefaultMixin)
    174 end
    175 
    176 setmetatable(middleclass, { __call = function(_, ...) return middleclass.class(...) end })
    177 
    178 return middleclass
    179