File Coverage

blib/lib/MooseX/Getopt/Basic.pm
Criterion Covered Total %
statement 132 133 99.2
branch 46 54 85.1
condition 10 14 71.4
subroutine 26 28 92.8
pod 2 3 66.6
total 216 232 93.1


line stmt bran cond sub pod time code
1             package MooseX::Getopt::Basic;
2             # ABSTRACT: MooseX::Getopt::Basic - role to implement the Getopt::Long functionality
3              
4             our $VERSION = '0.75';
5              
6 27     27   246606 use Moose::Role;
  27         388690  
  27         216  
7              
8 27     27   161938 use MooseX::Getopt::OptionTypeMap;
  27         76  
  27         1034  
9 27     27   15219 use MooseX::Getopt::Meta::Attribute;
  27         99  
  27         1698  
10 27     27   16106 use MooseX::Getopt::Meta::Attribute::NoGetopt;
  27         92  
  27         1553  
11 27     27   14078 use MooseX::Getopt::ProcessedArgv;
  27         140  
  27         1240  
12 27     27   236 use Try::Tiny;
  27         63  
  27         1825  
13 27     27   177 use Carp ();
  27         55  
  27         660  
14              
15 27     27   1124 use Getopt::Long 2.37 ();
  27         11671  
  27         1322  
16 27     27   148 use namespace::autoclean;
  27         59  
  27         252  
