Archivio per la categoria "Lua"



LuaRocks! Ovvero, un comodo package manager per le librerie di Lua

Lua è un linguaggio di programmazione dinamico e portabile particolarmente noto e utilizzato come linguaggio embdedded grazie ad alcune caratteristiche, proprie e della sua VM, che lo rendono ottimo per lo scripting di applicazioni più o meno complesse scritte in altri linguaggi, solitamente compilati. Ovviamente può essere utilizzato anche per programmare intere applicazioni oppure semplicemente script di automazione, ma in casi simili è molto facile che ci si ritrovi con la necessità di utilizzare librerie esterne da installare e gestire separatamente e manualmente: Lua infatti, diversamente da linguaggi come Ruby o Python, nella sua distribuzione ufficiale non fornisce un set di librerie standard insieme al runtime. Il crescente numero di queste librerie di terze parti ha cominciato a rendere difficile la gestione delle stesse nei propri sistemi e per questo, quasi un anno fa, è nato LuaRocks, un progetto per la realizzazione di sistema di distribuzione e gestione di moduli per Lua che per certi versi risulta essere molto simile a RubyGems.

Attualmente per installare LuaRocks nella maggior parte delle distribuzioni Linux è necessario prelevare il tarball ed eseguire i soliti passaggi ./configure && make && make install, tuttavia l'installazione sulle Ubuntu-derivate a partire da 8.04 Intrepid Ibex o su Debian a partire da 5.0 Lenny sarà molto più semplice dal momento che basterà installare il pacchetto luarocks tramite apt-get. Per Windows esiste un installer che automatizza le procedure, lasciando all'utente la scelta se installare un interprete Lua basilare senza librerie fornito dallo stesso installer o se utilizzare un interprete già installato nel proprio sistema. Tutte le informazioni necessarie al download e all'installazione di LuaRocks sono disponibili sul relativo sito.

Nel frattempo pochi mesi fa è nato un installer di Lua per Windows chiamato, con molta fantasia, Lua for Windows. Esso include molte delle più note librerie per Lua e un ambiente di sviluppo/debug già configurato e basato su SciTE. Si tratta quindi di un'ottima soluzione per avere in pochi secondi tutto il necessario per poter programmare in Lua, tuttavia LuaRocks non è stato ancora incluso per cui ecco i passaggi da seguire per integrare il tutto:

  • Scaricare Lua for Windows (LfW) e procedere con l'installazione: la mia installazione è stata effettuata nel path proposto di default, ovvero C:\Programmi\Lua\5.1
  • Scaricare LuaRocks per Windows, decomprimere l'archivio e aprire la shell dei comandi nella directory contenente install.bat
  • L'installer di LuaRocks permette di specificare alcune opzioni. Ecco come installarlo in modo che sfrutti l'interprete reso disponibile da LfW e che utilizzi un unico path per l'installazione dei pacchetti rock:

    install /LUA C:\Programmi\Lua\5.1 /BIN C:\Programmi\Lua\5.1 /P C:\Programmi\Lua\5.1\LuaRocks\0.6 /CONFIG C:\Programmi\Lua\5.1\LuaRocks /TREE C:\Programmi\Lua\5.1\LuaRocks\ /SCRIPTS C:\Programmi\Lua\5.1\LuaRocks\ /FORCECONFIG

    Di default LuaRocks permette anche ad utenti non amministrativi di installare dei pacchetti rock locali (solitamente in %APPDATA%/luarocks/rocks/), mentre con l'opzione /FORCECONFIG verrà considerato un unico file di configurazione, quello specificato da /CONFIG, e un unico path per l'installazione di rock e script a livello di sistema, specificati rispettivamente da /TREE e /SCRIPT. Potete fare riferimento alla documentazione per un approfondimento in merito.

  • La directory C:\Programmi\Lua\5.1 viene automaticamente aggiunta al PATH di sistema dall'installer di LfW per cui possiamo creare un hardlink ai file luarocks.bat e luarocks-admin.bat con il fine di poter invocare gli stessi più comodamente dalla shell. Da Windows XP in avanti si può operare come segue:

    cd C:\Programmi\Lua\5.1\LuaRocks\0.6
    fsutil hardlink create ../../luarocks.bat luarocks.bat
    fsutil hardlink create ../../luarocks-admin.bat luarocks-admin.bat

  • Modificare la variabile di sistema LUA_PATH aggiungendo ai path già impostati da LfW il seguente percorso per il caricamento dei file della libreria LuaRocks:

    C:\Programmi\Lua\5.1\LuaRocks\0.6\lua\?.lua

