Mentre la bufera di neve torna ad affliggere Bologna, io giochicchio con Mojolicious e mi segno un paio di note.
Per provare a scimmiottare un’interfaccia REST seria, m’ero costruito a colpi di given un controller che generava la risposta in funzione dell’attributo format dello stash (solite cose: html, json, xml); per altro, poichè non stavo usando “the right way” mi stavo pure scontrando con alcune difficoltà implementative (1).
In realtà esiste un comodissimo metodo respond_to che già compie questa selezione internamente (il codice).
Dato questo codice:
use Mojolicious::Lite;
get ‘/test’ => sub {
my $self = shift;
my $data = { a => 1, b => 2, c => 3 };
$self->respond_to(
json => { json => $data },
html => { text => $self->dumper($data) }
);
};
app->start;
possiamo ottenere diverse risposte:
GET /test HTTP/1.1
User-Agent: Mojolicious (Perl)
Accept: text/html
Content-Length: 0
Host: localhost:3001
HTTP/1.1 200 OK
X-Powered-By: Mojolicious (Perl)
Content-Type: text/html;charset=UTF-8
Connection: keep-alive
Date: Sat, 04 Feb 2012 15:33:23 GMT
Server: Mojolicious (Perl)
Content-Length: 39
{
‘c’ => 3,
‘a’ => 1,
‘b’ => 2
}
—————————–
(2) sim@titanio:/tmp$ mojo get -v -H ‘Accept: application/json’ ‘http://localhost:3001/test’
GET /test HTTP/1.1
User-Agent: Mojolicious (Perl)
Accept: application/json
Content-Length: 0
Host: localhost:3001
HTTP/1.1 200 OK
X-Powered-By: Mojolicious (Perl)
Content-Type: application/json
Connection: keep-alive
Date: Sat, 04 Feb 2012 15:34:01 GMT
Server: Mojolicious (Perl)
Content-Length: 19
{"c":3,"a":1,"b":2}
—————————
(3) sim@titanio:/tmp$ mojo get -v -H ‘Accept: text/plain’ ‘http://localhost:3001/test’GET /test HTTP/1.1
User-Agent: Mojolicious (Perl)
Accept: text/plain
Content-Length: 0
Host: localhost:3001
HTTP/1.1 204 No Content
X-Powered-By: Mojolicious (Perl)
Connection: keep-alive
Date: Sat, 04 Feb 2012 15:34:40 GMT
Server: Mojolicious (Perl)
Content-Length: 0
————————–
(4) sim@titanio:/tmp$ mojo get -v -H ‘Accept: text/plainz’ ‘http://localhost:3001/test’
GET /test HTTP/1.1
User-Agent: Mojolicious (Perl)
Accept: text/plainz
Content-Length: 0
Host: localhost:3001
HTTP/1.1 200 OK
X-Powered-By: Mojolicious (Perl)
Content-Type: text/html;charset=UTF-8
Connection: keep-alive
Date: Sat, 04 Feb 2012 15:35:15 GMT
Server: Mojolicious (Perl)
Content-Length: 39
{
‘c’ => 3,
‘a’ => 1,
‘b’ => 2
}
Le prime tre sono corrette, poichè dati determinati header ottengo le risposte giuste:
- text/html – 200
- application/json – 200
- text/plain – 204 – nessuna rappresentazione corretta
Il quarto a mio avviso è un fail, o meglio una scelta discutibile: invece che riconoscere l’header sbagliato e mandare a spendere il client con un 204, gli serviamo html.
Benchè alla fine di quel metodo venga restituito un 204 se il $target non esite (#L423), il gioco “sporco” accade 20 righe prima dove nel caso la rappresentazione passata non venga individuata, si ricade nella situazione di default (html di solito). Il problema a questo punto si incrocia con la possibilità che Mojolicious non abbia dentro di se la rappresentazione corretta benchè sia comune (openoffice, pdf – che forse ora sono stati inseriti, non so), cosa che può portare a conclusioni di default anche quando la rappresentazione richiesta è corretta ma non presente nei tipi di Mojo. In ogni caso, si può sempre aggiungere qualcosa ai MIME.
Ho comunque poi scoperto che la cosa è stata discussa in passato ed è stato deciso così.
Well, basta saperlo.
PS: Io avrei lasciato i client mal fatti nel loro brodo, ma tant’è – probabilmente non capisco bene le implicazioni.
Note:
(1) Le rotte in Mojolicious permettono di selezionare il formato utilizzando un array reference
/formats GET formats ^/formats\.(xml|html)$
ma, come si vede dalla regex, questo fa sì che la rotta “pulita” diventi “/formats.” che non è proprio quello che si vuole, di solito.
Ho rispolverato alcuni appunti cartacei relativi i Ruoli di Perl Moose che riporto qui.
- I ruoli rappresentano comportamenti condivisi fra le classi
- La classe fa ciò che dice il ruolo.
- I ruoli non sono classi; infatti i ruoli non si ereditano e non si istanziano.
- I ruoli vengono consumati da classi o da altri ruoli.
- I ruoli sono composti in una classe con la funzione with.
- Tutti i metodi, modificatori, attributi definiti in un ruolo sono aggiunti direttamente alla classe che consuma il ruolo.
- Attributi e metodi appariranno come se fossero definiti nella classe.
- Una sottoclasse della classe consumata (cioè con il ruolo) eredita tutti questi metodi/attributi.
Riferimenti:
- Moose::Role
- Moose::Manual::Roles
Trovata qua una riga di comando che mostra un po’ di caratteri utf-8 con Perl.
for ($i = 128; $i < 11_620; $i++) {
print chr $i, $i%30 ? " " : "\n$i "
};
print "\n"
’
Ho già parlato di DBIx::Class.
Avendo result source con relazioni si possono ottenere risultati interessanti.
Esistono gli oggetti Folk ed Email, ove l’oggetto Folk sia in relazione con molteplici oggetti Email (folk has_many emails).
[…]
__PACKAGE__->has_many(‘emails’,‘My::Schema::Result::Email’,‘id’);
E’ possibile creare un record scrivendo i dati dell’oggetto/i relativo/i in un arrayref.
my $new_folk = $folks_rs->create({
name => ‘Test folk’,
emails => [
{
email => ‘mail@casa.name’,
comment => ‘Test mail casalinga’,
},
{
email => ‘mail@azienda.org’,
comment => ‘Test mail aziendale’,
},
],
});
E ci si libera di tutto con un bel
Tempo addietro mi è stato chiesto se Perl aveva un interprete interattivo, e risposi di no.
In effetti si può però usare un trucco che ne mette uno a disposizione (con anche qualche feature) sfruttando il debugger del linguaggio.
Dato uno script pinco.pl è possibile debuggarlo lanciando il comando col flag -d:
Dunque, come ottenere un interprete?
Questo comando lancia il debugger su uno script (-e) inesistente, e da quel momento in poi possiamo usare tutti gli strumenti di Perl (print per stampare valori, use per caricare moduli) più tutti gli strumenti del debugger (x per avere un dump delle strutture dati, b per creare un breakpoint) e così via.
Meglio di una gomitata in un occhio, invero.
Un video a riguardo l’ha girato Gabor Szabo.
Metodo grezzissimo per strippare il pod dal modulo perl e stampare il codice.
Volevo annotarmi le differenze tra i vari modi per creare una distro software.
Pacchetti sfruttati: module-starter con ExtUtils::MakeMaker, Module::Build, Module::Install e h2xs.
sim@idrogeno:/tmp$ module-starter --author=sim
--email=xxx@xxxxx.xxx --module=Test::Build --mb
Added to MANIFEST: Build.PL
Added to MANIFEST: Changes
Added to MANIFEST: ignore.txt
Added to MANIFEST: lib/Test/Build.pm
Added to MANIFEST: MANIFEST
Added to MANIFEST: README
Added to MANIFEST: t/00-load.t
Added to MANIFEST: t/boilerplate.t
Added to MANIFEST: t/manifest.t
Added to MANIFEST: t/pod-coverage.t
Added to MANIFEST: t/pod.t
Created starter directories and files
sim@idrogeno:/tmp$ module-starter --author=sim
--email=xxx@xxxxx.xxx --module=Test::Install --mi
Added to MANIFEST: Changes
Added to MANIFEST: ignore.txt
Added to MANIFEST: lib/Test/Install.pm
Added to MANIFEST: Makefile.PL
Added to MANIFEST: MANIFEST
Added to MANIFEST: README
Added to MANIFEST: t/00-load.t
Added to MANIFEST: t/boilerplate.t
Added to MANIFEST: t/manifest.t
Added to MANIFEST: t/pod-coverage.t
Added to MANIFEST: t/pod.t
Created starter directories and files
sim@idrogeno:/tmp$ module-starter --author=sim
--email=xxx@xxxxx.xxx --module=Test::EUMM --eumm
Added to MANIFEST: Changes
Added to MANIFEST: ignore.txt
Added to MANIFEST: lib/Test/EUMM.pm
Added to MANIFEST: Makefile.PL
Added to MANIFEST: MANIFEST
Added to MANIFEST: README
Added to MANIFEST: t/00-load.t
Added to MANIFEST: t/boilerplate.t
Added to MANIFEST: t/manifest.t
Added to MANIFEST: t/pod-coverage.t
Added to MANIFEST: t/pod.t
Created starter directories and files
sim@idrogeno:/tmp$ h2xs -XAn Test::H2xs
Defaulting to backwards compatibility with perl 5.12.4
If you intend this module to be compatible with earlier perl
versions, please specify a minimum perl version with the -b
option.
Writing Test-H2xs/lib/Test/H2xs.pm
Writing Test-H2xs/Makefile.PL
Writing Test-H2xs/README
Writing Test-H2xs/t/Test-H2xs.t
Writing Test-H2xs/Changes
Writing Test-H2xs/MANIFEST
Tutti e 4 i modi scrivono i file Changes, MANIFEST, README, il package principale della lib e il test corrispondente.
Le tre distribuzioni Perl sfruttate da module-starter scrivono anche diversi test in più (per lo più inutili a mio avviso) ed un file ignore.txt che non ho capito ancora a cosa serve (*).
Quindi alla fine della fiera, buttando via la “fuffa” ci resta:
- Module::Build crea Build.PL
- Module::Install crea Makefile.PL
- ExtUtils::MakeMaker crea Makefile.PL
- h2xs crea Makefile.PL
Il Makefile.PL più stringato è quello di Module::Install (e ha una costruzione diversa), mentre i due Makefile.PL di h2xs e ExtUtils::MakeMaker sono praticamente identici (e si basano entrambi su WriteMakefile – anche h2xs usa ExtUtils::MakeMaker). Infine Build.PL ha il suo proprio modo per scriversi la configurazione, ma comunque pare abbastanza intuitivo.
I Makefile.PL di h2xs e EUMM sono virtualmente identici, e producono lo stesso risultato (un makefile che poi copia la lib in blib e generano le man page).
Il Makefile.PL di Module::Install genera un META.yml e una serie di file nella directory inc/ , infine il makefile che produce il solito output.
sim@idrogeno:/tmp/Test-Install$ perl Makefile.PL include /tmp/Test-Install/inc/Module/Install.pm include inc/Module/Install/Metadata.pm include inc/Module/Install/Base.pm include inc/Module/Install/Makefile.pm include inc/Module/Install/AutoInstall.pm include inc/Module/Install/Include.pm include inc/Module/AutoInstall.pm *** Module::AutoInstall version 1.03 *** Checking for Perl dependencies... [Core Features] - Test::More ...loaded. (0.98) *** Module::AutoInstall configuration finished. include inc/Module/Install/WriteAll.pm include inc/Module/Install/Win32.pm include inc/Module/Install/Can.pm include inc/Module/Install/Fetch.pm Checking if your kit is complete... Looks good Writing Makefile for Test::Install Writing META.yml
Il file Build.PL di Module::Build genera un ulteriore script Build e delle configurazioni (json e yml); il tutto è gestito in Perl senza l’intervento di make e l’effetto è identico (./Build produce il solito blib/ ). La documentazione spiega un po’ meglio.
(*) Svelato l’arcano qui.
.cvsignore
Module::Starter assumes you’ll be using CVS for revision control, and provides a .cvsignore file with the names of files that are auto-generated and not to be tracked with revision control. At Perl Training Australia we use git for new projects, and so we rename this to .gitignore.
(As of version 1.52, this file is now called “ignores.txt”, so you can use it however you like.)