The "wrong" package specification is required to call a subroutine - perl

I would like to ask you for advice on writing a Perl module. We have three files.
(1) main.pl : uses my_function()
#!/usr/bin/perl
use strict;
use warnings;
use MyClass;
require "./subroutines.pl";
my $instance = MyClass->new({});
$instance->my_method("a");
MyClass::my_function("b"); # This works.
my_function("c"); # Undefined subroutine &main::my_function called
exit;
(2) MyClass.pm : defines MyClass class. my_method() uses my_function() which is defined in "subroutines.pl".
package MyClass;
use strict;
use warnings;
require "./subroutines.pl";
sub new {
my $class = shift;
my $self = shift;
return bless $self, $class;
}
sub my_method{
my $self = shift;
my $text = shift;
my_function($text);
}
1;
(3) subroutines.pl : defines my_function().
use strict;
use warnings;
sub my_function {
print "[$_[0]] My function is working!\n";
}
1;
The problem is that my_function() is not working in main.pl, even though the source code has require "./subroutines.pl", while MyClass::my_function() works.
[a] My function is working!
[b] My function is working!
Undefined subroutine &main::my_function called at main.pl line 11.
Because my_function() is useful for me, I want to use it in both main.pl and MyClass.pm, but the subroutine is so general that it is quite strange to define it as a method in MyClass.pm. But it is also strange (to me) that we have to write MyClass:: before my_function(), because the subroutine does not depend on MyClass.
My question is: is it possible to modify the above codes so that my_function() works in main.pl without adding MyClass:: before the function call?

require only executes a given file once, so you would need do, but that would created two copies of the subroutine. Use a proper module instead, and use Exporter to export the symbol.
Subroutines.pm:
package Subroutines;
use strict;
use warnings;
use Exporter qw( import );
our #EXPORT = qw( my_function );
sub my_function {
print "[$_[0]] My function is working!\n";
}
1;
and
use Subroutines;

Related

Not able to export methods using Exporter module in perl

I'm trying to export the methods written in my custom module using Exporter perl module. Below is my custom module ops.pm
use strict;
use warnings;
use Exporter;
package ops;
our #ISA= qw/Exporter/;
our #EXPORT=qw/add/;
our #EXPORT_OK=qw/mutliply/;
sub new
{
my $class=shift;
my $self={};
bless($self,$class);
return $self;
}
sub add
{
my $self=shift;
my $num1=shift;
my $num2=shift;
return $num1+$num2;
}
sub mutliply
{
my $self=shift;
my $num1=shift;
my $num2=shift;
return $num1*$num2;
}
1;
Below is the script ops_export.pl using ops.pm
#!/usr/bin/perl
use strict;
use warnings;
use ops;
my $num=add(1,2);
print "$num\n";
when i execute the above script i'm getting below error.
Undefined subroutine &main::add called at ops_export.pl line 8.
I'm not getting why my script is checking in &main package even though i have exported the add in ops.pm using #EXPORT
Where am i going wrong?
ops is a pragma already used by Perl. From the docs:
ops - Perl pragma to restrict unsafe operations when compiling
I don't know what that actually means but that's the issue here.
Rename your module to something else, preferably something with uppercase characters as #simbabque suggests in a comment, because lowercase "modules" are somehow reserved for pragmas (think of warnings or strict).
Also: Calling your add function won't work because you mix up OO code and regular functions. Your add expects three parameters and you supply only two (1 and 2).
When writing OO modules you shouldn't export anything (not even new), i.e.:
package Oops;
use strict; use warnings;
use OtherModules;
# don't mention 'Export' at all
sub new {
...
}
sub add {
...
}
1;
And then in your scripts:
use strict; use warnings;
use Oops;
my $calculator = Oops->new();
my $result = $calculator->add(1, 2);
print $result, "\n"; # gives 3

How to create a dynamic subroutine name in perl

