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