What is this module using?

T

Tim McDaniel

Looking at the docs, it appears that Devel::Modlist reports on *all*
the modules used in an entire script. Is there some way I can
determine the modules used, directly or transitively, merely by the
current module?
 
R

Reini Urban

Quoth Eli the Bearded said:
That's not necessarily going to work. Consider:

perl -d:Modlist -mCPAN -e1

When I run that it doesn't mention Storable, LWP::*, or Time::*
but all three were used by CPAN just seconds before when I ran
"install Devel::Modlist":

True. Modules loaded at runtime are inherently harder, since you have to
run the program (with all possible inputs) to see them.

A CORE::GLOBAL::require hook which checks caller() looks like the best
answer, to me. You probably want to check (caller)[1] as well as
(caller)[0], or just check [1] while being careful to step back over
string evals until you find a real file.

For an easier way, I'd rather print the %INC keys in an END block, as
require stores the loaded module names there.

perl -mCPAN -e'END{print(join qq(\n),keys %INC)}'

This does not print the package names per se, but the relative paths of
all loaded modules.
s{/}{::}g; s{\.p[lm]$}{}; will do pretty printing of the names.
 
R

Reini Urban

Quoth Reini Urban said:
A CORE::GLOBAL::require hook which checks caller() looks like the best
answer, to me. You probably want to check (caller)[1] as well as
(caller)[0], or just check [1] while being careful to step back over
string evals until you find a real file.

For an easier way, I'd rather print the %INC keys in an END block, as
require stores the loaded module names there.

Read the OP. Tim (the OP) was asking for a way to find modules required
(recursively) only by one particular module, not modules required by the
whole program. Devel::Modlist is basically a cleaned-up version of
'print %INC in an END block', and Tim was looking for an alternative.

Oops, you are right, yes.
 
T

Tim McDaniel

Back about two years ago (Date: Wed, 18 Apr 2012 21:44:31 +0000 (UTC);
Message-ID: said:
Looking at the docs, it appears that Devel::Modlist reports on *all*
the modules used in an entire script. Is there some way I can
determine the modules used, directly or transitively, merely by the
current module?

Ben Morrow suggested in said:
perl -d:Modlist -mMy::Module -e1 ?

I've gotten around to trying that. The problem is that apparently I
had a different problem in mind than today's when I wrote
determine the modules used, directly or transitively

With the method above, it's indeed transitive. (Also, if I leave out
something from the INC path, it errors out at that "use" statement and
doesn't check anything after. Our system does have a non-trivial
include list.)

For today's problem, I want only "directly", not "transitively".

My group is adding calls subs in new modules and sometimes forgetting
to add the "use" statements. Each of our modules should "use"
everything it calls. I'd like a somewhat automated way to check
statically for missing "use"s before we check in files. So I do not
want transitive uses, and apparently we're doing a fair number of
transitive "use"s.

(I tried -d:Modlist as above with a library path that has only
Devel::Modlist, but the problem above arises: since I'm leaving out
many things from the INC path, it errors out at the first "use" of one
of our modules and doesn't report anything after. And if I include our
path, as aforesaid I get a lot of transitive uses that I don't want.)

I'm thinking that I should just write a simple script to read a Perl
file looking for
- ^use foo::bar::baz
save it as one of the uses (ignored any suffixed "nocritic", "no",
or whatever)
- foo::bar::baz->
confirm that foo::bar::baz is in the hash of uses
- foo::bar::baz::quux not followed by ->
confirm that foo::bar::baz is in the hash of uses

We very rarely do "require". We rarely do exports. So the above
should work well enough 98% of the time. I'm OK with false positives
in such odd cases, and false negatives (like calling an exported sub
where you forgot to "use" the module directly) should be rare and you
deserve the severe tire damage if you do it.

Comments? Better ideas?
 
R

Rainer Weikusat

(e-mail address removed) (Tim McDaniel) writes:

[...]
My group is adding calls subs in new modules and sometimes forgetting
to add the "use" statements. Each of our modules should "use"
everything it calls. I'd like a somewhat automated way to check
statically for missing "use"s before we check in files.

This may not be applicable to your problem but what about maintaining a
single list of use statements in a dedicated file?
 
T

Tim McDaniel

(e-mail address removed) (Tim McDaniel) writes:

[...]
My group is adding calls subs in new modules and sometimes forgetting
to add the "use" statements. Each of our modules should "use"
everything it calls. I'd like a somewhat automated way to check
statically for missing "use"s before we check in files.

This may not be applicable to your problem but what about maintaining a
single list of use statements in a dedicated file?

Reading and parsing the entire codebase when starting the program
would take some time.
 
R

Rainer Weikusat

Rainer Weikusat said:
(e-mail address removed) (Tim McDaniel) writes:

[...]
My group is adding calls subs in new modules and sometimes forgetting
to add the "use" statements. Each of our modules should "use"
everything it calls. I'd like a somewhat automated way to check
statically for missing "use"s before we check in files.

This may not be applicable to your problem but what about maintaining a
single list of use statements in a dedicated file?

Reading and parsing the entire codebase when starting the program
would take some time.

Insofar use statements are being used to include modules, the entire
codebase is 'read, parsed and compiled' prior to anything else
happening:

It is exactly equivalent to

BEGIN { require Module; Module->import( LIST ); }
 
T

Tim McDaniel

[email protected] (Tim McDaniel) said:
Rainer Weikusat said:
(e-mail address removed) (Tim McDaniel) writes:

[...]

My group is adding calls subs in new modules and sometimes forgetting
to add the "use" statements. Each of our modules should "use"
everything it calls. I'd like a somewhat automated way to check
statically for missing "use"s before we check in files.

This may not be applicable to your problem but what about maintaining a
single list of use statements in a dedicated file?

Reading and parsing the entire codebase when starting the program
would take some time.

Insofar use statements are being used to include modules, the entire
codebase is 'read, parsed and compiled' prior to anything else
happening:

I've been trying to think about this in the general case. The only
objection I can think of is that a program might not directly or
indirectly reach the entire codebase. There might be several
programs, and different (perhaps overlapping, perhaps disjoint) parts
of the codebase might be used by different programs. I think that
condition obtains at my ork-place.

The other objections I considered I don't think would actually be
problems:
- conflicting exports: they would have been happening before the "use
unification"
- ordering problems with BEGIN blocks: that's such a disaster of a
design that I don't think it needs to be considered.

Thank you for the idea and for prompting me to think under what
conditions it might or might not be useful.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top