Module:Class

From TwogPedia
Revision as of 20:57, 19 August 2022 by Couchor (talk | contribs) (Created page with "local Arguments = require('Module:Arguments') local Class = {} Class.PRIVATE_FUNCTION_SPECIFIER = '_' function Class.new(base, init) local instance = {} if not init and type(base) == 'function' then init = base base = nil elseif type(base) == 'table' then for index, value in pairs(base) do instance[index] = value end instance._base = base end instance.__index = instance local metatable = {} metatable.__call = function(class_tbl, ...) local o...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Documentation for this module may be created at Module:Class/doc

local Arguments = require('Module:Arguments')

local Class = {}

Class.PRIVATE_FUNCTION_SPECIFIER = '_'

function Class.new(base, init)
	local instance = {}

	if not init and type(base) == 'function' then
		init = base
		base = nil
	elseif type(base) == 'table' then
		for index, value in pairs(base) do
			instance[index] = value
		end
	  instance._base = base
	end

	instance.__index = instance

	local metatable = {}

	metatable.__call = function(class_tbl, ...)
		local object = {}
		setmetatable(object, instance)

		-- Call constructors
		if init and base and base.init then
			-- If the base class has a constructor,
			-- make sure to call that first
			base.init(object, ...)
			init(object, ...)
		elseif init then
			-- Else we just call our own
			init(object, ...)
		else
			-- And in cases where we don't have one but the
			-- base class does, call that one
			if base and base.init then
				base.init(object, ...)
			end
		end
		return object
	end

	instance.init = init
	instance.export = function(options)
		return Class.export(instance, options)
	end

	instance.is_a = function(self, class)
		local m = getmetatable(self)
		while m do
			if m == class then
				return true
			end
			m = m._base
		end
		return false
	end
	setmetatable(instance, metatable)
	return instance
end

---@generic T
---@param class T
---@param options ?table
---@return T
function Class.export(class, options)
	for name, f in pairs(class) do
		-- We only want to export functions, and only functions which are public (no underscore)
		if (
			type(f) == 'function' and
				(not string.find(name, Class.PRIVATE_FUNCTION_SPECIFIER))
		) then
			class[name] = Class._wrapFunction(class[name], options)
		end
	end
	return class
end

local Table = {}

-- Duplicate Table.isNotEmpty() here to avoid circular dependencies with Table
function Table.isNotEmpty(tbl)
	-- luacheck: push ignore (Loop can be executed at most once)
	for _ in pairs(tbl) do
		return true
	end
	-- luacheck: pop
	return false
end

---
-- Wrap the given function with an argument parses so that both wikicode and lua
-- arguments are accepted
--
function Class._wrapFunction(f, options)
	options = options or {}
	local alwaysRewriteArgs = options.trim
		or options.removeBlanks
		or options.valueFunc ~= nil

	return function(...)
		-- We cannot call getArgs with a spread operator when these are just lua
		-- args, so we need to wrap it
		local input = {...}

		local frame = input[1]
		local shouldRewriteArgs = alwaysRewriteArgs
			or (
				#input == 1
					and type(frame) == 'table'
					and type(frame.args) == 'table'
			)

		if shouldRewriteArgs then
			local namedArgs, indexedArgs = Class._frameToArgs(frame, options)
			if namedArgs then
				return f(namedArgs, unpack(indexedArgs))
			else
				return f(unpack(indexedArgs))
			end
		else
			return f(...)
		end
	end
end

--[[
Translates a frame object into arguments expected by a lua function.
]]
function Class._frameToArgs(frame, options)
	local args = Arguments.getArgs(frame, options)

	-- getArgs adds a metatable to the table. This breaks unpack. So we remove it.
	-- We also add all named params to a special table, since unpack removes them.
	local indexedArgs = {}
	local namedArgs = {}
	for key, value in pairs(args) do
		if type(key) == 'number' then
			indexedArgs[key] = value
		else
			namedArgs[key] = value
		end
	end

	return (Table.isNotEmpty(namedArgs) and namedArgs or nil), indexedArgs
end

return Class