<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://mywikibiz.com/index.php?action=history&amp;feed=atom&amp;title=Module%3ALua_class</id>
	<title>Module:Lua class - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://mywikibiz.com/index.php?action=history&amp;feed=atom&amp;title=Module%3ALua_class"/>
	<link rel="alternate" type="text/html" href="https://mywikibiz.com/index.php?title=Module:Lua_class&amp;action=history"/>
	<updated>2026-06-22T16:33:04Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.35.3</generator>
	<entry>
		<id>https://mywikibiz.com/index.php?title=Module:Lua_class&amp;diff=478660&amp;oldid=prev</id>
		<title>Zoran: Pywikibot 6.4.0</title>
		<link rel="alternate" type="text/html" href="https://mywikibiz.com/index.php?title=Module:Lua_class&amp;diff=478660&amp;oldid=prev"/>
		<updated>2021-07-16T04:44:53Z</updated>

		<summary type="html">&lt;p&gt;Pywikibot 6.4.0&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;libraryUtil = require('libraryUtil') -- overridden for new types and exceptions&lt;br /&gt;
&lt;br /&gt;
local classes, instances = {}, {} -- registry of all complete/internal class and instance objects (with some exceptions)&lt;br /&gt;
local inst_private_mts, inst_public_mts = {}, {} -- for each class since they are immutable&lt;br /&gt;
&lt;br /&gt;
local una_metamethods = {__ipairs=1, __pairs=1, __tostring=1, __unm=1}&lt;br /&gt;
local bin_metamethods = {__add=1, __concat=1, __div=1, __eq=1, __le=1, __lt=1, __mod=1, __mul=1, __pow=1, __sub=1}&lt;br /&gt;
local oth_metamethods = {__call=1, __index=1, __newindex=1, __init=1}&lt;br /&gt;
local not_metamethods = {__name=1, __bases=1, __methods=1, __slots=1, __protected=1} -- and __class&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function private_read(self_private, key)&lt;br /&gt;
	if not not_metamethods[key] then&lt;br /&gt;
		return instances[self_private][key] -- instance should be clean of misbahaved keys so that __index(cls_private, key) handles it&lt;br /&gt;
	end&lt;br /&gt;
	error(('AttributeError: unauthorized read attempt of internal &amp;quot;%s&amp;quot;'):format(key), 2)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function private_read_custom(self_private, key)&lt;br /&gt;
	if not not_metamethods[key] then&lt;br /&gt;
		local self = instances[self_private]&lt;br /&gt;
		local value = self.__class.__index(self_private, key) -- custom __index can handle misbehaved keys&lt;br /&gt;
		if value == nil then&lt;br /&gt;
			value = self[key] -- same reason of private_read for not checking key type&lt;br /&gt;
		end&lt;br /&gt;
		return value&lt;br /&gt;
	end&lt;br /&gt;
	error(('AttributeError: unauthorized read attempt of internal &amp;quot;%s&amp;quot;'):format(key), 2)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function private_write(self_private, key, value)&lt;br /&gt;
	libraryUtil.checkTypeMultiForIndex(key, {'string', 'number'})&lt;br /&gt;
	local self = instances[self_private]&lt;br /&gt;
	if tonumber(key) or not classes[self.__class].__methods[key] and key:sub(1,2) ~= '__' then&lt;br /&gt;
		self[key] = value&lt;br /&gt;
	else&lt;br /&gt;
		error(('AttributeError: forbidden write attempt {%s: %s} to immutable instance method'):format(key, tostring(value)), 2)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function private_write_custom(self_private, key, value)&lt;br /&gt;
	local self = instances[self_private]&lt;br /&gt;
	if type(key) ~= 'string' or not classes[self.__class].__methods[key] and key:sub(1,2) ~= '__' then&lt;br /&gt;
		if not self.__class.__newindex(self_private, key, value) then -- custom __newindex can handle misbehaved keys&lt;br /&gt;
			libraryUtil.checkTypeMultiForIndex(key, {'string', 'number'})&lt;br /&gt;
			self[key] = value&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		error(('AttributeError: forbidden write attempt {%s: %s} to immutable instance method'):format(key, tostring(value)), 2)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function objtostr(obj)&lt;br /&gt;
	local copy = {}&lt;br /&gt;
	for key, val in pairs(obj) do&lt;br /&gt;
		copy[key] = type(val) == 'function' and 'function' or val&lt;br /&gt;
	end&lt;br /&gt;
	return mw.text.jsonEncode(copy, mw.text.JSON_PRETTY)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local inst_mt = {&lt;br /&gt;
	__index = function (self, key)&lt;br /&gt;
		if tonumber(key) then&lt;br /&gt;
			return nil -- don't search numeric keys in classes&lt;br /&gt;
		end&lt;br /&gt;
		return self.__class[key] -- key could be misbehaved here without issues as __index(cls_private, key) would handle it&lt;br /&gt;
	end,&lt;br /&gt;
	__tostring = objtostr--&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local function public_read(self_public, key)&lt;br /&gt;
	if type(key) ~= 'string' or key:sub(1,1) ~= '_' then&lt;br /&gt;
		return instances[instances[self_public]][key] -- same reason of private_read...&lt;br /&gt;
	end&lt;br /&gt;
	error(('AttributeError: unauthorized read attempt of nonpublic &amp;quot;%s&amp;quot;'):format(key), 2)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function public_read_custom(self_public, key)&lt;br /&gt;
	if type(key) ~= 'string' or key:sub(1,1) ~= '_' then&lt;br /&gt;
		local self = instances[instances[self_public]]&lt;br /&gt;
		local value = self.__class.__index(instances[self_public], key)&lt;br /&gt;
		if value == nil then&lt;br /&gt;
			value = self[key] -- same reason of private_read...&lt;br /&gt;
		end&lt;br /&gt;
		return value&lt;br /&gt;
	end&lt;br /&gt;
	error(('AttributeError: unauthorized read attempt of nonpublic &amp;quot;%s&amp;quot;'):format(key), 2)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function public_write(self_public, key, value)&lt;br /&gt;
	if type(key) == 'string' and key:sub(1,1) == '_' then&lt;br /&gt;
		error(('AttributeError: unauthorized write attempt of nonpublic {%s: %s}'):format(key, tostring(value)), 2)&lt;br /&gt;
	end&lt;br /&gt;
	local self = instances[instances[self_public]]&lt;br /&gt;
	local cls = classes[self.__class]&lt;br /&gt;
	if cls.__methods[key] then&lt;br /&gt;
		error(('AttributeError: forbidden write attempt {%s: %s} to immutable instance method'):format(key, tostring(value)), 2)&lt;br /&gt;
	end&lt;br /&gt;
	if self[key] == nil and not cls.__slots[key] then -- if instance and __slots are valid, no danger of creating misbehaved attributes&lt;br /&gt;
		libraryUtil.checkTypeMultiForIndex(key, {'string', 'number'}) -- otherwise error message would not make sense&lt;br /&gt;
		error(('AttributeError: public attribute creation attempt {%s: %s} not expected by __slots'):format(key, tostring(value)), 2)&lt;br /&gt;
	end&lt;br /&gt;
	self[key] = value&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function public_write_custom(self_public, key, value)&lt;br /&gt;
	if type(key) == 'string' and key:sub(1,1) == '_' then&lt;br /&gt;
		error(('AttributeError: unauthorized write attempt of nonpublic {%s: %s}'):format(key, tostring(value)), 2)&lt;br /&gt;
	end&lt;br /&gt;
	local self = instances[instances[self_public]]&lt;br /&gt;
	local cls = classes[self.__class]&lt;br /&gt;
	if cls.__methods[key] then&lt;br /&gt;
		error(('AttributeError: forbidden write attempt {%s: %s} to immutable instance method'):format(key, tostring(value)), 2)&lt;br /&gt;
	end&lt;br /&gt;
	if not cls.__newindex(instances[self_public], key, value) then&lt;br /&gt;
		if self[key] == nil and not cls.__slots[key] then&lt;br /&gt;
			libraryUtil.checkTypeMultiForIndex(key, {'string', 'number'}) -- otherwise error message...&lt;br /&gt;
			error(('AttributeError: public attribute creation attempt {%s: %s} not expected by __slots'):format(key, tostring(value)), 2)&lt;br /&gt;
		end&lt;br /&gt;
		self[key] = value&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function constructor(wrapper, ...)&lt;br /&gt;
	if select('#', ...) ~= 1 or type(...) ~= 'table' then&lt;br /&gt;
		error('SyntaxError: incorrect instance constructor syntax, should be: Class{arg1, arg2..., kw1=kwarg1, kw2=kwarg2...}', 2)&lt;br /&gt;
	end&lt;br /&gt;
	local self = {} -- __new&lt;br /&gt;
	local cls_private = classes[classes[wrapper]] and classes[wrapper] or wrapper&lt;br /&gt;
	self.__class = cls_private&lt;br /&gt;
&lt;br /&gt;
	local self_private = {} -- wrapper&lt;br /&gt;
	local cls = classes[cls_private]&lt;br /&gt;
&lt;br /&gt;
	local mt = inst_private_mts[cls]&lt;br /&gt;
	if not mt then&lt;br /&gt;
		mt = {}&lt;br /&gt;
		mt.__index = cls.__index and private_read_custom or private_read&lt;br /&gt;
		mt.__newindex = cls.__newindex and private_write_custom or private_write&lt;br /&gt;
		for key in pairs(una_metamethods) do&lt;br /&gt;
			mt[key] = cls[key]&lt;br /&gt;
		end&lt;br /&gt;
		mt.__call = cls.__call&lt;br /&gt;
		mt.__metatable = 'unauthorized access attempt of wrapper object metatable'&lt;br /&gt;
&lt;br /&gt;
		inst_private_mts[cls] = mt&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	setmetatable(self_private, mt)&lt;br /&gt;
	instances[self_private] = self&lt;br /&gt;
&lt;br /&gt;
	local __init = cls.__init&lt;br /&gt;
	if __init and __init(self_private, ...) then&lt;br /&gt;
		error('TypeError: __init must not return a var-list')&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	for key in pairs(cls.__methods) do&lt;br /&gt;
		self[key] = function (...) return cls[key](self_private, ...) end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	setmetatable(self, inst_mt)&lt;br /&gt;
&lt;br /&gt;
	local self_public = {}&lt;br /&gt;
&lt;br /&gt;
	mt = inst_public_mts[cls]&lt;br /&gt;
	if not mt then&lt;br /&gt;
		mt = {}&lt;br /&gt;
		mt.__index = cls.__index and public_read_custom or public_read&lt;br /&gt;
		mt.__newindex = cls.__newindex and public_write_custom or public_write&lt;br /&gt;
		for key in pairs(una_metamethods) do&lt;br /&gt;
			if cls[key] then&lt;br /&gt;
				mt[key] = function (a) return cls[key](instances[a]) end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		for key in pairs(bin_metamethods) do&lt;br /&gt;
			if cls[key] then&lt;br /&gt;
				mt[key] = function (a, b) return cls[key](instances[a], instances[b]) end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		mt.__call = function (self_public, ...) return cls.__call(instances[self_public], ...) end&lt;br /&gt;
		mt.__metatable = 'unauthorized access attempt of wrapper object metatable'&lt;br /&gt;
&lt;br /&gt;
		inst_public_mts[cls] = mt&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	setmetatable(self_public, mt)&lt;br /&gt;
	instances[self_public] = self_private&lt;br /&gt;
	return self_public&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function multi_inheritance(cls, key)&lt;br /&gt;
	for _, base in ipairs(cls.__bases) do&lt;br /&gt;
		if key:sub(1,1) ~= '_' or base.__protected[key] or key:sub(1,2) == '__' and key ~= '__name' then&lt;br /&gt;
			local value = base[key]&lt;br /&gt;
			if value ~= nil then&lt;br /&gt;
				return value&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local cls_mt = {&lt;br /&gt;
	__index = multi_inheritance,&lt;br /&gt;
	__tostring = objtostr--&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local cls_private_mt = {&lt;br /&gt;
	__call = constructor,&lt;br /&gt;
	__index = function (cls_private, key)&lt;br /&gt;
		if not not_metamethods[key] then&lt;br /&gt;
			libraryUtil.checkTypeMultiForIndex(key, {'string'})&lt;br /&gt;
			local cls = classes[cls_private]&lt;br /&gt;
			local value = cls[key]&lt;br /&gt;
			if type(value) == 'table' and not cls.__slots[key] then&lt;br /&gt;
				return mw.clone(value) -- because class attributes are immutable by default&lt;br /&gt;
			end&lt;br /&gt;
			return value&lt;br /&gt;
		end&lt;br /&gt;
		error(('AttributeError: unauthorized read attempt of internal &amp;quot;%s&amp;quot;'):format(key), 2)&lt;br /&gt;
	end,&lt;br /&gt;
	__newindex = function (cls_private, key, value)&lt;br /&gt;
		local cls = classes[cls_private]&lt;br /&gt;
		if cls.__slots[key] then -- __slots should be valid, so no need to check key type before&lt;br /&gt;
			cls[key] = value&lt;br /&gt;
		else&lt;br /&gt;
			libraryUtil.checkTypeMultiForIndex(key, {'string'}) -- otherwise error message would not make sense&lt;br /&gt;
			error(('AttributeError: write attempt {%s: %s} not expected by __slots'):format(key, tostring(value)), 2)&lt;br /&gt;
		end&lt;br /&gt;
	end,&lt;br /&gt;
	__metatable = 'unauthorized access attempt of wrapper object metatable'&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local cls_public_mt = {&lt;br /&gt;
	__call = constructor,&lt;br /&gt;
	__index = function (cls_public, key)&lt;br /&gt;
		libraryUtil.checkTypeMultiForIndex(key, {'string'})&lt;br /&gt;
		if key:sub(1,1) ~= '_' then&lt;br /&gt;
			local value = classes[classes[cls_public]][key]&lt;br /&gt;
			if type(value) == 'table' then&lt;br /&gt;
				return mw.clone(value) -- all class attributes are immutable in the public scope&lt;br /&gt;
			end&lt;br /&gt;
			return value&lt;br /&gt;
		end&lt;br /&gt;
		error(('AttributeError: unauthorized read attempt of nonpublic &amp;quot;%s&amp;quot;'):format(key), 2)&lt;br /&gt;
	end,&lt;br /&gt;
	__newindex = function (cls_public, key, value)&lt;br /&gt;
		libraryUtil.checkTypeMultiForIndex(key, {'string'}) -- otherwise error message...&lt;br /&gt;
		error(('AttributeError: forbidden write attempt of {%s: %s}; a class is immutable in public scope'):format(key, tostring(value)), 2)&lt;br /&gt;
	end,&lt;br /&gt;
	__metatable = 'unauthorized access attempt of wrapper object metatable'&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function class(...)&lt;br /&gt;
	local args = {...}&lt;br /&gt;
	local cls = {} -- internal&lt;br /&gt;
&lt;br /&gt;
	local idx&lt;br /&gt;
	if type(args[1]) == 'string' then&lt;br /&gt;
		cls.__name = args[1]&lt;br /&gt;
		idx = 2&lt;br /&gt;
	else&lt;br /&gt;
		idx = 1&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	cls.__bases = {}&lt;br /&gt;
	for i = idx, #args-1 do&lt;br /&gt;
		libraryUtil.checkType('class', i, args[i], 'class')&lt;br /&gt;
		cls.__bases[#cls.__bases+1] = classes[classes[args[i]]]&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local kwargs = args[#args]&lt;br /&gt;
	libraryUtil.checkType('class', #args, kwargs, 'table')&lt;br /&gt;
	if kwargs.__name or kwargs.__bases then&lt;br /&gt;
		error('ValueError: __name and unpacked __bases must be passed as optional first args to &amp;quot;class&amp;quot;')&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	cls.__slots = {}&lt;br /&gt;
	if kwargs.__slots then&lt;br /&gt;
		for _, slot in ipairs(kwargs.__slots) do&lt;br /&gt;
			if slot:sub(1,2) ~= '__' then&lt;br /&gt;
				cls.__slots[slot] = true&lt;br /&gt;
			else&lt;br /&gt;
				error(('ValueError: slot &amp;quot;%s&amp;quot; has forbidden namespace'):format(slot))&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		kwargs.__slots = nil&lt;br /&gt;
	end&lt;br /&gt;
	local mt = {&lt;br /&gt;
		__index = function (__slots, key) -- multi_inheritance&lt;br /&gt;
			for _, base in ipairs(cls.__bases) do&lt;br /&gt;
				if key:sub(1,1) ~= '_' or base.__protected[key] then&lt;br /&gt;
					if base.__slots[key] then&lt;br /&gt;
						return true&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	}&lt;br /&gt;
	setmetatable(cls.__slots, mt)&lt;br /&gt;
&lt;br /&gt;
	cls.__protected = {}&lt;br /&gt;
	if kwargs.__protected then&lt;br /&gt;
		for _, key in ipairs(kwargs.__protected) do&lt;br /&gt;
			if key:sub(1,1) == '_' and key:sub(2,2) ~= '_' then&lt;br /&gt;
				cls.__protected[key] = true&lt;br /&gt;
			else&lt;br /&gt;
				error(('ValueError: the namespace of &amp;quot;%s&amp;quot; is not manually protectable'):format(key))&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		kwargs.__protected = nil&lt;br /&gt;
	end&lt;br /&gt;
	mt = {&lt;br /&gt;
		__index = function (__protected, key)&lt;br /&gt;
			for _, base in ipairs(cls.__bases) do&lt;br /&gt;
				if base.__protected[key] then&lt;br /&gt;
					return true&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	}&lt;br /&gt;
	setmetatable(cls.__protected, mt)&lt;br /&gt;
&lt;br /&gt;
	if kwargs.__methods then&lt;br /&gt;
		error('ValueError: __classmethods and __staticmethods should be passed as optional attributes instead of __methods')&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local cls_private = {} -- wrapper&lt;br /&gt;
	setmetatable(cls_private, cls_private_mt)&lt;br /&gt;
	classes[cls_private] = cls&lt;br /&gt;
&lt;br /&gt;
	if kwargs.__classmethods then&lt;br /&gt;
		for _, key in ipairs(kwargs.__classmethods) do&lt;br /&gt;
			local func = kwargs[key]&lt;br /&gt;
			cls[key] = function (...) return func(cls_private, ...) end&lt;br /&gt;
			kwargs[key] = nil&lt;br /&gt;
		end&lt;br /&gt;
		kwargs.__classmethods = nil&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local staticmethods = {}&lt;br /&gt;
	if kwargs.__staticmethods then&lt;br /&gt;
		for _, key in ipairs(kwargs.__staticmethods) do&lt;br /&gt;
			staticmethods[key] = true&lt;br /&gt;
		end&lt;br /&gt;
		kwargs.__staticmethods = nil&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	cls.__methods = {}&lt;br /&gt;
	for _, base in ipairs(cls.__bases) do&lt;br /&gt;
		for key in pairs(base.__methods) do&lt;br /&gt;
			if key:sub(1,1) ~= '_' or base.__protected[key] then&lt;br /&gt;
				cls.__methods[key] = true&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local valid = false&lt;br /&gt;
	for key, val in pairs(kwargs) do&lt;br /&gt;
		if key:sub(1,2) == '__' and not una_metamethods[key] and not bin_metamethods[key] and not oth_metamethods[key] then&lt;br /&gt;
			error(('ValueError: unrecognized metamethod or unauthorized internal attribute {%s: %s}'):format(key, tostring(val)))&lt;br /&gt;
		end&lt;br /&gt;
		cls[key] = val&lt;br /&gt;
		if type(val) == 'function' then&lt;br /&gt;
			if not staticmethods[key] and key:sub(1,2) ~= '__' then&lt;br /&gt;
				cls.__methods[key] = true&lt;br /&gt;
			end&lt;br /&gt;
			if key ~= '__init' then -- __init does not qualify to a functional/proper class&lt;br /&gt;
				valid = true&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	assert(valid, 'AssertionError: a (sub)class must have at least one functional method')&lt;br /&gt;
&lt;br /&gt;
	setmetatable(cls, cls_mt)&lt;br /&gt;
&lt;br /&gt;
	local cls_public = {}&lt;br /&gt;
	setmetatable(cls_public, cls_public_mt)&lt;br /&gt;
	classes[cls_public] = cls_private&lt;br /&gt;
	return cls_public&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function rissubclass2(class, classinfo)&lt;br /&gt;
	if class == classinfo then&lt;br /&gt;
		return true&lt;br /&gt;
	end&lt;br /&gt;
	for _, base in ipairs(class.__bases) do&lt;br /&gt;
		if rissubclass2(base, classinfo) then&lt;br /&gt;
			return true&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function rissubclass1(class, classinfo, parent, level)&lt;br /&gt;
	libraryUtil.checkTypeMulti(parent, 2, classinfo, {'class', 'table'}, level)&lt;br /&gt;
	if classes[classinfo] then&lt;br /&gt;
		return rissubclass2(class, classes[classes[classinfo]])&lt;br /&gt;
	end&lt;br /&gt;
	for i = 1, #classinfo do&lt;br /&gt;
		if rissubclass1(class, classinfo[i], parent, level+1) then&lt;br /&gt;
			return true&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function issubclass(class, classinfo)&lt;br /&gt;
	libraryUtil.checkType('issubclass', 1, class, 'class')&lt;br /&gt;
	class = classes[class]&lt;br /&gt;
	return rissubclass1(classes[class] or class, classinfo, 'issubclass', 4)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function isinstance(instance, classinfo)&lt;br /&gt;
	instance = instances[instance]&lt;br /&gt;
	if instance then -- because named (ClassName) instances would fail with checkType&lt;br /&gt;
		return rissubclass1(classes[instance.__class], classinfo, 'isinstance', 4)&lt;br /&gt;
	end&lt;br /&gt;
	error((&amp;quot;TypeError: bad argument #1 to 'isinstance' (instance expected, got %s)&amp;quot;):format(type(instance)), 2)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local _type = type&lt;br /&gt;
type = function (value)&lt;br /&gt;
	local t = _type(value)&lt;br /&gt;
	if t == 'table' then&lt;br /&gt;
		if classes[value] then&lt;br /&gt;
			return 'class'&lt;br /&gt;
		elseif instances[value] then&lt;br /&gt;
			return classes[instances[value].__class].__name or 'instance' -- should __name be directly readable instead?&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return t&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
libraryUtil.checkType = function (name, argIdx, arg, expectType, nilOk, level)&lt;br /&gt;
	if arg == nil and nilOk then&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
	if type(arg) ~= expectType then&lt;br /&gt;
		error((&amp;quot;TypeError: bad argument #%d to '%s' (%s expected, got %s)&amp;quot;):format(argIdx, name, expectType, type(arg)), level or 3)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
libraryUtil.checkTypeMulti = function (name, argIdx, arg, expectTypes, level)&lt;br /&gt;
	local argType = type(arg)&lt;br /&gt;
	for _, expectType in ipairs(expectTypes) do&lt;br /&gt;
		if argType == expectType then&lt;br /&gt;
			return&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local n = #expectTypes&lt;br /&gt;
	local typeList&lt;br /&gt;
	if n &amp;gt; 1 then&lt;br /&gt;
		typeList = table.concat(expectTypes, ', ', 1, n-1) .. ' or ' .. expectTypes[n]&lt;br /&gt;
	else&lt;br /&gt;
		typeList = expectTypes[1]&lt;br /&gt;
	end&lt;br /&gt;
	error((&amp;quot;TypeError: bad argument #%d to '%s' (%s expected, got %s)&amp;quot;):format(argIdx, name, typeList, type(arg)), level or 3)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
libraryUtil.checkTypeForIndex = function (index, value, expectType, level)&lt;br /&gt;
	if type(value) ~= expectType then&lt;br /&gt;
		error((&amp;quot;TypeError: value for index '%s' must be %s, %s given&amp;quot;):format(index, expectType, type(value)), level or 3)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
libraryUtil.checkTypeMultiForIndex = function (index, expectTypes, level)&lt;br /&gt;
	local indexType = type(index)&lt;br /&gt;
	for _, expectType in ipairs(expectTypes) do&lt;br /&gt;
		if indexType == expectType then&lt;br /&gt;
			return&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local n = #expectTypes&lt;br /&gt;
	local typeList&lt;br /&gt;
	if n &amp;gt; 1 then&lt;br /&gt;
		typeList = table.concat(expectTypes, ', ', 1, n-1) .. ' or ' .. expectTypes[n]&lt;br /&gt;
	else&lt;br /&gt;
		typeList = expectTypes[1]&lt;br /&gt;
	end&lt;br /&gt;
	error((&amp;quot;TypeError: index '%s' must be %s, %s given&amp;quot;):format(index, typeList, type(index)), level or 3)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
libraryUtil.checkTypeForNamedArg = function (name, argName, arg, expectType, nilOk, level)&lt;br /&gt;
	if arg == nil and nilOk then&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
	if type(arg) ~= expectType then&lt;br /&gt;
		error((&amp;quot;TypeError: bad named argument %s to '%s' (%s expected, got %s)&amp;quot;):format(argName, name, expectType, type(arg)), level or 3)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
libraryUtil.checkTypeMultiForNamedArg = function (name, argName, arg, expectTypes, level)&lt;br /&gt;
	local argType = type(arg)&lt;br /&gt;
	for _, expectType in ipairs(expectTypes) do&lt;br /&gt;
		if argType == expectType then&lt;br /&gt;
			return&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local n = #expectTypes&lt;br /&gt;
	local typeList&lt;br /&gt;
	if n &amp;gt; 1 then&lt;br /&gt;
		typeList = table.concat(expectTypes, ', ', 1, n-1) .. ' or ' .. expectTypes[n]&lt;br /&gt;
	else&lt;br /&gt;
		typeList = expectTypes[1]&lt;br /&gt;
	end&lt;br /&gt;
	error((&amp;quot;TypeError: bad named argument %s to '%s' (%s expected, got %s)&amp;quot;):format(argName, name, typeList, type(arg)), level or 3)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function try_parser(...)&lt;br /&gt;
	local args = {...}&lt;br /&gt;
	libraryUtil.checkType('try', 1, args[1], 'function', nil, 4)&lt;br /&gt;
	local try_clause = args[1]&lt;br /&gt;
&lt;br /&gt;
	assert(args[2] == 'except', 'AssertionError: missing required except clause')&lt;br /&gt;
	local except_clauses = {}&lt;br /&gt;
	local i = 3&lt;br /&gt;
	repeat&lt;br /&gt;
		libraryUtil.checkTypeMulti('try', i, args[i], {'string', 'table', 'function'}, 4)&lt;br /&gt;
		if ({string=1, table=1})[type(args[i])] then&lt;br /&gt;
			libraryUtil.checkType('try', i+1, args[i+1], 'function', nil, 4)&lt;br /&gt;
			except_clauses[#except_clauses+1] = {exceptions={}, handler=args[i+1]}&lt;br /&gt;
			if type(args[i]) == 'string' then&lt;br /&gt;
				except_clauses[#except_clauses].exceptions[args[i]] = true&lt;br /&gt;
			else&lt;br /&gt;
				for _, exception in ipairs(args[i]) do&lt;br /&gt;
					if type(exception) ~= 'string' then&lt;br /&gt;
						error(('TypeError: invalid exception type in except (string expected, got %s)'):format(type(exception)))&lt;br /&gt;
					end&lt;br /&gt;
					except_clauses[#except_clauses].exceptions[exception] = true&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			i = i + 3&lt;br /&gt;
		else&lt;br /&gt;
			except_clauses[#except_clauses+1] = {exceptions={}, handler=args[i]}&lt;br /&gt;
			i = i + 2&lt;br /&gt;
			break&lt;br /&gt;
		end&lt;br /&gt;
	until args[i-1] ~= 'except'&lt;br /&gt;
&lt;br /&gt;
	local else_clause, finally_clause&lt;br /&gt;
	if args[i-1] == 'except' then&lt;br /&gt;
		error('SyntaxError: except after except clause without specific exceptions, which should be the last')&lt;br /&gt;
	elseif args[i-1] == 'else' then&lt;br /&gt;
		libraryUtil.checkType('try', i, args[i], 'function', nil, 4)&lt;br /&gt;
		else_clause = args[i]&lt;br /&gt;
		i = i + 2&lt;br /&gt;
	end&lt;br /&gt;
	if args[i-1] == 'finally' then&lt;br /&gt;
		libraryUtil.checkType('try', i, args[i], 'function', nil, 4)&lt;br /&gt;
		finally_clause = args[i]&lt;br /&gt;
		i = i + 2&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if args[i-1] ~= nil then&lt;br /&gt;
		error(('SyntaxError: unexpected arguments #%d–#%d to &amp;quot;try&amp;quot;'):format(i-1, #args), 3)&lt;br /&gt;
	end&lt;br /&gt;
	return try_clause, except_clauses, else_clause, finally_clause&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function try(...)&lt;br /&gt;
	local try_clause, except_clauses, else_clause, finally_clause = try_parser(...)&lt;br /&gt;
&lt;br /&gt;
	local function errhandler(message)&lt;br /&gt;
		local errtype = mw.text.split(message, ':')[1]&lt;br /&gt;
		local handled = false&lt;br /&gt;
		for _, except in ipairs(except_clauses) do&lt;br /&gt;
			if except.exceptions[errtype] or #except.exceptions == 0 then&lt;br /&gt;
				handled, message = pcall(except.handler())&lt;br /&gt;
				break&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		if not handled then&lt;br /&gt;
			return message&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local success, message = xpcall(try_clause, errhandler)&lt;br /&gt;
	if else_clause and success then&lt;br /&gt;
		success, message = pcall(else_clause)&lt;br /&gt;
	end&lt;br /&gt;
	if finally_clause then&lt;br /&gt;
		finally_clause()&lt;br /&gt;
	end&lt;br /&gt;
	if not success and message then&lt;br /&gt;
		error(message)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return classes, instances--&lt;/div&gt;</summary>
		<author><name>Zoran</name></author>
	</entry>
</feed>