domingo, 28 de septiembre de 2014

Perl: POO con Moose, Herencia

Herencia con Moose

Uso de herencia en Programación Orientada a Objetos con Perl Moose (perl 5).


1) Herencia simple (INHERITANCE)

#This is perl 5, version 14, subversion 2 (v5.14.2)
#File: Person.pm
package Person; #Super-Class: Es la super-clase

    use Moose;
    use strict; #Obliga a la programación segura y definición de variables
    use warnings; #Ayudará a encontrar errores de sintaxis
    use namespace::autoclean;

    has 'name' => (
                is         => 'rw',
  isa        => 'Str',
                reader => 'getName',
                writer => 'setName',
    );

no Moose;
__PACKAGE__->meta->make_immutable; #no voy a cambiar mi clase
1;

#File: Developer.pm
package Developer;

    use Moose;
    use strict; #Obliga a la programación segura y definición de variables
    use warnings; #Ayudará a encontrar errores de sintaxis
    use namespace::autoclean;

    extends 'Person'; #SUBCLASSING, hereda de Person

    has 'skill' => (
                is         => 'rw',
               isa        => 'Str',
                reader => 'getSkill',
                writer => 'setSkill',
    );
 
no Moose;
__PACKAGE__->meta->make_immutable; #no voy a cambiar mi clase
1;

#.............................................................................................................................
#File: script_subclassing.pl
#!/usr/bin/perl
use strict;
use warnings;
use Moose;
use Developer; #Nuestra clase

my $instancia = Developer->new(name=>'Daro',skill=>'Perl developer');
print "Nombre: " . $instancia->getName() . "\n"; #return 'Daro'
print "Skill: " . $instancia->getSkill() . "\n"; #return 'Perl developer'
#..........................................................................................................................end


2) Herencia Múltiple (multiple inheritance)


#File: WriterMonkey.pm
package WriterMonkey;

    use Moose;
    use strict;
    use warnings;
    use namespace::autoclean;
 
    has 'keyBySeconds' => (
                is         => 'rw',
  isa        => 'Int',
                reader => 'getKeyBySeconds',
                writer => 'setKeyBySeconds',
    );

    sub writerCode {
        my ( $self ) = @_;
        print "Coding...     \n";
    }
 
no Moose;
__PACKAGE__->meta->make_immutable;
1;

#File: Developer.pm
package Developer;

    use Moose;
    use strict; #Obliga a la programación segura y definición de variables
    use warnings; #Ayudará a encontrar errores de sintaxis
    use namespace::autoclean;
 
    extends 'Person', 'WriterMonkey'; #multiple inheritance

    has 'skill' => (
                is         => 'rw',
  isa        => 'Str',
                reader => 'getSkill',
                writer => 'setSkill',
    );
 
no Moose;
__PACKAGE__->meta->make_immutable;
1;

#.........................................................................................................
#File: script_multiple_inheritance.pl
#!/usr/bin/perl
use strict;
use warnings;
use Moose;
use Developer; #Nuestra clase

my $instancia = Developer->new(name=>'Daro',skill=>'Perl developer', keyBySeconds=>60);
print "Nombre: " . $instancia->getName() . "\n"; #return 'Daro'
print "Skill: " . $instancia->getSkill() . "\n"; #return 'Perl developer'
$instancia->writerCode(); #print 'Coding...'
#..........................................................................................................................end

3) Clases Abstractas o Interfaces con métodos abstractos


Hay que tener en cuenta que ni Perl ni Moose ofrecen clases abstractas. Con Moose se puede definir una clase "interfaz única" con role (Moose::Role), que contiene solo una lista de los métodos requeridos (requires). Cualquier clase que consuma este role debe implementar todos los métodos necesarios, ya sea directamente o a través de la herencia. No se puede retrasar la implementación de los métodos requeridos para que puedan ser implementadas por subclases futuras.

