Aiuto:Lua: differenze tra le versioni

Da Wikipedia, l'enciclopedia libera.
Vai alla navigazione Vai alla ricerca
Contenuto cancellato Contenuto aggiunto
Riformulo
Etichette: Modifica da mobile Modifica da web per mobile
Riformulazione completata
Etichette: Modifica da mobile Modifica da web per mobile
Riga 91: Riga 91:


== Suggerimenti di stile ==
== Suggerimenti di stile ==
* Usare 4 spazi per l'indentazione e senza tabulazioni (l'[[Editor web|editor di codice]] di Wikipedia usa 4 spazi).
* Usare il [[tabulatore]] per l'[[indentazione]] (vanno bene anche i 4 spazi utilizzati dall'[[Editor web|editor di codice]] di Wikipedia).
* Limitare la lunghezza di una singola riga così che persone con monitor più piccoli possano comunque leggere con facilità il codice. Una riga troppo lunga può essere spezzata su linee multiple con l'indentazione allineata alla parentesi di apertura. Le condizioni di un'istruzione <code>if</code> dovrebbero essere piazzate su una linea successiva.
* Limitare la lunghezza di una singola riga così che persone con monitor più piccoli possano comunque leggere con facilità il codice. Una riga troppo lunga può essere spezzata su linee multiple con l'indentazione allineata alla parentesi di apertura. Le condizioni di un'istruzione <code>if</code> dovrebbero essere piazzate su una linea successiva.
* Evitare spazi inutili nelle chiamate di funzioni e tabelle o prima o dopo le parentesi di apertura (<code>[, (, {</code>) e di chiusura (<code>], ), }</code>).
* Evitare spazi inutili nelle chiamate di funzioni e tabelle o prima o dopo le parentesi di apertura (<code>[, (, {</code>) e di chiusura (<code>], ), }</code>).
Riga 108: Riga 108:
* Una '''lista di espressioni''' è un insieme di valori (stringhe, numeri, tabelle, funzioni, etc.) separati da virgole.
* Una '''lista di espressioni''' è un insieme di valori (stringhe, numeri, tabelle, funzioni, etc.) separati da virgole.
* Una '''sequenza''' è un insieme di valori che vanno da 1 a N (dove N è un intero positivo). Può essere creata racchiudendo tra parentesi graffe una lista di espressioni. Per esempio se <code>a = {1, "quotation", mw.ustring.gmatch( "abca", "a" ), {2, 3, 4}}</code> allora <code>a[1] = 1</code>, <code>a[2] = "quotation"</code>, <code>a[3]</code> equivale al valore restituito dalla funzione <code>gmatch</code> e <code>a[4]</code> è la tabella <code>{2, 3, 4}</code>. Una lista di espressioni può essere recuperata da una tabella con l'istruzione <code>unpack()</code>: <code>b, c, d = unpack(a)</code> restituirà <code>b = 1</code>, <code>c = "quotation"</code> e <code>d</code> alla funzione.
* Una '''sequenza''' è un insieme di valori che vanno da 1 a N (dove N è un intero positivo). Può essere creata racchiudendo tra parentesi graffe una lista di espressioni. Per esempio se <code>a = {1, "quotation", mw.ustring.gmatch( "abca", "a" ), {2, 3, 4}}</code> allora <code>a[1] = 1</code>, <code>a[2] = "quotation"</code>, <code>a[3]</code> equivale al valore restituito dalla funzione <code>gmatch</code> e <code>a[4]</code> è la tabella <code>{2, 3, 4}</code>. Una lista di espressioni può essere recuperata da una tabella con l'istruzione <code>unpack()</code>: <code>b, c, d = unpack(a)</code> restituirà <code>b = 1</code>, <code>c = "quotation"</code> e <code>d</code> alla funzione.
* Una '''tabella''' (o '''tavola''') è una sequenza supportata opzionalmente da chiavi con nome, per esempio <code>digit["two"] = "2"</code>. Va però ricordato che diverse funzioni come <code>table.concat</code> funzionano soltanto con gli indici numerici e ignorano questo tipo di chiavi.
* Una '''tabella''' (o '''tavola''') è una sequenza supportata opzionalmente da chiavi con nome, per esempio <code>digit["two"] = "2"</code>. Va però ricordato che diverse funzioni come <code>table.concat</code> richiedono necessariamente gli indici numerici e ignorano questo tipo di chiavi.
* Una '''metatable''' offre un vasto insieme opzionale di metodi per alterare il comportamento di una tabella. Permette anche di definire una tabella in modo che sia richiamabile come una funzione.
* Una '''metatable''' offre svariati metodi per alterare il comportamento di una tabella. Permette anche di definirne una in modo che sia richiamabile come una funzione.


