Jouons avec Moose (ou comment réapprendre le Perl Objet) – partie 4

Cet article est la quatrième partie d’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.

Dans notre précédent article, nous avons vu comment utiliser les Moose::Role pour définir des armes. Ajourd’hui nous allons créer une nouvelle classe de héros, les mages, qui vont nous servir à illustrer un concept tout aussi magique : la coercition (coercion en anglais). Cet article est dédicacé à Jérôme Bourgeois qui m’a donné l’idée de faire intervenir un mage dans cette série, merci à lui.

Nous allons aujourd’hui créer la classe « Mage » qui modélisera un nouveau type de héros. Pour commencer, et avant de s’attaquer à la coercition, nous allons spécialiser la classe Mage. Nous voulons qu’un mage soit un héros comme un autre à ceci prêt qu’il est plus chétif (c’est bien connu, les mages sont tous végétariens, ça facilite la circulation des fluides énergétiques, mais ça freine sensiblement le développement de la masse musculaire).

Bref. Un mage est un Héros disions-nous :

package Mage;
use Moose;
extends 'Heros';

Mais un mage est plus faible qu’un héros conventionnel, nous voulons donc altérer sa force et son endurance. Pour cela, Moose nous permet de modifier un attribut hérité en préfixant le nom dudit attribut par un “+” :

has '+force' => (default => 2);
has '+endurance' => (default => 2);

Les attributs force et endurance hérités de la classe Héros (définie dans le permiet article de cette série) vaudront donc 2 pour un Mage, au lieu de 3.

Perl> $merlin = new Mage name => "Merlin"
$Mage1 = Mage=HASH(0x8b082c4);

Perl> $merlin->force
2

Maintenant, nous allons enrichir le mage en le dottant d’un familier (pour nos amis non-rôliste, rapellons que les familiers sont des petites créatures qui accompagnent les mages). Pour cela, nous allons faire intervenir le mécanisme de coercition, en créant un attribut « familier ».

La coercition va nous permettre de donner à l’accesseur de l’attribut familier une chaîne en entrée et celui-ci se chargera de convertir la chaîne en un objet Heros.
Pour cela, il nous faut définir un type de champ, et cela se fera grâce qu module Moose::Util::TypeConstraints :

package Mage;
use Moose;
use Moose::Util::TypeConstraints;

use Heros;
subtype 'Familier'
    => as 'Object'
    => where  {$_->isa('Heros')};

Maintenant nous disposons d’un type d’attribut nommé « Familier » qui cache un objet de la classe « Heros ».
Nous allon à présent définir la coercition qui doit s’opérer lorsqu’un attribut de ce type est modifié avec une chaîne de caractères :

coerce 'Familier'
    => from 'Str'
        => via {new Heros
            name => $_,
            force => 1,
            endurance => 1};

Nous convertissons donc la chaîne donnée en Heros dont le nom est précisément la chaîne fournie. Au passage, comme le familier est une petite créature, nous écrasons les valeurs par défaut du Héros en force et endurance. Le lecteur comprendra ici que nous pourrions définir une classe Familier pour l’occasion.
Maintenant, il nous reste à déclarer l’attribut à proprement parlé :

has 'familier' => (
    is => 'rw',
    isa => 'Familier',
    coerce => 1
);

On note la présence du mot-clef “coerce” ici qui active la coercition. Ce mécanisme étant désactivé par défaut pour éviter les mauvaises surprises.

Bien. Vérifions que tout se comporte comme prévu :

Perl> $merlin->familier('sarkopette')
$Heros1 = Heros=HASH(0x8b2bb8c);

$merlin->familier->force
1

$merlin->familier->name
sarkopette

Le coercition a bien eu lieu, lorsque l’accesseur familier() est utilisé, une instanciation de Heros a lieu, comme par magie.

This entry was posted in Programmation and tagged , . Bookmark the permalink. . 2661 views.

5 Responses to Jouons avec Moose (ou comment réapprendre le Perl Objet) – partie 4

  1. pichop says:

    yeah !
    Vraiment cool ce petit tuto, ca me donne de plus en plus envie de me relancer dans du développement…Enfin, quand j’en aurait le temps.
    Déjà que j’en manque pour venir vous faire un petit “hello world” !

  2. Rhulk says:

    Encore, encore je suis accrooo Arrrgggh

  3. sukria says:

    Rhulk: haha :) Je vais essayer de faire une partie 5 un de ces quatre, mais mon temps libre est monopolisé par l’écriture de Coat en ce moment…

  4. Thierry Chich says:

    Merci beaucoup.
    C’était très intéressant. Jusque là, j’utilisais le pragma classes, qui me faisait de bien belles choses, mais j’ai bien l’impression que Moose est à la fois plus connu et mieux suivi. Mon seul regret, c’est que le get_ et set_ ne soit pas posé par défaut sur les accesseurs. Il suffit de poser
    use Moose::Policy ‘Moose::Policy::FollowPBP’;, mais c’est un peu lourd.

  5. sukria says:

    Pour info: Il y a Coat également qui implémente les fonctionnalités de base de Moose en Perl 5 natif (plus rapide donc et plus facile a installer donc).