* MooseX::Getopt::Session: New attribute "status".
[gitmo/MooseX-Getopt.git] / lib / MooseX / Getopt / Parser / Descriptive.pm
1
2 package MooseX::Getopt::Parser::Descriptive;
3
4 use Moose;
5
6 with 'MooseX::Getopt::Parser';
7
8 use MooseX::Getopt::OptionTypeMap;
9
10 use Getopt::Long::Descriptive ();
11
12
13 # Special configuration for parser
14 has config => (
15     is => 'rw',
16     isa => 'ArrayRef[Str]',
17     auto_deref => 1,
18     default => sub { [] },
19 );
20
21 # Format for usage description
22 has format => (
23     is => 'rw',
24     isa => 'Str',
25     default => 'usage: %c %o',
26 );
27
28
29 sub build_options {
30     my $self = shift;
31     my ($getopt, @attrs) = @_;
32
33     Moose->throw_error('First argument is not a MooseX::Getopt::Session')
34         unless $getopt->isa('MooseX::Getopt::Session');
35
36     my $options = $getopt->options;
37     my $new_options = {};
38
39     my $usage;
40     my (@opts, %cmd_flags_to_names);
41
42     foreach my $attr (@attrs) {
43         my $name = $attr->name;
44
45         my ($flag, @aliases) = $getopt->_get_cmd_flags_for_attr($attr);
46         my $type = $getopt->_get_cmd_type_for_attr($attr);
47
48         $cmd_flags_to_names{$flag} = $name;
49
50         my $opt_string = join '|', $flag, @aliases;
51         $opt_string .= MooseX::Getopt::OptionTypeMap->get_option_type($type) if $type;
52
53         my $doc;
54         $doc = $attr->documentation if $attr->has_documentation;
55         $doc = ' ' unless $doc;
56
57         my $is_required = !exists $options->{$name}
58                           && $attr->is_required
59                           && !$attr->has_default
60                           && !$attr->has_builder;
61
62         push @opts, [
63             $opt_string => $doc,
64             {
65                 ( $is_required ? ( required => $attr->is_required ) : () ),
66             },
67         ];
68     };
69
70     my $warnings = '';
71
72     GETOPT: {
73         local @ARGV = @{ $getopt->ARGV };
74
75         local $SIG{__WARN__} = sub {
76             return warn @_ if $_[0]=~/^\###/;   # Smart::Comments
77             $warnings .= $_[0];
78         };
79
80         eval {
81             ($new_options, $usage) = Getopt::Long::Descriptive::describe_options(
82                 $self->format, @opts, { getopt_conf => [ $self->config ] }
83             );
84         };
85         my $e = $@;
86         $warnings .= $e if $e;
87
88         my $extra_argv = \@ARGV;
89         $getopt->extra_argv( $extra_argv );
90     };
91
92     # Convert cmd_flags back to names in options hashref
93     $new_options = { map { $cmd_flags_to_names{$_} => $new_options->{$_} } keys %$new_options };
94
95     # Include old options and usage object
96     $new_options = { usage => $usage, %$options, %$new_options };
97
98     $getopt->status( !! $warnings );
99     $getopt->options( $new_options );
100
101     die $warnings if $warnings;
102
103     return $new_options;
104 };
105
106
107 1;
108
109 __END__
110
111 =pod
112
113 =head1 NAME
114
115 MooseX::Getopt::Parser::Descriptive - A Getopt::Long::Descriptive parser for MooseX::Getopt
116
117 =head1 SYNOPSIS
118
119   use MooseX::Getopt::Parser::Descriptive;
120
121   my $parser = MooseX::Getopt::Parser::Descriptive->new(
122       format => 'Usage: %c %o',
123       config => ['pass_through']
124   );
125   my $getopt = MooseX::Getopt::Session->new( parser => $parser );
126   my $app = My::App->new( getopt => $getopt );
127
128 =head1 DESCRIPTION
129
130 This class does L<MooseX::Getopt::Parser> for L<MooseX::Getopt>.  This
131 class is used by default if L<Getopt::Long::Descriptive> module is
132 missing.
133
134 =head1 METHODS
135
136 =over 4
137
138 =item B<build_options ($getopt, @attrs)>
139
140 This method parses the CLI options with L<Getopt::Long> and returns a hashref to options list.
141
142 The first argument have to be L<MooseX::Getopt::Session> object and
143 second argument is a list of attributes which contains options.
144
145 =item B<config>
146
147 This accessor contains the arrayref to list with special configuration
148 keywords for L<Getopt::Long>.
149
150 =item B<format>
151
152 This accessor contains the string with message printed by
153 L<Getopt::Long::Descriptive> if error is occured.
154
155 =back
156
157 =head1 BUGS
158
159 All complex software has bugs lurking in it, and this module is no
160 exception. If you find a bug please either email me, or add the bug
161 to cpan-RT.
162
163 =head1 SEE ALSO
164
165 =over 4
166
167 =item L<MooseX::Getopt::Parser>
168
169 =item L<MooseX::Getopt::Parser::Default>
170
171 =item L<MooseX::Getopt::Parser::Long>
172
173 =item L<Getopt::Long::Descriptive>
174
175 =back
176
177 =head1 AUTHOR
178
179 Piotr Roszatycki, E<lt>dexter@cpan.orgE<gt>
180
181 =head1 COPYRIGHT AND LICENSE
182
183 Copyright 2007-2008 by Infinity Interactive, Inc.
184
185 L<http://www.iinteractive.com>
186
187 This library is free software; you can redistribute it and/or modify
188 it under the same terms as Perl itself.
189
190 =cut