Modul:LuaDokumentation
Modulbeschreibung
Modul mit Templates zur (automatischen) Erstellung von Dokumentationen für Lua-Module. Dieses Modul verwendet Vorlage:LuaDokumentationsseite zur Erzeugung der Dokumentation. Siehe Funktion erzeugeDokumentation
, wie dieses Modul in Wikibooks verwendet werden kann.
Funktionen
erzeugeDokumentation
Lua-Funktion, um aus den Kommentaren eines Moduls automatisch eine Dokumentationsseite zu erzeugen.
Wenn "Modul: ..../Doku" als Modul angegeben wird, wird nur "Modul: ...." verwendet.
Module, die dieses Template benutzen, müssen als letzte Anweisung den Ausdruck return modulobjekt
besitzen (mit genau diesen Abständen).
Kommentare
BearbeitenKommentare, die später in der Dokumentation erscheinen sollen, müssen mit ---
(3 Minusstriche) beginnen.
Der darauf folgende Block von Kommentaren beginnend jeweils mit --
wird als ein Dokumentationsblock interpretiert.
Der jeweils erste ist der Dokumentationsblock für das gesamte Modul, die anderen für Funktionen.
Die Funktionsdeklaration muss dem Dokumentationsblock direkt folgen. (Bitte auf der Dokumentationsseite dieses Moduls melden, wenn eine
Dunktionsdeklaration nicht erkannt wird).
Tags bezeichnen den Kommentar näher. Das sind @...
Anweisungen. Alles vor dem ersten Tag wird als Beschreibung des Moduls,
der Funktion interpretiert. Wiki-Formatierungen können dabei verwendet werden.
Tags
BearbeitenFolgende Tags gibt es
@example
– Tag zum Starten eines Code-Beispiels. Dieses wird später über Vorlage:Codebeispiel eingebunden.@code
Code – der Code des Code-Beispiels@description
Beschreibung – Beschreibungstext des Code-Beispiels@lang
Sprache – Sprache des Code-Beispiels (entspricht Argumentlang
von Vorlage:Codebeispiel)@dont_show_result
– Wenn es sich beim Code um Mediawiki Text handelt, wird dieser nicht automatisch evaluiert.
@param
Name Beschreibung – Beschreibung eines Arguments einer Funktion@optional
– zeigt an, dass der Parameter optional ist@default_value
Standardwert – Standardwert des Arguments, wenn dieser nicht angegeben ist (impliziert@optional
)
Beispiele
Beispiel 1:
Folgender Lua-Aufruf erzeugt die Dokumentation für diese Seite{{#invoke:LuaDokumentation|erzeugeDokumentation|modul=LuaDokumentation}}
Beispiel 2:
Folgender Lua-Aufruf erzeugt die Dokumentation auf einer "Modul: ..../Doku" Unterseite{{#invoke:LuaDokumentation|erzeugeDokumentation}}
Parameter
modul
(optional) – Modulname (Standardwert: aktuelle Seite in der {{#invoke:}} aufgerufen wird)
getModuleName
Funktion, um den Modulnamen einer Seite (also ohne Präfix Modul:
und ohne Suffix /Doku
) zu extrahieren.
Beispiele
Beispiel 1:
LuaDokumentation.getModuleName("Modul:HalloWelt")
Beispiel 2:
LuaDokumentation.getModuleName("Modul:LuaDokumentation/Doku")
Beispiel 3:
LuaDokumentation.getModuleName({args = { modul = "HalloWelt/Doku" } })
Parameter
arg
(optional) – Seitentitel des Moduls oder einer Unterseite des Moduls als String oder das aktuelle Frame-Objekt (dann wird in args nach dem Parametermodul
gesucht) (Standardwert: aktueller Seitentitel)
getModuleSourceCode
Funktion, die den Source-Code eines Lua-Modules zurückgibt
Parameter
module_name
– Name des Moduls oder aktuelles Frame-Objekt (bei einem Frame-Objekt dann wird das Argumentmodul
verwendet)
parseModule
Funktion, um die Dokumentation eines Lua-Moduls zu parsen. Es wird eine table
zurückgegeben, die folgende Struktur aufweist
{
description = "....", -- Modulbeschreibung
examples = { -- alle @examples der Modulbeschreibung (nil wenn keine @examples vorhanden sind)
code = "...." or nil,
description = "..." or nil,
lang = "..." or nil,
dont_show_result = true or nil
},
functions = { -- Dokumentation aller Funktionen
{
name = "...",
descriptions = "..."
examples = { ... } -- wie bei Modulbeschreibung
params = { -- Liste aller @param Anweisungen (nil, wenn keine @param Anweisung vorhanden ist)
{
name = "...",
description = "...",
optional = true or nil,
default_value = "...." or nil
},
...
}
},
...
}
}
Parameter
module_name
– Name des Moduls oder aktuelles Frame-Objekt (bei einem Frame-Objekt dann wird das Argumentmodul
verwendet)
- Diese Dokumentation wurde mithilfe von Modul:LuaDokumentation erstellt und befindet sich im Quelltext.
- Liste der Unterseiten
--- Modul mit Templates zur (automatischen) Erstellung von Dokumentationen für Lua-Module. Dieses Modul verwendet [[Vorlage:LuaDokumentationsseite]] zur Erzeugung der Dokumentation. Siehe Funktion <code>[[#erzeugeDokumentation|erzeugeDokumentation]]</code>, wie dieses Modul in Wikibooks verwendet werden kann.
local LuaDokumentation = {}
local utils = require("Modul:Utils")
string.starts = utils.starts
string.ends = utils.ends
-- Templates for erzeugeDokumentation()
local baseTemplate = [[== Modulbeschreibung ==
%s%s%s]]
local funcTemplate = [[<h3>%s</h3>
%s]]
--- Lua-Funktion, um aus den Kommentaren eines Moduls automatisch eine Dokumentationsseite zu erzeugen.
--
-- Wenn "Modul: ..../Doku" als Modul angegeben wird, wird nur "Modul: ...." verwendet.
-- Module, die dieses Template benutzen, müssen als letzte Anweisung den Ausdruck <code>return modulobjekt</code> besitzen (mit genau diesen Abständen).
--
-- ==== Kommentare ====
--
-- Kommentare, die später in der Dokumentation erscheinen sollen, müssen mit <code>---</code> (3 Minusstriche) beginnen.
-- Der darauf folgende Block von Kommentaren beginnend jeweils mit <code>--</code> wird als ein Dokumentationsblock interpretiert.
-- Der jeweils erste ist der Dokumentationsblock für das gesamte Modul, die anderen für Funktionen.
-- Die Funktionsdeklaration muss dem Dokumentationsblock direkt folgen. (Bitte auf der Dokumentationsseite dieses Moduls melden, wenn eine
-- Dunktionsdeklaration nicht erkannt wird).
--
-- Tags bezeichnen den Kommentar näher. Das sind <code>@...</code> Anweisungen. Alles vor dem ersten Tag wird als Beschreibung des Moduls,
-- der Funktion interpretiert. Wiki-Formatierungen können dabei verwendet werden.
--
-- ==== Tags ====
--
-- Folgende Tags gibt es
--
-- * <code>@example</code> – Tag zum Starten eines Code-Beispiels. Dieses wird später über [[Vorlage:Codebeispiel]] eingebunden.
-- ** <code>@code</code> ''Code'' – der Code des Code-Beispiels
-- ** <code>@description</code> ''Beschreibung'' – Beschreibungstext des Code-Beispiels
-- ** <code>@lang</code> ''Sprache'' – Sprache des Code-Beispiels (entspricht Argument <code>lang</code> von [[Vorlage:Codebeispiel]])
-- ** <code>@dont_show_result</code> – Wenn es sich beim Code um Mediawiki Text handelt, wird dieser nicht automatisch evaluiert.
-- * <code>@param</code> ''Name'' ''Beschreibung'' – Beschreibung eines Arguments einer Funktion
-- ** <code>@optional</code> – zeigt an, dass der Parameter optional ist
-- ** <code>@default_value</code> ''Standardwert'' – Standardwert des Arguments, wenn dieser nicht angegeben ist (impliziert <code>@optional</code>)
--
-- @example
-- @description Folgender Lua-Aufruf erzeugt die Dokumentation für diese Seite
-- @code {{#invoke:LuaDokumentation|erzeugeDokumentation|modul=LuaDokumentation}}
-- @dont_show_result
-- @example
-- @description Folgender Lua-Aufruf erzeugt die Dokumentation auf einer "Modul: ..../Doku" Unterseite
-- @code {{#invoke:LuaDokumentation|erzeugeDokumentation}}
-- @dont_show_result
--
-- @param modul Modulname
-- @optional
-- @default_value aktuelle Seite in der {{#invoke:}} aufgerufen wird
function LuaDokumentation.erzeugeDokumentation(frame)
-- compute all examples
local create_examples = function(examples)
if examples ~= nil and #examples > 0 then
local result = "\n==== Beispiele ====\n"
for i, example_doc in ipairs(examples) do
example_doc.name = "Beispiel " .. i
example_doc.beschreibung = example_doc.description
if example_doc.dont_show_result then example_doc.kein_ergebnis = "ja" end
result = result .. frame:expandTemplate {
title = 'Codebeispiel',
args = example_doc
}
end
return result
else
return ""
end
end
local module_name = LuaDokumentation.getModuleName((frame.args or {})["modul"])
local module_doc = LuaDokumentation.parseModule(module_name)
if #module_doc.doc_functions > 0 then
result_func = "\n\n<h2>Funktionen</h2>\n"
for i, func_doc in ipairs(module_doc.doc_functions) do
result_func = result_func .. string.format(funcTemplate, func_doc.name, frame:preprocess(func_doc.description))
result_func = result_func .. create_examples(func_doc.examples)
if func_doc.params then
result_func = result_func .. "\n==== Parameter ====\n"
for i, param_doc in ipairs(func_doc.params) do
local optional = ""
if param_doc.optional ~= nil and param_doc.optional then optional = "''(optional)'' " end
local default_value = ""
if param_doc.default_value ~= nil then default_value = " ''(Standardwert: " .. mw.text.nowiki(param_doc.default_value) .. ")''" end
result_func = result_func .. string.format("* <code>%s</code> %s– %s%s\n", param_doc.name, optional, param_doc.description, default_value)
end
end
end
else
result_func = ''
end
local content
local desc
if module_doc.description ~= nil then
desc = frame:preprocess(module_doc.description)
else
desc = ""
end
if desc ~= "" or create_examples(module_doc.examples) ~= "" or result_func ~= "" then
content = string.format(baseTemplate, frame:preprocess(module_doc.description), create_examples(module_doc.examples), result_func)
else
content = "''Es existiert keine Dokumentation. Wenn du eine anlegen willst, solltest du keine „/Doku“-Unteseite benutzen, sondern [[Modul:LuaDokumentation|LuaDokumentation]].''";
end
return content
end
--- Funktion, um den Modulnamen einer Seite (also ohne Präfix <code>Modul:</code> und ohne Suffix <code>/Doku</code>) zu extrahieren.
--
-- @example
-- @code LuaDokumentation.getModuleName("Modul:HalloWelt")
-- @result HalloWelt
-- @lang lua
-- @example
-- @code LuaDokumentation.getModuleName("Modul:LuaDokumentation/Doku")
-- @result LuaDokumentation
-- @lang lua
-- @example
-- @code LuaDokumentation.getModuleName({args = { modul = "HalloWelt/Doku" } })
-- @result HalloWelt
-- @lang lua
--
-- @param arg Seitentitel des Moduls oder einer Unterseite des Moduls als String oder das aktuelle Frame-Objekt (dann wird in args nach dem Parameter <code>modul</code> gesucht)
-- @default_value aktueller Seitentitel
function LuaDokumentation.getModuleName(arg)
local module_name = ((arg or {}).args or {})["modul"] or mw.title.getCurrentTitle().fullText
if type(arg) == "string" and #arg > 0 then
module_name = arg
end
module_name = string.match(module_name, "^Modul%:(.*)$") or module_name -- strip namespace token "Modul:"
module_name = string.match(module_name, "^(.*)%/Doku$") or module_name -- strip suffix "/Doku"
return module_name
end
--- Funktion, die den Source-Code eines Lua-Modules zurückgibt
--
-- @param module_name Name des Moduls oder aktuelles Frame-Objekt (bei einem Frame-Objekt dann wird das Argument <code>modul</code> verwendet)
function LuaDokumentation.getModuleSourceCode(module_name)
module_name = LuaDokumentation.getModuleName(module_name)
local title = assert(mw.title.makeTitle("Modul", module_name), "no module with name " .. module_name)
return title:getContent()
end
--- Funktion, um die Dokumentation eines Lua-Moduls zu parsen. Es wird eine <code>table</code> zurückgegeben, die folgende Struktur aufweist
--
-- <syntaxhighlight lang="lua">
-- {
-- description = "....", -- Modulbeschreibung
-- examples = { -- alle @examples der Modulbeschreibung (nil wenn keine @examples vorhanden sind)
-- code = "...." or nil,
-- description = "..." or nil,
-- lang = "..." or nil,
-- dont_show_result = true or nil
-- },
-- functions = { -- Dokumentation aller Funktionen
-- {
-- name = "...",
-- descriptions = "..."
-- examples = { ... } -- wie bei Modulbeschreibung
-- params = { -- Liste aller @param Anweisungen (nil, wenn keine @param Anweisung vorhanden ist)
-- {
-- name = "...",
-- description = "...",
-- optional = true or nil,
-- default_value = "...." or nil
-- },
-- ...
-- }
-- },
-- ...
-- }
-- }
-- </syntaxhighlight>
--
-- @param module_name Name des Moduls oder aktuelles Frame-Objekt (bei einem Frame-Objekt dann wird das Argument <code>modul</code> verwendet)
function LuaDokumentation.parseModule(module_name)
-- variable sourc contains the modules source code
local source = assert(LuaDokumentation.getModuleSourceCode(module_name), "no module with name " .. module_name)
-- variable containing the result of this function
local result = {
doc_module = {},
doc_functions = {}
}
-- name of module variable, which is returned in the last statement
result.module_var = assert(string.match(source, "\nreturn ([%w_]+)%s*$"),
'no module name found near "' .. string.match(source, '\n([^\r\n]*)%s*$') .. '"')
local current_doc -- table with information of current docstring block (`nil` iff currently no docstring is parsed)
local current_tag -- table with information of current tag in docstring
local first_doc = true -- `true`, iff current docstring is the first parsed docstring and therefore
local description -- current docstring description (`nil` iff no docstring is parsed)
local current_tag_prop -- current tag property
-- to be called, iff parsing of description shall be terminated
local end_description = function()
if description ~= nil then
current_doc.description = mw.text.trim(description)
description = nil
end
end
-- inserts a new tag to tag list `tag_list` of `current_doc`
local insert_tag_to = function(tag_list)
if current_doc[tag_list] == nil then
current_doc[tag_list] = {}
end
current_tag = {}
table.insert(current_doc[tag_list], current_tag)
end
-- iterate over all lines
for line in string.gmatch(source, "[^\r\n]+") do
line = mw.text.trim(line)
if string.starts(line, "--") then
-- line is a comment:
if string.starts(line, "---") and current_doc == nil then
-- line starts a new lua docstring block
current_doc = {}
description = ""
end
-- just continue, iff currently a docstring block is parsed
if current_doc ~= nil then
-- trim `-` characters of line string
line = string.match(line, '^-*%s?(.*)$')
if string.match(line, "^%s*@") ~= nil then
-- docstring line with tags:
end_description()
current_tag_prop = nil
-- parse tag and its parameters
tag = string.match(line, "^%s*@([%w_]+)%s*.*$")
param = string.match(line, "^%s*@[%w_]+%s*(.*)$")
-- append information of current tag to `current_tag` and `current_doc`
if tag == "example" then
-- tag: @example
insert_tag_to("examples")
elseif tag == "description" then
-- tag: @description description
current_tag.description = param
elseif tag == "code" then
-- tag @code code
current_tag.code = param
current_tag_prop = "code"
elseif tag == "lang" then
-- tag @lang lang
current_tag.lang = param
elseif tag == "optional" then
-- tag @optional
current_tag.optional = true
elseif tag == "dont_show_result" then
-- tag @dont_show_result
current_tag.dont_show_result = true
elseif tag == "default_value" then
-- tag @default_value default_value
-- implies @optional
current_tag.optional = true
current_tag.default_value = param
elseif tag == "result" then
-- tag: @result result_description
current_tag.result = param
elseif tag == "param" then
-- tag: @param name param_description
insert_tag_to("params")
name, des = string.match(param, "^([%w_]+)%s+(.*)$")
current_tag.name = name
current_tag.description = des
end
else -- no param line, maybe description line?
-- test, if currently a description is parsed and append line to `description`
if description ~= nil then
description = description .. "\n" .. line
elseif current_tag_prop ~= nil then
current_tag[current_tag_prop] = current_tag[current_tag_prop] .. "\n" .. mw.text.trim(line)
end
end
end
elseif current_doc ~= nil then
-- next line of a parsed docstring block:
end_description()
current_tag = nil
if first_doc then
-- docstring block was a docstring for the module:
for k,v in pairs(current_doc) do result[k] = v end
current_doc = nil
first_doc = false
else
-- docstring block was a docstring for a function
-- try to parse function name:
-- possible regex of function declaration
function_regexes = {
'function%s+' .. result.module_var .. '%s*%.%s*([%w_]+)%(',
'function%s+' .. result.module_var .. '%s*%:%s*([%w_]+)%(',
result.module_var .. '%.([%w_]+)%s*=%s*function%s*%(',
result.module_var .. '%:([%w_]+)%s*=%s*function%s*%(',
}
for i, re in ipairs(function_regexes) do
function_name = string.match(line, re)
if function_name ~= nil then
-- function name found! -> add to result.doc_functions
current_doc.name = function_name
table.insert(result.doc_functions, current_doc)
break
end
end
current_doc = nil
end
end
end
return result
end
return LuaDokumentation