Let's say I have a CPAN distribution called Foo:
# Foo.pm
package Foo;
And suppose the distribution includes:
package Foo::Bar;
sub mysub { print "hello, world!\n" }
I would like callers to be able to import mysub() with a traditional
'use' statement and import list:
#!/usr/bin/perl
# myscript.pl
use strict;
use warnings;
use Foo qw( mysub );
mysub();
If mysub() were in Foo, I would know how to accomplish the goal with
Exporter, @Foo::Export_OK, etc.. But because mysub() is in Foo::Bar, I
don't think the traditional approach will work. RTFM Exporter makes me
wonder if I should write Foo::import() and call
Exporter::export_to_level() (?).
Bonus question:
use Foo qw( :all );
What is the best way to accomplish the goal?
TIA,
David
p.s. My motivation for this question is as follows -- I am writing some
exception throwing code that calls Carp::confess() internally and would
like to apply the %Carp::Internal feature so that the error messages the
user sees start at the point where they called my code, not where my
code calls confess(). I don't what to put my whole distribution package
into %Carp::Internal, so I'm thinking I'll put the throwing subroutines
into their own package and put that package name into %Carp::Internal.
How about importing mysub from Foo::Bar to Foo, and let Exporter to deal
with the next step?
package Foo;
use Foo::Bar qw{mysub};
our @EXPORT = qw{ mysub };
should work.
Shmuel.
Fill in @EXPORT and @EXPORT_OK as needed.
# --------------------------------------
# Exports
use base qw( Exporter );
our @EXPORT = qw( );
our @EXPORT_OK = qw( );
our %EXPORT_TAGS = (
all => [ @EXPORT, @EXPORT_OK ],
);
--
Just my 0.00000002 million dollars worth,
Shawn
Confusion is the first step of understanding.
Programming is as much about organization and communication
as it is about coding.
The secret to great software: Fail early & often.
Eliminate software piracy: use only FLOSS.
I was wondering about that idea, but was doubtful. Let's try it:
2011-01-16 13:47:47 dpchrist@p43400e ~
$ cat foo-bar-mysub.pl
#!/usr/bin/perl
package Foo::Bar;
require Exporter;
our @ISA = qw( Exporter );
our %EXPORT_TAGS = ( 'all' => [qw( mysub )]);
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = ();
sub mysub { print "hello, world!\n" }
package Foo;
our @ISA = qw( Exporter );
Foo::Bar->import qw( mysub );
require Exporter;
our %EXPORT_TAGS = ( 'all' => [qw( mysub )] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = ();
package main;
use strict;
use warnings;
Foo->import qw(mysub);
mysub();
2011-01-16 13:48:50 dpchrist@p43400e ~
$ perl -c foo-bar-mysub.pl
foo-bar-mysub.pl syntax OK
2011-01-16 13:48:52 dpchrist@p43400e ~
$ perl foo-bar-mysub.pl
hello, world!
It seems to work for this simple case...
Are there other ways?
David
I'm not sure where to ask this question, so please refer me to a better
resource if there is one...
I'm trying to implement a centralized exception generation function, say
myconfess(), that I can use throughout my code. myconfess() will do
some things and then call Carp::confess(). I'd like the stack trace to
appear to come from the point where myconfess() was called, rather than
from where myconfess() calls Carp::confess().
Carp includes two hashes which are supposed to enable this --
%Carp::Internal and %Carp::CarpInternal. I've tried both, but can't
seem to get them working. $Carp::CarpLevel does seem to work.
Here's some demonstration code. The eval's around Carp::confess() are
there so that I can trap the exception, print it, and keep going:
2011-01-16 19:39:31 dpchrist@p43400e ~/sandbox
$ nl -b a carp-internal.pl
1 #!/usr/bin/perl
2
3 package Foo;
4 use Carp;
5 $Carp::Internal{ __PACKAGE__ }++;
6 sub myconfess {
7 eval {
8 Carp::confess @_;
9 };
10 print $@, "\n";
11 }
12
13 package Bar;
14 use Carp;
15 sub myconfess {
16 local $Carp::CarpLevel = 2;
17 eval {
18 Carp::confess @_;
19 };
20 print $@, "\n";
21 }
22
23 package Baz;
24 use Carp;
25 $Carp::CarpInternal{ __PACKAGE__ }++;
26 sub myconfess {
27 eval {
28 Carp::confess @_;
29 };
30 print $@, "\n";
31 }
32
33 package main;
34 sub run {
35 Foo::myconfess('goodbye, cruel world!');
36 Bar::myconfess('goodbye, cruel world!');
37 Baz::myconfess('goodbye, cruel world!');
38 }
39 run();
2011-01-16 19:39:42 dpchrist@p43400e ~/sandbox
$ perl carp-internal.pl
goodbye, cruel world! at carp-internal.pl line 8
eval {...} called at carp-internal.pl line 7
Foo::myconfess('goodbye, cruel world!') called at carp-internal.pl line 35
main::run() called at carp-internal.pl line 39
goodbye, cruel world! at carp-internal.pl line 36
main::run() called at carp-internal.pl line 39
goodbye, cruel world! at carp-internal.pl line 28
eval {...} called at carp-internal.pl line 27
Baz::myconfess('goodbye, cruel world!') called at carp-internal.pl line 37
main::run() called at carp-internal.pl line 39
I would like the output to be:
goodbye, cruel world! at carp-internal.pl line 35
main::run() called at carp-internal.pl line 39
goodbye, cruel world! at carp-internal.pl line 36
main::run() called at carp-internal.pl line 39
goodbye, cruel world! at carp-internal.pl line 37
main::run() called at carp-internal.pl line 39
Any suggestions?
TIA,
David
I noticed that in the debugger, but didn't know if it was a literal
string or a shortcut similar to Data::Dumper...
> sidhekin@bluebird[07:57:52]~$ perl -le '$t{ +__PACKAGE__ }++; print keys
> %t;'
> main
> sidhekin@bluebird[07:57:53]~$ perl -le '$t{ (__PACKAGE__) }++; print keys
Thank you. The second form is per RTFM -- I didn't pay enough attention
and missed the parentheses. The fixed demonstration program follows.
I recently tripped over hash key context (or whatever it's call) when I
attempted to use constants for hash keys. Now I can add something else
to the shopping list:
2011-01-17 13:04:07 dpchrist@p43400e ~/sandbox
$ nl -b a hash-key-context.pl
1 #!/usr/bin/perl
2 use strict;
3 use warnings;
4 use Data::Dumper;
5 use constant KEY => 1;
6 my %hash;
7 $hash{ KEY } = __LINE__;
8 $hash{ KEY() } = __LINE__;
9 $hash{ __PACKAGE__ } = __LINE__;
10 $hash{ (__PACKAGE__) } = __LINE__;
11 print Data::Dumper->Dump([\%hash], [qw(*hash)]);
2011-01-17 13:04:16 dpchrist@p43400e ~/sandbox
$ perl hash-key-context.pl
%hash = (
'KEY' => '7',
'1' => '8',
'__PACKAGE__' => '9',
'main' => '10'
);
Camel book 3 "Scalar and List Context" (pp. 69-70) and "Hashes" (pp.
76-78) aren't much help. Where is hash key context explained?
> %t;'
> main
> sidhekin@bluebird[07:57:54]~$
>
> Careful with those barewords, now. ;-)
I can't find __PACKAGE__ in the Camel book 3 index (?). STFW I found it
in the online Perl Cookbook, where it's called a symbol:
http://docstore.mik.ua/orelly/perl/cookbook/ch12_06.htm
The online Camel book calls it a special literal token:
http://docstore.mik.ua/orelly/perl4/prog/ch02_06.htm
David
2011-01-17 12:19:55 dpchrist@p43400e ~/sandbox
$ nl -b a carp-internal2.pl
1 #!/usr/bin/perl
2
3 package Foo;
4 use Carp;
5 $Carp::Internal{ (__PACKAGE__) }++;
6 sub myconfess {
7 eval {
8 Carp::confess @_;
9 };
10 print $@, "\n";
11 }
12
13 package Bar;
14 use Carp;
15 sub myconfess {
16 local $Carp::CarpLevel = 2;
17 eval {
18 Carp::confess @_;
19 };
20 print $@, "\n";
21 }
22
23 package Baz;
24 use Carp;
25 $Carp::CarpInternal{ (__PACKAGE__) }++;
26 sub myconfess {
27 eval {
28 Carp::confess @_;
29 };
30 print $@, "\n";
31 }
32
33 package main;
34 sub run {
35 Foo::myconfess('goodbye, cruel world!');
36 Bar::myconfess('goodbye, cruel world!');
37 Baz::myconfess('goodbye, cruel world!');
38 }
39 run();
2011-01-17 12:20:04 dpchrist@p43400e ~/sandbox
$ perl carp-internal2.pl
goodbye, cruel world! at carp-internal2.pl line 35
main::run() called at carp-internal2.pl line 39
goodbye, cruel world! at carp-internal2.pl line 36
main::run() called at carp-internal2.pl line 39
goodbye, cruel world! at carp-internal2.pl line 37
main::run() called at carp-internal2.pl line 39
Mu.
> p.s. My motivation for this question is as follows -- I am
> writing some exception throwing code that calls Carp::confess()
> internally and would like to apply the %Carp::Internal feature
> so that the error messages the user sees start at the point
> where they called my code, not where my code calls confess().
> I don't what to put my whole distribution package into
> %Carp::Internal, so I'm thinking I'll put the throwing
> subroutines into their own package and put that package name
> into %Carp::Internal.
You are looking for Carp::Carp, and maybe for Carp::Clan::Share.
http://search.cpan.org/dist/Carp-Clan/lib/Carp/Clan.pod
http://search.cpan.org/dist/Carp-Clan-Share/lib/Carp/Clan/Share.pm
Regards,
--
Aristotle Pagaltzis // <http://plasmasturm.org/>
A mistake everybody makes once, but hopefully no more than once.
:)
As a bit of gratuitous self-promotion, repeat offenders may try
Perl::Critic::Policy::ValuesAndExpressions::UnexpandedSpecialLiteral