]> git.e2factory.org Git - e2factory.git/commitdiff
add middleclass
authorTobias Ulmer <tu@emlix.com>
Thu, 30 Jan 2014 17:29:08 +0000 (18:29 +0100)
committerTobias Ulmer <tu@emlix.com>
Wed, 16 Nov 2016 14:41:17 +0000 (15:41 +0100)
Signed-off-by: Tobias Ulmer <tu@emlix.com>
3RDPARTY
generic/class.lua [new file with mode: 0644]

index 58d7417bcb3054ea7c633a7af922bd1c32b7edf0..ba37b8a6edb6bea917ea74b55b271daa62d4cb8b 100644 (file)
--- a/3RDPARTY
+++ b/3RDPARTY
@@ -11,3 +11,6 @@ Lua is used for e2factory as well as LDoc:
 
 SHA-1 implementation by Steve Reid:
  - generic/sha1.c
+
+Middleclass by Enrique García Cota
+ - generic/class.lua
diff --git a/generic/class.lua b/generic/class.lua
new file mode 100644 (file)
index 0000000..9525ca5
--- /dev/null
@@ -0,0 +1,181 @@
+local middleclass = {
+  _VERSION     = 'middleclass v3.0.1',
+  _DESCRIPTION = 'Object Orientation for Lua',
+  _LICENSE     = [[
+    MIT LICENSE
+
+    Copyright (c) 2011 Enrique García Cota
+
+    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 function _setClassDictionariesMetatables(aClass)
+  local dict = aClass.__instanceDict
+  dict.__index = dict
+
+  local super = aClass.super
+  if super then
+    local superStatic = super.static
+    setmetatable(dict, super.__instanceDict)
+    setmetatable(aClass.static, { __index = function(_,k) return dict[k] or superStatic[k] end })
+  else
+    setmetatable(aClass.static, { __index = function(_,k) return dict[k] end })
+  end
+end
+
+local function _setClassMetatable(aClass)
+  setmetatable(aClass, {
+    __tostring = function() return "class " .. aClass.name end,
+    __index    = aClass.static,
+    __newindex = aClass.__instanceDict,
+    __call     = function(self, ...) return self:new(...) end
+  })
+end
+
+local function _createClass(name, super)
+  local aClass = { name = name, super = super, static = {}, __mixins = {}, __instanceDict={} }
+  aClass.subclasses = setmetatable({}, {__mode = "k"})
+
+  _setClassDictionariesMetatables(aClass)
+  _setClassMetatable(aClass)
+
+  return aClass
+end
+
+local function _createLookupMetamethod(aClass, name)
+  return function(...)
+    local method = aClass.super[name]
+    assert( type(method)=='function', tostring(aClass) .. " doesn't implement metamethod '" .. name .. "'" )
+    return method(...)
+  end
+end
+
+local function _setClassMetamethods(aClass)
+  for _,m in ipairs(aClass.__metamethods) do
+    aClass[m]= _createLookupMetamethod(aClass, m)
+  end
+end
+
+local function _setDefaultInitializeMethod(aClass, super)
+  aClass.initialize = function(instance, ...)
+    return super.initialize(instance, ...)
+  end
+end
+
+local function _includeMixin(aClass, mixin)
+  assert(type(mixin)=='table', "mixin must be a table")
+  for name,method in pairs(mixin) do
+    if name ~= "included" and name ~= "static" then aClass[name] = method end
+  end
+  if mixin.static then
+    for name,method in pairs(mixin.static) do
+      aClass.static[name] = method
+    end
+  end
+  if type(mixin.included)=="function" then mixin:included(aClass) end
+  aClass.__mixins[mixin] = true
+end
+
+local Object = _createClass("Object", nil)
+
+Object.static.__metamethods = { '__add', '__call', '__concat', '__div', '__ipairs', '__le',
+                                '__len', '__lt', '__mod', '__mul', '__pairs', '__pow', '__sub',
+                                '__tostring', '__unm'}
+
+function Object.static:allocate()
+  assert(type(self) == 'table', "Make sure that you are using 'Class:allocate' instead of 'Class.allocate'")
+  return setmetatable({ class = self }, self.__instanceDict)
+end
+
+function Object.static:new(...)
+  local instance = self:allocate()
+  instance:initialize(...)
+  return instance
+end
+
+function Object.static:subclass(name)
+  assert(type(self) == 'table', "Make sure that you are using 'Class:subclass' instead of 'Class.subclass'")
+  assert(type(name) == "string", "You must provide a name(string) for your class")
+
+  local subclass = _createClass(name, self)
+  _setClassMetamethods(subclass)
+  _setDefaultInitializeMethod(subclass, self)
+  self.subclasses[subclass] = true
+  self:subclassed(subclass)
+
+  return subclass
+end
+
+function Object.static:subclassed(other) end
+
+function Object.static:isSubclassOf(other)
+  return type(other)                   == 'table' and
+         type(self)                    == 'table' and
+         type(self.super)              == 'table' and
+         ( self.super == other or
+           type(self.super.isSubclassOf) == 'function' and
+           self.super:isSubclassOf(other)
+         )
+end
+
+function Object.static:include( ... )
+  assert(type(self) == 'table', "Make sure you that you are using 'Class:include' instead of 'Class.include'")
+  for _,mixin in ipairs({...}) do _includeMixin(self, mixin) end
+  return self
+end
+
+function Object.static:includes(mixin)
+  return type(mixin)          == 'table' and
+         type(self)           == 'table' and
+         type(self.__mixins)  == 'table' and
+         ( self.__mixins[mixin] or
+           type(self.super)           == 'table' and
+           type(self.super.includes)  == 'function' and
+           self.super:includes(mixin)
+         )
+end
+
+function Object:initialize() end
+
+function Object:__tostring() return "instance of " .. tostring(self.class) end
+
+function Object:isInstanceOf(aClass)
+  return type(self)                == 'table' and
+         type(self.class)          == 'table' and
+         type(aClass)              == 'table' and
+         ( aClass == self.class or
+           type(aClass.isSubclassOf) == 'function' and
+           self.class:isSubclassOf(aClass)
+         )
+end
+
+
+
+function middleclass.class(name, super, ...)
+  super = super or Object
+  return super:subclass(name, ...)
+end
+
+middleclass.Object = Object
+
+setmetatable(middleclass, { __call = function(_, ...) return middleclass.class(...) end })
+
+return middleclass