lunes, 27 de mayo de 2013

Corolario I


Un juego en Perl

Como corolario de la Parte I de "Perl for newbies" vamos a programar un juego muy simple. Se trata de adivinar qué número está pensando la computadora. Se le pide al usuario que adivine el número y le informamos si acertó o si su número es mayor o menor. Manos a la obra!

print '*'x78;
print "\n";
print 'Adivina mi numero';
print "\n";
print '*'x78;
print "\n";

print 'Estoy pensando un numero',"\n";
my $miNumero= 5;
print 'Quieres adivinar mi numero? (si/no)',"\n";
my $respuesta= <>;
chomp($respuesta);
if ('si'eq$respuesta) {
   print 'Dime que numero estoy pensando',"\n";
   my $numero= <>;
   chomp($numero);
   if ($miNumero==$numero){
      print 'Si! Acertaste! Mi numero es el ', $miNumero, '!!!',"\n";
   } elsif($miNumero<$numero) {
      print 'No. Mi numero es menor que ', $numero, "\n";
   } else {
      print 'No. Mi numero es mayor que ', $numero, "\n";
   }
} else {
   print 'Esta bien, no quieres adivinar mi numero',"\n";
}

print 'Gracias por jugar conmigo',"\n";
print '-'x78;
print "\n";

Las posibles salidas del programa son:

***************************************************************************
Adivina mi numero
***************************************************************************
Estoy pensando un numero
Quieres adivinar mi numero? (si/no)
si
Dime que numero estoy pensando
5
Si! Acertaste! Mi numero es el 5!!!
Gracias por jugar conmigo
---------------------------------------------------------------------------

***************************************************************************
Adivina mi numero
***************************************************************************
Estoy pensando un numero
Quieres adivinar mi numero? (si/no)
si
Dime que numero estoy pensando
2
No. Mi numero es mayor que 2
Gracias por jugar conmigo
---------------------------------------------------------------------------

***************************************************************************
Adivina mi numero
***************************************************************************
Estoy pensando un numero
Quieres adivinar mi numero? (si/no)
si
Dime que numero estoy pensando
9
No. Mi numero es menor que 9
Gracias por jugar conmigo
---------------------------------------------------------------------------

***************************************************************************
Adivina mi numero
***************************************************************************
Estoy pensando un numero
Quieres adivinar mi numero? (si/no)
no
Esta bien, no quieres adivinar mi numero
Gracias por jugar conmigo
---------------------------------------------------------------------------
Usamos el operador x para imprimir una cantidad fija de caracteres, en este caso '*' y '-'. También usamos <> para recibir la respuesta del usuario, chomp() para limpiarla, print para enviarle mensajes y la estructura de control if para tomar decisiones según el valor ingresado. El problema es que el usuario puede arriesgar una sola vez el valor, además ya sabemos que el número elegido será el 5 así que el juego se torna algo monótono y aburrido. Deberíamos darle al usuario un número distinto cada vez y la oportunidad de adivinarlo con cierta cantidad de intentos, digamos 3. Hagamos las modificaciones para que quede mejor este juego.

Modificaciones

print '*'x78;
print "\n";
print 'Adivina mi numero';
print "\n";
print '*'x78;
print "\n";

print 'Estoy pensando un numero del 0 al 9',"\n";
my $miNumero= int(rand(10));
print 'Quieres adivinar mi numero? (si/no)',"\n";
my $respuesta= <>;
chomp($respuesta);
my $miNumero;
if ('si'eq@respuesta) {
   for my $i (1..3){
      print 'Dime que numero estoy pensando',"\n";
      my $numero= <>;
      chomp($numero);
      if ($miNumero==$numero){
         print 'Si! Acertaste! Mi numero es el ', $miNumero, '!!!', "\n";
         print "Y usaste $i intentos \n";
         last;
      } elsif($miNumero<$numero) {
         print 'No. Mi numero es menor que ', $numero, "\n";
         if (3==$i){ print "Mi numero era el $miNumeroo \n"; }
      } else {
         print 'No. Mi numero es mayor que ', $numero, "\n";
         if (3==$i){ print "Mi numero era el $miNumeroo \n"; }
      }
   }
} else {
   print 'Esta bien, no quieres adivinar mi numero',"\n";
}

