Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Including modules and pragmas in caller's scope via use

by wanna_code_perl (Friar)
on Jul 29, 2014 at 20:49 UTC ( [id://1095522]=perlquestion: print w/replies, xml ) Need Help??

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

Hello monks,

I already have several Local::... modules that do things too specific for general public consumption. Now I have a "smaller" problem:

Like many programmers, I have an ever-growing repository of useful subroutines that are either too isolated or too simple to (yet...) merit their own module (in the Local:: module namespace or otherwise). I also have a list of modules and pragmas I use in almost every script. However, these are things I'd like to have available in most of my internal-use scripts.

The subroutines? Easy. Just pile them in a new module (say, Local::Junk and @EXPORT them by default (or with Exporter::Easy and qw(:all) if I'm feeling extra pedantic...).

But I don't know how to the other modules (and pragmas) that I'd like to include by default whenever I use Local::Junk, such as List::Util, autodie, etc.

In other words, I'd like to be able to simply do something like this:

use Local::Junk qw(:all);

Instead of:

use strict; use warnings; use autodie; use List::Util qw(first max maxstr min minstr reduce shuffle sum); # etc...

I tried this in Local/Junk.pm:

package Local::Junk; sub import { # The following work: warnings->import; strict->import; # The following do NOT work: autodie->import; List::Util->import(qw(first max maxstr min minstr reduce shuffle s +um)); }

With the above import() code, I can turn on warnings and strict just by using my module. But autodie doesn't work in the caller, and neither does List::Util, not even if I fully qualify the subroutines like List::Util::sum(...) in the caller.

My question:

Hopefully with the above, you get an idea of what I'm trying to accomplish. Again, in short, I want to be able to use Local::Junk and have that behave as if I'd called use ... on the list of modules and pragmas above (strict, List::Util, et. al.) Assuming it's possible to do so, how would I accomplish that?

Some other minor notes:

(The rest is not essential to the core question, but I anticipate a few of these points might come up):

My scripts are run on several servers. In-house modules are automatically distributed on our network via a local CPAN repository, so it would be more convenient to use a module, rather than separately copy a library and require '/path/to/mylib.pl'; on multiple OSes. (And even then, while require 'mylib.pl' did work with importing List::Util, it did not work with autodie. That is, I could call sum but open $fh, '<', 'nonexistent' failed silently).

I'm aware of distributions like Modern::Perl and common::sense. Without making value judgments on these types of things, I will say that, a) these modules only deal with basic pragmas and features, not more elaborate pragmas (e.g., autodie) and full modules (e.g., List::Util), and b) As a Local:: module, Local::Junk and any scripts/internal modules that use it will never see the (public) light of day, so there is no danger of this module imposing my will on unsuspecting programmers. Lastly, c) if I ever do decide to package up one of my scripts for wider-scale distribution (CPAN or otherwise), yes, I will have to expand the use statements and possibly pull some code into the script or a public module, but that amount of work would typically be tiny in comparison to the larger scope of expanding the documentation, unit tests, and the act of distribution itself.

Besides, now that I think of it, it'd probably be pretty easy to export a sub that would take the source code of $0 and s/use Local::Junk;/$expanded_use/s and output that for release...

Replies are listed 'Best First'.
Re: Including modules and pragmas in caller's scope via use
by Anonymous Monk on Jul 29, 2014 at 22:15 UTC

      Indeed, I think it does. I had a chance to play around with it, and after a minor disagreement with autodie, I got it to do everything I needed.

      For anyone reading this later on with the same question: the Import::Into docs make reference to autodie being difficult, but (to me, anyway) were a little vague on how to fix that. Almost all examples in the documentation use the following format:

      my $target = scalar caller; $package->import::into($target, @arguments);

      However, autodie doesn't work with the above approach, but they say "Some exporting modules, such as autodie or strictures, care about the filename they are being imported to.". But it took just a bit more effort than just using the alternate hashref syntax. With autodie, what worked the best for me was this:

      my ($package, $filename, $line) = caller; autodie->import::into({ package => $package, filename => $filename, line => $line });

      (Note both of these examples would go into your module's import sub, as usual with Import::Into.)

        The documentation could use some improvements for this. The better syntax would be:
        autodie->import::into(1);
        This imports to the package/file/line at caller level 1, which matches what you are doing manually.
Re: Including modules and pragmas in caller's scope via use
by Anonymous Monk on Jul 29, 2014 at 22:52 UTC
Re: Including modules and pragmas in caller's scope via use
by peter.pl (Novice) on Jul 31, 2014 at 03:28 UTC
    How about using do like this? Create your MyInit.pl like so:
    use v5.18; BEGIN { use List::MoreUtils qw| any |; use Scalar::Util qw| looks_like_number |; use Fatal qw| open |; } sub mySub { say "This is mySub, foo!"; }
    Then you can write your script like so:
    #!/usr/bin/perl use v5.18; BEGIN { do 'MyInit.pl'; } mySub(); my @array = ( 'one', 'two', 'three' ); if( any {$_ eq 'two'} @array ) { say 'So far so good...'; } if( looks_like_number( "five" ) ) { say 'Hmm...'; } else { say 'Perl can\'t read.'; } open( my $dne, '<', 'nonexistentfile.txt' ); die 'Failed to import autodie';
    Which seems to work like so:
    peter@hermes:~/src/Perl/test> perl myscript.pl This is mySub, foo! So far so good... Perl can't read. Can't open(GLOB(0x9cc7d8), <, nonexistentfile.txt): No such file or di +rectory at (eval 3) line 4. main::__ANON__('GLOB(0x9cc7d8)', '<', 'nonexistentfile.txt') c +alled at myscript.pl line 22
    The trick with autodie was that its import just gotos the import function from Fatal. So I just cut out the middleman.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others chanting in the Monastery: (9)
As of 2024-03-28 14:46 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found