Applied patch in RT43255
[gitmo/MooseX-Getopt.git] / lib / MooseX / Getopt.pm
1
2 package MooseX::Getopt;
3 use Moose::Role;
4
5 use MooseX::Getopt::OptionTypeMap;
6 use MooseX::Getopt::Meta::Attribute;
7 use MooseX::Getopt::Meta::Attribute::NoGetopt;
8
9 use Carp ();
10
11 use Getopt::Long (); # GLD uses it anyway, doesn't hurt
12 use constant HAVE_GLD => not not eval { require Getopt::Long::Descriptive };
13
14 our $VERSION   = '0.18';
15 our $AUTHORITY = 'cpan:STEVAN';
16
17 has ARGV       => (is => 'rw', isa => 'ArrayRef', metaclass => "NoGetopt");
18 has extra_argv => (is => 'rw', isa => 'ArrayRef', metaclass => "NoGetopt");
19
20 sub new_with_options {
21     my ($class, @params) = @_;
22
23     my $config_from_file;
24     if($class->meta->does_role('MooseX::ConfigFromFile')) {
25         local @ARGV = @ARGV;
26
27         my $configfile;
28         my $opt_parser = Getopt::Long::Parser->new( config => [ qw( pass_through ) ] );
29         $opt_parser->getoptions( "configfile=s" => \$configfile );
30
31         if(!defined $configfile) {
32             my $cfmeta = $class->meta->find_attribute_by_name('configfile');
33             $configfile = $cfmeta->default if $cfmeta->has_default;
34         }
35
36         if(defined $configfile) {
37             $config_from_file = $class->get_config_from_file($configfile);
38         }
39     }
40
41     my $constructor_params = ( @params == 1 ? $params[0] : {@params} );
42     
43     Carp::croak("Single parameters to new_with_options() must be a HASH ref")
44         unless ref($constructor_params) eq 'HASH';
45
46     my %processed = $class->_parse_argv(
47         options => [
48             $class->_attrs_to_options( $config_from_file )
49         ],
50         params => $constructor_params,
51     );
52
53     my $params = $config_from_file ? { %$config_from_file, %{$processed{params}} } : $processed{params};
54
55     # did the user request usage information?
56     if ( $processed{usage} && ($params->{'?'} or $params->{help} or $params->{usage}) )
57     {
58         $processed{usage}->die();
59     }
60
61     $class->new(
62         ARGV       => $processed{argv_copy},
63         extra_argv => $processed{argv},
64         %$constructor_params, # explicit params to ->new
65         %$params, # params from CLI
66     );
67 }
68
69 sub _parse_argv {
70     my ( $class, %params ) = @_;
71
72     local @ARGV = @{ $params{argv} || \@ARGV };
73
74     my ( $opt_spec, $name_to_init_arg ) = ( HAVE_GLD ? $class->_gld_spec(%params) : $class->_traditional_spec(%params) );
75
76     # Get a clean copy of the original @ARGV
77     my $argv_copy = [ @ARGV ];
78
79     my @err;
80
81     my ( $parsed_options, $usage ) = eval {
82         local $SIG{__WARN__} = sub { push @err, @_ };
83
84         if ( HAVE_GLD ) {
85             return Getopt::Long::Descriptive::describe_options($class->_usage_format(%params), @$opt_spec);
86         } else {
87             my %options;
88             Getopt::Long::GetOptions(\%options, @$opt_spec);
89             return ( \%options, undef );
90         }
91     };
92
93     die join "", grep { defined } @err, $@ if @err or $@;
94
95     # Get a copy of the Getopt::Long-mangled @ARGV
96     my $argv_mangled = [ @ARGV ];
97
98     my %constructor_args = (
99         map {
100             $name_to_init_arg->{$_} => $parsed_options->{$_}
101         } keys %$parsed_options,
102     );
103
104     return (
105         params    => \%constructor_args,
106         argv_copy => $argv_copy,
107         argv      => $argv_mangled,
108         ( defined($usage) ? ( usage => $usage ) : () ),
109     );
110 }
111
112 sub _usage_format {
113     return "usage: %c %o";
114 }
115
116 sub _traditional_spec {
117     my ( $class, %params ) = @_;
118
119     my ( @options, %name_to_init_arg, %options );
120
121     foreach my $opt ( @{ $params{options} } ) {
122         push @options, $opt->{opt_string};
123
124         my $identifier = $opt->{name};
125         $identifier =~ s/\W/_/g; # Getopt::Long does this to all option names
126
127         $name_to_init_arg{$identifier} = $opt->{init_arg};
128     }
129
130     return ( \@options, \%name_to_init_arg );
131 }
132
133 sub _gld_spec {
134     my ( $class, %params ) = @_;
135
136     my ( @options, %name_to_init_arg );
137
138     my $constructor_params = $params{params};
139
140     foreach my $opt ( @{ $params{options} } ) {
141         push @options, [
142             $opt->{opt_string},
143             $opt->{doc} || ' ', # FIXME new GLD shouldn't need this hack
144             {
145                 ( ( $opt->{required} && !exists($constructor_params->{$opt->{init_arg}}) ) ? (required => $opt->{required}) : () ),
146                 # NOTE:
147                 # remove this 'feature' because it didn't work 
148                 # all the time, and so is better to not bother
149                 # since Moose will handle the defaults just 
150                 # fine anyway.
151                 # - SL
152                 #( exists $opt->{default}  ? (default  => $opt->{default})  : () ),
153             },
154         ];
155
156         my $identifier = $opt->{name};
157         $identifier =~ s/\W/_/g; # Getopt::Long does this to all option names
158
159         $name_to_init_arg{$identifier} = $opt->{init_arg};
160     }
161
162     return ( \@options, \%name_to_init_arg );
163 }
164
165 sub _compute_getopt_attrs {
166     my $class = shift;
167     grep {
168         $_->does("MooseX::Getopt::Meta::Attribute::Trait")
169             or
170         $_->name !~ /^_/
171     } grep {
172         !$_->does('MooseX::Getopt::Meta::Attribute::Trait::NoGetopt')
173     } $class->meta->get_all_attributes
174 }
175
176 sub _get_cmd_flags_for_attr {
177     my ( $class, $attr ) = @_;
178
179     my $flag = $attr->name;
180
181     my @aliases;
182
183     if ($attr->does('MooseX::Getopt::Meta::Attribute::Trait')) {
184         $flag = $attr->cmd_flag if $attr->has_cmd_flag;
185         @aliases = @{ $attr->cmd_aliases } if $attr->has_cmd_aliases;
186     }
187
188     return ( $flag, @aliases );
189 }
190
191 sub _attrs_to_options {
192     my $class = shift;
193     my $config_from_file = shift || {};
194
195     my @options;
196
197     foreach my $attr ($class->_compute_getopt_attrs) {
198         my ( $flag, @aliases ) = $class->_get_cmd_flags_for_attr($attr);
199
200         my $opt_string = join(q{|}, $flag, @aliases);
201
202         if ($attr->has_type_constraint) {
203             my $type = $attr->type_constraint;
204             if (MooseX::Getopt::OptionTypeMap->has_option_type($type)) {
205                 $opt_string .= MooseX::Getopt::OptionTypeMap->get_option_type($type)
206             }
207         }
208
209         push @options, {
210             name       => $flag,
211             init_arg   => $attr->init_arg,
212             opt_string => $opt_string,
213             required   => $attr->is_required && !$attr->has_default && !$attr->has_builder && !exists $config_from_file->{$attr->name},
214             # NOTE:
215             # this "feature" was breaking because 
216             # Getopt::Long::Descriptive would return 
217             # the default value as if it was a command 
218             # line flag, which would then override the
219             # one passed into a constructor.
220             # See 100_gld_default_bug.t for an example
221             # - SL
222             #( ( $attr->has_default && ( $attr->is_default_a_coderef xor $attr->is_lazy ) ) ? ( default => $attr->default({}) ) : () ),
223             ( $attr->has_documentation ? ( doc => $attr->documentation ) : () ),
224         }
225     }
226
227     return @options;
228 }
229
230 no Moose::Role; 1;
231
232 __END__
233
234 =pod
235
236 =head1 NAME
237
238 MooseX::Getopt - A Moose role for processing command line options
239
240 =head1 SYNOPSIS
241
242   ## In your class
243   package My::App;
244   use Moose;
245
246   with 'MooseX::Getopt';
247
248   has 'out' => (is => 'rw', isa => 'Str', required => 1);
249   has 'in'  => (is => 'rw', isa => 'Str', required => 1);
250
251   # ... rest of the class here
252
253   ## in your script
254   #!/usr/bin/perl
255
256   use My::App;
257
258   my $app = My::App->new_with_options();
259   # ... rest of the script here
260
261   ## on the command line
262   % perl my_app_script.pl -in file.input -out file.dump
263
264 =head1 DESCRIPTION
265
266 This is a role which provides an alternate constructor for creating
267 objects using parameters passed in from the command line.
268
269 This module attempts to DWIM as much as possible with the command line
270 params by introspecting your class's attributes. It will use the name
271 of your attribute as the command line option, and if there is a type
272 constraint defined, it will configure Getopt::Long to handle the option
273 accordingly.
274
275 You can use the trait L<MooseX::Getopt::Meta::Attribute::Trait> or the
276 attribute metaclass L<MooseX::Getopt::Meta::Attribute> to get non-default
277 commandline option names and aliases.
278
279 You can use the trait L<MooseX::Getopt::Meta::Attribute::Trait::NoGetopt>
280 or the attribute metaclass L<MooseX::Getopt::Meta::Attribute::NoGetopt>
281 to have C<MooseX::Getopt> ignore your attribute in the commandline options.
282
283 By default, attributes which start with an underscore are not given
284 commandline argument support, unless the attribute's metaclass is set
285 to L<MooseX::Getopt::Meta::Attribute>. If you don't want you accessors
286 to have the leading underscore in thier name, you can do this:
287
288   # for read/write attributes
289   has '_foo' => (accessor => 'foo', ...);
290
291   # or for read-only attributes
292   has '_bar' => (reader => 'bar', ...);
293
294 This will mean that Getopt will not handle a --foo param, but your
295 code can still call the C<foo> method.
296
297 If your class also uses a configfile-loading role based on
298 L<MooseX::ConfigFromFile>, such as L<MooseX::SimpleConfig>,
299 L<MooseX::Getopt>'s C<new_with_options> will load the configfile
300 specified by the C<--configfile> option (or the default you've
301 given for the configfile attribute) for you.
302
303 Options specified in multiple places follow the following
304 precendence order: commandline overrides configfile, which
305 overrides explicit new_with_options parameters.
306
307 =head2 Supported Type Constraints
308
309 =over 4
310
311 =item I<Bool>
312
313 A I<Bool> type constraint is set up as a boolean option with
314 Getopt::Long. So that this attribute description:
315
316   has 'verbose' => (is => 'rw', isa => 'Bool');
317
318 would translate into C<verbose!> as a Getopt::Long option descriptor,
319 which would enable the following command line options:
320
321   % my_script.pl --verbose
322   % my_script.pl --noverbose
323
324 =item I<Int>, I<Float>, I<Str>
325
326 These type constraints are set up as properly typed options with
327 Getopt::Long, using the C<=i>, C<=f> and C<=s> modifiers as appropriate.
328
329 =item I<ArrayRef>
330
331 An I<ArrayRef> type constraint is set up as a multiple value option
332 in Getopt::Long. So that this attribute description:
333
334   has 'include' => (
335       is      => 'rw',
336       isa     => 'ArrayRef',
337       default => sub { [] }
338   );
339
340 would translate into C<includes=s@> as a Getopt::Long option descriptor,
341 which would enable the following command line options:
342
343   % my_script.pl --include /usr/lib --include /usr/local/lib
344
345 =item I<HashRef>
346
347 A I<HashRef> type constraint is set up as a hash value option
348 in Getopt::Long. So that this attribute description:
349
350   has 'define' => (
351       is      => 'rw',
352       isa     => 'HashRef',
353       default => sub { {} }
354   );
355
356 would translate into C<define=s%> as a Getopt::Long option descriptor,
357 which would enable the following command line options:
358
359   % my_script.pl --define os=linux --define vendor=debian
360
361 =back
362
363 =head2 Custom Type Constraints
364
365 It is possible to create custom type constraint to option spec
366 mappings if you need them. The process is fairly simple (but a
367 little verbose maybe). First you create a custom subtype, like
368 so:
369
370   subtype 'ArrayOfInts'
371       => as 'ArrayRef'
372       => where { scalar (grep { looks_like_number($_) } @$_)  };
373
374 Then you register the mapping, like so:
375
376   MooseX::Getopt::OptionTypeMap->add_option_type_to_map(
377       'ArrayOfInts' => '=i@'
378   );
379
380 Now any attribute declarations using this type constraint will
381 get the custom option spec. So that, this:
382
383   has 'nums' => (
384       is      => 'ro',
385       isa     => 'ArrayOfInts',
386       default => sub { [0] }
387   );
388
389 Will translate to the following on the command line:
390
391   % my_script.pl --nums 5 --nums 88 --nums 199
392
393 This example is fairly trivial, but more complex validations are
394 easily possible with a little creativity. The trick is balancing
395 the type constraint validations with the Getopt::Long validations.
396
397 Better examples are certainly welcome :)
398
399 =head2 Inferred Type Constraints
400
401 If you define a custom subtype which is a subtype of one of the
402 standard L</Supported Type Constraints> above, and do not explicitly
403 provide custom support as in L</Custom Type Constraints> above,
404 MooseX::Getopt will treat it like the parent type for Getopt
405 purposes.
406
407 For example, if you had the same custom C<ArrayOfInts> subtype
408 from the examples above, but did not add a new custom option
409 type for it to the C<OptionTypeMap>, it would be treated just
410 like a normal C<ArrayRef> type for Getopt purposes (that is,
411 C<=s@>).
412
413 =head1 METHODS
414
415 =over 4
416
417 =item B<new_with_options (%params)>
418
419 This method will take a set of default C<%params> and then collect
420 params from the command line (possibly overriding those in C<%params>)
421 and then return a newly constructed object.
422
423 If L<Getopt::Long/GetOptions> fails (due to invalid arguments),
424 C<new_with_options> will throw an exception.
425
426 If L<Getopt::Long::Descriptive> is installed and any of the following
427 command line params are passed, the program will exit with usage 
428 information. You can add descriptions for each option by including a
429 B<documentation> option for each attribute to document.
430
431   --?
432   --help
433   --usage
434
435 If you have L<Getopt::Long::Descriptive> a the C<usage> param is also passed to
436 C<new>.
437
438 =item B<ARGV>
439
440 This accessor contains a reference to a copy of the C<@ARGV> array
441 as it originally existed at the time of C<new_with_options>.
442
443 =item B<extra_argv>
444
445 This accessor contains an arrayref of leftover C<@ARGV> elements that
446 L<Getopt::Long> did not parse.  Note that the real C<@ARGV> is left
447 un-mangled.
448
449 =item B<meta>
450
451 This returns the role meta object.
452
453 =back
454
455 =head1 BUGS
456
457 All complex software has bugs lurking in it, and this module is no
458 exception. If you find a bug please either email me, or add the bug
459 to cpan-RT.
460
461 =head1 AUTHOR
462
463 Stevan Little E<lt>stevan@iinteractive.comE<gt>
464
465 Brandon L. Black, E<lt>blblack@gmail.comE<gt>
466
467 Yuval Kogman, E<lt>nothingmuch@woobling.orgE<gt>
468
469 =head1 CONTRIBUTORS
470
471 Ryan D Johnson, E<lt>ryan@innerfence.comE<gt>
472
473 Drew Taylor, E<lt>drew@drewtaylor.comE<gt>
474
475 =head1 COPYRIGHT AND LICENSE
476
477 Copyright 2007-2008 by Infinity Interactive, Inc.
478
479 L<http://www.iinteractive.com>
480
481 This library is free software; you can redistribute it and/or modify
482 it under the same terms as Perl itself.
483
484 =cut