User:Lilyuserin/Lua

From Wikimedia Commons, the free media repository
Jump to navigation Jump to search

Allgemeines

[edit]

Substitution und Transclusion sind mächtige Werkzeuge innerhalb der Wiki-Software MediaWiki. Diesen fehlt jedoch eine wichtige Funktionalität, die in jeder Programmiersprache enthalten ist, die Möglichkeit, Vorgänge in Schleifen zu wiederholen. Es gibt zwar Parserfunktionen und eine Menge nützlicher Erweiterungen, mit deren Hilfe logische Entscheidungen getroffen werden können, doch muss jeder mögliche Fall explizit vorgesehen werden.

Beispielsweise kann ich keine Tabelle erzeugen, deren Zeilenzahl von einem Parameter abhängt. Zumindest gibt es keinen einfachen Weg dafür, es müsste für jeden möglichen Fall eine eigene Vorlage mit entsprechender Benennung angelegt werden, also eine Vorlage mit einer Zeile, eine Vorlage mit zwei Zeilen, eine Vorlage mit drei Zeilen usw.

Diesem Umstand schafft die Scriptsprache Lua Abhilfe. Im folgenden gebe ich einen Überblick über die wichtigsten Elemente dieser Sprache, deren Kenntnis für das Programmieren von Scripten innerhalb eines Wikis erforderlich ist.

[edit]

Lua Programmierung

[edit]

Lua in der Wikipedia und in MediaWiki-Software

[edit]


Beispielmodule

[edit]

Erweiterungen für Lua

[edit]

Scribunto läuft nicht

[edit]
Mit folgenden Erweiterungen können in Vorlagen Schleifen programmiert werden:

Zusatzinfos

[edit]

Datentypen

[edit]

Es gibt in Lua acht Datentypen, von denen für Scribunto sechs relevant sind.

nil, boolean, number, string, userdata, function, thread, table

Eine Variable kann jeden Datentyp aufnehmen, type(varname) liefert den derzeit aktuellen Datentyp des Inhalts als String.

Nil

[edit]

Nichts, undefiniert, leer: wenn eine Variable nicht definiert ist, enthält sie nil, sie kann durch Zuweisen von nil auf undefiniert gesetzt werden.

Boolean

[edit]

Logischer Datentyp, true oder false, alle Inhalte außer false und nil sind true.

Number

[edit]

Zahlen, mit denen gerechnet werden kann. Integer (eigener Subtyp seit Lua 5.3), Dezimalzahl, Exponentialzahl oder Hexadezimalzahl.

String

[edit]

Eine Folge von Zeichen. Ein String wird entweder von doppelten oder einfachen Anführungszeichen eingeschlossen. Escape sequence ist der Backslash \, damit können Zeilenumbrüche, Tabulatoren und Ascii-Zeichen durch Angabe des Hexadezimalcodes innerhalb des Strings angegeben werden sowie Anführungszeichen und der Backslash selber.

Eine Besonderheit von Lua ist die Angabe von Strings durch long brackets, die nichts anders sind als doppelte eckige Klammern, damit können Strings erzeugt werden, die sich über mehrere Zeilen erstrecken. Ein Zeilenwechsel, der unmittelbar auf die öffnende Klammer folgt, wird ignoriert.

Mit dem unary length operator # kann die Länge des Strings ermittelt werden.

#("This is a string") --> 16

Strings werden durch zwei aufeinanderfolgende Punkte .. miteinander verkettet.

"This is" .. " a string" --> "This is a string"
Zeichenfolge Bedeutung
\a bell
\b back space
\f form feed
\n newline
\r carriage return
\t horizontal tab
\v vertical tab
\\ backslash
\" double quote
\' single quote
\[ left square bracket
\] right square bracket

Variable

[edit]

Sämtliche Bezeichnungen und Namen sind case-sensitive, d.h. Groß- und Kleinbuchstabenschreibweise wird unterschieden. Variablennamen dürfen nicht mit einer Zahl beginnen und dürfen nur Buchstaben, Ziffern sowie das Sonderzeichen _ enthalten. Zu vermeiden sind Namen, die mit einem Unterstrich beginnen und ausschließlich Großbuchstaben enthalten.

Folgende Wörter sind Schlüsselwörter und können nicht als Variablennamen verwendet werden

and       break     do        else      elseif    end
false     for       function  goto      if        in
local     nil       not       or        repeat    return
then      true      until     while

Tabellen

[edit]

Tabellen sind ein Feature von Lua, das diese Sprache am meisten von allen anderen Programmiersprachen unterscheidet.

Einerseits können Tabellen wie gewöhnliche Arrays verwendet werden, die wir aus anderen Programmiersprachen kennen. Zu beachten ist, dass der erste Index immer 1 ist, nicht 0 wie in vielen anderen Programmiersprachen. Andererseits können Tabellenelemente benannt werden, entweder mit Namen oder mit Stringkombination, Funktionen etc, praktisch alles kann ein Tabellenplatzbezeichner sein. Hat das Tabellenelement einen Namen, der als Variablennamen zulässig ist, kann es durch Qualifizierung oder Einfügen des Namens in eckige Klammern angesprochen werden, andere Bezeichner müssen in eckige Klammern unter Hochkomma gesetzt werden. Indizes stehen in eckigen Klammern. In einer Tabelle können indizierte und benannte Elemente parallel nebeneinander verwendet werden.

Dies entspricht den unbenannten und benannten Parametern in Vorlagen.

Definiert werden Tabellen mit geschweiften Klammer:

mytab = { }
definiert eine leere Tabelle.

Es gibt mehrere Möglichkeiten, einer Tabelle Werte zuzuweisen.

mymonat = { "Jänner", "Februar", "März" }
mydatum = { monat="Jänner", jahr="2012", tag="11" }
myops = { ["!"]="Rufzeichen", ["*"]="Stern", ["µ"]="mü" }
mytables = { mymonat, mydatum, myops }

Tabellenelemente können durch Punkte oder Strichpunkte voneinander getrennt werden, auch am Ende darf ein Trennzeichen stehen. Dadurch braucht das Ende einer Tabelle nicht besonders behandelt zu werden.

Referenziert werden die Tabellenelemente folgendermaßen:

mymonat[2]    --> Februar
mydatum.monat --> Jänner
myops["*"]    --> Stern
mytables.mydatum.jahr --> 2012

Für das effiziente Suchen in einer Tabelle ist es praktisch, die Umkehrung zu erzeugen, also Werte und Indizes zu vertauschen.

revmonat = {}
 for i,v in ipairs(mymonat) do
   revmonat [v] = i
end

Alle Tabelleneinträge abarbeiten

[edit]

Mit pairs() und ipairs() können alle Elemente einer Tabelle in einer Schleife abgearbeitet werden.

tab = {erster, zweiter, dritter, zahl=5, obst = 'Äpfel'}
for k, v in pairs(tab) do
  -- irgendwas wo k und v vorkommt; k ist der Index, v der Inhalt
  -- k=1, v="erster"
  -- k=2, v="zweiter" ...
  -- k=zahl, v=5
  -- k=obst, v="Äpfel"
end

Die Reihenfolge der Abarbeitung ist willkürlich und kann nicht vorhergesehen werden, ipairs() arbeitet die Parameter in der Reihenfolge der Indizes ab, allerdings nur bis zur ersten Lücke in der Numerierung, die benannten Tabelleneinträge werden daher von der Schleife nicht erfasst.

Tabellenelemente zusammenhängen table.concat

[edit]

Diese Funktion verbindet alle Elemente einer Tabellen zu einem String, für Debugzwecke nützlich. Allerdings werden nur Elemente mit Indizes erfasst, benannte Elemente können derart nicht verkettet werden, da die vordefinierte Ordnung fehlt.

tab = {erster, zweiter, dritter, zahl=5, obst = 'Äpfel'}
table.concat(tab, ", ") --> "erster, zweiter, dritter"

Es gibt auch eine Wikimedia-eigene Funktion mw.text.listToText, die eine Tabelle verkettet, aber das vorletzte und das letzte Element mittes eines Verbindungsstrings verbindet. Das Default-Trennzeichen ist das Standard-Komma, das Verbindungszeichen das Standard „und“

Tabelle entpacken unpack

[edit]

Ordnet die Elemente einer Tabelle einer Variablenliste zu unpack (tabelle [, i [, j]])

local feld = {11, 8, 5}
local x, y, z = table.unpack(feld)
--> x=11, y=8, z=5

i ist der Startwert, j die Anzahl der Elemente, i ist per Default 1, j die Zahl der Elemente der Tabelle #

Text in eine Tabelle aufteilen

[edit]

mw.text.split teilt einen Text nach einem vorgegebenen Muster in eine Tabelle bzw. Array.

Mehrfache Zuordnungen

[edit]

Eines der besonderen Features von Lua ist die Möglichkeit, einer Liste von Variablen eine Liste von Werten in einem Statement zuzuweisen.

a, b, c = 0, 1 --> a: 0; b: 1; c: nil

Vor einer Zuweisung werden alle Variablen auf der rechten Seite ausgewertet, daher kann z.B. ein Tausch des Inhalts zweier Variablen einfach durchgeführt werden:

a, b = b, a    --> a: b; b: a

Funktionen

[edit]

Eine Funktion kann eine beliebige Zahl an Parametern aufnehmen und eine beliebige Zahl an Rückgabewerten liefern. Wird die Funktion mit mehr Parametern aufgerufen als im Kopf definiert sind, werden die überflüssigen Parameter verworfen. Fehlende Parameter werden mit nil aufgefüllt.

Des weiteren kann eine Funktion mehrere Ergebnisse gleichzeitig liefern, die dann einer Variablenliste zugeordnet werden sollten (sonst würde es keinen Sinn haben, da die restlichen Werte ohnehin verworfen würden).

Eine Funktion, die als Ergebnis das Maximum einer Tabelle sowie den Index des Maximums liefert:

function max (tab)
  local index=1      -- Index
  local xam=tab(1)   -- Wert des Maximums
  for i,val in ipairs(tab) do
     if val > xam then
        index = i
        xam = val
      end
   end -- for
   return xam, index
end

a, b = max ( { 10, 20, 5, 5, 100, 99 }]
a --> 100
b --> 5

Eine Besonderheit ist der Aufruf mit einer variablen Anzahl von Parametern, die durch die Zeichenfolge ..., genannt vararg expression symbolisiert werden. Zu beachten ist, dass ... innerhalb der Funktion keine table, sondern eine Liste von Werten darstellt, die zur weiteren Bearbeitung mit {...} in eine table umgewandelt werden muss.

function variableParameterzahl (...)
   local tab = {...}
   for k, v in pairs(tab ) do
     -- irgendwelche Aktionen
  end
end

Man kann auch eine Parameterliste mit einer vararg expression kombinieren, diese muss am Ende der Parameterliste stehen. Derartige Funktionen heißen variadic functions

function variableParameterzahl (para1, para2, ...)
   local tab = {...}
   for k, v in pairs(tab ) do
     -- irgendwelche Aktionen
  end
end

Lua und MediaWiki Software

[edit]

Lua erfordert die Installation der Erweiterung Scribunto.

Beim Provider nachfragen, ob proc_open() möglich ist.

Jeder Lua-Modul ist eingekapselt und kann aus Sicherheitsgründen mit dem System ausschließlich über den Rückgabewert interagieren.

Jeder Lua-Modul liefert als Rückgabewert einen Textstring, der an der Stelle des Aufrufs in die aufrufende Seite eingebettet wird. Zum Zeitpunkt des Lua-Funktionsaufrufs hat der Parser etliche Schritte wie Vorlagenauswertung, Auswertung von Extension-Tags

