Module:Class
Enables equals treatment of LUA and wikicode users for modules. Using this module means you will no longer need to have two different entry points for each function, both wikicode and LUA can call the same function.
Usage[edit]
Usage of this module is simple. See the following example:
local Class = require('Module:Class') <!--- Add the import local Cool = Class.new() <!--- Create a class function Cool.doCoolStuff(a, b) <!--- Note the colon symbol! return a + b end return Cool.export() <!--- Export the table
Now, doCoolStuff
will be callable from both LUA and wikicode with the same arguments.
To repeat, you can now do Cool:doCoolStuff(2, 3)
while also being able to do {{#invoke:SomeModule|doCoolStuff|2|3}}
and both will return 5.
Named arguments[edit]
When named arguments are provided, things change slightly. Named arguments are provided as a lua table, and are always the first argument. So, example:
local Class = require('Module:Class') <!--- Add the import local Cool = Class.new() <!--- Create a class function Cool.doCoolStuff(args, a, b) <!--- Named args are now the first argument! return a + b + args.c end return Cool.export() <!--- Export the table
You can now do Cool:doCoolStuff(2, 3, {c = 5})
while also being able to do {{#invoke:SomeModule|doCoolStuff|2|3|c=5}}
and both will return 10.
Advanced[edit]
Module:Class supports advanced usage scenarios via export
's options parameter. These options are passed straight to Module:Arguments, which allows you to specify such things as frame inheritance, trimming functionality, and more. For details on this, see Wikipedia's documentation.
API[edit]
- Programmatic name: Class
- export(class: table, options: table) → class
Adjusts the table given so that its public functions (the ones not prefixed using an underscore) are usable from both LUA and wikicode and returns the adjusted table. Note: you can not create underscored versions of your public versions, please use a different name instead (with underscore if desired). So no copy() and _copy() in the same Module. The options arguments allows for providing arguments to Module:Arguments's getArgs.
- new(base: class, init: function) → class
Creates a new class, by setting the proper metadata. If base is given, that will be used as base class. When init is supplied with a function, it can be used as a constructor. If only init is given, the function will still work.
See all our documentation here.
The above documentation is transcluded from Module:Class/doc. (edit | history) Editors can experiment in this module's sandbox (edit | diff) and testcases (create) pages. Subpages of this module. |
--- -- @Liquipedia -- wiki=commons -- page=Module:Class -- -- Please see https://github.com/Liquipedia/Lua-Modules to contribute -- --- -- @author Vogan for Liquipedia -- local Arguments = require('Module:Arguments') local Class = {} Class.PRIVATE_FUNCTION_SPECIFIER = '_' ---@class BaseClass ---@operator call:self ---@field is_a fun(self, BaseClass):boolean 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) instance.init(object, ...) return object end instance.init = function(object, ...) if base then base.init(object, ...) end if init then init(object, ...) end end 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:table ---@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