I want to create a dynamic subroutine name in perl, Here is trial code , I am getting error "Bad name after feed_load::"
#!/usr/bin/perl
use strict;
use warnings;
BEGIN {
push #INC, '/freespace/attlas/data/bin/genericLoader /FeedLoaderLib/'
}
use feed_load;
my type ="L";
my $tempTablefunct = "Create".$type."Temp_Table";
feed_load::&$tempTablefunct->($tablename); ### pass a dynamic sub name HERE ###
&{ $pkg_name."::".$sub_name }(#args)
or
( $pkg_name."::".$sub_name )->(#args)
These will fail, however, because you asked Perl to forbid you from doing this by placing use strict; in your program. You can disable use strict; locally
my $ref = do { no strict 'refs'; \&{ $pkg_name."::".$sub_name } };
$ref->(#args)
But it turns out that \&$sub_name is already exempt from strictures.
my $ref = \&{ $pkg_name."::".$sub_name };
$ref->(#args)
If instead of sub call, you needed a method call, you can use
my $ref = $o->can($method_name);
$o->$ref(#args)
or just
$o->$method_name(#args)

Undefined subroutine error in perl package

This is main file upload.cgi
#!/usr/bin/perl
use strict;
use lib '.';
use XFSConfig;
use XUpload ;
use CGI::Carp qw(fatalsToBrowser);
use CGI;
use Fcntl ':flock';
use LWP::UserAgent;
use HTTP::Cookies;
use HTML::Form;
use Encode;
sub xmessage
{
my ($msg) = #_;
&lmsg($msg);
$msg=~s/'/\\'/g;
$msg=~s/<br>/\\n/g;
print"Content-type: text/html\n\n";
print"<HTML><HEAD><Script>alert('$msg');</Script></HEAD><BODY><b>$msg</b></BODY></HTML>";
exit;
}
sub lmsg
{
my $msg = shift;
open(F,">$c->{htdocs_tmp_dir}/$sid.html");
print F qq[new Object({"state":"error", "msg":"$msg"})];
close F;
&logit($msg);
}
and this function calls a function
&XUpload::ProcessFile()
and XUpload::ProcessFile() function calls a function &xmessage("Fatal"); which is defined in upload.cgi
and now i get this error
Undefined subroutine &XUpload::xmessage called at Modules/XUpload.pm line 17.
It seems package XUpload is unable to find function xmessage defined in upload.cgi at all
The xmessage sub in your cgi script is defined in the main package, while the XUpload module is (apparently) operating in the XUpload namespace.
Resolving this issue will ultimately involve learning about Perl's namespaces and the Exporter module. But a quick and dirty fix is to create an alias for your sub in the XUpload package. Add this line to your main script:
*XUpload::xmessage = *message;

Perl : Like in java we can access public member (variables) in other class is there any same concept in perl

I have 2 perl file and i want to use value of one variable in another perl file as input so how i can do it is there any concept like java we can declare it as public and use it.
any help appreciated thank you!
In this answer, I'll skip the discussion about whether it is the right decision to use OOP or not and just assume you want to do it the OOP-way.
In short, all variables of an object in Perl can be considered public. In fact, the problem is often the opposite - to make some of them private. Anyway, if you have a file Obj.pm which defines an object with a field foo which looks like this:
package Obj;
sub new {
my $class = shift;
my $self = {foo => "bar"};
bless $self, $class;
return $self;
}
you can access the foo variable as if it were public:
use Obj;
my $obj = Obj->new();
print $obj->{foo};
For perhaps a more pleasant OOP in Perl, look at the Moose package which gives you more flexibility.
As #user2864740 pointed you don't need "OO" in perl to share variables.It is one way, Let's say you have two files
Foo.pm(package):
#!/usr/bin/perl
use strict;
use warnings;
use Exporter;
package Foo;
our #ISA = qw(Exporter);
our #EXPORT = qw( blat); #exported by default
our #EXPORT_OK = qw(bar );#not exported by default
our $x="42";#variable to be shared should be "our" not "my"
sub bar {
print "Hello $_[0]\n"
}
sub blat {
print "World $_[0]\n"
}
1;
Access that variable from other file as
bar.pl :
#!/usr/bin/perl
use strict;
use warnings;
use Foo;
print "$Foo::x";#imported variable
blat("hello");#imported subroutine
If you want to import listed functions then:
#!/usr/bin/perl
use strict;
use warnings;
use Foo qw(bar blat);# import listed subs
print "$Foo::x";#imported variable
blat("hello ");#imported subroutine
bar("hi");#this also get imported

Why does my Perl program complain about needing explicit package names?

I have a module Routines.pm:
package Routines;
use strict;
use Exporter;
sub load_shortest_path_matrices {
my %predecessor_matrix = shift;
my %shortestpath_matrix = shift;
...
}
From another script I call the sub in the module, passing in arguments which happen to have the same name:
use Routines;
use strict;
my %predecessor_matrix = ();
my %shortestpath_matrix =();
&Routines::load_shortest_path_matrices($predecessor_matrix, $shortestpath_matrix);
However, this doesn't compile and I get
Global symbol "$predecessor_matrix" requires explicit package name
type of errors. Is it not possible to give the same name to variables in different scopes like this in Perl? (I'm from a C background)
$predecessor_matrix is a scalar and %predecessor_matrix is a hash. Different types in Perl (scalar, array, hash, function, and filehandle) have different entries in the symbol table, and, therefore, can have the same name.
Also, you have a problem in your function. It expects to be able to get two hashes from #_, but a hash in list context (such as in the argument list of a function) yields a list of key value pairs. So, both %predecessor_matrix and %shortestpath_matrix will wind up in the %predecessor_matrix of the function. What you need to do here is to use references:
package Routines;
use strict;
use Exporter;
sub load_shortest_path_matrices {
my $predecessor_matrix = shift;
my $shortestpath_matrix = shift;
$predecessor_matrix->{key} = "value";
...
}
and
use Routines;
use strict;
my %predecessor_matrix;
my %shortestpath_matrix;
Routines::load_shortest_path_matrices(
\%predecessor_matrix,
\%shortestpath_matrix
);
However, passing in structures to load as arguments is more C-like than Perl-like. Perl can return more than one value, so it is more common to see code like:
package Routines;
use strict;
use Exporter;
sub load_shortest_path_matrices {
my %predecessor_matrix;
my %shortestpath_matrix;
...
return \%predecessor_matrix, \%shortestpath_matrix;
}
and
use Routines;
use strict;
my ($predecessor_matrix, $shortestpath_matrix) =
Routines::load_shortest_path_matrices();
for my $key (keys %$predecessor_matrix) {
print "$key => $predecessor_matrix->{$key}\n";
}
you are declaring the hash %predecessor_matrix but are trying to pass the scalar $predecessor_matrix. The hash exists, the scalar doesn't.
Maybe you want to pass references to the hashes?
Routines::load_shortest_path_matrices(\%predecessor_matrix, \%shortestpath_matrix);
Here's another way to code it:
use strict;
use warnings;
use Routines;
my $predecessor_matrix = {};
my $shortestpath_matrix ={};
Routines::load_shortest_path_matrices( $predecessor_matrix
, $shortestpath_matrix
);
package Routines;
use strict;
use Exporter;
sub load_shortest_path_matrices {
my $predecessor_matrix = shift;
my $shortestpath_matrix = shift;
...
}
you can access the contents of the hashes like this
my $foobar=$shortestpath_matrix->{FOOBAR};