<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>