Ora LuaRocks è installato e funzionante, basta aprire la shell dei comandi e lanciare luarocks search --all per visualizzare tutti i pacchetti rock disponibili sul server (è disponibile anche un elenco consultabile più comodamente) e luarocks install nomepacchetto per installare i pacchetti rock nel sistema. A questo punto negli script Lua basterà aggiungere la riga require "luarocks.require" che si occuperà di effettuare l'override della funzione require standard di Lua, rendendo possibile il caricamento delle librerie installate tramite LuaRocks. Alternativamente si può ottenere lo stesso risultato lanciando così l'interprete: lua -lluarocks.require

Ecco un esempio di come sfruttare una libreria installata tramite LuaRocks:

-- luarocks install colors require "luarocks.require" require "colors" green = colors.new("#0f8923") print("Verdolino:", green) -- Verdolino: #0f8923

LuaRocks con l'ultima release ha raggiunto un livello di maturità accettabile e l'elenco delle librerie disponibili sotto forma di pacchetti rock è in lento ma costante aumento, ma ci sono alcune applicazioni o framework che ne traggono beneficio per l'installazione e la gestione delle loro dipendenze come per esempio Kepler (un framework per lo sviluppo web generico in Lua), Orbit (un altro framework per lo sviluppo web in Lua, ma MVC oriented) e Sputnik (un wiki scritto in Lua, leggero ma estendibile). Per la cronaca, ecco invece cosa si era costretti a fare solamente un anno fa per avere un'installazione minimale di Lua in Windows e cominciare ad aggiungere librerie come LuaSocket.

Microbenchmark: Ruby 1.9.0 contro tutti (... non proprio...)

Il rilascio di Ruby 1.9 è previsto intorno a Natale e con il passare dei giorni la curiosità dei rubyisti si fa sempre più intensa. Stuzzicato da un microbenchmark pubblicato da Antonio Cangiano sul suo blog in cui ha messo a confronto la velocità di esecuzione di Ruby 1.8.6, Ruby 1.9.0 e Python 2.5.1 usando volutamente una funzione ricorsiva che calcolasse i primi 35 numeri della successione di Fibonacci, ho pensato che sarebbe stato interessante fare lo stesso test con i suoi script ma con condizioni diverse. A differenza di Antonio, che ha eseguito il suddetto microbenchmark sul suo MacBook Pro con OS X 10.5, ho pensato di effettuare i miei test su Windows chiamando in causa a questo punto anche IronRuby e, tanto per fare, anche PHP e Lua. Mi sarebbe piaciuto provare anche JRuby, ma purtroppo non ho nessuna esperienza e non saprei nemmeno da dove cominciare.

  • Configurazione: Microsoft Windows XP SP2 (x86) - AMD Athlon64 3700+ (2,2 GHz) - 2 GB RAM
  • Dettaglio versioni:
    • Ruby 1.9.0 (SVN rev. 14067 compilata con VC++ 2005)
      ruby 1.9.0 (2007-12-01 patchlevel 0) [i386-mswin32_80]
    • Ruby 1.8.6 (Ruby OneClick Installer 1.8.6-25)
      ruby 1.8.6 (2007-03-13 patchlevel 0) [i386-mswin32]
    • IronRuby 1.0 pre-alpha (SVN rev. 65 compilata con CSC di VS 2005)
      IronRuby Pre-Alpha (1.0.0.0) on .NET 2.0.50727.832
    • Python 2.5.1 (Standard Python 2.5.1 Windows Installer)
      Python 2.5.1 (r251:54863, Apr 18 2007, 08:51:08) [MSC v.1310 32 bit (Intel)]
    • Python 3.0a1 (Standard Python 3.0a1 Windows Installer)
      Python 3.0a1 (py3k:57844, Aug 31 2007, 16:54:27) [MSC v.1310 32 bit (Intel)]
    • PHP 5.2.5 (Binari ufficiali per Win32 - versione TS - no debug - Zend Engine 2.2.0)
      PHP 5.2.5 (cli) (built: Nov  8 2007 23:18:51)
    • PHP 5.3.0 (Snapshot ufficiale - versione TS - no debug - Zend Engine 2.3.0)
      PHP 5.3.0-dev (cli) (built: Dec  1 2007 04:19:04)
    • PHP 6.0.0 (Snapshot ufficiale - versione TS - no debug - Zend Engine 3.0.0-dev)
      PHP 6.0.0-dev (cli) (built: Dec  1 2007 02:04:58)
    • Lua 5.1.2 (LuaBinaries per Win32 di LuaForge)
      Lua 5.1.2  Copyright (C) 1994-2007 Lua.org, PUC-Rio