print 'Gracias por jugar conmigo',"\n";
print '-'x78;
print "\n";

Usamos la función rand() para obtener un número aleatorio entre 0 y el argumento, en este caso 10, y aunque el número aleatorio podría ser el 0 nunca va a ser 10, pero como son números de coma flotante también usamos la función int() para que nos deje la parte entera del número. Usamos un bucle for que va de 1 a 3 gracias al operador .. que nos devuelve un arreglo de números consecutivos. Usamos last para salir del bucle cuando el usuario adivina el número. Pero el programa no funciona como queremos. Cuando el usuario escribe 'si' el programa termina sin informarnos nada anormal. Para que Perl nos dé más información sobre los posibles errores tenemos que usar dos pragmas muy útiles: strict y warnings. Veamos la diferencia. Cuando agregamos al comienzo del programa
use strict;
use warnings;
Nos informa lo siguiente:
Global symbol "@respuesta" requires explicit package name at adivina2.pl
Global symbol "$miNumeroo" requires explicit package name at adivina2.pl
Hay dos errores de tipeo, primero el @ en la variables $respuesta, luego la 'o' repetida al final de $miNumero. Corregimos y nos dice lo siguiente:
"my" variable $miNumero masks earlier declaration in same scope at adivina2.pl
Parece que declaramos dos veces la misma variable. Borramos la segunda declaración que es la incorrecta en este caso y corremos el programa. Funciona!
use warnings;
use strict;

print '*'x78;
print "\n";
print 'Adivina mi numero';
print "\n";
print '*'x78;
print "\n";

print 'Estoy pensando un numero del 0 al 9',"\n";
my $miNumero= int(rand(10));
print 'Quieres adivinar mi numero? (si/no)',"\n";
my $respuesta= <>;
chomp($respuesta);
if ('si'eq$respuesta) {
   for my $i (1..3){
      print 'Dime que numero estoy pensando',"\n";
      my $numero= <>;
      chomp($numero);
      if ($miNumero==$numero){
         print 'Si! Acertaste! Mi numero es el ', $miNumero, '!!!', "\n";
         print "Y usaste $i intentos \n";
         last;
      } elsif($miNumero<$numero) {
         print 'No. Mi numero es menor que ', $numero, "\n";
         if (3==$i){ print  "Mi numero era el $miNumero \n"; }
      } else {
         print 'No. Mi numero es mayor que ', $numero, "\n";
         if (3==$i){ print "Mi numero era el $miNumero \n"; }
      }
   }
} else {
   print 'Esta bien, no quieres adivinar mi numero',"\n";
}

print 'Gracias por jugar conmigo',"\n";
print '-'x78;
print "\n";

Y esta es mi jugada:

***************************************************************************
Adivina mi numero
***************************************************************************
Estoy pensando un numero del 0 al 9
Quieres adivinar mi numero? (si/no)
si
Dime que numero estoy pensando
7
No. Mi numero es menor que 7
Dime que numero estoy pensando
2
No. Mi numero es mayor que 2
Dime que numero estoy pensando
4    
No. Mi numero es mayor que 4
Mi numero era el 5  
Gracias por jugar conmigo
---------------------------------------------------------------------------

Más modificaciones

Podríamos seguir modificando el programa. Por ejemplo dejar que el usuario elija cuantos intentos puede tener, o que luego de un juego el usuario pueda seguir jugando en vez de terminar el programa, o que el programa elija un número de 2 cifras, o que en vez de elegir un número aleatorio sea una letra aleatoria. Cómo podemos asignar una letra aleatoria a una variable?
my $letra= ('a'..'z')[rand(26)];






martes, 5 de junio de 2012

Una introducción agradable a Moose


Lo que sigue es la versión en español del artículo A gentle introduction to Moose escrita por Jay Kuri en el 2009.


Perl, desde el lanzamiento de su versión 5 en 1994, tiene las características de un lenguaje orientado a objetos. Pero estas características OO siguen siendo algo así como un "hágalo Usted mismo", con el clásico estilo de Perl, ofreciendo un mínimo de apoyo integrado en el lenguaje y el resto se deja a cargo de los demás. 

