File Coverage

blib/lib/Data/CTable/Script.pm
Criterion Covered Total %
statement 21 65 32.3
branch 0 4 0.0
condition 0 2 0.0
subroutine 7 14 50.0
pod 0 6 0.0
total 28 91 30.7


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2             ## Emacs: -*- tab-width: 4; -*-
3              
4 1     1   843 use strict;
  1         3  
  1         57  
5              
6             package Data::CTable::Script;
7              
8 1     1   21 use vars qw($VERSION); $VERSION = '0.1';
  1         2  
  1         60  
9              
10             =pod
11              
12             =head1 NAME
13              
14             Data::CTable::Script - CTable virtual subclass to support shell scripts
15              
16             =head1 SYNOPSIS
17              
18             ## Call from a shell script:
19             use Data::CTable::Script;
20             exit !Data::CTable::Script->script();
21              
22             ## But more likely, you'll want to subclass first:
23             use Data::CTable::MyScript;
24             exit !Data::CTable::MyScript->script();
25              
26             This is an OO implementation of the outermost structure and utlility
27             routines that would be needed by most any perl/shell script that wants
28             to use Data::CTable functionality.
29              
30             See Data::CTable::Lister for a sample subclass that uses this
31             superstructure to implement a command-line tool that makes a table
32             containing file listings and then lets the user manipulate it using
33             various command-line options and then output it in various interesting
34             ways.
35              
36             See Data::CTable for the superclass.
37              
38             =head1 FURTHER INFO
39              
40             See the Data::CTable home page:
41              
42             http://christhorman.com/projects/perl/Data-CTable/
43              
44             =head1 AUTHOR
45              
46             Chris Thorman
47              
48             Copyright (c) 1995-2002 Chris Thorman. All rights reserved.
49              
50             This program is free software; you can redistribute it and/or modify
51             it under the same terms as Perl itself.
52              
53             =cut
54             {};
55              
56 1     1   4 use Data::CTable; use vars qw(@ISA);
  1     1   2  
  1         35  
  1         4  
  1         2  
  1         54  
