Issues using perl modules and passing variables into subroutines - perl

So I am new to the perl programing language and I want to get myself acquainted with creating, using, and passing parameters into modules. I made a hello world module that takes as a parameter two string variables from the main.pl testing program, one that says "hello" and another that says "world" and prints them out. Every time I try running main.pl I keep getting errors and I have spent many days trying to get this otherwise simple program to function correctly.
This is the code for my main.pl function:
use FindBin;
use lib $FindBin::Bin;
use test;
use strict;
my $firststring = "hello";
my $secondstring = "world";
test::printthing(\$firststring, \$secondstring);
And this is the coded for my test.pm module:
package test;
use strict
use Exporter;
our #ISA = qw/Exporter/;
our #EXPORT = qw/&main/;
sub printthing{
my $firstword = $_[0];
my $secondwork = $_[1];
print"$firstword\n";
print"$secondword\n";
}1;

You're missing the semicolon from the end of your use strict line in the module.
You try to export the main() subroutine, but your module doesn't have a subroutine called main().
You pass references to your variables to the subroutine but don't dereference them before printing them.
For the final point, you can either continue to pass in references, but dereference before printing.
test::printthing(\$firststring, \$secondstring);
# and then in the subroutine...
print"$$firstword\n";
print"$$secondword\n";
Or, you could just pass in the variables and ignore references completely.
test::printthing($firststring, $secondstring);
# and then in the subroutine...
print"$firstword\n";
print"$secondword\n";

Related

perl function definition fails with uninitialized value

My perl chops are a little stale so I'm probably missing something really obvious here, but I've added a small module to some older code CGI code to refactor common functions. Here is an excerpt of the module with the part that is giving me problems:
package Common;
use strict;
use warnings;
use base 'Exporter';
our #EXPORT_OK = (&fail_with_error);
sub fail_with_error {
my ($errmsg, $textcolor) = #_;
my $output = printf("<p><font color=\"%s\">ERROR: %s </font>/<p>", $textcolor, $errmsg);
print($output);
exit(1);
}
When I execute this module directly with perl Common.pm (or when I just import the function in test code, without even calling it) what I get is an uninitialized value error for $errmsg and $textcolor like this:
$ perl Common.pm
Use of uninitialized value $textcolor in printf at Common2.pm line 10.
Use of uninitialized value $errmsg in printf at Common2.pm line 10.
<p><font color="">ERROR: </font>/<p>1
It would seem that perl is giving the warning because it is executing the subroutine code literally, but the nature of a subroutine is that it is abstracted so different values can be passed in correct? It would stand to reason these shouldn't have to be populated to pass interpreter warnings, but nonetheless something is wrong.
I've searched around, but this error is very common because in most cases the variable really is uninitialized. I can't seem to find anything that applies to this type of case.
That's because you're accidentally populating #EXPORT_OK with a call to fail_with_error: &fail_with_error, instead of the function name. This calls fail_with_errors with the arguments populated from the current #_ which happens to be empty - so naturally both the variables are uninitialized (and also your function doesn't get exported). The correct assignment uses just the subroutine name:
our #EXPORT_OK = qw( fail_with_error );

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 ?

imported perl variable imports with no value

