[Madrid-pm] Selección de módulos dependiendo del S.O.

dayer dayer3 en gmail.com
Lun Nov 28 07:25:00 PST 2016


2016-11-28 11:58 GMT+01:00 Joaquin Ferrero <explorer en joaquinferrero.com>:

>     Buenos días.
>
>     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.
>
>     Comenté que había visto en CPAN diversas opciones para hacer eso
> mismo, sobre todo evitar tener que repetir el código
>
> if ($^O eq 'Win32') {
>
>     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.
>
>
> 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.
>
>
> Aquí explicaré la solución de Audio::Beep <https://metacpan.org/release/
> Audio-Beep>, que me parece el más corto y claro donde se puede ver esta
> técnica.
>
>
> En Beep.pm, dentro de new(), hay una línea que busca por el mejor
> reproductor que exista en nuestro sistema:
>
>         $h{player} =  _best_player();
>
>
> Dentro de _best_player() vemos cómo cargar el módulo correspondiente a
> nuestro S.O.:
>
> |sub| |_best_player {|
> |||my| |%os_modules| |= (|
> |||linux| |=> [|
> |||'Audio::Beep::Linux::beep'||,|
> |||'Audio::Beep::Linux::PP'||,|
> |||],|
> |||MSWin32| |=> [|
> |||'Audio::Beep::Win32::API'||,|
> |||],|
> |||freebsd| |=> [|
> |||'Audio::Beep::BSD::beep'||,|
> |||],|
> |||);|
> ||
> |||for| |my| |$mod| |( @{ ||$os_modules||{$^O} } ) {|
> |||if| |(||eval| |"require $mod"||) {|
> |||my| |$player| |= ||$mod||->new();|
> |||return| |$player| |if| |defined| |$player||;|
> |||}|
> |||}|
> |||return||;|
> |}|
>
>    Primero carga un hash con todos los módulos de la distribución.
>
>    Luego, en el bucle for(), extrae los módulos correspondientes al
>    S.O. en que se está ejecutando.
>
>    Hace un eval "requiere ...", y regresa si la inicialización ha sido
>    correcta.
>
> 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:
>
>    new(), para la inicialización,
>    play(), para tocar una nota, y
>    rest(), para hacer una pausa
>
> El programa principal solo tiene que hacer llamadas basadas en esa API:
>
> $self->player->play( _pitch(\%p), _duration(\%p) );
>
>
>
> Resto de distribuciones que he encontrado extrayendo las líneas
> interesantes:
>
> Net::Routing <https://metacpan.org/release/Net-Routing> - manage route
> entries on Operating Systems
>
>    BEGIN {
>        if ($^O eq 'linux') {
>           return $_routing_module = "Net::Routing::Linux";
>        }
>        elsif ($^O eq 'freebsd') {
>           return $_routing_module = "Net::Routing::FreeBSD";
>        }
>        elsif ($^O eq 'netbsd') {
>           return $_routing_module = "Net::Routing::NetBSD";
>        }
>        elsif ($^O eq 'darwin') {
>           return $_routing_module = "Net::Routing::Darwin";
>        }
>        #elsif ($^O eq 'MSWin32') {
>        #   return $_routing_module = "Net::Routing::MSWin32";
>        #}
>        #elsif ($^O eq 'openbsd') {
>        #   return $_routing_module = "Net::Routing::OpenBSD";
>        #}
>             die("[-] Net::Routing: Operating System not supported: $^O\n");
>    }
>         sub new {
>        my $self = shift->SUPER::new(
>           path => [ qw(/bin /sbin /usr/bin /usr/sbin /usr/local/bin
> /usr/local/sbin) ],
>           lc_all => 'en_GB.UTF-8',
>           target => NR_TARGET_ALL(),
>           family => NR_FAMILY_INET4(),
>           @_,
>        );
>             $self->path([ @{$self->path}, split(':', $ENV{PATH}) ]);
>             eval("use $_routing_module;");
>        if ($@) {
>           chomp($@);
>           $Error = "unable to load routing module [$_routing_module]: $@";
>           return;
>        }
>
> Sys::Ramdisk <https://metacpan.org/release/Sys-Ramdisk> - Create and nuke
> RAM disks on various systems
>
> Unix::Uptime <https://metacpan.org/release/Unix-Uptime> - Determine the
> current uptime, in seconds, and load averages, across different *NIX
> architectures
>
>    my $module = $modules{$^O}
>         or die "Operating system type $^O is currently unsupported";
>         require "Unix/Uptime/$module.pm";
>    our @ISA = ("Unix::Uptime::$module");
>
> IO::Async <https://metacpan.org/release/IO-Async> - Asynchronous
> event-driven programming
>
>    if( eval { require "IO/Async/OS/$^O.pm" } ) {
>        @ISA = "IO::Async::OS::$^O";
>    }
>
> System::Info <https://metacpan.org/release/System-Info> - Factory for
> system specific information objects
>
>    sub new {
>         my $factory = shift;
>              $^O =~ m/aix/i               and return
> System::Info::AIX->new;
>         $^O =~ m/bsd/i               and return System::Info::BSD->new;
>         $^O =~ m/cygwin/i            and return System::Info::Cygwin->new;
>         $^O =~ m/darwin/i            and return System::Info::Darwin->new;
>         $^O =~ m/haiku/              and return System::Info::Haiku->new;
>         $^O =~ m/hp-?ux/i            and return System::Info::HPUX->new;
>         $^O =~ m/irix/i              and return System::Info::Irix->new;
>         $^O =~ m/linux/i             and return System::Info::Linux->new;
>         $^O =~ m/solaris|sunos|osf/i and return System::Info::Solaris->new;
>         $^O =~ m/VMS/                and return System::Info::VMS->new;
>         $^O =~ m/mswin32|windows/i   and return System::Info::Windows->new;
>              return System::Info::Generic->new;
>         }
>
> App::Slaughter <https://metacpan.org/release/App-Slaughter> - Perl
> Automation Tool Helper
>
> Parse::Netstat <https://metacpan.org/release/Parse-Netstat> - Parse the
> output of "netstat" command
>
>         if ($flavor eq 'linux') {
>             require Parse::Netstat::linux;
>             Parse::Netstat::linux::parse_netstat(
>                 output=>$output, tcp=>$tcp, udp=>$udp, unix=>$unix);
>         } elsif ($flavor eq 'freebsd') {
>             require Parse::Netstat::freebsd;
>             Parse::Netstat::freebsd::parse_netstat(
>                 output=>$output, tcp=>$tcp, udp=>$udp, unix=>$unix);
>         } elsif ($flavor eq 'solaris') {
>             require Parse::Netstat::solaris;
>             Parse::Netstat::solaris::parse_netstat(
>                 output=>$output, tcp=>$tcp, udp=>$udp, unix=>$unix);
>         } elsif ($flavor eq 'win32') {
>             require Parse::Netstat::win32;
>             Parse::Netstat::win32::parse_netstat(
>                 output=>$output, tcp=>$tcp, udp=>$udp);
>         } else {
>             return [400, "Unknown flavor '$flavor', please see --help"];
>         }
>
> Sys::Filesystem <https://metacpan.org/release/Sys-Filesystem> - Retrieve
> list of filesystems and their properties
>
>    [ @query_order = map { __PACKAGE__ . '::' . $_ } ( ucfirst( lc $^O ),
> $^O =~ m/Win32/i ? 'Win32' : 'Unix', 'Dummy' ) ]
>
> 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.
>
> Saludos,
>
>
Muchas gracias Joaquín. Voy a experimentar con estas sugerencias y
actualizaré mi ejemplo :-)

Un saludo,
------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: <http://mail.pm.org/pipermail/madrid-pm/attachments/20161128/71d5cf40/attachment-0001.html>


Más información sobre la lista de distribución Madrid-pm