====== Programmation modulaire ======
====== 1. Modules et utilisation ======
===== Modules standards =====
Si l'interpréteur Perl possède en lui-même de nombreuses fonctions disponible, les //builtin// citées dans la longue page de manuel //perlfunc//, il en resterait largement insuffisant pour aborder des programmes d'envergure.
L'interpréteur Perl est donc normalement distribué simultanément avec une liste de modules qui sont considérés comme faisant partie de la distribution. En d'autres termes, si votre programme exige la présence de **"Perl 5.8 ou supérieur"**, il peut sans hésiter utiliser par exemple les modules //Data::Dumper//, //IO::Socket//, etc. La liste complète est décrite dans la page de manuel //perlmodlib//.
**Note**: parmi ces modules standards, il existent des modules dits //pragmatiques// et qui ont pour fonction de changer le comportement de l'intepréteur. Par exemple: restreindre les usages dangereux (//use strict;//), changer le comportement des signaux, des expressions régulières, etc.
===== Directive "use" =====
Pour utiliser un module Perl, il suffit de demander :
use List::Util (shuffle);
my @random = shuffle(1..10);
Le nom d'un module utilise la convention !CamelCase (ici //List// et //Util//), et le nommage est lui-même dans un espace hiérarchique. Cette hiérarchie n'est pas nécessairement lié à des relations de descendance au sens orienté objet, bien que ce soit en général le cas à chaque fois que cela est possible.
On peut passer optionnellement une liste de //symboles// (fonctions, variables, etc) auquel on veut pouvoir accéder directement (ici la fonction //shuffle//). Nous verrons qu'en général le module //exporte// les fonctions les plus demandées automatiquement pour nous et que cette possibilité est rarement exploitée.
===== Chemins de recherche =====
Nous le verrons plus loin, les modules Perl sont de simple fichiers Perl suivant une convention précise. L'interpréteur doit pouvoir les trouver au moment de la compilation, et il utilise plusieurs mécanismes pour ce faire :
* **Chemins par défaut**: l'interpréteur connaît nécessairement le chemin des modules standards avec lequel il a été installé, ces chemins sont toujours configurés. Ces mêmes chemins sont en général également utilisés pour les modules supplémentaires installés par le mécanisme de la distribution GNU/Linux sous jacent. Exemple des chemins par défaut chez Debian :
$ perl -e 'print join("\n",@INC,"")'
/etc/perl
/usr/local/lib/perl/5.8.8
/usr/local/share/perl/5.8.8
/usr/lib/perl5
/usr/share/perl5
/usr/lib/perl/5.8
/usr/share/perl/5.8
/usr/local/lib/site_perl
* **Option -I** (i majuscule): on peut ponctuellement rajouter un ou des chemins de recherche de modules à l'aide de cette option, souvent à partir de l'appel à l'interpréteur incorporé en début de script :
#!/usr/bin/perl -w -Iperl/tp1
...
Il est possible d'utiliser le même mécanisme, mais plus global, via les variables d'environnement //PERLOPT/PERL5OPT//, ex :
export PERL5OPT="-Iperl/tp1"
* **PERLLIB/PERL5LIB**: il est possible de passer par ces variables d'environnement pour rajouter une liste de chemin de recherches (supplémentaires en plus des chemins standards). La variable //PERL5LIB// a précédence sur //PERLLIB//. Exemple sous GNU/Linux (attention, le séparateur est **;** sous MS Windows !) :
export PERL5LIB="perl/tp1:perl/tp2"
* **use lib "...";**: en dernier recours, et cette méthode est rarement recommandée, on peut spécifier un chemin arbitraire lors de l'utilisation d'un module, on désigne alors celui ci par son fichier. Exemple :
use lib "./perl/tp1/tplib.pm";
...
====== 2. Anatomie d'un module ======
===== Installation =====
Suivant la source et la méthode d'installation de vos modules Perl, ceux-ci vont se trouver à différents endroits dans votre système de fichiers. Il n'y a pas de règle stricte, mais en général:
* les modules packagés par votre distribution utiliseront les chemins des modules standard Perl
* les modules que vous installerez localement via CPAN ou d'autres méthodes seront traditionnement dans ///usr/local/lib/perl// ou ///usr/local/lib/site_perl// (cette dernière convention étant classique chez Ruby et Python)
===== Fichiers et répertoires =====
Perl recherche les modules demandes à l'aide des chemins de recherche qu'on lui a fournis, recensées dans //@INC//, et en décomposant la hiérachie des noms en répertoire et nommant le module lui-même avec l'extension //.pm//. Exemple :
$ perl -e 'use IO::Socket; print $INC{"IO/Socket.pm"}'
/usr/lib/perl/5.8/IO/Socket.pm
On peut consulter le chemin utilisé par Perl pour un module donné en consultant le tableau //%INC// (et non la liste //@INC// !).
===== Modules natifs =====
Certains modules ne sont pas écrits en Perl ou seulement partiellement réalisés en Perl car ils assurent uniquement un rôle d'interface vers une bibliothèque écrite dans un autre langage (généralement en C). Dans ce cas le fichier //.pm// ne suffit pas et doit être accompagné d'une bibliothèque dynamique (écrite en C et compilée pour la plateforme).
Il s'agit par exemple d'un fichier //.so// sous Unix, rangé selon le modèle hiérarchique mais dans un sous -répertoire //auto/// (le chargement des modules natifs étant automatique et transparents grâce au module //Autoloader// que nous n'expliquerons pas en détail).
===== Bases d'un module =====
package Test::Bidon;
use warnings;
use strict;
BEGIN {
use Exporter 'import';
our @EXPORT = qw/bidon_hello bidon_bye/;
our @EXPORT_OK = qw/test/;
}
sub bidon_hello {
print "Hello les bidons\n";
}
sub bidon_bye {
print "Au revoir les bidons\n";
}
sub test {
print "Testons les bidons...\n";
}
1;
Les éléments importants à retenir :
* un module commence toujours par la directive //package//
* un module finit toujours par uen condition vraie (sauf si le module estime mettre en danger l'application)
* un module déclare les //symboles// disponibles (fonctions, variables) via l'utilisation du module standard //Exporter// et l'initialisation des listes //@EXPORT// et/ou //@EXPORT_OK//.
Si ce module est dans un fichier //Test/Bidon.pl// et que l'on exécute le test //bidon.pl// (on profite du fait que dans les chemins standards des modules il y a le chemin courant) :
#!/usr/bin/perl -w
use Test::Bidon;
use strict;
bidon_hello();
Test::Bidon::test();
bidon_bye();
Il est important de noter que les fonctions listées dans //@EXPORT// depuis le module sont automatiquement disponibles telles quelles (sans préfixe) pour l'utilisateur, ce qui n'est pas vrai par défaut pour les fonctions dans //@EXPORT_OK//. On peut toutefois explicitement //importer// ces fonctions (et donc les nommer sans le préfixe) :
use Test::Bidon qw/test/;
...
test();
===== Blocs BEGIN/END =====
Il est possible d'exécuter certaines partie du module dès son chargement (donc avant le démarrage du programme principal) ou après la fin du programme principal, en définissant des blocs nommés //BEGIN// ou //END// (cf. //labels//).
===== Documentation =====
Les modules de Perl (standards et surtout la majorité de CPAN) possèdent en général une très bonne documentation, et dans tous les cas fournissent une documentation (il s'agit d'une politique de diffusion obligatoire pour CPAN).
Documenter un module en Perl se fait comme dans la plupart des langages, dans le code lui-même à l'aide de marqueurs spécifiques. Cette technique s'appelle **POD** (Plain Old Documentation), et reprend l'organisation et la sémantique des pages de manuel.
Une section de documentation est une ligne commençant par le symbole **=** et un mot-clé de section. La documentation peut être présente à n'importe quel endroit du programme, on termine une ou plusieurs sections avec //=cut//. Pour les détails de formatage, se référer à //man perlpod//.
Pour le style standard (sections requises), se référer à man perlmodstyle. Exemple :
=head1 NAME
Test::Bidon - Un module de demonstration de programmation modulaire
=head1 SYNOPSIS
use Test::Bidon;
bidon_hello();
bidon_bye();
=head1 ABSTRACT
Module d'illustration de cours.
=head1 DESCRIPTION
Ce module implémente des méthodes qui présentent peu d'intérêt à part celui d'illustrer le fonctionnement des modules et en particulier d'Exporter.
==head2 Fonctions de base
=over
=item bidon_hello()
Dis bonjour.
=item bidon_bye()
Dis au revoir.
=back
=head1 SEE ALSO
Demo::Stupid, Porte::Naouak
=head1 AUTHOR
Vincent CARON
=head1 COPYRIGHT AND LICENSE
Copyright (c) 2007 Bearstech - This module is released under the GNU GPL v2
=cut
L'extraction de documentation peut se faire via différents formats avec les commandes //pod...//, par exemple pour extraire une page de manuel et la consulter en même temps :
$ pod2man Test/Bidon.pm |man -l