File Coverage

blib/lib/Getopt/Abridged.pm
Criterion Covered Total %
statement 119 120 99.1
branch 41 50 82.0
condition 15 21 71.4
subroutine 12 12 100.0
pod 2 2 100.0
total 189 205 92.2


line stmt bran cond sub pod time code
1             package Getopt::Abridged;
2             $VERSION = v0.0.1;
3              
4 2     2   23811 use warnings;
  2         5  
  2         67  
5 2     2   11 use strict;
  2         4  
  2         67  
6 2     2   18 use Carp;
  2         6  
  2         164  
7              
8 2     2   10 use base 'Getopt::Base';
  2         4  
  2         1905  
9              
10             =head1 NAME
11              
12             Getopt::Abridged - quick and simple full-featured option handling
13              
14             =head1 SYNOPSIS
15              
16             sub main {
17             my @args = @_;
18              
19             my $opt = Getopt::Abridged->new(
20             'w|world=s=world',
21             'g|greeting=s=hello',
22             'v|verbose=1',
23             'q|quiet=!verbose',
24             -positional => ['world'],
25             )->process(\@args) or return;
26              
27             print $opt->greeting, ' ', $opt->world, "\n" if($opt->verbose);
28             }
29              
30             main(@ARGV) if($0 eq __FILE__);
31              
32             =head1 About
33              
34             This module is provided as a shortcut for using Getopt::Base and to
35             support easily transitioning into Getopt::AsDocumented.
36              
37             =cut
38              
39             =head2 new
40              
41             my $opt = Getopt::Abridged->new(@opts, @args);
42              
43             =cut
44              
45             sub new {
46 2     2 1 25 my $package = shift;
47 2         10 my (@args) = @_;
48 2         18 my $self = $package->SUPER::new();
49              
50 2         77 my $order = $self->{defined_options} = [];
51              
52             my %opt_do = (
53             -positional => sub {
54 1     1   2 my $list = shift;
55 1 50 50     8 ((ref($list)||'') eq 'ARRAY') or
56             croak("'positional' value must be an array-ref");
57 1         11 $self->add_positionals(@$list);
58             },
59 2         19 );
60 2         18 my %type_map = (
61             s => 'string',
62             i => 'integer',
63             n => 'number',
64             );
65 2         9 while(@args) {
66 13         484 my $opt = shift(@args);
67 13 100       37 if($opt =~ m/^-/) {
68 1 50       5 @args or croak("'$opt' must have a value");
69 1         3 my $val = shift(@args);
70 1 50       5 my $do = $opt_do{$opt} or croak("no such option: $opt");
71 1         32 $do->($val);
72             }
73             else {
74 12         43 my ($spec, $type, @def) = split(/=/, $opt, 3);
75 12         18 my %setup;
76 12 100       87 if(! defined($type)) {
    100          
77 1         3 $type = '0';
78             }
79             elsif($type =~ s/^(\@|\%)//) {
80 4 100       17 $setup{form} = ($1 eq '@' ? 'ARRAY' : 'HASH');
81             }
82              
83 12         36 my @spec = split(/\|/, $spec);
84 12         17 my @short;
85 12   66     90 push(@short, shift(@spec))
86             while(@spec and length($spec[0]) == 1);
87              
88 12         21 my $long = pop(@spec);
89              
90 12 100       46 if(@def) {
    100          
    100          
91 6         8 my $def = shift(@def);
92 6 100       41 $setup{default} = $setup{form} ?
    100          
93             ($setup{form} eq 'ARRAY' ?
94             [split(/,/, $def)] : {split(/,|=/, $def)}
95             ) : $def;
96             }
97             elsif($type =~ m/^[10]/) {
98 2         4 $setup{type} = 'boolean';
99 2         5 $setup{default} = $type;
100             }
101             elsif($type =~ s/^\!//) {
102 2         6 my $name = 'no_' . $type;
103 2         4 push(@$order, $name);
104 2         9 $self->add_aliases($name => \@short, @spec, $long);
105 2         52 next;
106             }
107              
108 10         19 push(@$order, $long);
109              
110 10 50 66     51 $setup{type} ||= $type_map{$type} or
111             croak("no such type '$type'");
112              
113 10 100       30 $setup{short} = [@short] if(@short);
114 10 50       22 $setup{aliases} = [@spec] if(@spec);
115 10         45 $self->add_option($long => %setup);
116             }
117             }
118              
119 2         34 return($self);
120             } # new ################################################################
121              
122             =head2 import
123              
124             This translates your options into pod for use with Getopt::AsDocumented.
125              
126             Getopt::Abridged->import('pod');
127              
128             =cut
129              
130             my %installed;
131             sub import {
132 4     4   14773 my $package = shift;
133 4 100       2927 my @arg = @_ or return;
134              
135 2 50       6 (@arg == 1) or croak("usage: import('pod')");
136             my $process = sub {
137 2     2   2209 my $self = shift;
138 2 100       209 @_ and croak("should have no arguments!");
139 1         5 $self->print_pod;
140 1         5 return();
141 2         8 };
142              
143 2         4 $installed{process} = 1;
144 2     2   9624 { no strict 'refs'; *{$package . '::process'} = $process};
  2         5  
  2         198  
  2         3  
  2         4  
  2         11  
145              
146             } # import #############################################################
147              
148             =head2 unimport
149              
150             Getopt::Abridged->unimport;
151              
152             =cut
153              
154             sub unimport {
155 1     1   262 my $package = shift;
156 1         4 foreach my $key (keys %installed) {
157 1 50       4 delete($installed{$key}) or next;
158 2     2   12 my $st = do {no strict 'refs'; \%{$package . '::'}};
  2         3  
  2         1688  
  1         2  
  1         2  
  1         4  
159 1         8 delete($st->{$key});
160             }
161             } # unimport ###########################################################
162              
163             our $PODHANDLE;
164              
165             =head2 print_pod
166              
167             This is activated via import and the call to process(). If your
168             application is written to return/exit when process() returns false, you
169             may simply do:
170              
171             perl -MGetopt::Abridged=pod -S your_program
172              
173             You will then want to see L and change your
174             process() call to:
175              
176             Getopt::AsDocumented->process(\@args) or return;
177              
178             The builtin --version and --help options will be automatically included
179             in the pod output.
180              
181             TODO C<=for positional> directives need to be printed from here.
182              
183             =cut
184              
185             sub print_pod {
186 1     1 1 2 my $self = shift;
187              
188 1   50     5 my $fh = $PODHANDLE || \*STDOUT;
189              
190 1         10 require File::Basename;
191 1         66 my $name = File::Basename::basename($0);
192 1         6 print $fh "=head1 Usage\n\n $name [options]\n\n";
193 1         3 print $fh "=head1 Options\n\n=over\n\n";
194              
195             # Best way I can think of at the moment to get them to come out in the
196             # same order:
197 1 50       8 my $order = $self->{defined_options} or
198             croak("must have defined some options for me to print pod");
199              
200 1         2 my $optd = $self->{opt_data};
201              
202 1         3 my $short = $self->{short};
203 1         2 my %shortmap;
204 1         6 foreach my $s (keys %$short) {
205 4   50     23 my $list = $shortmap{$short->{$s}} ||= [];
206 4         11 push(@$list, $s);
207             }
208              
209 1         3 my $aliases = $self->{aliases};
210 1         2 my %aliasmap;
211 1         4 foreach my $n (keys %$aliases) {
212 1   50     9 my $list = $aliasmap{$aliases->{$n}} ||= [];
213 1         4 push(@$list, $n);
214             }
215              
216              
217 1         4 foreach my $canon (@$order) {
218 5         12 my $item = $optd->{$canon};
219 5   100     15 my $short = $shortmap{$canon} || [];
220 5   100     18 my $alias = $aliasmap{$canon} || [];
221              
222 4         14 print $fh "=item ",
223 6         11 join(', ', map({"-$_"} @$short),
224 5         9 map({s/_/-/g; $_} map({"--$_"} @$alias, $canon)));
  6         18  
  6         13  
225              
226 5 100       19 if($item->{type} ne 'boolean') {
227 3         6 my $example = uc($canon);
228 3 100       7 if(my $f = $item->{form}) {
229 1 50       3 if($f eq 'HASH') {
230 0         0 $example = 'NAME=' . $example;
231             }
232             else {
233 1         4 $example .= ' [' . (map({s/_/-/g; $_} '--' . $canon))[0] .
  1         2  
  1         4  
234             ' ...]';
235             }
236             }
237              
238 3 100       12 $example .= ' ' . "($item->{type})" if($item->{type} ne 'string');
239              
240 3         7 print $fh " ", $example;
241             }
242 5         19 print $fh "\n\nThe $canon.\n\n";
243 5 100 100     25 if(defined($item->{default}) and $canon !~ m/^no_/) {
244 3         11 print $fh "DEFAULT: $item->{default}\n\n";
245             }
246             }
247              
248 1         3 print $fh "=item --version\n\nPrint version number and quit.\n\n";
249 1         2 print $fh "=item -h, --help\n\nShow help about options.\n\n";
250              
251 1         5 print $fh "=back\n\n=cut\n\n";
252             } # print_pod ##########################################################
253              
254             =head1 AUTHOR
255              
256             Eric Wilhelm @
257              
258             http://scratchcomputing.com/
259              
260             =head1 BUGS
261              
262             If you found this module on CPAN, please report any bugs or feature
263             requests through the web interface at L. I will be
264             notified, and then you'll automatically be notified of progress on your
265             bug as I make changes.
266              
267             If you pulled this development version from my /svn/, please contact me
268             directly.
269              
270             =head1 COPYRIGHT
271              
272             Copyright (C) 2009 Eric L. Wilhelm, All Rights Reserved.
273              
274             =head1 NO WARRANTY
275              
276             Absolutely, positively NO WARRANTY, neither express or implied, is
277             offered with this software. You use this software at your own risk. In
278             case of loss, no person or entity owes you anything whatsoever. You
279             have been warned.
280              
281             =head1 LICENSE
282              
283             This program is free software; you can redistribute it and/or modify it
284             under the same terms as Perl itself.
285              
286             =cut
287              
288             # vi:ts=2:sw=2:et:sta
289             1;