Link alla versione online: lwp.interglacial.com/
Link allo zip scaricabile: interglacial.com/temp/lwpbook.zip
LWP (short for “Library for World Wide Web in Perl”) is a set of Perl modules and object-oriented classes for getting data from the Web and for extracting information from HTML.
Spesso escono articoli su vari argomenti, tenuti da personaggi “importanti” che ne sparano un po’ di tutti i generi.
Ovviamente, ci si può esaltare o meno alla lettura delle prossime X features della versione Y.ZZ^2 ecc., ma di solito io non faccio parte del gruppo.
La cosa invece che mi è parsa carina di questa intervista a Damian Conway sul futuro del perl (si parla sempre della fantomatica versione 6 del linguaggio, in gestazione da 10 anni), è questo paragrafo:
Greg: What non-computing books would you recommend programmers to read?
DC: Programming is an intrinsically creative task, so it’s critically important to feed your creativity from outside the discipline. My own interest has always been in new models and metaphors for computation and better ideas for interfaces, so I try and read as widely as I can in the hard sciences (especially physics and mathematics) and in the literature of general design. But that’s me, and most people wouldn’t find inspiration in those same places.
So the general answer, I think is that you need to find books that stretch your brain in unexpected ways, that break you out of your habitual ways of thinking and of viewing the world, that challenge your assumptions and your certainties. Some great example of such books are “The Design of Everyday Things” by Donald Norman, “Freakonomics” by Stephen Dubner and Steven Levitt, “Guns, Germs, and Steel” by Jared Diamond, “The Prince” by Machiavelli, “Catch Me If You Can”, by Frank Abignale, “Lost in the Cosmos” by Walker Percy, or just about anything that Douglas Hofstader has written (sadly, most people seem to stop at “Godel, Escher, Bach”).
Now, I don’t say that I agree with every idea or theory in those particular books, or even with most of them, but I do think that every one of them issues a direct challenge to our entrenched expectations and beliefs. And I think that’s the critical thing.
So much of everyday programming is monotone. You need to transcend that sameness if you want to become a better programmer. And learning to think outside the box (and even just that there’s a box to think outside of!) is essential to that growth.
I think that’s also why so many programmers naturally gravitate to science fiction. Really good SF takes you outside your assumptions in exactly the same way.
Oggi nel canale perl ci si è chiesto come individuare stringhe arbitrarie ricorrenti in un file (ie: query SQL in un file php).
La risposta di per se sarebbe semplice: si fa una regex che inizia con SELECT e finisce con qualcosa (ie:
e si è a cavallo.
Il grado di difficoltà però aumenta se le stringhe sono su più righe…
Avendo trovato una soluzione che non richiede nemmeno un ciclo, la scrivo poichè ne sono orgoglioso e mi è valsa un ++.
use strict;
use File::Slurp;
my $text = read_file(‘file.php’);
my @queries = $text =~ /("SELECT.*?");/msg
Ogni valore di @queries conterrà uno dei SELECT nel file, siano essi su più righe o meno.
Più breve di così…
Segnalo anche un paio di letture sulle regex che potrebbero venire comode per capire i modificatori /m e /s, che si usano pochino.
Regexp Power by Simon Cozens (1 e 2)
Dovevo trasferire rapidamente i dati da una singola tabella in un db MySQL a quattro distinte – in modo da normalizzare un po’ i dati.
Con perl e DBI la cosa viene facile.
use strict;
use DBI;
[…]
my $dsn = "dbi:mysql:database=$db_name";
my $dbh = DBI->connect( $dsn, $username, $password ) or die $DBI::errstr;
my $sth = $dbh->prepare(
‘SELECT name, surname, birth, address, cap, city, country, phone, email, notes FROM rubrica’
) or die $dbh->errstr;
$sth->execute();
my $ins0 = $dbh->prepare(
‘INSERT INTO persone (nome,cognome) VALUES (?,?)’
) or die $dbh->errstr;
my $ins1 = $dbh->prepare(
‘INSERT INTO indirizzi (id,via,cap,citta,paese) VALUES (?,?,?,?,?)’
) or die $dbh->errstr;
[… ecc, seguono altri statement insert …]
while ( my $row = $sth->fetchrow_hashref() ) {
$ins0->execute( $row->{name}, $row->{surname} );
my $rv = $dbh->last_insert_id(undef, undef, ‘persone’, ‘id’);
$ins1->execute( $rv, $row->{address}, $row->{cap}, $row->{city}, $row->{country} );
[…]
}
La cosa interessante sta in quel last_insert_id che raccatta l’ultimo valore auto incrementato e lo mette in uno scalare, riutilizzabile poi in altri insert per avere le foreign key allineate.
Per convertire una data in timestamp in perl:
1235775600
Attenzione, la data inserita è il 28 febbraio 2009, a mezzanotte.
Il modulo Time::Local fornisce funzioni che sono l’opposto di quelle built-in di perl localtime() e gmtime().
Attenzione ai mesi che vanno da 0 a 11 (gen .. dic).
Mi è capitato troppe volte di trovarmi file XML assolutamente illeggibili per le mani.
Una soluzione, come al solito, arriva da CPAN: XML::Tidy!
Ridi e scherza, questo modulino è in realtà un sacco di codice che parsa alla perfezione i file xml e li riordina ad-hoc.
#!/usr/bin/perl
use strict;
use warnings;
use XML::Tidy;
my $VERSION = 0.02;
my $file_in = $ARGV[0] || die "Usage:\t$0 <input.xml> <output.xml>\n";
my $file_out = $ARGV[1] || ‘output.xml’;
my $tidy_obj = XML::Tidy->new(‘filename’ => $file_in);
$tidy_obj->tidy();
$tidy_obj->write($file_out);
Il mio semplice script prende un file in input da cmdl e sputa fuori un output.xml “raddrizato” (2 whitespace di default come indentazione, se si vuole modificare bisogna dare un arogomento al metodo ->tidy()).
Per ulteriori info.
Nota: La libreria perl sta anche in un pacchetto debian (libxml-tidy-perl) che guarda caso fornisce uno scriptino (/usr/bin/xmltidy) molto simile (quasi identico) al mio.
A forza di spaccarsi la testa sulle cose, ogni tanto se ne esce.
Avendo un database su PostgreSQL, e volendo manipolarlo con strumenti ORM in perl si può usare DBIx::Class (DBIC per gli amici).
DBIC si appoggia a “schemi” di tabelle nel database che gli permettono di interagire col db-server in maniera corretta (e ottimizzata).
Gli schemi sono un po’ pallosi da estrarre, ma a tutto c’è soluzione:
Dopo questo comando nella directory Sim ci sarà un pacchetto Prova.pm (lo schema) che caricherà le classi che rappresentano le tabelle del database XXX (nella dir Sim/Prova/tabella_*.pm).
Le rappresentazioni delle tabelle sono interessanti da guardare.
Da questo momento sarà possibile scrivere script che usino lo schema (Sim::Prova), si connettano attraverso di esso (metodo connect) ed agiscano sui dati del database XXX.
use Sim::Prova;
my $schema = Sim::Prova->connect(‘dbi:Pg:dbname=XXX’, ‘YYY_user’, ‘ZZZ_passwd’, {});
my @all_authors = $schema->resultset(‘Authors’)->all;
foreach (@all_authors) {
print $_->name ."\n";
}
L’oggetto $schema porta la connessione, tramite ->resultset(‘table’) capisce com’è organizzata la tabella nel db e poi accetta i metodi utili per fare qualcosa (CRUD: Create, Retrieve, Update, Delete).
$schema->resultset(‘tabella’)->create( {id => 1, name => ‘Simone’} );
# R
my @rows = $schema->resultset(‘tabella’)->all;
foreach $row (@rows) {
print $_->id ." | ". $_->name ."\n";
}
# U
my $author = $schema->resultset(‘tabella’)->find(1);
# dentro $author c’è il nostro record.
$author->name(‘Mario Rossi’);
# rimpiazza l’attributo "name" di $author con qualcosa di diverso.
# A questo punto il database ha ancora il record non cambiato, ma
# $author contiene un record differente.
$author->update();
# così aggiorno i dati sul db.
# D
# Come update, si identifica il record giusto e…
$author->delete();
Un po’ di basic usage e di manualistica.