How to "use" multiple modules with one "use"? - perl

I want use some packages and some pragmas in all my programs, like:
use 5.014;
use warnings;
use autodie;
use My::ModuleA::Something;
use ModuleB qw(Func1 Func2);
I don't want repeat myself in every module, so looking for a way how to make one package e.g. My::Common what will contain the above packages and in my programs do only:
use My::Common;
say Func1("hello"); #say enabled and Func1 imported in the My::Common
how to achieve this?
The was read preldoc -f use and perldoc perlmodlib so i think I must "somewhat" to do this with BEGIN plus require&import, but absolutely don't know how.
UPDATE: I'm already tried the basic things.
With require - my prg.pl program.
require 'mymods.pl';
$var = "hello";
croak "$var\n";
mymods.pl contain
use strict;
use feature 'say';
use Carp qw(carp croak cluck);
1;
DOES NOT WORKS. Got error:
$ perl prg.pl
String found where operator expected at prg.pl line 3, near "croak "$var\n""
(Do you need to predeclare croak?)
syntax error at prg.pl line 3, near "croak "$var\n""
Execution of prg.pl aborted due to compilation errors.
with "use My":
use My;
$var = "hello";
croak "$var\n";
my My.pm
package My;
use strict;
use feature 'say';
use Carp qw(carp croak cluck);
1;
DOES NOT WORKS either. Got the same error.
Any working idea?

I'd go with this:
package My::Common;
use 5.14.0;
use strict;
use warnings;
use autodie;
use Carp qw(carp croak cluck);
sub import {
my $caller = caller;
feature->import(':5.14');
# feature->import('say');
strict->import;
warnings->import;
## autodie->import; # <-- Won't affect the caller side - see my edit.
{
no strict 'refs';
for my $method (qw/carp croak cluck/) {
*{"$caller\::$method"} = __PACKAGE__->can($method);
}
}
}
1;
Please correct me if I'm wrong, or there's a better way.
EDIT:
Sorry, I was wrong in using autodie->import...
This one should work, but it assumes that you always call My::Common from the main package:
package My::Common;
# ...
sub import {
# ...
strict->import;
warnings->import;
{
package main;
autodie->import;
}
# ...
}
So, of course, it's much safer and simpler to add a use autodie; to each script:
use My::Common;
use autodie;
# ...

It's actually fairly simple, if you override your "common" module's import method. See the source of chromatic's Modern::Perl module for an example of exporting pragmas.
For re-exporting things defined in other modules, I seem to recall that $export_to_level (see the Exporter docs, although it's not explained all that clearly) should do that, although I can't find any good examples at the moment. Another option would be Pollute::persistent, although I haven't used it, don't know anyone else who's used it, and can't say how stable/solid it's likely to be. If it works, though, it's probably the quickest and easiest option.

I've just noticed a module called rig in CPAN. Try it out.

Related

Program unexpectedly reports "Use of uninitialized value"

This is with regard to my previous question
Hold Subroutine response and set to variable in Perl
The statement Module::thesub("hello")
worked in Module.pm but fails if I move it to main.pl
main.pl
#!/usr/bin/perl
use strict;
use warnings;
use Module;
Module::thesub("hello");
Module.pm
#!/usr/bin/perl
use strict;
use warnings;
package Module;
sub thesub {
state $stored;
$stored = shift if #_;
return $stored;
}
my $testvar = thesub();
print $testvar;
1;
I get this error
Use of uninitialized value $testvar
which means the variable $testvar has no value.
How can I fix this?
Statements in a module run when the module is loaded, at use Module;. At that time thesub() still wasn't called with an argument and $stored in it is undefined. So that is what $testvar gets when it's assigned and the warning is emitted when it's printed.
The $testvar can be used in main
use strict;
use warnings;
use Module;
Module::thesub("hello");
my $testvar = Module::thesub();
even though I am not sure from the question what the purpose of this is.
Remove the assignment and print of $testvar from the module. Note that you'll also need use feature 'state'; at the beginning of the module, to enable the feature pragma.
A few comments on the module you show
No need for #!/usr/bin/perl, as a module is generally not meant to be run
The package Module; is commonly the first line
While what you have works, consider making symbols from the module available to the calling code, so that it can import them and simply say thesub(). A common way is
package Module;
use warnings;
use strict;
use Exporter qw(import);
our #EXPORT_OK = qw(thesub);
sub thesub { ... }
1;
and in the main
use Module qw(thesub);
thesub("hello");
See Exporter for starters and search SO, where there are great many posts on this.

Importing variable into Perl package

I'm writing a basic program whose core logic is split across several project-specific modules for cleanliness (keeping subroutines organised by their purpose in the program's logic).
Suddenly had trouble exposing an option from the main package in one of the modules, and using the our statement appeared to have no effect.
For brevity, I'll copy+paste an isolated test case I wrote to examine this behaviour:
main.pl
#!/usr/bin/perl
use warnings;
use strict;
use File::Basename;
# The variable to be read by the module.
our $verbose = 1;
# Load Output.pm from directory
use lib dirname "$0";
use Output;
write_message "Hello, world\n";
Output.pm
package Output;
use warnings;
use strict;
use parent "Exporter";
our #EXPORT = qw(write_message);
# Should be imported?
our $verbose;
sub write_message {
print $_[0] unless !$verbose;
}
1;
Expected result: "Hello, world"
Actual result: Dead silence
It's quite possible that what I'm trying to achieve isn't even possible in Perl, as this isn't the intended use of modules (and heck, I understand why that'd be the case).
I'm still quite new to Perl and there are some things I'm struggling to wrap my head around. I've seen people recommend using the our declarator to expose a variable across packages, but I can't understand why this isn't working.
PS: If anybody knows a better approach to splitting an app's program-specific logic between modules, I'd appreciate some pointers too. :) But first and foremost, I'd prefer to learn why our-ing a variable isn't working.
An our statement just creates a package variable (whereas my creates a lexical variable). It has nothing to do with exporting
The best option is probably to declare the variable in the Output package and access it as $Output::verbose elsewhere. Like this
main.pl
#!/usr/bin/perl
use strict;
use warnings;
use File::Basename;
use lib dirname $0;
use Output;
$Output::verbose = 1;
write_message "Hello, world\n";
Output.pm
package Output;
use strict;
use warnings;
use Exporter 5.57 'import';
our #EXPORT = qw/ write_message /;
our $verbose;
sub write_message {
print $_[0] if $verbose;
}
1;
Note that I have also removed the incorrect quotes from around $0, and ever since version 5.57 of Exporter it has been possible (and preferable) to import it's import subroutine instead of subclassing it
our declares a package variable in the current package. The one in main.pl refers to $main::verbose; the one in Output.pm refers to $Output::verbose.
You can use the full name $main::verbose to access the variable from anywhere, but you can't really "export" it because exporting refers to making symbols accessible to users of your module. You're trying to do the opposite.

require File::Find: how to use File::Find::name without getting a warning?

When I load File::Find with require like this, how could I modify this script to not get the warning?
#!/usr/bin/env perl
use warnings;
use strict;
use 5.10.1;
require File::Find;
File::Find->import('find');
find( {
wanted => sub {
my $file = $File::Find::name;
#say $file;
},
no_chdir => 1,
},
shift );
Output:
#Name "File::Find::name" used only once: possible typo at ./perl9.pl line 11.
Just replace the require with use. That'll fix it.
Generally, the only reason to ever use require is if you have some specific reason to do deferred module loading at runtime. Usually, you don't.
If you just don't want to import any symbols from the module, pass an empty list to use, like this:
use File::Find ();
or
use File::Find qw();
Edit: If you do have a legitimate reason to defer the module loading, and find ikegami's workaround too ugly, you can just disable the warning locally by writing:
no warnings 'once';
before the statement generating the warning. This will disable that particular warning for the rest of the innermost enclosing code block. To find out which warning messages belong in which classes, see perldiag.
For starters, don't load the file like that. :)
If you do, just add:
$File::Find::name if 0;
The clean way of doing it is to change $File::Find::name to
do { no warnings 'once'; $File::Find::name }

How to get the set of warning checks currently enabled in the perl module?

In the perllexwarn are defined all warnings what is possible to set.
But here is nothing about, how to print out what warnings i have currently enabled.
E.g.:
use strict;
use warnings;
print warnings::enabled->pretty_print(); #fictional...
How is it possible?
example:
use strict;
use 5.012;
use warnings;
my $aaa;
say "$aaa";
say warnings::enabled("uninitialized") ? "yes" : "no";
The above will output:
Use of uninitialized value $aaa in string at y line 6.
no
so, the "uninitialized" warning category is "set", because its prints a warning, but the warnings::enabled("uninitialized") not returns true.
Reading perllexwarn
... functions that are useful for module authors. These are used when you
want to report a module-specific warning to a calling module has
enabled warnings via the "warnings" pragma.
If I understand it correctly, it means the functions (enabled, warnif) only work for module-specific warnings, not for the standard categories. (There is probably a missing "that" before "has" in the documentation.)
Update: It seems standard categories work as well, but only in a module:
package MY;
use warnings::register;
sub S {
my $x;
print $x, "\t";
print warnings::enabled("uninitialized"),"\n";
}
package main;
use warnings;
MY::S();
no warnings;
MY::S();

Is there a way to "use" a single file that in turn uses multiple others in Perl?

I'd like to create several modules that will be used in nearly all scripts and modules in my project. These could be used in each of my scripts like so:
#!/usr/bin/perl
use Foo::Bar;
use Foo::Baz;
use Foo::Qux;
use Foo::Quux;
# Potentially many more.
Is it possible to move all these use statements to a new module Foo::Corge and then only have to use Foo::Corge in each of my scripts and modules?
Yes, it is possible, but no, you shouldn't do it.
I just spent two weeks to get rid of a module that did nothing but use other modules. I guess this module started out simple and innocent. But over the years it grew into a huge beast with lots and lots of use-statements, most of which weren't needed for any given run of our webapp. Finally, it took some 20 seconds just to 'use' that module. And it supported lazy copy-and-paste module creation.
So again: you may regret that step in a couple of months or years. And what do you get on the plus side? You saved typing a couple of lines in a couple of modules. Big deal.
Something like this should work:
http://mail.pm.org/pipermail/chicago-talk/2008-March/004829.html
Basically, create your package with lots of modules:
package Lots::Of::Modules;
use strict; # strictly optional, really
# These are the modules we want everywhere we say "use Lots::Of::Modules".
# Any exports are re-imported to the module that says "use Lots::Of::Modules"
use Carp qw/confess cluck/;
use Path::Class qw/file dir/;
...
sub import {
my $caller = caller;
my $class = shift;
no strict;
*{ $caller. '::'. $_ } = \*{ $class. '::'. $_ }
for grep { !/(?:BEGIN|import)/ } keys %{ $class. '::' };
}
Then use Lots::Of::Modules elsewhere;
use Lots::Of::Modules;
confess 'OH NOES';
Yes.
In Foo/Corge.pm
use Foo::Bar;
use Foo::Baz;
use Foo::Qux;
use Foo::Quux;
1; # Be successful
All that is left is to get the directory containing sub-directory Foo added to your library path (#INC). Alternatively, create Foo.pm and have it use the other modules. They would be in a Foo sub -directory beside Foo.pm.
If you think about it, all the complex Perl modules that use other modules do this all the time. They are not necessarily in the same top-level package (Foo in this example), but they are used just as necessarily.
While you could use Carp, and Path::Class and confess, and so on (as jrockway suggests), that seems like overkill from where I'm sitting.
[EDIT: My earlier solution involving use Lots::Of::Modules; had a subtle bug -- see bottom. The fix makes things a bit uglier, but still workable.]
[EDIT #2: Added BEGIN { ... } around the code to ensure that any functions defined are available at compile time. Thanks to jrockway for pointing this out.]
The following code will do exactly what jrockway's code does, only simpler and clearer:
In Lots/Of/Modules.inc:
use Carp qw/confess cluck/;
use Path::Class qw/file dir/;
0; # Flag an error if called with "use" or "require" instead of "do"
To import those 4 functions:
BEGIN { defined( do 'Lots/Of/Modules.inc' ) or die; }
Because we don't have a package Lots::Of::Modules; statement at the start of this file, the use statements will export into the caller's package.
We must use do instead of use or require, since the latter will only load the file once (causing failure if use Lots::Of::Modules; is called more than once, e.g. in separate modules used by the main program). The more primitive do does not throw an exception if it fails to find the file named by its argument in #INC, hence the need for checking the result with defined.
Another option would be for Foo::Corge to just re-export any items of interest normally:
package Foo::Corge;
use base 'Exporter';
BEGIN {
our #EXPORT_OK = qw( bar baz qux quux );
use Foo::Bar qw( bar );
use Foo::Baz qw( baz );
use Foo::Qux qw( qux );
use Foo::Quux qw( quux );
}
1;
(The 'use' statements can probably go outside the BEGIN, but that's where they were in the code I checked to verify that this worked the way I thought it did. That code actually evals the uses, so it has a reason for them to be inside BEGIN which likely doesn't apply in your case.)
using #EXPORT instead #EXPORT_OK , is more simple
Library is :
package mycommon;
use strict;
use warnings;
use base 'Exporter';
our #EXPORT = qw(test);
sub test {
print "this is a test";
}
1;
use it:
#!/usr/bin/perl
use strict;
use warnings;
use mycommon;
common::test()