La principal ventaja de este estilo "hágalo Usted mismo" es que el lenguaje impone muy pocas restricciones sobre la manera de hacer las cosas. Por otro lado tiene la desventaja de ser algo intimidante con los novatos. Por lo bueno y lo malo, se ha vuelto familiar.

Otra ventaja es que las características tienen la libertad de evolucionar, por no estar sujetas por el lenguaje algunos programadores muy inteligentes tuvieron la libertad de explorar formas de hacer las cosas de maneras que no estaban preconcebidas. Moose es el resultado de ésta exploración y rápidamente se convirtió en el estandar defacto para la POO en Perl. Hoy vamos a explorar las bases de la creación y manipulación de objetos en Moose.

En la convencional Programación Orientada a Objetos en Perl hay tres cosas principales que necesitan hacerse. Estas son:
  1. Creación de objetos
  2. Atributos y métodos de acceso
  3. Herencia
Tomaremos un rápido exámen alrededor de estas cuestiones y las compararemos con la técnica Perl y la de Moose.


Creación de objetos
En puro Perl, la forma de crear un objeto es crear una referencia a una variable y luego "bendecirla" con una clase. Podemos hacer esto con cualquier tipo de variable, pero lo más común es usar una referencia a un hash. Esto se hace generalmente en una subrutina 'new':
package FooClass;

  sub new {
      my $class = shift;
      my $foo = {};
      bless $foo, 'FooClass';
      return $foo;
  }

Esto devuelve un objeto. Hay algo más aún. La forma Moose de hacer esto es algo más sencilla:
  package FooClass;
  use Moose;

Eso es todo. Moose crea la subrutina new() por nosotros. Si la clase tiene atributos, Moose también se encargará de gestionarlos basándose ​​en los argumentos que se pueden colocar.
Crear una instancia de una clase sigue la misma convención en un objeto de Moose como un objeto de puro Perl: simplemente llamar a new() en la clase. Moose, sin embargo, permite pasar los valores iniciales de sus atributos en la llamada. Por ejemplo:
  FooClass->new( name => 'bob' );
Este es un poco de funcionalidad útil y gratuita que nos brinda el uso de Moose.


Atributos y métodos de acceso
En Perl, nuestro objeto es (muy a menudo) un hash y sus atributos son simplemente miembros de ese hash. De nuevo a menudo, tales atributos se acceden directamente:
  $foo->{name};
Este generalmente está mal visto, ya que proporciona muy poca estructura y hace fácil declarar mal accidentalmente los atributos. $foo-> {naem} puede ser un error muy difícil de encontrar. La "mejor práctica" generalmente consiste en crear las subrutinas de acceso para las variables, lo que limita a los que utilizan el objeto para trabajar con los atributos que hay creados. (Los geeks OO se refieren a esto como "encapsulación"). El problema es que en Perl OO lo debemos crearlas nosotros mismos:
   sub name {
        my $self = shift;
        if( @_ ) {
            $self->{'name'} = $_[0];
        }
        return $self->{'name'};
    }

Se trata de una gran cantidad de código sólo para escribir los setter/getter del objeto. En puro Perl hay un módulo de CPAN nacido para hacer esto más fácil. Class::Accessor construye estos métodos por nosotros:
  package FooClass;
  use base qw(Class::Accessor);
  FooClass->mk_accessors(qw(name age));

Class::Accessor crea el método new por nosotros. Esto es claramente mejor que hacerlo a mano. Ahora es prácticamente imposible crear accidentalmente atributos o acceder a los equivocados. Hay una cosa que no hace bien. No le impide de ninguna manera poner basura en los atributos. Esto es perfectamente legal:
  $foo = FooClass->new();
  $foo->name(192);
  $foo->age('magdalena');

Moose, por el contrario, no sólo hace lo que Class::Accessor, sino que añade la comprobación de tipos (y algunas otras cosas). El mismo objeto creado con Moose:
  package FooClass;
  use Moose;
  has 'name' => (
    is => 'rw',
    isa => 'Str'
  );

  has 'age' => (
    is => 'rw',
    isa => 'Int'
  );
  1;

