Ejemplo: el Módulo Number::Fraction

El módulo Number::Fraction permite la sobrecarga de constantes. Véase un ejemplo:

lhp@nereida:~/Lperl/src$ cat -n fractions.pl
 1  #!/usr/bin/perl
 2  use warnings;
 3  use strict;
 4  use Number::Fraction ':constants';
 5
 6  no warnings 'numeric';
 7  my $trescuartos = '1/2'+'1/4';
 8  print "$trescuartos\n";
 9
10  my $x = '1hola'+2;
11  print "$x\n";
12
13  no Number::Fraction;
14  $trescuartos = '1/2'+'1/4';
15  print "$trescuartos\n";
La salida de este programa es:
$ ./fractions.pl
3/4
3
2
La transformación de las constantes ocurre en tiempo de compilación como muestran las siguientes ejecuciones con B::Terse6.1

$ perl -MO=Terse,-exec \
       -MNumber::Fraction=':constants' \
       -e '$x = "1/2"'
OP (0x81ce758) enter
COP (0x824c708) nextstate
SVOP (0x8290460) const [2] RV (0x8298d88) \HASH
PADOP (0x824c308) gvsv  GV (0x814f648) *x
BINOP (0x8235818) sassign
LISTOP (0x8235048) leave [1]
-e syntax OK
$ perl -MO=Terse,-exec -e '$x = "1/2"'
OP (0x81570b8) enter
COP (0x816c5a0) nextstate
SVOP (0x81571a8) const [2] PV (0x814f5dc) "1/2"
PADOP (0x816c740) gvsv  GV (0x814f660) *x
BINOP (0x816c880) sassign
LISTOP (0x816c708) leave [1]
-e syntax OK

Esta sobrecarga se consigue definiendo import en la línea 22 del listado que sigue a continuación, para que llame a overload::constant sobre el hash %_const_handlers.

En este caso el hash tiene una única clave, ya que sólo estamos interesados en tratar las constantes de tipo cadena. El constructor new será especificado en la sección 6.9.5: Cuando recibe la cadena produce el objeto Number::Fraction.

 1 package Number::Fraction;
 2 
 3 use 5.006;
 4 use strict;
 5 use warnings;
 6 use Carp;
 7 
 8 our $VERSION = sprintf "%d.%02d", '$Revision: 1.34 $ ' =~ /(\d+)\.(\d+)/;
 9 
10 use overload
11   q("") => 'to_string',
12   '0+' => 'to_num',
13   '+' => 'add',
14   '*' => 'mult',
15   '-' => 'subtract',
16   '/' => 'div',
17   fallback => 1;
18 
19 my %_const_handlers =
20   (q => sub { return __PACKAGE__->new($_[0]) || $_[1] });
21 
22 sub import {
23   overload::constant %_const_handlers if $_[1] and $_[1] eq ':constants';
24 }

El import proveído hace que, en el caso de que el constructor no devuelva un objeto válido, se devuelva el segundo argumento, que es el valor que Perl le da por defecto a la constante. El resultado es la conversión correcta de aquellas cadenas que pueden ser interpretadas como fracciones y que otras cadenas como '1hola' sean interpretadas de acuerdo a las tradiciones de Perl.

Nótese la condición para la importación en la línea 23: if $_[1] and $_[1] eq ':constants'. Esto significa que para activar el manejador de constantes de tipo cadena el programa cliente ha de declarar:

use Number::Fraction ':constants';

esto es una buena idea: cambiar el modo en que funcionan las constantes es un cambio lo suficientemente trascendental como para sólo hacerlo bajo petición explícita del usuario.

Seguimos:

26 sub unimport {
27   overload::remove_constant(q => undef);
28 }
29 
30 sub new {
31  ...
32 }

Recuerde que la función unimport se ejecutará cuando el usuario haga una llamada en su programa a no Number::Fraction. En este caso la negación produce el abandono del manejo de las constantes.

Casiano Rodríguez León
Licencia de Creative Commons
Principios de Programación Imperativa, Funcional y Orientada a Objetos Una Introducción en Perl/Una Introducción a Perl
por Casiano Rodríguez León is licensed under a Creative Commons Reconocimiento 3.0 Unported License.

Permissions beyond the scope of this license may be available at http://campusvirtual.ull.es/ocw/course/view.php?id=43.
2012-06-19