start of 0.03
[gitmo/MooseX-Getopt.git] / lib / MooseX / Getopt.pm
CommitLineData
5dac17c3 1
2package MooseX::Getopt;
3use Moose::Role;
4
5use Getopt::Long;
6
8034a232 7use MooseX::Getopt::OptionTypeMap;
5dac17c3 8use MooseX::Getopt::Meta::Attribute;
9
e2911e34 10our $VERSION = '0.03';
8034a232 11our $AUTHORITY = 'cpan:STEVAN';
12
bae00439 13has ARGV => (is => 'rw', isa => 'ArrayRef');
3899e5df 14
5dac17c3 15sub new_with_options {
16 my ($class, %params) = @_;
17
8034a232 18 my (@options, %name_to_init_arg);
5dac17c3 19 foreach my $attr ($class->meta->compute_all_applicable_attributes) {
20 my $name = $attr->name;
3899e5df 21
de75868f 22 my $aliases;
23
24 if ($attr->isa('MooseX::Getopt::Meta::Attribute')) {
25 $name = $attr->cmd_flag if $attr->has_cmd_flag;
26 $aliases = $attr->cmd_aliases if $attr->has_cmd_aliases;
3899e5df 27 }
28 else {
29 next if $name =~ /^_/;
30 }
5dac17c3 31
8034a232 32 $name_to_init_arg{$name} = $attr->init_arg;
5dac17c3 33
de75868f 34 my $opt_string = $aliases
35 ? join(q{|}, $name, @$aliases)
36 : $name;
37
5dac17c3 38 if ($attr->has_type_constraint) {
39 my $type_name = $attr->type_constraint->name;
8034a232 40 if (MooseX::Getopt::OptionTypeMap->has_option_type($type_name)) {
de75868f 41 $opt_string .= MooseX::Getopt::OptionTypeMap->get_option_type($type_name);
5dac17c3 42 }
43 }
44
de75868f 45 push @options => $opt_string;
5dac17c3 46 }
47
3899e5df 48 my $saved_argv = [ @ARGV ];
8034a232 49 my %options;
5dac17c3 50
8034a232 51 GetOptions(\%options, @options);
5dac17c3 52
8034a232 53 #use Data::Dumper;
54 #warn Dumper \@options;
55 #warn Dumper \%name_to_init_arg;
56 #warn Dumper \%options;
57
58 $class->new(
bae00439 59 ARGV => $saved_argv,
8034a232 60 %params,
61 map {
62 $name_to_init_arg{$_} => $options{$_}
3899e5df 63 } keys %options,
8034a232 64 );
5dac17c3 65}
66
8034a232 67no Moose::Role; 1;
5dac17c3 68
69__END__
70
71=pod
72
73=head1 NAME
74
8034a232 75MooseX::Getopt - A Moose role for processing command line options
5dac17c3 76
77=head1 SYNOPSIS
78
79 ## In your class
80 package My::App;
81 use Moose;
82
83 with 'MooseX::Getopt';
84
85 has 'out' => (is => 'rw', isa => 'Str', required => 1);
86 has 'in' => (is => 'rw', isa => 'Str', required => 1);
87
88 # ... rest of the class here
89
90 ## in your script
91 #!/usr/bin/perl
92
93 use My::App;
94
95 my $app = My::App->new_with_options();
96 # ... rest of the script here
97
98 ## on the command line
99 % perl my_app_script.pl -in file.input -out file.dump
100
101=head1 DESCRIPTION
102
8034a232 103This is a role which provides an alternate constructor for creating
104objects using parameters passed in from the command line.
105
106This module attempts to DWIM as much as possible with the command line
107params by introspecting your class's attributes. It will use the name
108of your attribute as the command line option, and if there is a type
109constraint defined, it will configure Getopt::Long to handle the option
3899e5df 110accordingly.
111
112You can use the attribute metaclass L<MooseX::Getopt::Meta::Attribute>
113to get non-default commandline option names and aliases.
114
115By default, attributes which start with an underscore are not given
116commandline argument support, unless the attribute's metaclass is set
117to L<MooseX::Getopt::Meta::Attribute>.
8034a232 118
119=head2 Supported Type Constraints
120
121=over 4
122
123=item I<Bool>
124
125A I<Bool> type constraint is set up as a boolean option with
126Getopt::Long. So that this attribute description:
127
128 has 'verbose' => (is => 'rw', isa => 'Bool');
129
130would translate into C<verbose!> as a Getopt::Long option descriptor,
131which would enable the following command line options:
132
133 % my_script.pl --verbose
134 % my_script.pl --noverbose
135
136=item I<Int>, I<Float>, I<Str>
137
138These type constraints are set up as properly typed options with
139Getopt::Long, using the C<=i>, C<=f> and C<=s> modifiers as appropriate.
140
141=item I<ArrayRef>
142
143An I<ArrayRef> type constraint is set up as a multiple value option
144in Getopt::Long. So that this attribute description:
145
146 has 'include' => (
147 is => 'rw',
148 isa => 'ArrayRef',
149 default => sub { [] }
150 );
151
152would translate into C<includes=s@> as a Getopt::Long option descriptor,
153which would enable the following command line options:
154
155 % my_script.pl --include /usr/lib --include /usr/local/lib
156
157=item I<HashRef>
158
159A I<HashRef> type constraint is set up as a hash value option
160in Getopt::Long. So that this attribute description:
161
162 has 'define' => (
163 is => 'rw',
164 isa => 'HashRef',
165 default => sub { {} }
166 );
167
168would translate into C<define=s%> as a Getopt::Long option descriptor,
169which would enable the following command line options:
170
171 % my_script.pl --define os=linux --define vendor=debian
172
173=back
174
175=head2 Custom Type Constraints
176
177It is possible to create custom type constraint to option spec
178mappings if you need them. The process is fairly simple (but a
179little verbose maybe). First you create a custom subtype, like
180so:
181
182 subtype 'ArrayOfInts'
183 => as 'ArrayRef'
184 => where { scalar (grep { looks_like_number($_) } @$_) };
185
186Then you register the mapping, like so:
187
188 MooseX::Getopt::OptionTypeMap->add_option_type_to_map(
189 'ArrayOfInts' => '=i@'
190 );
191
192Now any attribute declarations using this type constraint will
193get the custom option spec. So that, this:
194
195 has 'nums' => (
196 is => 'ro',
197 isa => 'ArrayOfInts',
198 default => sub { [0] }
199 );
200
201Will translate to the following on the command line:
202
203 % my_script.pl --nums 5 --nums 88 --nums 199
204
205This example is fairly trivial, but more complex validations are
206easily possible with a little creativity. The trick is balancing
207the type constraint validations with the Getopt::Long validations.
208
209Better examples are certainly welcome :)
210
5dac17c3 211=head1 METHODS
212
213=over 4
214
215=item B<new_with_options (%params)>
216
8034a232 217This method will take a set of default C<%params> and then collect
218params from the command line (possibly overriding those in C<%params>)
219and then return a newly constructed object.
220
3899e5df 221=item B<ARGV>
222
223This accessor contains a reference to a copy of the C<@ARGV> array
224which was copied before L<Getopt::Long> mangled it, in case you want
225to see your original options.
226
5dac17c3 227=item B<meta>
228
8034a232 229This returns the role meta object.
230
5dac17c3 231=back
232
233=head1 BUGS
234
235All complex software has bugs lurking in it, and this module is no
236exception. If you find a bug please either email me, or add the bug
237to cpan-RT.
238
239=head1 AUTHOR
240
241Stevan Little E<lt>stevan@iinteractive.comE<gt>
242
e2911e34 243Brandon L. Black, E<lt>blblack@gmail.comE<gt>
244
5dac17c3 245=head1 COPYRIGHT AND LICENSE
246
247Copyright 2007 by Infinity Interactive, Inc.
248
249L<http://www.iinteractive.com>
250
251This library is free software; you can redistribute it and/or modify
252it under the same terms as Perl itself.
253
254=cut