17              
18             has ARGV => (is => 'rw', isa => 'ArrayRef', traits => ['NoGetopt']);
19             has extra_argv => (is => 'rw', isa => 'ArrayRef', traits => ['NoGetopt']);
20              
21             sub process_argv {
22 121     121 1 10448 my ($class, @params) = @_;
23              
24 121 100       469 my $constructor_params = ( @params == 1 ? $params[0] : {@params} );
25              
26 121         237 my $config_from_file;
27 121 100       521 if($class->meta->does_role('MooseX::ConfigFromFile')) {
28 13         4992 local @ARGV = @ARGV;
29              
30             # just get the configfile arg now out of @ARGV; the rest of the args
31             # will be fetched later
32 13         18 my $configfile;
33 13         81 my $opt_parser = Getopt::Long::Parser->new( config => [ qw( no_auto_help pass_through no_auto_version ) ] );
34 13         1207 $opt_parser->getoptions( "configfile=s" => \$configfile );
35              
36 13         3936 my $cfmeta = $class->meta->find_attribute_by_name('configfile');
37 13         832 my $init_arg = $cfmeta->init_arg;
38              
39             # was it passed to the constructor?
40 13 100       32 if (!defined $configfile)
41             {
42 7 50       27 $configfile = $constructor_params->{$init_arg} if defined $init_arg;
43             }
44              
45 13 100       27 if(!defined $configfile) {
46             # this is a classic legacy usecase documented in
47             # MooseX::ConfigFromFile that we should continue to support
48 7     7   42 $configfile = try { $class->configfile };
  7         353  
49              
50 7 50 33     229 $configfile = $cfmeta->default
51             if not defined $configfile and $cfmeta->has_default;
52              
53             # note that this will die horribly if the default sub depends on
54             # other attributes
55 7 100       147 $configfile = $configfile->($class) if ref $configfile eq 'CODE';
56 7 100       104 if (defined $configfile) {
57             $config_from_file = try {
58 4     4   163 $class->get_config_from_file($configfile);
59             }
60             catch {
61 0 0   0   0 die $_ unless /Specified configfile '\Q$configfile\E' does not exist/;
62 4         27 };
63             }
64              
65 7 100 66     12142 $constructor_params->{$init_arg} = $configfile
66             if defined $configfile and defined $init_arg;
67             }
68             else {
69 6         17 $config_from_file = $class->get_config_from_file($configfile);
70             }
71             }
72              
73 121 50       46023 Carp::croak("Single parameters to new_with_options() must be a HASH ref")
74             unless ref($constructor_params) eq 'HASH';
75              
76 121 100       575 my %processed = $class->_parse_argv(
77             options => [
78             $class->_attrs_to_options( $config_from_file )
79             ],
80             params => $config_from_file ? { %$config_from_file, %$constructor_params } : $constructor_params,
81             );
82              
83 111 100       728 my $params = $config_from_file ? { %$config_from_file, %{$processed{params}} } : $processed{params};
  9         33  
84              
85             # did the user request usage information?
86 111 100 100     1229 if ( $processed{usage} and $params->{help_flag} ) {
87 10         4358 $class->print_usage_text($processed{usage});
88 9         2262 exit 0;
89             }
90              
91             return MooseX::Getopt::ProcessedArgv->new(
92             argv_copy => $processed{argv_copy},
93             extra_argv => $processed{argv},
94             usage => $processed{usage},
95 101         91651 constructor_params => $constructor_params, # explicit params to ->new
96             cli_params => $params, # params from CLI
97             );
98             }
99              
100             sub new_with_options {
101 120     120 1 580323 my ($class, @params) = @_;
102              
103 120         470 my $pa = $class->process_argv(@params);
104              
105             # $pa->constructor_params contains everything passed to new_with_options,
106             # so it may contain the "argv" key, which may not exist on the class
107 100         259 my %constructor_params = %{ $pa->constructor_params };
  100         3486  
108 100 50       533 delete $constructor_params{argv} if (not $class->meta->find_attribute_by_name('argv'));
109              
110             $class->new(
111             ARGV => $pa->argv_copy,
112             extra_argv => $pa->extra_argv,
113             ( $pa->usage ? ( usage => $pa->usage ) : () ),
114             %constructor_params, # explicit params to ->new
115 100 100       11419 %{ $pa->cli_params }, # params from CLI
  100         2873  
116             );
117             }
118              
119 23     23   76 sub _getopt_spec { shift->_traditional_spec(@_); }
120              
121             sub _parse_argv {
122 121     121   535 my ( $class, %params ) = @_;
123              
124 121 100       240 local @ARGV = @{ $params{params}{argv} || \@ARGV };
  121         833  
125              
126 121         720 my ( $opt_spec, $name_to_init_arg ) = $class->_getopt_spec(%params);
127              
128             # Get a clean copy of the original @ARGV
129 121         378 my $argv_copy = [ @ARGV ];
130              
131 121         215 my @warnings;
132             my ( $parsed_options, $usage ) = try {
133 121     121   5921 local $SIG{__WARN__} = sub { push @warnings, @_ };
  8         6985  
134              
135 121         580 return $class->_getopt_get_options(\%params, $opt_spec);
136             }
137             catch {
138 10     10   9588 $class->_getopt_spec_exception(\@warnings, $_);
139 121         1071 };
140              
141 111 50       139935 $class->_getopt_spec_warnings(@warnings) if @warnings;
142              
143             # Get a copy of the Getopt::Long-mangled @ARGV
144 111         324 my $argv_mangled = [ @ARGV ];
145              
146             my %constructor_args = (
147             map {
148 111         675 $name_to_init_arg->{$_} => $parsed_options->{$_}
  128         515  
149             } keys %$parsed_options,
150             );
151              
152             return (
153 111 100       1165 params => \%constructor_args,
154             argv_copy => $argv_copy,
155             argv => $argv_mangled,
156             ( defined($usage) ? ( usage => $usage ) : () ),
157             );
158             }
159              
160             sub _getopt_get_options {
161 23     23   57 my ($class, $params, $opt_spec) = @_;
162 23         43 my %options;
163 23         118 Getopt::Long::GetOptions(\%options, @$opt_spec);
164 23         13575 return ( \%options, undef );
165             }
166              
167       0     sub _getopt_spec_warnings { }
168              
169             sub _getopt_spec_exception {
170 10     10   37 my ($self, $warnings, $exception) = @_;
171 10         108 die @$warnings, $exception;
172             }
173              
174             # maintained for backwards compatibility only
175             sub _getopt_full_usage
176             {
177 9     9   112 my ($self, $usage) = @_;
178 9         25 print $usage->text;
179             }
180             #(this is already documented in MooseX::Getopt. But FIXME later, via RT#82195)
181             #pod =for Pod::Coverage
182             #pod print_usage_text
183             #pod =cut
184 9     9 0 184 sub print_usage_text { shift->_getopt_full_usage(@_) }
185              
186             sub _usage_format {
187 98     98   560 return "usage: %c %o";
188             }
189              
190             sub _traditional_spec {
191 23     23   68 my ( $class, %params ) = @_;
192              
193 23         44 my ( @options, %name_to_init_arg );
194              
195 23         38 foreach my $opt ( @{ $params{options} } ) {
  23         62  
196 119         214 push @options, $opt->{opt_string};
197              
198 119         174 my $identifier = $opt->{name};
199 119         235 $identifier =~ s/\W/_/g; # Getopt::Long does this to all option names
200              
201 119         264 $name_to_init_arg{$identifier} = $opt->{init_arg};
202             }
203              
204 23         84 return ( \@options, \%name_to_init_arg );
205             }
206              
207             sub _compute_getopt_attrs {
208 121     121   225 my $class = shift;
209 1089         19322 sort { $a->insertion_order <=> $b->insertion_order }
210             grep {
211 657 100       74535 $_->does("MooseX::Getopt::Meta::Attribute::Trait")
212             or
213             $_->init_arg !~ /^_/
214             } grep {
215 658         25898 defined $_->init_arg
216             } grep {
217 121         433 !$_->does('MooseX::Getopt::Meta::Attribute::Trait::NoGetopt')
  1003         192455  
218             } $class->meta->get_all_attributes
219             }
220              
221             sub _get_cmd_flags_for_attr {
222 603     603   1162 my ( $class, $attr ) = @_;
223              
224 603         1391 my $flag = $attr->init_arg;
225              
226 603         794 my @aliases;
227              
228 603 100       1592 if ($attr->does('MooseX::Getopt::Meta::Attribute::Trait')) {
229 343 100       85814 $flag = $attr->cmd_flag if $attr->has_cmd_flag;
230 343 100       11462 @aliases = @{ $attr->cmd_aliases } if $attr->has_cmd_aliases;
  235         6995  
231             }
232              
233 603         19793 return ( $flag, @aliases );
234             }
235              
236             sub _attrs_to_options {
237 121     121   276 my $class = shift;
238 121   100     612 my $config_from_file = shift || {};
239              
240 121         220 my @options;
241              
242 121         434 foreach my $attr ($class->_compute_getopt_attrs) {
243 603         4585 my ( $flag, @aliases ) = $class->_get_cmd_flags_for_attr($attr);
244              
245 603         1557 my $opt_string = join(q{|}, $flag, @aliases);
246              
247 603 100       22057 if ($attr->name eq 'configfile') {
    100          
248 13         29 $opt_string .= '=s';
249             }
250             elsif ($attr->has_type_constraint) {
251 491         15920 my $type = $attr->type_constraint;
252 491 50       4035 if (MooseX::Getopt::OptionTypeMap->has_option_type($type)) {
253 491         5139 $opt_string .= MooseX::Getopt::OptionTypeMap->get_option_type($type)
254             }
255             }
256              
257             my $push = {
258             name => $flag,
259             init_arg => $attr->init_arg,
260             opt_string => $opt_string,
261 603   66     19897 required => $attr->is_required && !$attr->has_default && !$attr->has_builder && !exists $config_from_file->{$attr->name},
262             # NOTE:
263             # this "feature" was breaking because
264             # Getopt::Long::Descriptive would return
265             # the default value as if it was a command
266             # line flag, which would then override the
267             # one passed into a constructor.
268             # See 100_gld_default_bug.t for an example
269             # - SL
270             #( ( $attr->has_default && ( $attr->is_default_a_coderef xor $attr->is_lazy ) ) ? ( default => $attr->default({}) ) : () ),
271             };
272 603 100       25173 if ($attr->has_documentation) {
273 108         3815 my $doc = $attr->documentation;
274 108         958 $doc =~ s/[\r\n]+/ /g;
275 108         296 $push->{doc} = $doc;
276             }
277 603         3338 push @options, $push;
278             }
279              
280 121         979 return @options;
281             }
282              
283             1;
284              
285             __END__
286              
287             =pod
288              
289             =encoding UTF-8
290              
291             =head1 NAME
292              
293             MooseX::Getopt::Basic - MooseX::Getopt::Basic - role to implement the Getopt::Long functionality
294              
295             =head1 VERSION
296              
297             version 0.75
298              
299             =head1 SYNOPSIS
300              
301             ## In your class
302             package My::App;
303             use Moose;
304              
305             with 'MooseX::Getopt::Basic';
306              
307             has 'out' => (is => 'rw', isa => 'Str', required => 1);
308             has 'in' => (is => 'rw', isa => 'Str', required => 1);
309              
310             # ... rest of the class here
311              
312             ## in your script
313             #!/usr/bin/perl
314              
315             use My::App;
316              
317             my $app = My::App->new_with_options();
318             # ... rest of the script here
319              
320             ## on the command line
321             % perl my_app_script.pl --in file.input --out file.dump
322              
323             =head1 DESCRIPTION
324              
325             This is like L<MooseX::Getopt> and can be used instead except that it
326             doesn't make use of L<Getopt::Long::Descriptive> (or "GLD" for short).
327              
328             =head1 METHODS
329              
330             =head2 new_with_options
331              
332             See L<MooseX::Getopt/new_with_options>.
333              
334             =head2 process_argv
335              
336             See L<MooseX::Getopt/process_argv>.
337              
338             =for Pod::Coverage print_usage_text
339              
340             =head1 SUPPORT
341              
342             Bugs may be submitted through L<the RT bug tracker|https://rt.cpan.org/Public/Dist/Display.html?Name=MooseX-Getopt>
343             (or L<bug-MooseX-Getopt@rt.cpan.org|mailto:bug-MooseX-Getopt@rt.cpan.org>).
344              
345             There is also a mailing list available for users of this distribution, at
346             L<http://lists.perl.org/list/moose.html>.
347              
348             There is also an irc channel available for users of this distribution, at
349             L<C<#moose> on C<irc.perl.org>|irc://irc.perl.org/#moose>.
350              
351             =head1 AUTHOR
352              
353             Stevan Little <stevan@iinteractive.com>
354              
355             =head1 COPYRIGHT AND LICENSE
356              
357             This software is copyright (c) 2007 by Infinity Interactive, Inc.
358              
359             This is free software; you can redistribute it and/or modify it under
360             the same terms as the Perl 5 programming language system itself.
361              
362             =cut