Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Perl too smart require()ing libs

by clscott (Friar)
on Jun 22, 2007 at 05:32 UTC ( [id://622720]=perlquestion: print w/replies, xml ) Need Help??

clscott has asked for the wisdom of the Perl Monks concerning the following question:

Background

At $work we have a bunch of perl 4 style libraries that get required into apps when we need their functionality.

As they are not packages they automatically pull a whole pile of subroutine and variable definitions into the main:: namespace. I wasn't feeling very happy about that.

So in a effort to begin refactoring I wrote packages as wrappers around these libraries. The packages use Exporter and @EXPORT_OK so we could use the package and import only the subroutines our apps actually needed. This allows us to incrementally migrate the code base to the package style as we need to, by keeping the original libraries intact.

As these types of things usually do, there are interdependencies between the libraries, for example bar.pl calls a sub defined in foo.pl so the package for bar.pl (BarWrapper.pm) needs to require both bar.pl and foo.pl

The problem

When I "use" two wrapper packages and they both "require" the same lib, the second package gets shafted and doesn't get the subroutines defined and imported into its namespace.

The Question

How the heck can I work around or overcome this?

Code to demonstrate

#runme.pl use lib '.'; use ExampleClass; my $ec = ExampleClass->new; print $ec->does_work,"\n";
#ExampleClass.pm package ExampleClass; use lib '.'; use BarWrapper; use FooWrapper qw/can_i_see_you/; sub new { my $class = shift; bless {}, $class; } sub does_work { can_i_see_you(); } 1;
#BarWrapper.pm package BarWrapper; use vars qw/@ISA @EXPORT_OK @SUBS/; require Exporter; @ISA = qw(Exporter); @EXPORT_OK = qw(i_am_another_sub); require "bar.pl"; require "foo.pl"; 1;
#bar.pl sub i_am_another_sub { return "subber!"; } 1;
#FooWrapper.pm package FooWrapper; use vars qw/@ISA @EXPORT_OK @SUBS/; require Exporter; @ISA = qw(Exporter); @EXPORT_OK = qw(can_i_see_you dont_import_me ); require "foo.pl"; 1;
#foo.pl sub can_i_see_you { return "You can see me!"; } sub dont_import_me { return "Don't import me"; } 1;
--
Clayton

Replies are listed 'Best First'.
Re: Perl too smart require()ing libs
by ikegami (Patriarch) on Jun 22, 2007 at 05:48 UTC

    Use do, not use/require, to load unpackaged libs.

    #BarWrapper.pm package BarWrapper; use vars qw/@ISA @EXPORT_OK @SUBS/; require Exporter; @ISA = qw(Exporter); @EXPORT_OK = qw(i_am_another_sub); do "bar.pl"; do "foo.pl"; 1;
    #FooWrapper.pm package FooWrapper; use vars qw/@ISA @EXPORT_OK @SUBS/; require Exporter; @ISA = qw(Exporter); @EXPORT_OK = qw(can_i_see_you dont_import_me ); do "foo.pl"; 1;

    The wrappers are packaged, so you should continue to use use/require to load them.

      Thank you. This is the approach I've taken and it seems to be working well.

      --
      Clayton
Re: Perl too smart require()ing libs
by andreas1234567 (Vicar) on Jun 22, 2007 at 08:02 UTC
    You can use pl2pm to convert your Perl4-style .pl library files to Perl5-style library modules.

    Create Foo.pm and Bar.pm:

    $ pl2pm foo.pl bar.pl
    Rewrite ExampleClass.pm:
    #ExampleClass.pm package ExampleClass; use lib '.'; use Bar; use Foo qw/can_i_see_you/; sub new { my $class = shift; bless {}, $class; } sub does_work { can_i_see_you(); } 1;
    $ perl -w runme.pl You can see me!
    --
    print map{chr}unpack(q{A3}x24,q{074117115116032097110111116104101114032080101114108032104097099107101114})

      I attempted this just to see what the resulting pm would look like but pl2pm choked on the library.

      Thanks for the suggestion though.

      --
      Clayton
Re: Perl too smart require()ing libs
by merlyn (Sage) on Jun 22, 2007 at 22:19 UTC
    Didn't see anyone comment on this, but:
    use lib '.';
    is basically a no-op (unless you're root, where that's removed).

    If your intent is to add the directory of the module/script to the @INC path, that's definitely not going to do it. You'll need something more like:

    use File::Basename qw(dirname); use lib dirname(__FILE__);
      Didn't see anyone comment on this, but: use lib '.'; is basically a no-op (unless you're root, where that's removed).
      Actually, I had a use for this today. I have PERL5LIB set to some custom locations, but had a test version of a library in the current directory. I needed 'use lib qw(.)' in my test program in order to override what PERL5LIB had in it. Or I could've put "." at the front of PERL5LIB...yeah, it's a different intent than what you (probably correctly) assumed from the OP, but it's not completely a "no-op" :-)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://622720]
Approved by almut
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others studying the Monastery: (5)
As of 2024-03-28 16:53 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found