lunes, 18 de enero de 2010

Dulce dulce Moose

[English translation]

Uno de los comentarios que recibí por el artículo anterior fue acerca de como se vería utilizando la sintaxis de MooseX::Declare.

Este módulo provee extensiones sintácticas que van mucho más allá del azúcar sintáctico regular de Moose.  Utilizando la magia negra de Devel::Declare, MooseX::Declare crea toda una nueva sintaxis muy similar a la de Perl6, para declarar las clases y roles de Moose, sin embargo, el uso de estas extensiones me genera sentimientos encontrados.

Por un lado está la apariencia y simplicidad de la sintaxis implementada por el módulo, y por otra parte me he dado cuenta que al cambiar la sintaxis de esta manera dejan de funcionar herramientas que doy por sentadas, como perltidy, que da errores en la declaración de prototipos en los métodos, también dejan de funcionar bien módulos como PPI y hasta el coloreo de vim.

Estoy consciente de que todo es cuestión de reparar perltidy, PPI y el coloreo de vim, pero el detalle es que es difícil implementar cuanta sintaxis se le ocurra a cualquiera que introduzca nuevos módulos en el CPAN.

Siempre he argumentado que una de las ventajas de Devel::Declare es que permite evolucionar Perl5 a través del CPAN, módulos como TryCatch y MooseX::Declare muestran extensiones sintácticas que en algún momento podrían agregarse a Perl5 de resultar ampliamente aceptadas.

Pero ¿cómo llegarán a ser ampliamente aceptadas, si no las usamos porque rompen las herramientas que normalmente usamos?

A lo mejor nada de esto importa porque ya en marzo de 2010 llega Rakudo *, y todo el mundo comenzará la gran migración a Perl6.

Como en realidad tengo la misma cantidad de argumentos a favor y en contra, voy a seguir meditando en cuales tienen mas peso que otros. Pero mientras tanto aqui tienen la versión de roles del juego de los animales en MooseX::Declare, para que uds. se hagan una idea propia sobre sus costos y beneficios:

 1 #!/usr/bin/env perl
 2 use MooseX::Declare;
 3 
 4 class QuestionNode {
 5     has pregunta => ( is => "ro", isa => "Str", required => 1 );
 6     has [ "si", "no" ] => ( is => "rw", isa => "Str|QuestionNode", required => 1 );
 7 }
 8 
 9 role AnimalsGame {
10 
11     has tree => (
12         is      => "ro",
13         isa     => "QuestionNode",
14         default => sub {
15             QuestionNode->new(
16                 { pregunta => 'vive en el agua', no => 'tigre', si => 'tiburón' } );
17         }
18     );
19 
20     method play {
21         my $guess = $self->tree;
22         my ( $node, $branch );
23         while ( ref($guess) ) {
24             $node   = $guess;
25             $branch = $self->si( $node->pregunta ) ? "si" : "no";
26             $guess  = $node->$branch;
27         }
28         return if $self->si("Es un(a) $guess");
29         my $animal = $self->prompt("Nombre del animal: ");
30         my $diff   = $self->prompt(
31             "Una pregunta cierta para $animal pero falsa para $guess: ");
32         $node->$branch( QuestionNode->new( { pregunta => $diff, no => $guess, si => $animal } ) );
33     }
34 
35 }
36 
37 role ConsoleGame {
38     use Term::ReadLine;
39     use IO::Handle;
40 
41     has title => ( is => "ro", isa => "Str", default => "El juego de los animales" );
42     has term => (
43         is         => "ro",
44         isa        => "Object",
45         lazy_build => 1,
46         handles    => { prompt => "readline" }
47     );
48 
49     method _build_term {
50         Term::ReadLine->new( $self->title );
51     }
52 
53     method si(Str $prompt) {
54         while (1) {
55             my $answer = $self->prompt("$prompt? (y/n): ");
56             return ( $2 ? 1 : 0 ) if $answer =~ /^\s*((si|s)|(no|n))\s*/i;
57             $self->term->OUT->print("Responde 's' o 'n'\n");
58         }
59     }
60 
61     method run {
62         $self->play;
63         $self->play while $self->si("Quieres jugar de nuevo");
64     }
65 }
66 
67 class Game with AnimalsGame with ConsoleGame {}
68 
69 Game->new->run;

No hay comentarios:

Publicar un comentario