[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