Le build di Ruby 1.9 e IronRuby sono state effettuate direttamente da me allineandomi questa mattina con i trunk nei rispettivi repository SVN, nel primo caso senza badare a ottimizzazioni particolari e nel secondo caso usando la modalità release. Per le versioni di sviluppo di PHP ho prelevato questa mattina da snaps.php.net i binari ufficiali e ho effettuato i test con la configurazione (php.ini) di default, così come per la versione stabile 5.2.5. Lo script per Python è stato leggermente modificato per la versione 3.0 dal momento che print è diventata una funzione e funziona diversamente dalla versione 2.5.

Gli script usati per Ruby, IronRuby e Python sono gli stessi di Antonio, aggiungo solo le mie varianti Lua e PHP (occhio, si tratta solamente di un becero port ai rispettivi linguaggi). Ecco come si presenta la versione in Lua:

function fib(n) if n == 0 or n == 1 then return n end return fib(n - 1) + fib(n - 2) end for n = 0, 35 do print("n=" .. n .. " => " .. fib(n)) end

Ed ecco invece la versione in PHP:

function fib($n) { if ($n == 0 || $n == 1) return $n; return fib($n - 1) + fib($n - 2); } for ($i = 0; $i <= 35; $i++) echo "n=", $i, " => ", fib($i), "\n";

I tempi riportati di seguito rappresentano la media calcolata sui risultati di 6 esecuzioni scartando la prima. Ecco i risultati ottenuti:

Ruby 1.9.0 : 21,123s
Ruby 1.8.6 : 94,736s
IronRuby : 26,123s
Python 2.5.1 : 33,827s
Python 3.0a1 : 48,718s
PHP 5.2.5 : 91,672s
PHP 5.3.0 : 77,813s
PHP 6.0.0 : 73,969s
Lua 5.1.2 : 14,912s

Ora un po' di considerazioni:

  • Ruby 1.9 è dannatamente più veloce di Ruby 1.8.6. Punto.
  • IronRuby non è nemmeno uscito dallo stato di pre-alpha e già offre prestazioni molto buone, vicine a quelle di Ruby 1.9 che invece si sta avvicinando al rilascio. Ottimo!
  • Mi incuriosisce la differenza tra i tempi di Ruby 1.8.6 registrati da Antonio su OS X e quelli registrati da me su Windows: 159 secondi rispetto a 95 secondi mi sembra un abisso, soprattutto perché immagino che un Core 2 Duo 2.2 GHz sia più performante di un Athlon64 3700+ 2.2GHz.
  • Python 3.0 è più lento di Python 2.5.1, ma la versione 3.0a1 risale a fine Agosto per cui sarebbe il caso di ripetere lo stesso benchmark con una versione più aggiornata.
  • PHP sembra migliorare abbastanza con il passaggio da Zend Engine da 2.2.0 a 2.3.0, ma comunque le prende alla grande da Ruby 1.9 e Python.
  • Lua li straccia senza alcun ritegno.
  • Ordine di arrivo: Lua 5.1.2, Ruby 1.9.0, IronRuby 1.0 pre-alpha, Python 2.5.1, Python 3.0a1, PHP 6.0, PHP 5.3, PHP 5.2.5, Ruby 1.8.6.

Ovviamente un singolo microbenchmark di questo tipo non può essere assolutamente considerato come un valido indicatore delle prestazioni offerte da un linguaggio in situazioni reali, però i risultati sono comunque curiosi. A quanto pare i rubyisti avranno già un bel regalo assicurato per questo Natale 🙂

