Nouveau tutoriel : comment utiliser des décorateurs en Perl
Bonsoir,
j'ai le plaisir d'annoncer la publication sur ce site d'un nouvel article: Comment utiliser des décorateurs en Perl - Un tutoriel pour changer le comportement d'une fonction sans en modifier le code source.
Un « décorateur » est une fonction qui permet de modifier le comportement d'une autre fonction sans toucher au code de cette autre fonction. Cela permet notamment d'ajouter des traces d'exécution (par exemple à des fins de débogage) ou d'accélérer le fonctionnement d'une fonction en ajoutant un cache.
Perl n'a pas de fonctionnalité spécifique pour utiliser des décorateurs, mais cet article montre qu'il est assez facile de créer cette fonctionnalité. Au passage, l'article illustre l'utilisation de certaines fonctions dites « avancées » de Perl, lesquelles sont en fait moins mystérieuses qu'il n'y paraît de prime abord.
Bonne lecture et bonne soirée à tous.
Utilisation des décorateurs dans un module
Bonjour,
j'essaye de mettre en oeuvre les décorateurs avec ce cas d'application simple : nos programmes écrivent dans un fichier de log qui sera poussé vers un serveur de logs. Les lignes du fichier log ont un format spécifique et les écritures sont gérées par des fonctions d'un module.
Les fonctions gérant les lignes de type INFO et WARN sont similaires, à l'exception du préfixe de la ligne (OXRES ou OXINC).
Version sans décorateurs :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| sub oxa_msg_info {
my ( $msg, $flag ) = @_;
my $tms = ( $flag ) ? utils_timestamp() . ' - ' : '';
say 'OXRES: ' . $tms . $msg;
return;
}
sub oxa_msg_warn {
my ( $msg, $flag ) = @_;
my $tms = ( $flag ) ? utils_timestamp() . ' - ' : '';
say "OXINC: " . $tms . "$msg";
return;
} |
Version avec décorateurs :
Cette version crée en début de module deux coderefs via l'appel de la fonction decorateur en lui passant en argument la référence à la fonction générique info_or_warn qui ne fait qu'une écriture et le préfixe associé.
Nous avons donc à disposition les deux fonctions oxa_msg_info et oxa_msg_warn utilisant la fonction générique info_or_warn redécorée en fonction du besoin .
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| {
no warnings 'redefine';
*{xxx_utils::oxa_msg_info} = decorateur(\&info_or_warn, 'OXRES');
*{xxx_utils::oxa_msg_warn} = decorateur(\&info_or_warn, 'OXINC');
}
sub info_or_warn {
my ( $msg ) = @_;
say $msg;
}
sub decorateur {
my ( $coderef, $type_msg) = @_;
return sub {
my ( $msg, $flag ) = @_;
my $tms = ( $flag ) ? utils_timestamp() . ' - ' : '';
$coderef->($type_msg . ': ' . $tms . $msg);
}
} |
Cela fonctionne, et je me pose maintenant la question de la pertinence de ce cas et si oui, de son écriture.
Commentaires/suggestions bienvenus.