Lo anterior proporciona el mismo name() y age() que estamos acostumbrados. Pero si tratamos de establecer la edad como 'magdalena' ahora vamos a obtener un error. Por otro lado también tenemos la capacidad de decir esencialmente "este atributo no se puede cambiar después de crear el objeto". Entre otras cosas, el sistema de atributos y de control de tipos de Moose es increíblemente flexible y merece su propio tutorial dedicado.


Herencia
La herencia en programación orientada a objetos está diseñada para permitir la especialización de una clase. El ejemplo clásico es que se puede tener una clase Figura que puede proporcionar un cierto grado de funcionalidad, y cuando se necesita una clase Cuadrado se puede heredar de Figura y añadir sólo el código que hace particular al Cuadrado. En Perl "puro" OO podríamos hacer esto:
  package Cuadrado;
  @ISA = ("Figura");
  # el resto de la clase Cuadrado

Perl tiene la inteligencia para buscar los métodos que no encuentra en la clase Cuadrado en las clases definidas en @ISA. Funciona bien, pero no es muy intuitivo. Moose tiene herencia también, y lo hace más evidente diciendo:
  package Cuadrado;
  use Moose;
  extends 'Figura';
  # el resto de la clase Cuadrado

Bastante sencillo


Otras cosas de Moose
Moose no hace nada que no se pueda hacer con Perl OO. Moose se basa en las mismas características OO soportadas por el lenguaje Perl. Se ocupa, sin embargo, de una enorme cantidad de trabajo que de lo contrario tendríamos que hacer nosotros mismos, dándole la libertad para trabajar en su "nueva" funcionalidad en lugar de reinventar la rueda una vez más.

En este artículo he mostrado cómo hacer las cosas "normales" de Perl OO con Moose. En este punto, usted sabe cómo hacer uso de la programación orientada a objetos básica y podría comenzar a reemplazar sus enrolladas clases hechas a mano por otras construidas con Moose.

Moose, sin embargo, es más que un poco de sintaxis inteligente y algunos ahorros de tiempo. Moose tiene algunas características adicionales que lo hacen realmente increíble para trabajar con él. Sólo voy a referirme a ellas aquí, ya que requeriría un libro entero para cubrirlas adecuadamente. Algunas de las características disponibles con Moose son las siguientes: 
  • Metadatos de la clase: La posibilidad que tiene su código de examinar la estructura de sus objetos.
  • Coerción: La capacidad de convertir los valores de un tipo a otro cuando sea necesario.
  • Modificadores de métodos: La capacidad de agregar código que se ejecuta antes, después o alrededor de un método existente.
  • Roles: La capacidad de agregar funcionalidad predefinida a las clases sin usar herencia.
Hay muchas otras que vale la pena investigar también. Los roles son especialmente interesantes y proporcionan una flexibilidad que no tiene precedentes en casi cualquier lenguaje orientado a objetos. También digno de mención son las extensiones de Moose que proporcionan una funcionalidad incluso más allá de Moose estándar.

Para obtener más información sobre Moose, eche un vistazo a la documentación. Para ver más en detalle Moose vs Perl OO, eche un vistazo a la versión "sin azúcar" del manual.

También puede consultar la página de inicio de Moose. Por último, he comenzado una lista de "Trampas de Moose" en Catalyzed Wiki para rastrear algunas de las partes más difíciles de Moose que he encontrado. Siéntase libre de agregar las propias, a medida que descubre los placeres de usar Moose.




Con Moose la POO vuela


Moose es un completo sistema de objetos para Perl 5. Defines tu clase en forma declarativa. Está basado en gran parte en el sistema de objetos de Perl 6 tomando las mejores ideas de CLOS, Smalltalk y otros lenguajes.
Crearemos la clase Transporte. Un Colectivo es un medio de Transporte. Entonces en el archivo Colectivo.pm escribimos la clase Colectivo que tiene un número de línea y un color:
  package Colectivo;
  use Moose;
  has 'nombre' => (is => 'rw');
  has 'color' => (is => 'rw');
  1;
Aquí decimos que Colectivo tiene nombre y color, y que son atributos de lectura/escritura. Podemos usar la clase:

  use Colectivo;
  my $rapido = Colectivo->new(nombre => 129);
  print $rapido->nombre; # imprime 129
  $rapido->color("amarillo"); # configura el color

