File Coverage

blib/lib/Devel/DidYouMean.pm
Criterion Covered Total %
statement 18 18 100.0
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 24 24 100.0


line stmt bran cond sub pod time code
1 1     1   25751 use 5.008;
  1         3  
  1         30  
2 1     1   4 use strict;
  1         1  
  1         29  
3 1     1   4 use warnings;
  1         9  
  1         45  
4             package Devel::DidYouMean;
5             $Devel::DidYouMean::VERSION = '0.05';
6 1     1   442 use Text::Levenshtein;
  1         611  
  1         35  
7 1     1   363 use Perl::Builtins;
  1         2998  
  1         45  
8              
9             # ABSTRACT: Intercepts failed function and method calls, suggesting the nearest matching alternative.
10              
11              
12             our $DYM_MATCHING_SUBS = [];
13              
14             $SIG{__DIE__} = sub {
15              
16 1     1   5 no strict qw/refs/;
  1         1  
  1         300  
17             my ($error, $package, $sub_name, $new_error) = @_;
18              
19             my $undef_sub = qr/^Undefined subroutine &(.+?) called (at .+?\.)/;
20             my $missing_method = qr/^Can't locate object method "(.+?)" via package "(.+?)" (at .+?\.)/;
21              
22             if ($error =~ /$undef_sub/)
23             {
24             my @sub_path = split /::/, $1;
25             $sub_name = pop @sub_path;
26             $package = join '::', @sub_path;
27             $new_error = $2;
28             }
29             elsif ($error =~ /$missing_method/)
30             {
31             $sub_name = $1;
32             $package = $2;
33             $new_error = $3;
34             }
35             else
36             {
37             print "No match\n";
38             return undef;
39             }
40              
41             my $package_namespace = $package . '::';
42             my %valid_subs = ();
43              
44             for (keys %$package_namespace)
45             {
46             my $absolute_name = $package_namespace . $_;
47             if (defined &{$absolute_name})
48             {
49             $valid_subs{$_} = Text::Levenshtein::fastdistance($sub_name, $_);
50             }
51             }
52              
53             # if package is main, add in builtin functions
54             if ($package eq 'main')
55             {
56             for (Perl::Builtins::list)
57             {
58             $valid_subs{$_} = Text::Levenshtein::fastdistance($sub_name, $_);
59             }
60             }
61              
62             $DYM_MATCHING_SUBS = [];
63             my $match_score;
64              
65             # return similarly named functions
66             for (sort { $valid_subs{$a} <=> $valid_subs{$b} } keys %valid_subs)
67             {
68             $match_score = $valid_subs{$_} unless $match_score;
69              
70             if ($match_score < $valid_subs{$_})
71             {
72             die $error . "Did you mean " . join(', ', @$DYM_MATCHING_SUBS) . "?\n";
73             }
74             push @$DYM_MATCHING_SUBS, $_;
75             }
76             };
77              
78             1;
79              
80             __END__