(categorytree ce <charinsert> chem gallery graph hiero imagemap includeonly inputbox maplink math noinclude <nowiki> onlyinclude poem <pre> ref references score einbinden#section section (source) syntaxhighlight templatedata TemplateStyles timeline)

bereits durchgeführt. Das bedeutet, dass Vorlagen nicht mehr ausgewertet werden, wenn sie als Rückgabewert eines Lua-Moduls erscheinen, dieses Verhalten wird hier beschrieben. Vorlage können jedoch mit den Funktionen frame:expandTemplate und frame:preprocess zur Zeit der Durchführung des Moduls ausgewertet werden

Der Text {{Meine Vorlage}} im Rückgabestring wird daher nicht mehr ausgewertet, sondern als {{Meine Vorlage}} in der Wikiseite dargestellt.

Sonstige Tipps

[edit]

Die Erweiterung Code Editor vereinfacht das Editieren erheblich, indem sie Zeilennummern hinzufügt und den Code farblich gestaltet. Konfigurationstexte zum Copy&Paste gibt es hier.

Ein einfacher Lua-Modul

[edit]
local p = {} -- p stands for package

function p.mehrfach(frame)

  local w, count, vorlage="", frame.args.count, frame.args.vorlage or "2x"
  if count == nil then count = 1 end

  --[[ 
    Die Vorlage [[:Template:Vorlage]] hat beispielsweise die Parameter
    p, q und r. Die Werte von n Parametersätzen
    p1, q1, r1, p2 ... werden an den Modul übergeben.
    Wenn der Parameter p[j] existiert, wird die Vorlage [[:Template:Meine Vorlage]] 
    mit den Paramtern p[j], q[j] und r[j] aufgerufen, ggfs. werden Defaultwerte für
    q und r eingesetzt. Diese Defaultwerte könnten z.B. als weitere benannte Parameter
    übergeben werden.

  --]]
  if not mw.title.new("template:" .. vorlage).exists then return "Vorlage " .. vorlage .. " existiert nicht" end
  for i = 1,count do  
    local j = tostring(i)
    local p = frame.args["p" .. j]
    if p then
      local q = frame.args["q" .. j] or "default-q"
      local r = frame.args["r" .. j] or "default-r"
      w = w .. frame:expandTemplate{ title = vorlage, args = { p, q, r } }
    end
  end
  return w
end

function p.main(frame)
  local titel = frame.args.name or "Hauptseite"
  if mw.title.new(titel).exists then return "Seite " .. titel .. " existiert" 
  else return "Seite " .. titel .. " existiert nicht " end
end

function p.vorlage(frame)
  local titel = frame.args.name or "2x"
  if mw.title.new("template:" .. titel).exists then return "Vorlage " .. titel .. " existiert" 
  else return "Vorlage " .. titel .. " existiert nicht " end
end

function p.datei(frame)
  local titel = frame.args.name or "Info_Icon.png"
  if mw.title.new("File:" .. titel).exists then return "Datei " .. titel .. " existiert" 
  else return "Datei " .. titel .. " existiert nicht " end
end

function p.namespace(frame)
  return mw.site.namespaces.template.id .. mw.site.namespaces.template.name
end

function p.zerlegen(frame)
  local was, _ = {}, ""
  local i = 1
  local param = frame.args.param

  for _ in string.gmatch(param,"([%w!§&=%$%(%)%%%[%]%*%+%-%?]+),") do
    was[i] = _
    i = i+1
  end
  return #was .. " -- " .. table.concat( was, ", ")
end

function p.split(frame)
  --[[
  Diese Funktion teilt einen String durch Trennzeichen auf und erzeugt eine Tabelle
  nicht nur eine Tabelle, sondern sogar eine Sequence, d.h. die Elemente sind mit natürlich Zahlen
  indiziert
  --]]
  local was, _ = {}, ""
  local param = frame.args.param

  was = mw.text.split( param, '[%,%s]')
  return #was .. " -- " .. table.concat( was, ", ")
end
return p

Dokumentation

[edit]

Das umfangreiche System von Dokumentationsvorlagen soll durch einen einzigen Lua-Modul ersetzt werden.


Unterseiten