57             @ISA = qw(Data::CTable);
58              
59             =pod
60              
61             =head1 METHODS
62              
63             $Class->usage() ## Don't subclass
64             $Class->usage_message($ScriptName) ## Subclass this
65              
66             usage() figures out the name of the script being called and passes it
67             to usage_message (designed to be sublcassed), which can the print the
68             message including the name of the script.
69              
70             =cut
71              
72             sub usage
73             {
74 0     0 0   my $this = shift;
75              
76             ## This inserts actual name of tool into the documentation.
77 1     1   5 use File::Basename;
  1         1  
  1         450  
78 0           my $ScriptName = join('', (File::Basename::fileparse($0))[0,2]);
79              
80 0           return($this->usage_message($ScriptName));
81             }
82              
83             sub usage_message
84             {
85 0     0 0   my $this = shift;
86 0           my ($ScriptName) = @_;
87              
88 0           return(do{(my $doc = << 'END') =~ s/_SCR_/$ScriptName/g; $doc});
  0            
  0            
89            
90             _SCR_ [options]
91              
92             This is an empty help message for the _SCR_ script. Please subclass
93             this module and override the usage_message() method.
94            
95             END
96 0           {};
97             }
98              
99             =pod
100              
101             $Class->optionspec()
102              
103             Specification for command-line option parsing for the script. Meant
104             to be subclassed.
105              
106             Should return a hash mapping GetOpt::Long-style specifications to
107             default values. This base class implementation returns the following
108             spec entries. Subclasses could replace these entirely or add to them:
109              
110             ## Common options
111             "help" => 0 ,
112             "verbose" => 0 ,
113            
114             ## Which fields are included in output
115             "fields=s" => [],
116            
117             ## Sorting
118             "sort=s" => [],
119            
120             ## Output method
121             "output=s" => [],
122              
123             In the above specs "=s" means a string argument, and [] means multiple
124             values are allowed and will be collected in an array, whose initial
125             contents are empty. 0 means the option defaults to off; a default of
126             foo => 1 would allow the --nofoo switch to turn off the foo option.
127              
128             =cut
129             {};
130              
131             sub optionspec
132             {
133 0     0 0   my $Class = shift;
134              
135 0           my $Spec = {(
136             ## Common options
137             "help" => 0 ,
138             "verbose" => 0 ,
139            
140             ## Which fields are included in output
141             "fields=s" => [],
142            
143             ## Sorting
144             "sort=s" => [],
145            
146             ## Output method
147             "output=s" => [],
148             )};
149            
150 0           return($Spec);
151             }
152              
153             =pod
154            
155             $Class->script()
156              
157             Class method: main entry point for the script. Parses options,
158             presents usage(), instantiates an object and lets it do its work.
159             Returns a Boolean success value. (A perl script should exit() the
160             opposite of this value: i.e. exit(0) means success.)
161              
162             =cut
163              
164             sub script
165             {
166 0     0 0   my $Class = shift;
167            
168 0           my $Success;
169              
170 0           my $OptSpec = $Class->optionspec();
171            
172 0           my ($Opts, $Args) = $Class->get_opts_hash(%$OptSpec);
173            
174 0 0         print ($Class->usage()), goto done if $Opts->{help};
175            
176             ## Place all remaining arguments into the "args" option
177 0           $Opts->{args} = $Args;
178            
179 0           print $ {$Class->run($Opts)};
  0            
180            
181 0           $Success = 1;
182 0           done:
183             return($Success);
184             }
185              
186              
187             =pod
188            
189             $Class->run()
190              
191             Main entry point for the script. Instantiates an object and lets it do
192             its work. Returns a reference to a scalar which will be printed
193             before the script exits. (Pass \ '' for no output).
194              
195             =cut
196             {};
197              
198             sub run
199             {
200 0     0 0   my $Class = shift;
201 0           my ($Opts) = @_;
202            
203 1     1   6 use Data::CTable qw(path_info);
  1         1  
  1         147  
204            
205             ## Create an empty options hash in case we didn't get one.
206 0   0       $Opts ||= {};
207              
208             ## Instantiate an object of this class.
209 0           my $this = $Class->new({_Options => $Opts});
210            
211             ## Do nothing in this base class.
212 0           return(\ '');
213             }
214              
215             =pod
216              
217             $Class->get_opts_hash()
218              
219             Internal method to process command-line options using GetOpt::Long and
220             a few enhancements, most importantly: any multi-valued field is
221             post-processed to treat any values separated by commas or spaces as
222             multiple values.
223              
224             =cut
225              
226             sub get_opts_hash
227             {
228 0     0 0   my $Class = shift;
229 0           my (@Specs) = @_;
230            
231 1     1   1126 use Getopt::Long qw(GetOptions);
  1         21776  
  1         7  
232            
233 0           my $Opts = {};
234             my $mkspec = sub
235             {
236 0     0     my ($Spec, $Default) = @_;
237 0           my ($Opt ) = ($Spec =~ /(\w+)/)[0];
238 0           $Opts->{$Opt} = $Default;
239 0 0         ($Spec => (ref($Opts->{$Opt}) ? $Opts->{$Opt} : \ $Opts->{$Opt}));
240 0           };
241            
242             ## Extract all arguments that seem to be GetOpt-style arguments.
243 0           GetOptions(map {&$mkspec(@Specs[($_*2),($_*2)+1])} (0..int($#Specs/2)));
  0            
244            
245             ## Allow commas and/or spaces to separate values in any
246             ## multi-valued options. (Not tabs -- we might want to accept a
247             ## tab as a valid input character.)
248              
249             ## This goes a bit beyond the customary Getopt::Long paradigm, but
250             ## is convenient since it allows something like -f=f1,f2,f3 -f=f4
251              
252 0           foreach (grep {ref $Opts->{$_} eq 'ARRAY'} keys %$Opts)
  0            
  0            
253 0           {$Opts->{$_} = [map {split(/[ ,]+/)} @{$Opts->{$_}}]};
  0            
254            
255             ## Get any remaining arguments.
256 0           my $Args = [@ARGV];
257            
258             ## Debugging
259             ## use Data::Dumper; print &Dumper($Opts, $Args);
260              
261 0           return($Opts, $Args);
262             }
263              
264             1;