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

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;

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

perl : how to share variables and subroutines across various perl files

I am trying something of this sort:
main.pl
use YAML::XS
our $yaml_input = YAML::XS::LoadFile("$input_file");
parse_yaml($yaml_input);
#this variable has to be passed to the function parse_yaml which is in other file.
parser.pl
sub parse_yaml($yaml_input)
{
#some processing
}
I have read few answers about using a package but how do we use it in this case.
Basically you need to import the parse_yaml subroutine into you current program, rather than trying to export the value of the parameter, but I'm uncertain why you have written your own parse_yaml utility when YAML::XS::LoadFile has already done it for you
This is all very clearly described in the documentation for the Exporter module
Here's a brief example
main.pl
use strict;
use warnings 'all';
use YAML::XS 'LoadFile';
use MyUtils 'parse_yaml';
my $input_file = 'data.yaml';
my $yaml_input = LoadFile($input_file);
parse_yaml($input_file);
# this variable has to be passed to the function parse_yaml which is in other file.
MyUtils.pm
package MyUtils;
use strict;
use warnings;
use Exporter 'import';
our #EXPORT_OK = 'parse_yaml';
sub parse_yaml {
my ($yaml_file) = #_;
# some processing
}
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

Perl prototype subroutine in class

I am trying to call a prototype function from a class without instantiating an object. An example of my class MyClass :
package MyClass;
use strict;
use warnings;
sub import{
my $class = shift;
my ($caller) = caller();
eval "sub ${caller}::myprot(\&);";
eval "*${caller}::myprot = \&MyClass::myprot;";
}
sub myprot (&) {
my ($f) = #_;
$f->();
}
1;
I want to call the prototype from a script main.pl:
use strict;
use warnings;
use MyClass;
myprot {
print "myprot\n";
};
and I am getting the errors:
Use of uninitialized value in subroutine entry at MyClass.pm line 14.
Use of uninitialized value in subroutine entry at MyClass.pm line 14.
Undefined subroutine &main::myprot called at main.pm line 8.
I don't really understand the undefined subroutine error: With use, import is called which defines the prototype for main.pl. I also really don't understand the uninitialised value error.
I'd be happy for some explanation.
You're looking for Exporter.
package MyClass;
use strict;
use warnings;
use Exporter qw( import );
our #EXPORT = qw( myprot );
sub myprot(&) {
my ($f) = #_;
$f->();
}
1;
I usually use #EXPORT_OK (requiring the use of use MyClass qw( myprot );) rather than exporting by default.
There's a bunch of sketchy things going on in that code.
Unchecked use of eval means if it fails, you'll never know. eval should be used as eval "code" or die $#. You'll find it's throwing an error because strict does not like it when you mess with the symbol table (that's what *name = \&code is doing).
Using eval to export subroutines is overkill. eval STRING is a potential security hole and should be used as a last resort (eval BLOCK is fine). You can manipulate the symbol table without eval, but strict will not like the use of symbolic references.
my $caller = "foo";
*{"${caller}::myprot"} = \&MyClass::myprot;
# Can't use string ("foo::myprot") as a symbol ref while "strict refs" in use...
You have to turn off strict first. This is generally known as "aliasing".
no strict 'refs';
*{$caller.'::myprot'} = \&myprot;
Setting the prototype beforehand is unnecessary, the alias will take care of it for you.
It turns out this is all unnecessary, there's a number of modules which do this for you. The most common one is Exporter and comes with Perl. This makes your custom import unnecessary.
use Exporter 'import';
our #EXPORT = qw(myprot);
Other general tips...
Hard coding the name of a class in a class (ie. \&MyClass::myprot should just be \&myprot) should be avoided. It makes it harder to change the class or move the code around.
Hybrid modules which are both classes and export functions, are discouraged. They're harder to use, test and document and produce odd side effects. You should put myprot into its own module.
Are you sure you really want to do this?
The problem is that the double quotes will eat the backslash you have in the glob assignment.
eval "*${caller}::myprot = \&MyClass::myprot;"
should be
eval "*${caller}::myprot = \\&MyClass::myprot;"
But please don't ask me to debug your code!

using variables of one perl file in another

I am writing two perl script which requires an array consisting long list of strings
Here I wanted to declare my array in a separate perl package and use this package to access that array in other two perl scripts
Can you please tell me how could i do this
I checked for perl cpan module Exporter, but could find it can export subroutines,I only want my array to be exported not any subroutines
Thank you in advance.
Exporter can handle any package symbol, be it a subroutine or variable:
package My::Package;
use parent 'Exporter';
our #EXPORT_OK = qw/#foo/;
our #foo = (42, 666);
Then:
use My::Package qw/#foo/;
print "#foo\n";
Output: 42 666.
However, package variables (aka. “globals”) are frowned upon. Usually, techniques like object orientation provide a better solution. If you don't want to go there, you could still write a kind of “accessor” or “initializer”:
package My::Package;
sub main {
my #foo = (42, 666);
return \#foo;
}
Then:
use My::Package;
my $foo = My::Package::main();
print "#$foo\n";
You can create a package variable and export it, just like a subroutine:
package Local::Foo;
use strict;
use warnings;
use Exporter qw(import); # Allows you to export things
our #EXPORT = qw(#foo_array);
our #foo_array = ( ... );
1;
Now, you can use it in your program:
my #local_array = #foo_array;
This is called a really. really bad idea. Variables are polluting your main program's namespace without your knowledge. Plus, you could change #foo_array and destroy its special meaning.
If you go this route, do not do the export. Simply refer to the variable directly via the package name. After all, you've declared it with our:
package Local::Foo;
...
our #foo_array = ( ... );
And, in your program:
my #program_array = #Local::Foo::foo_array;
This is a tiny bit better. You won't have namespace collisions, and you know where that value is coming from. However, I would take the lead of use constant which uses subroutines to define constants. When you say this:
use PI => 3.141529;
What you're really doing is this:
sub PI {
return 3.141529;
}
That allows you to do this:
my $circumference = PI * ( 2 * $radius );
You could take a similar task with your array:
package Local::Foo;
use strict;
use warnings;
use Exporter qw(import);
our #EXPORT_OK = qw(foo_array);
sub foo_array {
return qw( ... );
}
Now, to use this in your program:
use Local::Foo qw(foo_array);
...
my #program_array - foo_array;
You can access the value of foo_array, but you can't change it at all. It's totally protected -- a constant value.
Yeah, I have to echo amon's deprecation of exporting. You can create it as a constant
package TheData;
use constant BIG_ARRAY => [ 0..300_000 ];
And then other packages can reference it as if it were a static member:
package DataUser;
my $big_array_data = TheData->BIG_ARRAY;
Much cleaner for a more modern Perl. (Note that constant just is shorthand for what amon specified.)