Jouons avec Moose (ou comment réapprendre le Perl Objet) – partie 1
Cet article inaugure une série consacrée à Moose qui vise à montrer comment écrire du Perl Objet moderne. Les exemples de code sont tous testés avec l’excellent shell Devel::REPL.
Jusqu’à hier, je croyais connaître Perl. Hier j’ai découvert Moose. Il s’agit d’une extension du système objet de Perl. Au début je dois avouer que j’étais scéptique. J’avais tort.
Moose est une extension qui enrichi le système objet de Perl5 d’une façon profonde.
C’est à dire :
- une syntaxe élégante (avec des mot-clef qui ont du sens)
- une meta-classe digne de ce nom (constructeur et accesseurs par défaut)
- un système d’interface
- un système d’héritage propre
- une gestion fine des attributs des objets.
Au lieu de vanter ses mérites en long en large et en travers, je propose à ceux qui en ont envie de me suivre au travers d’un exemple concret : nous allons découvrir ensemble Moose en modélisant Conan le Barbare ! (quoi de plus épique, sans déconner ?).
Notre premier objectif est de disposer d’une classe Heros qui décrive un héros de base.
Pour commencer, ce héros devra avoir un nom :
package Heros;
use Moose;
has 'name' => (
is => 'ro',
required => 1,
isa => 'Str'
);
Avec ces quelques lignes, nous venons de dire beaucoup de choses. Tout d’abord, Heros est un objet Moose, ce qui nous fournit un constructeur par défaut et tout un jeu d’accesseurs évolués. Nous disons également que les objets de la classe Heros ont impérativement un attribut “name” et que cet attribut n’est pas modifiable.
Regardons ce que cela donne:
Perl> $perso = new Heros name => 'Conan'
$Heros1 = Heros=HASH(0x8abe7d8);
Perl> $perso->name
Conan
Perl> $perso->name('Merlin')
Runtime error: Cannot assign a value to a
read-only accessor at (eval 62) line 1
Très bien, tout ça est parfait. Nous assignons un nom lors de l’instanciation, mais ne pouvons pas le modifier par la suite. C’est bien ce que nous avons décrit.
Nous voulons maintenant donner de la vie (et de la mort !) à notre héros, pour cela il nous faut deux nouveaux attributs : un nombre de points de vie et un score en endurance (qui nous permettra d’amortir les dégâts pris lors d’une attaque).
has 'pv' => (
is => 'rw', required => 1, isa => 'Int',
default => 20,
);
has 'endurance' => (
is => 'rw', required => 1, isa => 'Int',
default => 3
);
Notre personnage aura donc 20 points de vie lors de sa naissance, et amortira 3 points de dégâts lors d’un choc reçu.
C’est très bien, mais il nous faut détecter la mort du personnage lorsque ses points de vie atteindront 0…
Pour cela Moose nous permet d’attacher des déclencheurs (trigger) à des attributs. C’est ce que nous allons faire pour l’attribut “pv” :
has 'pv' => (
is => 'rw', required => 1, isa => 'Int',
default => 20,
trigger => sub {
my ($self, $pv, @args) = @_;
$self->meurt if $pv == 0;
}
);
Maintnant, lorsque les point de vie arrivent à zéro, la méthode meurt() est appelée. Il nous reste donc à la définir :
sub meurt
{
my ($self) = @_;
$self->endurance(0);
print $self->name . " est mort !\n";
}
Très bien, amusons-nous cruellement à tuer Conan maintenant :
Perl> $perso->pv 20 Perl> $perso->pv(0) Conan est mort ! 0 Perl>
C’est bien ce que nous voulons, lorsque les PV sont nul, le personnage meurt. Mais cette façon arbitraire de faire perdre des points de vie au personnage n’est pas très orthodoxe pour les rôlistes que nous sommes. Il nous faut une méthode blessure() qui sera dédiée à encaisser les coups, et ce de la bonne façon (en amortissant les dégâts avec l’endurance) :
sub blessure
{
my ($self, $degats) = @_;
$degats = $degats - $self->endurance;
$degats = 0 if $degats < 0;
my $pv = $self->pv - $degats;
$pv = 0 if $pv < 0;
$self->pv($pv);
}
Très bien, nous pouvons désormais blesser Conan en prenant en compte son endurance :
Perl> $perso->pv 20 Perl> $perso->blessure(4) 19 Perl>
Pour terminer (et surtout pour être honnète vis à vis de Conan), il nous faut donner à notre héros la possibilité de causer des dégâts. Pour cela il a besoin naturellement d’un score en force et d’une méthode pour frapper.
has 'force' => (
is => 'rw', required => 1, isa => 'Int',
default => 3
);
sub attaque
{
my ($self) = @_;
return $self->force + int(rand(10) + 1);
}
Voici donc une attaque qui prend la force et y ajoute un score compris entre 1 et 10 :
Perl> $perso->attaque 7 Perl> $perso->attaque 9 Perl>
Voilà, notre héros est désormais armé pour arpenter les chemins de terre et y pourfendre bêtes et immondices.
Dans notre prochain article nous verrons comment étendre la classe “Heros” en classe “Barbare”, afin de spécialiser Conan, et lui donner encore plus de prestence (il va être content le Conan).
1163 views · Tags: Moose, Perl · Both comments and pings are currently closed.
Excellente petite entrée en matière.
Je ne sais pas si c’est Moose ou Connan qui m’interesse le plus !
Héhé, nous sommes donc au moins deux à trouver l’idée de cette série amusante, tant mieux ! :)
Tien, cool ca l’ami ! Ca me donne envie de me pencher dessus (moose, pas conan)