Ovid has asked for the wisdom of the Perl Monks concerning the following question:
I'm working on a module named Class::Sniff. While it's primarily for finding "code smells" in object-oriented hierarchies, it also lets you graph those hierarchies. For example, here's the graph of the B:: modules (Perl's backend modules).
The problem I'm trying to solve is that requiring a package via string eval creates a symbol table entry for that package, even if the require fails. Thus, I can't tell if the package is "real" or not (e.g., if it's likely to get called and should be added to my graph).
Jesse Vincent sent a bug report about Class::Sniff detecting non-existent packages.
Seems Jesse has a lot of code like this:
eval "require RT::Ticket_Overlay"; if ($@ && $@ !~ qr{^Can't locate RT/Ticket_Overlay.pm}) { die $@; };
Well, that seems quite reasonable. Except for this:
#!/usr/bin/env perl -l use strict; use warnings; print $::{'Foo::'} || 'Not found'; eval "use Foo"; print $::{'Foo::'} || 'Not found'; eval "require Foo"; print $::{'Foo::'} || 'Not found'; __END__ Not found Not found *main::Foo::
That's right. Attempting the require a non-existent module via a string eval creates a symbol-table entry. Aristotle told me he was astonished that no one had caught this before. Frankly, I just think that not enough people are trying to do introspection in Perl.
This one will be tricky to work around. I thought "if the module doesn't actually exist, can I check to see if @ISA is there?" It gets automatically created for every package, but since the module representing that package doesn't exist, maybe it won't? No such luck:
print defined *NoSuchModule::ISA{ARRAY} ? 'Yes' : 'No'; print defined *NoSuchModule::xxx{ARRAY} ? 'Yes' : 'No';
That always prints "Yes" and then "No". @ISA is always created for every package if you try to access it. Darn.
I thought I could check for the module's existence in %INC, but inlined packages don't show up there, either (unless the author explicitly puts them there).
The only thing I can think of is this curious line:
print scalar keys %Foo::;If you do that with a non-existent package which nonetheless has a symbol table entry, it still has no keys in its symbol table. However, if you do that with a module which exists but failed to compile, you will probably have a few symbol table entries. This still doesn't quite solve the problem.
So how do I detect if a module in a symbol table failed to load? I'm not sure if I can. If I simply check to see if there are any keys in the symbol table, that should be enough, right? If someone evals "require $badmodule" and that require fails due to compilation errors, they'll exit or die, right? (too optimistic, I know)
Of course, even this is problematic. As Rafael Garcia-Suarez pointed out, a nested stash will create its parent stash (e.g., CGI::Application will create a symbol table for CGI, even if the latter is not loaded).
I can't just check %INC because inlined modules won't be there unless the author remembers to add them manually. Could I hook require or add a coderef to @INC? It's a strange edge case I'm dealing with, but for larger, more complex applications, it's a problem.
Cheers,
Ovid
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: How Can I Know If a Package is "Real"?
by Corion (Patriarch) on Feb 16, 2009 at 12:48 UTC | |
Re: How Can I Know If a Package is "Real"?
by Bloodnok (Vicar) on Feb 16, 2009 at 13:20 UTC | |
Re: How Can I Know If a Package is "Real"?
by tilly (Archbishop) on Feb 16, 2009 at 19:04 UTC | |
Re: How Can I Know If a Package is "Real"?
by Herkum (Parson) on Feb 16, 2009 at 15:58 UTC | |
Re: How Can I Know If a Package is "Real"?
by Tanktalus (Canon) on Feb 16, 2009 at 19:44 UTC | |
Re: How Can I Know If a Package is "Real"?
by DrHyde (Prior) on Feb 17, 2009 at 10:28 UTC |