Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Perl > Perl Misc > How can I pick a module depending if I have it or not?

Reply
Thread Tools

How can I pick a module depending if I have it or not?

 
 
jl_post@hotmail.com
Guest
Posts: n/a
 
      11-06-2013
Dear Perl community,

Recently I had to debug a Perl script in a Windows environment that was meant for a Unix environment. The script used the module Device::SerialPort, and since I didn't have it on my Windows installation of Strawberry Perl, the compiler check "perl -c script.pl" was giving me errors.

No problem, I thought; I'll just use the "cpan Device::SerialPort" to install it, and that'll be the end of my problem. Well, I wasn't able to install the Device::SerialPort module through Strawberry Perl, so I looked around CPAN and the internets to see what I could do.

I discovered a very similar module named Win32::SerialPort. It is so similar to Device::SerialPort that many of the method names are the same. And I was able to install Win32::SerialPort onto my Strawberry Perl setup. After that I was able to change:

use Device::SerialPort;
my $port = Device::SerialPort->new($portName)
or die "Can't establish connection with $portName.\n";

to:

use Win32::SerialPort;
my $port = Win32::SerialPort->new($portName)
or die "Can't establish connection with $portName.\n";

and the rest of the code (that involved the SerialPort, at least) compiled just fine.

However, once I finished debugging the script I had to remember to change the "Win32::SerialPort" module to "Device::SerialPort" before I sent the script back for use on a Unix platform. Eventually an idea came to me thatI could let the script determine which module to use (depending on whetherthat module existed). In other words, if Device::SerialPort exists, use that one, but if not, use Win32::SerialPort. (And if neither exist, exit/die with an informative error message.)

So my question is: How can I use a module if it is installed, or another if it is not installed?

I want to be able to do something like this:

my $port = do
{
if (use Device::SerialPort)
{
Device::SerialPort->new($portName)
or die "Can't establish connection with $portName.\n";
}
elsif (use Win32::SerialPort)
{
Win32::SerialPort->new($portName)
or die "Can't establish connection with $portName.\n";
}
else
{
die "This script requires the Device::SerialPort or Win32::SerialPort module.\n";
}
};


Of course this code won't compile, so I was wondering if someone knows how to get a Perl script to do what I want -- that is, to detect which modules (out of several) exist, and to properly load them as if I used them withnormal "use" syntax.

Thanks in advance,

-- Jean-Luc
 
Reply With Quote
 
 
 
 
$Bill
Guest
Posts: n/a
 
      11-06-2013
On 11/6/2013 10:27, http://www.velocityreviews.com/forums/(E-Mail Removed) wrote:
> Dear Perl community,
>
> Recently I had to debug a Perl script in a Windows environment that was meant for a Unix environment. The script used the module Device::SerialPort, and since I didn't have it on my Windows installation of Strawberry Perl, the compiler check "perl -c script.pl" was giving me errors.
>
> No problem, I thought; I'll just use the "cpan Device::SerialPort" to install it, and that'll be the end of my problem. Well, I wasn't able to install the Device::SerialPort module through Strawberry Perl, so I looked around CPAN and the internets to see what I could do.
>
> I discovered a very similar module named Win32::SerialPort. It is so similar to Device::SerialPort that many of the method names are the same. And I was able to install Win32::SerialPort onto my Strawberry Perl setup. After that I was able to change:
>
> use Device::SerialPort;
> my $port = Device::SerialPort->new($portName)
> or die "Can't establish connection with $portName.\n";
>
> to:
>
> use Win32::SerialPort;
> my $port = Win32::SerialPort->new($portName)
> or die "Can't establish connection with $portName.\n";
>
> and the rest of the code (that involved the SerialPort, at least) compiled just fine.
>
> However, once I finished debugging the script I had to remember to change the "Win32::SerialPort" module to "Device::SerialPort" before I sent the script back for use on a Unix platform. Eventually an idea came to me that I could let the script determine which module to use (depending on whether that module existed). In other words, if Device::SerialPort exists, use that one, but if not, use Win32::SerialPort. (And if neither exist, exit/die with an informative error message.)
>
> So my question is: How can I use a module if it is installed, or another if it is not installed?
>
> I want to be able to do something like this:
>
> my $port = do
> {
> if (use Device::SerialPort)
> {
> Device::SerialPort->new($portName)
> or die "Can't establish connection with $portName.\n";
> }
> elsif (use Win32::SerialPort)
> {
> Win32::SerialPort->new($portName)
> or die "Can't establish connection with $portName.\n";
> }
> else
> {
> die "This script requires the Device::SerialPort or Win32::SerialPort module.\n";
> }
> };
>
>
> Of course this code won't compile, so I was wondering if someone knows how to get a Perl script to do what I want -- that is, to detect which modules (out of several) exist, and to properly load them as if I used them with normal "use" syntax.


Try using eval - something like:

