Export Code Attribute - perl

I want to create a function which can be imported and used as a code attribute.
I am using Sub::Attribute to create the attributes. The example given uses inheritance but I want to export and use it. Hope my question is clear.
Code snippet to create an attribute:
package attpkg;
use strict;
use Sub::Attribute;
use Exporter 'import';
our #EXPORT_OK = ('Myattr');
sub Myattr : ATTR_SUB {
my ($class, $sym_ref, $code_ref, $attr_name, $attr_data) = #_;
print "#_";
#$code_ref->();
print "_____________\n";
}
1;
Code Snippet that tries to import the attribute but fails:
use strict;
use attpkg qw(Myattr);
sub pHelloWorld : Myattr {
print "Hello World\n";
}
pHelloWorld();

Sub::Attribute secretly also creates a function called MODIFY_CODE_ATTRIBUTES() in the attpkg namespace. You'll need to export that too.

Related

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

Perl exported functions does not work

Assuming I have this module:
package MyApp;
use base 'Exporter';
our #EXPORT = qw(msg);
sub import {
my ($class, #args) = #_;
my ($package, $script) = caller;
print "$package, $script\n";
}
sub msg {
print "Hello msg\n";
}
1;
and used by this script App.cgi:
#!/usr/bin/perl
use MyApp;
msg();
if I run this App.cgi I get this error:
undefined subroutine &main::msg in App.cgi at line 3
If I rename or remove the sub import in the package MyApp.pm it works fine.
So what is the problem with the import or how it should be used while exporting functions.
You're overriding Exporter's import method with one of your own that doesn't actually export anything, it just prints to stdout. Either don't do that (what's the point?) Or call $class->export_to_level(1, #_) to ensure that Exporter's stuff gets called. You need to use export_to_level and not SUPER::import, because your own import method adds a caller frame, and without being told otherwise, Exporter would export to the wrong place.

Perl export to child modules

I have this parent module MyApp.pm:
package MyApp;
use Moose;
use base 'Exporter';
our #EXPORT = qw(msg);
sub msg {
print "Hello msg\n";
}
1;
which is inherited by this child module MyApp2.pm:
package MyApp2;
use Moose;
extends qw(MyApp);
1;
and when used in the App.cgi script like this:
#!/usr/bin/perl
use MyApp2;
msg();
I get error message:
Undefined subroutine &main::msg called at App.cgi line 3.
So the exported function does not work in the child class MyApp2 but works only if I use "use MyApp" instead of "use MyApp2". I assume the exported function should be accessible to the child modules also which is extending the parent class. What I am doing wrong.
Inheritance only changes how method calls are handled; function calls or variable accesses (like our #EXPORT) are not affected.
Instead of exporting a function, you could use it as a method:
use MyApp2;
MyApp2->msg;
but in this case, it would be cleaner to explicitly load MyApp in order to import the msg function, and to additionally load MyApp2 in order to load this class.
use MyApp;
use MyApp2;
msg;
It is generally advisable for a module to either be object oriented or to offer an interface via exported functions, but not do both.
Here is the solution I found for my request:
package MyApp;
use Moose;
use base 'Exporter';
our #EXPORT = qw(msg);
sub import {
my ($class, #args) = #_;
my $caller = $class.'::';
{
no strict 'refs';
#{$caller.'EXPORT'} = #EXPORT;
foreach my $sub (#EXPORT) {
next if (*{"$caller$sub"}{CODE});
*{"$caller$sub"} = \*{$sub};
}
}
goto &Exporter::import;
}
sub msg {
print "Hello msg MyApp\n";
}
1;
The idea here is I export all the contents of the "#EXPORT" array into the child module, only add none existent subs so will not overwrite any methods in the child class.
In this example above, this exports from MyApp to the child MyApp2.
This works for my own needs.

inspect the parameters to "use", and pass on the rest?

I have a Perl module and I'd like to be able to pick out the parameters that my my module's user passed in the "use" call. Whichever ones I don't recognize I'd like to pass on. I tried to do this by overriding the "import" method but I'm not having much luck.
EDIT:
To clarify, as it is, I can use my module like this:
use MyModule qw/foo bar/;
which will import the foo and bar methods of MyModule. But I want to be able to say:
use MyModule qw/foo doSpecialStuff bar/;
and look for doSpecialStuff to check if I need to do some special stuff at the beginning of the program, then pass qw/foo bar/ to the Exporter's import
Normally, you would do this to gain Exporter's import() functionality (this isn't the only way, but it's a common method that works):
package MyClass;
use strict;
use warnings;
use Exporter 'import'; # gives you Exporter's import() method directly
our #EXPORT_OK = qw(stuff more_stuff even_more_stuff);
...and then you will get an import() method automatically created for you. However, if you want to do something extra in import() before the normal method gets a hold of the parameters, then don't import Exporter's import(), and define your own, which calls Exporter's import() after making any alterations to the argument list that you need:
package MyClass;
use strict;
use warnings;
use parent 'Exporter';
sub import
{
my ($class, #symbols) = #_;
# do something with #symbols, as appropriate for your application
# ...code here left as an exercise for the reader :)
# now call Exporter's import, and import to the right level
local $Exporter::ExportLevel = 1;
$class->SUPER::import(#symbols);
}
However, I'm wondering why you need to do this... the standard behaviour of dying when being passed an unrecognized symbol is normally a good thing. Why would you want to ignore unrecognized symbols? (Edit: I see now, you want to specify additional behaviour on top of importing symbols, which is not uncommon in Perl. So defining your own import() method is definitely the way to go here, to grab those values.)
PS. if you only want to import symbols which are defined by #EXPORT_OK, it could be implemented like this:
#symbols = grep {
my $sym = $_;
grep { $_ eq $sym } #EXPORT_OK
} #symbols;
The typical use of Exporter is to declare your module to inherit from Exporter, and to have Exporter's import method called implicitly when your module is used. But this keeps you from creating your own import method for your module.
The workaround is to use Exporter's export_to_level method, which performs Exporter's functions without explicitly going through the Exporter::import method. Here's a typical way to use it:
package My::Module;
use base 'Exporter'; # or use Exporter; our #ISA=qw(Exporter);
our #EXPORT = qw(...);
our #EXPORT_OK = qw(...);
our %EXPORT_TAGS = (...);
sub import {
my ($class,#import_args) = #_;
my #import_args_to_pass_on = ();
foreach my $arg (#import_args) {
if (... want to process this arg here ...) {
...
} else {
push #import_args_to_pass_on, $arg;
}
}
My::Module->export_to_level(1, "My::Module", #import_args_to_pass_on, #EXPORT);
#or: $class->export_to_level(1, $class, #import_args_to_pass_on, #EXPORT);
}
I have done it this way in my modules:
sub import {
return if not #_;
require Exporter;
my $pkg = shift;
# process #_ however you want
unshift #_, $pkg;
goto &Exporter::import;
}
you can also inherit from Exporter if you want unimport and the like.