PS: noto al termine della scrittura che Antonio ha scritto un altro articolo, aggiungendo Lisp e Haskell.

Invocare metodi Lua da C# con i Delegate

Nel precedente messaggio abbiamo visto come recuperare un oggetto LuaFunction, contenente il riferimento a una funzione definita in uno script Lua, sfruttando il metodo GetFunction. Lo stesso metodo però ha un overload abbastanza interessante che offre la possibilità di recuperare un delegate, con il vantaggio di poterci quindi integrare meglio all'interno del framework .NET. Vediamo un esempio:

1 using System; 2 using LuaInterface; 3 4 namespace NRK 5 { 6 public delegate double AddDelegate(double a, double b); 7 8 class Application 9 { 10 static void Main(string[] args) 11 { 12 Lua lua = new Lua(); 13 14 lua.DoString(@" 15 function add(x, y) 16 return x + y 17 end 18 "); 19 20 AddDelegate add = lua.GetFunction(typeof(AddDelegate), "add") as AddDelegate; 21 22 if (IsDefinedInLua(add)) 23 { 24 double res = add(5.3, 3.2); 25 Console.WriteLine(String.Format("Il risultato è: {0}", res)); 26 } 27 } 28 29 static bool IsDefinedInLua(Delegate delegateOfFunction) 30 { 31 if (delegateOfFunction.Target is LuaDelegate) 32 return (delegateOfFunction.Target as LuaDelegate).function != null; 33 34 return false; 35 } 36 } 37 }

Come al solito analizziamo il codice:

  • riga 6: definiamo il delegate che verrà utilizzato per invocare la nostra funzione in Lua. Purtroppo non è possibile definire il delegate utilizzando una lista variabile di argomenti dal momento che LuaInterface non lo supporta, quindi questo tipo di definizione non è valido e a runtime lancia un'eccezione:
    // non funzionerà a runtime... public delegate double AddDelegate(params double[] args);
  • riga 20: l'overload di GetFunction prende come parametri un System.Type per poter generare il delegate del tipo corretto e il nome della funzione in Lua da associargli. Come potete vedere la sintassi è un po' verbosa, usando i generics sarebbe possibile rimuovere almeno un AddDelegate e la chiamata a typeof, per fare ciò dovremmo definire un metodo di utilità come vedremo più avanti.
  • riga 22: il metodo IsDefinedInLua che qui abbiamo utilizzato e che alla riga 29 abbiamo definito è un helper che ci permette di capire se internamente il nostro delegate punta a una funzione Lua effettivamente definita oppure no, questo per evitare di incappare in una NullReferenceException nel caso nel codice Lua non sia esistente la funzione add. La mia impressione è che probabilmente sarebbe stato meglio se in LuaInterface avessero definito un tipo che identificasse chiaramente il puntamento a una funzione inesistente all'interno di una istanza di LuaDelegate (chessò, un tipo NullLuaFunction per esempio) anziché utilizzare direttamente null, in questo modo avrebbero evitato ai programmatori di incappare in eccezioni di questo tipo a runtime o di effettuare costantemente dei controlli per evitarle.

Facendo un passo indietro, prima abbiamo notato come l'overload di GetFunction utilizzato in questa occasione abbia in realtà una sintassi abbastanza pesante, vediamo quindi come ridurne la verbosità sfruttando i generics:

static T CreateDelegate<T>(Lua lua, String function) where T : class { Type delegateType = typeof(T); if (!delegateType.IsSubclassOf(typeof(Delegate))) throw new ArgumentException("T must be derived from System.Delegate"); return lua.GetFunction(delegateType, function) as T; } // Esempio di utilizzo: // AddDelegate add = CreateDelegate<AddDelegate>(lua, "add");

