Advertisement
airevent

Lua object model

Sep 28th, 2012
42
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 5.30 KB | None | 0 0
  1. -- lua-object-model
  2.  
  3. oop = {}
  4. new = {}
  5. class = {}
  6.  
  7.  
  8.  
  9. -- является ли сущность классом
  10. function oop.is_class( essence )
  11.     local mt = getmetatable(essence)
  12.     return mt and mt.class and true or false
  13. end
  14.  
  15.  
  16.  
  17. -- является ли сущность объектом
  18. function oop.is_object( essence )
  19.     local mt = getmetatable(essence)
  20.     return mt and mt.instance and true or false
  21. end
  22.  
  23. -- алиасы
  24. oop.is_obj      = oop.is_object
  25. oop.is_instance = oop.is_object
  26.  
  27.  
  28.  
  29. -- является ли сущность объектом класса
  30. function oop.instanceof( instance, class )
  31.     local imt, cmt = getmetatable(instance), getmetatable(class)
  32.     return imt and imt.instance and cmt and cmt.class and
  33.         imt.instance == cmt.class and true or false
  34. end
  35.  
  36.  
  37.  
  38. -- клонирует сущность
  39. -- lib - уже склонированные таблицы для создания ссылок на клонов
  40. function oop.clone( essence, lib )
  41.     if type(essence) ~= "table" then
  42.         -- не клонирует примитивные типы и юзердату
  43.         return essence
  44.     elseif oop.is_class(essence) then
  45.         -- не клонирует классы
  46.         return essence
  47.     elseif oop.is_object(essence) then
  48.         -- для объектов вызвать собственный метод
  49.         return getmetatable(essence).__clone(essence, lib)
  50.     else
  51.         -- начать клонирование
  52.         lib = lib or {}
  53.  
  54.         if lib[essence] then -- уже клонировали этот элемент
  55.             return lib[essence]
  56.         end
  57.  
  58.         local copy = {}
  59.         lib[essence] = copy -- запомнить
  60.  
  61.         for k,v in pairs(essence) do
  62.             copy[oop.clone(k, lib)] = oop.clone(v, lib)
  63.         end
  64.  
  65.         -- копировать метатаблицу именно после клонирования!
  66.         setmetatable(copy, getmetatable(essence))
  67.  
  68.         return copy
  69.     end
  70. end
  71.  
  72.  
  73.  
  74. -- создать объект класса
  75. -- local obj = new:A{ ... }
  76. setmetatable(new, {
  77.     __index = function( _, name ) -- _=new
  78.         local class = rawget(_G, name)
  79.         local mt = getmetatable(class)
  80.         return mt and mt.__new or
  81.             error("Undefined class: '" .. name .. "'")
  82.     end
  83. })
  84.  
  85.  
  86.  
  87. -- создать класс
  88. -- local c,p = class:A{ a=1, b=2 } : extends{ B, C }
  89. -- c - class, p - class prototype
  90. setmetatable(class, {
  91.     __index = function( _, name ) -- _=class
  92.         local c = {} -- class
  93.         local c_mt = {} -- class metatable
  94.         local p_mt = {} -- prototype metatable
  95.         local i_mt = {} -- instance metatable
  96.  
  97.         rawset(_G, name, c) -- сделать глобальным
  98.  
  99.         c.prototype = {} -- public, private, protected
  100.         c_mt.parents = {} -- список родителей
  101.         c_mt.class = name -- имя класса
  102.         c_mt.imt = i_mt -- для быстрого доступа
  103.         i_mt.instance = name -- имя класса-создателя
  104.  
  105.         local p = c.prototype -- alias
  106.  
  107.         setmetatable(c, c_mt)
  108.         setmetatable(p, p_mt)
  109.  
  110.         function p:init() end -- конструктор
  111.  
  112.         -- объявить о своих родителях
  113.         function c:extends( parents )
  114.             for i,v in ipairs(parents) do
  115.                 c_mt.parents[i] = v
  116.             end
  117.  
  118.             -- запретить дальнейшее добавление родителей
  119.             c.extends = nil
  120.  
  121.             return c,p
  122.         end
  123.  
  124.         -- добавить свойства при создании класса
  125.         function c_mt:__call( _, properties )
  126.             for k,v in pairs(properties) do
  127.                 p[k] = v
  128.             end
  129.  
  130.             -- запретить дальнейшее добавление свойств
  131.             c_mt.__call = nil
  132.  
  133.             return c,p
  134.         end
  135.  
  136.          -- создать объект
  137.         function c_mt:__new( properties )
  138.             local instance = {} -- объект
  139.  
  140.             instance.prototype = c.prototype
  141.  
  142.             setmetatable(instance, i_mt)
  143.  
  144.             for k,v in pairs(properties) do
  145.                 instance[k] = v
  146.             end
  147.  
  148.             instance:init() -- конструктор
  149.  
  150.             return instance
  151.         end
  152.  
  153.         -- поиск в родителях (статические члены)
  154.         function c_mt:__index( k )
  155.             -- последний родитель приоритетнее
  156.             for i=#c_mt.parents,1,-1 do
  157.                 local v = c_mt.parents[i][k]
  158.                 if v ~= nil then
  159.                     c[k] = oop.clone(v)
  160.                     return c[k]
  161.                 end
  162.             end
  163.         end
  164.  
  165.         -- поиск в родителях (прототип)
  166.         function p_mt:__index( k )
  167.             -- последний родитель приоритетнее
  168.             for i=#c_mt.parents,1,-1 do
  169.                 local v = c_mt.parents[i].prototype[k]
  170.                 if v ~= nil then
  171.                     self[k] = oop.clone(v)
  172.                     return self[k]
  173.                 end
  174.             end
  175.         end
  176.  
  177.         -- поиск в создателе
  178.         function i_mt:__index( k )
  179.             local v = oop.clone(p[k])
  180.  
  181.             if v == nil then
  182.                 error(string.format("Undefined property: %s.%s",
  183.                     name, tostring(k)))
  184.             end
  185.  
  186.             rawset(self, k, v) -- избежать __newindex
  187.             return self[k]
  188.         end
  189.  
  190.         -- запретить случайно создавать члены
  191.         function i_mt:__newindex( k, v )
  192.             if p[k] == nil then
  193.                 error(string.format("Pollution: %s.%s = '%s'",
  194.                     name, tostring(k), tostring(v)))
  195.             end
  196.  
  197.             rawset(self, k, v) -- избежать рекурсии
  198.         end
  199.  
  200.         -- порядок клонирования/копирования
  201.         function i_mt:__clone( lib )
  202.             return self -- не клонировать по-умолчанию
  203.         end
  204.  
  205.         return c
  206.     end
  207. })
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement