Un coup d'oeil sur les calendriers

| Aucun Commentaire | Aucun Trackback

Depuis quelques années maintenant, une initiative de la communauté Perl, que l'on peut appeler une tradition maintenant, s'organise à cette période. Il s'agit d'un calendrier de l'Avent. Du premier décembre au jour de Noël (l'Avent donc), un article est publié pour expliquer tantôt un module, tantôt une technique, ou encore un élément de la culture d'un monger 1.

A ma connaissance, il existe quatre calendriers de l'Avent dans la communauté Perl cette année. Chacun est consacré à un projet particulier de la communauté :

J'ai fait une courte recherche pour savoir si des communautés d'autres langages de programmation avaient suivi l'initiative, mais je n'ai rien trouvé de vraiment suivi :

  • Ruby en a fait un en 2006 et en 2008, mais visiblement rien cette année ;
  • PHP en a fait un en 2007, et un cette année ;
  • je n'ai rien trouvé pour Python ;
  • et je me suis arrêté là ! N'hésitez pas à déposer un commentaire pour me faire découvrir d'autres calendriers de ce type.

Personnellement, je trouve que c'est une initiative intéressante, d'une part cela permet d'en apprendre plus sur un langage ou un logiciel en particulier, et puis cela permet également d'assurer une sorte de promotion pour l'objet du calendrier.

Bref, en ce qui me concerne, bien plus intéressant que le calendrier d'une célèbre marque de pneus, par exemple ;-)

Notes de bas de page:

1 en français, on parlera de mongueur

A long time ago

| Aucun Commentaire | Aucun Trackback

Cela fait maintenant un bail que je n'ai plus publié de billets sur ce blog, mais cela ne signifie pas que Perl ne m'a pas été utile dans l'intervalle. En fait, ce serait même plutôt le contraire ! Pour le moment, il m'est surtout utile pour faire des prototypes me permettant de mieux comprendre certaines technologies.

Ainsi, dans le GNU/Linux Magazine France du mois de novembre 2009, il y a un article (Mettez un sphinx dans votre moteur de recherche !) sur un outil sur lequel j'avais déjà jetté un bref coup d'oeil : Sphinx. Je n'ai pas encore eu le temps de finir l'article (je suis en retard sur tout, je vous dis !), mais le principe est de fournir un point d'entrée à une base de données via une requête. Les résultats de cette requête est alors indexée par un logiciel extérieur (Sphinx en l'occurrence). Ensuite lorsque l'on veut effectuer une recherche en texte intégral sur cette base de données, on commence par interroger Sphinx pour obtenir les identifiants des données, on peut ensuite récupérer les données directement dans la base de données.

Je n'ai pas de bases de données suffisamment importantes sous la main que pour pouvoir vérifier si les promesses de performances sont au rendez-vous, mais d'après l'auteur de l'article, c'est le cas !

Je m'interroge donc sur la possibilité d'utiliser Sphinx pour créer des OPACs « nouvelle génération ». L'avantage étant que le simple fait d'ajouter Sphinx dans le jeu permet d'exploiter un langage de requête bien plus riche que les OPACs classiques.

J'ai déjà utilisé cette technique de l'indexation par un programme extérieur pour mettre à disposition une base de données Winisis via le protocole Z39.50. J'avais utilisé pour cela Perl, avec les modules suivants :

Bref, tout cela me donne envie de tenter de réaliser un équivalent de Sphinx, mais en Perl. En exploitant la versatilité de DBI, cela permettrait d'offrir ce service d'indexation à quantité de bases de données !

Perl est vraiment un outil que j'apprécie dans ma boîte à outils, et comme beaucoup d'autres programmeurs Perl, ce que j'apprécie particulièrement, c'est de pouvoir compter sur le travail de tant d'autres pour m'aider à résoudre mes problèmes quotidiens. Parfois, les services rendus ne sont pas de l'ordre du support pour terminer un travail, mais simplement de rendre une situation encore plus comfortable.

M'appuyant souvent sur le CPAN, j'en suis venu à me faire une copie sur mon disque dur que je garde synchronisé aussi régulièrement que possible. Ce travail est réalisé par l'excellent minicpan (CPAN::Mini). Me voici donc dans la situation agréable d'avoir toujours à porter de main une archive du CPAN, que je sois connecté à Internet ou non. Mais le CPAN ne se limite pas à cela, c'est également l'outil que je consulte pour lire la documentation (oui, je sais perldoc est là pour cela), mais que faire quand je suis sur la route ? C'est simple, utiliser minicpanwebserver (CPAN::Mini::Webserver). Ce dernier s'appuie sur le fichier de configuration de minicpan, et met à disposition le tout via un serveur web. Je peux maintenant faire des recherches, lire la documentation, les tests, et je peux même lancer l'installation à partir de cette interface. Bref, un CPAN survitaminé ! A essayer !

Am I connected?

| Aucun Commentaire | Aucun Trackback

La plupart des outils que je développe s'appuie sur LWP, et donc, j'ai besoin d'un accès au web pour les faire fonctionner (belle lapalissade !). Et parmi ces outils, certains sont prévus pour se lancer via cron, et donc se pose la question de savoir ce qui se passe pour le programme quand il se lance et que je ne suis pas connecté. Une des manières de traiter le problème consiste à modifier le programme de manière à ne lancer le traitement que lorsque l'accès au web est opérationnel. C'est ici que LWP::Online vient me rendre service. Il me permet d'importer une fonction, online(), qui va vérifier si un accès au web est bien présent. Si c'est le cas, la fonction retournera une valeur positive. LWP::Online vérifie l'accès au web en vérifiant la présence des copyrights sur certains sites comme Google et Yahoo!, cela rajoute donc une certaine latence dans votre programme, mais cela reste intéressant pour certains outils.

Un biscuit pour un autre

| Aucun Commentaire | Aucun Trackback

Dernièrement, je me suis trouvé confronté à un problème plutôt idiot, mais néanmoins gênant. J'utilise depuis quelques années maintenant les services offerts par un site. J'ai dû me connecter à ce site dernièrement, mais

  1. je ne me souvenais plus de mon mot de passe !
  2. la réinitialisation du mot de passe était difficiel car pas moyen de me souvenir de l'adresse de courrier électronique employée pour créer le compte !

Damned! Comment faire ?

Et bien, se féliciter d'être paresseux ! En effet, pour profiter des services de ce site, je m'étais écrit un petit robot en Perl avec LWP. Ce brave outil fonctionnait toujours puisqu'il s'appuyait sur un cookie. Ce cookie était dans le format propriétaire de HTTP::Cookies, je devais donc le convertir dans le format de Mozilla Firefox.

Aussitôt dit, aussitôt fait. Une petite recherche sur le web, et je trouve un article des mongueurs expliquant un cas de conversion de cookies, mais de Mozilla vers LWP. Après quelques tâtonnements, j'ai finalement adapté le programme. Le voici :

#!/usr/bin/env perl

use strict;
use warnings;

use HTTP::Cookies;
use HTTP::Cookies::Mozilla;
use Getopt::Long;

my $config = {};

GetOptions( $config, 'from=s', 'to=s' );

die _usage() unless _valid_config( $config );

my $input_jar = HTTP::Cookies->new( file => $config->{from} );
bless $input_jar, 'HTTP::Cookies::Mozilla';

$input_jar->save( $config->{to} );

sub _usage {
    return "Usage: $0 --from cookies.lwp --to cookies.mozilla\n";
}

sub _valid_config {
    my $config = shift;

    if (exists $config->{from} and exists $config->{to}) {
        return 1;   
    } else {
        return 0;
    }
}

Il m'a donc suffit d'appeler ce programme de la manière suivante : $./cookies_converter -f my_lwp_cookie.txt -t /path/to/mozilla/profile/cookies.sqlite

Ensuite, j'ai pu aller sur la page de mon compte pour changer mon mot de passe et mettre une adresse de courrier électronique plus récente.

Aidez-moi à remplir mon buffer

| Aucun Commentaire | Aucun Trackback

Au détour d'un tweet, j'ai découvert un petit outil venant compléter emacs. Il s'agit du projet perl-completion.el. Ce dernier permet d'avoir une auto-complétion intelligente, c'est-à-dire qui ne se limite pas aux contenus des buffers ouverts. Vous pouvez ainsi obtenir une aide pour le nom des modules, mais aussi des méthodes exportées par ces modules. Bref, un must !

