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.


In reply to How Can I Know If a Package is "Real"? by Ovid

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.