eval "use Device::SerialPort";
if ($@) {
print "Can't find Device::SerialPort\n";
eval "use Win32::SerialPort";
if ($@) {
die "Can't find Win32::SerialPort - quitting";
} else {
print "Found Win32::SerialPort - using it\n";
}
} else {
print "Found Device::SerialPort - using it\n";
}


 
Reply With Quote
 
 
 
 
Rainer Weikusat
Guest
Posts: n/a
 
      11-06-2013
"(E-Mail Removed)" <(E-Mail Removed)> writes:
> Recently I had to debug a Perl script in a Windows environment that
> was meant for a Unix environment. The script used the module
> Device::SerialPort, and since I didn't have it on my Windows
> installation of Strawberry Perl, the compiler check "perl -c
> script.pl" was giving me errors.


[...]

> I discovered a very similar module named Win32::SerialPort. It is
> so similar to Device::SerialPort that many of the method names are
> the same.


[...]

> However, once I finished debugging the script I had to remember to
> change the "Win32::SerialPort" module to "Device::SerialPort"
> before I sent the script back for use on a Unix platform.


[...]

> So my question is: How can I use a module if it is installed, or
> another if it is not installed?


Someone else must have implemented this already but you could use this
small module:

-------------
package Delegate;

sub import
{
my ($candidates, $fname);

shift;
$candidates = shift;

for (@$candidates) {
$fname = $_;
$fname =~ s/::/\//g;
$fname .= '.pm';

eval {
require $fname;
};

$@ || do {
unshift(@_, $_);
$_ .= "::import";
goto &$_;
};
}

die("No way man ... \n");
}

1;
---------------

Example usage

---------------
use Delegate (['B::Mad', 'ModA'], 'for_whats_it_worth');

print(for_whats_it_worth(), "\n");
---------------

The first argument is a reference to an anonymous array containing a
list of candiate module names, the others are an ordinary import list.

NB: This doesn't duplicate the documented functionality of use ... /
require Bareword completely as it doesn't try loading a file with .pmc
at the end.
 
Reply With Quote
 
Rainer Weikusat
Guest
Posts: n/a
 
      11-06-2013
Rainer Weikusat <(E-Mail Removed)> writes:
> "(E-Mail Removed)" <(E-Mail Removed)> writes:
>> Recently I had to debug a Perl script in a Windows environment that
>> was meant for a Unix environment. The script used the module
>> Device::SerialPort, and since I didn't have it on my Windows
>> installation of Strawberry Perl, the compiler check "perl -c
>> script.pl" was giving me errors.

>
> [...]
>
>> I discovered a very similar module named Win32::SerialPort. It is
>> so similar to Device::SerialPort that many of the method names are
>> the same.

>
> [...]
>
>> However, once I finished debugging the script I had to remember to
>> change the "Win32::SerialPort" module to "Device::SerialPort"
>> before I sent the script back for use on a Unix platform.

>
> [...]
>
>> So my question is: How can I use a module if it is installed, or
>> another if it is not installed?

>
> Someone else must have implemented this already but you could use this
> small module:
>
> -------------
> package Delegate;
>
> sub import
> {
> my ($candidates, $fname);
>
> shift;
> $candidates = shift;
>
> for (@$candidates) {
> $fname = $_;
> $fname =~ s/::/\//g;
> $fname .= '.pm';
>
> eval {
> require $fname;
> };
>
> $@ || do {
> unshift(@_, $_);
> $_ .= "::import";
> goto &$_;
> };
> }
>
> die("No way man ... \n");
> }
>
> 1;
> ---------------


While this is a neat idea, it won't work with modules which don't define
or inherit an import method, won't work with OO-modules at all and is
restricted to a single set of delegations per program. Something more
suitable (for the problem situation which was about OO-modules) could
look like this:

-------------
sub require_one
{
my $fname;

for (@_) {
$fname = $_;
$fname =~ s/::/\//g;
$fname .= '.pm';

eval {
require $fname;
};

return $_ unless $@;
}

die("need any of ".join(', ', @_)."\n");
}
-------------

This expects a list of module names as arguments and will return the
name of the first one which could be loaded. This name can then used to
call class methods like this

$serial_class = require_one('Win32::SerialPort', 'Device::SerialPort');
$port = $serial_class->new($portName);
 
Reply With Quote
 
Charles DeRykus
Guest
Posts: n/a
 
      11-07-2013
On 11/6/2013 10:27 AM, (E-Mail Removed) wrote:
> ...
> So my question is: How can I use a module if it is installed, or another if it is not installed?
>
> I want to be able to do something like this:
>
> my $port = do
> {
> if (use Device::SerialPort)
> {
> Device::SerialPort->new($portName)
> or die "Can't establish connection with $portName.\n";
> }
> elsif (use Win32::SerialPort)
> {
> Win32::SerialPort->new($portName)
> or die "Can't establish connection with $portName.\n";
> }
> else
> {
> die "This script requires the Device::SerialPort or Win32::SerialPort module.\n";
> }
> };
>



