Skip to content

Instantly share code, notes, and snippets.

@exodist
Last active October 13, 2017 17:25
Show Gist options
  • Save exodist/708d8b41af5de51f92abb4b38a266aba to your computer and use it in GitHub Desktop.
Save exodist/708d8b41af5de51f92abb4b38a266aba to your computer and use it in GitHub Desktop.
DepTracer
package DepTracer;
use strict;
use warnings;
use Object::HashBase qw/
-_on
-exclude
-dep_map
-loaded
-my_require
-real_require
/;
my %DEFAULT_EXCLUDE = (
'warnings.pm' => 1,
'strict.pm' => 1,
);
sub start { shift->{+_ON} = 1 }
sub stop { shift->{+_ON} = 0 }
sub clear_loaded { %{$_[0]->{+LOADED}} = () }
my %REQUIRE_CACHE;
sub init {
my $self = shift;
my $exclude = $self->{+EXCLUDE} ||= { %DEFAULT_EXCLUDE };
my $stash = \%CORE::GLOBAL::;
# We use a string in the reference below to prevent the glob slot from
# being auto-vivified by the compiler.
$self->{+REAL_REQUIRE} = exists $stash->{require} ? \&{'CORE::GLOBAL::require'} : undef;
my $dep_map = $self->{+DEP_MAP} ||= {};
my $loaded = $self->{+LOADED} ||= {};
my %seen;
my $require = $self->{+MY_REQUIRE} = sub {
my ($file) = @_;
my $loaded_by = $self->loaded_by;
my $real_require = $self->{+REAL_REQUIRE};
unless($real_require) {
my $caller = $loaded_by->[0];
$real_require = $REQUIRE_CACHE{$caller} ||= eval "package $caller; sub { CORE::require(\$_[0]) }" or die $@;
}
goto &$real_require unless $self->{+_ON};
if ($file =~ m/^[_a-z]/i) {
unless ($exclude->{$file}) {
push @{$dep_map->{$file}} => $loaded_by;
$loaded->{$file}++;
}
}
goto &$real_require;
};
{
no strict 'refs';
no warnings 'redefine';
*{'CORE::GLOBAL::require'} = $require;
}
}
sub loaded_by {
my $level = 1;
while(my @caller = caller($level++)) {
next if $caller[0] eq __PACKAGE__;
return [$caller[0], $caller[1]];
}
return ['', ''];
}
1;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment