Pourquoi se soucier des vieux Perl ?
Parce qu'il y a énormément de code Perl caché qui tourne sur de vieux systèmes
Parce qu'on peut donc s'y trouver confronté
Pourquoi ne pas mettre Perl à jour ?
À cause de l'impact potentiel (souvent dur à estimer)
Parce que ce n'est pas toujours possible
Missionné sur un poste d'expert Perl
But : maintenir du vieux code, développer du nouveau
Plate-forme : plus de 2000 serveurs
Certains ont été installés il y a plusieurs années
Vieux systèmes, vieux Perls
Perl 5.000 .. octobre 1994
Perl 5.001 .. mars 1995
Perl 5.002 .. février 1996
Perl 5.003 .. juin 1996
Perl 5.004 .. mai 1997
Perl 5.005 .. juillet 1998
Perl 5.6 .. mars 2000
Perl 5.8 .. juillet 2002
Perl 5.10 .. JBDNF?^W^W
RSN! \o/
Perl 5.12 .. JBTEOTU?^W
JBDNF?
core
la distribution standard de Perl, l'ensemble des modules préinstallés avec Perl
pragma
module avec un nom en minuscule, souvent lexical, par exemple strict
et warnings
Au niveau du langage
version
syntaxe
fonctionnalités
Au niveau des modules
version
fonctionnalités
disponibilité
use 5.8
ou require 5.8
Origine de ce prérequis
ajouté par un outil de génération de code, par exemple h2xs
ajouté intentionnellement par l'auteur
Exemple
maddingue@gwaihir:Speech-eSpeak-0.21 $ perl Makefile.PL && make all test Perl v5.8.8 required--this is only v5.8.7, stopped at Makefile.PL line 1. BEGIN failed--compilation aborted at Makefile.PL line 1.
"ZOMG!1! UR PERL IZ NOT TEH LATEST U L4M3RZ LOLOLOL!!1! BAI"
Yeah, sure
Pertinence
estimer la pertinence de ce prérequis
si non pertinent, on peut le retirer
on gagne
peut-être
si pertinent, il faut continuer à chercher
Exemple
use 5.008006
est typique de h2xs
Peut donc généralement être supprimé
Mots-clés et opérateurs
Fonctions
Chaînes
Regexps
Mots-clés et opérateurs
our
(Perl 5.6)
state
(Perl 5.10)
//
(Perl 5.10 ou 5.8+DOR)
our
Variables globales à usage unique peuvent être placées dans un
bloc no strict
{ no strict 'vars'; $VERSION = '1.23'; @ISA = qw(Flower); }
Variables publiques déclarées avec vars
use vars qw($DEBUG);
Fonctions
open()
binmode()
open()
Syntaxe très protéiforme avec plusieurs modes différents
Mais déjà en place depuis longtemps
Toutefois, deux ajouts récents sont couramment utilisés
open()
open my $fh, $path
Fonctionalité introduite avec Perl 5.6
Syntaxe valide dans les anciens Perls
Mais $fh
pas automatiquement affecté
open()
open my $fh, $path
Solution : créer manuellement le descripteur de fichier
use FileHandle; open my $fh = new FileHandle, $path or die $!;
ou, plus lisible
use FileHandle; my $fh = new FileHandle; open $fh, $path;
open()
open()
avec 3 arguments
open($fh, '<', $path);
Syntaxe introduite avec Perl 5.6
Offre une protection contre la magie
open()
open()
avec 3 arguments
Malheureusement, le code suivant ne marche pas :-(
my @args = ('>', $path); open($fh, @args);
Solution simple : retransformer en open()
à 2 arguments
open($fh, '<'.$path);
Problème : perte de la protection supplémentaire
open()
open()
avec 3 arguments
Seconde solution : FileHandle
(depuis 5.002), ou IO::File
(depuis 5.003_07)
use FileHandle; my $fh = FileHandle->new($path, $mode); # where $mode is ANSI mode: r, w, r+, etc
binmode()
À l'origine pour passer le descripteur de fichier en mode binaire
Peut maintenant être utilisé pour sélectionner la couche PerlIO (ajouté dans 5.6)
binmode(FILEHANDLE, LAYER)
Ne produit qu'un avertissement
Chaînes
v-strings
qr//
v-strings
Syntaxe introduite avec Perl 5.6
Tout usage autre que pour définir un numéro de version est à proscrire
v-strings
Comparer des versions
Solution : revenir à de simples chaînes de caractères ou à des flottants
Avantage : technique éprouvée, utilisée depuis des années
Inconvénient : moins fiable
Exemple avec des flottants:
if ($version > 2.034) { ... }
v-strings
Comparer des versions
Solution : utiliser version
(fonctionne à partir de 5.005_04,
inclus dans le core 5.10)
Avantage : interface objet avec surcharge d'opérateurs
Inconvénient : ne fournit pas beaucoup véritablement de compatibilité en deçà de 5.6
Exemple:
use version; my $vers1 = version->new("1.2.3"); my $vers2 = version->new("1.2.5"); if ($vers1 < $vers2) { ... }
v-strings
Comparer des versions
Solution : use Perl::Version
(pur Perl, fonctionne avec au moins 5.004)
Avantage : module objet classique, bien adapté pour manipuler des versions
Inconvénient : il faut numifier les objets pour les comparer
Example:
use Perl::Version; my $vers1 = Perl::Version->new("1.2.3"); my $vers2 = Perl::Version->new("1.2.5"); if ($vers1->numify < $vers2->numify) { ... }
v-strings
Afficher la version de Perl
printf "version is v%vd\n", $^V;
peut être changé en
if ($] > 5.006) { printf "version is v%vd\n", $^V; } else { printf "version is v%s\n", $]; }
qr//
Syntaxe introduite avec Perl 5.005
Souvent rencontrée dans les suites de test
Typiquement dans like( $result, qr/regexp/ )
Peut donc être remplacée par une chaîne simple sans risque fonctionnel
Utilisation dans du code fonctionnel
Si utilisé pour une bonne raison, ne peut être remplacé
Perte de lisibilité du code trop importante
Impact sur la maintenance
Voir Test::Harness
3.0, Regexp::Assemble
, Regexp::Common
Regexps
Assertions
Classes
Motifs étendus
Assertions
\z
(Perl 5.005)
\Z
est vraie en fin de chaîne ou avant un saut de ligne
\z
est vraie en fin de chaîne
Sera vu comme "z"
par Perl 5.004
Donc nécessité de protéger l'utilisation de cette assertion
my $end = $] >= 5.005 ? "\\z" : "\\Z"; substr($path, 0, -$ignore) =~ s/X(?=X*$end)/$CHARS[int(rand($#CHARS))]/ge;
Classes
Classes POSIX [:class:]
(Perl 5.6)
Solution : remplacer par leur équivalent explicite, cf. perlre
Classes Unicode (Perl 5.6)
\x{263a} wide hex character \N{nom} named character
\pP Match P, named property. Use \p{Prop} for longer names. \X Match eXtended Unicode "combining character sequence", equivalent to (?:\PM\pM*) \C Match a single C char (octet) even under Unicode.
Abandonnez tout espoir
Motifs étendus
(?#text)
(Perl 5.003)
(?imsx-imsx)
(Perl 5.003)
(?:pattern)
(Perl 5.003)
(?=pattern)
(Perl 5.003)
(?!pattern)
(Perl 5.003)
Motifs étendus
(?<=pattern)
(Perl 5.005)
(?<!pattern)
(Perl 5.005)
(?>pattern)
(Perl 5.005, experimental)
(?(condition)yes-pattern|no-pattern)
(Perl 5.005, experimental)
(?{ code })
(Perl 5.005, experimental)
(??{ code })
(Perl 5.6, experimental)
Dépendances possibles :
pragmas
modules du core
warnings
C'est la première cause d'incompatibilité avec les anciens Perl
Pourtant $^W
est disponible depuis Perl 5.0
...
warnings
C'était la première cause d'incompatibilité avec les anciens Perl
JFDI: warnings-compat
$CPAN/S/SA/SAPER/warnings-compat-0.04.tar.gz
$ perl5.00405 -e 'use warnings; warnings::warnif "hello"' hello at -e line 1 $ perl5.00405 -e 'no warnings; warnings::warnif "hello"' $
warnings-compat
Quelques limitations, mais ça marche !
use warnings::register; { no warnings 'redefine'; ... } warnings::warnif "...";
Limitations :
Non lexicale
Catégories non utilisées
base
Introduit dans Perl 5.005
Établit une relation de dérivation de classe
Mais relativement complexe pour son but
Et en conséquence fragile
Déconseillé par plusieurs porters
base
Solution : remplacer par le code équivalent
use base qw(Parse::Syslog);
devient
use Parse::Syslog; { no strict; push @ISA, qw(Parse::Syslog); }
constant
Introduit dans Perl 5.004
Mais les fonctionnalités ont évolué
En particulier, les déclarations groupées, apparues dans Perl 5.8.0
constant
Du code comme
use constant { PROTOCOL_NAME => "http", PROTOCOL_PORT => 80, PROTOCOL_TYPE => "stream", };
doit être réécrit :
use constant PROTOCOL_NAME => "http"; use constant PROTOCOL_PORT => 80; use constant PROTOCOL_TYPE => "stream";
constant
Autre solution : mettre à jour module
Cpanifié après que Nicholas Clark a vu cette présentation à YAPC::Europe 2007
$CPAN/S/SA/SAPER/constant-1.11.tar.gz
Fonctionne sur Perl 5.005
Important : le core évolue !
Vérifier les dates et versions d'introduction
Module::CoreList
, corelist
$ corelist Data::Dumper Data::Dumper was first released with perl 5.005
Vérifier aussi la disponibilité sur le CPAN
Un nombre croissant de modules sont à double vie
Des modules du CPAN sont régulièrement intégrés au core
Des modules du core sont régulièrement mis à disposition indépendamment sur le CPAN
Modules corifiés :
5.004 : CGI
, CPAN
, IO
(IO::File
, IO::Socket
, ...)
5.005 : Test
5.6 : File::Temp
, Pod::Parser
, Term::ANSIColor
5.8 : Encode
, Filter::Simple
, Locale::Maketext
,
Scalar::Util
, List::Util
, Storable
, Test::More
5.10 : Module::Build
, CPANPLUS
and its numerous dependencies
(Archive::Tar
, IO::Zlib
, Module::Pluggable
, ...)
Modules cpanifiés :
2001 : Test::Harness
2002 : Safe
, ExtUtils::MakeMaker
, version
2003 : Data::Dumper
2004 : XSLoader
2005 : Sys::Syslog
2006 : ExtUtils::Install
, threads
, threads::shared
, Exporter
2007 : B::Lint
, File::Path
, constant
, File::Copy
(peut-être)
Modules du core évoluent aussi
Ajouts de fonctionnalités
Corrections de bugs
Mises à jour indépendantes de Perl
Alors faites-le !