How can I load a Perl module at runtime? - perl

I would like to use the HTML::Template module. However, it is not installed on the server I'm using to develop CGI scripts.
Is it possible to load a module at runtime: I found the Template.pm file on my local Perl installation and uploaded the file to the server I'm using.
#!/usr/bin/perl -w
use CGI qw(:standard :html4);
use CGI::Carp qw(warningsToBrowser fatalsToBrowser);
# use HTML::Template;
use Template;
# my $package = "HTML::Template";
# eval {
# (my $pkg = $package) =~ s|::|/|g; # require need a path
# require "$pkg.pm";
# import $package;
# };
# die $# if( $# );
# open the HTML template
my $template = HTML::Template->new(filename => 'test.tmpl');
# fill in some parameters in the template
$template->param(home => $ENV{HOME});
$template->param(path => $ENV{PATH});
# send the obligatory Content-Type
print "Content-Type: text/html\n\n";
# print the template
print $template->output;

Here is what I do:
cgi-bin/script.pl
cgi-bin/lib/HTML/Template.pm
In script.pl (unless you are running under mod_perl):
use FindBin qw( $Bin );
use File::Spec::Functions qw( catfile );
use lib catfile $Bin, 'lib';
use HTML::Template;
# The rest of your script
If HTML::Template is truly optional, read perldoc -f require.
See also How do I keep my own module/library directory? and What's the difference between require and use? in perlfaq8.

This is similar to Sinan's answer, but uses local::lib:
Set up your files as:
cgi-bin/script.pl
cgi-bin/lib/HTML/Template.pm
And in your script:
use strict;
use warnings;
use local::lib 'lib';
use HTML::Parser;
The advantage of local::lib is you can install modules from CPAN directly into a directory of your choosing:
perl -MCPAN -Mlocal::lib=lib -e 'CPAN::install("HTML::Parser")'

HTML::Template and Template are different Perl modules. If you want to use HTML::Template, you will need to use HTML::Template; at the top of the script to import that package.
Ensure that you copied the HTML/Template.pm file from your local machine to the server, rather than Template.pm.

I should have added this as an option, since I'm one of the maintainers of this module: App::FatPacker can be used to include a third-party module with your application when it ships, so it does not need to be installed separately in the deployment environment.

Yes it is. Look at Module::Runtime. I would install your HTML module though, even in a local install directory. It's probably less hassle.

Related

Loading Perl Modules from non-standard directories

How to load Perl modules using non-standard directories?
I download the trace module from cpan website and put into non-standard directories(/home/nrama/perl-script). but It doesn't taking my non-standard directories while executing below script. please let me know how to resolve this issue.
Trace module URL:
https://metacpan.org/pod/release/JV/Debug-Trace-0.05/lib/Debug/Trace.pm
Error:
syntax error at shift.pl line 3, near "use Trace."
Execution of shift.pl aborted due to compilation errors.
Sample script:-
use strict;
use lib ("/home/nrama/perl-script");
use Trace.pm;
func('Nataraj', 'vino', 'mano' );
sub func {
my $name_1 = shift;
my $name_2 = shift;
my $name_3 = shift;
print "say hello to $name_1 $name_2 $name_3\n";
}
Note: Using perl, v5.6.0
use Trace.pm;
is not valid Perl, thus the syntax error. That should be
use Debug::Trace;
Furthermore, it makes no sense to harcode an absolute path in a script. You should remove
use lib ("/home/nrama/perl-script");
and either set env var PERL5LIB to that path in the login script
export PERL5LIB="$HOME/perl-script"
or replace it with a relative path to the script such as
use FindBin qw( $RealBin );
use lib $RealBin;
or
use FindBin qw( $RealBin );
use lib "$RealBin/lib";

Why would one put `#! /usr/bin/false` in a Perl Module?

