Spiffy - Cadre d'interface Spiffy Perl pour vous
package Keen; use Spiffy -Base; field 'mirth'; const mood => ':-)'; sub happy { if ($self->mood eq ':-(') { $self->mirth(-1); print "Cheer up!"; } super; }
"Spiffy" est un framework et une méthodologie pour faire de la programmation orientée objet (OO) en Perl. Spiffy combine les meilleures parties d'Exporter.pm, base.pm, mixin.pm et SUPER.pm en une seule classe de base magique. Il tente de résoudre tous les problèmes du Perl OO traditionnel, d'une manière propre, directe et (peut-être un jour) standard.
Spiffy emprunte des idées à d'autres langages OO comme Python, Ruby, Java et Perl 6. Il ajoute également quelques astuces qui lui sont propres.
Si vous jetez un œil sur CPAN, il existe une tonne de modules liés à OO. Lorsque vous démarrez un nouveau projet, vous devez choisir l’ensemble de modules qui a le plus de sens, puis utiliser ces modules dans chacune de vos classes. Spiffy, en revanche, contient tout ce dont vous aurez probablement besoin dans un seul module, et vous ne devez l'utiliser qu'une seule fois dans l'un de vos cours. Si vous faites de Spiffy.pm la classe de base de la classe la plus basse de votre projet, Spiffy transmettra automatiquement toute sa magie à toutes vos sous-classes. Vous pourriez éventuellement oublier que vous l'utilisez !
La différence la plus frappante entre Spiffy et les autres classes de base Perl orientées objet est qu'elle a la capacité d'exporter des éléments. Si vous créez une sous-classe de Spiffy, toutes les choses exportées par Spiffy seront automatiquement exportées par votre sous-classe, en plus de toutes les autres choses que vous souhaitez exporter. Et si quelqu'un crée une sous-classe de votre sous-classe, tous ces éléments seront automatiquement exportés, et ainsi de suite. Considérez-le comme une « exportation héritée » et il utilise la syntaxe familière de la spécification Exporter.pm.
Pour utiliser Spiffy ou n'importe quelle sous-classe de Spiffy comme classe de base de votre classe, vous spécifiez l'argument -base
à la commande use
.
use MySpiffyBaseModule -base;
Vous pouvez également utiliser la use base 'MySpiffyBaseModule';
syntaxe et tout fonctionnera exactement de la même manière. La seule mise en garde est que Spiffy.pm doit déjà être chargé. C'est parce que Spiffy recâble base.pm à la volée pour effectuer toutes les magies Spiffy.
Spiffy prend en charge les mixins de type Ruby avec des rôles de type Perl6. Tout comme base
vous pouvez utiliser l'une des invocations suivantes :
use mixin 'MySpiffyBaseModule'; use MySpiffyBaseModule -mixin;
La deuxième version ne fonctionnera que si la classe mélangée est une sous-classe de Spiffy. La première version fonctionnera dans tous les cas, à condition que Spiffy ait déjà été chargé.
Pour limiter les méthodes mélangées, utilisez des rôles. (Indice : ils fonctionnent comme une liste d'exportateurs ):
use MySpiffyBaseModule -mixin => qw(:basics x y !foo);
En Perl orienté objet, presque chaque sous-programme est une méthode. Chaque méthode reçoit l'objet qui lui est transmis comme premier argument. Cela signifie que pratiquement tous les sous-programmes commencent par la ligne :
my $self = shift;
Spiffy fournit un mécanisme de filtre simple et facultatif pour insérer cette ligne pour vous, ce qui donne un code plus propre. Si vous pensez qu’une méthode moyenne comporte 10 lignes de code, cela représente 10 % de votre code ! Pour activer cette option, utilisez simplement l'option - Base
au lieu de l'option -base
, ou ajoutez l'option -selfless
. Si le filtrage des sources vous donne la nausée, n'utilisez pas cette fonctionnalité. Personnellement, je trouve cela addictif dans ma quête d’écriture de code parfaitement propre et maintenable.
Une fonctionnalité utile de Spiffy est qu'il exporte deux fonctions : field
et const
qui peuvent être utilisées pour déclarer les attributs de votre classe et générer automatiquement des méthodes d'accès pour celles-ci. La seule différence entre les deux fonctions est que les attributs const
ne peuvent pas être modifiés ; ainsi l'accesseur est beaucoup plus rapide.
Un aspect intéressant de la programmation OO est lorsqu’une méthode appelle la même méthode depuis une classe parent. Ceci est généralement connu sous le nom d’appel d’une super méthode. La facilité de Perl pour faire cela est moche :
sub cleanup { my $self = shift; $self->scrub; $self->SUPER::cleanup(@_); }
Spiffy rend, euh, très facile d'appeler des super méthodes. Vous utilisez simplement la super
fonction. Vous n'avez pas besoin de lui transmettre d'arguments car il les transmet automatiquement pour vous. Voici la même fonction avec Spiffy :
sub cleanup { $self->scrub; super; }
Spiffy a une méthode spéciale pour analyser les arguments appelée parse_arguments
, qu'il utilise également pour analyser ses propres arguments. Vous déclarez quels arguments sont booléens (singletons) et lesquels sont appariés, avec deux méthodes spéciales appelées boolean_arguments
et paired_arguments
. Parse arguments extrait les booléens et les paires et les renvoie dans un hachage anonyme, suivi d'une liste des arguments sans correspondance.
Enfin, Spiffy peut exporter quelques fonctions de débogage WWW
, XXX
, YYY
et ZZZ
. Chacun d'eux produit un dump YAML de ses arguments. WWW avertit la sortie, XXX meurt avec la sortie, YYY imprime la sortie et ZZZ confesse la sortie. Si YAML ne répond pas à vos besoins, vous pouvez basculer tous les dumps au format Data::Dumper avec l'option -dumper
.
C'est Spiffy !
Spiffy implémente une idée complètement nouvelle en Perl. Des modules qui agissent à la fois comme des classes orientées objet et qui exportent également des fonctions. Mais cela va encore plus loin avec le concept d’Exporter.pm ; il parcourt tout le chemin @ISA
d'une classe et respecte les spécifications d'exportation de chaque module. Puisque Spiffy fait appel au module Exporter pour ce faire, vous pouvez utiliser toutes les fonctionnalités d'interface sophistiquées dont dispose Exporter, y compris les balises et la négation.
Spiffy considère tous les arguments qui ne commencent pas par un tiret comme constituant la spécification d'exportation.
package Vehicle; use Spiffy -base; our $SERIAL_NUMBER = 0; our @EXPORT = qw($SERIAL_NUMBER); our @EXPORT_BASE = qw(tire horn); package Bicycle; use Vehicle -base, '!field'; $self->inflate(tire);
Dans ce cas, Bicycle->isa('Vehicle')
ainsi que tout ce que Vehicle
et Spiffy
exportent iront dans Bicycle
, à l'exception field
.
L'exportation peut être très utile lorsque vous avez conçu un système avec des centaines de classes et que vous souhaitez qu'elles aient toutes accès à certaines fonctions ou constantes.
or variables. Just export them in your main base class and every subclass
obtiendront les fonctions dont ils ont besoin.
Vous pouvez faire presque tout ce que fait Exporter car Spiffy délègue le travail à Exporter (après avoir ajouté un peu de magie Spiffy). Spiffy propose une variable @EXPORT_BASE
qui ressemble à @EXPORT
, mais uniquement pour les utilisations utilisant -base
.
Si vous avez fait beaucoup de programmation OO en Perl, vous avez probablement utilisé l'héritage multiple (MI), et si vous avez fait beaucoup de MI, vous avez probablement rencontré des problèmes étranges et des maux de tête. Certains langages comme Ruby tentent de résoudre les problèmes MI en utilisant une technique appelée mixins. Fondamentalement, toutes les classes Ruby utilisent uniquement l'héritage unique (SI), puis mélangent les fonctionnalités d'autres modules si nécessaire.
Les mixins peuvent être considérés de manière simpliste comme l'importation des méthodes d'une autre classe dans votre sous-classe. Mais du point de vue de la mise en œuvre, ce n’est pas la meilleure façon de procéder. Spiffy fait ce que Ruby fait. Il crée une classe anonyme vide, importe tout dans cette classe, puis enchaîne la nouvelle classe dans votre chemin SI ISA. En d'autres termes, si vous dites :
package AAA; use BBB -base; use CCC -mixin; use DDD -mixin;
Vous vous retrouvez avec une seule chaîne d'héritage de classes comme celle-ci :
AAA << AAA-DDD << AAA-CCC << BBB;
AAA-DDD
et AAA-CCC
sont les noms de packages réels des classes générées. La bonne chose à propos de ce style est que le mixage en CCC n'entrave aucune méthode en AAA, et DDD n'entre pas non plus en conflit avec AAA ou CCC. Si vous avez mélangé une méthode en CCC qui était également en AAA, vous pouvez toujours y accéder en utilisant super
.
Lorsque Spiffy mixe dans CCC, il extrait toutes les méthodes de CCC qui ne commencent pas par un trait de soulignement. En réalité, cela va plus loin que cela. Si CCC est une sous-classe, elle intégrera toutes les méthodes que CCC can
utiliser via l'héritage. C'est très puissant, peut-être trop puissant.
Pour limiter ce que vous mixez, Spiffy emprunte le concept de rôles à Perl6. Le terme rôle est cependant utilisé de manière plus vague dans Spiffy. Cela ressemble beaucoup à une liste d'importation utilisée par le module Exportateur, et vous pouvez utiliser des groupes (balises) et des négations. Si le premier élément de votre liste utilise la négation, Spiffy démarrera avec toutes les méthodes que votre classe mixin peut utiliser.
use EEE -mixin => qw(:tools walk !run !:sharp_tools);
Dans cet exemple, walk
et run
sont des méthodes que EEE peut utiliser, et tools
et sharp_tools
sont des rôles de classe EEE. Comment la classe EEE définit-elle ces rôles ? Il définit très simplement des méthodes appelées _role_tools
et _role_sharp_tools
qui renvoient des listes de méthodes supplémentaires. (Et peut-être d'autres rôles !) Ce qui est intéressant ici, c'est que puisque les rôles ne sont que des méthodes, ils peuvent également être hérités. Prends ce Perl6 !
En utilisant l'indicateur -Base
au lieu de -base
vous n'avez jamais besoin d'écrire la ligne :
my $self = shift;
Cette instruction est ajoutée à chaque sous-programme de votre classe à l'aide d'un filtre source. La magie est simple et rapide, il y a donc peu de pénalités de performances pour créer du code propre à égalité avec Ruby et Python.
package Example; use Spiffy -Base; sub crazy { $self->nuts; } sub wacky { } sub new() { bless [], shift; }
est exactement la même chose que :
package Example; use Spiffy -base; use strict;use warnings; sub crazy {my $self = shift; $self->nuts; } sub wacky {my $self = shift; } sub new { bless [], shift; } ;1;
Notez que les parenthèses vides après le sous-programme new
l'empêchent d'avoir un $self ajouté. Notez également que le code supplémentaire est ajouté aux lignes existantes pour garantir que les numéros de ligne ne sont pas modifiés.
-Base
active également les pragmas stricts et d'avertissement, et ajoute cet ennuyeux '1;' ligne à votre module.
Spiffy prend désormais en charge les méthodes privées lorsque vous utilisez le mécanisme de filtrage '-Base'. Il vous suffit de déclarer les sous-marins avec le mot-clé my
et de les appeler avec un '$'
devant. Comme ça:
package Keen; use SomethingSpiffy -Base; # normal public method sub swell { $self->$stinky; } # private lexical method. uncallable from outside this file. my sub stinky { ... }
La fonction XXX est très pratique pour le débogage car vous pouvez l'insérer presque n'importe où et elle videra vos données dans un YAML propre et agréable. Prenons la déclaration suivante :
my @stuff = grep { /keen/ } $self->find($a, $b);
Si vous rencontrez un problème avec cette instruction, vous pouvez la déboguer de l'une des manières suivantes :
XXX my @stuff = grep { /keen/ } $self->find($a, $b); my @stuff = XXX grep { /keen/ } $self->find($a, $b); my @stuff = grep { /keen/ } XXX $self->find($a, $b); my @stuff = grep { /keen/ } $self->find(XXX $a, $b);
XXX est facile à insérer et à retirer. C'est également une tradition de marquer les zones de code incertaines avec XXX. Cela rendra les dumpers de débogage faciles à repérer si vous oubliez de les retirer.
WWW et YYY sont sympas car ils vident leurs arguments puis renvoient les arguments. De cette façon, vous pouvez les insérer à de nombreux endroits tout en continuant à exécuter le code comme avant. Utilisez ZZZ lorsque vous devez mourir avec à la fois un dump YAML et une trace de pile complète.
Les fonctions de débogage sont exportées par défaut si vous utilisez l'option -base
, mais uniquement si vous avez préalablement utilisé l'option -XXX
. Pour exporter les 4 fonctions, utilisez la balise export :
use SomeSpiffyModule ':XXX';
Pour forcer les fonctions de débogage à utiliser Data::Dumper au lieu de YAML :
use SomeSpiffyModule -dumper;
Cette section décrit les fonctions exportées par Spiffy. Les fonctions field
, const
, stub
et super
ne sont exportées que lorsque vous utilisez les options -base
ou -Base
.
champ
Définit les méthodes d'accesseur pour un champ de votre classe :
package Example; use Spiffy -Base; field 'foo'; field bar => []; sub lalala { $self->foo(42); push @{$self->{bar}}, $self->foo; }
Le premier paramètre transmis au field
est le nom de l'attribut en cours de définition. Les accesseurs peuvent recevoir une valeur par défaut facultative. Cette valeur sera renvoyée si aucune valeur pour le champ n'a été définie dans l'objet.
const
const bar => 42;
La fonction const
est similaire à <field> sauf qu'elle est immuable. Il ne stocke pas non plus de données dans l'objet. Vous voudrez probablement toujours donner à un const
une valeur par défaut, sinon la méthode générée sera quelque peu inutile.
bout
stub 'cigar';
La fonction stub
génère une méthode qui mourra avec un message approprié. L'idée est que les sous-classes doivent implémenter ces méthodes afin que les méthodes stub ne soient pas appelées.
super
Si cette fonction est appelée sans aucun argument, elle appellera la même méthode que celle dans laquelle elle se trouve, plus haut dans l'arborescence ISA, en lui transmettant tous les mêmes arguments. S'il est appelé avec des arguments, il utilisera ces arguments avec $self
devant. En d’autres termes, cela fonctionne comme vous vous en doutez.
sub foo { super; # Same as $self->SUPER::foo(@_); super('hello'); # Same as $self->SUPER::foo('hello'); $self->bar(42); } sub new() { my $self = super; $self->init; return $self; }
super
ne fera tout simplement rien s’il n’y a pas de super méthode. Enfin, super
fait ce qu'il faut dans les sous-programmes AUTOLOAD.
Cette section répertorie toutes les méthodes dont toute sous-classe de Spiffy hérite automatiquement.
mélanger
Une méthode pour mélanger une classe au moment de l’exécution. Prend les mêmes arguments que use mixin ...
. Fait de la classe cible un mixin de l'appelant.
$self->mixin('SomeClass'); $object->mixin('SomeOtherClass' => 'some_method');
analyser_arguments
Cette méthode prend une liste d’arguments et les regroupe par paires. Il autorise les arguments booléens qui peuvent ou non avoir une valeur (par défaut 1). La méthode renvoie une référence de hachage de toutes les paires sous forme de clés et de valeurs dans le hachage. Tous les arguments qui ne peuvent pas être appariés sont renvoyés sous forme de liste. Voici un exemple :
sub boolean_arguments { qw(-has_spots -is_yummy) } sub paired_arguments { qw(-name -size) } my ($pairs, @others) = $self->parse_arguments( 'red', 'white', -name => 'Ingy', -has_spots => -size => 'large', 'black', -is_yummy => 0, );
Après cet appel, $pairs
contiendra :
{ -name => 'Ingy', -has_spots => 1, -size => 'large', -is_yummy => 0, }
et @others
contiendra « rouge », « blanc » et « noir ».
arguments_booléens
Renvoie la liste des arguments reconnus comme booléens. Remplacez cette méthode pour définir votre propre liste.
arguments_appariés
Renvoie la liste des arguments reconnus comme étant appariés. Remplacez cette méthode pour définir votre propre liste.
Lorsque vous use
le module Spiffy ou une sous-classe de celui-ci, vous pouvez lui transmettre une liste d'arguments. Ces arguments sont analysés à l'aide de la méthode parse_arguments
décrite ci-dessus. L'argument spécial -base
, est utilisé pour faire du package actuel une sous-classe du module Spiffy utilisé.
Tous les paramètres non appariés agissent comme une liste d'importation normale ; tout comme ceux utilisés avec le module Exportateur.
La bonne façon d'utiliser un module Spiffy comme classe de base consiste à utiliser le paramètre -base
dans l'instruction use
. Cela diffère des modules typiques dans lesquels vous souhaiteriez use base
.
package Something; use Spiffy::Module -base; use base 'NonSpiffy::Module';
Maintenant, il peut être difficile de savoir ce qui est Spiffy et ce qui ne l'est pas. Par conséquent, Spiffy a été conçu pour fonctionner avec base.pm. Vous pouvez dire :
package Something; use base 'Spiffy::Module'; use base 'NonSpiffy::Module';
use base
est également très utile lorsque votre classe n'est pas un module réel (un fichier séparé) mais simplement un package dans un fichier déjà chargé. base
fonctionnera que la classe soit un module ou non, alors que la syntaxe -base
ne peut pas fonctionner de cette façon, puisque use
essaie toujours de charger un module.
Pour faire fonctionner Spiffy avec base.pm, un sale tour a été joué. Spiffy échange base::import
avec sa propre version. Si les modules de base ne sont pas Spiffy, Spiffy appelle la base::import d'origine. Si les modules de base sont Spiffy, alors Spiffy fait son propre travail.
Il y a deux mises en garde.
Spiffy doit être chargé en premier.
Si Spiffy n'est pas chargé et use base
est invoqué sur un module Spiffy, Spiffy mourra avec un message utile indiquant à l'auteur de lire cette documentation. C'est parce que Spiffy devait effectuer l'échange d'importation au préalable.
Si vous obtenez cette erreur, mettez simplement une instruction comme celle-ci au début de votre code :
use Spiffy ();
Pas de mélange
base.pm
peut prendre plusieurs arguments. Et cela fonctionne avec Spiffy tant que toutes les classes de base sont Spiffy, ou qu'elles sont toutes non Spiffy. S'ils sont mélangés, Spiffy mourra. Dans ce cas, utilisez simplement des instructions use base
distinctes.
Spiffy est une merveilleuse façon de faire de la programmation OO en Perl, mais c'est encore un travail en cours. De nouvelles choses seront ajoutées et celles qui ne fonctionnent pas bien pourraient être supprimées.
Ingy dot Net <[email protected]>
Droits d'auteur 2004-2014. Ingy dot Net.
Ce programme est un logiciel gratuit ; vous pouvez le redistribuer et/ou le modifier dans les mêmes conditions que Perl lui-même.
Voir http://www.perl.com/perl/misc/Artistic.html