Integreremo più avanti questo metodo nel nostro codice, però possiamo già fare qualche considerazione:

  • purtroppo i delegate e le classi che ne derivano non possono essere usati come constraint per i generic. Può sembrare brutto ma in realtà esiste un buon motivo per questa limitazione, riprenderò l'argomento in un breve con un messaggio dedicato che vi illustro in questo messaggio.
  • il fatto che non si possano usare i delegate come constraint ci obbliga a fare un minimo di controllo giusto per essere sicuri e, nel caso, indicare la retta via, per cui controlliamo che il tipo T sia effettivamente derivante da System.Delegate e sia quindi consumabile da GetFunction.
  • usiamo class come constraint per poter utilizzare l'operatore as ed effettuare quindi un cast dal tipo base System.Delegate (resituito da GetFunction) al tipo specificato da T.
  • avendo a disposizione le novità di C# 3.0 sarebbe stato possibile utilizzare gli extension method per poter "attaccare" direttamente a LuaInterface.Lua il metodo generico CreateDelegate<T>, sarebbe stato sicuramente tutto molto più pulito.

Nei prossimi messaggi cominceremo a capire meglio l'utilità di utilizzare un delegate piuttosto che un oggetto LuaFunction per invocare i metodi definiti in Lua.

C# e Lua? Insieme? Rien de plus facile!

Qualche giorno fa vi ho parlato di Lua e di come configurarne correttamente l'interprete su Windows per poter fare qualche esperimento con questo linguaggio, quello che però non vi ho detto è che un valido motivo per quel messaggio introduttivo c'è e va oltre il semplice utilizzo nell'ambito dello scripting fine a se stesso. Del resto il punto di forza di Lua non risiede tanto nel suo utilizzo stand-alone, vista tra l'altro la scarsità di librerie a disposizione, quanto nell'estrema facilità e versatilità di integrazione dell'interprete all'interno di applicazioni scritte in altri linguaggi, in modo da poter offrire funzionalità di scripting o plugin in maniera facile e veloce nei propri progetti (come dimostrato per esempio in alcuni videogiochi). Tornando a noi, il motivo principale di questo interessamento è che in questo periodo ho l'occasione di poter sperimentare l'integrazione di Lua in un piccolo progetto scritto in C# grazie all'utilizzo dell'ottima libreria LuaInterface, perciò nei prossimi giorni cercherò di riportarvi qualche annotazione su questa esperienza attraverso qualche messaggio con un approccio particolarmente easy, non intendo scrivere un tutorial o simili.

Due note prima di cominciare: per questa serie di messaggi non è necessario seguire preventivamente le mie istruzioni sull'interprete Lua in Windows dato che esse servivano solamente per configurare l'interprete stesso in forma stand-alone (vi potrebbero tornare comunque utili nel momento in cui vorrete effettuare delle prove di codice Lua direttamente nel suo ambiente), inoltre io utilizzerò C# ma LuaInterface dovrebbe supportare tutti i linguaggi CLS-compliant che girano sul CLR.

L'unico ingrediente necessario per iniziare è l'ultima versione di LuaInterface e la nostra ricetta prevede che dall'archivio utilizziate i file LuaInterface.dll (il bridge vero e proprio da includere come reference nel progetto della vostra applicazione o da passare come argomento a CSC.EXE attraverso il parametro /r nel caso scriviate tutto con un editor di testo), luanet.dll e lua51.dll (rispettivamente la libreria che fa da collante tra il CLR e l'interprete Lua e la DLL dell'interprete Lua stesso, entrambi i file sono da copiare nella directory che conterrà il vostro programma compilato). A questo punto creiamo una piccolissima applicazione console per verificare che tutto funzioni correttamente...

1 using System; 2 using LuaInterface; 3 4 namespace NRK 5 { 6 class Application 7 { 8 static void Main(string[] args) 9 { 10 Lua luaEngine = new Lua(); 11 Console.WriteLine(luaEngine.GetType()); 12 } 13 } 14 }

Una volta compilato il programma, dovremmo ottenere come output in console la scritta LuaInterface.Lua. Da notare l'importazione del namespace LuaInterface alla riga 2 e la creazione dell'istanza dell'interprete Lua alla riga 10. La prova successiva: dare in pasto all'interprete del codice Lua da eseguire per ottenere un risultato. Per fare ciò sviluppiamo in Lua la classica funzione add...