#File: Printable.pm
package Printable; #Clase Interface/Abstracta
    use strict;
    use warnings;
    use Moose::Role;

    requires 'doPrint', 'doPrint2'; #Métodos abstractos
    #requires must be implemented by a subclass or consumer class

no Moose;
1;

#File: Paper.pm
package Paper;
    use Moose;

    with 'Printable'; #Implement la clase Printable

    has 'text' => (
  isa        => 'Str', #Tipo String
                reader => 'getText',
                writer => 'setText'
    );

    sub doPrint {
        my ( $self ) = @_;
        print "Doing 1 ... " . $self->getText() . "    \n";
    };

    sub doPrint2 {
        my ( $self ) = @_;
        print "Doing 2 ... " . $self->getText() . "    \n";
    };
    
    
no Moose;
1;

#File: script_test_interface.pl
#!/usr/bin/perl
use strict;
use warnings;
use Moose;
use Paper; #Nuestra clase que implementa la interface Printable

my $instancia = Paper->new(text=>'texto a immprimir.');
$instancia->doPrint();
$instancia->doPrint2();



Referencias:
-Blog: Getting Started with Moose.
-Moose::Manual::Classes.
-Roles_Versus_Abstract_Base_Classes.
-Moose Manual.



Perl: POO con Moose, Estructura de datos

Estructura de datos con Moose

Las clases en Moose (con perl 5) pueden tener estructuras de datos como atributos usando Types en la definición del isa.

1) Clase con Atributos Hash

#This is perl 5, version 14, subversion 2 (v5.14.2)
#File: MyHash.pm
package MyHash;

    use Moose;
    use strict;
    use warnings;
    use namespace::autoclean;

    has 'myHashRef' => (
is => 'rw',
isa => 'HashRef',
reader  => 'getMyHashRef',
writer  => 'setMyHashRef',
default => sub {
return {
'0' => "first",
'1' => "second"
}
                                    }
                     );

    sub printOptions {
        my ( $self ) = @_;
        my $str = $self->getMyHashRef->{'0'};
        $str .= "\n";
        $str .= $self->getMyHashRef->{'1'};
        $str .= "\n";
        print $str;
    }

no Moose;
__PACKAGE__->meta->make_immutable;
1;

#................................................................................................
#File: script_test_MyHash.pl
#!/usr/bin/perl
use strict;
use warnings;
use MyHash;

my $instancia = MyHash->new();
$instancia->printOptions();
$instancia->setMyHashRef({'0' => "primero", '1' => "segundo"});
$instancia->printOptions();
#.............................................................................................end



Referencias:
-Types in Moose.
-Attribute Native.


jueves, 25 de septiembre de 2014

Perl: POO con Moose, Básico

Programación Orientada a Objetos en Perl con Moose

Para programar OO con Perl se puede usar la vieja escuela con perlobj (mediante un mecanismo conocido como bendición) o usar algo más moderno como uno de los sistemas de POO para Perl: Moose, Moo (Minimalist Object Orientation Moose compatible), Class::Accessor, Class::Tiny, Role::Tiny o Perl 6 OO (en el futuro). Aquí vamos a usar MooseMoose es un "postmodern object system for Perl 5" que hace más amigable la POO que la vieja escuela de perlobj.  En la vieja escuela era necesario crear el método new de las clases, en cambio con Moose no es necesario porque las clases heredan de Moose::Object quien ya implementa el new. O sea que prescindimos de la creación de constructores new.


Instalar Moose



Se debe por lo menos tener instalado Perl 5.8, pero es preferible 5.10 o 5.12. Moose se instala fácilmente con CPAN:

cpan Moose
#o se puede usar: sudo perl -MCPAN -e 'install Moose'
#o también: sudo apt-get install libmoose-perl

Ejemplos de Clases Moose:


1) Una Clase con Atributo String


