Lua è un linguaggio di programmazione completo, recentemente installato su MediaWiki come alternativa ai template. Più precisamente, Lua è fatto in modo da integrare, piuttosto che sostituire, i template, con un codice estremamente più potente ed efficiente. In particolare, la migrazione dai template agli script Lua può essere fatto in modo completamente trasparente per l'utente: il codice template può essere sostituito da una chiamata ad un modulo o a una speicifica funzione di Lua, mantenendo inalterato il codice di chiamata del template. Quindi, per l'utente finale, volendo, non cambia assolutamente nulla: il {{Sc}}, ad esempio, continuerà, volendo, ad essere chiamato con il codice {{Sc|Parole in maiuscoletto}} e l'utente finale non ha motivo nè modo di porsi il problema di che tipo di codice si scatena.

L'implementazione di Lua in MediaWiki è stata accompagnata dall'aggiunta di un nuovo namepace (Modulo:), dalla definizione di un metodo di inclusione del linguaggio nell'ambiente MediaWiki, e dalla realizzazione di alcune librerie fra le quali particolarmente importante quella che consente di gestire i caratteri Unicode. L'insieme degli adattamenti di Lua a MediaWiki è definito con il nome di Scribunto.

Documentazione generale modifica

  1. Linguaggio Lua in generale: sito principale
  2. Implementazione in MediaWiki: Scribunto, Manuale
  3. Estensioni implementate: Scribunto, che comprende anche LuaSandbox

Alcune differenze fondamentali con il linguaggio template e con js-python modifica

differenze rispetto ai template
  1. Lua è un vero linguaggio di programmazione, che usa variabili, funzioni, oggetti.
  2. possiede un completo set di funzioni per le stringhe, che mancavano totalmente nei template e che permettono/impongono un completo ripensamento della logica di costruzione degli algoritmi;
  3. la chiamata ripetuta di un modulo Lua nella stessa pagina comporta un ridotto tempo di elaborazione
  4. Lua è efficiente nella lettura e elaborazione di grosse masse di dati (può quindi sostituire i "mega-switch" utilizzati in alcuni template)
differenze rispetto a js-python
  1. possiede un sistema originale (e semplificato) di "regex" (i patterns); una delle opzioni è potentissima, in quanto rende i patterns capaci di risolvere i costrutti annidati (tag html, codice template), cosa che le regex non possono fare, rendendo di fatto inutile find_stringa() e produci_lista();
  2. molti degli operatori di base sono diversi;
  3. l'implementazione come estensione di altri programmi richiede l'introduzione di un concetto di frame (ambiente di lavoro) non semplicissimo da padroneggiare;
  4. sono disponibili delle specifiche librerie di funzioni per l'ambiente MediaWiki
interazioni template-moduli
  1. è possibile chiamare un modulo Lua da un template; vedi Template:VoceIndice;
  2. è possibile passare a Lua come parametri ogni tipo di codice wiki (link, template)
  3. è possibile quindi convertire il solo codice template (inserendo al suo interno una chiamata a Lua) senza modificare minimamente il codice di chiamata template e quindi senza modificare il codice delle pagine dove è scritta la chiamata al template scritto in modo tradizionale.

Lua e LuaSandbox: esempio modifica

Su fr.source corre il template Table, che fa una cosa assai simile al nostro RigaIndice, e si appoggia a uno script Lua.

E' possibile far correre anche qui una implementazione di prova utilizzando in pratica sia l'estensione Lua che l'estensione LuaSandbox. Per farlo seguite queste istruzioni:

  • copiare Utente:Alex brollo/sandbox/Modulo:Table in una vostra pagina (sostituendo Alex brollo con il vostro nome utente);
  • copiare Utente:Alex brollo/sandbox/Template:Table in una vostra pagina (come sopra);
  • entrare in Speciale:TemplateSandbox
    • nel campo "Prefisso della sandbox" impostare Utente:Alex brollo/sandbox (sostituendo Alex brollo con il vostro nome utente)
    • nel campo "Pagina da visualizzare" impostare Utente:Alex brollo/sandbox/Pagina:Prova (sic: qui non modificare!)
    • lasciare in bianco gli altri due campi; premere "Visualizza".

Da qui in poi potete sperimentare modificando i codici delle due sottopagine Modulo:Table e Template:Table e chiamando in visualizzazione qualsiasi pagina in cui abbiate inserito del codice di prova.

La rivoluzione mw.loadData() modifica

La funzione consente di caricare in memoria una tabella di dati, che resta stabile nella memoria del browser (viene caricata una volta sola anche se viene poi utilizzata più volte in ripetute chiamate di scripts Lua).

Questo meccanismo consente un caricamento ed uso particolarmente rapido di serie di dati complessi ripetitivi; sfruttando questa possibilità dovrebbe essere finalmente possibile costruire (via bot) delle buone tabelle di dati dei singoli libri avviandosi a un efficiente e rapido automatismo nella costruzione di link (es. conversione numero di pagina cartacea->numero di pagina djvu->link a capitolo in ns0; forse soluzione definitiva di AutoreCitato; altro?)

