<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">2016-11-28 11:58 GMT+01:00 Joaquin Ferrero <span dir="ltr"><<a href="mailto:explorer@joaquinferrero.com" target="_blank">explorer@joaquinferrero.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">    Buenos días.<br>
<br>
    En la charla que nos dio dayer, vimos cómo seleccionar un comportamiento u otro según el S.O. en donde nos encontremos. Incluido la carga de módulos distintos para Linux/Windows.<br>
<br>
    Comenté que había visto en CPAN diversas opciones para hacer eso mismo, sobre todo evitar tener que repetir el código<br>
<br>
if ($^O eq 'Win32') {<br>
<br>
    una y otra vez. La idea es tener una API común, y luego cada módulo, tendrá su interfaz propia de cada S.O.<br>
<br>
<br>
He encontrado varios ejemplos, y todos ellos muestran formas muy distintas de solventar la cuestión. Al final del mensaje pongo un listado con las líneas interesantes.<br>
<br>
<br>
Aquí explicaré la solución de Audio::Beep <<a href="https://metacpan.org/release/Audio-Beep" rel="noreferrer" target="_blank">https://metacpan.org/release/<wbr>Audio-Beep</a>>, que me parece el más corto y claro donde se puede ver esta técnica.<br>
<br>
<br>
En Beep.pm, dentro de new(), hay una línea que busca por el mejor reproductor que exista en nuestro sistema:<br>
<br>
        $h{player} =  _best_player();<br>
<br>
<br>
Dentro de _best_player() vemos cómo cargar el módulo correspondiente a nuestro S.O.:<br>
<br>
|sub| |_best_player {|<br>
|||my| |%os_modules| |= (|<br>
|||linux| |=> [|<br>
|||'Audio::Beep::Linux::beep'|<wbr>|,|<br>
|||'Audio::Beep::Linux::PP'||,<wbr>|<br>
|||],|<br>
|||MSWin32| |=> [|<br>
|||'Audio::Beep::Win32::API'||<wbr>,|<br>
|||],|<br>
|||freebsd| |=> [|<br>
|||'Audio::Beep::BSD::beep'||,<wbr>|<br>
|||],|<br>
|||);|<br>
||<br>
|||for| |my| |$mod| |( @{ ||$os_modules||{$^O} } ) {|<br>
|||if| |(||eval| |"require $mod"||) {|<br>
|||my| |$player| |= ||$mod||->new();|<br>
|||return| |$player| |if| |defined| |$player||;|<br>
|||}|<br>
|||}|<br>
|||return||;|<br>
|}|<br>
<br>
   Primero carga un hash con todos los módulos de la distribución.<br>
<br>
   Luego, en el bucle for(), extrae los módulos correspondientes al<br>
   S.O. en que se está ejecutando.<br>
<br>
   Hace un eval "requiere ...", y regresa si la inicialización ha sido<br>
   correcta.<br>
<br>
Y dentro de los módulos Audio::Beep::Linux::beep, Audio::Beep::Linux::PP, Audio::Beep::Win32::API y Audio::Beep::BSD::beep, lo único que hay son tres funciones básicas:<br>
<br>
   new(), para la inicialización,<br>
   play(), para tocar una nota, y<br>
   rest(), para hacer una pausa<br>
<br>
El programa principal solo tiene que hacer llamadas basadas en esa API:<br>
<br>
$self->player->play( _pitch(\%p), _duration(\%p) );<br>
<br>
<br>
<br>
Resto de distribuciones que he encontrado extrayendo las líneas interesantes:<br>
<br>
Net::Routing <<a href="https://metacpan.org/release/Net-Routing" rel="noreferrer" target="_blank">https://metacpan.org/release/<wbr>Net-Routing</a>> - manage route entries on Operating Systems<br>
<br>
   BEGIN {<br>
       if ($^O eq 'linux') {<br>
          return $_routing_module = "Net::Routing::Linux";<br>
       }<br>
       elsif ($^O eq 'freebsd') {<br>
          return $_routing_module = "Net::Routing::FreeBSD";<br>
       }<br>
       elsif ($^O eq 'netbsd') {<br>
          return $_routing_module = "Net::Routing::NetBSD";<br>
       }<br>
       elsif ($^O eq 'darwin') {<br>
          return $_routing_module = "Net::Routing::Darwin";<br>
       }<br>
       #elsif ($^O eq 'MSWin32') {<br>
       #   return $_routing_module = "Net::Routing::MSWin32";<br>
       #}<br>
       #elsif ($^O eq 'openbsd') {<br>
       #   return $_routing_module = "Net::Routing::OpenBSD";<br>
       #}<br>
            die("[-] Net::Routing: Operating System not supported: $^O\n");<br>
   }<br>
        sub new {<br>
       my $self = shift->SUPER::new(<br>
          path => [ qw(/bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin) ],<br>
          lc_all => 'en_GB.UTF-8',<br>
          target => NR_TARGET_ALL(),<br>
          family => NR_FAMILY_INET4(),<br>
          @_,<br>
       );<br>
            $self->path([ @{$self->path}, split(':', $ENV{PATH}) ]);<br>
            eval("use $_routing_module;");<br>
       if ($@) {<br>
          chomp($@);<br>
          $Error = "unable to load routing module [$_routing_module]: $@";<br>
          return;<br>
       }<br>
<br>
Sys::Ramdisk <<a href="https://metacpan.org/release/Sys-Ramdisk" rel="noreferrer" target="_blank">https://metacpan.org/release/<wbr>Sys-Ramdisk</a>> - Create and nuke RAM disks on various systems<br>
<br>
Unix::Uptime <<a href="https://metacpan.org/release/Unix-Uptime" rel="noreferrer" target="_blank">https://metacpan.org/release/<wbr>Unix-Uptime</a>> - Determine the current uptime, in seconds, and load averages, across different *NIX architectures<br>
<br>
   my $module = $modules{$^O}<br>
        or die "Operating system type $^O is currently unsupported";<br>
        require "Unix/Uptime/$<a href="http://module.pm" rel="noreferrer" target="_blank">module.pm</a>";<br>
   our @ISA = ("Unix::Uptime::$module");<br>
<br>
IO::Async <<a href="https://metacpan.org/release/IO-Async" rel="noreferrer" target="_blank">https://metacpan.org/release/<wbr>IO-Async</a>> - Asynchronous event-driven programming<br>
<br>
   if( eval { require "IO/Async/OS/$^O.pm" } ) {<br>
       @ISA = "IO::Async::OS::$^O";<br>
   }<br>
<br>
System::Info <<a href="https://metacpan.org/release/System-Info" rel="noreferrer" target="_blank">https://metacpan.org/release/<wbr>System-Info</a>> - Factory for system specific information objects<br>
<br>
   sub new {<br>
        my $factory = shift;<br>
             $^O =~ m/aix/i               and return System::Info::AIX->new;<br>
        $^O =~ m/bsd/i               and return System::Info::BSD->new;<br>
        $^O =~ m/cygwin/i            and return System::Info::Cygwin->new;<br>
        $^O =~ m/darwin/i            and return System::Info::Darwin->new;<br>
        $^O =~ m/haiku/              and return System::Info::Haiku->new;<br>
        $^O =~ m/hp-?ux/i            and return System::Info::HPUX->new;<br>
        $^O =~ m/irix/i              and return System::Info::Irix->new;<br>
        $^O =~ m/linux/i             and return System::Info::Linux->new;<br>
        $^O =~ m/solaris|sunos|osf/i and return System::Info::Solaris->new;<br>
        $^O =~ m/VMS/                and return System::Info::VMS->new;<br>
        $^O =~ m/mswin32|windows/i   and return System::Info::Windows->new;<br>
             return System::Info::Generic->new;<br>
        }<br>
<br>
App::Slaughter <<a href="https://metacpan.org/release/App-Slaughter" rel="noreferrer" target="_blank">https://metacpan.org/release/<wbr>App-Slaughter</a>> - Perl Automation Tool Helper<br>
<br>
Parse::Netstat <<a href="https://metacpan.org/release/Parse-Netstat" rel="noreferrer" target="_blank">https://metacpan.org/release/<wbr>Parse-Netstat</a>> - Parse the output of "netstat" command<br>
<br>
        if ($flavor eq 'linux') {<br>
            require Parse::Netstat::linux;<br>
            Parse::Netstat::linux::parse_n<wbr>etstat(<br>
                output=>$output, tcp=>$tcp, udp=>$udp, unix=>$unix);<br>
        } elsif ($flavor eq 'freebsd') {<br>
            require Parse::Netstat::freebsd;<br>
            Parse::Netstat::freebsd::parse<wbr>_netstat(<br>
                output=>$output, tcp=>$tcp, udp=>$udp, unix=>$unix);<br>
        } elsif ($flavor eq 'solaris') {<br>
            require Parse::Netstat::solaris;<br>
            Parse::Netstat::solaris::parse<wbr>_netstat(<br>
                output=>$output, tcp=>$tcp, udp=>$udp, unix=>$unix);<br>
        } elsif ($flavor eq 'win32') {<br>
            require Parse::Netstat::win32;<br>
            Parse::Netstat::win32::parse_n<wbr>etstat(<br>
                output=>$output, tcp=>$tcp, udp=>$udp);<br>
        } else {<br>
            return [400, "Unknown flavor '$flavor', please see --help"];<br>
        }<br>
<br>
Sys::Filesystem <<a href="https://metacpan.org/release/Sys-Filesystem" rel="noreferrer" target="_blank">https://metacpan.org/release/<wbr>Sys-Filesystem</a>> - Retrieve list of filesystems and their properties<br>
<br>
   [ @query_order = map { __PACKAGE__ . '::' . $_ } ( ucfirst( lc $^O ), $^O =~ m/Win32/i ? 'Win32' : 'Unix', 'Dummy' ) ]<br>
<br>
En esta última distribución, se usa Module::Pluggable, para cargar el módulo como si fuera un "plugin" o complemento de la propia distribución.<br>
<br>
Saludos,<span class="HOEnZb"><font color="#888888"><br>
</font></span><br></blockquote><div><br></div><div>Muchas gracias Joaquín. Voy a experimentar con estas sugerencias y actualizaré mi ejemplo :-)<br><br></div><div>Un saludo, <br></div></div></div></div>