File Coverage

lib/Devel/Trepan/CmdProcessor/Command/Info_Subcmd/Packages.pm
Criterion Covered Total %
statement 57 205 27.8
branch 0 84 0.0
condition 0 10 0.0
subroutine 19 27 70.3
pod n/a
total 76 326 23.3


line stmt bran cond sub pod time code
1             # -*- coding: utf-8 -*-
2             # Copyright (C) 2014 Rocky Bernstein <rocky@cpan.org>
3 12     12   120 use warnings; no warnings 'redefine'; no warnings 'once';
  12     12   46  
  12     12   459  
  12     1   76  
  12     1   31  
  12     1   397  
  12         72  
  12         32  
  12         379  
  1         9  
  1         4  
  1         24  
  1         5  
  1         3  
  1         27  
  1         5  
  1         4  
  1         22  
4 12     12   79 use rlib '../../../../..';
  12     1   34  
  12         79  
  1         6  
  1         3  
  1         4  
5              
6             package Devel::Trepan::CmdProcessor::Command::Info::Packages;
7              
8 12     12   5251 use Devel::Trepan::CmdProcessor::Command::Subcmd::Core;
  12     1   33  
  12         346  
  1         557  
  1         5  
  1         36  
9 12     12   77 use Getopt::Long qw(GetOptionsFromArray);
  12     1   33  
  12         120  
  1         7  
  1         3  
  1         11  
10              
11 12     12   1725 use strict;
  12     1   33  
  12         687  
  1         122  
  1         3  
  1         62  
12             our (@ISA, @SUBCMD_VARS);
13             # Values inherited from parent
14 12     12   77 use vars @Devel::Trepan::CmdProcessor::Command::Subcmd::SUBCMD_VARS;
  12     1   36  
  12         6133  
  1         6  
  1         3  
  1         423  
15              
16             ## FIXME: do automatically.
17             our $CMD = "info packages";
18              
19             unless (@ISA) {
20 12     12   92 eval <<"EOE";
  12         42  
  12         718  
21             use constant MAX_ARGS => undef; # Need at most this many - undef -> unlimited.
22             EOE
23             }
24             @ISA = qw(Devel::Trepan::CmdProcessor::Command::Subcmd);
25             =pod
26              
27             =head2 Synopsis:
28              
29             =cut
30             our $HELP = <<'HELP';
31             =pod
32              
33             B<info packages> [I<options>] [I<match>]
34              
35             options:
36              
37             -e | --exact
38             -p | --prefix
39             -r | --regexp
40             -f | --files
41             -s | --subs
42              
43             The default is C<--prefix>
44              
45             Give package names and optionally the file(s) that package is in for
46             packages matching I<match>. Options control how to interpret the the
47             match pattern.
48              
49             =head2 Examples:
50              
51             info packages Tie:: # match all packages that start with Tie::
52             # e.g. Tie::ExtraHash and Tie::Hash
53             info packages -p Tie:: # same as above
54             info packages -r ^Tie:: # same as above
55             info packages -s Tie:: # same as above, but list the subs
56             # of each package along with the package
57             info packages -e Tie::Hash # match exactly Tie::Hash
58             info packages -e -f Tie::Hash # same as above but show the file(s) where
59             # the package is defined
60             info packages -r ::Tie$ # match Tie only at the end,
61             # e.g. ReadLine::Tie
62             info packages # List all packages
63              
64             =head2 See also:
65              
66             L<C<info functions>|Devel::Trepan::CmdProcessor::Command::Info::Functions>, and
67             L<C<complete>|Devel::Trepan::CmdProcessor::Command::Complete>.
68              
69             =cut
70             HELP
71              
72             our $SHORT_HELP = 'All function names, or those matching REGEXP';
73             our $MIN_ABBREV = length('pa');
74              
75             sub complete($$) {
76 0     0     my ($self, $prefix) = @_;
  0     0      
77 0           my @pkgs = Devel::Trepan::Complete::complete_packages($prefix);
  0            
78 0           my @opts = (qw(-r --regexp -p --prefix -s --subs -f --files),
  0            
79             @pkgs);
80 0           Devel::Trepan::Complete::complete_token(\@opts, $prefix) ;
  0            
81             }
82              
83             my $DEFAULT_OPTIONS = {
84             exact => 0,
85             prefix => 0,
86             regexp => 0,
87             files => 0,
88             funcs => 0,
89             };
90              
91             sub parse_options($$)
92             {
93 0     0     my ($self, $args) = @_;
  0     0      
94 0           my %opts = %$DEFAULT_OPTIONS;
  0            
95             my $result = &GetOptionsFromArray($args,
96             '-e' => \$opts{exact},
97             '--exact' => \$opts{exact},
98             '-r' => \$opts{regexp},
99             '--regexp' => \$opts{regexp},
100             '-f' => \$opts{files},
101             '--files' => \$opts{files},
102             '-p' => \$opts{prefix},
103             '--prefix' => \$opts{prefix},
104             '-s' => \$opts{subs},
105             '--subs' => \$opts{subs}
106 0           );
  0            
107             # Option consistency checking
108 0           my $count = $opts{exact} + $opts{regexp} + $opts{prefix};
  0            
109 0 0         if ($count == 0) {
  0 0          
    0          
    0          
110 0           $opts{prefix} = 1;
  0            
111             } elsif ($count > 1) {
112 0 0         if ($opts{regexp}) {
  0 0          
    0          
    0          
113 0           $self->{proc}->errmsg("regexp option used with prefix and/or exact; regexp used");
  0            
114 0           $opts{prefix} = $opts{exact} = 0;
  0            
115             } elsif ($opts{prefix}) {
116 0           $self->{proc}->errmsg("prefix used with exact; prefix used");
  0            
117 0           $opts{exact} = 0;
  0            
118             }
119             }
120              
121 0           \%opts;
  0            
122              
123             }
124              
125             # FIXME combine with Command::columnize_commands
126 12     12   109 use Array::Columnize;
  12     1   44  
  12         10371  
  1         8  
  1         3  
  1         781  