1 using System; 2 using LuaInterface; 3 4 namespace NRK 5 { 6 class Application 7 { 8 static void Main(string[] args) 9 { 10 Lua luaEngine = new Lua(); 11 12 luaEngine.DoString(@" 13 function add(x, y) 14 return x + y 15 end 16 "); 17 18 LuaFunction luaFunction_Add = luaEngine.GetFunction("add"); 19 object[] ret = luaFunction_Add.Call(5.3, 3.2); 20 21 double result = Convert.ToDouble(ret[0]); 22 Console.WriteLine(String.Format("Il risultato è: {0}", result)); 23 } 24 } 25 }

Eseguendo il compilato dovremmo ottenere come risultato la somma di 5,3 e 3,2, con il seguente output in console: Il risultato è: 8,5. Ora analizziamo i punti di interesse di questo listato:

  • riga 12: il metodo DoString dell'istanza di Lua ci permette di dare in pasto all'interprete delle parti di codice Lua in forma di stringa. In questo caso abbiamo utilizzato questo metodo per definire in Lua la funzione add che restituirà la somma di due parametri.
  • riga 18: il metodo GetFunction dell'istanza di Lua consente di "importare" nel nostro programma una funzione definita in Lua, infatti in questo caso lo utilizziamo per ottenere il riferimento alla nostra funzione add nella forma di una istanza della classe LuaFunction.
  • riga 19: l'istanza di LuaFunction espone il metodo Call il quale consente di invocare la funzione in Lua a cui fa riferimento specificandone i parametri da passare e ottenendo come risultato un array di Object. In questo caso verrà restuito un array di un solo elemento contenente il nostro risultato.

Come potete vedere l'importazione dell'interprete Lua in un'applicazione scritta in C# con LuaInterface è un'operazione di una semplicità imbarazzante che ci permette di iniziare veramente da subito. Prossimamente approfondiremo l'argomento complicando sempre di più il nostro codice di esempio.

Installazione e configurazione dell'interprete LUA in Windows

