Having just figured out this, I was wondering how the -M
would handle a terminal ::
affixed to a package name,
$ perl -MFoo:: -e1
What I got was...
Can't locate
Foo/.pm
in@INC
(you may need to install theFoo::
module) (@INC
contains: [...]).
This seems to indicate that it doesn't work, so curiosity compelled me....
$ mkdir Foo;
$ echo "package Foo { sub k { die 42 } }; 1;" > Foo/.pm
$ PERL5LIB=. perl -MFoo:: -e'Foo::->k'
That did in fact work. Is this convention of use mod::;
resolving to mod/.pm
supported? Was this a holdover from antiquity. Where did this behavior come from?
With this schema I could do,
Foo/.pm # package Foo
Foo/Bar/.pm # package Foo::Bar
Foo/Bar/Baz/.pm # package Foo::Bar::Baz;
then I could do
use Foo::; # resolves to Foo/.pm
use Foo::Bar::; # resolves to Foo/Bar/.pm
use Foo::Bar::Baz::; # resolves to Foo/Bar/Baz/.pm
Foo::->new;
Foo::Bar::->new;
Foo::Bar::Baz::->new;
I like this because this adds the benefit of
use
and invocation.Is this design by intent? Is it documented anywhere? Has anyone ever thought of this awesome idea before?
Is this convention of use mod::; resolving to mod/.pm supported?
No.
The parser is too liberal when it comes to accepting ::
, allowing you do rather absurd things.
$ cat Foo/Bar.pm
package Foo::Bar;
sub import { print "imported.\n"; }
print "loaded.\n";
1
$ perl -I. -e'require Foo::Bar'
loaded.
$ perl -I. -e'require Foo::::::Bar'
loaded.
Using the non-canonical form leads to problems.
$ perl -I. -e'use Foo::Bar; use Foo::Bar; use Foo::Bar;'
loaded.
imported.
imported.
imported.
$ perl -I. -e'use Foo::::::Bar; use Foo::::::Bar; use Foo::Bar;'
loaded.
loaded.
imported.
Similarly, that use Foo::Bar::
loads Foo/Bar/.pm
shouldn't be taken as an intentional, supported feature.
Has anyone ever thought of this awesome idea before?
It actually would be a mess.
For starters, you would have to use use Foo::Bar::;
instead of use Foo::Bar;
.
$ cat Foo/Bar/.pm
package Foo::Bar;
sub import { print "imported.\n"; }
sub baz { print "ok.\n"; }
1
$ perl -I. -e'use Foo::Bar;'
Can't locate Foo/Bar.pm in @INC ...
$ perl -I. -e'use Foo::Bar::;'
$
But using use Foo::Bar::;
isn't enough because import
was never called. The package directive would need to match the file name (package Foo::Bar::
) for import
to be called, which means you'd have to adjust qualified references to the package as well.
$ cat Foo/Bar/.pm
package Foo::Bar::;
sub import { print "imported.\n"; }
sub baz { print "ok.\n"; }
1
$ perl -I. -e'use strict; use Foo::Bar; Foo::Bar::baz();'
Can't locate Foo/Bar.pm in @INC ...
BEGIN failed--compilation aborted at -e line 1.
$ perl -I. -e'use strict; use Foo::Bar::; Foo::Bar::baz();'
imported.
Undefined subroutine &Foo::Bar::baz called at -e line 1.
$ perl -I. -e'use strict; use Foo::Bar::; Foo::Bar::::baz();'
imported.
ok.
To put it lightly, this is undesirable.
Even if your module doesn't have an import
method at this time, that could change, and having two different and incompatible conventions for loading modules is hurtful.
Where did this behavior come from
While the expression Foo::Bar::
produces the string Foo::Bar
, use
doesn't take an expression.
Additionally, the literal is passed to an implementation of package name to file name transliteration that performs no sanity checks. Perl simply performs an operation equivalent to calling the following sub:
sub pkg_to_qfn { ( $_[0] =~ s{::}{/}gr ) . '.pm' }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With