How to create a dynamic subroutine name in perl - 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)

Related

Error in Perl Rose::DB : Can't use string ... as a HASH ref while "strict"

I am getting an error when using Rose::DB.
#MyApp/DB.pm
package MyIMDB::DB;
use strict; use warnings;
use base qw(Rose::DB);
__PACKAGE__->use_private_registry;
__PACKAGE__->register_db (
driver => 'SQLite',
....
);
1;
# MyApp/DB/Object.pm
package MyApp::DB::Object;
use strict; use warnings;
use MyApp::DB;
use base qw(Rose::DB::Object);
sub init_db { MyIMDB::DB->new }
1;
#
package MyApp::Users; #controller
use strict; use warnings;
use base 'Mojolicious::Controller';
use Mojo::ByteStream 'b';
use MyApp::Models::User;
use Data::Dumper;
sub my_action {
my $uc = shift;
my $err = MyApp::Models::User::->validate(...); #extra ::
# http://perldoc.perl.org/perlobj.html#Invoking-Class-Methods
}
# MyApp/Models/User.pm # 2 packages in this file
package MyApp::Models::User::Manager;
use base qw(Rose::DB::Object::Manager);
use MyApp::Models::User;
sub object_class { 'MyApp::Models::User'}
__PACKAGE__->make_manager_methods('users');
# class methods get_x, get_x_iterator, get_x_count, delete_x, update_x
1;
MyApp::Models::User
use strict; use warnings;
use base qw(MyApp::DB::Object);
__PACKAGE__->meta->setup(
#setup tables, columns....
);
sub validate {
my $u = shift;
my $n = MyApp::Models::User::Manager::->get_users_count(query => [user_name => $user]);
}
1;
The error I get is:
"Can't use string ("MyApp::Models::User") as a HASH ref while "strict refs"
in use at /usr/local/share/perl/5.18.2/Rose/DB/Object.pm line 91, <DATA> line 2231."
The entry point is my_action() method of MyApp:Users class.
I tried alternative setups of creating class MyApp::Models::User::Manager : separate .pm file, make_manager_class(), but to no avail.
(I found this discussion from 2007 with the same error message, but it does not help me out http://comments.gmane.org/gmane.comp.lang.perl.modules.dbi.rose-db-object/1537).
This may indicate I am trying to call an object method as if it were a class method. I tried the tricks listed here http://perldoc.perl.org/perlobj.html#Invoking-Class-Methods, but no success.
I now I can examine the contents of variables with Data::Dumper, but I have no clue what to dump as there are very little data structures used.
While use strict is a good idea when writing Perl code, you may want to relax the strict-ness by adding
no strict `refs`;
to get past the current error. As #ikegami pointed out another way to fix this is to get rid of the bad reference, but if you don't want to rewrite the module working around it with relaxing strict-ness is your best bet.

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

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;

In Perl, how to share a variable between subroutines, with use strict?

If I don't use strict; the following code works fine and prints out "alice":
assign_name();
print_name();
sub assign_name {
$name = "alice";
}
sub print_name {
print $name;
}
However when I do use strict; then I know I'll have to declare the variable before using it. I read somewhere I should use our instead of my to declare a global variable. So I had the following:
use strict;
use warnings;
assign_name();
print_name();
sub assign_name {
our $name = "alice";
}
sub print_name {
print $name; # This is line 12.
}
And then I get the following error:
Variable "$name" is not imported at test.pl line 12.
Global symbol "$name" requires explicit package name at test.pl line 12.
Execution of test.pl aborted due to compilation errors.
Please help.
Just declare the variable where both subs can see it.
use strict;
use warnings;
my $name;
assign_name();
print_name();
sub assign_name {
$name = "alice";
}
sub print_name {
print $name;
}
(There's no reason to use our here!)
I know this is beyond the scope of your question, and ikegami's answer answers it nicely, still I think there is more to be said. If you have functions that are mean to change package-scoped variables, likely you could do better rewriting those variables as object attributes. In Perl we can do that using Moose.
#!/usr/bin/env perl
use strict;
use warnings;
{ # proper use of scoping, h/t tchrist
package Person;
use Moose;
use namespace::autoclean; # recommended
has 'name' => ( is => 'rw', isa => 'Str', required => 1);
__PACKAGE__->meta->make_immutable; # recommended
}
my $person = Person->new( name => 'Joel' );
$person->name( 'Adam' ); # change name
print $person->name . "\n";
In this example we make a name attribute, we can set it during object construction, then change it or view it using accessor methods. The data that would have been global, in this case the name, is then contained inside the object's internal data. This allows different parts of your code to reuse that same logic without worrying about the state of that global data.
You should declare the global variable upper :
use strict;
use warnings;
my $name;
assign_name();
print_name();
sub assign_name {
$name = "alice";
}
sub print_name {
print $name; # This is line 12.
}

How to replace package name with a variable when using strictures

I have two Perl packages: pack_hash and pack_run
package pack_hash;
$VERSION = '1.00';
#ISA = qw( Exporter );
#EXPORT_OK = qw( %hashInfo );
$hashInfo{abc} = ['a', 'b', 'c'];
1;
package pack_run;
use stricts;
use warnings;
use Data::Dumper;
use pack_hash qw( %hashInfo );
somethingDoing();
sub somethingDoing {
my $var1 = \%pack_hash::hashInfo; # getting the hash reference
print Dumper($var1);
...
...
}
1;
Can anyone please let me know, whether it is possible to replace the name of the hash-package (pack_hash), by using any variable, like:
my $pakVar = "pack_hash";
my $var1 = \%$pakVar::hashInfo;
I, know it is WRONG/NOT_CORRECT, but I want this kind of symbolic ref transformation, when I'm using strictures.
I also wanted to know, whether it is possible to do the thing with eval. But I want a final variable, here $var1, which will refer the particular hash (hashInfo);
No, that is not possible. But this is:
use strict;
use warnings;
use Symbol qw<qualify_to_ref>;
my $pakVar = 'pack_hash';
my $var1 = *{ qualify_to_ref( 'hashInfo', $pakVar ) }{HASH};
qualify_to_ref takes the name of a package variable and the package name and returns a GLOB reference pointer, then you just access the HASH slot of the GLOB. You can also do it this way:
my $var1 = \%{ qualify_to_ref( 'hashInfo', $pakVar ) };
But it is just as easy to turn off strict in a very tight do as well;
my $var1
= do {
no strict;
\%{ $pakVar . '::hashInfo' };
};
I understand that some coding cultures consider turning off strict or warnings as "cheating". I know that I've had code review questions about turning off one class of warning in a small block like this. I knew which warnings I was going to get, so I didn't need it. The reviewer didn't see it this way.
For this reason some veteran Perl-ers think nothing about turning off strict. But if you can't because it makes the natives restless--you can use Symbol. However, some shops have rules against package variables, so it never becomes an issue.
If you have a class method that returns a reference to the hash:
package pack_hash;
use strict;
use warnings;
our %hashInfo;
$hashInfo{abc} = ['a', 'b', 'c'];
sub hashInfo { \%hashInfo }
then you can easily get the reference:
use strict;
use warnings;
my $pakVar = 'pack_hash';
my $hashInfo = $pakVar->hashInfo();
print #{ $hashInfo->{'abc'} };

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};