I was looking at the source code for the CPAN Perl module Digest::Perl::MD5 and noticed that it has the she bang #! /usr/bin/false. Here's the first few lines of Digest/Perl/MD5.pm ...
#! /usr/bin/false
#
# $Id: MD5.pm,v 1.19 2004/02/14 02:25:32 lackas Exp $
#
package Digest::Perl::MD5;
use strict;
use integer;
use Exporter;
use vars qw($VERSION #ISA #EXPORTER #EXPORT_OK);
... why would the author of Digest::Perl::MD5 use #! /usr/bin/false? And what if my system does not have /usr/bin/false but has /bin/false instead?
why would the author of Digest::Perl::MD5 use #! /usr/bin/false?
So that if someone tried to use the module as an executable (Perl $ ./MD5.pm), it would quietly die instead of trying to execute the module as a program.
And what if my system does not have /usr/bin/false but has /bin/false instead?
Then it will nosily die complaining that it couldn't find /usr/bin/false if anyone tried that.

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");

Print current directory using Perl

I have this code to print the current directory using Perl:
use Cwd qw(abs_path);
my $path = abs_path($0);
print "$path\n";
But it is displaying the filename of my script along with the directory.
Like this:
C:\Perl\duration.pl
I want it only to display C:\Perl\.
How can I do it?
To get the current working directory (pwd on many systems), you could use cwd() instead of abs_path:
use Cwd qw();
my $path = Cwd::cwd();
print "$path\n";
Or abs_path without an argument:
use Cwd qw();
my $path = Cwd::abs_path();
print "$path\n";
See the Cwd docs for details.
To get the directory your perl file is in from outside of the directory:
use File::Basename qw();
my ($name, $path, $suffix) = File::Basename::fileparse($0);
print "$path\n";
See the File::Basename docs for more details.
Each of the following snippets get the script's directory, which is not the same as the current directory. It's not clear which one you want.
use FindBin qw( $RealBin );
say $RealBin;
or
use Cwd qw( abs_path );
use File::Basename qw( dirname );
say dirname(abs_path($0));
or
use Cwd qw( abs_path );
use Path::Class qw( file );
say file(abs_path($0))->dir;
Use:
print($ENV{'PWD'});
But I think it doesn't work on Windows...
Just remove the '$0'
use Cwd qw(abs_path);
my $path = abs_path();
print "$path\n";
Here is one simple solution:
use Cwd;
my $cwd = cwd();
print "Current working directory: '$cwd()'";
I hope this will help.
You could use FindBin:
use FindBin '$RealBin';
print "$RealBin\n";
FindBin is a standard module that is installed when you install Perl. To get a list of the standard pragmatics and modules, see perldoc perlmodlib.
I used my script in dirs with symlinks.
The script parses the path and executes commands depending on the path.
I was faced with the correct determination of the current path.
Here is example:
root#srv apache # pwd
/services/apache
root#srv apache # readlink -f .
/services/apache2225
Cwd module disclosures path (analogue of readlink -f)
http://perldoc.perl.org/Cwd.html
root#server apache # perl -e 'use Cwd; print cwd . "\n";'
/services/apache2225
If you need to get current path like pwd, you can use $ENV{'PWD'}
root#srv apache # perl -e 'use Cwd; print $ENV{'PWD'}."\n";'
/services/apache
Thank you.

How do I load libraries relative to the script location in Perl?

How can you get current script directory in Perl?
This has to work even if the script is imported from another script (require).
This is not the current directory
Example:
#/aaa/foo.pl
require "../bbb/foo.pl"
#/bbb/bar.pl
# I want to obtain my directory (`/bbb/`)
print($mydir)
The script foo.pl could be executed in any ways and from any directory, like perl /aaa/foo.pl, or ./foo.pl.
What people usually do is
use FindBin '$Bin';
and then use $Bin as the base-directory of the running script. However, this won't work if you do things like
do '/some/other/file.pl';
and then expect $Bin to contain /some/other/ within that. I'm sure someone thought of something incredibly clever to work this around and you'll find it on CPAN somewhere, but a better approach might be to not include a program within a program, but to use Perl's wonderful ways of code-reuse that are much nicer than do and similar constructs. Modules, for example.
Those generally shouldn't care about what directory they were loaded from. If they really need to operate on some path, you can just pass that path to them.
See Dir::Self CPAN module. This adds pseudo-constant __DIR__ to compliment __FILE__ & __LINE__.
use Dir::Self;
use lib __DIR__ . '/lib';
I use this snippet very often:
use Cwd qw(realpath);
use File::Basename;
my $cwd = dirname(realpath($0));
This will give you the real path to the directory containing the currently running script. "real path" means all symlinks, "." and ".." resolved.
Sorry for the other 4 responses but none of them worked, here is a solution that really works.
In below example that adds the lib directory to include path the $dirname will contain the path to the current script. This will work even if this script is included using require from another directory.
BEGIN {
use File::Spec;
use File::Basename;
$dirname = dirname(File::Spec->rel2abs( __FILE__ )) . "/lib/";
}
use lib $dirname;
From perlfaq8's answer to How do I add the directory my program lives in to the module/library search path?
(contributed by brian d foy)
If you know the directory already, you can add it to #INC as you would for any other directory. You might if you know the directory at compile time:
use lib $directory;
The trick in this task is to find the directory. Before your script does anything else (such as a chdir), you can get the current working directory with the Cwd module, which comes with Perl:
BEGIN {
use Cwd;
our $directory = cwd;
}
use lib $directory;
You can do a similar thing with the value of $0, which holds the script name. That might hold a relative path, but rel2abs can turn it into an absolute path. Once you have the
BEGIN {
use File::Spec::Functions qw(rel2abs);
use File::Basename qw(dirname);
my $path = rel2abs( $0 );
our $directory = dirname( $path );
}
use lib $directory;
The FindBin module, which comes with Perl, might work. It finds the directory of the currently running script and puts it in $Bin, which you can then use to construct the right library path:
use FindBin qw($Bin);
You can also use local::lib to do much of the same thing. Install modules using local::lib's settings then use the module in your program:
use local::lib; # sets up a local lib at ~/perl5
See the local::lib documentation for more details.
Let's say you're looking for script.pl. You may be running it, or you may have included it. You don't know. So it either lies in the %INC table in the first case or as $PROGRAM_NAME (aka $0) in the second.
use strict;
use warnings;
use English qw<$PROGRAM_NAME>;
use File::Basename qw<dirname>;
use File::Spec;
use List::Util qw<first>;
# Here we get the first entry that ends with 'script.pl'
my $key = first { defined && m/\bscript\.pl$/ } keys %INC, $PROGRAM_NAME;
die "Could not find script.pl!" unless $key;
# Here we get the absolute path of the indicated path.
print File::Spec->rel2abs( dirname( $INC{ $key } || $key )), "\n";
Link to File::Basename, File::Spec, and List::Util