| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package App::DuckPAN::Cmd::New; |
|
2
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:DDG'; |
|
3
|
|
|
|
|
|
|
# ABSTRACT: Take a name as input and generates a new, named Goodie or Spice instant answer skeleton |
|
4
|
|
|
|
|
|
|
$App::DuckPAN::Cmd::New::VERSION = '1017'; |
|
5
|
|
|
|
|
|
|
# See the template/templates.yml file in the Goodie or Spice repository for the |
|
6
|
|
|
|
|
|
|
# list of template-sets and files generated for them |
|
7
|
|
|
|
|
|
|
|
|
8
|
1
|
|
|
1
|
|
842
|
use Moo; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
6
|
|
|
9
|
|
|
|
|
|
|
with qw( App::DuckPAN::Cmd ); |
|
10
|
|
|
|
|
|
|
|
|
11
|
1
|
|
|
1
|
|
188
|
use MooX::Options protect_argv => 0; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
5
|
|
|
12
|
1
|
|
|
1
|
|
954
|
use Try::Tiny; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
78
|
|
|
13
|
1
|
|
|
1
|
|
3
|
use List::MoreUtils 'any'; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
18
|
|
|
14
|
|
|
|
|
|
|
|
|
15
|
1
|
|
|
1
|
|
718
|
use App::DuckPAN::TemplateDefinitions; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
33
|
|
|
16
|
|
|
|
|
|
|
|
|
17
|
1
|
|
|
1
|
|
6
|
no warnings 'uninitialized'; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
1324
|
|
|
18
|
|
|
|
|
|
|
########################## |
|
19
|
|
|
|
|
|
|
# Command line arguments # |
|
20
|
|
|
|
|
|
|
########################## |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
# A 'template' for the user is equivalent to a 'template-set' for the program |
|
23
|
|
|
|
|
|
|
option template => ( |
|
24
|
|
|
|
|
|
|
is => 'rwp', |
|
25
|
|
|
|
|
|
|
format => 's', |
|
26
|
|
|
|
|
|
|
default => 'default', |
|
27
|
|
|
|
|
|
|
short => 't', |
|
28
|
|
|
|
|
|
|
doc => 'template used to generate the instant answer skeleton (default: default)', |
|
29
|
|
|
|
|
|
|
); |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
option list_templates => ( |
|
32
|
|
|
|
|
|
|
is => 'ro', |
|
33
|
|
|
|
|
|
|
short => 'l', |
|
34
|
|
|
|
|
|
|
doc => 'list the available instant answer templates and exit', |
|
35
|
|
|
|
|
|
|
); |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
option cheatsheet => ( |
|
38
|
|
|
|
|
|
|
is => 'ro', |
|
39
|
|
|
|
|
|
|
short => 'c', |
|
40
|
|
|
|
|
|
|
doc => "create a Cheat Sheet (short for `--template cheatsheet'; valid only for Goodies)", |
|
41
|
|
|
|
|
|
|
); |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
option no_optionals => ( |
|
44
|
|
|
|
|
|
|
is => 'ro', |
|
45
|
|
|
|
|
|
|
short => 'N', |
|
46
|
|
|
|
|
|
|
doc => 'do not create any optional files from the chosen template', |
|
47
|
|
|
|
|
|
|
); |
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
############## |
|
50
|
|
|
|
|
|
|
# Attributes # |
|
51
|
|
|
|
|
|
|
############## |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
has _template_defs => ( |
|
54
|
|
|
|
|
|
|
is => 'ro', |
|
55
|
|
|
|
|
|
|
init_arg => undef, |
|
56
|
|
|
|
|
|
|
lazy => 1, |
|
57
|
|
|
|
|
|
|
builder => 1, |
|
58
|
|
|
|
|
|
|
doc => 'Template definitions for the templates for the current IA type', |
|
59
|
|
|
|
|
|
|
); |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
sub _build__template_defs { |
|
62
|
0
|
|
|
0
|
|
|
my $self = shift; |
|
63
|
0
|
|
|
|
|
|
my $template_defs; |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
# Read the templates.yml file |
|
66
|
|
|
|
|
|
|
try { |
|
67
|
0
|
|
|
0
|
|
|
$template_defs = App::DuckPAN::TemplateDefinitions->new; |
|
68
|
|
|
|
|
|
|
} catch { |
|
69
|
0
|
|
|
0
|
|
|
my $error = $_; |
|
70
|
|
|
|
|
|
|
|
|
71
|
0
|
0
|
|
|
|
|
if ($error =~ /no such file/i) { |
|
72
|
|
|
|
|
|
|
# Handle the 'no such file or directory' exception |
|
73
|
|
|
|
|
|
|
# specially to show more information since it can be a |
|
74
|
|
|
|
|
|
|
# common error for users with an older IA repository |
|
75
|
0
|
|
|
|
|
|
my $type = $self->app->get_ia_type(); |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
$self->app->emit_and_exit(1, |
|
78
|
|
|
|
|
|
|
"Template definitions file not found for " . $type->{name} . |
|
79
|
0
|
|
|
|
|
|
" Instant Answers. You may need to pull the latest version " . |
|
80
|
|
|
|
|
|
|
"of this repository."); |
|
81
|
|
|
|
|
|
|
} |
|
82
|
|
|
|
|
|
|
else { |
|
83
|
0
|
|
|
|
|
|
$self->app->emit_and_exit(1, $error); |
|
84
|
|
|
|
|
|
|
} |
|
85
|
0
|
|
|
|
|
|
}; |
|
86
|
|
|
|
|
|
|
|
|
87
|
0
|
|
|
|
|
|
return $template_defs; |
|
88
|
|
|
|
|
|
|
} |
|
89
|
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
has _template_set => ( |
|
91
|
|
|
|
|
|
|
is => 'ro', |
|
92
|
|
|
|
|
|
|
init_arg => undef, |
|
93
|
|
|
|
|
|
|
lazy => 1, |
|
94
|
|
|
|
|
|
|
builder => 1, |
|
95
|
|
|
|
|
|
|
doc => 'The template set chosen by the user', |
|
96
|
|
|
|
|
|
|
); |
|
97
|
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
sub _build__template_set { |
|
99
|
0
|
|
|
0
|
|
|
my $self = shift; |
|
100
|
0
|
|
|
|
|
|
my $type = $self->app->get_ia_type(); |
|
101
|
0
|
|
|
|
|
|
my $template_defs = $self->_template_defs; |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
# Get the template chosen by the user |
|
104
|
0
|
|
|
|
|
|
my $template_set = $template_defs->get_template_set($self->template); |
|
105
|
|
|
|
|
|
|
|
|
106
|
0
|
0
|
|
|
|
|
unless ($template_set) { |
|
107
|
|
|
|
|
|
|
# We didn't find the template-set by the name. This could mean |
|
108
|
|
|
|
|
|
|
# that there was a typo in the name or the user has an older IA |
|
109
|
|
|
|
|
|
|
# repo and it not present in that version. |
|
110
|
|
|
|
|
|
|
$self->app->emit_and_exit(1, |
|
111
|
|
|
|
|
|
|
"'" . $self->template . "' is not a valid template for a " . |
|
112
|
0
|
|
|
|
|
|
$type->{name} . " Instant Answer. You may need to update " . |
|
113
|
|
|
|
|
|
|
"your repository to get the latest templates.\n" . |
|
114
|
|
|
|
|
|
|
$self->_available_templates_message); |
|
115
|
|
|
|
|
|
|
} |
|
116
|
|
|
|
|
|
|
|
|
117
|
0
|
|
|
|
|
|
return $template_set; |
|
118
|
|
|
|
|
|
|
} |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
########### |
|
121
|
|
|
|
|
|
|
# Methods # |
|
122
|
|
|
|
|
|
|
########### |
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
# Copy of @ARGV before MooX::Options processes it |
|
125
|
|
|
|
|
|
|
my @ORIG_ARGV; |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
before new_with_options => sub { @ORIG_ARGV = @ARGV }; |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
sub run { |
|
130
|
0
|
|
|
0
|
0
|
|
my ($self, @args) = @_; |
|
131
|
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
# Check which IA repo we're in... |
|
133
|
0
|
|
|
|
|
|
my $type = $self->app->get_ia_type(); |
|
134
|
|
|
|
|
|
|
|
|
135
|
0
|
|
|
|
|
|
my $no_handler = 0; |
|
136
|
|
|
|
|
|
|
# Process the --cheatsheet option |
|
137
|
0
|
0
|
0
|
|
|
|
if ($self->cheatsheet || $self->template eq 'cheatsheet') { |
|
138
|
0
|
0
|
|
|
|
|
if ($type->{name} ne 'Goodie') { |
|
139
|
0
|
|
|
|
|
|
$self->app->emit_and_exit(1, |
|
140
|
|
|
|
|
|
|
"Cheat Sheets can be created only in the Goodie " . |
|
141
|
|
|
|
|
|
|
"Instant Answer repository."); |
|
142
|
|
|
|
|
|
|
} |
|
143
|
|
|
|
|
|
|
|
|
144
|
0
|
|
|
|
|
|
$self->_set_template('cheatsheet'); |
|
145
|
0
|
|
|
|
|
|
$no_handler = 1; |
|
146
|
|
|
|
|
|
|
} |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
# Process the --list-templates option: List the template-set names and exit with success |
|
149
|
0
|
0
|
|
|
|
|
$self->app->emit_and_exit(0, $self->_available_templates_message) |
|
150
|
|
|
|
|
|
|
if $self->list_templates; |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
# Gracefully handle the case where '--template' is the last argument |
|
153
|
0
|
0
|
0
|
|
|
|
$self->app->emit_and_exit( |
|
154
|
|
|
|
|
|
|
1, |
|
155
|
|
|
|
|
|
|
"Please specify the template for your Instant Answer.\n" . |
|
156
|
|
|
|
|
|
|
$self->_available_templates_message |
|
157
|
|
|
|
|
|
|
) if ($ORIG_ARGV[$#ORIG_ARGV] // '') eq '--template'; |
|
158
|
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
# Get the template-set instance based on the command line arguments. |
|
160
|
0
|
|
|
|
|
|
my $template_set = $self->_template_set(); |
|
161
|
|
|
|
|
|
|
|
|
162
|
0
|
|
|
|
|
|
$self->app->emit_info('Creating a new ' . $template_set->description . '...'); |
|
163
|
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
# Instant Answer name as parameter |
|
165
|
0
|
0
|
|
|
|
|
my $entered_name = (@args) ? join(' ', @args) : $self->app->get_reply('Please enter a name for your Instant Answer: '); |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
# Validate the entered name |
|
168
|
0
|
0
|
|
|
|
|
$self->app->emit_and_exit(1, 'Must supply a name for your Instant Answer.') unless $entered_name; |
|
169
|
0
|
0
|
|
|
|
|
$self->app->emit_and_exit(1, |
|
170
|
|
|
|
|
|
|
"'$entered_name' is not a valid name for an Instant Answer. " . |
|
171
|
|
|
|
|
|
|
'Please run the program again and provide a valid name.' |
|
172
|
|
|
|
|
|
|
) unless $entered_name =~ m@^( [a-zA-Z0-9\s] | (?<![:/])(::|/)(?![:/]) )+$@x; |
|
173
|
0
|
0
|
0
|
|
|
|
$self->app->emit_and_exit(1, |
|
174
|
|
|
|
|
|
|
'The name for this type of Instant Answer cannot contain package or path separators. ' . |
|
175
|
|
|
|
|
|
|
'Please run the program again and provide a valid name.' |
|
176
|
|
|
|
|
|
|
) if !$template_set->subdir_support && $entered_name =~ m![/:]!; |
|
177
|
|
|
|
|
|
|
|
|
178
|
0
|
|
|
|
|
|
$entered_name =~ s/\//::/g; #change "/" to "::" for easier handling |
|
179
|
|
|
|
|
|
|
|
|
180
|
0
|
|
|
|
|
|
my $package_name = $self->app->phrase_to_camel($entered_name); |
|
181
|
0
|
|
|
|
|
|
my ($name, $separated_name, $path, $lc_path) = ($package_name, $package_name, '', ''); |
|
182
|
|
|
|
|
|
|
|
|
183
|
0
|
|
|
|
|
|
$separated_name =~ s/::/ /g; |
|
184
|
|
|
|
|
|
|
|
|
185
|
0
|
0
|
|
|
|
|
if ($package_name =~ m/::/) { |
|
186
|
0
|
|
|
|
|
|
my @path_parts = split(/::/, $package_name); |
|
187
|
0
|
0
|
|
|
|
|
if (scalar @path_parts > 1) { |
|
188
|
0
|
|
|
|
|
|
$name = pop @path_parts; |
|
189
|
0
|
|
|
|
|
|
$path = join("/", @path_parts); |
|
190
|
0
|
|
|
|
|
|
$lc_path = join("/", map { $self->app->camel_to_underscore($_) } @path_parts); |
|
|
0
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
} |
|
192
|
|
|
|
|
|
|
else { |
|
193
|
0
|
|
|
|
|
|
$self->app->emit_and_exit(1, "Malformed input. Please provide a properly formatted package name for your Instant Answer."); |
|
194
|
|
|
|
|
|
|
} |
|
195
|
|
|
|
|
|
|
} |
|
196
|
|
|
|
|
|
|
|
|
197
|
0
|
|
|
|
|
|
my $lc_name = $self->app->camel_to_underscore($name); |
|
198
|
0
|
0
|
|
|
|
|
my $filepath = $path ? "$path/$name" : $name; |
|
199
|
0
|
0
|
|
|
|
|
my $lc_filepath = $lc_path ? "$lc_path/$lc_name" : $lc_name; |
|
200
|
0
|
0
|
|
|
|
|
if (scalar $lc_path) { |
|
201
|
0
|
|
|
|
|
|
$lc_path =~ s/\//_/g; #safe to modify, we already used this in $lc_filepath |
|
202
|
0
|
|
|
|
|
|
$lc_name = $lc_path . '_' . $lc_name; |
|
203
|
|
|
|
|
|
|
} |
|
204
|
|
|
|
|
|
|
|
|
205
|
0
|
0
|
|
|
|
|
my @optional_templates = $self->_ask_optional_templates |
|
206
|
|
|
|
|
|
|
unless $self->no_optionals; |
|
207
|
|
|
|
|
|
|
|
|
208
|
0
|
|
|
|
|
|
my %vars = ( |
|
209
|
|
|
|
|
|
|
ia_package_name => $package_name, |
|
210
|
|
|
|
|
|
|
ia_name_separated => $separated_name, |
|
211
|
|
|
|
|
|
|
ia_id => $lc_name, |
|
212
|
|
|
|
|
|
|
ia_path => $filepath, |
|
213
|
|
|
|
|
|
|
ia_path_lc => $lc_filepath, |
|
214
|
|
|
|
|
|
|
); |
|
215
|
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
# Cheat sheets use hyphenated file names. |
|
217
|
0
|
0
|
|
|
|
|
if ($self->template eq 'cheatsheet') { |
|
218
|
0
|
|
|
|
|
|
my $underscored = $vars{ia_id} =~ s/_cheat_sheet//r; |
|
219
|
0
|
|
|
|
|
|
$vars{cheat_sheet_hyphenated} = $underscored =~ s/_/-/gr; |
|
220
|
|
|
|
|
|
|
} |
|
221
|
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
# If the Perl module every becomes optional, this should only run if the user |
|
223
|
|
|
|
|
|
|
# requests one |
|
224
|
0
|
0
|
|
|
|
|
unless($no_handler){ |
|
225
|
0
|
|
|
|
|
|
%vars = (%vars, %{$self->_config_handler}); |
|
|
0
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
} |
|
227
|
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
# Generate the instant answer files. The return value is a hash with |
|
229
|
|
|
|
|
|
|
# information about the created files and any error that was encountered. |
|
230
|
0
|
|
|
|
|
|
my %generate_result = $template_set->generate(\%vars, \@optional_templates); |
|
231
|
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
# Show the list of files that were successfully created |
|
233
|
0
|
|
|
|
|
|
my @created_files = @{$generate_result{created_files}}; |
|
|
0
|
|
|
|
|
|
|
|
234
|
0
|
|
|
|
|
|
$self->app->emit_info('Created files:'); |
|
235
|
0
|
|
|
|
|
|
$self->app->emit_info(" $_") for @created_files; |
|
236
|
0
|
0
|
|
|
|
|
$self->app->emit_info(' (none)') unless @created_files; # possible on error |
|
237
|
|
|
|
|
|
|
|
|
238
|
0
|
0
|
|
|
|
|
if (my $error = $generate_result{error}) { |
|
239
|
|
|
|
|
|
|
# Remove the line number information if not in verbose mode. |
|
240
|
|
|
|
|
|
|
# This error message would be seen mostly by users writing IAs |
|
241
|
|
|
|
|
|
|
# for whom the line numbers don't add much value. |
|
242
|
0
|
0
|
|
|
|
|
$error =~ s/.*\K at .* line \d+\.$// |
|
243
|
|
|
|
|
|
|
unless $self->app->verbose; |
|
244
|
|
|
|
|
|
|
|
|
245
|
0
|
|
|
|
|
|
$self->app->emit_and_exit(1, $error) |
|
246
|
|
|
|
|
|
|
} |
|
247
|
|
|
|
|
|
|
|
|
248
|
0
|
|
|
|
|
|
$self->app->emit_info('Success!'); |
|
249
|
|
|
|
|
|
|
} |
|
250
|
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
# Allow user to choose a handler |
|
252
|
|
|
|
|
|
|
sub _config_handler { |
|
253
|
0
|
|
|
0
|
|
|
my $self = shift; |
|
254
|
|
|
|
|
|
|
|
|
255
|
0
|
|
|
|
|
|
my @handlers = ( |
|
256
|
|
|
|
|
|
|
# Scalar-based |
|
257
|
|
|
|
|
|
|
'remainder: (default) The query without the trigger words, spacing and case are preserved.', |
|
258
|
|
|
|
|
|
|
'query_raw: Like remainder but with trigger words intact', |
|
259
|
|
|
|
|
|
|
'query: Full query normalized with a single space between terms', |
|
260
|
|
|
|
|
|
|
'query_lc: Like query but in lowercase', |
|
261
|
|
|
|
|
|
|
'query_clean: Like query_lc but with non-alphanumeric characters removed', |
|
262
|
|
|
|
|
|
|
'query_nowhitespace: All whitespace removed', |
|
263
|
|
|
|
|
|
|
'query_nowhitespace_nodash: All whitespace and hyphens removed', |
|
264
|
|
|
|
|
|
|
# Array-based |
|
265
|
|
|
|
|
|
|
'matches: Returns an array of captured expression from a regular expression trigger', |
|
266
|
|
|
|
|
|
|
'words: Like query_clean but returns an array of the terms split on whitespace', |
|
267
|
|
|
|
|
|
|
'query_parts: Like query but returns an array of the terms split on whitespace', |
|
268
|
|
|
|
|
|
|
'query_raw_parts: Like query_parts but array contains original whitespace elements' |
|
269
|
|
|
|
|
|
|
); |
|
270
|
|
|
|
|
|
|
|
|
271
|
0
|
|
|
|
|
|
my $res = $self->app->get_reply( |
|
272
|
|
|
|
|
|
|
'Which handler would you like to use to process the query?', |
|
273
|
|
|
|
|
|
|
choices => \@handlers, |
|
274
|
|
|
|
|
|
|
default => $handlers[0] |
|
275
|
|
|
|
|
|
|
); |
|
276
|
|
|
|
|
|
|
|
|
277
|
0
|
0
|
|
|
|
|
unless($res =~ /^([^:]+)/){ |
|
278
|
0
|
|
|
|
|
|
$self->app->emit_and_exit(1, "Failed to extract handler from response: $res"); |
|
279
|
|
|
|
|
|
|
} |
|
280
|
0
|
|
|
|
|
|
my $handler = $1; |
|
281
|
0
|
0
|
|
0
|
|
|
my $var = (any {$handler eq $_} qw(words query_parts query_raw_parts matches)) ? '@' : '$'; |
|
|
0
|
|
|
|
|
|
|
|
282
|
0
|
0
|
|
|
|
|
my $trigger = $handler eq 'matches' |
|
283
|
|
|
|
|
|
|
? q{query => qr/trigger regex/} |
|
284
|
|
|
|
|
|
|
: q{any => 'triggerword', 'trigger phrase'}; |
|
285
|
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
return { |
|
287
|
0
|
|
|
|
|
|
ia_handler => $handler, |
|
288
|
|
|
|
|
|
|
ia_handler_var => $var, |
|
289
|
|
|
|
|
|
|
ia_trigger => $trigger |
|
290
|
|
|
|
|
|
|
}; |
|
291
|
|
|
|
|
|
|
} |
|
292
|
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
# Ask the user for which optional templates they want to use and return a list |
|
294
|
|
|
|
|
|
|
# of the chosen templates |
|
295
|
|
|
|
|
|
|
sub _ask_optional_templates { |
|
296
|
0
|
|
|
0
|
|
|
my $self = shift; |
|
297
|
0
|
|
|
|
|
|
my $template_set = $self->_template_set; |
|
298
|
0
|
|
|
|
|
|
my $combinations = $template_set->optional_template_combinations; |
|
299
|
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
# no optional templates; nothing to do |
|
301
|
0
|
0
|
|
|
|
|
return unless @$combinations; |
|
302
|
|
|
|
|
|
|
|
|
303
|
0
|
|
|
|
|
|
my $show_optional_templates = $self->app->ask_yn( |
|
304
|
|
|
|
|
|
|
'Would you like to configure optional templates?', |
|
305
|
|
|
|
|
|
|
default => 0, |
|
306
|
|
|
|
|
|
|
); |
|
307
|
|
|
|
|
|
|
|
|
308
|
0
|
0
|
|
|
|
|
if ($show_optional_templates) { |
|
309
|
|
|
|
|
|
|
# The choice strings to show to the user |
|
310
|
0
|
|
|
|
|
|
my @choices; |
|
311
|
|
|
|
|
|
|
# Mapping from a choice string to the corresponding template combination |
|
312
|
|
|
|
|
|
|
my %choice_combinations; |
|
313
|
|
|
|
|
|
|
|
|
314
|
0
|
|
|
|
|
|
for my $combination (@$combinations) { |
|
315
|
|
|
|
|
|
|
# Label of every template in the combination |
|
316
|
0
|
|
|
|
|
|
my @labels = map { $_->label } @$combination; |
|
|
0
|
|
|
|
|
|
|
|
317
|
0
|
|
|
|
|
|
my $choice = join(', ', @labels); |
|
318
|
|
|
|
|
|
|
|
|
319
|
0
|
|
|
|
|
|
push @choices, $choice; |
|
320
|
0
|
|
|
|
|
|
$choice_combinations{$choice} = $combination; |
|
321
|
|
|
|
|
|
|
} |
|
322
|
|
|
|
|
|
|
|
|
323
|
0
|
|
|
|
|
|
my $reply = $self->app->get_reply( |
|
324
|
|
|
|
|
|
|
'Choose configuration', |
|
325
|
|
|
|
|
|
|
choices => \@choices, |
|
326
|
|
|
|
|
|
|
default => $choices[0], |
|
327
|
|
|
|
|
|
|
); |
|
328
|
|
|
|
|
|
|
|
|
329
|
0
|
|
|
|
|
|
return @{$choice_combinations{$reply}}; |
|
|
0
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
} |
|
331
|
|
|
|
|
|
|
|
|
332
|
0
|
|
|
|
|
|
return; |
|
333
|
|
|
|
|
|
|
} |
|
334
|
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
# Create a message with the list of available template-sets for this IA type |
|
336
|
|
|
|
|
|
|
sub _available_templates_message { |
|
337
|
0
|
|
|
0
|
|
|
my $self = shift; |
|
338
|
0
|
|
|
|
|
|
my $template_defs = $self->_template_defs; |
|
339
|
|
|
|
|
|
|
# template-sets, sorted by name |
|
340
|
|
|
|
|
|
|
my @template_sets = |
|
341
|
0
|
|
|
|
|
|
sort { $a->name cmp $b->name } $template_defs->get_template_sets; |
|
|
0
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
|
|
343
|
0
|
|
|
|
|
|
my $message = "Available templates:"; |
|
344
|
|
|
|
|
|
|
|
|
345
|
0
|
|
|
|
|
|
for my $template_set (@template_sets) { |
|
346
|
0
|
|
|
|
|
|
$message .= sprintf("\n %10s - %s", |
|
347
|
|
|
|
|
|
|
$template_set->name, |
|
348
|
|
|
|
|
|
|
$template_set->description, |
|
349
|
|
|
|
|
|
|
); |
|
350
|
|
|
|
|
|
|
} |
|
351
|
|
|
|
|
|
|
|
|
352
|
0
|
|
|
|
|
|
return $message; |
|
353
|
|
|
|
|
|
|
} |
|
354
|
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
1; |
|
356
|
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
__END__ |
|
358
|
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
=pod |
|
360
|
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
=head1 NAME |
|
362
|
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
App::DuckPAN::Cmd::New - Take a name as input and generates a new, named Goodie or Spice instant answer skeleton |
|
364
|
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
=head1 VERSION |
|
366
|
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
version 1017 |
|
368
|
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
=head1 AUTHOR |
|
370
|
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
DuckDuckGo <open@duckduckgo.com>, Zach Thompson <zach@duckduckgo.com>, Zaahir Moolla <moollaza@duckduckgo.com>, Torsten Raudssus <torsten@raudss.us> L<https://raudss.us/> |
|
372
|
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
|
374
|
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
This software is Copyright (c) 2013 by DuckDuckGo, Inc. L<https://duckduckgo.com/>. |
|
376
|
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
This is free software, licensed under: |
|
378
|
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
The Apache License, Version 2.0, January 2004 |
|
380
|
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
=cut |