File Coverage

blib/lib/Term/Menus/FromFile.pm
Criterion Covered Total %
statement 21 83 25.3
branch 0 12 0.0
condition n/a
subroutine 7 15 46.6
pod 6 6 100.0
total 34 116 29.3


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3             package Term::Menus::FromFile;
4              
5             =head1 NAME
6              
7             I
8              
9             =head1 SYNOPSIS
10              
11             Lets you store I menu definitions in a file.
12              
13             =head1 DESCRIPTION
14              
15             I reads a file (in a specific format), an uses that to
16             create a menu with I. The menus can either just return their
17             selection (like I) or can call other scripts/programs on your
18             system. In the latter case I will run the program for you,
19             and return the output of the program.
20              
21             There are seperate functions for if you have an open filehandle, or just the
22             path to the file. If you want multiple return values, there are functions
23             wrapping I's menu function as well. (Note: The 'call the chosen
24             script' ablity does not exist for multiple return value menus.)
25              
26             =head1 USAGE
27              
28             No functions are imported by default: you'll have to import them yourself.
29             Avalible functions are listed below.
30              
31             =head2 Menu File Format
32              
33             The file format is fairly straightforward: At the top of the file is a
34             'Title' line, followed by menu entry lines. Menu entries have three fields,
35             seperated by semicolons. The fields are: 'Order', 'Menu_text' and 'Command'.
36             The 'Command' field is only relevant if you want to call a script on selection.
37             Title lines must start with C<#TITLE:>.
38              
39             Example file:
40              
41             #TITLE:Menu 1
42             1;Item 1;
43             2;Item 2;perl test_data/test_command.pl
44             3;Item 3;fiddledo
45              
46             In the example, 'Item 1' has no command, 'Item 2' uses C to run a script
47             and 'Item 3' runs the C command directly. (I wonder what that does...)
48              
49             =head2 Functions
50              
51             =head3 Possible Exports
52              
53             pick_from_filename pick_command_from_filename
54             pick_from_file pick_command_from_file
55             menu_from_filename menu_from_file
56              
57             =cut
58              
59 5     5   232891 use 5.006; # This module uses some Perl 5.6 semantics.
  5         18  
  5         208  
60              
61 5     5   26 use warnings;
  5         13  
  5         140  
62 5     5   24 use strict;
  5         15  
  5         167  
63 5     5   27 use Carp;
  5         17  
  5         424  
64 5     5   26 use Exporter;
  5         10  
  5         207  
65 5     5   24563 use Term::Menus;
  5         3038234  
  5         673  
66              
67 5     5   57 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
  5         16  
  5         5014  
