Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- lua-object-model
- oop = {}
- new = {}
- class = {}
- -- является ли сущность классом
- function oop.is_class( essence )
- local mt = getmetatable(essence)
- return mt and mt.class and true or false
- end
- -- является ли сущность объектом
- function oop.is_object( essence )
- local mt = getmetatable(essence)
- return mt and mt.instance and true or false
- end
- -- алиасы
- oop.is_obj = oop.is_object
- oop.is_instance = oop.is_object
- -- является ли сущность объектом класса
- function oop.instanceof( instance, class )
- local imt, cmt = getmetatable(instance), getmetatable(class)
- return imt and imt.instance and cmt and cmt.class and
- imt.instance == cmt.class and true or false
- end
- -- клонирует сущность
- -- lib - уже склонированные таблицы для создания ссылок на клонов
- function oop.clone( essence, lib )
- if type(essence) ~= "table" then
- -- не клонирует примитивные типы и юзердату
- return essence
- elseif oop.is_class(essence) then
- -- не клонирует классы
- return essence
- elseif oop.is_object(essence) then
- -- для объектов вызвать собственный метод
- return getmetatable(essence).__clone(essence, lib)
- else
- -- начать клонирование
- lib = lib or {}
- if lib[essence] then -- уже клонировали этот элемент
- return lib[essence]
- end
- local copy = {}
- lib[essence] = copy -- запомнить
- for k,v in pairs(essence) do
- copy[oop.clone(k, lib)] = oop.clone(v, lib)
- end
- -- копировать метатаблицу именно после клонирования!
- setmetatable(copy, getmetatable(essence))
- return copy
- end
- end
- -- создать объект класса
- -- local obj = new:A{ ... }
- setmetatable(new, {
- __index = function( _, name ) -- _=new
- local class = rawget(_G, name)
- local mt = getmetatable(class)
- return mt and mt.__new or
- error("Undefined class: '" .. name .. "'")
- end
- })
- -- создать класс
- -- local c,p = class:A{ a=1, b=2 } : extends{ B, C }
- -- c - class, p - class prototype
- setmetatable(class, {
- __index = function( _, name ) -- _=class
- local c = {} -- class
- local c_mt = {} -- class metatable
- local p_mt = {} -- prototype metatable
- local i_mt = {} -- instance metatable
- rawset(_G, name, c) -- сделать глобальным
- c.prototype = {} -- public, private, protected
- c_mt.parents = {} -- список родителей
- c_mt.class = name -- имя класса
- c_mt.imt = i_mt -- для быстрого доступа
- i_mt.instance = name -- имя класса-создателя
- local p = c.prototype -- alias
- setmetatable(c, c_mt)
- setmetatable(p, p_mt)
- function p:init() end -- конструктор
- -- объявить о своих родителях
- function c:extends( parents )
- for i,v in ipairs(parents) do
- c_mt.parents[i] = v
- end
- -- запретить дальнейшее добавление родителей
- c.extends = nil
- return c,p
- end
- -- добавить свойства при создании класса
- function c_mt:__call( _, properties )
- for k,v in pairs(properties) do
- p[k] = v
- end
- -- запретить дальнейшее добавление свойств
- c_mt.__call = nil
- return c,p
- end
- -- создать объект
- function c_mt:__new( properties )
- local instance = {} -- объект
- instance.prototype = c.prototype
- setmetatable(instance, i_mt)
- for k,v in pairs(properties) do
- instance[k] = v
- end
- instance:init() -- конструктор
- return instance
- end
- -- поиск в родителях (статические члены)
- function c_mt:__index( k )
- -- последний родитель приоритетнее
- for i=#c_mt.parents,1,-1 do
- local v = c_mt.parents[i][k]
- if v ~= nil then
- c[k] = oop.clone(v)
- return c[k]
- end
- end
- end
- -- поиск в родителях (прототип)
- function p_mt:__index( k )
- -- последний родитель приоритетнее
- for i=#c_mt.parents,1,-1 do
- local v = c_mt.parents[i].prototype[k]
- if v ~= nil then
- self[k] = oop.clone(v)
- return self[k]
- end
- end
- end
- -- поиск в создателе
- function i_mt:__index( k )
- local v = oop.clone(p[k])
- if v == nil then
- error(string.format("Undefined property: %s.%s",
- name, tostring(k)))
- end
- rawset(self, k, v) -- избежать __newindex
- return self[k]
- end
- -- запретить случайно создавать члены
- function i_mt:__newindex( k, v )
- if p[k] == nil then
- error(string.format("Pollution: %s.%s = '%s'",
- name, tostring(k), tostring(v)))
- end
- rawset(self, k, v) -- избежать рекурсии
- end
- -- порядок клонирования/копирования
- function i_mt:__clone( lib )
- return self -- не клонировать по-умолчанию
- end
- return c
- end
- })
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement