perl: change #INC for current scope only - perl

Modification to Perl's #INC array seems for an individual scope very confusing. I would like some clarification, as it seems to be fighting any means of dynamic initialization of objects.
One would think that I could define it as local to solve this problem.
According to the manual, "local modifies the listed variables to be local to the enclosing block, file, or eval."
The part that is annoying me is the "or" portion.
Problem: I would like to change the #INC array to include one and ONLY one directory under certain circumstances and ONLY for the current file.
Example attempt and issues:
Lets say I have a launching script index.pl:
#!/usr/bin/perl
use strict;
use warnings FATAL => 'all';
use File::Basename;
# Lets say I want to modify #INC here to look in ONLY one path. Local
# should allow us to declare for one scope or file (how non explicit this
# is annoys me) Since I have not defined a scope with brackets, it should
# be effective for the current file
local #INC = (dirname(__FILE__) . '/foo/'); #some relative path
# Lets say bar now uses standard perl modules
require 'bar.pm';
# ^- This will fail because local did not work as described, fails at use
# XML::Simple because it is traversing foo
my $bar = bar->new();
For the sake of being comprehensive, here is a bar.pm:
package bar;
use strict;
use warnings;
sub new
{
my $class = shift;
my $self = bless {}, $class;
use XML::Simple;
return $self;
}
1;
Is there anyway to modify #INC ONLY for the current file while leaving it intact in all parsed files afterwards?
(I know I can unshift, but eventually there could be dozens of directories it could be traversing)

require(dirname(__FILE__) . '/foo/bar.pm');

use File::Basename;
use subs 'require';
sub require {
my $module_file = shift;
die "unexpected absolute path $module_file\n" if $module_file =~ /^\//;
CORE::require(dirname(__FILE__) . '/foo/' . $module_file);
}
See http://perldoc.perl.org/CORE.html#OVERRIDING-CORE-FUNCTIONS

local #INC works, but your bar.pm file still needs to be able to find XML/Simple.pm (a use statement is executed at the time a file is compiled, no matter where it appears in the file), presumably from the original #INC, so your local #INC should start with a copy of the original #INC.
{
local #INC = (dirname(__FILE__) . '/foo/', #INC);
require 'bar.pm';
} # local #INC out of scope now, original #INC restored
my $bar = bar->new();

Related

"Can't locate object method "new" [...]" in Perl using the AI::Pathfinding::AStar CPAN module

This is the first "serious" thing I'm doing in Perl, so please pardon me if the question is somewhat silly.
I wanted to play around with the A* pathfinding algorithm. I found the AI::Pathfinding::AStar CPAN Module and am basically trying to get the given example to work.
First of all I separated the example into two files, because I couldn't figure out how to make the use My::Map::Package; work with everything in a single file. I came up with the following two files:
MyAstar.pm:
package MyAstar;
use warnings;
use strict;
use base "AI::Pathfinding::AStar";
my %NODES = get_all_nodes();
sub get_all_nodes {...}
sub getSurrounding {...}
main.pl:
#!/usr/bin/env perl
package main;
use lib '/home/foo/astar/';
use warnings;
use strict;
use MyAstar;
my $map = MyAstar->new or die "No map for you!";
my $path = $map->findPath(1, 5);
print join(', ', #$path), "\n";
When I execute main.pl I get the following error:
Can't locate object method "new" via package "MyAstar" at main.pl line 9.
I'm not sure what the problem is here. I would have expected, there to be a subroutine by the name new in the AI::Pathfinding::AStar package, but couldn't find it. Is the CPAN Module broken or am I doing something wrong?
You try to call a function (MyAstar->new, which conventionally is used as a constructor), but you don't define it. There is no default constructor in Perl (like in e.g., Java).
Add something like this to your MyAstar.pm:
sub new {
my $class = shift;
my $self = bless{}, $class;
# initialize $self here as needed, maybe using any passed arguments in #_
return $self;
}

In Perl, why do I get "undefined subroutine" in a perl module but not in main ?

I'm getting an "undefined subroutine" for sub2 in the code below but not for sub1.
This is the perl script (try.pl)...
#!/usr/bin/env perl
use strict;
use IO::CaptureOutput qw(capture_exec_combined);
use FindBin qw($Bin);
use lib "$Bin";
use try_common;
print "Running try.pl\n";
sub1("echo \"in sub1\"");
sub2("echo \"in sub2\"");
exit;
sub sub1 {
(my $cmd) = #_;
print "Executing... \"${cmd}\"\n";
my ($stdouterr, $success, $exit_code) = capture_exec_combined($cmd);
print "${stdouterr}\n";
return;
}
This is try_common.pm...
#! /usr/bin/env perl
use strict;
use IO::CaptureOutput qw(capture_exec_combined);
package try_common;
use Exporter;
our #ISA = qw(Exporter);
our #EXPORT = qw(
sub2
);
sub sub2 {
(my $cmd) = #_;
print "Executing... \"${cmd}\"\n";
my ($stdouterr, $success, $exit_code) = capture_exec_combined($cmd);
print "${stdouterr}\n";
return;
}
1;
When I run try.pl I get...
% ./try.pl
Running try.pl
Executing... "echo "in sub1""
in sub1
Executing... "echo "in sub2""
Undefined subroutine &try_common::capture_exec_combined called at
/home/me/PERL/try_common.pm line 20.
This looks like some kind of scoping issue because if I cut/paste the "use IO::CaptureOutput qw(capture_exec_combined);" as the first line of sub2, it works. This is not necessary in the try.pl (it runs sub1 OK), but a problem in the perl module. Hmmmm....
Thanks in Advance for any help!
You imported capture_exec_combined by the use clause before declaring the package, so it was imported into the main package, not the try_common. Move the package declaration further up.
You should take a look at the perlmod document to understand how modules work. In short:
When you use package A (in Perl 5), you change the namespace of the following code to A, and all global symbol (e.g. subroutine) definitions after that point will go into that package. Subroutines inside a scope need not be exported and may be used preceded by their scope name: A::function. This you seem to have found.
Perl uses package as a way to create modules and split code in different files, but also as the basis for its object orientation features.
Most of the times, modules are handled by a special core module called Exporter. See Exporter. This module uses some variables to know what to do, like #EXPORT, #EXPORT_OK or #ISA. The first defines the names that should be exported by default when you include the module with use Module. The second defines the names that may be exported (but need to be mentioned with use Module qw(name1 name2). The last tells in an object oriented fashion what your module is. If you don't care about object orientation, your module typically "is a" Exporter.
Also, as stated in another answer, when you define a module, the package module declaration should be the first thing to be in the file so anything after it will be under that scope.
I hate when I make this mistake although I don't make it much anymore. There are two habits you can develop:
Most likely, make the entire file the package. The first lines will be the package statement and no other package statements show up in the file.
Or, use the new PACKAGE BLOCK syntax and put everything for that package inside the block. I do this for small classes that I might need only locally:
package Foo {
# everything including use statements go in this block
}
I think I figured it out. If, in the perl module, I prefix the "capture_exec_combined" with "::", it works.
Still, why isn't this needed in the main, try.pl ?