68              
69             @ISA = qw(Exporter);
70              
71             $VERSION = '1.00.00';
72              
73             @EXPORT_OK = qw(pick_from_filename pick_command_from_filename
74             pick_from_file pick_command_from_file
75             menu_from_filename menu_from_file
76             );
77            
78             #%EXPORT_TAGS = (PICKS => [qw(pick_from_filename pick_command_from_filename
79             # pick_from_file pick_command_from_file
80             # )]
81             # ,MENUS => [qw(menu_from_filename menu_from_file)]
82             # ,FILENAMES => [qw(pick_from_filename pick_command_from_filename
83             # menu_from_filename
84             # )]
85             # ,FILES => [qw(pick_from_file pick_command_from_file menu_from_file)]
86             # ,COMMANDS => [qw(pick_command_from_filename pick_command_from_file)]
87             # ,NO_CMD => [qw(pick_from_filename pick_from_file menu_from_filename
88             # menu_from_file
89             # )]
90             # );
91              
92             =head3 pick_from_filename
93              
94             =over 4
95              
96             =item Arguments
97              
98             One argument: The name of the menu file.
99              
100             =item Return Value
101              
102             Returns the menu item picked. (By text, as in I's C function.)
103              
104             =back
105              
106             Opens a menu file, reads it, displays a menu to the user, and returns the user-picked
107             value to the program. It will C if it can't find or open the menu file, or
108             if the file parses to an empty menu.
109              
110             =cut
111              
112             sub pick_from_filename ($) {
113 0     0 1   my $menu_file_name = shift;
114            
115             # Open the menu file, if it exists.
116 0           my $menu_file = _open_file($menu_file_name);
117            
118             # Call pick_from_file to get the actual pick.
119 0           return pick_from_file($menu_file);
120             }
121              
122             =head3 pick_command_from_filename
123              
124             =over 4
125              
126             =item Arguments
127              
128             One argument: The name of the menu file.
129              
130             =item Return Value
131              
132             Returns the output of the command that was run.
133              
134             =back
135              
136             Opens a menu file, reads it, displays a menu to the user, and runs the command
137             specifed in the menu file for the menu time the user picked. The output of the
138             command is returned in a scalar. (Note that the return value will be in $?,
139             also called $CHILD_ERROR.)
140              
141             It will C if it can't find or open the menu file, or if the file parses
142             to an empty menu.
143              
144             =cut
145              
146             sub pick_command_from_filename ($) {
147 0     0 1   my $menu_file_name = shift;
148            
149             # Open the menu file, if it exists.
150 0           my $menu_file = _open_file($menu_file_name);
151            
152             # Call pick_command_from_file to get the actual pick.
153 0           return pick_command_from_file($menu_file);
154              
155             }
156              
157             =head3 pick_from_file
158              
159             =over 4
160              
161             =item Arguments
162              
163             One argument: An open filehandle.
164              
165             =item Return Value
166              
167             Returns the menu item picked. (By text, as in I's C function.)
168              
169             =back
170              
171             Reads an already opened menu file, displays the menu to the user, and returns the
172             user-picked value to the program. It will C if it can't find or open the
173             menu file, or if the file parses to an empty menu.
174              
175             =cut
176              
177             sub pick_from_file ($) {
178 0     0 1   my $menu_file = shift;
179              
180 0           (my $title, my $menu_lines) = _parse_file($menu_file);
181 0           my @menu_lines = @$menu_lines;
182            
183             # Sort the array correctly, then drop extra info.
184 0           @menu_lines = map { $$_{'menu_item'} } (sort { $$a{'order'} <=> $$b{'order'} } @menu_lines);
  0            
  0            
185            
186             # Return the user's pick.
187 0           return pick(\@menu_lines, $title);
188             }
189              
190             =head3 pick_command_from_file
191              
192             =over 4
193              
194             =item Arguments
195              
196             One argument: An open filehandle.
197              
198             =item Return Value
199              
200             Returns the output of the command that was run.
201              
202             =back
203              
204             Reads an already open menu file, displays the menu to the user, and runs the command
205             specifed in the menu file for the menu time the user picked. The output of the
206             command is returned in a scalar. (Note that the return value will be in $?,
207             also called $CHILD_ERROR.)
208              
209             It will C if it can't find or open the menu file, or if the file parses
210             to an empty menu.
211              
212             =cut
213              
214             sub pick_command_from_file ($) {
215 0     0 1   my $menu_file = shift;
216            
217 0           (my $title, my $menu_lines) = _parse_file($menu_file);
218 0           my @menu_lines = @$menu_lines;
219            
220             # Sort the menu items into the correct order.
221 0           @menu_lines = sort { $$a{'order'} <=> $$b{'order'} } @menu_lines;
  0            
222            
223             # Grab the commands, then the menu items themselves
224             # and trash the rest.
225 0           my %command = map { $$_{'menu_item'} => $$_{'command'} } @menu_lines;
  0            
226 0           @menu_lines = map { $$_{'menu_item'} } @menu_lines;
  0            
227            
228             # Get the user's pick.
229 0           my $menu_pick = pick(\@menu_lines, $title);
230            
231             # Check to see if they actually choose anything...
232 0 0         if ($menu_pick eq ']quit[') {
233             # This isn't an error, so we don't throw one,
234             # but the caller should be able to tell nothing was done.
235 0           return ']quit[';
236             }
237            
238             # Run the command, and return the output.
239             # (The return value will be avalible in $?, or $CHILD_ERROR.)
240 0           my $return = eval { `$command{$menu_pick}`; };
  0            
241 0 0         if ($?) {
242 0           carp "Unable to run user's command choice: $command{$menu_pick} $!\n";
243             }
244 0           return $return;
245             }
246              
247             =head3 menu_from_filename
248              
249             =over 4
250              
251             =item Arguments
252              
253             One argument: The name of the menu file.
254              
255             =item Return Value
256              
257             Returns the menu items picked. (By text in an array reference,
258             as in I's C function.)
259              
260             =back
261              
262             Opens a menu file, reads it, displays a menu to the user, and returns the user-picked
263             values to the caller. It will C if it can't find or open the menu file, or
264             if the file parses to an empty menu.
265              
266             I< B >
267              
268             =cut
269              
270             sub menu_from_filename ($) {
271 0     0 1   my $menu_file_name = shift;
272            
273             # Open the menu file, if it exists.
274 0           my $menu_file = _open_file($menu_file_name);
275              
276             # Call menu_from_file to get the actual menu picks.
277 0           return menu_from_file($menu_file);
278             }
279              
280             =head3 menu_from_file
281              
282             =over 4
283              
284             =item Arguments
285              
286             One argument: An open filehandle.
287              
288             =item Return Value
289              
290             Returns the menu items picked. (By text in an array reference,
291             as in I's C function.)
292              
293             =back
294              
295             Reads an open menu file, displays a menu to the user, and returns the user-picked
296             values to the caller. It will C if it can't find or open the menu file, or
297             if the file parses to an empty menu.
298              
299             I< B >
300              
301             =cut
302              
303             sub menu_from_file ($) {
304 0     0 1   my $menu_file = shift;
305            
306 0           (my $title, my $menu_lines) = _parse_file($menu_file);
307 0           my @menu_lines = @$menu_lines;
308            
309             # Sort the array correctly, then drop extra info.
310 0           @menu_lines = map { $$_{'menu_item'} } (sort { $$a{'order'} <=> $$b{'order'} } @menu_lines);
  0            
  0            
311            
312             # Return the user's choices.
313 0           return Menu(\@menu_lines,$title);
314             }
315              
316             ####################################################
317             #
318             # Below here are private functions.
319             #
320             ####################################################
321              
322              
323             # Opens a file for reading, and returns a filehandle.
324             # Arugments: The name of the file, in a scalar.
325             # Return value: A filehandle, in a scalar.
326             # Croaks if the file can't be found, or if there were
327             # Errors opening it.
328             sub _open_file ($) {
329 0     0     my $menu_file_name = shift;
330            
331             # Open the menu file, if it exists.
332 0           my $menu_file;
333 0 0         if ( -e $menu_file_name ) {
334 0 0         open $menu_file, '<', $menu_file_name or croak "Unable to open menu file $menu_file_name: $!/n";
335             }
336             else {
337 0           croak "The menu file $menu_file_name does not exist.\n";
338             }
339              
340 0           return $menu_file;
341             }
342              
343             # Parses an open file.
344             # Arguments: A filehandled, in a scalar.
345             # Return Value: A two-member list. The first value is
346             # the title of the menu, and the second is a reference to
347             # an array with the menu items.
348             # Each menu item is a hash in the array, containing three
349             # values: 'order', 'menu_item', and 'command'.
350             # Croaks if no menu times were found in the file.
351             sub _parse_file ($) {
352 0     0     my $menu_file = shift;
353            
354             # Read out the title, which should be the first thing in the file.
355 0           my $title;
356 0           while (my $line = <$menu_file>) {
357 0           print $line;
358 0 0         if ($line =~ /#TITLE:(.*)/ ) {
359 0           $title = $1;
360 0           last;
361             }
362             }
363            
364             #Break out the menu items, into an array.
365 0           my @menu_lines;
366 0           while (my $line = <$menu_file>) {
367 0           print $line;
368 0           my %menu_item;
369 0           ($menu_item{'order'}, $menu_item{'menu_item'}, $menu_item{'command'})
370             = split /;/, $line;
371 0           push @menu_lines, \%menu_item;
372             }
373            
374 0 0         if ($#menu_lines <= 0) {
375 0           croak "There are no entries in the menu file given.\n";
376             }
377            
378 0           return ($title, \@menu_lines);
379             }
380              
381             =head1 CAVEATS
382              
383             The menu file is basically assumed to be valid, if we managed to parse any
384             lines. We probably shouldn't do that.
385              
386             Also, the title is required, when it really should be optional.
387              
388             And comments. We don't allow comments.
389              
390             There are some forms of menus that I supports that we don't.
391              
392             The 'menu' functions don't work, until I figure out what format I
393             actually does support.
394              
395             =head1 REQUIRES
396              
397             Perl 5.6
398              
399             Term::Menus
400              
401             =head1 AUTHOR
402              
403             Daniel T. Staal
404              
405             DStaal@usa.net
406              
407             =head1 SEE ALSO
408              
409             L
410              
411             =head1 COPYRIGHT and LICENSE
412              
413             Copyright (c) 2008 Daniel T. Staal. All rights reserved.
414             This program is free software; you can redistribute it and/or
415             modify it under the same terms as Perl itself.
416              
417             This copyright will expire in 30 years, or 5 years after the author's
418             death, whichever is longer.
419              
420             =cut
421              
422             1;