Perl library to avoid redefining an already defined function - perl

I have two perl module files like :
is_date_holiday.pl :
use strict;
use warnings;
sub IsDateHoliday
{
...
}
1
calc_prev_working_date_mult.pl :
use strict;
use warnings;
require "is_date_holiday.pl"; # IsDateHoliday
sub CalcPrevWorkingDateMult
{
...
}
1
On using them both in a perl file like :
require "is_date_holiday.pl"; # IsDateHoliday
require "calc_prev_working_date_mult.pl" # CalcPrevWorkingDateMult
It complains that I am redefining the function IsDateHoliday
How can do an equivalent of #ifndef ?

You don't actually have modules, but you should.
IsDateHoliday.pm:
package IsDateHoliday;
use strict;
use warnings;
use Exporter qw( import );
our #EXPORT_OK = qw( IsDateHoliday );
our %EXPORT_TAGS = ( all => \#EXPORT_OK );
sub IsDateHoliday
{
...
}
1;
CalcPrevWorkingDateMult.pm:
package CalcPrevWorkingDateMult;
use strict;
use warnings;
use Exporter qw( import );
our #EXPORT_OK = qw( CalcPrevWorkingDateMult );
our %EXPORT_TAGS = ( all => \#EXPORT_OK );
use IsDateHoliday qw( :all );
sub CalcPrevWorkingDateMult
{
...
}
1;
main.pl:
use IsDateHoliday qw( :all );
use CalcPrevWorkingDateMult qw( :all );

Really you should create packages for these and then use them. That will eliminate the issues with redefining because you can then import what you need and use won't import stuff twice.
package IsDateHoliday;
use strict;
use warnings;
use Exporter;
our #ISA = qw(Exporter);
our #EXPORT = qw(IsDateHoliday);
sub IsDateHoliday {
#...
}
1; # not a typo, Perl needs modules to return true
Name the file "IsDateHoliday.pm" then when you need it:
use strict;
use lib '.'; # to include the local directory
use IsDateHoliday;
Same treatment for the other one.
Of course one might question why you don't just use Date::Calc from CPAN. (Might not have holidays but I'm sure something else on CPAN does!)

Although it'd be best to change to use over require, which will check to see if it's already been loaded first, if you really wanted to write C in perl, likely the closest to what you're trying to do would be to just set some variable, and check to see if exists, but you have to hide the subroutine definition in an eval.
# in the included file:
my $DateHolidayLoaded;
if ( !$DateHolidayLoaded ) {
eval {
sub IsDateHoliday { ... }
$DateHolidayLoaded = 1;
};
}
You can test for a function's existance, too, but you have to specify what namespace to use ... and in this case, it'd be 'main' :
if ( ! defined( main->can( 'IsDateHoliday' ) ) ) { require 'is_date_holiday.pl' }
But this will only work in the file doing the include; if you do this test in a file with the subroutine definition, it'll always be true.

Related

How to conditionally import functions from another module and export them to the local namespace

Assume I have a module named Local that exports a subroutine subLocal via the %EXPORT_TAGS interface.
This module is closely related to another module named Remote that defines subroutines the user of Local might want to import.
There are two requirements I would like to have:
Module Local should import the subroutines defined in Remote only if the user of module Local is importing a subroutine defined in Remote (either by explicitly naming the export or by using a specific export tag)
When a subroutine from Remote is imported into Local, the user of module Local should be able to refer to that subroutine as if it is in his local namespace (the same behavior you would get when referring to a subroutine defined in Local).
I've only found a (hacky) solution for req. 2 by adding an entry in the symbol table, but this always occurs -- regardless if the user of Local actually needs the subroutines in Remote. According to perldoc, this pointlessly "pollutes" the namespace.
So at what point during compilation or runtime should I be trying to import the subroutines from Remote? And how do I actually import them in such a way that they appear in the local namespace?
This is my current approach. Module Local:
package Local;
use strict;
use warnings;
BEGIN
{
require Exporter;
our #ISA = qw| Exporter |;
our #EXPORT_LOCAL = qw| subLocal |;
our #EXPORT_REMOTE = qw| subRemote |;
our #EXPORT_OK = ( #EXPORT_LOCAL, #EXPORT_REMOTE );
our %EXPORT_TAGS =
( all => \#EXPORT_OK, local => \#EXPORT_LOCAL, remote => \#EXPORT_REMOTE );
*subRemote = \&Remote::subRemote; # <-- can I do this conditionally somewhere?
# <-- and is there a better way to put this function in the user's local namespace?
}
use Remote; # <-- can I do this conditionally somewhere?
sub subLocal { return "(local)" }
1;
And module Remote:
package Remote;
use strict;
use warnings;
BEGIN
{
require Exporter;
our #ISA = qw| Exporter |;
our #EXPORT_REMOTE = qw| subRemote |;
our #EXPORT_OK = ( #EXPORT_REMOTE );
our %EXPORT_TAGS =
( all => \#EXPORT_OK, remote => \#EXPORT_REMOTE );
}
sub subRemote { return "(remote)" }
1;
Why would you want to import subs into Local subs that Local is asked to export? Might as well place them directly into the right module instead of Local!
Either way, you won't be able to use (just) Exporter. There might an existing alternative to Exporter you could use. Otherwise, you'll need to write your own import.
Local.pm:
package Local;
use strict;
use warnings;
use Carp qw( croak );
use Exporter qw( );
use Import::Into qw( );
use Remote qw( );
my #export_ok_local = qw( subLocal );
my #export_ok_remote = qw( subRemote );
my #export_ok_all = ( #export_ok_local, #export_ok_remote );
my %export_tags = (
':ALL' => \#export_ok_all,
':DEFAULT' => [],
':local' => \#export_ok_local,
':remote' => \#export_ok_remote,
);
our #EXPORT_OK = #export_ok_local;
sub import {
my $class = shift;
my $target = caller;
my #imports =
map {
!/^:/
? $_
: !$export_tags{$_}
? croak("\"$_\" isn't a recognized tag")
: #{ $export_tags{$_} }
}
#_;
my %imports = map { $_ => 1 } #imports;
my #local = grep { $imports{$_} } #export_ok_local;
my #remote = grep { $imports{$_} } #export_ok_remote;
delete #imports{ #local, #remote };
my #unknown = keys(%imports);
croak("Not exported by ".__PACKAGE__.": #unknown\n") if #unknown;
Remote->import::into($target, #remote);
#_ = ( $class, #local );
goto &Exporter::import;
}
sub subLocal { print("subLocal\n"); }
1;
Remote.pm:
package Remote;
use strict;
use warnings;
use Exporter qw( import );
our #EXPORT_OK = qw( subRemote );
sub subRemote { print("subRemote\n"); }
1;
Test:
$ perl -e'
use Local qw( subLocal subRemote );
subLocal();
subRemote();
'
subLocal
subRemote
$ perl -e'
use Local qw( :ALL );
subLocal();
subRemote();
'
subLocal
subRemote
It's far simpler to simply import everything you want to export.
package Local;
use strict;
use warnings;
use Exporter qw( import );
my ( #EXPORT_LOCAL, #EXPORT_REMOTE );
BEGIN {
#EXPORT_LOCAL = qw| subLocal |;
#EXPORT_REMOTE = qw| subRemote |;
our #EXPORT_OK = ( #EXPORT_LOCAL, #EXPORT_REMOTE );
our %EXPORT_TAGS = (
ALL => \#EXPORT_OK,
local => \#EXPORT_LOCAL,
remote => \#EXPORT_REMOTE,
);
}
use Remote #EXPORT_REMOTE;
sub subLocal { ... }
1;
To be honest I think that the confusion you will create by messing with import is probably more of a problem than the namespace pollution in the first place, which is only an issue if you choose identifiers that clash with the imported ones
Here's an example using object-oriented design, which doesn't use import at all and there is zero namespace pollution. You don't even have to say in the main program which methods you will use
Remote.pm
use 5.010;
package Remote;
sub new {
my $class = shift;
my $self = bless {}, $class;
}
sub subRemote {
say "I am subRemote";
}
1;
Local.pm
use 5.010;
package Local;
use base 'Remote';
sub new {
my $class = shift;
my $self = $class->SUPER::new(#_);
}
sub subLocal {
say "I am subLocal";
}
1;
main.pl
use 5.010;
use Local;
my $obj = Local->new;
$obj->subLocal;
$obj->subRemote;
output
I am subLocal
I am subRemote
I take the question to be: That the caller of Local can require subRemote in its import list, but if it doesn't then the symbol isn't pushed into the caller's namespace.
I also assume that Local should not import from Remote at all unless the caller of Local requires some of Remote's subs in its import list.
Then write your own sub import. The list supplied by the caller are arguments passed to import, following the first argument which is __PACKAGE__ (in this case Local).
Then in your import you can check whether subRemote is asked for. If it is, require the package where it is defined and push its sub's full name to the caller's symbol table, otherwise not. You can establish and check any other conditions you may need.
This way Local loads Remote only if the caller of Local requires a sub from Remote.
An example for the above description
Local.pm
package Local;
use warnings;
use strict;
use Exporter qw();
our #EXPORT_OK = qw(subLocal subRemote);
sub import {
my $class = shift;
my $re = qr/^(?:subRemote|other)/;
my #local_exports = grep { !/$re/ } #_;
my #remote_exports = grep { /$re/ } #_; # check both
if (#remote_exports) {
no strict 'refs';
require Remote;
foreach my $export (#remote_exports)
{
my $to_caller = caller() . '::' . $export;
*{ $to_caller } = \&{ 'Remote::' . $export };
}
}
#_ = ($class, #local_exports); # set up #_ for goto
goto &Exporter::import; # switch to Exporter::import
}
sub subLocal { print "subLocal() in ", __PACKAGE__, "\n" }
1;
The references to subs from Remote that are asked for are written to the caller's symbol table. Then our import is swapped by Exporter::import for exporting the rest of the symbols, from Local. For a note on goto see this for example. A few things are left out, firstly checks of received import lists.
There are no surprises with main and Remote
main.pl
use warnings;
use strict;
use Local qw(subLocal subRemote);
subLocal();
subRemote();
Remote.pm
package Remote;
use warnings;
use strict;
use Exporter qw(import);
our #EXPORT_OK = qw(subRemote);
sub subRemote { print "subRemote() in ", __PACKAGE__, "\n" }
with the output
subLocal() in Local
subRemote() in Remote
This accomplishes what is asked but it has to deal with rather specific details.

Perl: script and module calling a second module

I have the following:
Module1
package module1;
require Exporter;
our #ISA = qw(Exporter);
our #EXPORT = qw(<list of subs within>);
use Module2;
sub M1S1 ()
{
$x = M2S1();
}
Module 2
package module2;
require Exporter;
our #ISA = qw(Exporter);
our #EXPORT = qw(<list of modules within>);
sub M2S1()
{
...
}
sub M2S2()
{
...
}
Script
use Module2;
use Module1;
$y = M1S1();
$z = M2S2();
When the script calls a sub in Module 1 which in turn calls a sub in Module 2, the sub is not found, even though the script can call those subs directly.
I'm not a beginner to Perl by any means, but I've never fully gotten the hang of modules. Our environment has gotten very dependent on module2, so I don't want to make any changes that would require changing all the scripts that use it. Module1 has limited use so I can make changes to it if necessary.
The file name, the name in the package directive, and the name in the use statement must match, and that includes case.
Module1.pm
package Module1;
use Module1;
Or if you had a non-flat namespace,
Foo/Bar.pm
package Foo::Bar;
use Foo::Bar;
Note that you can have similar problems when you have two exporting modules that use each other (directly or indirectly), but that doesn't seem to the case.
$ cat Module1.pm
package Module1;
use strict;
use warnings;
use Exporter qw( import );
our #EXPORT = qw( M1S1 );
use Module2;
sub M1S1 { M2S1() }
1;
$ cat Module2.pm
package Module2;
use strict;
use warnings;
use Exporter qw( import );
our #EXPORT = qw( M2S1 M2S2 );
sub M2S1 { "M2S1" }
sub M2S2 { "M2S2" }
1;
$ cat script.pl
#!/usr/bin/perl
use strict;
use warnings;
use Module2;
use Module1;
print(M1S1(), "\n");
print(M2S2(), "\n");
$ ./script.pl
M2S1
M2S2

How can I call a subroutine declared in another package without prefixing the subroutine name with its package name?

I'm not entirely sure this is possible, but I would like to simply shorten the name of the subroutine I'm calling declared in another package by just omitting the package name.
For example, I have a module defined:
package Package1;
use strict;
use warnings;
BEGIN
{
require Exporter;
our #ISA = qw( Exporter );
our #EXPORT_OK = qw( subroutine1 );
}
sub subroutine1
{
print "Hello!$/";
}
return 1;
And I have a driver application defined:
use strict;
use warnings;
use Package1;
&Package1::subroutine1;
The only way I can seem to shorten the call to subroutine1 is with making an alias like the following:
*s1 = \&Package1::subroutine1;
&s1;
Surely I'm being a doofus and missing something here.. Is there a cleaner way to achieve this?
Change
use Package1;
to
use Package1 qw( subroutine1 );
or change
our #EXPORT_OK = qw( subroutine1 );
to
our #EXPORT = qw( subroutine1 );
I recommend the first change.
You're already using Exporter, which is how you achieve this. All you need to do is change your driver application code to
use Package1 'subroutine1';
in order to tell the import method provided by Exporter to export your symbol to the calling package.

Why don't functions from package A get imported into package B when they recursively call each other?

I'm trying to use two packages and call functions from one to other, but I've got this error:
Undefined subroutine &module2::method_1_2 called at module2.pm line 20.
Is there any way to call functions from one package to the other one without getting this error?
Thanks in advance.
xabi
exec error:
./test.pl
method_1_1
method_2_1
method_2_2
Undefined subroutine &module2::method_1_2 called at module2.pm line 20.
Sample code (test.pl):
#!/usr/bin/perl
use strict;
use module1;
use module2;
method_1_1();
method_2_2();
module1.pm
package module1;
use strict;
use module2;
require Exporter;
use vars qw(#ISA #EXPORT);
#ISA = qw(Exporter);
#EXPORT = qw( method_1_1 method_1_2 );
sub method_1_1
{
print "method_1_1\n";
method_2_1();
}
sub method_1_2
{
print "method_1_2\n";
}
1;
module2.pm:
package module2;
use strict;
use module1;
require Exporter;
use vars qw(#ISA #EXPORT);
#ISA = qw(Exporter);
#EXPORT = qw( method_2_1 method_2_2 );
sub method_2_1
{
print "method_2_1\n";
}
sub method_2_2
{
print "method_2_2\n";
method_1_2();
}
1;
The problem is that the very first thing module1 does is to use module2. That means all of module2 is read and executed while module1 is still compiling.
The next thing to happen is that module2 does use module1. Because module1 has been found and put into %INC Perl doesn't execute it again, and just does module1->import to fetch the exported symbols.
But of course module1 has in fact barely started compiling, and #module1::EXPORT doesn't even exist, never mind about its two subroutines. That makes Exporter import nothing at all into module2, so when it comes to make the call method_1_2() it knows nothing about it.
The cleanest way to fix this is to do the import after the compilation (including all the use statements and BEGIN blocks) but before runtime. Perl's INIT block is ideal for this, and we can get the code working by changing the modules to the form below. I have shown only module2 here, as the pattern of calls means this is all that's needed to fix this particular problem, but the general case needs the equivalent change to all cooperating modules.
package module2;
use strict;
use warnings;
use module1;
INIT { module1->import }
use base 'Exporter';
our #EXPORT = qw( method_2_1 method_2_2 );
sub method_2_1 {
print "method_2_1\n";
}
sub method_2_2 {
print "method_2_2\n";
method_1_2();
}
1;
The problem is that you assign to #EXPORT after it was already used. The following is copied from Mini-Tutorial: Mutual Use of Exporting Modules
[ The need to use this technique is a very strong indicator of a design flaw in your system, but I recognize that the resources are not always available to fix design flaws. ]
If ModA uses ModB, ModB uses ModA, and ModA or ModB imports symbols from the other, one needs to pay attention to code execution order. The best way I've found to avoid problems is to setup Exporter before loading any other module.
# ModA.pm
package ModA;
use strict;
use warnings;
use Exporter qw( import );
BEGIN { our #EXPORT_OK = qw( ... ); }
use This;
use ModB;
use That;
...
1;
# ModB.pm
package ModB;
use strict;
use warnings;
use Exporter qw( import );
BEGIN { our #EXPORT_OK = qw( ... ); }
use This;
use ModA;
use That;
...
1;
Interesting, I am not sure why method_1_2 isn't being exported into the module2 namespace, but you can get around this by explicitly referencing the package:
module1.pm
package module1;
use strict;
use warnings;
use module2 (); #don't import methods
use base 'Exporter';
our #EXPORT = qw( method_1_1 method_1_2 );
sub method_1_1
{
print "method_1_1\n";
module2::method_2_1();
}
sub method_1_2
{
print "method_1_2\n";
}
1;
module2.pm
package module2;
use strict;
use warnings;
use module1 (); #don't import methods
use base 'Exporter';
our #EXPORT = qw( method_2_1 method_2_2 );
sub method_2_1
{
print "method_2_1\n";
}
sub method_2_2
{
print "method_2_2\n";
module1::method_1_2();
}
1;
Okay, I think I see what is going on, but take this with a grain of salt. The use function is effectively a BEGIN block and BEGIN blocks run as soon as they are parsed, so the code looks like this in execution order.
perl starts parsing test.pl
it sees use module1; so it loads module1.pm and starts parsing it
perl sees use module2; in module1.pm so it loads module2.pm and starts parsing it
At this point, the functions in module1 do not yet exist, so they can't be imported
parsing continues
Something Borodin said tipped me off to the best solution: "#module1::EXPORT doesn't even exist". The problem here is that the #EXPORT variable doesn't exist. This can be fixed by putting it in a BEGIN block:
module1.pm
package module1;
use strict;
use warnings;
use base 'Exporter';
BEGIN {
our #EXPORT = qw( method_1_1 method_1_2 );
}
use module2;
sub method_1_1
{
print "method_1_1\n";
module2::method_2_1();
}
sub method_1_2
{
print "method_1_2\n";
}
1;
module2.pm
package module2;
use strict;
use warnings;
use base 'Exporter';
BEGIN {
our #EXPORT = qw( method_2_1 method_2_2 );
}
use module1;
sub method_2_1
{
print "method_2_1\n";
}
sub method_2_2
{
print "method_2_2\n";
method_1_2();
}
1;
IMPORTANT NOTE: I do not believe prototypes in module1 will be honored in any of these cases (and I don't see how they could be since module2 gets compiled before module1, so it can't know the prototypes exist). This is yet another argument to never use prototypes.

How do you print exported module constants in Perl?

I want to define some constants in one package and then use them in another package, but I don't seem to be doing this right! At first shot I was getting
Bareword "FAVORITE_COLOR" not allowed while "strict subs" in use at ...
I guess it was because I wasn't using the base path for my package in the lib() function,
Module
My/Colors.pm
package My::Colors;
BEGIN {
use Exporter;
our($VERSION, #ISA, #EXPORT, #EXPORT_OK, %EXPORT_TAGS);
$VERSION = 1.00;
#ISA = qw(Exporter);
#EXPORT = qw( );
#EXPORT_OK = qw( FAVORITE_COLOR DISLIKED_COLOR );
%EXPORT_TAGS = ( 'all' => [ #EXPORT, #EXPORT_OK ], 'const' => [ 'FAVORITE_COLOR', 'DISLIKED_COLOR'] );
}
our #EXPORT_OK;
use lib qw( /home/dev );
use Carp;
use constant {
DISLIKED_COLOR => "green",
FAVORITE_COLOR => "red"
};
sub new {
my($class, %args) = #_;
my $self = bless({}, $class);
my $target = exists $args{target} ? $args{target} : "new";
$self->{target} = $target;
return $self;
}
1;
Module that includes exported constants
color_driver.plx
#!/usr/bin/perl -w
use warnings;
use strict;
use diagnostics;
use lib qw( /home/dev/My );
use Colors;
use Colors qw(:const);
sub main{
my $color = new Colors;
print "Color is",FAVORITE_COLOR;
}
main();
any idea what I'm doing wrong?
When I remove strict the constant doesnt translate to its value =/
Updated
Unfortunately now perl is complaining that it can't find new sub
Can't locate object method "new" via package "Colors" (perhaps you
forgot to
load "Colors"?) at color_driver.plx line 15 (#1)
In the module:
package My::Colors;
In the script:
use lib qw( /home/dev/My );
use Colors qw(:const);
my $color = new Colors;
Either change those lines of the module to
package Colors;
or change those lines of the script to
use lib qw( /home/dev );
use My::Colors qw(:const);
my $color = new My::Colors;
use Colors qw( :const );
is almost identical to
BEGIN {
require Colors;
Colors->import(qw( :const ));
}
You are telling Perl to look in the Colors package/namespace for import (and new), but the module populates the package/namespace My::Colors.