#File: NameStr.pm
package NameStr;

    use Moose;
    use strict; #Obliga a la programación segura y definición de variables
    use warnings; #Ayudará a encontrar errores de sintaxis
    use namespace::autoclean;

    has 'name' => (
                is         => 'rw', #Lectura-Escritura. También se puede usar 'ro' = read-only
  isa        => 'Str', #Tipo String (es obligatorio el valor string)
    );

    sub myNameIs
    {
        my $self = shift;
        my $myname = $self->name();
        print "My name: $myname \n";
    }


no Moose;
__PACKAGE__->meta->make_immutable; #no voy a cambiar mi clase
1; # Don't forget "1;" at end to return a true value from the file.
=pod
Nota 1: el  "isa  => 'Str'" hace que sea obligatorio que cuando se setea el valor el mismo sea string. Si se quiere que acepte un Undef lo que se debe poner es "isa => 'Maybe[Str]'".
Nota 2: Poner make_immutable junto con autoclean es una buena práctica Moose.
=cut

#...........................................................
#File: script_NameStr.pl
#!/usr/bin/perl
use strict;
use warnings;
use Moose;
use NameStr; #Nuestra clase

my $instancia = NameStr->new();
$instancia->name('Daro');
$instancia->myNameIs();
#......................................................End

2) Una Clase con Atributo String y getter-setter

#Se puede usar getter and setter estilo Java

#File: NameStr.pm
package NameStr;

    use Moose;
    use strict; #Obliga a la programación segura y definición de variables
    use warnings; #Ayudará a encontrar errores de sintaxis
    use namespace::autoclean;

    has 'name' => (
                is         => 'rw', #Lectura-Escritura
  isa        => 'Str', #Tipo String
                reader => 'getName', #getter
                writer => 'setName', #setter
    );

    sub myNameIs
    {
        my $self = shift;
        my $myname = $self->getName(); #getter
        print "My name: $myname \n";
    }


no Moose;
__PACKAGE__->meta->make_immutable; #no voy a cambiar mi clase
1;

#...........................................................
#File: script_NameStr.pl
#!/usr/bin/perl
use strict;
use warnings;
use Moose;
use NameStr; #Nuestra clase

my $instancia = NameStr->new();
$instancia->setName('Daro'); #setter
$instancia->myNameIs();
#......................................................End

3) Una clase con atributo Integer


#File: AgeInt.pm
package AgeInt;

    use Moose;
    use strict; #Obliga a la programación segura y definición de variables
    use warnings; #Ayudará a encontrar errores de sintaxis
    use namespace::autoclean;

    has 'age' => (
                is         => 'rw', #Lectura-Escritura
  isa        => 'Int', #Tipo Integer
                default =>  37            
    );


no Moose;
__PACKAGE__->meta->make_immutable; #no voy a cambiar mi clase
1;

#...........................................................
#File: script_AgeInt.pl
#!/usr/bin/perl
use strict;
use warnings;
use Moose;
use AgeInt;  #Nuestra clase

my $instancia = AgeInt->new();
print $instancia->age() . "\n";
$instancia->age(19);
print $instancia->age() . "\n";
#......................................................End

4) Propiedades de atributos


#File: NameStrAtr.pm
package NameStrAtr;

    use Moose;
    use strict; #Obliga a la programación segura y definición de variables
    use warnings; #Ayudará a encontrar errores de sintaxis
    use namespace::autoclean;

    has 'name' => (
                is         => 'rw', #Lectura/Escritura
  isa        => 'Str', #Tipo String
                reader => 'getName',
                writer => 'setName',
                required => 1, #Es requerido y no permite el valor 'undef'
                clearer   => 'clearName', #permite limpiar el valor, provoca que hasName devuelva false
                predicate => 'hasName', #devuelve true si tiene un valor
                lazy    => 1, #no se inicializa hasta que se llama al método lector
                default => '',
                init_arg => 'elNombre' #Nombre con el cual se referencia desde el constructor
    );

no Moose;
__PACKAGE__->meta->make_immutable; #no voy a cambiar mi clase
1;

#.............................................................................................................
#File: script_NameStrAtr.pl
#!/usr/bin/perl
use strict;
use warnings;
use Moose;
use NameStrAtr; #Nuestra clase

