File Coverage

blib/lib/App/CmdDispatch/Help.pm
Criterion Covered Total %
statement 117 117 100.0
branch 60 64 93.7
condition 8 11 72.7
subroutine 26 26 100.0
pod 5 5 100.0
total 216 223 96.8


line stmt bran cond sub pod time code
1             package App::CmdDispatch::Help;
2              
3 9     9   75287 use warnings;
  9         29  
  9         330  
4 9     9   50 use strict;
  9         16  
  9         17435  
5              
6             our $VERSION = '0.44';
7              
8             sub new
9             {
10 39     39 1 1576 my ( $class, $owner, $commands, $config ) = @_;
11 39   100     116 $config ||= {};
12 39 100       116 die "Command definition is not a hashref.\n" unless ref $commands eq ref {};
13 37 100       64 die "No commands specified.\n" unless keys %{$commands};
  37         106  
14 36 100       133 die "Config parameter is not a hashref.\n" unless ref $config eq ref {};
15 35 100       62 die "Invalid owner object.\n" unless eval { $owner->isa( 'App::CmdDispatch' ); };
  35         188  
16 34         137 _extend_table_with_help( $commands );
17 34         69 my %conf = (
18             indent_hint => ' ',
19             indent_help => ' ',
20             _extract_config_parm( $config, 'indent_hint' ),
21             _extract_config_parm( $config, 'pre_hint' ),
22             _extract_config_parm( $config, 'post_hint' ),
23             _extract_config_parm( $config, 'indent_help' ),
24             _extract_config_parm( $config, 'pre_help' ),
25             _extract_config_parm( $config, 'post_help' ),
26             alias_len => 1,
27             );
28 34         241 return bless { owner => $owner, %conf }, $class;
29             }
30              
31             sub _extract_config_parm
32             {
33 204     204   307 my ( $config, $parm ) = @_;
34 204 100       580 return unless defined $config->{"help:$parm"};
35 6         20 return ( $parm => $config->{"help:$parm"} );
36             }
37              
38             sub _extend_table_with_help
39             {
40 34     34   61 my ( $commands ) = @_;
41             $commands->{help} = {
42 34         124 code => \&_dispatch_help,
43             clue => "help [command|alias]",
44             abstract => 'Display complete help',
45             help => "Display help about commands and/or aliases. Limit display with the\nargument.",
46             };
47             $commands->{hint} = {
48 34         101 code => \&_dispatch_hint,
49             clue => "hint [command|alias]",
50             abstract => 'Display command hints',
51             help => 'A list of commands and/or aliases. Limit display with the argument.',
52             };
53 34         64 return;
54             }
55              
56             sub _dispatch_help
57             {
58 22     22   56 my $owner = shift;
59 22         66 return $owner->{_helper}->help( @_ );
60             }
61              
62             sub _dispatch_hint
63             {
64 24     24   38 my $owner = shift;
65 24         64 return $owner->{_helper}->hint( @_ );
66             }
67              
68             sub _hint_string
69             {
70 80     80   140 my ( $self, $cmd, $maxlen ) = @_;
71 80         127 my $desc = $self->_table->get_command( $cmd );
72 80 50       155 return '' unless $desc;
73 80 100       203 my $indent = ( $maxlen ? ' ' x ( 3 + $maxlen - length $desc->{clue} ) : ' ' );
74 80 100       289 return $desc->{clue} . ( $desc->{abstract} ? $indent . $desc->{abstract} : '' );
75             }
76              
77             sub _clue_string
78             {
79 55     55   123 my ( $self, $cmd ) = @_;
80 55         98 my $desc = $self->_table->get_command( $cmd );
81 55 50       117 return '' unless $desc;
82 55         123 return $desc->{clue};
83             }
84              
85             sub _alias_hint
86             {
87 16     16   40 my ($self, $alias) = @_;
88 16         42 return sprintf "%-$self->{alias_len}s : %s", $alias, $self->_table->get_alias( $alias );
89             }
90              
91             sub _help_string
92             {
93 55     55   90 my ( $self, $cmd ) = @_;
94 55         83 my $desc = $self->_table->get_command( $cmd );
95              
96 55 100       113 return '' unless defined $desc->{help};
97 54         144 return join( "\n", map { $self->{indent_help} . $_ } split /\n/, $desc->{help} );
  65         269  
98             }
99              
100             sub _list_command
101             {
102 39     39   75 my ( $self, $code ) = @_;
103 39         89 $self->_print( "\nCommands:\n" );
104 39         314 foreach my $c ( $self->{owner}->command_list() )
105             {
106             # The following should not be possible. But I'll keep this until
107             # I'm absolutely certain.
108 125 50 33     767 next if $c eq '' or !$self->_table->get_command( $c );
109 125         244 $self->_print( $code->( $c ) );
110             }
111 39         276 return;
112             }
113              
114             sub _find_longest_alias
115             {
116 11     11   20 my ( $self ) = @_;
117 11         15 my $len;
118 11         28 foreach my $c ( $self->{owner}->alias_list() )
119             {
120 14         36 $len = length $c;
121 14 100       50 $self->{alias_len} = $len if $len > $self->{alias_len};
122             }
123 11         23 return;
124             }
125              
126             sub _list_aliases
127             {
128 39     39   68 my ( $self ) = @_;
129 39 100       67 return unless $self->_table->has_aliases;
130              
131 11         42 $self->_find_longest_alias();
132 11         25 $self->_print( "\nAliases:\n" );
133 11         74 foreach my $c ( $self->{owner}->alias_list() )
134             {
135 14         47 $self->_print( $self->{indent_hint} . $self->_alias_hint( $c ) . "\n" );
136             }
137 11         67 return;
138             }
139              
140 61   100 61   253 sub _is_missing { return !defined $_[0] || $_[0] eq ''; }
141              
142             sub _get_abstract_offset
143             {
144 23     23   38 my ( $self ) = @_;
145              
146 23         32 my $maxlen = 0;
147 23         39 my $len;
148 23         42 foreach my $cmd ( $self->_table->command_list() )
149             {
150 76         131 $len = length $self->_table->get_command( $cmd )->{clue};
151 76 100       169 $maxlen = $len if $len > $maxlen;
152             }
153 23         50 return $maxlen;
154             }
155              
156             sub hint
157             {
158 33     33 1 81 my ( $self, $arg ) = @_;
159              
160 33 100       58 if( _is_missing( $arg ) )
161             {
162 20         40 my $maxlen = $self->_get_abstract_offset();
163 20 100       54 $self->_print( "\n$self->{pre_hint}\n" ) if $self->{pre_hint};
164             $self->_list_command(
165 20     64   109 sub { $self->{indent_hint}, $self->_hint_string( $_[0], $maxlen ), "\n"; } );
  64         117  
166 20         98 $self->_list_aliases();
167 20 100       57 $self->_print( "\n$self->{post_hint}\n" ) if $self->{post_hint};
168 20         49 return;
169             }
170              
171 13 100       35 if( $self->_table->get_command( $arg ) )
    100          
    100          
    100          
172             {
173 4         11 $self->_print( "\n", $self->_hint_string( $arg ), "\n" );
174             }
175             elsif( $self->_table->get_alias( $arg ) )
176             {
177 1         4 $self->_print( "\n", $self->_alias_hint( $arg ), "\n" );
178             }
179             elsif( $arg eq 'commands' )
180             {
181 3         7 my $maxlen = $self->_get_abstract_offset();
182 3     12   52 $self->_list_command( sub { $self->{indent_hint}, $self->_hint_string( $_[0], $maxlen ), "\n"; } );
  12         26  
183             }
184             elsif( $arg eq 'aliases' )
185             {
186 3         10 $self->_list_aliases();
187             }
188             else
189             {
190 2         6 $self->_print( "Unrecognized command '$arg'\n" );
191             }
192              
193 13         70 return;
194             }
195              
196             sub help
197             {
198 28     28 1 67 my ( $self, $arg ) = @_;
199              
200 28 100       54 if( _is_missing( $arg ) )
201             {
202 13 100       35 $self->_print( "\n$self->{pre_help}\n" ) if $self->{pre_help};
203             $self->_list_command(
204             sub {
205 37     37   72 $self->{indent_hint}, $self->_clue_string( $_[0] ), "\n",
206             $self->_help_string( $_[0] ), "\n";
207             }
208 13         84 );
209 13         63 $self->_list_aliases();
210 13 100       40 $self->_print( "\n$self->{post_help}\n" ) if $self->{post_help};
211 13         33 return;
212             }
213              
214 15 100       36 if( $self->_table->get_command( $arg ) )
    100          
    100          
    100          
215             {
216             $self->_print( "\n", $self->_clue_string( $arg ),
217 6   66     15 "\n", ( $self->_help_string( $arg ) || $self->{indent_help} . "No help for '$arg'" ),
218             "\n" );
219             }
220             elsif( $self->_table->get_alias( $arg ) )
221             {
222 1         3 $self->_print( "\n", $self->_alias_hint( $arg ), "\n" );
223             }
224             elsif( $arg eq 'commands' )
225             {
226             $self->_list_command(
227             sub {
228 12     12   25 $self->{indent_hint}, $self->_clue_string( $_[0] ), "\n",
229             $self->_help_string( $_[0] ), "\n";
230             }
231 3         21 );
232             }
233             elsif( $arg eq 'aliases' )
234             {
235 3         7 $self->_list_aliases();
236             }
237             else
238             {
239 2         7 $self->_print( "Unrecognized command '$arg'\n" );
240             }
241              
242 15         86 return;
243             }
244              
245             sub normalize_command_help
246             {
247 22     22 1 40 my ( $self, $table ) = @_;
248 22         63 foreach my $cmd ( $table->command_list )
249             {
250 87         196 my $desc = $table->get_command( $cmd );
251 87 100       170 $desc->{clue} = $cmd unless defined $desc->{clue};
252 87 50       164 $desc->{hint} = '' unless defined $desc->{hint};
253 87 100       194 $desc->{help} = '' unless defined $desc->{help};
254             }
255 22         109 return;
256             }
257              
258             sub sort_commands
259             {
260 31 100   31 1 75 return ( sort grep { $_ ne 'hint' && $_ ne 'help' } @_ ), 'hint', 'help';
  123         468  
261             }
262              
263             sub _print
264             {
265 209     209   347 my ( $self ) = shift;
266 209         470 return $self->{owner}->_print( @_ );
267             }
268              
269 515     515   1113 sub _table { return $_[0]->{owner}->{table}; }
270              
271             1;
272             __END__