127             sub columnize_pkgs($$)
128             {
129 0     0     my ($proc, $commands) = @_;
  0     0      
130 0           my $width = $proc->{settings}->{maxwidth};
  0            
131 0           my $r = Array::Columnize::columnize($commands,
  0            
132             {displaywidth => $width,
133             colsep => ' ',
134             ljust => 1,
135             lineprefix => ' '});
136 0           chomp $r;
  0            
137 0           return $r;
  0            
138             }
139              
140             sub run($$)
141             {
142 0     0     my ($self, $args) = @_;
  0     0      
143 0           my @args = @$args;
  0            
144 0           my $options = parse_options($self, \@args);
  0            
145 0           my $proc = $self->{proc};
  0            
146 0           my $match = undef;
  0            
147              
148 0 0         if (@args == 3) {
  0 0          
149 0           $match = $args[2];
  0            
150             }
151              
152 0           my %pkgs;
  0            
153 0           foreach my $function (keys %DB::sub) {
  0            
154 0           my @parts = split('::', $function);
  0            
155 0 0         if (scalar @parts > 1) {
  0 0          
156 0           my $func = pop(@parts);
  0            
157 0           my $pkg = join('::', @parts);
  0            
158 0   0       $pkgs{$pkg} ||= [{}, {}];
  0   0        
159 0 0         if ($options->{files}) {
  0 0          
160 0           my $file_range = $DB::sub{$function};
  0            
161 0 0         if ($file_range =~ /^(.+):(\d+-\d+)/) {
  0 0          
162 0           my ($filename, $range) = ($1, $2);
  0            
163 0           my $files = $pkgs{$pkg}->[0];
  0            
164 0           $files->{$filename} = 1;
  0            
165 0           $pkgs{$pkg}->[0] = $files;
  0            
166             }
167             }
168 0 0         if ($options->{subs}) {
  0 0          
169 0           my $funcs = $pkgs{$pkg}->[1];
  0            
170 0           $funcs->{$func} = 1;
  0            
171 0           $pkgs{$pkg}->[1] = $funcs;
  0            
172             }
173              
174             }
175             }
176 0           my @pkgs = keys %pkgs;
  0            
177 0 0         if ($options->{regexp}) {
  0 0          
    0          
    0          
178 0 0         @pkgs = grep /$match/, @pkgs if defined $match;
  0 0          
179             } elsif ($options->{prefix}) {
180 0 0         @pkgs = grep /^$match/, @pkgs if defined $match;
  0 0          
181             } else {
182 0 0         @pkgs = grep /^$match$/, @pkgs if defined $match;
  0 0          
183             }
184 0 0         if (scalar @pkgs) {
  0 0          
185 0 0 0       if ($options->{files} || $options->{subs}) {
  0 0 0        
186 0           for my $pkg (sort @pkgs) {
  0            
187 0 0         if ($options->{subs}) {
  0 0          
188 0           my $subs = $pkgs{$pkg}->[1];
  0            
189 0           my @subs = sort keys %$subs;
  0            
190 0           $proc->section($pkg);
  0            
191 0 0         if (scalar @subs) {
  0 0          
192 0           my $msg = columnize_pkgs($proc, \@subs);
  0            
193 0           $proc->msg($msg);
  0            
194             } else {
195 0           $proc->msg($pkg);
  0            
196             }
197             }
198 0 0         if ($options->{files}) {
  0 0          
199 0           my $filename = $pkgs{$pkg}->[0];
  0            
200 0           my @files = sort keys %$filename;
  0            
201 0 0         if (scalar @files) {
  0 0          
202 0 0         my $file_str = @files == 1 ? 'file' : 'files';
  0 0          
203 0           my $msg = sprintf("%s is in %s %s", $pkg, $file_str,
  0            
204             join(', ', @files));
205 0           $proc->msg($msg);
  0            
206             } else {
207 0           $proc->msg($pkg);
  0            
208             }
209             }
210             }
211             } else {
212 0           @pkgs = sort @pkgs;
  0            
213 0           my $msg = columnize_pkgs($proc, \@pkgs);
  0            
214 0           $proc->msg($msg);
  0            
215             }
216             } else {
217 0           $proc->msg('No matching package');
  0            
218             }
219             }
220              
221             unless (caller) {
222             # Demo it.
223             require Devel::Trepan::CmdProcessor::Mock;
224             my $proc = Devel::Trepan::CmdProcessor->new(undef, 'bogus');
225             my $cmd = __PACKAGE__->new($proc);
226             $cmd->{proc} = $proc;
227             my $frame_ary = Devel::Trepan::CmdProcessor::Mock::create_frame();
228             $proc->frame_setup($frame_ary);
229             $proc->{settings}{highlight} = 0;
230             %DB::sub = qw(main::gcd 1);
231             $cmd->run([]);
232              
233             # require_relative '../../mock'
234             # my($dbgr, $parent_cmd) = MockDebugger::setup('show');
235             # $cmd = __PACKAGE__->new(parent_cmd);
236             # $cmd->run(@$cmd->prefix);
237             }
238              
239             # Suppress a "used-once" warning;
240             $HELP || scalar @SUBCMD_VARS;