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