* MooseX::Getopt: use explict Getopt::Long module.
[gitmo/MooseX-Getopt.git] / lib / MooseX / Getopt.pm
CommitLineData
5dac17c3 1
2package MooseX::Getopt;
3use Moose::Role;
4
550da402 5use Moose::Util::TypeConstraints;
6
8034a232 7use MooseX::Getopt::OptionTypeMap;
550da402 8
c6c1f628 9use MooseX::Getopt::Session;
550da402 10
5dac17c3 11use MooseX::Getopt::Meta::Attribute;
0f8232b6 12use MooseX::Getopt::Meta::Attribute::NoGetopt;
5dac17c3 13
75a6449b 14
2a4bd49b 15use Getopt::Long ();
16
17
354c610a 18our $VERSION = '0.150001';
8034a232 19our $AUTHORITY = 'cpan:STEVAN';
20
550da402 21
c6c1f628 22use constant _default_getopt_session => 'MooseX::Getopt::Session';
23
24
c6c1f628 25has getopt => (
550da402 26 is => 'rw',
c6c1f628 27 isa => 'MooseX::Getopt::Session',
550da402 28 metaclass => 'NoGetopt',
ac2073c8 29 handles => [ 'ARGV', 'extra_argv' ],
550da402 30);
3899e5df 31
ee211848 32
c6c1f628 33sub new_with_options {
34 my $class = shift;
6bb4cb66 35
4848d3bb 36 return $class->new( $class->get_options_from_argv(@_) );
37};
38
39
40sub get_options_from_argv {
41 my $class = shift;
42
43 Moose->throw_error("Single parameters to get_options_from_argv() must be a HASH ref")
c6c1f628 44 if ref $_[0] and ref $_ ne 'HASH';
75a6449b 45
10ed52cb 46 my $options = { %{ $class->get_options_from_configfile }, @_ == 1 ? %{ $_[0] } : @_ };
6bb4cb66 47
10ed52cb 48 my $getopt = defined $options->{getopt}
49 ? $options->{getopt}
c7ecf9ea 50 : $class->_default_getopt_session->new(
ac2073c8 51 classes_filter => sub { $_ eq $class },
10ed52cb 52 options => $options,
ac2073c8 53 );
ee211848 54
10ed52cb 55 my $new_options = {
56 %{ $options }, # explicit options to ->new
57 %{ $getopt->options }, # options from CLI
4848d3bb 58 getopt => $getopt,
10ed52cb 59 };
4848d3bb 60
10ed52cb 61 return $new_options;
c6c1f628 62};
0e715336 63
0e715336 64
10ed52cb 65sub get_options_from_configfile {
d0904645 66 my $class = shift;
67
10ed52cb 68 my $options = {};
d0904645 69
70 if ($class->meta->does_role('MooseX::ConfigFromFile')) {
71 local @ARGV = @ARGV;
72
73 my $configfile;
74 my $opt_parser = Getopt::Long::Parser->new( config => [ 'pass_through' ] );
75 $opt_parser->getoptions( "configfile=s" => \$configfile );
76
77 if (not defined $configfile) {
78 my $cfmeta = $class->meta->find_attribute_by_name('configfile');
79 $configfile = $cfmeta->default if $cfmeta->has_default;
80 };
81
82 if (defined $configfile) {
10ed52cb 83 $options = $class->get_config_from_file($configfile);
d0904645 84 };
85 };
86
10ed52cb 87 return $options;
d0904645 88};
89
90
bff3807b 91sub _compute_getopt_attrs {
92 my $class = shift;
c6c1f628 93
94 return grep {
95 $_->does('MooseX::Getopt::Meta::Attribute::Trait')
bff3807b 96 or
97 $_->name !~ /^_/
adbe3e57 98 } grep {
99 !$_->does('MooseX::Getopt::Meta::Attribute::Trait::NoGetopt')
c6c1f628 100 } $class->meta->compute_all_applicable_attributes;
101};
4ad81caf 102
5dac17c3 103
8034a232 104no Moose::Role; 1;
5dac17c3 105
106__END__
107
108=pod
109
110=head1 NAME
111
8034a232 112MooseX::Getopt - A Moose role for processing command line options
5dac17c3 113
114=head1 SYNOPSIS
115
4e086633 116 ## In your class
5dac17c3 117 package My::App;
118 use Moose;
4e086633 119
5dac17c3 120 with 'MooseX::Getopt';
4e086633 121
5dac17c3 122 has 'out' => (is => 'rw', isa => 'Str', required => 1);
123 has 'in' => (is => 'rw', isa => 'Str', required => 1);
4e086633 124
5dac17c3 125 # ... rest of the class here
4e086633 126
5dac17c3 127 ## in your script
128 #!/usr/bin/perl
4e086633 129
5dac17c3 130 use My::App;
4e086633 131
5dac17c3 132 my $app = My::App->new_with_options();
133 # ... rest of the script here
4e086633 134
5dac17c3 135 ## on the command line
136 % perl my_app_script.pl -in file.input -out file.dump
137
138=head1 DESCRIPTION
139
4e086633 140This is a role which provides an alternate constructor for creating
141objects using parameters passed in from the command line.
8034a232 142
4e086633 143This module attempts to DWIM as much as possible with the command line
144params by introspecting your class's attributes. It will use the name
145of your attribute as the command line option, and if there is a type
8034a232 146constraint defined, it will configure Getopt::Long to handle the option
3899e5df 147accordingly.
148
2814de27 149You can use the trait L<MooseX::Getopt::Meta::Attribute::Trait> or the
150attribute metaclass L<MooseX::Getopt::Meta::Attribute> to get non-default
151commandline option names and aliases.
3899e5df 152
2814de27 153You can use the trait L<MooseX::Getopt::Meta::Attribute::Trait::NoGetopt>
154or the attribute metaclass L<MooseX::Getopt::Meta::Attribute::NoGetopt>
0f8232b6 155to have C<MooseX::Getopt> ignore your attribute in the commandline options.
156
3899e5df 157By default, attributes which start with an underscore are not given
158commandline argument support, unless the attribute's metaclass is set
3d9a716d 159to L<MooseX::Getopt::Meta::Attribute>. If you don't want you accessors
160to have the leading underscore in thier name, you can do this:
161
162 # for read/write attributes
163 has '_foo' => (accessor => 'foo', ...);
4e086633 164
3d9a716d 165 # or for read-only attributes
4e086633 166 has '_bar' => (reader => 'bar', ...);
3d9a716d 167
4e086633 168This will mean that Getopt will not handle a --foo param, but your
169code can still call the C<foo> method.
8034a232 170
ee69c4ba 171If your class also uses a configfile-loading role based on
172L<MooseX::ConfigFromFile>, such as L<MooseX::SimpleConfig>,
173L<MooseX::Getopt>'s C<new_with_options> will load the configfile
b4a79051 174specified by the C<--configfile> option (or the default you've
175given for the configfile attribute) for you.
176
177Options specified in multiple places follow the following
178precendence order: commandline overrides configfile, which
179overrides explicit new_with_options parameters.
ee69c4ba 180
8034a232 181=head2 Supported Type Constraints
182
183=over 4
184
185=item I<Bool>
186
4e086633 187A I<Bool> type constraint is set up as a boolean option with
8034a232 188Getopt::Long. So that this attribute description:
189
190 has 'verbose' => (is => 'rw', isa => 'Bool');
191
4e086633 192would translate into C<verbose!> as a Getopt::Long option descriptor,
8034a232 193which would enable the following command line options:
194
195 % my_script.pl --verbose
4e086633 196 % my_script.pl --noverbose
197
8034a232 198=item I<Int>, I<Float>, I<Str>
199
4e086633 200These type constraints are set up as properly typed options with
8034a232 201Getopt::Long, using the C<=i>, C<=f> and C<=s> modifiers as appropriate.
202
203=item I<ArrayRef>
204
205An I<ArrayRef> type constraint is set up as a multiple value option
206in Getopt::Long. So that this attribute description:
207
208 has 'include' => (
4e086633 209 is => 'rw',
210 isa => 'ArrayRef',
8034a232 211 default => sub { [] }
212 );
213
4e086633 214would translate into C<includes=s@> as a Getopt::Long option descriptor,
8034a232 215which would enable the following command line options:
216
217 % my_script.pl --include /usr/lib --include /usr/local/lib
218
219=item I<HashRef>
220
221A I<HashRef> type constraint is set up as a hash value option
222in Getopt::Long. So that this attribute description:
223
224 has 'define' => (
4e086633 225 is => 'rw',
226 isa => 'HashRef',
8034a232 227 default => sub { {} }
228 );
229
4e086633 230would translate into C<define=s%> as a Getopt::Long option descriptor,
8034a232 231which would enable the following command line options:
232
233 % my_script.pl --define os=linux --define vendor=debian
234
235=back
236
237=head2 Custom Type Constraints
238
4e086633 239It is possible to create custom type constraint to option spec
8034a232 240mappings if you need them. The process is fairly simple (but a
4e086633 241little verbose maybe). First you create a custom subtype, like
8034a232 242so:
243
244 subtype 'ArrayOfInts'
245 => as 'ArrayRef'
246 => where { scalar (grep { looks_like_number($_) } @$_) };
247
248Then you register the mapping, like so:
249
250 MooseX::Getopt::OptionTypeMap->add_option_type_to_map(
251 'ArrayOfInts' => '=i@'
252 );
253
4e086633 254Now any attribute declarations using this type constraint will
8034a232 255get the custom option spec. So that, this:
256
257 has 'nums' => (
258 is => 'ro',
259 isa => 'ArrayOfInts',
260 default => sub { [0] }
261 );
262
263Will translate to the following on the command line:
264
265 % my_script.pl --nums 5 --nums 88 --nums 199
266
4e086633 267This example is fairly trivial, but more complex validations are
8034a232 268easily possible with a little creativity. The trick is balancing
269the type constraint validations with the Getopt::Long validations.
270
271Better examples are certainly welcome :)
272
f63e6310 273=head2 Inferred Type Constraints
274
275If you define a custom subtype which is a subtype of one of the
276standard L</Supported Type Constraints> above, and do not explicitly
277provide custom support as in L</Custom Type Constraints> above,
278MooseX::Getopt will treat it like the parent type for Getopt
279purposes.
280
281For example, if you had the same custom C<ArrayOfInts> subtype
282from the examples above, but did not add a new custom option
283type for it to the C<OptionTypeMap>, it would be treated just
284like a normal C<ArrayRef> type for Getopt purposes (that is,
285C<=s@>).
286
ac2073c8 287=head2 Session
288
289L<MooseX::Getopt> can handle more than one class which contain
290attributes filled from CLI. In this case, you need to use explicite
291L<MooseX::Getopt::Session> object and then the Getopt attributes will be
292searched in any class which does L<MooseX::Getopt>.
293
294 package My::App;
295 use Moose;
296 with 'MooseX::Getopt';
297 has 'send' => (is => 'rw', predicate => 'has_send');
298
299 package My::App::Send;
300 use Moose;
301 with 'MooseX::Getopt';
302 has 'to' => (is => 'rw', isa => 'Str', default => 'localhost');
303 sub send { my $self = shift; warn "Sending mail to ", $self->to; }
304
305 # ... rest of the class here
306
307 ## in your script
308 #!/usr/bin/perl
309
310 my $getopt = MooseX::Getopt::Session->new;
311
312 my $app = My::App->new_with_options( getopt => $getopt );
313 if ($app->has_send) {
314 # Use the same command line
315 my $sender = My::App::Send->new_with_options( getopt => $getopt );
316 $sender->send;
317 }
318 # ... rest of the script here
319
320 ## on the command line
321 % perl my_app_script.pl --send --to server.example.net
322
5dac17c3 323=head1 METHODS
324
325=over 4
326
327=item B<new_with_options (%params)>
328
4e086633 329This method will take a set of default C<%params> and then collect
8034a232 330params from the command line (possibly overriding those in C<%params>)
331and then return a newly constructed object.
332
f63e6310 333If L<Getopt::Long/GetOptions> fails (due to invalid arguments),
334C<new_with_options> will throw an exception.
335
fad5da09 336If you have L<Getopt::Long::Descriptive> a the C<usage> param is also passed to
337C<new>.
338
4848d3bb 339=item B<get_options_from_argv (%params)>
340
341This method returns the list of parameters collected from command line
342without creating the new object.
343
10ed52cb 344=item B<get_options_from_configfile>
345
346This method returns the list of parameters collected with
347L<MooseX::ConfigFromFile> mechanism.
348
3899e5df 349=item B<ARGV>
350
ac2073c8 351This accessor contains a reference to a copy of the C<@ARGV> array as it
352originally existed at the time of C<new_with_options>.
353
354The C<ARGV> is delegated from L<MooseX::Getopt::Session> object.
f63e6310 355
356=item B<extra_argv>
357
358This accessor contains an arrayref of leftover C<@ARGV> elements that
359L<Getopt::Long> did not parse. Note that the real C<@ARGV> is left
360un-mangled.
3899e5df 361
ac2073c8 362The C<extra_argv> is delegated from L<MooseX::Getopt::Session> object.
363
364=item B<getopt>
365
366This accessor contains a L<MooseX::Getopt::Session> object. This object can
367be shared between more than one class which does L<MooseX::Getopt>. The new
368object is created by default.
369
5dac17c3 370=item B<meta>
371
8034a232 372This returns the role meta object.
373
5dac17c3 374=back
375
ac2073c8 376=head1 SEE ALSO
377
378=over 4
379
380=item L<MooseX::Getopt::Strict>
381
382=item L<MooseX::Getopt::Session>
383
384=item L<MooseX::Getopt::Parser>
385
386=back
387
5dac17c3 388=head1 BUGS
389
4e086633 390All complex software has bugs lurking in it, and this module is no
5dac17c3 391exception. If you find a bug please either email me, or add the bug
392to cpan-RT.
393
394=head1 AUTHOR
395
396Stevan Little E<lt>stevan@iinteractive.comE<gt>
397
e2911e34 398Brandon L. Black, E<lt>blblack@gmail.comE<gt>
399
630657d5 400Yuval Kogman, E<lt>nothingmuch@woobling.orgE<gt>
401
78a71ae5 402=head1 CONTRIBUTORS
403
404Ryan D Johnson, E<lt>ryan@innerfence.comE<gt>
405
ac2073c8 406Piotr Roszatycki, E<lt>dexter@cpan.orgE<gt>
407
5dac17c3 408=head1 COPYRIGHT AND LICENSE
409
adbe3e57 410Copyright 2007-2008 by Infinity Interactive, Inc.
5dac17c3 411
412L<http://www.iinteractive.com>
413
414This library is free software; you can redistribute it and/or modify
415it under the same terms as Perl itself.
416
417=cut