Si vous voulez en voir plus, il y a un screencast qui vous permettra d'apprécier le travail fait. Il y a également un dépôt git en ligne.

Enjoy!

Donnez-moi vos feuilles !

| Aucun Commentaire | Aucun Trackback

Peu de temps pour programmer ces derniers temps, mais qu'importe, voici un petit outil programmé aujourd'hui. Il permet d'afficher les feuilles d'un document XML. En effet, j'ai eu entre les mains un fichier à convertir, il s'agissait d'un export XML provenant de BCDI. Or, je ne connaissais pas ce vocabulaire XML et je voulais illustrer une migration de données. j'avais donc besoin d'une liste des feuilles de cet arbre XML, où je pourrai tirer quelques éléments pour effectuer la pseudo migration. Aussitôt pensé, aussitôt fait.

Perl peut utiliser la libxml avec le module XML::LibXML et via cette dernière, je peux appliquer des expressions XPath sur mon fichier XML. L'expression XPath en question est **//*[count()=0]*. Le reste est vraiment simplissime.

Voici le code :

#!/usr/bin/env perl

use strict;
use warnings;

use XML::LibXML;
use Getopt::Long;

my $config = {};

GetOptions( $config, 'xml=s' );

_usage() if not _validated( $config );

my $parser = XML::LibXML->new();
my $catalog = $parser->parse_file( $config->{xml} );

my @nodes = $catalog->findnodes( '//*[count(*)=0]' );
my %leaf_nodes;
foreach my $node (@nodes) {
    my $path = $node->nodePath();
    $path =~ s/\[\d+\]//g;
    $leaf_nodes{$path}++;
}

print ($_, $/) foreach keys %leaf_nodes;

sub _usage {
    die "Usage: $0 --xml file.xml\n";
}

sub _validated {
    my $config = shift;
    
    if (exists $config->{xml}) {
        return 1;
    } else {
        return 0;
    }
}

L'outil est tellement simpliste qu'il ne me sera probablement plus utile demain, mais au moins, j'ai une base pour analyser un éventuel fichier XML en vue d'une migration. Les prochains billets traiteront d'ailleurs probablement de migration de catalogues de bibliothèques.

Le collectionneur de liens

| Aucun Commentaire | Aucun Trackback

Parfois, au détour d'une page web, je tombe sur une mine d'informations que je veux récupérer en local. Prenons par exemple ce site répertoriant des diapositives sur un sujet que ne cesse de me passionner : l'information retrieval. Comme vous pouvez le voir, il y a pas mal de ressources à télécharger, et je dois avouer que la perspective de récupérer ces fichiers en cliquant sur tout les liens ne me tente guère. Il existe une extension pour Mozilla Firefox qui permet d'automatiser ce genre d'opérations, il s'agit de DownThemAll!, une extension incontournable … pour les utilisateurs de Mozilla Firefox, mais depuis plusieurs semaine, je dois avouer que Chromium emporte mes faveurs. Que faire ? Et bien, voyons voir ce que Perl peut faire pour nous !

Pour la partie récupération d'une page HTML, Perl met à notre disposition LWP::UserAgent. Sur base de cette page HTML, nous devrons collecter les liens qui s'y trouvent. Un module se consacre justement à cette tâche : HTML::LinkExtractor. Certains des liens pouvant être relatifs, aussi nous devrons traiter le HTML avant de collecter le lien. Ici aussi, un module se charge de transformer tous les liens relatifs en liens absolus, il s'agit de HTML::ResolveLink.

