Subject: | Flaw in determining package names |
If I run this script:
#!perl
package What::Ever;
use Moops;
class Foo {
};
eval { Foo->meta }; warn $@ if $@;
eval { What::Ever::Foo->meta }; warn $@ if $@;
__END__
I get this error message:
Can't locate object method "meta" via package "Foo" (perhaps you forgot to load "Foo"?) at - line 9.
If I comment out the package declaration, I get this error message:
Can't locate object method "meta" via package "What::Ever::Foo" (perhaps you forgot to load "What::Ever::Foo"?) at - line 7.
Judging by the code, I think this is by design. But here is the catch: When a module (or any file) is loaded via ‘use’ or ‘require’, the package in which the module is initially compiled is that of the caller (the code containing the ‘require’ statement). That means that this module:
$ cat Pfoom.pm
use Moops;
class Pfoom { }
__END__
may define a top-level Pfoom class (if ‘use Pfoom’ is in main), or it may define a subpackage, such as Gromple::Pfoom (if ‘use Pfoom’ is in the Gromple package).
Now, there is a glitch in existing Perl versions up to 5.27.4, in that, while PL_curstash points to the package of the code currently being compiled and PL_curstname is a char* holding the package name, sometimes they can get out of synch, because PL_curstname is set only with ‘package’ declarations, and not at the beginning of a string eval or file.
In bleadperl (5.27.5) I fixed it, because it was causing the wrong package to show up in error messages (see <https://perl5.git.perl.org/perl.git/commitdiff/04680144c43>).
Now Parse::Keyword::compiling_package, which Moops happens to use, gets the name from PL_curstname, the variable that is sometimes off.
This means that
eval "use Pfoom";
will create a Pfoom class as long as there is no currently compiling scope, but
use Pfoom;
will create a package named Whatever::Pfoom, assuming that the scope in which ‘use’ occurs has a ‘package Whatever’ declaration in it.
As of 5.27.6, the former behaves consistently the same way as the latter, which happens to break Pod::Elemental::Transformer::Splint (<https://rt.perl.org/Ticket/Display.html?id=132373>).
I can see two possible ways for you to fix this unpredictability in the way Moops handles unqualified package names:
1) Drop support for nested package names; just do things the Perl 5 way.
2) Look at the file name of the code that is currently being compiled. (I don’t know offhand how to do that from pure-Perl, but I can look into it if you want to follow this route.)