Notar que no se definió el método new, Moose lo hace por nosotros.
Ahora bien, Colectivo hereda de Transporte. Para expresar eso facilmente en Transporte.pm escribimos:

  package Transporte;
  use Moose;
  has 'nombre' => (is => 'rw');
  has 'color' => (is => 'rw');
  1;

Y entonces actualizamos nuestro Colectivo.pm:

  package Colectivo;
  use Moose;
  extends 'Transporte';
  1;

Notar que 'extends' reemplaza el tradicional uso de 'base' y configura el array @ISA.

En este momento, Colectivo y Transporte son identicos. Ellos pueden ser instanciados y tienen sus dos atributos. Lo que distingue a un Colectivo de otros medios de Transporte es su bocina. Nosotros lo agregamos aquí:

  package Colectivo;
  use Moose;
  extends 'Transporte';
  sub bocina { 'tuturururu' }
  1;

y luego hacer referencia a eso en el método común "tocar" de la clase Transporte:

  package Transporte;
  use Moose;
  has 'nombre' => (is => 'rw');
  has 'color' => (is => 'rw');
  sub tocar {
    my $self = shift;
    print $self->nombre, " hace ", $self->bocina, "\n";
  }
  sub bocina { confess shift, " deberia haber definido una bocina!" }
  1;

Notar el uso de "confess", si la clase derivada no tiene definido un método bocina, se quejará. Pero como Colectivo definió su bocina, nunca ejecutará Transporte::bocina(). Ahora puedo crear mi colectivo:

  my $rapido = Colectivo->new(nombre => 129);
  $rapido->tocar; # toca la bocina "tuturururu"

Hasta ahora hemos codificado cosas que sin Moose serian simples de hacer, comenzaremos a complicarnos para ver su verdadero poder. Primero, un Transporte es una clase abstracta que se usa solamente para proveer atributos y métodos comunes a una clase concreta (en este caso, la clase Colectivo). En términos de Moose, esto se describe como un rol. Un rol nunca tiene instancias, porque no es una clase completa.

Cuando convertimos la clase Transporte en un rol obtenemos algo de soporte adicional:

  package Transporte;
  use Moose::Role;
  has 'nombre' => (is => 'rw');
  has 'color' => (is => 'rw');
  sub tocar {
    my $self = shift;
    print $self->nombre, " hace ", $self->bocina, "\n";
  }
  requires 'bocina';
  1;

Notar que reemplazamos el 'confess' por un requires. Esto informa a Moose que este rol debe ser usado con una clase que provea el método 'bocina', lo cual se chequea en tiempo de compilacion. Para el rol, nosotros lo vamos a 'usar' más que 'extenderlo':

  package Colectivo;
  use Moose;
  with 'Transporte';
  sub bocina { 'tuturururu' }
  1;

Si nos faltara incluir 'bocina' obtendríamos una notificación bien temprano. Eso es bueno! En este caso Colectivo trabaja igual que antes.

Qué pasa con 'with' y 'requires'. Debido a que son definidos por Moose y Moose::Role, ellos permanecen como parte del package. Para los puristas que hay en nosotros, no nos gusta este tipo de contaminación, nosotros podemos borrarlos cuando hayamos terminado, usando el correspondiente 'no' (similar al uso de 'strict' y 'no strict'). Por ejemplo, limpiando Colectivo.pm:

  package Colectivo;
  use Moose;
  with 'Animal';
  sub bocina { 'tuturururu' }
  no Moose; # sacando los andamios
  1;

En forma similar, Transporte.pm no requiere Moose::Role al final.

Moose soporta la noción de valor por defecto. Agregaremos un color por defecto y haremos que sea la clase la responsable:

  package Transporte;
  ...
  has 'color' => (is => 'rw', default => sub { shift->default_color });
  requires 'default_color';
  ...

