In Perl, is there any way to tell which .pl script has initialized this instance of a module?
Specifically, I'd like to get the name of the script calling a module, which has a Log4perl object it. That way, I'll know which .log file I want to write to within the module.
Am I doing this wrong? If I define the $logger in my .pl script, will any $logger calls within the module write to the same .log file as the calling script?
I don't have any sample code yet, but have been reading up on Log4perl. Basically, if I set an Appender to a file, caller.log, which is the file appender for my calling script, caller.pl, I'd want any logging defined in the custom imported module, to also write to caller.log (implicitly, if possible -- obviously I could just pass the name of the log name when I initialize the module instance).
Is this possible without passing arguments specifying which File Appender the module should write to? Doesn't Log4perl use just one $logger instance?
Also, let me know if I'm way out, and if there's a different approach I should be considering.
Thank you
EDIT: Sorry, after I posted this, I looked at the Related Links, and I guess my search wording just wasn't correct. It looks like this is a pretty good solution: Self logging Perl modules (without Moose)
If anyone has any other ideas, though, please let me know.
EDIT 2: Finally tested, and got it to work as I had wanted -- was a lot easier than was making it out to be, too!
This is my setup, pretty much:
Module.pm
package Module;
use Log::Log4perl qw(get_logger :levels);
use Data::Dumper;
my $logger = get_logger("Module");
sub new {
my ($class, $name) = #_;
my #caller = caller(0);
$logger->debug("Creating new Module. Called by " . Dumper(\#caller));
my $object = { 'name' => $name };
return bless($object, $class);
}
caller.pl
use Module;
use Log::Log4perl qw(get_logger :levels);
use Data::Dumper;
my $PATH = "$ENV{'APPS'}/$ENV{'OUTDIR'}";
my $SCRIPT = "caller";
my $logger = get_logger("Module");
$logger->level($DEBUG);
my $file_appender = Log::Log4perl::Appender->new("Log::Dispatch::File",
filename=> "$PATH/$SCRIPT.log",
mode => "append",);
$logger->add_appender($file_appender);
my $layout = Log::Log4perl::Layout::PatternLayout->new("%d %p> %F{1}:%L %M - %m%n");
$file_appender->layout($layout);
my $lib = Module->new('Chris');
$logger->info(Dumper($lib));
You could subclass Log4perl, overriding its constructor. In your custom constructor, use caller() to get the filename that called the constructor and put it in $self.
You can put a subroutine hook into #INC that can run arbitrary code, as documented in perldoc -f require. For example:
# UseLogger.pm
package UseLogger;
sub import { unshift #INC, \&UseLogger::log_use }
sub log_use {
my ($self, $filename) = #_;
my #c = caller(0);
print "Module $filename required in file $c[1] line $c[2]\n";
return 0;
}
1;
$ perl -MUseLogger my_script.pl
Module feature.pm required in file my_script.pl line 2
Module Encode.pm required in file my_script.pl line 5
Module XSLoader.pm from /usr/lib/perl5/5.14.0/cygwin-thread-multi-64int/Encode.pm line 13
...
$0 contains the path to the script. You can use File::Basename's basename if you want to want the file name component.
Related
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 ?
I'm working with ugly code and trying to do a cleanup by moving values in a module into a configuration file. I want to keep the modules default values if a variable doesn't exist in the conf file, otherwise use the conf file version. There are lots of variables (too many) in the module so I wanted a helper method to support this. This is a first refactoring step, I likely will go further to better handle config variables later, but one step at a time.
I want a method that would take a variable in my module and either load the value from conf or set a default. So something like this (writing this from scratch, so treat it as just pseudocode for now)
Our ($var_a, $var_b ...);
export($var_a, $var_b ...);
my %conf = #load config file
load_var(\$var_a, "foo");
load_var(\$var_b, "$var_abar");
sub load_var($$){
my($variable_ref, $default) = #_
my $variale_name = Dumper($$variable_ref); #get name of variable
my $variable_value = $conf{$variable_name} // $default;
#update original variable by having $variable_ref point to $variable_value
}
So two questions here. First, does anyone know if some functionality like my load_var already exists which I an reuse?
Second, if I have to write it from scratch, can i do it with a perl version older then 5.22? when I read perlref it refers to setting references as being a new feature in 5.22, but it seems odd that such a basic behavior of references wasn't implemented sooner, so I'm wonder if I'm misunderstanding the document. Is there a way to pass a variable to my load_var method and ensure it's actually updated?
For this sort of problem, I would be thinking along the lines of using the AUTOLOAD - I know it's not quite what you asked, but it's sort of doing a similar thing:
If you call a subroutine that is undefined, you would ordinarily get an immediate, fatal error complaining that the subroutine doesn't exist. (Likewise for subroutines being used as methods, when the method doesn't exist in any base class of the class's package.) However, if an AUTOLOAD subroutine is defined in the package or packages used to locate the original subroutine, then that AUTOLOAD subroutine is called with the arguments that would have been passed to the original subroutine.
Something like:
#!/usr/bin/env perl
package Narf;
use Data::Dumper;
use strict;
use warnings;
our $AUTOLOAD;
my %conf = ( fish => 1,
carrot => "banana" );
sub AUTOLOAD {
print "Loading $AUTOLOAD\n";
##read config file
my $target = $AUTOLOAD =~ s/.*:://gr;
print $target;
return $conf{$target} // 0;
}
sub boo {
print "Boo!\n";
}
You can either call it OO style, or just 'normally' - but bear in mind this creates subs, not variables, so you might need to specify the package (or otherwise 'force' an import/export)
#!/usr/bin/env perl
use strict;
use warnings;
use Narf;
print Narf::fish(),"\n";
print Narf::carrot(),"\n";
print Narf::somethingelse(),"\n";
print Narf::boo;
Note - as these are autoloaded, they're not in the local namespace. Related to variables you've got this perlmonks discussion but I'm not convinced that's a good line to take, for all the reasons outlined in Why it's stupid to `use a variable as a variable name'
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How do you create a Perl module?
I have the script that reads an xml file and creates hash table. its working properly but now i need to create module for that code, that i can call in my main function.In my main function file path as input and it gives output as hash. now i need to create module for this code.
#!/usr/bin/perl
use warnings;
use strict;
use XML::LibXML::Reader;
#Reading XML with a pull parser
my $file;
open( $file, 'formal.xml');
my $reader = XML::LibXML::Reader->new( IO => $file ) or die ("unable to open file");
my %nums;
while ($reader->nextElement( 'Data' ) ) {
my $des = $reader->readOuterXml();
$reader->nextElement( 'Number' );
my $desnode = $reader->readInnerXml();
$nums{$desnode}= $des;
print( " NUMBER: $desnode\n" );
print( " Datainfo: $des\n" );
}
how can i create module for this code?
You need to create a file with .pm extension, i.e. "MyModule.pm" with this code:
package MyModule;
use warnings;
use strict;
use XML::LibXML::Reader;
sub mi_function_name {
#Reading XML with a pull parser
my $file;
open( $file, 'formal.xml');
my $reader = XML::LibXML::Reader->new( IO => $file ) or die ("unable to open file");
my %nums;
while ($reader->nextElement( 'Data' ) ) {
my $des = $reader->readOuterXml();
$reader->nextElement( 'Number' );
my $desnode = $reader->readInnerXml();
$nums{$desnode}= $des;
print( " NUMBER: $desnode\n" );
print( " Datainfo: $des\n" );
}
}
1; #this is important
And in the file you want to use this module:
use MyModule;
#...
MyModule::mi_function_name;
This is a very simple and basic usage of a module, I recommend the lecture of better tutorials (http://www.perlmonks.org/?node_id=102347) to gain further knowledge on this
Take a look at the Perl Documentation. One of the tutorials included is perlmod. This offers a lot of good information.
First step: Make your program into a subroutine. That way, you can call it your code. I've taken the liberty to do that:
#!/usr/bin/perl
use warnings;
use strict;
use Carp;
use XML::LibXML::Reader;
#Reading XML with a pull parser
sub myFunction {
my $fh = shift; #File Handle (should be opened before calling
my $reader = XML::LibXML::Reader->new( IO => $fh )
or croak ("unable to open file");
my %nums;
while ($reader->nextElement( 'Data' ) ) {
my $des = $reader->readOuterXml();
$reader->nextElement( 'Number' );
my $desnode = $reader->readInnerXml();
$nums{$desnode} = $des;
}
return %nums;
}
1;
I've made a wee change. You notice that I no longer open a file. Instead, you'll pass a file handle to your MyFunction subroutine. Second, instead of printing out $desnode and $des, it now returns a hash that has these values in them. You don't want subroutines to output data. You want them to return the data, and let your program decide what to do with the information.
I've also put in a use Carp; line. Carp gives you two functions (as well as a few others). One is called carp which is a replacement for warning, and the other is called croak which is a replacement for die. What these two functions do is report the line number in the user's program which called your function. That way, the user doesn't see the error in your module, but their program.
I've also added the line 1; at the bottom of your program. When a module loads, if it returns a zero on load, the load fails. Thus, your last statement should return a non-zero value. The 1; guarantees it.
Now that we have a subroutine that you can return, let's make your program into a module.
To create a module, all you have to do is say package <moduleName> on top of your program. And, also make sure that the last statement executes with a non-zero value. The tradition is just to put a 1; as the last line of the program. Modules names end with a .pm suffix by default. Modules names can have components in the names separated by double colons. For example File::Basename. In that case, the module, Basename.pm lives in the directory File somewhere in the #INC list of directories (which, by default includes the current directory).
The package command simply creates a separate namespace, so your package variables and functions don't collide with the names of the variables and functions inside the program that uses your package.
If you use an object oriented interface, there's no reason why you need to export anything. The program that uses your module will simply use the object oriented syntax. If your module is function based, you probably want to export your function names into the main program.
For example, let's take File::Basename. This module imports the function basename and dirname into your program. This allows you to do this:
my $directoryName = dirname $fileName;
Instead of having to do this:
my $direcotryName = File::Basename::dirname $fileName;
To export a function, make sure your module uses the Exporter module, and then set the package variable #EXPORT_OK or #EXPORT to contain the list of functions you're allowing to be exported in the user's program. The difference is that if you say #EXPORT_OK, the functions will be exported, but the user must request each one. If you use #EXPORT, all those functions will automatically be exported.
Using your program as a basis, your module will be called Mypackage.pm and look like this:
#!/usr/bin/perl
package Mymodule;
use warnings;
use strict;
use Exporter qw(import);
use Carp;
use XML::LibXML::Reader;
our #EXPORT_OK(myFunction);
#Reading XML with a pull parser
sub MyFunction {
my $fh = shift; #File Handle (should be opened before calling
my $reader = XML::LibXML::Reader->new( IO => $fh )
or die ("unable to open file");
my %nums;
while ($reader->nextElement( 'Data' ) ) {
my $des = $reader->readOuterXml();
$reader->nextElement( 'Number' );
my $desnode = $reader->readInnerXml();
$nums{$desnode}= $des;
}
return %nums;
}
1;
The big thing is the use of:
package Mypackage
use Exporter qw(import)
our #EXPORT_OK qw(myFunction);
The package function sets up an independent name space, so your variables and function names don't override (or get overwritten) by the user's program.
The use Exporter says that your program is using the import function of the Exporter module. This allows you to import variables and functions into the main namespace of the user's program. That way, the user can simply refer to your function as mi_function_name instead of Mypackage::my_function_name. In theory, you don't have to export anything, and newer modules don't. These module are entirely object oriented or just don't want to bother with namespace issues.
The #EXPORT_OK array says what you're exporting. This is preferred over #EXPORT. With #EXPORT_OK, the developer must specify what functions he wants to import into their program. With #EXPORT, this is done automatically.
In the program that uses your module, you'll need to do this:
use Mypackage qw(myFunction);
Now, all you have to do in your program is
my %returnedHash = myFunction($fh);
Now, things are constantly evolving in Perl, and I've never received any formal training. I simply read the documentation and take a look at various examples and hope that I understand them correctly. So, if someone might say that I'm doing something wrong, they're probably correct. I've also didn't test any of the code. I might have screwed something in your program when I turned it into a subroutine.
However, the gist should be correct: You need to make your code into callable subroutines that return the information you need. Then, you can turn it into a module. It's not all that difficult to do.
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".
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" );