Using undefined constant in perl file not throwing any warning - perl

I have a module where I have few variables declared hfs_const.pm. I
am using this module in another Perl program.
I am also using few of the module's variables in another Perl file.
Test case: I remove one variable from the module which I am using in the Perl file through an object. Then I compile the Perl file.
I am using use strict and use warnings, but when I compile the Perl program it shows that everything is OK.
I believe it should have thrown an error for undeclared module variable.
Following is the module and Perl file
hfs_const.pm
#!/usr/bin/perl
package hfs_const; # const definition file for hfs.
use Exporter 'import';
use strict;
use warnings;
#--------------------------------------------------------------------------------------
use constant ENABLE_HFS => 1;
use constant PROC_MOUNT_DIR => "/proc/fs/hydrafs/hfsd/mount";
#use constant PROC_MOUNT_DIR =>"/export/proc";
use constant PROC_HFSD_INFO_FILE => "/proc/fs/hydrafs/hfsd/info";
use constant DEBUG => 0;
use constant IGNORE_SERVICE => 0;
#use constant MAX_HFS_PER_AN =>250;
#use constant RETRY_COUNT =>3;
use constant GET_ALL_HFS_TIMEOUT => 12;
#use constant HFS_COUNT_TO_CHANGE_AN =>250;
use constant CREATING_TIME => 600;
#our $bar=4;
sub new {
my $class = shift;
my $this = {};
bless $this, $class;
return $this;
}
sub getname {
my $this = shift;
print "Ankur";
}
1;
hfs.pl
#!/usr/bin/perl
#
use strict;
use warnings;
use hfs_const;
my $const = new hfs_const();
my $isRO = 3;
if ( $isRO != 4 ) {
print $hfs_const::bar;
print hfs_const::RETRY_COUNT;
print $const->HFS_COUNT_TO_CHANGE_AN;
print hfs_const::MAX_HFS_PER_AN;
}
else {
print hfs_const::GET_ALL_HFS_TIMEOUT;
}
$const->getname();
I get the following warning on compilation
int#mint-VirtualBox ~ $ perl -c hfs.pl
Name "hfs_const::RETRY_COUNT" used only once: possible typo at hfs.pl line 12.
Name "hfs_const::MAX_HFS_PER_AN" used only once: possible typo at hfs.pl line 14.
Name "hfs_const::bar" used only once: possible typo at hfs.pl line 11.
hfs.pl syntax OK
But I do not receive any warning for constant HFS_COUNT_TO_CHANGE_AN which is used through object.
Can anybody explain why is it happening?

You're treating HFS_COUNT_TO_CHANGE_AN as a method ($const->HFS_COUNT_TO_CHANGE_AN) so Perl won't check that it exists at compile time. You'll get a run-time error though.

Related

Call from a code reference in Template Toolkit

I have a simple higher-order function that builds a message formatter.
use strict;
use warnings;
sub make_formatter {
my $level = shift;
return sub {
my $message = shift;
return "[$level] $message";
}
}
I use it from Perl like that:
my $component_formatter = make_formatter('ComponentError');
print $component_formatter->('Hello') . "\n";
I want to use make_formatter from a Template Toolkit template. I have tried to do the following:
use Template;
use Template::Constants;
my $template = Template->new({
# DEBUG => Template::Constants::DEBUG_ALL,
VARIABLES => {
make_formatter => make_formatter,
}
});
my $template_str = "
[% my_formatter = make_formatter('MyFormatter') %]
<h1>[% my_formatter('Sample message') %]</h1>
";
$template->process(\$template_str);
The output of this script is:
$ perl test.pl
Use of uninitialized value $level in concatenation (.) or string at test.pl line 10.
<h1>[] MyFormatter</h1>
Is it possible to call my_formatter using only Template Toolkit syntax ? Calling external Perl code that is not callable by default from Template Toolkit is not an option.
First let me please point out that putting use strict; use warnings; at the beginning of your script is strongly advised.
If you do that for your snippet generating the $template,
you will get a Bareword "make_formatter" not allowed while "strict subs" in use error, which should help you determine this is not a useful notation.
Now if you call make_formatter() instead, this will output <h1>[] MyFormatter</h1>. This makes sense: your function returned the sub, which is called with 'MyFormatter' in your template ( and $level is undef, as you called make_formatter with no input ).
As Mr. Haegland pointed out,
my $template = Template->new({
VARIABLES => {
make_formatter => \&make_formatter,
}
});
leads to the output I understand you want:
<h1>[MyFormatter] Sample message</h1>
\&make_formatter gives you a subroutine reference,
which in perl normally you could call using:
my $ref = \&make_formatter; $ref->( 'Input' );
This can then be called in the first line of your template,
returning another code ref, which is then called in your second line.
Hope this helps!

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)

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.

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