SOLVED: As it turns out, my problem was rooted in the fact that I was not putting a $ in front of DEBUGVAR in the #EXPORT_OK assignment and the "use config_global qw(config DEBUGVAR);" line. Since it raises no error, I had no way to know this was the issue. So, the fix is to place the proper syntax in front of your variables at these points.
So I am trying to get the hang of writing and importing perl modules. I don't know why it was made so difficult to do this, but I am having a great deal of trouble with this seeimingly trivial task. Here is the contents of my module:
package global_config;
use strict;
require Exporter;
our #ISA = qw(Exporter);
our #EXPORT_OK = qw(DEBUGVAR);
our ($DEBUGVAR);
our $DEBUGVAR = "Hello, World!";
return 1;
Here are the contents of my perl script that imports the module:
use strict;
use config_global qw(config, DEBUGVAR);
our %config;
our $DEBUGVAR;
print "variable imported with value: ".$DEBUGVAR;
The output is "variable imported with value:", and nothing else. My variable appears to be losing it's value. What am I doing wrong?
EDIT: After fiddling around a bit, and turning warnings on, I have isolated the issue to being that $DEBUGVAR is never actually imported. When I use it via $config_global:DEBUGVAR, it works as expected. The issue now is that it is not importing into the namespace. What gives?
I see several issues:
You should not use a comma in the qw() syntax. The qw takes each whitespace separated phrase and puts it in an array element.
These two are the same:
my #bar = qw(foo bar barfu); #No commas!
my #bar = ("foo", "bar", "barfu"); #Commas Required
If you're exporting a variable, you need to put the sigil in front of it.
You have:
our #EXPORT_OK = qw(DEBUGVAR);
It should be:
our #EXPORT_OK = qw($DEBUGVAR);
You should use the newer Exporter syntax:
Here's the newer Exporter Syntax:
package global_config;
use strict;
use warnings;
use Exporter 'import'; #Not "require". No need for "#ISA"
our #EXPORT_OK = qw(DEBUGVAR);
our $DEBUGVAR = "Hello, World";
1; #Makes no real difference, but you shouldn't say "return 1". Just standard.
Finally, what are you doing exporting variables? That's just a bad practice.
Exporting anything is now questioned -- even functions. It pollutes the user's namespace. (At least you're using #EXPORT_OKAY). Take a look at File::Spec. It uses fully qualified package names for its subroutines by default.
The variable in question is accessible via the full package name $global_config::DEBUGVAR, so there's no real need to export it.
What if everybody did it? Yes, you last heard of this excuse in kindergarten, but it applies here. Imagine if several modules exported $DEBUGVAR.
There are several ways around your quandary, but the best is to use object oriented Perl to help set this variable, and even allow users to change it.
package MyPackage;
use strict;
use warnings;
use feature qw(say);
sub new {
my $class = shift;
my $debug = shift; #Optional Debug Value
my $self = {};
bless $self, $class;
if (not defined $debug) {
$debug = "Hello, world!";
$self->Debug($debug);
return $self;
}
sub Debug {
my $self = shift;
my $debug = shift;
if (defined $debug) {
$self->{DEBUG} = $debug;
}
return $debug;
}
1;
To use this module, I simply create a new object, and Debug will be set for me:
use strict;
use warnings;
use MyPackage #No exporting needed
#Create an object w/ Debug value;
my $obj = MyPackage->new; #Debug is the default.
say $obj->Debug; #Prints "Hello, world!"
# Change the value of Debug
$obj->Debug("Foo!");
say $obj->Debug; #Now prints "Foo!"
#Create a new object with a different default debug
$obj2 = MyPackage->new("Bar!");
say $obj2->Debug; #Print "Bar!";
This solves several issues:
It allows multiple values of debug because each object now has its own values
There is no worry about namespace pollution or accessing package variables. Again, all you need is contained in the object itself.
It's easier to debug issues since the complexity is hidden inside the objects themselves.
It's the new preferred method, so you might as well get use to the syntax and be able to read object oriented Perl code. You'll be seeing it more and more.
While exporting variables from a package isn't necessarily a recommended practice, to do so, you need to use the actual name of the variable you are exporting. In this case it is $DEBUGVAR and not DEBUGVAR which would be the name of a subroutine.
In the script using the config module, you do not need to declare the $DEBUGVAR variable as our, since imported variables are exempt from strict vars.
You have gotten the name mixed up, it looks like:
use config_global ...
package global_config;
Though one would think that would issue warnings. Unless you are not using warnings...?
ETA:
our #EXPORT_OK = qw($DEBUGVAR);
^
Also, you have two declarations on that variable. You really need to use warnings when debugging, otherwise, you'll never get anywhere.
Are you sure you want a comma here:
use config_global qw(config, DEBUGVAR);
Also, you aren't exporting config, so it might work better as:
use config_global qw(DEBUGVAR);
I'd also remove the last our $DEBUGVAR; since it might set it to undef (or at least put it before the "use" line) -- I am not sure about this though.

Modifications to local perl module not recognized

I have a single perl subroutine in a file of its own. It is called separately by two different perl scripts. I have modified the list of arguments passed in, and made the necessary changes in both calling scripts, but only one script does what I expect. When I use the perl debugger on the other one, when the debugger steps into the subroutine in the module, it shows me the way the module looked before I edited it. So when I run that script, it is passing in the new argument list, but the module is trying to assign them the old way, which clearly is wrong.
What could cause this? Why does one script work correctly and the other one not?
For specifics, yes I'm using strict and warnings.
Old:
use strict;
use warnings;
use lib("/absolute/path/to/module"); #mymodule.pm lives here
use packagename;
my $string = "foo";
my %Hash = my_sub($foo);
and in the module:
package packagename;
use strict;
use warnings;
use Exporter;
use vars qw(#ISA #EXPORT #EXPORT_OK);
#ISA = qw( Exporter );
#EXPORT = qw(my_sub);
#EXPORT_OK = qw(my_sub);
sub my_sub {
my $string = $_[0];
my %Hash;
...
return %Hash;
}
I've added an array reference to the arguments. New to the calling script are:
my #array = qw(Zero One Two);
my %Hash = my_sub(\#array, $string);
New to the module:
sub my_sub {
my (#array) = #{$_[0]};
my $string = $_[1];
}
When I run my script with the debugger and step into this module, it shows my $string being assigned from $_[0] as the first line of the subroutine, just as though I never changed the module.
Again, this only happens with one of my scripts but the other one works fine. Everything is in the same directory. I'm running this on linux, perl 5.10. I'm baffled!
I would guess that the scripts are loading different copies of the module, and you only modified one copy. Try adding
print $INC{'packagename.pm'}."\n";
after the use packagename line in each script. (Don't forget to replace :: with / in packagename, if any.) That will tell you if the scripts are really loading the same module.

Why can't my Perl script see the our() variables I defined in another file?

I have a question relating to Perl and scoping. I have a common file with lots of various variables. I require the common file in my main script, but I cannot access the variables; they seem to be outside of its scope. I assumed that an our declaration would overcome that problem, but it doesn't seem to work.
Script 1: common.pl
#!/usr/bin/perl
our $var1 = "something";
our $var2 = "somethingelse";
Script 2: ftp.pl
#!/usr/bin/perl
use strict;
use warnings;
require('common.pl');
print $var1;
I get the error: Global symbol "$var1" requires explicit package name
There's no require statement in your second example, but it wouldn't work anyway. What our does is declare a lexically-scoped package variable. Since you have no package statement, it uses the default package main. So your first script sets up the variable $main::var1, but this will only be available within that file's scope.
A better way to provide common variables for other scripts is to use Exporter. You can define package symbols in one place and Exporter will take care of copying them to the requesting script or class's namespace when needed.
I would put the config in a module instead.
File: MyConfig.pm
package MyConfig;
require Exporter;
use strict;
our #ISA = qw(Exporter);
our #EXPORT = qw( getconfig );
my %confighash = (
thisone => 'one',
thatone => 2,
somthingelse => 'froboz',
);
sub getconfig {
return %confighash;
}
1;
Example usage:
#!/usr/bin/perl
use strict;
use warnings;
use MyConfig;
my %config = getconfig();
print $config{ somthingelse };
This should print froboz
It looks like you need a proper configuration file there. I'd go for a non-code configuration file that you can read when you need to setup things. There are modules on CPAN to handle just about any configuration format you can imagine.
If you want to do it the way you have it, get rid of our and declare them with use vars. Don't let the PBP police scare you off that. :) You only really need our to limit a scope of a package variable, and that's exactly the opposite of what you are trying to do.
our() does something a little different than you think. Its sole purpose is to work with strict in requiring you to declare package variables that you are going to use (unless they are fully-qualified or imported). Like strict, its effect is lexically-scoped. To use it to allow accessing a global $main:var1 from multiple files (which are separate scopes) as just $var1, you need to say our $var1 in each file.
Alternatively, you would change your required file to be a module with its own package that exports the variables to any package that uses it.
Try this. I am new at Perl but this is how I got it to work on a script I made
#!/usr/bin/perl
$var1 = "something";
$var2 = "somethingelse";
Script 2: ftp.pl
#!/usr/bin/perl
use strict;
use warnings;
our $var1;
our $var2;
require('common.pl');
print $var1;