line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# ABSTRACT: Specification for commandline app |
2
|
5
|
|
|
5
|
|
191772
|
use strict; |
|
5
|
|
|
|
|
29
|
|
|
5
|
|
|
|
|
147
|
|
3
|
5
|
|
|
5
|
|
26
|
use warnings; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
189
|
|
4
|
|
|
|
|
|
|
package App::Spec; |
5
|
5
|
|
|
5
|
|
97
|
use 5.010; |
|
5
|
|
|
|
|
17
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = '0.011'; # VERSION |
8
|
|
|
|
|
|
|
|
9
|
5
|
|
|
5
|
|
1871
|
use App::Spec::Subcommand; |
|
5
|
|
|
|
|
18
|
|
|
5
|
|
|
|
|
185
|
|
10
|
5
|
|
|
5
|
|
37
|
use App::Spec::Option; |
|
5
|
|
|
|
|
9
|
|
|
5
|
|
|
|
|
115
|
|
11
|
5
|
|
|
5
|
|
33
|
use App::Spec::Parameter; |
|
5
|
|
|
|
|
13
|
|
|
5
|
|
|
|
|
118
|
|
12
|
|
|
|
|
|
|
|
13
|
5
|
|
|
5
|
|
26
|
use Moo; |
|
5
|
|
|
|
|
11
|
|
|
5
|
|
|
|
|
25
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
with('App::Spec::Role::Command'); |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
has title => ( is => 'rw' ); |
18
|
|
|
|
|
|
|
has abstract => ( is => 'rw' ); |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
sub runner { |
24
|
30
|
|
|
30
|
1
|
283
|
my ($self, %args) = @_; |
25
|
30
|
|
|
|
|
128
|
my $class = $self->class; |
26
|
30
|
|
|
|
|
339
|
my $cmd = $class->new; |
27
|
30
|
|
|
|
|
1542
|
my $run = App::Spec::Run->new({ |
28
|
|
|
|
|
|
|
spec => $self, |
29
|
|
|
|
|
|
|
cmd => $cmd, |
30
|
|
|
|
|
|
|
%args, |
31
|
|
|
|
|
|
|
}); |
32
|
30
|
|
|
|
|
208
|
return $run; |
33
|
|
|
|
|
|
|
} |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
sub usage { |
36
|
16
|
|
|
16
|
1
|
80
|
my ($self, %args) = @_; |
37
|
16
|
|
|
|
|
48
|
my $cmds = $args{commands}; |
38
|
16
|
100
|
|
|
|
40
|
my %highlights = %{ $args{highlights} || {} }; |
|
16
|
|
|
|
|
88
|
|
39
|
16
|
|
50
|
0
|
|
69
|
my $colored = $args{colored} || sub { $_[1] }; |
|
0
|
|
|
|
|
0
|
|
40
|
16
|
|
|
|
|
69
|
my $appname = $self->name; |
41
|
|
|
|
|
|
|
|
42
|
16
|
|
100
|
|
|
76
|
my $abstract = $self->abstract // ''; |
43
|
16
|
|
|
|
|
64
|
my $title = $self->title; |
44
|
16
|
|
|
|
|
72
|
my ($options, $parameters, $subcmds) = $self->_gather_options_parameters($cmds); |
45
|
16
|
|
|
|
|
89
|
my $header = $colored->(['bold'], "$appname - $title"); |
46
|
16
|
|
|
|
|
70
|
my $usage = <<"EOM"; |
47
|
|
|
|
|
|
|
$header |
48
|
|
|
|
|
|
|
$abstract |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
EOM |
51
|
|
|
|
|
|
|
|
52
|
16
|
|
|
|
|
42
|
my $body = ''; |
53
|
16
|
|
|
|
|
50
|
my $usage_header = $colored->([qw/ bold /], "Usage:"); |
54
|
16
|
|
|
|
|
48
|
$usage .= "$usage_header $appname"; |
55
|
16
|
100
|
|
|
|
68
|
$usage .= " @$cmds" if @$cmds; |
56
|
16
|
100
|
|
|
|
63
|
if (keys %$subcmds) { |
57
|
4
|
|
|
|
|
8
|
my $maxlength = 0; |
58
|
4
|
|
|
|
|
9
|
my @table; |
59
|
4
|
|
|
|
|
8
|
my $usage_string = ""; |
60
|
4
|
|
|
|
|
8
|
my $header = "Subcommands:"; |
61
|
4
|
100
|
|
|
|
16
|
if ($highlights{subcommands}) { |
62
|
3
|
|
|
|
|
14
|
$colored->([qw/ bold red /], $usage_string); |
63
|
3
|
|
|
|
|
11
|
$colored->([qw/ bold red /], $header); |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
else { |
66
|
1
|
|
|
|
|
3
|
$colored->([qw/ bold /], $header); |
67
|
|
|
|
|
|
|
} |
68
|
4
|
|
|
|
|
12
|
$usage .= " $usage_string"; |
69
|
4
|
|
|
|
|
12
|
$body .= "$header\n"; |
70
|
|
|
|
|
|
|
|
71
|
4
|
|
|
|
|
9
|
my %keys; |
72
|
4
|
|
|
|
|
25
|
@keys{ keys %$subcmds } = (); |
73
|
4
|
|
|
|
|
12
|
my @keys; |
74
|
4
|
50
|
|
|
|
14
|
if (@$cmds) { |
75
|
0
|
|
|
|
|
0
|
@keys = sort keys %keys; |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
else { |
78
|
4
|
|
|
|
|
132
|
for my $key (qw/ help _meta /) { |
79
|
8
|
100
|
|
|
|
23
|
if (exists $keys{ $key }) { |
80
|
7
|
|
|
|
|
27
|
push @keys, $key; |
81
|
7
|
|
|
|
|
18
|
delete $keys{ $key }; |
82
|
|
|
|
|
|
|
} |
83
|
|
|
|
|
|
|
} |
84
|
4
|
|
|
|
|
29
|
unshift @keys, sort keys %keys; |
85
|
|
|
|
|
|
|
} |
86
|
4
|
|
|
|
|
89
|
for my $name (@keys) { |
87
|
26
|
|
|
|
|
43
|
my $cmd_spec = $subcmds->{ $name }; |
88
|
26
|
|
|
|
|
53
|
my $summary = $cmd_spec->summary; |
89
|
26
|
|
|
|
|
48
|
push @table, [$name, $summary]; |
90
|
26
|
100
|
|
|
|
66
|
if (length $name > $maxlength) { |
91
|
11
|
|
|
|
|
21
|
$maxlength = length $name; |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
} |
94
|
4
|
|
|
|
|
21
|
$body .= $self->_output_table(\@table, [$maxlength]); |
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
|
97
|
16
|
100
|
|
|
|
59
|
if (@$parameters) { |
98
|
8
|
|
|
|
|
14
|
my $maxlength = 0; |
99
|
8
|
|
|
|
|
19
|
my @table; |
100
|
|
|
|
|
|
|
my @highlights; |
101
|
8
|
|
|
|
|
21
|
for my $param (@$parameters) { |
102
|
24
|
|
|
|
|
64
|
my $name = $param->name; |
103
|
24
|
|
|
|
|
53
|
my $highlight = $highlights{parameters}->{ $name }; |
104
|
24
|
100
|
|
|
|
57
|
push @highlights, $highlight ? 1 : 0; |
105
|
24
|
|
|
|
|
66
|
my $summary = $param->summary; |
106
|
24
|
|
|
|
|
73
|
my $param_usage_header = $param->to_usage_header; |
107
|
24
|
100
|
|
|
|
55
|
if ($highlight) { |
108
|
8
|
|
|
|
|
24
|
$colored->([qw/ bold red /], $param_usage_header); |
109
|
|
|
|
|
|
|
} |
110
|
24
|
|
|
|
|
45
|
$usage .= " " . $param_usage_header; |
111
|
24
|
|
|
|
|
43
|
my ($req, $multi) = (' ', ' '); |
112
|
24
|
50
|
|
|
|
90
|
if ($param->required) { |
113
|
24
|
|
|
|
|
35
|
$req = "*"; |
114
|
|
|
|
|
|
|
} |
115
|
24
|
50
|
|
|
|
78
|
if ($param->mapping) { |
|
|
100
|
|
|
|
|
|
116
|
0
|
|
|
|
|
0
|
$multi = '{}'; |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
elsif ($param->multiple) { |
119
|
6
|
|
|
|
|
11
|
$multi = '[]'; |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
|
122
|
24
|
|
|
|
|
51
|
my $flags = $self->_param_flags_string($param); |
123
|
|
|
|
|
|
|
|
124
|
24
|
|
|
|
|
86
|
push @table, [$name, $req, $multi, $summary . $flags]; |
125
|
24
|
100
|
|
|
|
120
|
if (length $name > $maxlength) { |
126
|
13
|
|
|
|
|
36
|
$maxlength = length $name; |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
} |
129
|
8
|
|
|
|
|
54
|
my $parameters_string = $colored->([qw/ bold /], "Parameters:"); |
130
|
8
|
|
|
|
|
26
|
$body .= "$parameters_string\n"; |
131
|
8
|
|
|
|
|
36
|
my @lines = $self->_output_table(\@table, [$maxlength]); |
132
|
8
|
|
|
|
|
31
|
my $lines = $self->_colorize_lines(\@lines, \@highlights, $colored); |
133
|
8
|
|
|
|
|
40
|
$body .= $lines; |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
|
136
|
16
|
50
|
|
|
|
57
|
if (@$options) { |
137
|
16
|
|
|
|
|
28
|
my @highlights; |
138
|
16
|
|
|
|
|
50
|
$usage .= " [options]"; |
139
|
16
|
|
|
|
|
39
|
my $maxlength = 0; |
140
|
16
|
|
|
|
|
35
|
my @table; |
141
|
16
|
|
|
|
|
89
|
for my $opt (sort { $a->name cmp $b->name } @$options) { |
|
61
|
|
|
|
|
163
|
|
142
|
58
|
|
|
|
|
122
|
my $name = $opt->name; |
143
|
58
|
|
|
|
|
106
|
my $highlight = $highlights{options}->{ $name }; |
144
|
58
|
100
|
|
|
|
122
|
push @highlights, $highlight ? 1 : 0; |
145
|
58
|
|
|
|
|
103
|
my $aliases = $opt->aliases; |
146
|
58
|
|
|
|
|
120
|
my $summary = $opt->summary; |
147
|
|
|
|
|
|
|
my @names = map { |
148
|
58
|
100
|
|
|
|
105
|
length $_ > 1 ? "--$_" : "-$_" |
|
94
|
|
|
|
|
305
|
|
149
|
|
|
|
|
|
|
} ($name, @$aliases); |
150
|
58
|
|
|
|
|
138
|
my $string = "@names"; |
151
|
58
|
100
|
|
|
|
136
|
if (length $string > $maxlength) { |
152
|
47
|
|
|
|
|
72
|
$maxlength = length $string; |
153
|
|
|
|
|
|
|
} |
154
|
58
|
|
|
|
|
106
|
my ($req, $multi) = (' ', ' '); |
155
|
58
|
50
|
|
|
|
152
|
if ($opt->required) { |
156
|
0
|
|
|
|
|
0
|
$req = "*"; |
157
|
|
|
|
|
|
|
} |
158
|
58
|
100
|
|
|
|
192
|
if ($opt->mapping) { |
|
|
100
|
|
|
|
|
|
159
|
3
|
|
|
|
|
6
|
$multi = '{}'; |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
elsif ($opt->multiple) { |
162
|
15
|
|
|
|
|
30
|
$multi = '[]'; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
58
|
|
|
|
|
120
|
my $flags = $self->_param_flags_string($opt); |
166
|
|
|
|
|
|
|
|
167
|
58
|
|
|
|
|
245
|
push @table, [$string, $req, $multi, $summary . $flags]; |
168
|
|
|
|
|
|
|
} |
169
|
16
|
|
|
|
|
72
|
my $options_string = $colored->([qw/ bold /], "Options:"); |
170
|
16
|
|
|
|
|
55
|
$body .= "\n$options_string\n"; |
171
|
16
|
|
|
|
|
65
|
my @lines = $self->_output_table(\@table, [$maxlength]); |
172
|
16
|
|
|
|
|
66
|
my $lines = $self->_colorize_lines(\@lines, \@highlights, $colored); |
173
|
16
|
|
|
|
|
73
|
$body .= $lines; |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
16
|
|
|
|
|
134
|
return "$usage\n\n$body"; |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
sub _param_flags_string { |
180
|
82
|
|
|
82
|
|
163
|
my ($self, $param) = @_; |
181
|
82
|
|
|
|
|
121
|
my @flags; |
182
|
82
|
100
|
|
|
|
197
|
if ($param->type eq 'flag') { |
183
|
38
|
|
|
|
|
72
|
push @flags, "flag"; |
184
|
|
|
|
|
|
|
} |
185
|
82
|
100
|
|
|
|
173
|
if ($param->multiple) { |
186
|
24
|
|
|
|
|
51
|
push @flags, "multiple"; |
187
|
|
|
|
|
|
|
} |
188
|
82
|
100
|
|
|
|
166
|
if ($param->mapping) { |
189
|
3
|
|
|
|
|
6
|
push @flags, "mapping"; |
190
|
|
|
|
|
|
|
} |
191
|
82
|
100
|
|
|
|
205
|
my $flags = @flags ? " (" . join("; ", @flags) . ")" : ''; |
192
|
82
|
|
|
|
|
193
|
return $flags; |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
sub _colorize_lines { |
196
|
24
|
|
|
24
|
|
78
|
my ($self, $lines, $highlights, $colored) = @_; |
197
|
24
|
|
|
|
|
45
|
my $output = ''; |
198
|
24
|
|
|
|
|
89
|
for my $i (0 .. $#$lines) { |
199
|
82
|
|
|
|
|
132
|
my $line = $lines->[ $i ]; |
200
|
82
|
100
|
|
|
|
188
|
if ($highlights->[ $i ]) { |
201
|
12
|
|
|
|
|
37
|
$colored->([qw/ bold red /], $line); |
202
|
|
|
|
|
|
|
} |
203
|
82
|
|
|
|
|
178
|
$output .= $line; |
204
|
|
|
|
|
|
|
} |
205
|
24
|
|
|
|
|
63
|
return $output; |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
sub _output_table { |
209
|
28
|
|
|
28
|
|
71
|
my ($self, $table, $lengths) = @_; |
210
|
28
|
|
|
|
|
46
|
my @lines; |
211
|
|
|
|
|
|
|
my @lengths = map { |
212
|
104
|
100
|
|
|
|
278
|
defined $lengths->[$_] ? "%-$lengths->[$_]s" : "%s" |
213
|
28
|
|
|
|
|
60
|
} 0 .. @{ $table->[0] } - 1; |
|
28
|
|
|
|
|
89
|
|
214
|
28
|
|
|
|
|
74
|
for my $row (@$table) { |
215
|
5
|
|
|
5
|
|
8717
|
no warnings 'uninitialized'; |
|
5
|
|
|
|
|
20
|
|
|
5
|
|
|
|
|
3010
|
|
216
|
108
|
|
|
|
|
585
|
push @lines, sprintf join(' ', @lengths) . "\n", @$row; |
217
|
|
|
|
|
|
|
} |
218
|
28
|
100
|
|
|
|
138
|
return wantarray ? @lines : join '', @lines; |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
sub _gather_options_parameters { |
223
|
16
|
|
|
16
|
|
46
|
my ($self, $cmds) = @_; |
224
|
16
|
|
|
|
|
36
|
my @options; |
225
|
|
|
|
|
|
|
my @parameters; |
226
|
16
|
|
|
|
|
45
|
my $global_options = $self->options; |
227
|
16
|
|
|
|
|
39
|
my $commands = $self->subcommands; |
228
|
16
|
|
|
|
|
44
|
push @options, @$global_options; |
229
|
|
|
|
|
|
|
|
230
|
16
|
|
|
|
|
50
|
for my $cmd (@$cmds) { |
231
|
12
|
|
|
|
|
33
|
my $cmd_spec = $commands->{ $cmd }; |
232
|
12
|
|
50
|
|
|
47
|
my $options = $cmd_spec->options || []; |
233
|
12
|
|
50
|
|
|
41
|
my $parameters = $cmd_spec->parameters || []; |
234
|
12
|
|
|
|
|
26
|
push @options, @$options; |
235
|
12
|
|
|
|
|
28
|
push @parameters, @$parameters; |
236
|
|
|
|
|
|
|
|
237
|
12
|
|
100
|
|
|
65
|
$commands = $cmd_spec->subcommands || {}; |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
} |
240
|
16
|
|
|
|
|
57
|
return \@options, \@parameters, $commands; |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
sub generate_completion { |
244
|
0
|
|
|
0
|
1
|
0
|
my ($self, %args) = @_; |
245
|
0
|
|
|
|
|
0
|
my $shell = delete $args{shell}; |
246
|
|
|
|
|
|
|
|
247
|
0
|
0
|
|
|
|
0
|
if ($shell eq "zsh") { |
|
|
0
|
|
|
|
|
|
248
|
0
|
|
|
|
|
0
|
require App::Spec::Completion::Zsh; |
249
|
0
|
|
|
|
|
0
|
my $completer = App::Spec::Completion::Zsh->new( |
250
|
|
|
|
|
|
|
spec => $self, |
251
|
|
|
|
|
|
|
); |
252
|
0
|
|
|
|
|
0
|
return $completer->generate_completion(%args); |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
elsif ($shell eq "bash") { |
255
|
0
|
|
|
|
|
0
|
require App::Spec::Completion::Bash; |
256
|
0
|
|
|
|
|
0
|
my $completer = App::Spec::Completion::Bash->new( |
257
|
|
|
|
|
|
|
spec => $self, |
258
|
|
|
|
|
|
|
); |
259
|
0
|
|
|
|
|
0
|
return $completer->generate_completion(%args); |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
} |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
sub make_getopt { |
265
|
61
|
|
|
61
|
1
|
160
|
my ($self, $options, $result, $specs) = @_; |
266
|
61
|
|
|
|
|
100
|
my @getopt; |
267
|
61
|
|
|
|
|
133
|
for my $opt (@$options) { |
268
|
119
|
|
|
|
|
267
|
my $name = $opt->name; |
269
|
119
|
|
|
|
|
187
|
my $spec = $name; |
270
|
119
|
50
|
|
|
|
371
|
if (my $aliases = $opt->aliases) { |
271
|
119
|
|
|
|
|
312
|
$spec .= "|$_" for @$aliases; |
272
|
|
|
|
|
|
|
} |
273
|
119
|
100
|
|
|
|
404
|
unless ($opt->type eq 'flag') { |
274
|
38
|
|
|
|
|
85
|
$spec .= "=s"; |
275
|
|
|
|
|
|
|
} |
276
|
119
|
|
|
|
|
303
|
$specs->{ $name } = $opt; |
277
|
119
|
100
|
|
|
|
289
|
if ($opt->multiple) { |
278
|
33
|
100
|
|
|
|
130
|
if ($opt->type eq 'flag') { |
|
|
50
|
|
|
|
|
|
279
|
28
|
|
|
|
|
84
|
$spec .= '+'; |
280
|
|
|
|
|
|
|
} |
281
|
|
|
|
|
|
|
elsif ($opt->mapping) { |
282
|
5
|
|
|
|
|
16
|
$result->{ $name } = {}; |
283
|
5
|
|
|
|
|
15
|
$spec .= '%'; |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
else { |
286
|
0
|
|
|
|
|
0
|
$result->{ $name } = []; |
287
|
0
|
|
|
|
|
0
|
$spec .= '@'; |
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
} |
290
|
119
|
|
|
|
|
336
|
push @getopt, $spec, \$result->{ $name }, |
291
|
|
|
|
|
|
|
} |
292
|
61
|
|
|
|
|
216
|
return @getopt; |
293
|
|
|
|
|
|
|
} |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
=pod |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
=head1 NAME |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
App::Spec - Specification for commandline apps |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
=head1 SYNOPSIS |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
WARNING: This is still experimental. The spec is subject to change. |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
This module represents a specification of a command line tool. |
306
|
|
|
|
|
|
|
Currently it can read the spec from a YAML file or directly from a data |
307
|
|
|
|
|
|
|
structure in perl. |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
It uses the role L. |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
The L module is the framework which will run the actual |
312
|
|
|
|
|
|
|
app. |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
Have a look at the L for how to write an app. |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
In the examples directory you will find the app C which is supposed |
317
|
|
|
|
|
|
|
to demonstrate everything that App::Spec supports right now. |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
Your script: |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
use App::Spec; |
322
|
|
|
|
|
|
|
my $spec = App::Spec->read("/path/to/myapp-spec.yaml"); |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
my $run = $spec->runner; |
325
|
|
|
|
|
|
|
$run->run; |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
# this is equivalent to |
328
|
|
|
|
|
|
|
#my $run = App::Spec::Run->new( |
329
|
|
|
|
|
|
|
# spec => $spec, |
330
|
|
|
|
|
|
|
# cmd => Your::App->new, |
331
|
|
|
|
|
|
|
#); |
332
|
|
|
|
|
|
|
#$run->run; |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
Your App class: |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
package Your::App; |
337
|
|
|
|
|
|
|
use base 'App::Spec::Run::Cmd'; |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
sub command1 { |
340
|
|
|
|
|
|
|
my ($self, $run) = @_; |
341
|
|
|
|
|
|
|
my $options = $run->options; |
342
|
|
|
|
|
|
|
my $param = $run->parameters; |
343
|
|
|
|
|
|
|
# Do something |
344
|
|
|
|
|
|
|
$run->out("Hello world!"); |
345
|
|
|
|
|
|
|
$run->err("oops"); |
346
|
|
|
|
|
|
|
# you can also use print directly |
347
|
|
|
|
|
|
|
} |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
=head1 METHODS |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
=over 4 |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
=item read |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
my $spec = App::Spec->read("/path/to/myapp-spec.yaml"); |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
=item load_data |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
Takes a file, hashref or glob and returns generated appspec hashref |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
my $hash = $class->load_data($file); |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
=item build |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
Builds objects out of the hashref |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
my $appspec = App::Spec->build(%hash); |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
=item runner |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
Returns an instance of the your app class |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
my $run = $spec->runner; |
375
|
|
|
|
|
|
|
$run->run; |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
# this is equivalent to |
378
|
|
|
|
|
|
|
my $run = App::Spec::Example::MyApp->new({ |
379
|
|
|
|
|
|
|
spec => $spec, |
380
|
|
|
|
|
|
|
}); |
381
|
|
|
|
|
|
|
$run->run; |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
=item usage |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
Returns usage output for the specified subcommands: |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
my $usage = $spec->usage( |
388
|
|
|
|
|
|
|
commands => ["subcommand1","subcommand2"], |
389
|
|
|
|
|
|
|
); |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
=item generate_completion |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
Generates shell completion script for the spec. |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
my $completion = $spec->generate_completion( |
396
|
|
|
|
|
|
|
shell => "zsh", |
397
|
|
|
|
|
|
|
); |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
=item make_getopt |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
Returns options for Getopt::Long |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
my @getopt = $spec->make_getopt($global_options, \%options, $option_specs); |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
=item abstract, appspec, class, description, has_subcommands, markup, name, options, parameters, subcommands, title |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
Accessors for the things defined in the spec (file) |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
=back |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
=head1 SEE ALSO |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
L - Utilities for App::Spec authors |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
=head1 LICENSE |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
This library is free software and may be distributed under the same terms |
418
|
|
|
|
|
|
|
as perl itself. |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
=cut |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
1; |
423
|
|
|
|
|
|
|
|