Maybe a combination of 'use if' and Module::Load::Conditional ...

use Module::Load::Condition qw/check_install/;

our( $m1, $m2 );
use if $m1=check_install(module=>Device::SerialPort),Devi ce::SerialPort;
use if $m2=check_install(module=>Win32::SerialPort), Win32::SerialPort;

die "This script requires..." unless $m1 or $m2;

--
Charles DeRykus
 
Reply With Quote
 
C.DeRykus
Guest
Posts: n/a
 
      11-07-2013
On Wednesday, November 6, 2013 5:09:26 PM UTC-8, C.DeRykus wrote:
> On 11/6/2013 10:27 AM, (E-Mail Removed) wrote:
>> ...

>
> Maybe a combination of 'use if' and Module::Load::Conditional ...
>
> use Module::Load::Condition qw/check_install/;
>
> our( $m1, $m2 );
> use if $m1=check_install(module=>Device::SerialPort),Devi ce::SerialPort;
>
> use if $m2=check_install(module=>Win32::SerialPort), Win32::SerialPort;
>
> die "This script requires..." unless $m1 or $m2;
>


And to reduce the "yuck" look:

use Module::Load::Condition qw/check_install/;

my $mod1 = check_install(module=>..., ...);
my $mod2 = check_install(module=>..., ...);
die "This script requires..." unless $mod1 or $mod2;

use if $mod1, Device::SerialPort;
use if $mod2, Win32::SerialPort;


--
Charles DeRykus
 
Reply With Quote
 
Rainer Weikusat
Guest
Posts: n/a
 
      11-08-2013
Rainer Weikusat <(E-Mail Removed)> writes:
> Rainer Weikusat <(E-Mail Removed)> writes:
>> "(E-Mail Removed)" <(E-Mail Removed)> writes:


[...]

>>> So my question is: How can I use a module if it is installed, or
>>> another if it is not installed?

>>
>> Someone else must have implemented this already but you could use this
>> small module:
>>
>> -------------
>> package Delegate;


[...]

> While this is a neat idea, it won't work with modules which don't define
> or inherit an import method, won't work with OO-modules at all and is
> restricted to a single set of delegations per program.


The last assertion is wrong because while a module will only be loaded
once, it's import method will be called for as many times as there are
use statements naming it. It is also surprisingly easy to make 'OO
modules' work, courtesy of the fact that Perl-OO doesn't work by special
magic but reuses existing language facilities.

This deals with 'bareword modules' only but it can do 'implicit imports'
as this really doesn't require any work minus using the import-mechanism
correctly. The code is open to abuse in many different ways but "in line
with the usual UNIX(*) tradition, it gives you enough rope to hang
yourself" (as opposed to hanging you proactively to make sure you don't
do something someone considers to be stupid for some reason).

package Delegate;

#
# Delegate something to the first module from a set of
# candidate modules which can be loaded.
#
# Usage
# -----
#
# use Delegate (['candidate0', 'candidiate1', ...], 'importsub0', 'importsub1', ...);
#
# Load the first candidate module which can be loaded and import the
# specified subroutines from it.
#
# use Delegate ({ Winner => ['candidate0', 'candidiate1', ...]}, 'importsub0', 'importsub1', ...);
#
# Same as above but additionally, create a package whose name is the
# single key of the anonymous hash passed as first argument
# functioning as class derived from the selected candidate module.
#

sub require_one
{
eval "require $_;" and return $_
for @_;

return;
}

sub import
{
my ($arg0, $candidates, $delegate, $x);

shift;

$arg0 = shift;
if (ref($arg0) eq 'HASH') {
$delegate = (keys(%$arg0))[0];
$candidates = $arg0->{$delegate};
} else {
$candidates = $arg0;
}

$x = require_one(@$candidates);
die("Need one of ".join(',', @$candidates)) unless $x;

eval "package $delegate; our \@ISA = qw($x); 1;"
if $delegate;

if ($x->can('import')) {
unshift(@_, $x);
$x .= '::import';
goto &$x;
}
}

# Because properties of existing things are discovered and not
# invented, this code is in the public domain. Whoever discovers
# a bug in it is entitled to keep it.
1;
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
How to get JSON values and how to trace sessions?? webmaster@terradon.nl Python 2 04-25-2013 02:12 PM
Hi, How can I fix error 1720 please? Thanks milabood@gmail.com Windows 64bit 1 04-13-2013 02:19 AM
ImportError depending on the calling module Samuel Python 6 09-06-2007 08:01 PM
When to pick quad core and when to pick dual core thingy NZ Computing 6 11-21-2006 07:08 AM
When to pick ASP.Net, when to pick desktop? tom c ASP .Net 5 11-01-2006 06:15 PM



Advertisments