Module:Module introspection: Difference between revisions
Jump to navigation
Jump to search
refactor so main function preprocesses module's code and passes it to all necessary helper functions, then uses that info to build tables (which are now done by helper functions) |
ArrowHead294 (talk | contribs) mNo edit summary |
||
| (106 intermediate revisions by 2 users not shown) | |||
| Line 1: | Line 1: | ||
-- This module follows [[User:Ganaram inukshuk/Provisional style guide for Lua]] | -- This module follows [[User:Ganaram inukshuk/Provisional style guide for Lua]] | ||
local getArgs = require("Module:Arguments").getArgs | local getArgs = require("Module:Arguments").getArgs | ||
local iutils = require("Module:Introspection utils") | |||
local yesno = require("Module:Yesno") | |||
local p = {} | local p = {} | ||
-- Helper function | -- Helper function | ||
-- | -- Given the output of the above function, create a mediawiki table | ||
function p. | function p.make_dependency_table(module_deps) | ||
-- Table headers | |||
local lines = {} | local lines = {} | ||
table.insert(lines, '{| class="wikitable sortable"') | |||
table.insert(lines, "|+ style=\"font-size: 105%;\" | " .. string.format("Lua modules required (%d)", #module_deps)) | |||
table.insert(lines, "|-") | |||
table.insert(lines, "! Variable") | |||
table.insert(lines, "! Module") | |||
table.insert(lines, "! Functions used") | |||
for | -- Table rows (assuming they're all alphabetized) | ||
local | for _, info in ipairs(module_deps) do | ||
local funcs_text | |||
if | if #info.funcs == 0 then | ||
funcs_text = "''dependency not used''" | |||
else | else | ||
local | local func_lines = {} | ||
for _, func in ipairs(info.funcs) do | |||
table.insert(func_lines, string.format("<code>%s</code>", func)) | |||
end | end | ||
funcs_text = table.concat(func_lines, "<br />") | |||
end | end | ||
- | table.insert(lines, "|-") | ||
table.insert(lines, "| " .. info.var) | |||
table.insert(lines, "| [[" .. info.dep .. "]]") | |||
table.insert(lines, "| " .. funcs_text) | |||
table.insert( | |||
end | end | ||
-- | -- Table footer | ||
table.insert(lines, "|}") | |||
-- | -- Join all lines into a single string | ||
return table.concat(lines, "\n") | |||
end | end | ||
-- Helper function | -- Helper function | ||
-- | -- Lists module's own functions; requires module name to produce links to each | ||
-- function. | |||
function p.make_function_table(module_name, module_funcs, descriptions, main_function) | |||
-- Check whether descriptions was passed in | |||
local has_descriptions = false | |||
if type(descriptions) == "table" then | |||
for _, _ in pairs(descriptions) do | |||
has_descriptions = true | |||
break | |||
end | end | ||
end | end | ||
-- Table headers | |||
local lines = {} | |||
--table.insert(lines, string.format("'''Module:%s''' provides %d function(s):", module_name, #module_funcs)) | |||
-- | table.insert(lines, '{| class="wikitable sortable"') | ||
-- | table.insert(lines, "|+ style=\"font-size: 105%;\" | " .. string.format("Functions provided (%d)", #module_funcs)) | ||
table.insert(lines, "|-") | |||
table.insert(lines, "! Line") | |||
table.insert(lines, "! Function") | |||
table.insert(lines, "! Params") | |||
-- If there are descriptions, add a column for that | |||
if has_descriptions then | |||
table.insert(lines, "! Description") | |||
if | |||
end | end | ||
for _, | -- Table rows | ||
local link = string.format("[[Module:%s#L-%d|% | for _, info in ipairs(module_funcs) do | ||
-- Find params for that function, or say "none" if none | |||
local params = {} | |||
for _, param in ipairs(info.params) do | |||
table.insert(params, param) | |||
end | |||
local params_string = "" | |||
if #params == 0 then | |||
params_string = "''none''" | |||
else | |||
params_string = string.format("<code>(%s)</code>", table.concat(params, ", ")) | |||
end | |||
-- Create link to line for that function | |||
local line_num = string.format("[[Module:%s#L-%d|%d]]", module_name, info.line, info.line) | |||
-- Create text for function | |||
local func = "" | |||
if info.name then | |||
func = string.format("<code>%s</code>", info.name) | |||
else | |||
func = "''none''" | |||
end | |||
-- If the function is the main function, add "main" to that cell | -- If the function is the main function, add "main" to that cell | ||
if | if info.name == main_function then | ||
func = func .. " '''(main)'''" | |||
end | end | ||
table.insert( | -- If the function is invokable (it has one param called "frame"), add | ||
table.insert( | -- "invokable" to that cell | ||
table.insert( | if #params == 1 and params[1] == "frame" then | ||
func = func .. " '''(invokable)'''" | |||
end | |||
table.insert(lines, "|-") | |||
table.insert(lines, "| " .. line_num) | |||
table.insert(lines, "| " .. func) | |||
table.insert(lines, "| " .. params_string) | |||
if has_descriptions then | |||
table.insert(lines, "| " .. (descriptions[info.name] or "")) | |||
end | |||
end | end | ||
table.insert( | table.insert(lines, "|}") | ||
return | return table.concat(lines, "\n") | ||
end | end | ||
| Line 203: | Line 128: | ||
function p._module_introspection(args) | function p._module_introspection(args) | ||
local args = args or {} | local args = args or {} | ||
local module_name = args["module_name" ] | local module_name = args["module_name" ] | ||
local main_function = args["main_function"] | local main_function = args["main_function"] | ||
local descriptions = args["descriptions" ] | |||
local is_doc = args["is_doc"] | |||
-- Check whether this page is a docpage | |||
-- If so, don't bother | |||
if is_doc then | |||
return "''To see introspection summary, see this module's main page.''" | |||
end | |||
-- Preprocess module and blank-out comments | -- Preprocess module and blank-out comments | ||
local title = mw.title.new('Module:' .. module_name) | --local title = mw.title.new('Module:' .. module_name) | ||
local | --local code = title:getContent() | ||
--code = iutils.preprocess_code(code) -- Blank-out comments | |||
local code = iutils.get_and_preprocess_content("Module", module_name) | |||
-- Get dependencies | -- Get dependencies and their functions used, then build a table | ||
local | local module_deps = iutils.find_dependencies(code) | ||
local | local dep_table = p.make_dependency_table(module_deps) | ||
-- Get module's functions, then build a table using that information | -- Get module's functions, then build a table using that information | ||
local | local module_funcs = iutils.find_functions(code) | ||
local | local func_table = p.make_function_table(module_name, module_funcs, descriptions, main_function) | ||
-- Return the tables | -- Return the tables | ||
-- Styling may be improved at a later time | |||
local lines = { | |||
'{| class="wikitable mw-collapsible"', | |||
'|-', | |||
'! colspan="2" style="font-size: 105%;" | ' .. string.format("Introspection summary for Module:%s ", module_name), | |||
"|-", | |||
'| style="vertical-align: top; border-right: none;" | ', | |||
func_table, | |||
'| style="vertical-align: top; border-left: none;" | ', | |||
dep_table, | |||
"|}" | |||
} | |||
-- Check whether descriptions was passed in | |||
local has_descriptions = false | |||
if type(descriptions) == "table" then | |||
for _, _ in pairs(descriptions) do | |||
has_descriptions = true | |||
break | |||
end | |||
end | |||
-- If no descriptions were provided, add text below that points to the code. | |||
if not has_descriptions then | |||
table.insert(lines, "''No function descriptions were provided. The Lua code may have further information.''") | |||
end | |||
return table.concat(lines, "\n") | |||
end | end | ||
-- Wrapper function for modules | -- Wrapper function for modules | ||
function p.module_introspection(frame) | function p.module_introspection(frame) | ||
-- Extract arguments using getArgs | -- Extract arguments using getArgs | ||
local args = getArgs(frame) | local args = getArgs(frame) or {} | ||
-- Get module name from arguments, or default to current page | -- Get module name from arguments, or default to current page | ||
| Line 234: | Line 193: | ||
-- Strip trailing "/doc" if the template is used on a documentation subpage | -- Strip trailing "/doc" if the template is used on a documentation subpage | ||
module_name = module_name:gsub("/doc$", "") | --module_name = module_name:gsub("/doc$", "") | ||
-- Check whether page is the doc page | |||
-- To ensure proper referencing, do not display introspection on a docpage. | |||
local is_doc = string.find(module_name, "/doc$") | |||
-- Normalize module name so it can be used to find the main function, which | -- Normalize module name so it can be used to find the main function, which | ||
| Line 242: | Line 205: | ||
local main_function = args["main_function"] or "_" .. normalized_name | local main_function = args["main_function"] or "_" .. normalized_name | ||
-- | -- Process all function descriptions, if provided as desc_function_name | ||
local | local func_descriptions = {} | ||
["module_name"] | for key, val in pairs(args) do | ||
local func_name = key:match("^desc_([%w_]+)$") | |||
if func_name and val and val ~= "" then | |||
func_descriptions[func_name] = val | |||
end | |||
end | |||
-- Return | |||
local result = p._module_introspection({ | |||
["module_name" ] = module_name, | |||
["main_function"] = main_function, | ["main_function"] = main_function, | ||
["descriptions" ] = func_descriptions, | |||
["is_doc"] = is_doc | |||
}) | }) | ||
-- Debugger option to show generated WikiText | |||
local wtext = yesno(frame.args["wtext"] or args["wtext"]) | |||
if wtext == true then | |||
result = "<syntaxhighlight lang=\"wikitext\">" .. result .. "</syntaxhighlight>" | |||
end | |||
return frame:preprocess(result) | |||
end | end | ||
return p | return p | ||
Latest revision as of 20:23, 3 December 2025
- This module should not be invoked directly; use its corresponding template instead: Template:Module introspection.
| Introspection summary for Module:Module introspection | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||||||||||||||||||||
No function descriptions were provided. The Lua code may have further information.
-- This module follows [[User:Ganaram inukshuk/Provisional style guide for Lua]]
local getArgs = require("Module:Arguments").getArgs
local iutils = require("Module:Introspection utils")
local yesno = require("Module:Yesno")
local p = {}
-- Helper function
-- Given the output of the above function, create a mediawiki table
function p.make_dependency_table(module_deps)
-- Table headers
local lines = {}
table.insert(lines, '{| class="wikitable sortable"')
table.insert(lines, "|+ style=\"font-size: 105%;\" | " .. string.format("Lua modules required (%d)", #module_deps))
table.insert(lines, "|-")
table.insert(lines, "! Variable")
table.insert(lines, "! Module")
table.insert(lines, "! Functions used")
-- Table rows (assuming they're all alphabetized)
for _, info in ipairs(module_deps) do
local funcs_text
if #info.funcs == 0 then
funcs_text = "''dependency not used''"
else
local func_lines = {}
for _, func in ipairs(info.funcs) do
table.insert(func_lines, string.format("<code>%s</code>", func))
end
funcs_text = table.concat(func_lines, "<br />")
end
table.insert(lines, "|-")
table.insert(lines, "| " .. info.var)
table.insert(lines, "| [[" .. info.dep .. "]]")
table.insert(lines, "| " .. funcs_text)
end
-- Table footer
table.insert(lines, "|}")
-- Join all lines into a single string
return table.concat(lines, "\n")
end
-- Helper function
-- Lists module's own functions; requires module name to produce links to each
-- function.
function p.make_function_table(module_name, module_funcs, descriptions, main_function)
-- Check whether descriptions was passed in
local has_descriptions = false
if type(descriptions) == "table" then
for _, _ in pairs(descriptions) do
has_descriptions = true
break
end
end
-- Table headers
local lines = {}
--table.insert(lines, string.format("'''Module:%s''' provides %d function(s):", module_name, #module_funcs))
table.insert(lines, '{| class="wikitable sortable"')
table.insert(lines, "|+ style=\"font-size: 105%;\" | " .. string.format("Functions provided (%d)", #module_funcs))
table.insert(lines, "|-")
table.insert(lines, "! Line")
table.insert(lines, "! Function")
table.insert(lines, "! Params")
-- If there are descriptions, add a column for that
if has_descriptions then
table.insert(lines, "! Description")
end
-- Table rows
for _, info in ipairs(module_funcs) do
-- Find params for that function, or say "none" if none
local params = {}
for _, param in ipairs(info.params) do
table.insert(params, param)
end
local params_string = ""
if #params == 0 then
params_string = "''none''"
else
params_string = string.format("<code>(%s)</code>", table.concat(params, ", "))
end
-- Create link to line for that function
local line_num = string.format("[[Module:%s#L-%d|%d]]", module_name, info.line, info.line)
-- Create text for function
local func = ""
if info.name then
func = string.format("<code>%s</code>", info.name)
else
func = "''none''"
end
-- If the function is the main function, add "main" to that cell
if info.name == main_function then
func = func .. " '''(main)'''"
end
-- If the function is invokable (it has one param called "frame"), add
-- "invokable" to that cell
if #params == 1 and params[1] == "frame" then
func = func .. " '''(invokable)'''"
end
table.insert(lines, "|-")
table.insert(lines, "| " .. line_num)
table.insert(lines, "| " .. func)
table.insert(lines, "| " .. params_string)
if has_descriptions then
table.insert(lines, "| " .. (descriptions[info.name] or ""))
end
end
table.insert(lines, "|}")
return table.concat(lines, "\n")
end
-- Main function; to be called by wrapper
function p._module_introspection(args)
local args = args or {}
local module_name = args["module_name" ]
local main_function = args["main_function"]
local descriptions = args["descriptions" ]
local is_doc = args["is_doc"]
-- Check whether this page is a docpage
-- If so, don't bother
if is_doc then
return "''To see introspection summary, see this module's main page.''"
end
-- Preprocess module and blank-out comments
--local title = mw.title.new('Module:' .. module_name)
--local code = title:getContent()
--code = iutils.preprocess_code(code) -- Blank-out comments
local code = iutils.get_and_preprocess_content("Module", module_name)
-- Get dependencies and their functions used, then build a table
local module_deps = iutils.find_dependencies(code)
local dep_table = p.make_dependency_table(module_deps)
-- Get module's functions, then build a table using that information
local module_funcs = iutils.find_functions(code)
local func_table = p.make_function_table(module_name, module_funcs, descriptions, main_function)
-- Return the tables
-- Styling may be improved at a later time
local lines = {
'{| class="wikitable mw-collapsible"',
'|-',
'! colspan="2" style="font-size: 105%;" | ' .. string.format("Introspection summary for Module:%s ", module_name),
"|-",
'| style="vertical-align: top; border-right: none;" | ',
func_table,
'| style="vertical-align: top; border-left: none;" | ',
dep_table,
"|}"
}
-- Check whether descriptions was passed in
local has_descriptions = false
if type(descriptions) == "table" then
for _, _ in pairs(descriptions) do
has_descriptions = true
break
end
end
-- If no descriptions were provided, add text below that points to the code.
if not has_descriptions then
table.insert(lines, "''No function descriptions were provided. The Lua code may have further information.''")
end
return table.concat(lines, "\n")
end
-- Wrapper function for modules
function p.module_introspection(frame)
-- Extract arguments using getArgs
local args = getArgs(frame) or {}
-- Get module name from arguments, or default to current page
local module_name = args["module_name"] or mw.title.getCurrentTitle().text
-- Strip trailing "/doc" if the template is used on a documentation subpage
--module_name = module_name:gsub("/doc$", "")
-- Check whether page is the doc page
-- To ensure proper referencing, do not display introspection on a docpage.
local is_doc = string.find(module_name, "/doc$")
-- Normalize module name so it can be used to find the main function, which
-- is assumed to be the same name as the module. Module assumes snake_case
-- is used for function names. (If this fails, it can be entered manually.)
local normalized_name = module_name:gsub("[^%w]", "_"):lower()
local main_function = args["main_function"] or "_" .. normalized_name
-- Process all function descriptions, if provided as desc_function_name
local func_descriptions = {}
for key, val in pairs(args) do
local func_name = key:match("^desc_([%w_]+)$")
if func_name and val and val ~= "" then
func_descriptions[func_name] = val
end
end
-- Return
local result = p._module_introspection({
["module_name" ] = module_name,
["main_function"] = main_function,
["descriptions" ] = func_descriptions,
["is_doc"] = is_doc
})
-- Debugger option to show generated WikiText
local wtext = yesno(frame.args["wtext"] or args["wtext"])
if wtext == true then
result = "<syntaxhighlight lang=\"wikitext\">" .. result .. "</syntaxhighlight>"
end
return frame:preprocess(result)
end
return p