2 package MooseX::Getopt;
5 use Moose::Util::TypeConstraints;
7 use MooseX::Getopt::OptionTypeMap;
9 use MooseX::Getopt::Session;
11 use MooseX::Getopt::Meta::Attribute;
12 use MooseX::Getopt::Meta::Attribute::NoGetopt;
18 our $VERSION = '0.150001';
19 our $AUTHORITY = 'cpan:STEVAN';
22 use constant _default_getopt_session => 'MooseX::Getopt::Session';
27 isa => 'MooseX::Getopt::Session',
28 metaclass => 'NoGetopt',
29 handles => [ 'ARGV', 'extra_argv' ],
33 sub new_with_options {
36 return $class->new( $class->get_options_from_argv(@_) );
40 sub get_options_from_argv {
43 Moose->throw_error("Single parameters to get_options_from_argv() must be a HASH ref")
44 if ref $_[0] and ref $_ ne 'HASH';
46 my $options = { %{ $class->get_options_from_configfile }, @_ == 1 ? %{ $_[0] } : @_ };
48 my $getopt = defined $options->{getopt}
50 : $class->_default_getopt_session->new(
51 classes_filter => sub { $_ eq $class },
56 %{ $options }, # explicit options to ->new
57 %{ $getopt->options }, # options from CLI
65 sub get_options_from_configfile {
70 if ($class->meta->does_role('MooseX::ConfigFromFile')) {
74 my $opt_parser = Getopt::Long::Parser->new( config => [ 'pass_through' ] );
75 $opt_parser->getoptions( "configfile=s" => \$configfile );
77 if (not defined $configfile) {
78 my $cfmeta = $class->meta->find_attribute_by_name('configfile');
79 $configfile = $cfmeta->default if $cfmeta->has_default;
82 if (defined $configfile) {
83 $options = $class->get_config_from_file($configfile);
91 sub _compute_getopt_attrs {
95 $_->does('MooseX::Getopt::Meta::Attribute::Trait')
99 !$_->does('MooseX::Getopt::Meta::Attribute::Trait::NoGetopt')
100 } $class->meta->compute_all_applicable_attributes;
112 MooseX::Getopt - A Moose role for processing command line options
120 with 'MooseX::Getopt';
122 has 'out' => (is => 'rw', isa => 'Str', required => 1);
123 has 'in' => (is => 'rw', isa => 'Str', required => 1);
125 # ... rest of the class here
132 my $app = My::App->new_with_options();
133 # ... rest of the script here
135 ## on the command line
136 % perl my_app_script.pl -in file.input -out file.dump
140 This is a role which provides an alternate constructor for creating
141 objects using parameters passed in from the command line.
143 This module attempts to DWIM as much as possible with the command line
144 params by introspecting your class's attributes. It will use the name
145 of your attribute as the command line option, and if there is a type
146 constraint defined, it will configure Getopt::Long to handle the option
149 You can use the trait L<MooseX::Getopt::Meta::Attribute::Trait> or the
150 attribute metaclass L<MooseX::Getopt::Meta::Attribute> to get non-default
151 commandline option names and aliases.
153 You can use the trait L<MooseX::Getopt::Meta::Attribute::Trait::NoGetopt>
154 or the attribute metaclass L<MooseX::Getopt::Meta::Attribute::NoGetopt>
155 to have C<MooseX::Getopt> ignore your attribute in the commandline options.
157 By default, attributes which start with an underscore are not given
158 commandline argument support, unless the attribute's metaclass is set
159 to L<MooseX::Getopt::Meta::Attribute>. If you don't want you accessors
160 to have the leading underscore in thier name, you can do this:
162 # for read/write attributes
163 has '_foo' => (accessor => 'foo', ...);
165 # or for read-only attributes
166 has '_bar' => (reader => 'bar', ...);
168 This will mean that Getopt will not handle a --foo param, but your
169 code can still call the C<foo> method.
171 If your class also uses a configfile-loading role based on
172 L<MooseX::ConfigFromFile>, such as L<MooseX::SimpleConfig>,
173 L<MooseX::Getopt>'s C<new_with_options> will load the configfile
174 specified by the C<--configfile> option (or the default you've
175 given for the configfile attribute) for you.
177 Options specified in multiple places follow the following
178 precendence order: commandline overrides configfile, which
179 overrides explicit new_with_options parameters.
181 =head2 Supported Type Constraints
187 A I<Bool> type constraint is set up as a boolean option with
188 Getopt::Long. So that this attribute description:
190 has 'verbose' => (is => 'rw', isa => 'Bool');
192 would translate into C<verbose!> as a Getopt::Long option descriptor,
193 which would enable the following command line options:
195 % my_script.pl --verbose
196 % my_script.pl --noverbose
198 =item I<Int>, I<Float>, I<Str>
200 These type constraints are set up as properly typed options with
201 Getopt::Long, using the C<=i>, C<=f> and C<=s> modifiers as appropriate.
205 An I<ArrayRef> type constraint is set up as a multiple value option
206 in Getopt::Long. So that this attribute description:
211 default => sub { [] }
214 would translate into C<includes=s@> as a Getopt::Long option descriptor,
215 which would enable the following command line options:
217 % my_script.pl --include /usr/lib --include /usr/local/lib
221 A I<HashRef> type constraint is set up as a hash value option
222 in Getopt::Long. So that this attribute description:
227 default => sub { {} }
230 would translate into C<define=s%> as a Getopt::Long option descriptor,
231 which would enable the following command line options:
233 % my_script.pl --define os=linux --define vendor=debian
237 =head2 Custom Type Constraints
239 It is possible to create custom type constraint to option spec
240 mappings if you need them. The process is fairly simple (but a
241 little verbose maybe). First you create a custom subtype, like
244 subtype 'ArrayOfInts'
246 => where { scalar (grep { looks_like_number($_) } @$_) };
248 Then you register the mapping, like so:
250 MooseX::Getopt::OptionTypeMap->add_option_type_to_map(
251 'ArrayOfInts' => '=i@'
254 Now any attribute declarations using this type constraint will
255 get the custom option spec. So that, this:
259 isa => 'ArrayOfInts',
260 default => sub { [0] }
263 Will translate to the following on the command line:
265 % my_script.pl --nums 5 --nums 88 --nums 199
267 This example is fairly trivial, but more complex validations are
268 easily possible with a little creativity. The trick is balancing
269 the type constraint validations with the Getopt::Long validations.
271 Better examples are certainly welcome :)
273 =head2 Inferred Type Constraints
275 If you define a custom subtype which is a subtype of one of the
276 standard L</Supported Type Constraints> above, and do not explicitly
277 provide custom support as in L</Custom Type Constraints> above,
278 MooseX::Getopt will treat it like the parent type for Getopt
281 For example, if you had the same custom C<ArrayOfInts> subtype
282 from the examples above, but did not add a new custom option
283 type for it to the C<OptionTypeMap>, it would be treated just
284 like a normal C<ArrayRef> type for Getopt purposes (that is,
289 L<MooseX::Getopt> can handle more than one class which contain
290 attributes filled from CLI. In this case, you need to use explicite
291 L<MooseX::Getopt::Session> object and then the Getopt attributes will be
292 searched in any class which does L<MooseX::Getopt>.
296 with 'MooseX::Getopt';
297 has 'send' => (is => 'rw', predicate => 'has_send');
299 package My::App::Send;
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; }
305 # ... rest of the class here
310 my $getopt = MooseX::Getopt::Session->new;
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 );
318 # ... rest of the script here
320 ## on the command line
321 % perl my_app_script.pl --send --to server.example.net
327 =item B<new_with_options (%params)>
329 This method will take a set of default C<%params> and then collect
330 params from the command line (possibly overriding those in C<%params>)
331 and then return a newly constructed object.
333 If L<Getopt::Long/GetOptions> fails (due to invalid arguments),
334 C<new_with_options> will throw an exception.
336 If you have L<Getopt::Long::Descriptive> a the C<usage> param is also passed to
339 =item B<get_options_from_argv (%params)>
341 This method returns the list of parameters collected from command line
342 without creating the new object.
344 =item B<get_options_from_configfile>
346 This method returns the list of parameters collected with
347 L<MooseX::ConfigFromFile> mechanism.
351 This accessor contains a reference to a copy of the C<@ARGV> array as it
352 originally existed at the time of C<new_with_options>.
354 The C<ARGV> is delegated from L<MooseX::Getopt::Session> object.
358 This accessor contains an arrayref of leftover C<@ARGV> elements that
359 L<Getopt::Long> did not parse. Note that the real C<@ARGV> is left
362 The C<extra_argv> is delegated from L<MooseX::Getopt::Session> object.
366 This accessor contains a L<MooseX::Getopt::Session> object. This object can
367 be shared between more than one class which does L<MooseX::Getopt>. The new
368 object is created by default.
372 This returns the role meta object.
380 =item L<MooseX::Getopt::Strict>
382 =item L<MooseX::Getopt::Session>
384 =item L<MooseX::Getopt::Parser>
390 All complex software has bugs lurking in it, and this module is no
391 exception. If you find a bug please either email me, or add the bug
396 Stevan Little E<lt>stevan@iinteractive.comE<gt>
398 Brandon L. Black, E<lt>blblack@gmail.comE<gt>
400 Yuval Kogman, E<lt>nothingmuch@woobling.orgE<gt>
404 Ryan D Johnson, E<lt>ryan@innerfence.comE<gt>
406 Piotr Roszatycki, E<lt>dexter@cpan.orgE<gt>
408 =head1 COPYRIGHT AND LICENSE
410 Copyright 2007-2008 by Infinity Interactive, Inc.
412 L<http://www.iinteractive.com>
414 This library is free software; you can redistribute it and/or modify
415 it under the same terms as Perl itself.