BEGIN blocks in Perl - perl

Searching the Internet, I get that the BEGIN block will get evaluated and executed in the compile phase. But can the #INC or other variables be inherited?
Below is what I wrote for testing. The directory structure is as:
|-- alexpackages
| |-- alex1.pm
| `-- alex2.pm
|-- foo.pl
`-- main.pl
For each file:
cat alexpackages/alex1.pm
package alex1;
sub foo()
{
print "this is alex1::foo\n";
}
1;
cat alexpackages/alex2.pm
package alex2;
sub foo2()
{
print "this is is alex2::foo2\n";
}
1;
cat foo.pl
alex1::foo();
cat main.pl
BEGIN
{
push(#INC, '~/programs/perl/alexpackages');
}
use strict;
use warnings;
use alex1;
use alex2;
#alex1::foo(); # 1. This works good
system("perl foo.pl"); # 2. This fails
Just as what my program tells that the #INC does not work for a new system call. It seems to me that system call will not inherit the system environment. Am I right?
And can how I make the environment variables to the following system call?

Processes started with system will inherit the environment variables from the calling process, but #INC is just a global Perl variable, not a system environment variable. It is not visible outside the Perl program.
A couple of notes on your code
Package names, being globals, should be capitalised, so your packages should be Alex1 and Alex2, in files alexpackages/Alex1.pm and alexpackages/Alex2.pm
It is best to use the lib pragma to manipulate #INC, so
use lib '~/programs/perl/alexpackages'
is best. And a use statement creates an implicit BEGIN block, so that is also unnecessary.
It is wrong to use prototypes on Perl subroutines, so sub foo() should be just sub foo
You may prefer to use Exporter to copy the symbols of a package into the calling code. That way you don't have to fully-qualify your subroutine name when you call it, like foo() instead of Alex1::foo()
The code would look like this
main.pl
use strict;
use warnings;
use lib '~/programs/perl/alexpackages';
use Alex1;
foo();
~/programs/perl/alexpackages/Alex1.pm
package Alex1;
use strict;
use warnings;
use base 'Exporter';
our #EXPORT = qw/ foo /;
sub foo {
print "This is Alex1::foo\n";
}
1;

There are many ways to specify library search directories both from within a Perl script or the command line. Here are two things you could do to make another directory available to the Perl script you invoke with system:
$ENV{PERL5LIB} = "~/programs/perl/alexpackages";
system("perl foo.pl");
system("perl -I~/programs/perl/alexpackages foo.pl");
Both PERL5LIB and the -I switch are documented in perlrun.

Related

Why doesn't my Perl script use my module?

module.pm
package module;
use 5.012;
use warnings;
sub Parse
{
return 1;
}
1;
script.pl
#!/usr/bin/perl -w
use 5.012;
use warnings;
use lib 'C:/';
use module;
print Parse("value");
Stdout
Undefined subroutine &main::Parse
You need either to write:
print module::Parse("value");
or to change the module package to export the name Parse.
See http://perldoc.perl.org/perlmod.html#Perl-Modules for guidance in exporting symbols from your module.
(By the way, you should really name your module Module rather than module. Lowercase module-names are used for Perl built-in features like use warnings and use strict.)
Several things:
First, use Local as your module prefix. That way, if you just happen to have a module with the same name in your Perl installation, it will use yours. Call it "Local::Module". Then, create a Local directory, and name your module Module.pm.
The other thing you have to understand is that you define your module in another namespace. By default, everything is in the main namespace until you use the package statement. That creates another namespace that your package uses. This way, if your package has a function foo, and you've defined a function foo in your main program, they won't collide.
Thus, you have two choices: One (the preferred now) is to simply call your subroutine with the full package name prepended to it. The second is to export your subroutine names to your main program. This can cause problems with duplicate names, but you don't have to keep typing in the package name every time you call your subroutine.
Without Exporting the name
Local/Module.pm
# /usr/bin/env perl
# Local/Module.pm
package Local::Module;
use strict;
use warnings;
sub Parse {
my $value = shift; #Might as well get it.
print "I got a value of $value\n";
return $value;
}
1; #Need this or the module won't load
program.pl
# /usr/bin/env perl
# program.pl
use strict;
use warnings;
use Local::Module;
Local::Module::Parse("Foo");
With export:
Local/Module.pm
# /usr/bin/env perl
# Local/Module.pm
package Local::Module;
use strict;
use warnings;
use Exporter qw(import);
our #EXPORT_OK(Parse); #Allows you to export this name into your main program
sub Parse {
my $value = shift; #Might as well get it.
print "I got a value of $value\n";
return $value;
}
1; #Need this or the module won't load
program.pl
# /usr/bin/env perl
# program.pl
use strict;
use warnings;
use Local::Module qw(Parse);
Parse("Foo");

Perl problem 'require' the same file

I have a shared module in perl. The main program needs two files, first, a shared file (let's call it 'X'), and, second, a 'package' file. File 'X' is also included in the 'package' file using 'require'. When I compile this program it gives me the following error:
Undefined subroutine &main::trim called at testing.pl line 8.
My understanding is that perl couldn't find the trim() module. If I don't include the package file, then this will run without any problem.
Can anyone shed light on this problem?
These are my codes:
Main program: testing.pl
#!/usr/bin/perl -w
use strict;
use postgres;
require "shared.pl";
trim("als");
Package File: postgres.pm
#!/usr/bin/perl
package postgres;
use strict;
use DBI;
require "shared.pl";
1;
shared file: shared.pl
#!/usr/bin/perl
# =============
# shared module
# =============
use strict;
sub trim($)
{
}
1;
If the module doesn't use package, you want do instead of require. See What is the difference between library files and modules?.
do "shared.pl" or die $#;
You really should create a proper module, one with a package statement.
package Shared;
use strict;
use warnings;
our #EXPORT = qw( trim );
use Exporter qw( import );
sub trim { ... }
1;
Name the file Shared.pm and load it using use Shared;.
By default, require will only load a file one time. In this case, that one time is from the file postgres.pm, in the postgres package. So the trim subroutine gets defined in the postgres namespace as &postgres::trim.
One workaround would be to use the fully qualified subroutine name in the testing.pl file:
postgres::trim("als"); # not trim("als")
Another workaround is to hack the %INC table (the variable that keeps track of what modules/files have already been use'd and require'd) so you can reload shared.pl into the main package:
use postgres;
delete $INC{"shared.pl"};
require "shared.pl";
A third workaround would be to export the trim function from the postgres package to the main package. The docs for the Exporter module are a good introduction to why and how this is done.
# in postgres.pm
*main::trim = *trim;
# or in testing.pl
*trim = *postgres::trim;
trim("als");

How can I split my Perl code across multiple files?

My scripts are getting too long. How do I split my code (procedural subs) into multiple Perl files and tell the interpreter to make sense of them?
Kind of like:
# -> main.pl
#include "foo.pl"
say_hello();
and:
# -> foo.pl
sub say_hello {print "hello!"}
What you want to do is create one or more modules. Start by looking over perlmod, especially the Perl Modules section.
Since you say you're writing procedural code, you'll want to export functions from your modules. The traditional way to do that is to use Exporter (which comes with Perl), although Sub::Exporter is a newer CPAN module that allows for some nice things. (See also its Sub::Exporter::Tutorial for an introduction to exporting functions.)
Modules can be placed in any of the directories listed in the #INC variable. Try perl -V to get a list. You can also use lib to add directories at runtime. One trick is to use the FindBin module to find the location of your script, and then add a directory relative to that:
use FindBin; # Suppose my script is /home/foo/bin/main.pl
use lib "$FindBin::Bin/lib"; # Add /home/foo/bin/lib to search path
Your sample code, converted to a module:
In main.pl:
#! /usr/bin/perl
use strict;
use warnings;
use Foo;
say_hello();
In Foo.pm:
package Foo;
use strict;
use warnings;
use Exporter 'import';
our $VERSION = '1.00';
our #EXPORT = qw(say_hello);
sub say_hello {print "hello!"}
1; # A module must end with a true value or "use" will report an error
I think you may be looking for do? http://perldoc.perl.org/functions/do.html
put it in the same folder as your class and add use ClassName to the top of the calling file.
Also check the Perl OOP tutorial.

In Perl, what is the difference between a .pm (Perl module) and .pl (Perl script) file?

What is the Difference between .pm (Perl module) and .pl (Perl script) file?
Please also tell me why we return 1 from file. If return 2 or anything else, it's not generating any error, so why do we return 1 from Perl module?
At the very core, the file extension you use makes no difference as to how perl interprets those files.
However, putting modules in .pm files following a certain directory structure that follows the package name provides a convenience. So, if you have a module Example::Plot::FourD and you put it in a directory Example/Plot/FourD.pm in a path in your #INC, then use and require will do the right thing when given the package name as in use Example::Plot::FourD.
The file must return true as the last statement to indicate successful execution of any initialization code, so it's customary to end such a file with 1; unless you're sure it'll return true otherwise. But it's better just to put the 1;, in case you add more statements.
If EXPR is a bareword, the require assumes a ".pm" extension and replaces "::" with "/" in the filename for you, to make it easy to load standard modules. This form of loading of modules does not risk altering your namespace.
All use does is to figure out the filename from the package name provided, require it in a BEGIN block and invoke import on the package. There is nothing preventing you from not using use but taking those steps manually.
For example, below I put the Example::Plot::FourD package in a file called t.pl, loaded it in a script in file s.pl.
C:\Temp> cat t.pl
package Example::Plot::FourD;
use strict; use warnings;
sub new { bless {} => shift }
sub something { print "something\n" }
"Example::Plot::FourD"
C:\Temp> cat s.pl
#!/usr/bin/perl
use strict; use warnings;
BEGIN {
require 't.pl';
}
my $p = Example::Plot::FourD->new;
$p->something;
C:\Temp> s
something
This example shows that module files do not have to end in 1, any true value will do.
A .pl is a single script.
In .pm (Perl Module) you have functions that you can use from other Perl scripts:
A Perl module is a self-contained piece of Perl code that can be used by a Perl program or by other Perl modules. It is conceptually similar to a C link library, or a C++ class.

Perl - Package/Module Issues

From everything I've read on using Perl modules, the basic usage is:
Module file with .pm extension, which includes the statement package <name>, where <name> is the filename of the module without the extension.
Code file that uses module contains the statement use <name>;.
The application I'm coding has one main code script which uses about 5 modules. I had forgotten to include the package <name> statement in the modules, but my code still ran just fine with the use <name> statement. I started receiving Undefined subroutine errors with one of the modules, so I added the package statement to each of the modules. Now the rest of those modules stopped working. What gives?
Example:
mainapp.pl
#!/usr/bin/perl
use UtyDate;
my $rowDate = CurrentDate("YYYYMMDD");
UtyDate.pm
#!/usr/bin/perl
package UtyDate;
sub CurrentDate
{
#logic
}
return 1;
When I run the above code, I get the error Undefined subroutine &main::CurrentDate called at.... However, if I remove the package UtyDate; line from UtyDate.pm, I get no error. This situation exists for several but not all of my modules.
There's obviously a lot more code I'm not showing, but I'm confused how any of the code I'm not showing could affect the package/use constructs I've shown here.
When you use a module, the code in the module is run at compile time. Then import is called on the package name for the module. So, use Foo; is the same as BEGIN { require Foo; Foo->import; }
Your code worked without the package declarations because all the code was executed under the package main, which is used by the main application code.
When you added the package declarations it stopped working, because the subroutines you defined are no longer being defined in main, but in UtyDate.
You can either access the subroutines by using a fully qualified name UtyDate::CurrentDate(); or by importing the subroutines into the current name space when you use the module.
UtyDate.pm
package UtyDate;
use strict;
use warnings;
use Exporter 'import';
# Export these symbols by default. Should be empty!
our #EXPORT = ();
# List of symbols to export. Put whatever you want available here.
our #EXPORT_OK = qw( CurrentDate AnotherSub ThisOneToo );
sub CurrentDate {
return 'blah';
}
sub AnotherSub { return 'foo'; }
Main program:
#!/usr/bin/perl
use strict;
use warnings;
use UtyDate 'CurrentDate';
# CurrentDate is imported and usable.
print CurrentDate(), " CurrentDate worked\n";
# AnotherSub is not
eval { AnotherSub() } or print "AnotherSub didn't work: $#\n";
# But you can still access it by its fully qualified name
print UtyDate::AnotherSub(), " UtyDate::AnotherSub works though\n";
See Exporter docs for more info.
You are missing the exporter perl header code. You will need to add something like the following to the top of your pm file below the package statement:
package UtyDate;
BEGIN {
use Exporter ();
use vars qw($VERSION #ISA #EXPORT);
$VERSION = "1.0.0";
#ISA = qw(Exporter);
#EXPORT = qw( &CurrentDate );
}
See this link: http://perldoc.perl.org/Exporter.html#DESCRIPTION
Alternatively to Gray's suggestion, you can do this:
use UtyDate;
UtyDate::CurrentDate(...);
Besides using the exporter, as Gray points out, you could (UGLY, but works) also call the functions with the module name ..
You functiond/procedures don't work since they are now in a differen namespace (defined by the module name)
use UtyDate;
UtyDate::CurrentDate( )