La tabella va inserita in una pagina Modulo; un semplice esempio (verificato) in Modulo:Dati.

Un test che funziona modifica

In Modulo:Dati/Opere di Niccolò Machiavelli VI.djvu trovate un "contenitore di dati" Lua, fatto per essere caricato con l'istruzione mw.loadData(). Rappresenta il set di dati prodotto dal tag pagelist in Indice:Opere di Niccolò Machiavelli VI.djvu. La pagina non è scritta a mano: è prodotta dallo script contenuto in Utente:Alex brollo/parseIndice.js in circa mezzo secondo. In futuro, se l'idea passa, sarà costruita via bot, e eventualmente aggiornata con un click su un bottone o su un link o con una hotkey AltGr-l per i furbacchioni che usano Chrome Shortcut Manager.

Questa "base-dati" viene caricata da uno script Lua che sta in Modulo:Pg. A sua volta Modulo:Pg viene chiamato da {{Pg}}. Per ora il template Pg funziona solo in nsPagina.

Esaminiamo Modulo:Dati/Opere di Niccolò Machiavelli VI.djvu e i suoi dati.

Innanzitutto, viene costruita la tabella d2b che corrisponde a un array semplice, in cui l'indice dell'elemento rappresenta il numero di pagina djvu. Esempio: d2b[6]="i" significa che nella pagina djvu 6 è contenuta la pagina denominata "i".

Alla fine dell'elenco, le istruzioni:

for i,v in ipairs(d2b)
    do
      b2d[v]=i
    end

creano la seconda tabella b2d; questa è una tabella a chiave, la chiave è la denominazione della pagina, il valore è il numero dalla pagina djvu.

A questo punto inizia la tabella che rappresenta i dati di Indice sommario. E' un array di tabelle a chiave; ogni riga di Indice sommario diventa un oggetto con cinque attributi: nome, titolo, from, to (calcolato), e delta.

Per seguire il procedimento, esaminiamo il codice della pagina Pagina:Pensieri e giudizi.djvu/195, che usa Pg.

A ciascun numero di pagina (pagine del libro, corrispondono a book -> b quindi b2d mnemonicamente significa converti book in djvu) viene applicato il template con il numero pagina come unico parametro. Con un tool o una semplice regex si può fare in un colpo solo, se tutti i numeri del testo di una pagina corrispondono a numeri pagina in cifre. Se i numeri di pagina hanno formati alieni, numeri romani o quant'altro, si applica il template a mano.

Il codice del template è il seguente:

{{#switch:{{NAMESPACE}}
|Pagina
|Indice=[[Pagina:{{BASEPAGENAME}}/{{#invoke:Prova|b2dt}}|{{{1|}}}]]
|{{{1|}}}
}}

che significa: se siamo in nsIndice o in nsPagina, crea un link verso la pagina djvu che verrà restituita da Modulo:Pg, funzione b2dt. Altrimenti, restituisci il numero di pagina com'è.

Vediamo la funzione b2dt di Modulo:Pg.

local p = {}

function p.b2dt(frame)                     
   local base = mw.title.getCurrentTitle()
   local paginaDati="Modulo:Dati/"..base.rootText
   local pagine = mw.loadData(paginaDati)
   frame=frame:getParent()
   risultato=pagine.b2d[frame.args[1]]
   return risultato
end

function p.b2ns0(frame)
.....

return p
local base = mw.title.getCurrentTitle()
acchiappa il titolo della pagina da cui è stato chiamato il template...
local paginaDati="Modulo
Dati/"..base.rootText: ricava il nome base dell'indice e delle pagine...
local pagine = mw.loadData(paginaDati)
carica la pagina dati di quel nome base...
frame=frame
getParent(): questa mi è costata sangue per capirla.... chiede a Lua di non considerare i parametri di #invoke, ma dell'ambiente che ha chiamato #invoke ossia: i parametri del template (in questo caso, il solo numero della pagina del libro)
risultato=pagine.b2d[frame.args[1]]
adesso in memoria c'è la tabella pagine giusta (letta con mw.loadData), il risultato è il valore contenuto nella sottotabella b2d, con chiave frame.args[1] (ossia: il primo e unico parametro di Pg)
return risultato... end... return p; il valore viene restituito a p e sostituisce la chiamata #invoke nel codice template; il template restituisce il link "finito".

Nei prossimi giorni, verrà sistemata la seconda parte del template Pg, che scatterà in ns0 e chiamerà una funzione Lua diversa. La funzione Lua:

  1. leggerà il codice raw della pagina ns0
  2. troverà un tag pages
  3. leggerà il valore del parametro index
  4. caricherà i dati
  5. trasformerà il numero pagina in numero pagina djvu
  6. infine scorrerà la lista dei capitoli vedendo in quale capitolo "casca" la pagina djvu
  7. restituirà il nome completo del capitolo al template e il template lo integrerà nel link.
Aggiornamento
più facile di quello che pensavo, scrivere la funzione b2ns0:   Fatto.

Utenti interessati modifica