domingo, 25 de mayo de 2014

Cómo sacar algunos sigils ($@%&), parte 2

Buenas! En la entrada anterior habíamos llegado a poder escribir una variable sin sigil, así:


boo = "Cuidado!!";
print boo . ", te vas  a caer de las escaleras!\n";

(estas "variables" en realidad son subrutinas, pero nadie tiene porqué saberlo :D Vamos a llamarlas variables igual, o a lo sumo "nuestras variables especiales", porque les tenemos mucho cariño).

Hay que declarar cada una de las variables como una subrutina. Un montón de copiar y pegar de código, repetido y dificil de mantener. Y ¡ay! si tenés que hacer algún cambio.

¿Se puede hacer más dinámico? No perfectamente como yo hubiera querido, pero zafa bastante bien.

Necesitamos primero definir cada variable con "var". Var no es más que una subrutina, que va a generar nuestra "variable especial".
var "espia";
var "amante_de_espia";
y luego podemos usarlas:
espia = "James Bond";
amante_de_espia = "Mariam D'Abo";
say "Mi nombre es " . espia ", y me acuesto con " . amante_de_espia;
Ningún sigil. ¡Genial!  ¿Cómo se hace? Es medio complicado, pero acá va:

"espia" y "amante_de_espia" son en realidad funciones (lo vimos en la primera parte), asi que "var" tiene que crearlas al vuelo. Para eso tiene que ponerlas en el mismo namespace, osea, al mismo nivel que el programa principal.
sub var ($) {
        my $p = "main";
        no strict 'refs';
        *{"${p}::${_[0]}"} = sub (;$) :lvalue {
                state $internal = "**internal**";
                if ( $_[0] ) { $internal = $_[0]; }
                return $internal;
        };
        use strict;
}
La parte horrible de esto, como se ve, es la cuarta linea.
*{"${p}::${_[0]}"}
$p es "main" (linea 2) y ${_[0]} es $_[0] escrito minuciosamente. Sí escribimos: var "espia", $_[0] es "espia". Osea, que queda:
*main::espia
Que quiere decir que vamos a manejar el nombre "espia", en el namespace "main", exactamente donde nuestro programa lo va a ir a buscar.. Vamos bien.

La línea completa es así:
*main::espia = sub (;$) :lvalue {
Que dice que nuestro nombre "espía" va a ser una función, igual que la que que vimos en la entrada anterior. Ese es todo el truco para insertarla en el espacio de nombres correcto.

Lo último que hace falta, que arruina un poco las cosas, es que el compilador, cuando revisa todo el script, encuentra que 'espia = "James Bond"' no es nada: no es una variable porque no tiene sigil, y no es una función, porque todavía no se ejecutó lo de arriba que hace que exista. Lo mejor que puede encontrar es que pongamos la definición en un bloque BEGIN:

 BEGIN { var "espia"; }
De esa manera, perl lo ejecuta primero, creando nuestras variables especiales para cuando las vaya a ejecutar. Y ¡ojo! También puede ser un buen lugar para declarar varias variables así:
BEGIN {
        var "espia";
        var "jefe";
        var "familia_que_ignora_la_verdad";
}

Creo que voy a hacer una tercera parte. Quedaron ideas :)

Saludos!
 -- Diego.





Cómo sacar algunos sigils ($@%&), parte 1

Estuve jugando a sacarle los sigils (los símbolos que indican si las variables son strings, listas o hashes (diccionarios en python))

Lo primero que podemos hacer es definir de antemano una función con un prototipo ";$", que quiere decir que la función recibe como argumento un escalar, opcionalmente. Osea, que se puede ejecutar "boo" o "boo($persona)".
#!/usr/bin/perl
use strict;
use warnings;

sub boo(;$) {
     print "Boo!";
}
Luego, para ejecutarlo, solo tenemos que llamar a la función, sin siquiera paréntesis:
#!/usr/bin/perl
use strict;
use warnings;

sub boo(;$) {
     print "Boo!";
}
boo;
Y eso nos imprime por pantalla "Boo!", como se espera.  Hagamos una mejora: si uno le da un argumento a "boo", entonces que lo guarde; si no, que lo devuelva.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;

sub boo(;$) {
        state $susto = "Default Boo";
        if ( $_[0] ) { $susto = $_[0]; }
        return $susto;
}

say "En la oscuridad, llego a la esquina y... " . boo . "!";
boo "Cuidado";
say "En la oscuridad, llego a la esquina y... " . boo . "!";
Ahora tiene un poco más de pinta de variable sin sigil. Pero ¡pidamos más! ¿Podremos asignar un valor a "boo" con un igual, como en (casi) cualquier lenguaje de programación? Por supuesto! Si le ponemos el atributo "lvalue" a boo.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;

sub boo(;$) :lvalue {
        state $susto = "Default Boo";
        if ( $_[0] ) { $susto = $_[0]; }
        return $susto;
}

say "En la oscuridad, llego a la esquina y... " . boo . "!";
boo "Cuidado";
say "En la oscuridad, llego a la esquina y... " . boo . "!";
boo = "AAAAAAAAAAH!";
say "En la oscuridad, llego a la esquina y... " . boo . "!";


Sigo con un intento, por ahora fallido, de hacer esto aún más general, en la segunda parte.

 -- Diego.

domingo, 17 de marzo de 2013

Text::Fuzzy

Acá hay un mini ejemplo de cómo usar Text::Fuzzy:
#!/usr/bin/env perl
use v5.16;
use warnings;
use Text::Fuzzy;

my $tf = Text::Fuzzy->new("latitude");
say "Levenshtein edit distance is ", $tf->distance("altitude");
$tf->transpositions_ok(1);
say "Damerau-Levenshtein edit distance is ", $tf->distance("altitude");

martes, 9 de octubre de 2012

Tutorial de PDL::Graphics::Gnuplot

Me encontré con un video de youtube donde explican cómo usar PDL::Graphics::Gnuplot. Interesante!! 15 minutos.

domingo, 23 de septiembre de 2012

Creciendo con Mojolicious

Una vez que nuestro proyecto con Mojolicious va creciendo, esto de tenerlo en un solo archivo se vuelve incómodo. Para separar los templates del código, ejecutamos:
./myapp inflate
Esto creará un directorio "templates" y pondrá los templates en el lugar indicado. A partir de ahí se pueden seguir agregando templates y haciéndo referencia a ellos como siempre:
$self->render('login');

viernes, 10 de agosto de 2012

Como instalar perl+mojolicious sin root

Quiero empezar un proyecto nuevo, y quiero que el proyecto viva completamente en un directorio. Asi, cuando quiera ponerlo en producción, puedo copiar todo el directorio y listo. Vamos a ver si podemos hacer eso ( o terminaré con algo tipo PAR o FatApp ) pero el primer paso es instalar un nuevo perl y un nuevo Mojolicious en mi $HOME. NOTA: Todos estos pasos se van a hacer como usuario, NO como root. Primero instalaremos perlbrew:
curl -kL http://install.perlbrew.pl | bash
Luego editarmos el archivo .bashrc y agregamos lo siguiente:
source ~/perl5/perlbrew/etc/bashrc
Salimos de la sesión y volvemos a entrar, o ejecutamos "bash" para que se apliquen los cambios. Instamos la última versión de perl
perlbrew install perl-5.16.0
La ponemos como default
perlbrew switch perl-5.16.0
Opcionalmente podemos instalar cpanm, que es una versión menos verborrágica de cpan. Si no lo instalamos, cambiar cpanm por cpan en todo este tutorial
cpan App::cpanminus
Y ahora, instalar Mojolicious
cpanm Mojolicious