A partir de ces outils, nous allons donc pouvoir réfléchir à la manière dont nous voudrions utiliser l'outil. En ce qui me concerne, j'aimerais pouvoir récupérer les liens provenant d'une page précise, et ces liens, je les sélectionnerai avec une expression rationnelle, par exemple : \.pdf$ pour sélectionner tous les liens se terminant par .pdf. L'interface de mon outil se fera en ligne de commande (comme d'habitude). Un appel se faisant de la manière suivante : links_gatherer.pl -u http://nlp.stanford.edu/IR-book/newslides.html -r '\.pdf$', ce qui m'affichera la liste des fichiers satisfaisant mon expression rationnelle. Si je redirige la sortie de ce programme vers un fichier, je peux ensuite appeler wget à la rescousse pour télécharger ces fichiers (wget -i mesliens.txt). Evidemment, je pourrais modifier mon script pour qu'il s'occupe également du téléchargement, mais j'essaye de rester fidèle à la philosophie Unix de l'outil spécialisé dans une et une seule tâche, qu'il essaye de faire du mieux possible.

Voici le script final :

#!/usr/bin/env perl

use strict;
use warnings;

use HTML::LinkExtractor;
use LWP::UserAgent;
use Getopt::Long;
use Data::Dump;
use HTML::ResolveLink;

use feature 'say';

my $config = {
    regexp => '\.(rar|zip|pdf|ppt|odt)$',
};

my $ua = LWP::UserAgent->new();
$ua->agent( 'Mozilla/5.0' );

GetOptions($config, 'url=s', 'regexp=s');

if (exists $config->{url}) {
    my $response = $ua->get( $config->{url} );
    my $resolver = HTML::ResolveLink->new(
        base => $config->{url},
    );
    
    if ($response->is_success) {
        my $parser = HTML::LinkExtractor->new();
        $parser->parse(\$resolver->resolve($response->decoded_content));
        
        my $re = qr/$config->{regexp}/isx;        
        foreach my $link ( @{$parser->links} ) {
            if (exists $link->{href}) {
                say $link->{href} if $link->{href} =~ /$re/;
            }
        }
    } else {
        die "HTML error: ", $response->status_line, $/;
    }
} else {
    die "Usage: $0 --url http://www.webpage.com --regexp '\.pdf$'\n";
}

Bon, évidemment, mon outil est loin d'égaler tout ce que DownThemAll! est capable de faire, mais mon usage habituel de cette extension est satisfait par le script ci-dessus.

OSDCfr 2009

| Aucun Commentaire | Aucun Trackback

Ces deux et trois octobre 2009 se déroulera l'Open Source Developers Conference / France. Cela se passera au Carrefour numérique de la Cité des Sciences, à Paris.

On y parlera de Perl, de Python et de Ruby, entre autres. Bref, une excellente occasion de socialiser un peu !

La ronde des questions

| Aucun Commentaire | Aucun Trackback

Fin du mois d'août. Fin des vacances1, et avant de commencer une nouvelle année académique, il est nécessaire de terminer la précédente. Et donc, voici venu le temps des secondes sessions.

En tant que prof, j'aime bien les examens oraux, et j'aime bien les questions tirées au hasard, c'est pour cela que j'avais développé un petit script CGI en Perl. Rien de bien excitant.

Mais durant mes lectures d'été, je suis tombé sur un billet d'un mongueur français traitant d'une autre autre manière de faire des applications web. Ce mongueur, c'est sukria, et cette autre manière de faire, c'est Dancer2.

Bref, cela m'a donné envie de passer d'un script CGI à une application web autonome ! La voici :

#!/usr/bin/env perl

use strict;
use warnings;

use YAML;
use Dancer;
use Template;

my $file = shift(@ARGV) or die "Usage: $0 questions.yml";
my $questions = YAML::LoadFile($file);

get '/random' => sub {
    my $random_index = int rand scalar(@{$questions});
    my $question = $questions->[ $random_index ];
    
    template 'random' => { question => $question, number => $random_index + 1 };
};

Dancer->dance();

Et donc, je lance cette application à partir d'une ligne de commande :

$ questions_roll.pl /path/to/questions.yaml

Et je peux voir les lignes suivantes :

~ >> Listening on 127.0.0.1:3000 == Entering the development dance floor … ~

Et donc, en pointant mon navigateur à l'adresse http://localhost:3000/random, je peux voir s'afficher une question au hasard.

Vraiment simple, non ? Tellement simple qu'il m'est déjà venu quelques idées d'améliorations. Ce ne sera probablement plus pour cette session d'examen, mais je garde ces idées au chaud.

Notes :

1 enfin, ce qui me tient lieu de vacances

2 en fait, Dancer est lui même une réécriture de Sinatra en Perl. The Pragmatic Bookshelf a édité deux screencasts sur ce sujet. Je n'ai pas encore eu le temps de les regarder, mais cela ne tardera pas !