Perl script to penetrate to sub directories

I have a long list of sub directories such that C0/C1/C2...C354. It individually contains respective files. I am trying to change the ownership of the directories (not the files in the directories). This is what I have wrote:
#!/usr/bin/perl -w
use strict;
use File::Find;
my #directories;
find sub{
print "$File::Find::name";
print "\n";
return unless -d;
next if (m/^\./);
push #directories, $File::Find::name;
}, ".";
foreach my $file (#directories){
my $cmd = qx |chown deep:deep $file|;
}
It goes uptil C0/C1 and stops penetrating into the other files. Is there a problem with my linux file-system or there is a limitation to the File::Find module in Perl. Please help. Thank you.
There is no loop inside the function given to File::Find::find but you still use "next" inside it. This will cause it to look for a loop outside the function and it will probably find it somewhere inside File::Find, thus causing erratic behavior.
You probably want to have a "return" instead of a "next".
And there should have been a (runtime) warning about it.

How do I dynamically discover packages from a partial namespace in perl?

I have a directory structure that looks like:
Foo::Bar::Baz::1
Foo::Bar::Baz::2 etc
Can I list the packages from something like:
use Foo::Bar::Baz;
Thanks!
Edit: Made it more clear what the modules are.
If you want to load all modules in your include path with a certain prefix (e.g. everything under a::b::c, you can use Module::Find.
For example:
use Module::Find 'useall';
my #loaded = useall 'Foo::Bar::Baz'; # loads everything under Foo::Bar::Baz
This depends on your #INC path being set up with the necessary directories, so do any required manipulation (e.g. with use lib) first.
Normally a script such as a/b/c.pl won't have a namespace other than main. Perhaps you are thinking of discovering modules with names such as a/b/c.pm (which is a bad name, since lower-cased package names are generally reserved for Perl internals).
However, given a directory path, you can look for potential Perl modules using File::Find:
use strict;
use warnings;
use File::Find;
use Data::Dumper;
my #modules;
sub wanted
{
push #modules, $_ if m/\.pm$/
}
find(\&wanted, 'A/B');
print "possible modules found:\n";
print Dumper(\#modules)'
This might be overkill, but you can inspect the symbol table before and after loading the module and see what changed:
use strict; use warnings;
my %original = map { $_ => 1 } get_namespaces("::");
require Inline;
print "New namespaces since 'require Inline' call are:\n";
my #new_namespaces = sort grep !defined $original{$_}, get_namespaces("::");
foreach my $new_namespace (#new_namespaces) {
print "\t$new_namespace\n";
}
sub get_namespaces {
# recursively inspect symbol table for known namespaces
my $pkg = shift;
my #namespace = ();
my %s = eval "%" . $pkg;
foreach my $key (grep /::$/, keys %s) {
next if $key eq "main::";
push #namespace, "$pkg$key", get_namespaces("$pkg$key");
}
return #namespace;
}
New namespaces since 'require Inline' call are:
::AutoLoader::
::Config::
::Digest::
::Digest::MD5::
::Dos::
::EPOC::
::Exporter::
::Exporter::Heavy::
::File::
::File::Spec::
::File::Spec::Cygwin::
::File::Spec::Unix::
::File::Spec::Win32::
::Inline::Files::
::Inline::denter::
::Scalar::
::Scalar::Util::
::Socket::
::VMS::
::VMS::Filespec::
::XSLoader::
::vars::
::warnings::register::
Just to be clear, are you looking at random packages in random Perl code?
Or for Perl modules, e.g. "a/b/c/d1.pm" with module "a::b::c::d1"?
In either case, you can not use a single "use" statement to load them all.
What you need to do is to find all the appropriate files, using either glob or File::Find.
In the first case (modules), you can then load them either by require-ing each file, OR by converting filename into module name (s#/#::#g; s#\.pm$##;) and calling use on each module individually.
As far as actual packages nested in random Perl files, those packages can be:
Listed by grepping each file (again, found via glob or File::Find) for /^package (.*);/
Actually loaded by executing require $file for each file.
In this case, please note that the package name for each of those packages in a/b/c/1.pl will NOT need to be related to "a::b::c" - e.g. they CAN be named by the file author "p1", "a::p1" or "a::b::c::p1_something".

How can I dynamically include Perl modules without using eval?

I need to dynamically include a Perl module, but if possible would like to stay away from eval due to work coding standards. This works:
$module = "My::module";
eval("use $module;");
But I need a way to do it without eval if possible. All google searches lead to the eval method, but none in any other way.
Is it possible to do it without eval?
Use require to load modules at runtime. It often a good idea to wrap this in a block (not string) eval in case the module can't be loaded.
eval {
require My::Module;
My::Module->import();
1;
} or do {
my $error = $#;
# Module load failed. You could recover, try loading
# an alternate module, die with $error...
# whatever's appropriate
};
The reason for the eval {...} or do {...} syntax and making a copy of $# is because $# is a global variable that can be set by many different things. You want to grab the value as atomically as possible to avoid a race condition where something else has set it to a different value.
If you don't know the name of the module until runtime you'll have to do the translation between module name (My::Module) and file name (My/Module.pm) manually:
my $module = 'My::Module';
eval {
(my $file = $module) =~ s|::|/|g;
require $file . '.pm';
$module->import();
1;
} or do {
my $error = $#;
# ...
};
How about using the core module Module::Load
With your example:
use Module::Load;
my $module = "My::module";
load $module;
"Module::Load - runtime require of both modules and files"
"load eliminates the need to know whether you are trying to require either a file or a module."
If it fails it will die with something of the like "Can't locate xxx in #INC (#INC contains: ...".
Well, there's always require as in
require 'My/Module.pm';
My::Module->import();
Note that you lose whatever effects you may have gotten from the import being called at compile time instead of runtime.
Edit: The tradeoffs between this and the eval way are: eval lets you use the normal module syntax and gives you a more explicit error if the module name is invalid (as opposed to merely not found). OTOH, the eval way is (potentially) more subject to arbitrary code injection.
No, it's not possible to without eval, as require() needs the bareword module name, as described at perldoc -f require. However, it's not an evil use of eval, as it doesn't allow injection of arbitrary code (assuming you have control over the contents of the file you are requireing, of course).
EDIT: Code amended below, but I'm leaving the first version up for completeness.
I use I used to use this little sugar module to do dynamic loads at runtime:
package MyApp::Util::RequireClass;
use strict;
use warnings;
use Exporter 'import'; # gives you Exporter's import() method directly
our #EXPORT_OK = qw(requireClass);
# Usage: requireClass(moduleName);
# does not do imports (wrong scope) -- you should do this after calling me: $class->import(#imports);
sub requireClass
{
my ($class) = #_;
eval "require $class" or do { die "Ack, can't load $class: $#" };
}
1;
PS. I'm staring at this definition (I wrote it quite a while ago) and I'm pondering adding this:
$class->export_to_level(1, undef, #imports);... it should work, but is not tested.
EDIT: version 2 now, much nicer without an eval (thanks ysth): :)
package MyApp::Util::RequireClass;
use strict;
use warnings;
use Exporter 'import'; # gives you Exporter's import() method directly
our #EXPORT_OK = qw(requireClass);
# Usage: requireClass(moduleName);
# does not do imports (wrong scope) -- you should do this after calling me: $class->import(#imports);
sub requireClass
{
my ($class) = #_;
(my $file = $class) =~ s|::|/|g;
$file .= '.pm';
require $file; # will die if there was an error
}
1;
Class::MOP on CPAN has a load_class method for this:
http://metacpan.org/pod/Class::MOP
i like doing things like..
require Win32::Console::ANSI if ( $^O eq "MSWin32" );