File Coverage

blib/lib/Common/CLI.pm
Criterion Covered Total %
statement 92 126 73.0
branch 25 40 62.5
condition 5 9 55.5
subroutine 17 24 70.8
pod 12 12 100.0
total 151 211 71.5


line stmt bran cond sub pod time code
1             package Common::CLI;
2              
3 2     2   82735 use warnings;
  2         5  
  2         79  
4 2     2   12 use strict;
  2         4  
  2         77  
5              
6 2     2   10 use Carp qw(confess);
  2         8  
  2         138  
7 2     2   9605 use Data::Dumper;
  2         23791  
  2         161  
8 2     2   2632 use Data::FormValidator;
  2         75095  
  2         101  
9 2     2   3376 use Getopt::Long;
  2         29919  
  2         16  
10 2     2   432 use File::Basename qw(basename);
  2         6  
  2         3197  
11              
12             our $VERSION = '0.04';
13              
14             sub new {
15 6     6 1 3338 my $class = shift;
16 6         10 my $self = {};
17 6         14 bless $self, $class;
18 6         28 $self->init(@_);
19 6         12 return $self;
20             }
21              
22             sub init {
23 6     6 1 14 my ( $self, %args ) = @_;
24              
25             #
26             # This allow us to override hard coded arguments in constructor.
27             #
28 6 100       23 %args = $self->arguments() if !exists $args{profile};
29              
30 6         28 my ( $profile, $options, $help ) = __parse_profile( $args{profile} );
31 6         25 $self->options($options);
32 6         20 $self->profile($profile);
33 6         35 $self->help($help);
34 6         13 my $input = __parse_command_line_options($options);
35 6         28 $self->input($input);
36 6         14 return;
37             }
38              
39             sub profile {
40 13     13 1 22 my $self = shift;
41 13 100       28 $self->{profile} = shift if @_;
42 13         38 return $self->{profile};
43             }
44              
45             sub options {
46 7     7 1 514 my $self = shift;
47 7 100       39 $self->{options} = shift if @_;
48 7         14 return $self->{options};
49             }
50              
51             sub help {
52 7     7 1 721 my $self = shift;
53 7 100       17 $self->{help} = shift if @_;
54 7         14 return $self->{help};
55             }
56              
57             sub input {
58 12     12 1 13 my $self = shift;
59 12 100       28 $self->{input} = shift if @_;
60 12         24 return $self->{input};
61             }
62              
63             sub validate_options {
64 6     6 1 490 my $self = shift;
65              
66 6         13 my $results = Data::FormValidator->check( $self->input(), $self->profile() );
67              
68 6 100 100     2192 if ( $results->has_invalid or $results->has_missing ) {
69 4         33 return ( undef, [ $results->invalid ], [ $results->missing ] );
70             }
71              
72             #
73             # Data::FormValidator::Results->valid returns a hashref in scalar
74             # context.
75             #
76              
77 2         34 return scalar $results->valid;
78             }
79              
80             sub run {
81 0     0 1 0 my $self = shift;
82              
83 0         0 my ( $options, $invalid, $missing ) = $self->validate_options();
84              
85             #
86             # We don't have suitable options to use, show invalid or missing
87             # fields before displaying help and exiting.
88             #
89              
90 0 0 0     0 if ( $invalid or $missing ) {
91 0         0 __display_usage();
92 0 0       0 __display_invalid($invalid) if $invalid;
93 0 0       0 __display_missing($missing) if $missing;
94 0         0 $self->display_help();
95 0         0 exit(1);
96             }
97              
98 0 0       0 if ( $options->{help} ) {
99 0         0 __display_usage();
100 0         0 $self->display_help();
101 0         0 exit(0);
102             }
103              
104 0         0 my $status = $self->main($options);
105              
106 0         0 return $status;
107             }
108              
109             sub main {
110 0     0 1 0 confess "main() must be overriden";
111             }
112              
113             sub arguments {
114 0     0 1 0 return ( profile => { optional => [ [ 'help', 'Displays this help' ], ], } );
115             }
116              
117             sub merge_arguments {
118 1     1 1 24 my ( $self, $left, $right ) = @_;
119              
120 1         2 for my $flag (qw( required optional )) {
121 2         3 for ( @{ $right->{profile}{$flag} } ) {
  2         6  
122 1         1 push @{ $left->{profile}{$flag} }, $_;
  1         4  
123             }
124             }
125              
126 1         3 for my $flag (qw( defaults constraint_methods )) {
127 2 100 66     11 if ( $right->{profile}{$flag}
128             and ref $right->{profile}{$flag} eq 'HASH' )
129             {
130              
131 1         2 for ( keys %{ $right->{profile}{$flag} } ) {
  1         3  
132 1 50       7 $left->{profile}{$flag}{$_} = $right->{profile}{$flag}{$_}
133             unless exists $left->{profile}{$flag}{$_};
134             }
135             }
136             }
137              
138 1         4 return %$left;
139             }
140              
141             sub display_help {
142 0     0 1 0 my $self = shift;
143              
144 0         0 for my $item ( @{ $self->help } ) {
  0         0  
145 0         0 my $message = '';
146 0         0 $message .= " --" . $item->[0] . "\n";
147 0         0 $message .= "\t" . $item->[1];
148              
149 0 0       0 if ( ${ $self->profile }{defaults}{ $item->[2] } ) {
  0         0  
150 0         0 $message .= " (default: " . ${ $self->profile }{defaults}{ $item->[2] } . ")";
  0         0  
151             }
152              
153 0         0 $message .= "\n";
154              
155 0         0 print $message;
156             }
157             }
158              
159             sub __parse_profile {
160 6     6   10 my ($profile) = @_;
161              
162 6         8 my @options;
163             my %profile;
164 0         0 my @help;
165              
166 6         9 for my $spec (qw( optional required )) {
167 12 100       36 next if !exists $profile->{$spec};
168 6 50       19 if ( ref $profile->{$spec} eq 'ARRAY' ) {
169 6         9 for ( @{ $profile->{$spec} } ) {
  6         12  
170 7 50       16 next if ref ne 'ARRAY';
171              
172             # store help data
173 7         24 my @help_data = ( $_->[0], $_->[1] );
174              
175             # store `Getopt::Long' description
176 7         11 unshift @options, $_->[0];
177              
178             # remove `Getopt::Long' required data, store only the
179             # required bits for `Data::FormValidator'
180 7         33 ( $_ = $_->[0] ) =~ s/=.*$//;
181              
182             # store stripped option
183 7         22 push @help_data, $_;
184 7         14 push @help, \@help_data;
185              
186 7 100       25 $profile{$spec} = [] if !exists $profile{$spec};
187 7         7 unshift @{ $profile{$spec} }, $_;
  7         26  
188             }
189             }
190             }
191              
192 6         11 for my $spec (qw( constraint_methods require_some defaults )) {
193 18 100       39 next if !exists $profile->{$spec};
194 4 50       11 next if ref $profile->{$spec} ne 'HASH';
195 4         5 for my $k ( keys %{ $profile->{$spec} } ) {
  4         11  
196 5         18 $profile{$spec}{$k} = $profile->{$spec}{$k};
197             }
198             }
199              
200 6         24 return ( \%profile, \@options, \@help );
201             }
202              
203             sub __parse_command_line_options {
204 6     6   8 my ($options) = @_;
205              
206 6         4 my %parsed_options;
207 6 50       8 if ( !GetOptions( \%parsed_options, @{$options} ) ) {
  6         25  
208 0         0 return;
209             }
210 6         1159 return \%parsed_options;
211             }
212              
213             sub __display_missing {
214 0     0     my $missing = shift;
215              
216             }
217              
218             sub __display_invalid {
219 0     0     my $invalid = shift;
220              
221             }
222              
223             sub __display_usage {
224 0     0     my $name = basename($0);
225 0           print "\nUsage: $0 OPTIONS\n\n";
226             }
227              
228             1;
229              
230             __END__