Si el color no es provisto, el color por defecto de la clase será consultado a través del método default_color(), y 'requires' asegura que la clase concreta provea este método. Nuestras clases derivadas de Transporte lucirían así:

  ## Avion.pm:
  package Avion;
  use Moose;
  with 'Transporte';
  sub default_color { 'blanco' }
  sub bocina { 'trom' }
  no Moose;
  1;
  ## Colectivo.pm:
  package Colectivo;
  use Moose;
  with 'Transporte';
  sub default_color { 'amarillo' }
  sub bocina { 'tuturururu' }
  no Moose;
  1;
  ## Bicicleta.pm:
  package Bicicleta;
  use Moose;
  with 'Transporte';
  sub default_color { 'roja' }
  sub bocina { 'tilin' }
  no Moose;
  1;

Ahora tenemos Bicicleta entre nuestras clases implementadas:

  use Bicicleta;
  my $ligera = Bicicleta->new(color => 'azul', nombre => 'Ligera');
  $ligera->tocar; # imprime "Ligera hace tilin"

Bueno, esto fue bastante sencillo. Ahora resolveremos otros problemillas.

La clase Ambulancia es especial, porque cuando toca su bocina los demás transportes deben apartarse del camino. En forma tradicional usaríamos una llamada a SUPER:: para llamar al comportamiento de la clase padre, pero esto no funciona con roles. Los roles no quedan en @ISA, porque son 'pegados' en el lugar en vez de 'encimados'.
Afortunadamente, Moose provee el conveniente 'after' para agregar comportamiento adicional a un método existente. Moose reemplaza el método original conservando el contexto (lista, escalar o void) así como su valor de retorno. Nuestro método 'tocar' para Ambulancia quedaría así:

  package Ambulancia;
  use Moose;
  with 'Transporte';
  sub default_color { 'blanca' }
  sub bocina { 'huuuuuu' }
  after 'tocar' => sub {
    print "Apartense!\n";
  };
  no Moose;
  1;

Esto produce una ambulancia que funciona bien:

  my $ambu = Ambulancia->new(nombre => 'Urgencia');
  $ambu->tocar;

resulta:

  Urgencia hace huuuuuu
  Apartense!

También podemos usar 'before' y 'around' para preceder al comportamiento original o controlar la llamada del comportamiento original, según sea necesario. Por ejemplo, para permitir que 'nombre' sea usado como método de acceso y aún como un método de clase que devuelve un Transporte sin nombre, podemos rodear el 'nombre' con 'around':
  package Transporte;
  ...
  has 'nombre' => (is => 'rw');
  around 'nombre' => sub {
    my $next = shift;
    my $self = shift;
    blessed $self ? $self->$next(@_) : "un $self sin nombre";
  };
El 'has' crea el comportamiento original. El 'around' intercepta la llamada a 'nombre' y toma el coderef como primer parámetro en la variable $next y el original $self como segundo parámetro. Testea $self y si es un objeto llama al original coderef con el resto de los parámetros en @_. Así se obtiene el comportamiento original (un getter o setter) para el objeto, pero si es una clase nos devuelve un string literal.

What if we never gave our animal a nombre? We'll get warnings about undefined values. We can give a default nombre just as we did a default color:
¿Y qué sucede si nunca le damos nombre a nuestro Transporte? Vamos a recibir warnings por valores indefinidos. Podemos dar un 'nombre' por defecto tal como lo hicimos con 'color':
  has 'nombre' => (
    is => 'rw',
    default => sub { 'un '. ref shift .' sin nombre ' },
   );

De nuevo, nos place que 'around' inmediatamente siga este paso.

Si no queremos que la gente cambie el color después de la creación de la instancia inicial, podemos declarar el atributo de sólo lectura:
  has 'color' => (is => 'ro', default => sub { shift->default_color });

Ahora un intento de establecer el color aborta con el mensaje 'Cannot assign a value to a read-only accessor'. Si realmente quisiera tener una manera de establecer el color de vez en cuando, podemos definir un escritor separado:

  has 'color' => (
    is => 'ro',
    writer => 'private_set_color',
    default => sub { shift->default_color },
  );

Por lo tanto, no podemos cambiar el color de una bicileta directamente:

  my $ligera = Bicicleta->new;
  my $color = $ligera->color; # método getter obtiene el color
  $ligera->color('verde'); # MUERE

Sin embargo, podemos utilizar nuestro método privado en su lugar:
  $ligera->private_set_color('verde'); # método setter privado

