line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# ============================================================================« |
2
|
|
|
|
|
|
|
package MooseX::App; |
3
|
|
|
|
|
|
|
# ============================================================================« |
4
|
|
|
|
|
|
|
|
5
|
10
|
|
|
10
|
|
2594786
|
use 5.010; |
|
10
|
|
|
|
|
30
|
|
6
|
10
|
|
|
10
|
|
5336
|
use utf8; |
|
10
|
|
|
|
|
92
|
|
|
10
|
|
|
|
|
45
|
|
7
|
10
|
|
|
10
|
|
286
|
use strict; |
|
10
|
|
|
|
|
22
|
|
|
10
|
|
|
|
|
200
|
|
8
|
10
|
|
|
10
|
|
37
|
use warnings; |
|
10
|
|
|
|
|
10
|
|
|
10
|
|
|
|
|
527
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:MAROS'; |
11
|
|
|
|
|
|
|
our $VERSION = 1.37_01; |
12
|
|
|
|
|
|
|
|
13
|
10
|
|
|
10
|
|
4519
|
use MooseX::App::Meta::Role::Attribute::Option; |
|
10
|
|
|
|
|
24
|
|
|
10
|
|
|
|
|
523
|
|
14
|
10
|
|
|
10
|
|
5130
|
use MooseX::App::Exporter qw(app_usage app_description app_base app_fuzzy app_strict app_prefer_commandline app_permute option parameter); |
|
10
|
|
|
|
|
31
|
|
|
10
|
|
|
|
|
84
|
|
15
|
10
|
|
|
10
|
|
5361
|
use MooseX::App::Message::Envelope; |
|
10
|
|
|
|
|
48
|
|
|
10
|
|
|
|
|
409
|
|
16
|
10
|
|
|
10
|
|
77
|
use Moose::Exporter; |
|
10
|
|
|
|
|
13
|
|
|
10
|
|
|
|
|
60
|
|
17
|
10
|
|
|
10
|
|
531
|
use Scalar::Util qw(blessed); |
|
10
|
|
|
|
|
14
|
|
|
10
|
|
|
|
|
7831
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
my ($IMPORT,$UNIMPORT,$INIT_META) = Moose::Exporter->build_import_methods( |
20
|
|
|
|
|
|
|
with_meta => [ qw(app_usage app_description app_namespace app_exclude app_base app_fuzzy app_command_name app_command_register app_strict app_prefer_commandline option parameter app_permute) ], |
21
|
|
|
|
|
|
|
also => [ 'Moose' ], |
22
|
|
|
|
|
|
|
as_is => [ 'new_with_command' ], |
23
|
|
|
|
|
|
|
install => [ 'unimport','init_meta' ], |
24
|
|
|
|
|
|
|
); |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
sub import { |
27
|
11
|
|
|
11
|
|
475
|
my ( $class, @plugins ) = @_; |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
# Get caller |
30
|
11
|
|
|
|
|
38
|
my ($caller_class) = caller(); |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
# Process plugins |
33
|
11
|
|
|
|
|
223
|
MooseX::App::Exporter->process_plugins($caller_class,@plugins); |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
# Call Moose-Exporter generated importer |
36
|
11
|
|
|
|
|
131
|
return $class->$IMPORT( { into => $caller_class } ); |
37
|
|
|
|
|
|
|
} |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
sub init_meta { |
40
|
11
|
|
|
11
|
0
|
928
|
my ($class,%args) = @_; |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
# Get required roles and metaroles |
43
|
11
|
|
|
|
|
42
|
$args{roles} = ['MooseX::App::Role::Base']; |
44
|
|
|
|
|
|
|
$args{metaroles} = { |
45
|
11
|
|
|
|
|
61
|
class => [ |
46
|
|
|
|
|
|
|
'MooseX::App::Meta::Role::Class::Base', |
47
|
|
|
|
|
|
|
'MooseX::App::Meta::Role::Class::Documentation' |
48
|
|
|
|
|
|
|
], |
49
|
|
|
|
|
|
|
attribute => [ |
50
|
|
|
|
|
|
|
'MooseX::App::Meta::Role::Attribute::Option' |
51
|
|
|
|
|
|
|
], |
52
|
|
|
|
|
|
|
}; |
53
|
|
|
|
|
|
|
|
54
|
11
|
|
|
|
|
135
|
return MooseX::App::Exporter->process_init_meta(%args); |
55
|
|
|
|
|
|
|
} |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
sub app_command_name(&) { |
58
|
3
|
|
|
3
|
1
|
49
|
my ( $meta, $namesub ) = @_; |
59
|
3
|
|
|
|
|
116
|
return $meta->app_command_name($namesub); |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
sub app_command_register(%) { |
63
|
0
|
|
|
0
|
1
|
0
|
my ( $meta, %commands ) = @_; |
64
|
|
|
|
|
|
|
|
65
|
0
|
|
|
|
|
0
|
foreach my $command (keys %commands) { |
66
|
0
|
|
|
|
|
0
|
$meta->command_register($command,$commands{$command}); |
67
|
|
|
|
|
|
|
} |
68
|
0
|
|
|
|
|
0
|
return; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
sub app_namespace(@) { |
72
|
0
|
|
|
0
|
1
|
0
|
my ( $meta, @namespaces ) = @_; |
73
|
0
|
|
|
|
|
0
|
return $meta->app_namespace( \@namespaces ); |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
sub app_exclude(@) { |
77
|
3
|
|
|
3
|
1
|
34
|
my ( $meta, @namespaces ) = @_; |
78
|
3
|
|
|
|
|
113
|
return $meta->app_exclude( \@namespaces ); |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
sub new_with_command { |
82
|
70
|
|
|
70
|
1
|
38189
|
my ($class,@args) = @_; |
83
|
|
|
|
|
|
|
|
84
|
70
|
100
|
66
|
|
|
571
|
Moose->throw_error('new_with_command is a class method') |
85
|
|
|
|
|
|
|
if ! defined $class || blessed($class); |
86
|
|
|
|
|
|
|
|
87
|
69
|
|
|
|
|
418
|
my $meta = $class->meta; |
88
|
69
|
|
|
|
|
1913
|
my $metameta = $meta->meta; |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
# Sanity check |
91
|
69
|
100
|
66
|
|
|
1118
|
Moose->throw_error('new_with_command may only be called from the application base package:'.$class) |
92
|
|
|
|
|
|
|
if $metameta->does_role('MooseX::App::Meta::Role::Class::Command') |
93
|
|
|
|
|
|
|
|| ! $metameta->does_role('MooseX::App::Meta::Role::Class::Base'); |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
$meta->command_check() |
96
|
68
|
50
|
33
|
|
|
40142
|
if $ENV{APP_DEVELOPER} || $ENV{HARNESS_ACTIVE}; |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
# Extra args |
99
|
68
|
|
|
|
|
110
|
my %args; |
100
|
68
|
50
|
33
|
|
|
441
|
if (scalar @args == 1 |
|
|
100
|
|
|
|
|
|
101
|
|
|
|
|
|
|
&& ref($args[0]) eq 'HASH' ) { |
102
|
0
|
|
|
|
|
0
|
%args = %{$args[0]}; |
|
0
|
|
|
|
|
0
|
|
103
|
|
|
|
|
|
|
} elsif (scalar @args % 2 == 0) { |
104
|
67
|
|
|
|
|
183
|
%args = @args; |
105
|
|
|
|
|
|
|
} else { |
106
|
1
|
|
|
|
|
6
|
Moose->throw_error('new_with_command got invalid extra arguments'); |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
# Get ARGV |
110
|
67
|
|
|
|
|
147
|
my $argv = delete $args{ARGV}; |
111
|
67
|
|
|
|
|
100
|
my $parsed_argv; |
112
|
67
|
100
|
|
|
|
176
|
if (defined $argv) { |
113
|
7
|
|
|
|
|
243
|
$parsed_argv = MooseX::App::ParsedArgv->new( argv => $argv ); |
114
|
|
|
|
|
|
|
} else { |
115
|
60
|
|
|
|
|
320
|
$parsed_argv = MooseX::App::ParsedArgv->instance(); |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
|
118
|
67
|
|
|
|
|
268
|
my $first_argv = $parsed_argv->first_argv; |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
# Requested help |
121
|
67
|
100
|
100
|
|
|
1319
|
if (defined $first_argv |
|
|
100
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
122
|
|
|
|
|
|
|
&& lc($first_argv) =~ m/^(help|h|\?|usage|-h|--help|-\?|--usage)$/) { |
123
|
2
|
|
|
|
|
14
|
return MooseX::App::Message::Envelope->new( |
124
|
|
|
|
|
|
|
$meta->command_usage_global(), |
125
|
|
|
|
|
|
|
); |
126
|
|
|
|
|
|
|
# No args |
127
|
|
|
|
|
|
|
} elsif (! defined $first_argv |
128
|
|
|
|
|
|
|
|| $first_argv =~ m/^\s*$/ |
129
|
|
|
|
|
|
|
|| $first_argv =~ m/^-{1,2}\w/) { |
130
|
2
|
|
|
|
|
10
|
return MooseX::App::Message::Envelope->new( |
131
|
|
|
|
|
|
|
$meta->command_message( |
132
|
|
|
|
|
|
|
header => "Missing command", # LOCALIZE |
133
|
|
|
|
|
|
|
type => "error", |
134
|
|
|
|
|
|
|
), |
135
|
|
|
|
|
|
|
$meta->command_usage_global(), |
136
|
|
|
|
|
|
|
127, # exitcode |
137
|
|
|
|
|
|
|
); |
138
|
|
|
|
|
|
|
# Looks like a command |
139
|
|
|
|
|
|
|
} else { |
140
|
63
|
|
|
|
|
305
|
my $return = $meta->command_find(); |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
# Nothing found |
143
|
63
|
100
|
66
|
|
|
325
|
if (blessed $return |
144
|
|
|
|
|
|
|
&& $return->isa('MooseX::App::Message::Block')) { |
145
|
2
|
|
|
|
|
12
|
return MooseX::App::Message::Envelope->new( |
146
|
|
|
|
|
|
|
$return, |
147
|
|
|
|
|
|
|
$meta->command_usage_global(), |
148
|
|
|
|
|
|
|
127, # exitcode |
149
|
|
|
|
|
|
|
); |
150
|
|
|
|
|
|
|
# One command found |
151
|
|
|
|
|
|
|
} else { |
152
|
61
|
|
|
|
|
2444
|
my $command_class = $meta->command_get($return); |
153
|
61
|
|
|
|
|
384
|
return $class->initialize_command_class($command_class,%args); |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
} |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
|
159
|
10
|
|
|
10
|
|
62
|
no Moose; |
|
10
|
|
|
|
|
14
|
|
|
10
|
|
|
|
|
75
|
|
160
|
|
|
|
|
|
|
1; |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
__END__ |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
=encoding utf8 |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
=head1 NAME |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
MooseX::App - Write user-friendly command line apps with even less suffering |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
=head1 SYNOPSIS |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
In your base class: |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
package MyApp; |
175
|
|
|
|
|
|
|
use MooseX::App qw(Color); |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
option 'global_option' => ( |
178
|
|
|
|
|
|
|
is => 'rw', |
179
|
|
|
|
|
|
|
isa => 'Bool', |
180
|
|
|
|
|
|
|
documentation => q[Enable this to do fancy stuff], |
181
|
|
|
|
|
|
|
); # Global option |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
has 'private' => ( |
184
|
|
|
|
|
|
|
is => 'rw', |
185
|
|
|
|
|
|
|
); # not exposed |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
Write multiple command classes (If you have only a single command class |
188
|
|
|
|
|
|
|
you should use L<MooseX::App::Simple> instead). Packackes in the namespace may be |
189
|
|
|
|
|
|
|
deeply nested. |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
package MyApp::SomeCommand; |
192
|
|
|
|
|
|
|
use MooseX::App::Command; # important (also imports Moose) |
193
|
|
|
|
|
|
|
extends qw(MyApp); # optional, only if you want to use global options from base class |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
# Positional parameter |
196
|
|
|
|
|
|
|
parameter 'some_parameter' => ( |
197
|
|
|
|
|
|
|
is => 'rw', |
198
|
|
|
|
|
|
|
isa => 'Str', |
199
|
|
|
|
|
|
|
required => 1, |
200
|
|
|
|
|
|
|
documentation => q[Some parameter that you need to supply], |
201
|
|
|
|
|
|
|
); |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
option 'some_option' => ( |
204
|
|
|
|
|
|
|
is => 'rw', |
205
|
|
|
|
|
|
|
isa => 'Int', |
206
|
|
|
|
|
|
|
required => 1, |
207
|
|
|
|
|
|
|
documentation => q[Very important option!], |
208
|
|
|
|
|
|
|
); # Option |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
sub run { |
211
|
|
|
|
|
|
|
my ($self) = @_; |
212
|
|
|
|
|
|
|
# Do something |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
And then you need a simple wrapper script (called eg. myapp): |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
#!/usr/bin/env perl |
218
|
|
|
|
|
|
|
use MyApp; |
219
|
|
|
|
|
|
|
MyApp->new_with_command->run; |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
On the command line: |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
bash$ myapp help |
224
|
|
|
|
|
|
|
usage: |
225
|
|
|
|
|
|
|
myapp <command> [long options...] |
226
|
|
|
|
|
|
|
myapp help |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
global options: |
229
|
|
|
|
|
|
|
--global_option Enable this to do fancy stuff [Flag] |
230
|
|
|
|
|
|
|
--help --usage -? Prints this usage information. [Flag] |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
available commands: |
233
|
|
|
|
|
|
|
some_command Description of some command |
234
|
|
|
|
|
|
|
another_command Description of another command |
235
|
|
|
|
|
|
|
help Prints this usage information |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
or |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
bash$ myapp some_command --help |
240
|
|
|
|
|
|
|
usage: |
241
|
|
|
|
|
|
|
myapp some_command <SOME_PARAMETER> [long options...] |
242
|
|
|
|
|
|
|
myapp help |
243
|
|
|
|
|
|
|
myapp some_command --help |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
parameters: |
246
|
|
|
|
|
|
|
some_parameter Some parameter that you need to supply [Required] |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
options: |
249
|
|
|
|
|
|
|
--global_option Enable this to do fancy stuff [Flag] |
250
|
|
|
|
|
|
|
--some_option Very important option! [Int,Required] |
251
|
|
|
|
|
|
|
--help --usage -? Prints this usage information. [Flag] |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
=head1 DESCRIPTION |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
MooseX-App is a highly customisable helper to write user-friendly |
256
|
|
|
|
|
|
|
command line applications without having to worry about most of the annoying |
257
|
|
|
|
|
|
|
things usually involved. Just take any existing L<Moose> class, add a single |
258
|
|
|
|
|
|
|
line (C<use MooseX-App qw(PluginA PluginB ...);>) and create one class |
259
|
|
|
|
|
|
|
for each command in an underlying namespace. Options and positional parameters |
260
|
|
|
|
|
|
|
can be defined as simple L<Moose> accessors using the C<option> and |
261
|
|
|
|
|
|
|
C<parameter> keywords respectively. |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
MooseX-App will then |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
=over |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
=item * Find, load and initialise the command classes (see |
268
|
|
|
|
|
|
|
L<MooseX::App::Simple> for single class/command applications) |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
=item * Create automated help and documentation from modules POD as well as |
271
|
|
|
|
|
|
|
attributes metadata and type constraints |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
=item * Read, encode and validate the command line options and positional |
274
|
|
|
|
|
|
|
parameters entered by the user from @ARGV and %ENV (and possibly prompt |
275
|
|
|
|
|
|
|
the user for additional parameters see L<MooseX::App::Plugin::Term>) |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
=item * Provide helpful error messages if user input cannot be validated |
278
|
|
|
|
|
|
|
(either missing or wrong attributes or Moose type constraints not satisfied) |
279
|
|
|
|
|
|
|
or if the user requests help. |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
=back |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
Commandline options are defined using the 'option' keyword which accepts |
284
|
|
|
|
|
|
|
the same attributes as Moose' 'has' keyword. |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
option 'some_option' => ( |
287
|
|
|
|
|
|
|
is => 'rw', |
288
|
|
|
|
|
|
|
isa => 'Str', |
289
|
|
|
|
|
|
|
); |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
This is equivalent to |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
has 'some_option' => ( |
294
|
|
|
|
|
|
|
is => 'rw', |
295
|
|
|
|
|
|
|
isa => 'Str', |
296
|
|
|
|
|
|
|
traits => ['AppOption'], # Load extra metaclass |
297
|
|
|
|
|
|
|
cmd_type => 'option', # Set attribute type |
298
|
|
|
|
|
|
|
); |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
Single letter options are treated as flags and may be combined with eachother. |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
Positional parameters are defined with the 'parameter' keyword |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
parameter 'some_option' => ( |
305
|
|
|
|
|
|
|
is => 'rw', |
306
|
|
|
|
|
|
|
isa => 'Str', |
307
|
|
|
|
|
|
|
); |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
This is equivalent to |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
has 'some_option' => ( |
312
|
|
|
|
|
|
|
is => 'rw', |
313
|
|
|
|
|
|
|
isa => 'Str', |
314
|
|
|
|
|
|
|
traits => ['AppOption'], |
315
|
|
|
|
|
|
|
cmd_type => 'parameter', |
316
|
|
|
|
|
|
|
); |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
All keywords are imported by L<Moosex::App> (in the app base class) and |
319
|
|
|
|
|
|
|
L<MooseX::App::Command> (in the command class) or L<MooseX::App::Simple> |
320
|
|
|
|
|
|
|
(single class application). |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
Furthermore, all options and parameters can also be supplied via %ENV |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
option 'some_option' => ( |
325
|
|
|
|
|
|
|
is => 'rw', |
326
|
|
|
|
|
|
|
isa => 'Str', |
327
|
|
|
|
|
|
|
cmd_env => 'SOME_OPTION', # sets the env key |
328
|
|
|
|
|
|
|
); |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
Moose type constraints help MooseX::App to construct helpful error messages |
331
|
|
|
|
|
|
|
and parse @ARGV in a meaningful way. The following type constraints are |
332
|
|
|
|
|
|
|
supported: |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
=over |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
=item * ArrayRef: Specify multiple values ('--opt value1 --opt value2', |
337
|
|
|
|
|
|
|
also see L<app_permute> and L<cmd_split>) |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
=item * HashRef: Specify multiple key value pairs ('--opt key=value --opt |
340
|
|
|
|
|
|
|
key2=value2', also see L<app_permute>) |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
=item * Enum: Display all possibilities |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
=item * Bool: Flags that do not require values |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
=item * Int, Num: Used for proper error messages |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
=back |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
Read the L<Tutorial|MooseX::App::Tutorial> for getting started with a simple |
351
|
|
|
|
|
|
|
MooseX::App command line application. |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
=head1 METHODS |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
=head2 new_with_command |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
my $myapp_command = MyApp->new_with_command(); |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
This constructor reads the command line arguments and tries to create a |
360
|
|
|
|
|
|
|
command class instance. If it fails it returns a |
361
|
|
|
|
|
|
|
L<MooseX::App::Message::Envelope> object holding an error message. |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
You can pass a hash of default/fallback params to new_with_command |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
my $obj = MyApp->new_with_command(%default); |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
Optionally you can pass a custom ARGV to this constructor |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
my $obj = MyApp->new_with_command( ARGV => \@myARGV ); |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
However, if you do so you must take care of propper @ARGV encoding yourself. |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
=head2 initialize_command_class |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
my $obj = MyApp->initialize_command_class($command_name,%default); |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
Helper method to instantiate the command class for the given command. |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
=head1 GLOBAL OPTIONS |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
These options may be used to alter the default behaviour of MooseX-App. |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
=head2 app_base |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
app_base 'my_script'; # Defaults to $0 |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
Usually MooseX::App will take the name of the calling wrapper script to |
388
|
|
|
|
|
|
|
construct the program name in various help messages. This name can |
389
|
|
|
|
|
|
|
be changed via the app_base function. |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
=head2 app_fuzzy |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
app_fuzzy 1; # default |
394
|
|
|
|
|
|
|
OR |
395
|
|
|
|
|
|
|
app_fuzzy 0; |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
Enables fuzzy matching of commands and attributes. Is turned on by default. |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
=head2 app_strict |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
app_strict 0; # default |
402
|
|
|
|
|
|
|
OR |
403
|
|
|
|
|
|
|
app_strict 1; |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
If strict is enabled the program will terminate with an error message if |
406
|
|
|
|
|
|
|
superfluous/unknown positional parameters are supplied. If disabled all |
407
|
|
|
|
|
|
|
extra parameters will be copied to the L<extra_argv> attribute. Unknown |
408
|
|
|
|
|
|
|
options (with leading dashes) will always yield an error message. |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
The command_strict config in the command classes allows one to set this option |
411
|
|
|
|
|
|
|
individually for each command in the respective command class. |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
=head2 app_prefer_commandline |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
app_prefer_commandline 0; # default |
416
|
|
|
|
|
|
|
or |
417
|
|
|
|
|
|
|
app_prefer_commandline 1; |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
Specifies if parameters/options supplied via @ARGV,%ENV should take precedence |
420
|
|
|
|
|
|
|
over arguments passed directly to new_with_command. |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
=head2 app_namespace |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
app_namespace 'MyApp::Commands', 'YourApp::MoreCommands'; |
425
|
|
|
|
|
|
|
OR |
426
|
|
|
|
|
|
|
app_namespace(); |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
Usually MooseX::App will take the package name of the base class as the |
429
|
|
|
|
|
|
|
namespace for commands. This namespace can be changed and you can add |
430
|
|
|
|
|
|
|
multiple extra namespaces. |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
If app_namespace is called with no arguments then autoloading of command |
433
|
|
|
|
|
|
|
classes will be disabled entirely. |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
=head2 app_exclude |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
app_exclude 'MyApp::Commands::Roles','MyApp::Commands::Utils'; |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
A sub namespace included via app_namespace (or the default behaviour) can |
440
|
|
|
|
|
|
|
be excluded using app_exclude. |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
=head2 app_command_name |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
app_command_name { |
445
|
|
|
|
|
|
|
my ($package_short,$package_full) = @_; |
446
|
|
|
|
|
|
|
# munge package name; |
447
|
|
|
|
|
|
|
return $command_name; |
448
|
|
|
|
|
|
|
}; |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
This coderef can be used to control how autoloaded package names should be |
451
|
|
|
|
|
|
|
translated to command names. If this command returns nothing the respective |
452
|
|
|
|
|
|
|
command class will be skipped and not loaded. |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
=head2 app_command_register |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
app_command_register |
457
|
|
|
|
|
|
|
do => 'MyApp::Commands::DoSomething', |
458
|
|
|
|
|
|
|
undo => 'MyApp::Commands::UndoSomething'; |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
This keyword can be used to register additional commands. Especially |
461
|
|
|
|
|
|
|
useful in conjunction with app_namespace and disabled autoloading. |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
=head2 app_description |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
app_description qq[Description text]; |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
Set the app description text. If not set this information will be taken from |
468
|
|
|
|
|
|
|
the Pod DESCRIPTION or OVERVIEW sections. (see command_description to set |
469
|
|
|
|
|
|
|
usage per command) |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
=head2 app_usage |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
app_usage qq[myapp --option ...]; |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
Set a custom usage text. If not set this will be taken from the Pod SYNOPSIS |
476
|
|
|
|
|
|
|
or USAGE section. If both sections are not available, the usage information |
477
|
|
|
|
|
|
|
will be autogenerated. (see command_usage to set usage per command) |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
=head2 app_permute |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
app_permute 0; # default |
482
|
|
|
|
|
|
|
OR |
483
|
|
|
|
|
|
|
app_permute 1; |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
Allows one to specify multiple values with one key. So instead of writing |
486
|
|
|
|
|
|
|
C<--list element1 --list element2 --list element3> one might write |
487
|
|
|
|
|
|
|
C<--list element1 element2 element3> for ArrayRef elements. HashRef elements |
488
|
|
|
|
|
|
|
may be expressed as <--hash key=value key2=value2>. |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
=head1 GLOBAL ATTRIBUTES |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
All MooseX::App classes will have two extra attributes |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
=head2 extra_argv |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
Carries all parameters from @ARGV that were not consumed (only if app_strict |
497
|
|
|
|
|
|
|
is turned off, otherwise superfluous parameters will raise an exception). |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
=head2 help_flag |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
Help flag that is set when help was requested. |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
=head1 ATTRIBUTE OPTIONS |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
Options and parameters accept extra attributes for customisation: |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
=over |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
=item * cmd_tags - Extra tags (as used by the help) |
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
=item * cmd_flag - Override option/parameter name |
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
=item * cmd_aliases - Additional option/parameter name aliases |
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
=item * cmd_split - Split values into ArrayRefs on this token |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
=item * cmd_position - Specify option/parameter order in help |
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
=item * cmd_env - Read options/parameters from %ENV |
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
=item * cmd_count - Value of option equals to number of occurrences in @ARGV |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
=item * cmd_negate - Adds an option to negate boolean flags |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
=back |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
Refer to L<MooseX::App::Meta::Role::Attribute::Option> for detailed |
528
|
|
|
|
|
|
|
documentation. |
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
=head1 METADATA |
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
MooseX::App will use your class metadata and POD to construct the commands and |
533
|
|
|
|
|
|
|
helpful error- or usage-messages. These bits of information are utilised |
534
|
|
|
|
|
|
|
and should be provided if possible: |
535
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
=over |
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
=item * Package names |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
=item * L<required> options for Moose attributes |
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
=item * L<documentation> options for Moose attributes |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
=item * Moose type constraints (Bool, ArrayRef, HashRef, Int, Num, and Enum) |
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
=item * Documentation set via app_description, app_usage, |
547
|
|
|
|
|
|
|
command_short_description, command_long_description and command_usage |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
=item * POD (NAME, ABSTRACT, DESCRIPTION, USAGE, SYNOPSIS, OVERVIEW, |
550
|
|
|
|
|
|
|
COPYRIGHT, LICENSE, COPYRIGHT AND LICENSE, AUTHOR and AUTHORS sections) |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
=item * Dzil ABSTRACT tag if no POD is available yet |
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
=back |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
=head1 PLUGINS |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
The behaviour of MooseX-App can be customised with plugins. To load a |
559
|
|
|
|
|
|
|
plugin just pass a list of plugin names after the C<use MooseX-App> statement. |
560
|
|
|
|
|
|
|
(Attention: order sometimes matters) |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
use MooseX::App qw(PluginA PluginB); |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
Currently the following plugins are shipped with MooseX::App |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
=over |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
=item * L<MooseX::App::Plugin::BashCompletion> |
569
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
Adds a command that generates a bash completion script for your application. |
571
|
|
|
|
|
|
|
See third party L<MooseX::App::Plugin::ZshCompletion> for Z shell completion. |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
=item * L<MooseX::App::Plugin::Color> |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
Colorful output for your MooseX::App applications. |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
=item * L<MooseX::App::Plugin::Config> |
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
Config files for MooseX::App applications. |
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
=item * L<MooseX::App::Plugin::ConfigHome> |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
Try to find config files in users home directory. |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
=item * L<MooseX::App::Plugin::Term> |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
Prompt user for options and parameters that were not provided via options or |
588
|
|
|
|
|
|
|
params. Prompt offers basic editing capabilities and non-persistent history. |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
=item * L<MooseX::App::Plugin::Typo> |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
Handle typos in command names and provide suggestions. |
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
=item * L<MooseX::App::Plugin::Version> |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
Adds a command to display the version and license of your application. |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
=item * L<MooseX::App::Plugin::Man> |
599
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
Display full manpage of application and commands. |
601
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
=item * L<MooseX::App::Plugin::MutexGroup> |
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
Allow for mutally exclusive options. |
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
=item * L<MooseX::App::Plugin::Depends> |
607
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
Adds dependent options. |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
=back |
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
Refer to L<Writing MooseX-App Plugins|MooseX::App::WritingPlugins> |
613
|
|
|
|
|
|
|
for documentation on how to create your own plugins. |
614
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
=head1 CAVEATS & KNOWN BUGS |
616
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
Startup time may be an issue - escpecially if you load many plugins. If you do |
618
|
|
|
|
|
|
|
not require the functionality of plugins and ability for fine grained |
619
|
|
|
|
|
|
|
customisation (or Moose for that matter) then you should probably |
620
|
|
|
|
|
|
|
use L<MooX::Options> or L<MooX::Cmd>. |
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
In some cases - especially when using non-standard class inheritance - you may |
623
|
|
|
|
|
|
|
end up with command classes lacking the help attribute. In this case you need |
624
|
|
|
|
|
|
|
to include the following line in your base class or command classes. |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
with qw(MooseX::App::Role::Common); |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
When manually registering command classes (eg. via app_command_register) in |
629
|
|
|
|
|
|
|
multiple base classes with different sets of plugins (why would you ever want |
630
|
|
|
|
|
|
|
to do that?), then meta attributes may lack some attribute metaclasses. In |
631
|
|
|
|
|
|
|
this case you need to load the missing attribute traits explicitly: |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
option 'argument' => ( |
634
|
|
|
|
|
|
|
depends => 'otherargument', |
635
|
|
|
|
|
|
|
trait => ['MooseX::App::Plugin::Depends::Meta::Attribute'], # load trait |
636
|
|
|
|
|
|
|
); |
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
=head1 SEE ALSO |
639
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
Read the L<Tutorial|MooseX::App::Tutorial> for getting started with a simple |
641
|
|
|
|
|
|
|
MooseX::App command line application. |
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
For alternatives you can check out |
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
L<MooseX::App::Cmd>, L<MooseX::Getopt>, L<MooX::Options>, L<MooX::Cmd>and L<App::Cmd> |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
=head1 SUPPORT |
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
Please report any bugs or feature requests via |
650
|
|
|
|
|
|
|
L<https://github.com/maros/MooseX-App/issues/new>. I will be notified, and |
651
|
|
|
|
|
|
|
then you'll automatically be notified of progress on your report as I make |
652
|
|
|
|
|
|
|
changes. |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
=head1 AUTHOR |
655
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
Maroš Kollár |
657
|
|
|
|
|
|
|
CPAN ID: MAROS |
658
|
|
|
|
|
|
|
maros [at] k-1.com |
659
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
http://www.k-1.com |
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
=head1 CONTRIBUTORS |
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
Special thanks to all contributors. |
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
In no particular order: Andrew Jones, George Hartzell, Steve Nolte, |
667
|
|
|
|
|
|
|
Michael G, Thomas Klausner, Yanick Champoux, Edward Baudrez, David Golden, |
668
|
|
|
|
|
|
|
J.R. Mash, Thilo Fester, Gregor Herrmann, Sergey Romanov, Sawyer X, Roman F., |
669
|
|
|
|
|
|
|
Hunter McMillen, Maik Hentsche, Alexander Stoddard, Marc Logghe, Tina Müller, |
670
|
|
|
|
|
|
|
Lisa Hare |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
You are more than welcome to contribute to MooseX-App. Please have a look |
673
|
|
|
|
|
|
|
at the L<https://github.com/maros/MooseX-App/issues?q=is%3Aissue+is%3Aopen+label%3AWishlist> |
674
|
|
|
|
|
|
|
list of open wishlist issues for ideas. |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
=head1 COPYRIGHT |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
MooseX::App is Copyright (c) 2012-17 Maroš Kollár. |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
This library is free software and may be distributed under the same terms as |
681
|
|
|
|
|
|
|
perl itself. The full text of the licence can be found in the LICENCE file |
682
|
|
|
|
|
|
|
included with this module. |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
=cut |