my $instancia = NameStrAtr->new(elNombre=>'Daro'); #required
print "Nombre: " . $instancia->getName() . "\n"; #return 'Daro'
$instancia->setName('Daro Andres');
print "Nombre: " . $instancia->getName() . "\n"; #return 'Daro Andres'
print "Has value?: " . $instancia->hasName() . "\n"; #return 1 (true)
$instancia->clearName(); #Limpia el valor
print "Has value?: " . $instancia->hasName() . "\n"; #return (false)
#........................................................................................................End

5) Inicializadores de atributos con Builder   


#File: NameStrBuilt.pm
package NameStrBuilt;

    use Moose;
    use strict; #Obliga a la programación segura y definición de variables
    use warnings; #Ayudará a encontrar errores de sintaxis
    use namespace::autoclean;

    has 'name' => (
                is         => 'rw', #Lectura/Escritura
  isa        => 'Str', #Tipo String
                reader => 'getName',
                writer => 'setName',
                builder   => 'buildName'

    );

    #Constructor inicializador del atributo name
    sub buildName {
        my $self = shift;
        $self->setName('Built Name (Nombre construido)'); #Inicializa
    }

no Moose;
__PACKAGE__->meta->make_immutable; #no voy a cambiar mi clase
1;

#.............................................................................................................
#File: script_NameStr.pl
#!/usr/bin/perl
use strict;
use warnings;
use Moose;
use NameStrBuilt; #Nuestra clase

my $instancia = NameStrBuilt->new();
print "Nombre: " . $instancia->getName() . "\n"; #return 'Built Name (Nombre construido)'
#........................................................................................................End

6) Disparadores trigger en atributos

Un disparador es una función que es llamada cada vez que se cambia el atributo.

#File: NameStrTrigged .pm
package NameStrTrigged;

    use Moose;
    use strict; #Obliga a la programación segura y definición de variables
    use warnings; #Ayudará a encontrar errores de sintaxis
    use namespace::autoclean;

    has 'name' => (
                is         => 'rw', #Lectura/Escritura
  isa        => 'Str', #Tipo String
                reader => 'getName',
                writer => 'setName',
                trigger => \&triggerForSetName, #referencia a la función que se va a disparar cuando se setea el valor

    );

    #El trigger se dispara despues que se setea el atributo
    sub triggerForSetName {
        my ( $self, $name, $old_name ) = @_;
        if ($old_name){
            print "Trigger executed... new: ".$name." old: ".$old_name."\n";
        }
    }
 
no Moose;
__PACKAGE__->meta->make_immutable; #no voy a cambiar mi clase
1;

#.............................................................................................................
#File: script_NameStr.pl
#!/usr/bin/perl
use strict;
use warnings;
use Moose;
use NameStrTrigged; #Nuestra clase

my $instancia = NameStrTrigged->new(name=>'Nombre inicial');
print "Nombre: " . $instancia->getName() . "\n"; #return 'Built Name (Nombre construido)'
$instancia->setName('Segundo nombre');
print "Nombre: " . $instancia->getName() . "\n"; #return 'Built Name (Nombre construido)'
=pod
Se imprime en pantalla:
Nombre: Nombre inicial
Trigger executed... new: Segundo nombre old: Nombre inicial
Nombre: Segundo nombre
Presione una tecla para continuar . . .
=cut
#........................................................................................................End


Bueno, así vimos un resumen general del uso de clases con Moose.


Referencias:
http://en.wikibooks.org/wiki/Programming_with_Moose
https://dl.dropboxusercontent.com/u/45670449/Moose_Manual.pdf
http://modernperlbooks.com/books/modern_perl/chapter_07.html
https://www.perl.org/about/whitepapers/perl-object-oriented.html
https://metacpan.org/pod/Moose::Manual
http://perlmaven.com/object-oriented-perl-using-moose
https://metacpan.org/pod/Moo
http://perldoc.perl.org/perlootut.html#Role%3a%3aTiny