Mediante el uso de un nombre de largo, hacemos menos probable que accidentalmente lo llamen, a menos que intencionalmente querramos cambiar el color.

Vamos a crear una bicicleta de carreras, BicicletaCarrera, mediante el agregado de características de competición a una bicicleta. En primer lugar definimos las características de competición usando roles, claro:
  package Competidor;
  use Moose::Role;
  has $_ => (is => 'rw', default => 0)
    foreach qw(victorias posicion shows perdidas);
  no Moose::Role;
  1;

Tenga en cuenta que desde que 'has' es solo una llamada a función, podemos utilizar las estructuras tradicionales de control de Perl (en este caso, un bucle foreach). Con un poco de código, hemos añadido otros cuatro atributos.
El valor inicial de 0 significa que no tienes que escribir el código de inicialización independiente en nuestro constructor.
Ahora, podemos añadir algunos métodos de acceso:

  package Competidor;
  ...
  sub gano { my $self = shift; $self->victorias($self->victorias + 1) }
  sub aplazado { my $self = shift; $self->posicion($self->posicion + 1) }
  sub showed { my $self = shift; $self->shows($self->shows + 1) }
  sub perdio { my $self = shift; $self->perdidas($self->perdidas + 1) }

  sub tabla_posiciones {
    my $self = shift;
    join ", ", map { $self->$_ . " $_" } qw(victorias posicion shows perdidas);
  }
  ...

Cada llamada al método 'gano' incrementa el número de victorias. Esto sería más sencillo si se presume que estos objetos se implementan como hashes (que lo son por defecto), como:

  sub gano { shift->{victorias}++; }

Sin embargo, mediante el uso de la interfaz pública (una llamada de método), podríamos cambiar la posterior implementación de adentro hacia afuera del objeto usando arreglos sin romper este código. Esto es especialmente importante cuando se crea un rol genérico, que podría mezclarse con cualquier tipo de objeto.

Para crear la bicicleta de carreras, mezlcamos una Bicicleta con un Competidor:

  package BicicletaCarrera;
  use Moose;
  extends 'Bicicleta';
  with 'Competidor';
  no Moose;
  1;

Y ahora podemos montar las bicicletas!:

  use BicicletaCarrera;
  my $bici = BicicletaCarrera->new(nombre => 'ligera');
  $bici->gano; $bici->gano; $bici->gano;
  $bici->aplazado;
  $bici->perdio; # corremos algunas carreras
  print $bici->tabla_posiciones, "\n";
  # 3 ganadas, 1 aplazada, 0 shows, 1 perdida

Hasta ahora, sólo he arañado la superficie de lo que ofrece Moose. Ahora a codificar y ganar experiencia!

viernes, 9 de marzo de 2012

Hoja de estilos de colores Web2.0

/*colores intensos*/
.Mozilla-Rojo{
 color: #FF1A00
}
.Rollyo-Rojo{
 color: #CC0000
}
.RSS-Naranja{
 color: #FF7400
}
.Techcrunch-Verde{
 color: #008C00
}
.Newsvine-Verde{
 color: #006E2E
}
.Flock-Azul{
 color: #4096EE
}
.Flickr-Rosa{
 color: #FF0084
}

/*colores oscuros*/
.Ruby-Rojo{
 color: #B02B2C
}
.Etsy-Vermellon{
 color: #D15600
}
.Things-Oro{
 color: #C79810
}
.Writely-Oliva{
 color: #73880A
}
.Basecamp-Verde{
 color: #6BBA70
}
.Mozilla-Azul{
 color: #3F4C6B
}
.Digg-Azul{
 color: #356AA0
}
.Last-Rosa{
 color: #D01F3C
}

/*colores suaves*/
.Shiny-Plata{
 color: #EEEEEE
}
.Reddit-Blanco{
 color: #FFFFFF
}
.Magnolia-Rosa{
 color: #F9F7ED
}
.Pikachu-Amarillo{
 color: #FFFF88
}
.Qoop-Verde{
 color: #CDEB8B
}
.Gmail-Azul{
 color: #C3D9FF
}
.Shadows-Gris{
 color: #36393D
}