Модуль:Class
Перейти к навигации
Перейти к поиску
{ [1] = 2, [2] = 3, [3] = 5
}
--[[
Функция, создающая классы с множественным наследованием.
Источник: http://lua-users.org/wiki/SimpleLuaClasses.
Создание класса: MyClass = require "Модуль:Class".create {атрибуты}
_init — функция конструирования,
_call — перегрузка круглых скобок для экземпляров класса.
_index — перегрузка квадратных скобок для экземпляров класса.
--]]
-- Dependencies:
local clone = (mw or require 'mw.lua').clone
local serialise = (require 'Module:Test' or require 'Test.lua').serialise
local m = {}
m.create = function (...)
local c = {} -- a new class instance.
c._base = {} -- список базовых классов
c._inits = {} -- конструкторы базовых классов и собственный.
local own_init -- собственный конструктор
-- В общем случае, множественное наследование:
local args = {...}
for _, param in ipairs (args) do
if type (param) == 'function' then
-- Этот параметр -- конструктор:
own_init = param
elseif type (param) == 'table' then
-- Это один из базовых классов. Сделать его глубокую копию:
c = clone (param)
c._base = param._base or {}
c._inits = param._inits or {}
-- и запомнить его конструктор(ы) и дописать к списку базовых классов:
c._base [#c._base + 1] = param
end
end -- for _, param in ipairs (arg)
-- Дописываем к списку конструкторов собственный, чтобы он вызвался последним:
c._inits [#c._inits + 1] = own_init
-- the class will be the metatable for all its objects,
-- and they will look up their methods in it.
c.__index = c
-- expose a constructor which can be called by <classname>(<args>)
local mt = {}
mt.__call = function (class_tbl, ...)
local obj = {}
for key, field in pairs (c) do
if type (field) ~= 'function'
and key ~= '_call' and key ~= '_index' and key ~= '__index' and key ~= '_base' and key ~= '_inits' then
obj [key] = mw.clone (field)
end
end
setmetatable (obj, c)
-- Запись перегруженного оператора () (class:_call ()) в экземпляр класса.
-- Только к моменту первого вызова конструктора _call окончательно установлена,
-- но устанавить __call для метатаблицы нужно только в первый раз:
if not c.__call and class_tbl._call and type (class_tbl._call) == 'function' then
c.__call = class_tbl._call
end
-- Аналогично с class:_index ():
if not c.__index and class_tbl._index and type (class_tbl._index) == 'function' then
c.__index = class_tbl._index
end
-- Вызов конструкторов базовых классов, и в конце собственного:
for _, init in ipairs (class_tbl._inits) do
if type (init) == 'function' then
init (obj, ...)
end
end
return obj
end
-- Внесение _init () в таблицу _inits:
mt.__newindex = function (class_tbl, key, value)
if key == '_init' and type (value) == 'function' then
class_tbl._inits [#class_tbl._inits + 1] = value
else
rawset (class_tbl, key, value)
end
end -- mt.__newindex = function (class_tbl, key, value)
c.is_a = function (self, class)
if not class then
return false
end
local m = getmetatable (self)
if m == class then
-- объект непосредственно этого класса:
return true
end
-- Проверка базовых классов:
for _, b in ipairs (class._base or {}) do
-- рекурсивный вызов:
if c.is_a (self, b) then
return true
end
end
return false
end -- c.is_a = function (self, class)
setmetatable (c, mt)
return c
end
m.test = function ()
local Array = (require 'Module:Array' or require 'Array.lua').Array
local arr = Array (2, 3, 5)
return serialise (arr)
end
return m