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