== Funzioni ==
== Funzioni ==
* Una funzione può ritornare qualunque tipo di variabile &mdash; ''inclusa una funzione''. Questa è una caratteristica potente che può facilmente confondere un principiante. Per esempio l'istruzione <code>a=mw.ustring.gmatch(text,"(.)")</code> assegnerà ad <code>a</code> una funzione, non un valore stringa &mdash; in questo caso una funzione che ogni volta che viene chiamata ritornerà uno dei caratteri della stringa <code>text</code> fino ad esaurirli ed a ritornare <code>nil</code>. Molte funzioni iteratrici funzionano in questa maniera.
* Una funzione può ritornare qualunque tipo di variabile, ''inclusa una funzione''. Questa è una caratteristica potente che potrebbe confondere un principiante. Un esempio è l'istruzione <code>a = mw.ustring.gmatch( text, "(.)" )</code> che assegnerà ad <code>a</code> una funzione e non il valore di una stringa. In questo caso la funzione ritornerà ad ogni chiamata uno dei caratteri della stringa <code>text</code> fino ad esaurirli e tornare <code>nil</code>. Molte [[Iteratore|funzioni iteratrici]] agiscono proprio in questa maniera.
* Potete mantenere conteggi separati per funzioni iteratrici usando variabili differenti. Per esempio con l'istruzione <code>q=mw.ustring.gmatch(text,"(.)")</code> potete estrarre caratteri dalla stessa stringa dell'esempio precedente valutando <code>d=q()</code> senza che questo modifichi il comportamento di <code>a()</code>.
* È possibile mantenere i conteggi separati per funzioni iteratrici, utilizzando variabili differenti. L'istruzione <code>q = mw.ustring.gmatch( text, "(.)" )</code> estrarrà caratteri dalla stessa stringa dell'esempio precedente valutando <code>d = q()</code> senza che questo modifichi il comportamento di <code>a()</code>.
* Le funzioni che devono essere chiamate da un'istruzione <code><nowiki>{{#invoke|...}}</nowiki></code> devono essere della forma <code>p.myFunctionName</code>, dove <code>p</code> è la tabella che viene esportata al termine del modulo", altre funzioni sono locali al modulo e possono avere qualunque nome valido, ma non saranno accessibili dall'esterno del modulo.
* Le funzioni da chiamare col comando <code>{{#invoke|...}}</code> devono essere aperte nella forma <code>p.myFunctionName</code>, dove <code>p</code> indica la tabella che viene esportata al termine del modulo. Altre funzioni saranno locali al modulo e possono avere qualunque nome valido, ma non saranno accessibili dall'esterno del programma.


== Pagine correlate ==
== Pagine correlate ==

Versione delle 11:57, 12 dic 2017

Questa è un'introduzione per fornire un primo orientamento per chi è nuovo a Lua/Scribunto, il linguaggio utilizzato per creare i moduli. Non vuol essere una guida generale alla programmazione in Lua (ce ne sono già tante sul Web), ma all'uso specifico nel caso dei moduli di Wikipedia.

Se non sei interessato alla programmazione, ma solo all'uso di programmi già scritti, consulta le pagine correlate.

Generalità

Lua è un linguaggio di programmazione implementato su Wikipedia con alcune sostanziali restrizioni mediante Scribunto. Il suo scopo è permettere di processare i dati disponibili sulle pagine di Wikipedia per organizzarne in maniera personalizzata la visualizzazione.

La documentazione principale di Wikipedia in italiano è il manuale di riferimento al Lua, che fornisce un sommario conciso del linguaggio e delle librerie standard. I reference manuals originali del linguaggio sono ben scritti e comprensibili, ma potrebbero risultare problematici per i principianti, in quanto presentano alcune caratteristiche non compatibili con Wikipedia.

Creare un modulo di prova

Dato che i moduli funzionano solo nell'omonimo namespace, esiste la pagina Modulo:Sandbox per le prove (analogamente a Wikipedia:Pagina delle prove per gli ordinari esperimenti di modifica). Se si desidera creare un modulo di prova è possibile farlo in una sottopagina di Modulo:Sandbox creandone una con il proprio nome utente, in questo modo: Modulo:Sandbox/IlTuoNomeUtente/NomeModulo.

Implementazione corrente

Al momento per manipolare le stringhe è consigliabile utilizzare le funzioni della libreria mw.ustring invece che della mw.string, poiché quest'ultima non è in grado di gestire i caratteri Unicode e può produrre errori casuali o comportamenti inaspettati (per esempio codici come "UNIQ5ae8f2aa414ff233-h-3--QINU" nel testo trascluso).

Richiamare un modulo Lua

Esempio di chiamata di un modulo Lua

La chiamata di un modulo Lua è simile a quella di un template e consiste in un piccolo blocco di testo come {{#invoke:HelloWorld|hello}}.

Questo testo invoca lo script Lua "HelloWord" ospitato nel namespace Modulo. L'effetto della chiamata è quello di inviare le informazioni incluse nel blocco invoke al modulo Lua e rimpiazzare quanto contenuto nelle parentesi graffe con il testo che viene restituito dal modulo.

Infatti il primo "parametro", in questo caso "hello", è in realtà la chiamata di una funzione contenuta nel modulo Lua. Questo campo deve sempre essere incluso nell'istruzione #invoke. Chi è abituato all'utilizzo dei normali template di Wikipedia si aspetterebbe che tutto quello che compare dopo il primo | fosse un parametro e la presenza di questo campo potrebbe confonderlo. Quando si documenta un modulo è pertanto utile includere degli esempi d'uso espliciti come {{#invoke:HelloWorld|hello}}, così che ci si ricordi di compilarlo.

Se si verifica un errore di esecuzione, il blocco invoke sarà sostituito dalla scritta rossa "⧼scribunto-parser-error⧽". Se nel proprio browser è abilitato il JavaScript, è possibile cliccare sulla scritta per aprire una finestra pop-up contenente una descrizione dettagliata dell'errore e di solito un collegamento diretto alla riga da correggere. Ci sono alcune eccezioni, per esempio nel caso di "Errore script: nessun modulo "$2"." o "Errore script: la funzione "$2" non esiste." se i nomi del modulo o della funzione sono sbagliati.

Output

La parte fondamentale di un programma Lua è l'istruzione return, che restituisce il risultato della funzione alla pagina che contiene l'#invoke. Una funzione Lua può anche non contenere un'istruzione return, ma allora sarebbe inutile chiamarla.

Il modulo deve ritornare una tabella di valori, che in Lua sono espressi come una lista di oggetti separati da virgole all'interno di parentesi graffe. Quando il modulo viene chiamato dal comando #invoke, il primo parametro del comando (il nome della funzione) viene ricercato nella tabella esportata. La funzione viene quindi invocata e deve ritornare qualcosa di rappresentabile come una stringa.

Tipicamente un modulo Lua avrà questa forma:

-- Tutti i moduli Lua su Wikipedia devono iniziare definendo una variabile di tipo tabella che contenga
-- le funzioni accessibili dall'esterno. Può avere qualunque nome e contenere anche altri dati.
local p = {}

-- Viene aggiunta una funzione alla variabile. Questa è richiamabile da Wikipedia mediante il
-- comando #invoke.
-- L'argomento "frame" conterrà i dati che Wikipedia invia a questa funzione quando viene
-- chiamata.
function p.hello( frame )
    -- L'istruzione successiva termina la funzione e ritorna la stringa "HelloWorld" a Wikipedia.
    -- La funzione verrà visualizzata al posto del richiamo del comando #invoke.
    return "Hello, world!"
-- Termina la funzione.
end

-- Il modulo deve terminare restituendo la variabile che contiene le sue funzioni a Wikipedia.
return p

-- Questo modulo può ora essere utilizzato chiamando {{#invoke:HelloWorld|hello}}.
-- Il comando #invoke inizia con il nome del modulo, in questo caso "HelloWorld",
-- quindi il nome di una delle sue funzioni come argomento, in questo caso "hello".

Input

I programmi vengono eseguiti solo quando la pagina viene analizzata "sintatticamente" (cioè quando essa o una pagina che la incorpora vengono modificate o mostrate in anteprima), non ogni volta che viene visualizzata. Pertanto non è possibile realizzare un modulo Lua che permetta di inserire una temperatura in Fahrenheit e ottenerne il valore in Celsius o cliccare su un segmento di un insieme di Mandelbrot per espanderlo. Deve esserci una pagina Wiki (o perlomeno una pagina di cui sia stata richiesta l'anteprima) che contenga i dati di input. È comunque possibile utilizzare le funzioni di libreria come mw.title.new per importare contenuto da ogni testo presente su Wiki. Non si possono però importare dati dai file, nemmeno da quelli in formato .svg (nonostante sia un formato XML testuale).

Quando la funzione p.hello viene chiamata, riceve un argomento di tipo tabella che contiene varie informazioni passate dalla pagina di Wikipedia che effettua la chiamata di {{#invoke:HelloWorld|hello}}, tra cui gli argomenti della chiamata stessa. L'argomento della funzione può avere qualunque nome Lua valido, ma convenzionalmente su Wikipedia è utilizzato il nome frame.

frame contiene un'altra tabella, frame.args, che a sua volta contiene i parametri passati nella chiamata di #invoke (fatta eccezione per il primo parametro, usato soltanto per selezionare il nome della funzione da eseguire).

Parametri posizionali

  • Se la funzione len del modulo:String viene chiamata con {{#invoke:String|len|Pippo}}, allora frame.args[1] conterrà la stringa "Pippo".
  • Con l'istruzione {{#invoke:HelloWorld|hello_nome1|Pippo|come va}} verrà richiamata la funzione hello_nome1 del modulo:HelloWorld, a cui saranno passati due parametri contenenti rispettivamente le stringhe "Pippo" e "come va". Queste saranno accessibili all'interno del modulo attraverso le istruzioni frame.args[1] e frame.args[2].

Parametri nominali

I parametri nominali vengono indicizzati con un nome per il parametro. Un esempio di chiamata con parametri nominali è {{#invoke:HelloWorld|hello_nome2|nome=Pippo|saluto=come va}}, in cui verrà chiamata la funzione hello_nome2 che riceverà i due parametri nome e saluto, contenenti le stringhe "Pippo" e "come va". In questo caso il loro contenuto sarà accessibile con le istruzioni frame.args["nome"] e frame.args["saluto"].

Quando i nomi dei parametri contengono solo caratteri alfabetici, numeri e il carattere underscore (e non iniziano con un numero), è possibile accedere al loro valore anche con l'istruzione frame.args.nome_parametro, quindi nell'esempio sopra con frame.args.nome e frame.args.saluto.

frame:getParent

frame contiene un puntatore all'argomento "padre", quello del modulo invocato, utile per recuperare gli argomenti in caso di funzione richiamata da un template, nel momento in cui questo viene incluso all'interno di un'altra pagina. È sufficiente il comando

local args = frame.getParent( frame ).args

e la tabella args conterrà quegli argomenti.

Un'abbreviazione per il comando sopra è frame:getParent().args, in cui il parametro (frame) viene sottinteso dai due punti.

Debuglog

Il programma può essere testato fin dall'inizio, semplicemente usando la concatenazione di stringhe. È sufficiente aggiungere una variabile con un nome riconoscibile come "debuglog" nella funzione da analizzare, con un'istruzione come local debuglog = "" (dev'essere inizializzata con una stringa vuota, altrimenti avrebbe un valore nil e concatenare una stringa genererebbe un errore). La sintassi per testare una variabile x è la seguente:

debuglog = " x = " .. tostring(x)

La funzione tostring impedisce di commettere degli errori: forzerà sempre il valore della variabile x in modo che compilazioni come "table" (tavola) e "nil" (indefinita) vengano mostrate.

Al termine del programma è indispensabile inserire il comando return output .. debuglog, dove "output" indica il valore da ritornare (se stabilito in precedenza) a cui viene concatenato il valore di debuglog.

Suggerimenti di stile

  • Usare il tabulatore per l'indentazione (vanno bene anche i 4 spazi utilizzati dall'editor di codice di Wikipedia).
  • Limitare la lunghezza di una singola riga così che persone con monitor più piccoli possano comunque leggere con facilità il codice. Una riga troppo lunga può essere spezzata su linee multiple con l'indentazione allineata alla parentesi di apertura. Le condizioni di un'istruzione if dovrebbero essere piazzate su una linea successiva.
  • Evitare spazi inutili nelle chiamate di funzioni e tabelle o prima o dopo le parentesi di apertura ([, (, {) e di chiusura (], ), }).
  • Dividere istruzioni multiple su righe diverse, a meno che non siano molto brevi.
  • Lasciare dei commenti con un doppio -. Usarli è davvero utile: anche nei moduli più semplici, dei commenti chiari aiutano a modificare del codice scritto da altri autori o non modificato da tempo.

Errori

Alcuni tipici errori:

  • Una variabile ignora qualunque tentativo di assegnarle un valore. Sono presenti due istruzioni local e la prima setta il valore in una regione limitata del programma: uscendo da quella regione, questa viene scartata in favore dell'istruzione generale (rimasta al vecchio valore).
  • Un valore di una tabella numerata ignora i tentativi di assegnargliene un altro. Questo avviene perché a["50"] ≠ a[50]. Processare un parametro rimandante alla funzione di una riga, con un secondo valore numerico collocato su una riga differente, lascia al modulo due diversi tipi di variabile da usare come indice.
  • Attempt to call a string value. L'identificatore .. è stato dimenticato tra una stringa e una variabile in una sequenza di concatenzione.
  • ... nil ... Un valore indefinito impedisce diverse azioni, per esempio assegnare un valore ad a.1 se a è nil o la concatenazione a .. b se una delle due è nil. È indispensabile inizializzare le variabili con dei valori come local a = "" o local a = {}. In assenza di una variabile inizializzata con local, viene spesso utilizzato anche global.
  • string expected, got function. Alcune funzioni come mw.ustring.gmatch ritornano funzioni e non stringhe.

Concetti base

  • Una lista di espressioni è un insieme di valori (stringhe, numeri, tabelle, funzioni, etc.) separati da virgole.
  • Una sequenza è un insieme di valori che vanno da 1 a N (dove N è un intero positivo). Può essere creata racchiudendo tra parentesi graffe una lista di espressioni. Per esempio se a = {1, "quotation", mw.ustring.gmatch( "abca", "a" ), {2, 3, 4}} allora a[1] = 1, a[2] = "quotation", a[3] equivale al valore restituito dalla funzione gmatch e a[4] è la tabella {2, 3, 4}. Una lista di espressioni può essere recuperata da una tabella con l'istruzione unpack(): b, c, d = unpack(a) restituirà b = 1, c = "quotation" e d alla funzione.
  • Una tabella (o tavola) è una sequenza supportata opzionalmente da chiavi con nome, per esempio digit["two"] = "2". Va però ricordato che diverse funzioni come table.concat richiedono necessariamente gli indici numerici e ignorano questo tipo di chiavi.
  • Una metatable offre svariati metodi per alterare il comportamento di una tabella. Permette anche di definirne una in modo che sia richiamabile come una funzione.

Funzioni

  • Una funzione può ritornare qualunque tipo di variabile, inclusa una funzione. Questa è una caratteristica potente che potrebbe confondere un principiante. Un esempio è l'istruzione a = mw.ustring.gmatch( text, "(.)" ) che assegnerà ad a una funzione e non il valore di una stringa. In questo caso la funzione ritornerà ad ogni chiamata uno dei caratteri della stringa text fino ad esaurirli e tornare nil. Molte funzioni iteratrici agiscono proprio in questa maniera.
  • È possibile mantenere i conteggi separati per funzioni iteratrici, utilizzando variabili differenti. L'istruzione q = mw.ustring.gmatch( text, "(.)" ) estrarrà caratteri dalla stessa stringa dell'esempio precedente valutando d = q() senza che questo modifichi il comportamento di a().
  • Le funzioni da chiamare col comando {{#invoke|...}} devono essere aperte nella forma p.myFunctionName, dove p indica la tabella che viene esportata al termine del modulo. Altre funzioni saranno locali al modulo e possono avere qualunque nome valido, ma non saranno accessibili dall'esterno del programma.

Pagine correlate