Configurare correttamente l'interprete Lua in Windows non è difficile, però non è nemmeno immediato ottenere un ambiente totalmente funzionante. Per questo motivo vi riporto i pochi ma importanti passi per poter usare comodamente questo linguaggio e per sfruttare senza troppi problemi le librerie e i moduli esterni, come quelli scaricabili da LuaForge:

  1. Scaricare l'interprete (per esempio lua5_1_2_Win32_bin.zip) da questa pagina alla voce Executables. L'ultima versione di Lua a disposizione nel momento in cui vi sto scrivendo è la 5.1.2.
  2. Decomprimere lo zip in una directory a piacimento (es. C:\Programmi\Lua), si otterranno 4 file: lua5.1.exe (l'interprete), luac5.1.exe (compila gli script in bytecode per la VM di Lua), bin2c5.1.exe (converte gli script da Lua a C), e lua5.1.dll (il cuore di tutto). Non è necessario, ma volendo potete rinominare per comodità lua5.1.exe in lua.exe oppure creare un hardlink NTFS chiamato lua.exe che punta a lua5.1.exe.
  3. Creare una ulteriore sotto-directory (es. modules) nel path in cui abbiamo decompresso Lua e nella quale andremo a posizionare i moduli per Lua che vorremo installare. Il path completo di questa directory sarà a questo punto C:\Programmi\Lua\modules.
  4. Impostare alcune variabili d'ambiente a livello locale, se volete usare Lua solo con il vostro utente, o di sistema, più comodo se volete invocare Lua in processi di sistema che girano con altri utenti senza però litigare troppo. La prima variabile sarà impostata con il path della sotto-directory appena creata come base comune per le altre due variabili utilizzate dall'interprete Lua per capire dove e in che maniera effettuare il lookup dei moduli da caricare (per questo noterete più opzioni divise da punto e virgola):

    LUA_DIR = C:\Programmi\lua\modules
    LUA_CPATH = ?.dll;%LUA_DIR%\lib\?.dll
    LUA_PATH = ?.lua;%LUA_DIR%\lua\?.lua;%LUA_DIR%\lua\?\?.lua

    Le directory specificate in LUA_CPATH e LUA_PATH non esistono ancora nel nostro filesystem, volendo è possibile crearle preventivamente ottenendo quindi C:\Programmi\Lua\modules\lib e C:\Programmi\Lua\modules\lua.

    Protip: in Windows 2003, per evitare di usare la GUI (Proprietà del sistema -> Avanzate -> Variabili d'ambiente), potete sfruttare setx da linea di comando per impostare le vostre variabili di sistema o locali, mentre con Windows XP questo tool non è incluso ma è possibile ottenerlo e installarlo attraverso gli Strumenti di supporto per Windows XP che sono gratuiti. Il comportamento e le funzionalità di setx sono differenti da quelli di set.

  5. Questo punto non è fondamentale ma offre maggiori comodità per l'esecuzione degli script da linea di comando. Prima di tutto l'inserimento del percorso dell'interprete (C:\Programmi\Lua) nella variabile PATH renderà superfluo lo specificare il percorso dell'interprete per eseguire gli script, inoltre è possibile creare una nuova voce .LUA nei tipi di file conosciuti (da Risorse del computer o Esplora risorse scegliere Strumenti -> Opzioni cartella -> Tipi di file... sinceramente non conosco altri metodi rapidi senza tampinare direttamente il registro, operazione che vi risparmierei) specificando l'eseguibile dell'interprete come programma da eseguire per l'azione open. Volendo esagerare con la pigrizia, è possibile infine inserire l'estensione .LUA nella variabile d'ambiente PATHEXT in modo da non dover specificare l'estensione degli script nel momento in cui vengono invocati da linea di comando. Supponendo quindi di avere un ipotetico script chiamato miaprova.lua e di essere posizionati con la shell nella directory in cui esso è stato salvato, a questo punto non servirà fare altro che scrivere miaprova ed esso verrà automaticamente lanciato con l'interprete Lua.

Ora verifichiamo il corretto funzionamento dell'ambiente iniziando con il creare lo script miaprova.lua ed eseguendolo da linea di comando:

1 –– banale, ma almeno vediamo se funziona... 2 local username = os.getenv("USERNAME") 3 local ora_corrente = os.date("%H:%M:%S") 4 print(string.format("Ciao %s, sono le %s", username, ora_corrente))

C:\Temp>miaprova
Ciao adaniele, sono le 11:42:46

Ora passiamo a una verifica leggermente più complessa, cercando di utilizzare librerie esterne. Per il nostro test utilizzeremo LuaSocket, il cui pacchetto compresso contiene le directory lib e lua che rappresentano rispettivamente LUA_CPATH e LUA_PATH. Molte volte i pacchetti delle librerie di Lua 5 che vengono distribuiti hanno questa struttura (al massimo manca una delle due directory se non contengono file necessari) per cui di norma basta decomprimerli all'interno di LUA_DIR per "installarli" rispettando l'albero corretto, comunque la regola è che i file o le directory contenenti .DLL vanno posizionati in LUA_CPATH mentre i file o le directory contenenti .LUA vanno messi in LUA_PATH. Seguendo correttamente questo passaggio otterremo la seguente struttura di directory:

%LUA_CPATH%\socket\core.dll
%LUA_CPATH%\mime\core.dll
%LUA_PATH%\compat-5.1.lua
%LUA_PATH%\ltn12.lua
%LUA_PATH%\socket.lua
%LUA_PATH%\mime.lua
%LUA_PATH%\socket\http.lua
%LUA_PATH%\socket\tp.lua
%LUA_PATH%\socket\ftp.lua
%LUA_PATH%\socket\smtp.lua
%LUA_PATH%\socket\url.lua

Ora modifichiamo il nostro script miaprova.lua con il seguente codice ed eseguiamolo:

1 http = require "socket.http" 2 local body, http_status = http.request("http://www.google.it/") 3 print(string.format("Il server ha restituito lo stato %s", http_status))

C:\Temp>miaprova
Il server ha restituito lo stato 200

Nel caso di una configurazione errata dei path o di un errore nel posizionamento dei file della libreria dovreste accorgevene immediatamente poiché vi verrà presentato un errore abbastanza autoesplicativo e simile al seguente: C:\Temp\miaprova.lua:1: module 'socket.http' not found: [...] . Se invece lo script viene eseguito senza errori allora significa che abbiamo configurato correttamente l'interprete sul nostro computer con Windows. Ho avuto modo di usare Lua poche volte in passato, principalmente per estendere SciTE che lo integra proprio per questo scopo, però come linguaggio non mi dispiace.