Not able to export methods using Exporter module in perl - 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

Related

Can't use Exporter properly

I've wasted many days on a larger block of code, containing Exporter statements, which used to work about a year ago. Several variations on this have failed, including an install of ./FOO/BAR/Foobar.pm which signaled success.
I am using Windows 10, Perl v5.26.0, built for MSWin32-x64-multi-thread
Caller.pl
#!/usr/bin/perl
use lib ".";
use lib "./FOO/BAR";
use strict;
use warnings;
use FOO::BAR::Foobar;
print "try FOO::BAR::Foobar::foo()\n";
FOO::BAR::Foobar::foo(); # perl can't find this
print "try foo()\n";
foo(); # errors out - can't find &main::foo
print "done\n";
./FOO/BAR/Foobar.pl
#!/usr/bin/perl -w
use strict;
use warnings;
package Foobar;
our($VERSION , #ISA , #EXPORT , #EXPORT_OK , %EXPORT_TAGS , $FOO);
BEGIN {
require Exporter;
#ISA = qw(Exporter);
#EXPORT_OK = qw(foo);
}
sub foo {
print "Loaded\n";
$FOO = q{some val};
}
1;
Execution dump
perl Caller.pl
try FOO::BAR::Foobar::foo()
Undefined subroutine &FOO::BAR::Foobar::foo called at Caller.pl line 12.
What's going on? Should I abandon any use of Exporter? But then how to link functions across modules?
There are three things going wrong:
With FOO::BAR::Foobar::foo(): There is no such sub, there is only Foobar::foo().
With foo(): use FOO::BAR::Foobar; is the equivalent of BEGIN { require FOO::BAR::Foobar; FOO::BAR::Foobar->import() }, but there is no method import available in the package FOO::BAR::Foobar, since you're inheriting Exporter into the package Foobar.
With foo(): You're using #EXPORT_OK instead of #EXPORT, which means that you need to explicitly import foo, but you're not doing that in use FOO::BAR::Foobar;.
So two things are needed to fix this:
As already pointed out in the comment by #HåkonHægland, change package Foobar; to package FOO::BAR::Foobar;.
Change use FOO::BAR::Foobar; to use FOO::BAR::Foobar qw/foo/;.
Then the code you've shown will work - there's no need to abandon Exporter. I'd just recommend a different style of using Exporter: Instead of inheriting via #ISA, just import import into your package. Here's how I would have written your file ./FOO/BAR/Foobar.pm:
package FOO::BAR::Foobar;
use strict;
use warnings;
use Exporter 'import';
our #EXPORT_OK = qw(foo);
our $FOO;
sub foo {
print "Loaded\n";
$FOO = q{some val};
}
1;

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.

How to declare an array variable to be global in module scope

I have some code I decided to pull into a module in perl. I admit that I am doing a bit of monkey-see monkey-do stuff following documentation I've found online.
There is only one pubicly visible subroutine, which sets 2 variables * would like to use in other subroutines in the module, without passing them explicitly as parameters -- $fname, and #lines. Looking online I came up with the "our" keyword, but when I try to declare them at global level (see code snippet below), I get the following error:
mig_tools.pm did not return a true value at
I have worked around the issue by declaring "our $fname" and "our #lines" in every subroutine they are used, but I would prefer to declare them once at global scope. Is that possible?
Here's what I take to be the relevant part of the code.
package mig_tools;
require Exporter;
use strict;
use warnings;
our #ISA = qw(Exporter);
our #EXPORT = qw( ensure_included);
our $fname;
our #lines;
// definitions of already_has_include find_include_insert_point and ensure_included.
All-lowercase variables are reserved for local identifiers and pragma names. Your module should be in MigTools.pm and you should use it with use MigTools
The did not return a true value error is just because your module file didn't return a true value when it was executed. It is usual to add a line containing just 1; to the end of all modules
Your MigTools.pm should look like this. It is best to use the import directly from Exporter instead of subclassing it, and our doesn't help you to create a global variable, but I am a little worried about why you are structuring your module this way
package MigTools;
use strict;
use warnings;
use Exporter qw/ import /;
our #EXPORT = qw/ ensure_included /;
my ($fname, #lines)
sub ensure_included {
}
sub already_has_include {
}
sub find_include_insert_point {
}
sub ensure_included {
}
1;

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

How to call method in base class in Perl

#child.pm
#!/usr/bin/perl
package child1;
use strict;
use warnings;
use Exporter;
use parent;
my #ISA=qw(cal Exporter);
sub new{
my $class=shift;
my $ref=cal->new();
bless ($ref,$class);
return $ref;
}
sub add{
my $ref=shift;
print "This is from child class";
my($a,$b)=#_;
return ($a+$b);
}
##parent.pm
#!/usr/bin/perl
package cal;
use strict;
use warnings;
use Exporter;
my #EXPORT=qw(add);
my #ISA=qw(Exporter EXPORT);
sub new{
my $class=shift;
my $ref=[];
bless ($ref,$class);
return $ref;
}
sub add{
my $ref=shift;
my $a=shift;
my $b=shift;
return ($a+$b);
}
1;
#test.pl
#!/usr/bin/perl
use strict;
use warnings;
use Exporter;
use child;
my #ISA=qw(child1 Exporter);
my $obj=new child1();
my $sum=$obj->add(1,2);
print "$sum=sum";
I am getting the error Can't locate object method "add" via package "child1" at ./test.pl line 8.
I want to access the base class add method
and I am getting this above error
please clarify..
The main culprit here is my #ISA. For inheritance to work, you have to use the package #ISA (declare it with our).
However, there are some issues in your code beyond that:
Please use parent 'cal' instead of manipulating #ISA yourself.
Object-oriented modules have little reason to use Exporter.
The child1's new can be written without reblessing, because the parent's new is inherited. The inherited new is written in a way that already supports inheritance.
Don't give your modules lower-case names, these are reserved for “pragmas”. The parent module already exists, and I used it in my 1st point.
#ISA must be a public package variable, not a private lexical (my). Same for #EXPORT. Change my to our on all those declarations.
Even better, depending on the version of perl you have, simplify you life with either the parent or base pragma to load superclasses and to set up the class relationships.
With respect to style, you will avoid considerable confusion if you make the paths to the files that contains your modules’ code match their package names. You would do well to heed a well-established convention described in the perlmod documentation.
Module names are also capitalized unless they're functioning as pragmas; pragmas are in effect compiler directives, and are sometimes called “pragmatic modules” (or even “pragmata” if you're a classicist).
The Cal module uses an internal _initialize method as described in the perlobj documentation to facilitate inheritance of the constructor.
See below for a complete working example.
Cal.pm
package Cal;
use strict;
use warnings;
sub new {
my $class=shift;
my $self=[];
bless ($self,$class);
$self->_initialize();
return $self;
}
sub _initialize {}
sub add {
my $ref=shift;
my $a=shift;
my $b=shift;
print "This is from parent class\n";
return ($a+$b);
}
1;
Child1.pm
package Child1;
use warnings;
use strict;
use v5.10.1; # when parent was added to the core
use parent "Cal";
# if you have an older perl, use base instead of parent
# use base "Cal";
sub _initialize {
my $self=shift;
push #$self, "I am a " . ref($self) . "!";
}
sub add{
my $self=shift;
my($a,$b)=#_;
print "This is from child class\n";
return ($a+$b);
}
1;
test.pl
#!/usr/bin/perl
use strict;
use warnings;
use Child1;
my $obj=Child1->new();
my $sum1=$obj->add(1,2);
print "$sum1=sum1\n";
# call the add method in Cal
my $sum2=$obj->Cal::add(1,2);
print "$sum2=sum2\n";
# call add as a class method of Cal, which
# happens to work in this case because Cal::add
# does not use the instance passed to it
my $sum3=Cal->add(1,2);
print "$sum3=sum3\n";
Output:
This is from child class
3=sum1
This is from parent class
3=sum2
This is from parent class
3=sum3
The .pm modules do not need, and likely do not want, the #!/usr/bin/perl lines. This is only for programs intended to be executed from the command line, like your .pl module. While you may 'perl -cw' your .pm modules, or do other command line debugging with them, such is not normal "production" use.
And .pl modules should not have #ISA, or other "our" declarations found in packages nor any exporter related things.
As said before, change "my"s for package stuff to "our"s. The "my" hides things to outsiders as if the statements were never there.
In the "cal" class, do you want something like the following? I favor SUPER as it really shows what is going on and is much more generic.
package child1;
use Exporter;
our #ISA=qw(cal Exporter);
sub new{
my $class=shift;
my $ref=$class->SUPER::new();
return $ref;
}
}
One final point: you may need a "\n" on the final print statement. Without it the buffer may not flush correctly on exit in some environments so you will never see the output.