line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package CXC::Form::Tiny::Plugin::OptArgs2::Meta; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# ABSTRACT: Form metaclass role for OptArgs2 |
4
|
|
|
|
|
|
|
|
5
|
5
|
|
|
5
|
|
5115
|
use v5.20; |
|
5
|
|
|
|
|
22
|
|
6
|
|
|
|
|
|
|
|
7
|
5
|
|
|
5
|
|
28
|
use warnings; |
|
5
|
|
|
|
|
11
|
|
|
5
|
|
|
|
|
204
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
our $VERSION = '0.11'; |
10
|
|
|
|
|
|
|
|
11
|
5
|
|
|
5
|
|
2273
|
use Clone (); |
|
5
|
|
|
|
|
12421
|
|
|
5
|
|
|
|
|
167
|
|
12
|
5
|
|
|
5
|
|
36
|
use Scalar::Util qw( blessed ); |
|
5
|
|
|
|
|
17
|
|
|
5
|
|
|
|
|
322
|
|
13
|
5
|
|
|
5
|
|
1549
|
use Ref::Util qw( is_plain_hashref is_arrayref is_regexpref is_ref ); |
|
5
|
|
|
|
|
1837
|
|
|
5
|
|
|
|
|
363
|
|
14
|
5
|
|
|
5
|
|
36
|
use Form::Tiny::Utils 'get_package_form_meta'; |
|
5
|
|
|
|
|
13
|
|
|
5
|
|
|
|
|
396
|
|
15
|
|
|
|
|
|
|
use Types::Standard |
16
|
5
|
|
|
5
|
|
39
|
qw( ArrayRef Bool CodeRef Dict Enum Int Optional RegexpRef Str Tuple Undef Value ); |
|
5
|
|
|
|
|
12
|
|
|
5
|
|
|
|
|
81
|
|
17
|
5
|
|
|
5
|
|
23745
|
use Type::Params qw( signature_for ); |
|
5
|
|
|
|
|
22105
|
|
|
5
|
|
|
|
|
65
|
|
18
|
5
|
|
|
5
|
|
1762
|
use Types::Common::String qw ( NonEmptySimpleStr NonEmptyStr ); |
|
5
|
|
|
|
|
14
|
|
|
5
|
|
|
|
|
59
|
|
19
|
|
|
|
|
|
|
|
20
|
5
|
|
|
5
|
|
5865
|
use Moo::Role; |
|
5
|
|
|
|
|
14
|
|
|
5
|
|
|
|
|
46
|
|
21
|
|
|
|
|
|
|
|
22
|
5
|
|
|
5
|
|
2548
|
use experimental 'signatures', 'postderef', 'lexical_subs'; |
|
5
|
|
|
|
|
35
|
|
|
5
|
|
|
|
|
46
|
|
23
|
|
|
|
|
|
|
|
24
|
5
|
|
|
5
|
|
3776
|
use namespace::clean; |
|
5
|
|
|
|
|
60932
|
|
|
5
|
|
|
|
|
36
|
|
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
my sub croak { |
27
|
0
|
|
|
0
|
|
0
|
require Carp; |
28
|
0
|
|
|
|
|
0
|
goto \&Carp::croak; |
29
|
|
|
|
|
|
|
} |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# need to stash which form this field was added to in order to handle |
32
|
|
|
|
|
|
|
# inheritance of inherited fields which aren't options, but which |
33
|
|
|
|
|
|
|
# contain nested forms which *are* options. |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
around add_field => sub ( $orig, $self, @parameters ) { |
36
|
|
|
|
|
|
|
# this may return either a FieldDefinition or a FieldDefinition, but |
37
|
|
|
|
|
|
|
# in either case, it has an addons methods. |
38
|
|
|
|
|
|
|
my $field = $self->$orig( @parameters ); |
39
|
|
|
|
|
|
|
$field->addons->{ +__PACKAGE__ }{package} = $self->package; |
40
|
|
|
|
|
|
|
return $field; |
41
|
|
|
|
|
|
|
}; |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
has inherit_required => ( |
51
|
|
|
|
|
|
|
is => 'rwp', |
52
|
|
|
|
|
|
|
isa => Bool, |
53
|
13
|
|
|
13
|
|
516
|
builder => sub { !!1 }, |
54
|
|
|
|
|
|
|
); |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
has inherit_optargs => ( |
63
|
|
|
|
|
|
|
is => 'rwp', |
64
|
|
|
|
|
|
|
isa => Bool, |
65
|
13
|
|
|
13
|
|
58487
|
builder => sub { !!0 }, |
66
|
|
|
|
|
|
|
); |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
has inherit_optargs_match => ( |
77
|
|
|
|
|
|
|
is => 'rwp', |
78
|
|
|
|
|
|
|
isa => Undef | ArrayRef [ Tuple [ Bool, RegexpRef ] ], |
79
|
15
|
|
|
15
|
|
14717
|
builder => sub { undef }, |
80
|
|
|
|
|
|
|
); |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
has nested_path_sep => ( |
92
|
|
|
|
|
|
|
is => 'rwp', |
93
|
15
|
|
|
15
|
|
582
|
builder => sub { '_' }, |
94
|
|
|
|
|
|
|
); |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
|
107
|
10
|
|
|
|
|
19
|
has _optargs => ( |
108
|
|
|
|
|
|
|
is => 'rwp', |
109
|
|
|
|
|
|
|
lazy => 1, |
110
|
|
|
|
|
|
|
init_arg => undef, |
111
|
|
|
|
|
|
|
## no critic (Subroutines::ProtectPrivateSubs ) |
112
|
10
|
|
|
10
|
|
168
|
builder => sub ( $self ) { $self->_build_opt_args->_optargs }, |
|
10
|
|
|
|
|
40
|
|
|
10
|
|
|
|
|
47
|
|
113
|
|
|
|
|
|
|
); |
114
|
|
|
|
|
|
|
|
115
|
10
|
|
|
10
|
1
|
202
|
sub optargs ( $self ) { |
|
10
|
|
|
|
|
22
|
|
|
10
|
|
|
|
|
19
|
|
116
|
10
|
|
|
|
|
258
|
return Clone::clone( $self->_optargs ); |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
|
119
|
0
|
|
|
|
|
0
|
has rename => ( |
120
|
|
|
|
|
|
|
is => 'rwp', |
121
|
|
|
|
|
|
|
lazy => 1, |
122
|
|
|
|
|
|
|
init_arg => undef, |
123
|
0
|
|
|
0
|
|
0
|
builder => sub ( $self ) { $self->_build_opt_args->rename }, |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
124
|
|
|
|
|
|
|
); |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
|
135
|
2
|
|
|
2
|
1
|
6
|
sub rename_options ( $self, $opt ) { |
|
2
|
|
|
|
|
8
|
|
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
3
|
|
136
|
2
|
|
|
|
|
53
|
my $rename = $self->rename; |
137
|
2
|
|
|
|
|
33
|
for my $from ( keys $opt->%* ) { |
138
|
20
|
|
|
|
|
41
|
my $to = $rename->{$from}; |
139
|
20
|
50
|
|
|
|
43
|
croak( "unexpected option key: $from\n" ) |
140
|
|
|
|
|
|
|
if !defined $to; |
141
|
20
|
|
|
|
|
51
|
$opt->{$to} = delete $opt->{$from}; |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
|
162
|
2
|
|
|
2
|
1
|
69
|
sub inflate_optargs ( $self, $optargs ) { |
|
2
|
|
|
|
|
7
|
|
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
5
|
|
163
|
|
|
|
|
|
|
|
164
|
2
|
|
|
|
|
8
|
state $folder = do { |
165
|
2
|
|
|
|
|
18
|
require Hash::Fold; |
166
|
2
|
|
|
|
|
23
|
Hash::Fold->new( delimiter => chr( 0 ) ); |
167
|
|
|
|
|
|
|
}; |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
# make a copy of the flattened hash |
170
|
2
|
|
|
|
|
6863
|
my %flat = $optargs->%*; |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
# translate the OptArgs names into that required by the Form::Tiny structure |
173
|
2
|
|
|
|
|
22
|
$self->rename_options( \%flat ); |
174
|
|
|
|
|
|
|
|
175
|
2
|
|
|
|
|
13
|
return $folder->unfold( \%flat ); |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
|
179
|
10
|
|
|
10
|
|
18
|
sub _build_opt_args ( $self ) { |
|
10
|
|
|
|
|
20
|
|
|
10
|
|
|
|
|
18
|
|
180
|
10
|
|
|
|
|
24
|
my %rename; |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
my @optargs; |
183
|
10
|
|
|
|
|
49
|
for my $aref ( $self->_create_options( \%rename )->@* ) { |
184
|
51
|
|
|
|
|
109
|
my ( $name, $spec ) = $aref->@*; |
185
|
51
|
|
|
|
|
218
|
my %spec = $spec->%*; |
186
|
51
|
|
|
|
|
101
|
delete $spec{order}; |
187
|
51
|
|
|
|
|
129
|
push @optargs, $name, \%spec; |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
|
190
|
10
|
|
|
|
|
93
|
$self->_set__optargs( \@optargs ); |
191
|
10
|
|
|
|
|
51
|
$self->_set_rename( \%rename ); |
192
|
10
|
|
|
|
|
240
|
return $self; |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
18
|
|
|
18
|
|
32
|
my sub _match_inherit_optargs ( $matches, $package ) { |
|
18
|
|
|
|
|
25
|
|
|
18
|
|
|
|
|
28
|
|
|
18
|
|
|
|
|
25
|
|
196
|
|
|
|
|
|
|
|
197
|
18
|
|
|
|
|
27
|
my $excluded = 0; |
198
|
|
|
|
|
|
|
|
199
|
18
|
|
|
|
|
34
|
for my $match ( $matches->@* ) { |
200
|
26
|
|
|
|
|
52
|
my ( $retval, $qr ) = $match->@*; |
201
|
26
|
100
|
|
|
|
149
|
return $retval if $package =~ $qr; |
202
|
16
|
100
|
|
|
|
43
|
$excluded++ unless $retval; |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
# if no exclusions, then user forgot to add the exclude all |
206
|
|
|
|
|
|
|
# catch-all at the end. just having inclusions doesn't make |
207
|
|
|
|
|
|
|
# sense. |
208
|
|
|
|
|
|
|
|
209
|
8
|
|
|
|
|
38
|
return $excluded != 0; |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
|
212
|
88
|
|
|
88
|
|
167
|
sub _inherit_optargs ( $self, $package ) { |
|
88
|
|
|
|
|
145
|
|
|
88
|
|
|
|
|
131
|
|
|
88
|
|
|
|
|
133
|
|
213
|
|
|
|
|
|
|
|
214
|
88
|
|
66
|
|
|
548
|
return $package eq $self->package |
215
|
|
|
|
|
|
|
|| ( |
216
|
|
|
|
|
|
|
$self->inherit_optargs |
217
|
|
|
|
|
|
|
&& ( !defined $self->inherit_optargs_match |
218
|
|
|
|
|
|
|
|| _match_inherit_optargs( $self->inherit_optargs_match, $package ) ) ); |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
# this has too many arguments |
222
|
|
|
|
|
|
|
sub _create_options ( |
223
|
27
|
|
|
|
|
41
|
$self, $rename, |
|
27
|
|
|
|
|
44
|
|
224
|
27
|
|
|
|
|
50
|
$path = [], |
225
|
27
|
|
|
|
|
40
|
$opt_path = [], |
226
|
27
|
|
|
|
|
129
|
$blueprint = $self->blueprint( recurse => 0 ), |
227
|
27
|
|
|
27
|
|
180
|
) |
|
27
|
|
|
|
|
13295
|
|
228
|
|
|
|
|
|
|
{ |
229
|
27
|
|
|
|
|
53
|
my @optargs; |
230
|
|
|
|
|
|
|
|
231
|
27
|
|
|
|
|
148
|
for my $field ( sort keys $blueprint->%* ) { |
232
|
|
|
|
|
|
|
|
233
|
92
|
|
|
|
|
203
|
my $def = $blueprint->{$field}; |
234
|
|
|
|
|
|
|
|
235
|
92
|
100
|
100
|
|
|
1750
|
if ( is_plain_hashref( $def ) || ( my $is_subform = $def->is_subform ) ) { |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
# Normally a sub-form's options get a prefix based on the field name, e.g. |
238
|
|
|
|
|
|
|
# db.opts => --db-opts. Sometimes the extra levels are overkill for the option names, |
239
|
|
|
|
|
|
|
# so if the options entry contains 'name' specification, use that for the prefix. |
240
|
|
|
|
|
|
|
# unfortunately if the field name is nested, we only get here at the bottom of the |
241
|
|
|
|
|
|
|
# hierarchy, so need to backtrack. |
242
|
|
|
|
|
|
|
|
243
|
23
|
|
|
|
|
239
|
my @paths = ( [ $path->@*, $field ], [ $opt_path->@*, $field ] ); |
244
|
|
|
|
|
|
|
|
245
|
23
|
100
|
|
|
|
58
|
if ( $is_subform ) { |
246
|
|
|
|
|
|
|
|
247
|
19
|
|
33
|
|
|
57
|
my $addons = $def->addons->{ +__PACKAGE__ } // croak( 'no addons for field ' . $def->name ); |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
# bail if we're not inheriting |
250
|
19
|
100
|
|
|
|
46
|
next unless $self->_inherit_optargs( $addons->{package} ); |
251
|
|
|
|
|
|
|
|
252
|
13
|
50
|
50
|
|
|
93
|
if ( defined( my $name = ( $addons->{optargs} // {} )->{name} ) ) { |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
## no critic (ControlStructures::ProhibitDeepNests) |
255
|
0
|
0
|
|
|
|
0
|
if ( my @fixup = $opt_path->@* ) { |
256
|
0
|
|
|
|
|
0
|
my @comp = split( /[.]/, $def->name ); |
257
|
0
|
|
|
|
|
0
|
splice( @fixup, @fixup - @comp, @comp, $name ); |
258
|
|
|
|
|
|
|
# replace default opt_path |
259
|
0
|
|
|
|
|
0
|
$paths[-1] = \@fixup; |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
else { |
262
|
0
|
|
|
|
|
0
|
$paths[-1] = [$name]; |
263
|
|
|
|
|
|
|
} |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
|
266
|
13
|
|
|
|
|
99
|
push @optargs, get_package_form_meta( blessed $def->type )->_create_options( $rename, @paths )->@*; |
267
|
|
|
|
|
|
|
} |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
else { |
270
|
4
|
|
|
|
|
34
|
push @optargs, $self->_create_options( $rename, @paths, $def )->@*; |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
else { |
275
|
69
|
|
33
|
|
|
761
|
my $addons = $def->addons->{ +__PACKAGE__ } // croak( 'no addons for field ' . $def->name ); |
276
|
69
|
50
|
|
|
|
171
|
next unless defined( my $orig_optargs = $addons->{optargs} ); |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
croak( "optargs initialized, but no option or argument specification for field $field?" ) |
279
|
69
|
50
|
|
|
|
150
|
if !defined $orig_optargs->{spec}; |
280
|
|
|
|
|
|
|
|
281
|
69
|
|
|
|
|
114
|
my $optargs = $orig_optargs->{spec}; |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
# This bit deals with creating the option name and then mapping it back onto the |
284
|
|
|
|
|
|
|
# Form::Tiny blueprint for the form, which may introduce extra layers in the |
285
|
|
|
|
|
|
|
# nested hash if the field name has multiple components. |
286
|
|
|
|
|
|
|
# Special cases arise: |
287
|
|
|
|
|
|
|
# 1) multi-component field name, e.g. 'output.parsed' |
288
|
|
|
|
|
|
|
# 2) options name ne field name, e.g. '--raw-output' ne 'output.raw'. |
289
|
|
|
|
|
|
|
# 3) field name has an underscore, which can get confused |
290
|
|
|
|
|
|
|
# when the options are unflattened, as underscore is |
291
|
|
|
|
|
|
|
# used to indicated nested structures |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
# if @path > 1, then a multi-component name was given to form_field. |
295
|
|
|
|
|
|
|
# Form::Tiny doesn't keep track of sub-forms' parents, so it doesn't know |
296
|
|
|
|
|
|
|
# so we keep track of the entire path via $path. |
297
|
|
|
|
|
|
|
# we only need the last component to get the (leaf) form field name. |
298
|
69
|
|
|
|
|
1089
|
my $field_name = $def->get_name_path->path->[-1]; |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
# this is the fully qualified normalized field name, with |
301
|
|
|
|
|
|
|
# components separated by NUL and will be used create the |
302
|
|
|
|
|
|
|
# correct hierarchy when the options hash is unflattened. |
303
|
69
|
|
|
|
|
607
|
my $fq_field_name = join( chr( 0 ), $path->@*, $field_name ); |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
# generate the fully qualified option name using the |
306
|
|
|
|
|
|
|
# specified field name. the field may specify an |
307
|
|
|
|
|
|
|
# alternate option name, so use that if specified. |
308
|
69
|
|
66
|
|
|
337
|
my $fq_option_name = $optargs->{name} // join( $self->nested_path_sep, $opt_path->@*, $field_name ); |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
# store the mapping between option name and fully |
311
|
|
|
|
|
|
|
# qualified normalized field name. |
312
|
|
|
|
|
|
|
|
313
|
69
|
50
|
|
|
|
191
|
if ( defined( my $old_rename = $rename->{$fq_option_name} ) ) { |
314
|
0
|
|
|
|
|
0
|
croak( "redefined rename of $fq_option_name to $fq_field_name (originally to $old_rename)" ); |
315
|
|
|
|
|
|
|
} |
316
|
69
|
|
|
|
|
241
|
$rename->{$fq_option_name} = $fq_field_name; |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
$optargs->{default} = $def->default->() |
319
|
69
|
100
|
66
|
|
|
223
|
if $optargs->{show_default} && $def->has_default; |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
push @optargs, [ $fq_option_name, $optargs ] |
322
|
69
|
100
|
|
|
|
194
|
if $self->_inherit_optargs( $addons->{package} ); |
323
|
|
|
|
|
|
|
} |
324
|
|
|
|
|
|
|
} |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
## no critic (BuiltinFunctions::RequireSimpleSortBlock) |
327
|
|
|
|
|
|
|
return [ |
328
|
|
|
|
|
|
|
# no order, pass 'em through |
329
|
73
|
|
|
|
|
184
|
( grep { !defined $_->[1]{order} } @optargs ), |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
# order, sort 'em, but complain if multiple arguments with the |
332
|
|
|
|
|
|
|
# same order, as that is not deterministic |
333
|
|
|
|
|
|
|
( |
334
|
|
|
|
|
|
|
sort { |
335
|
2
|
|
|
|
|
8
|
my $order = $a->[1]{order} <=> $b->[1]{order}; |
336
|
2
|
50
|
|
|
|
9
|
croak( "$a->[0] and $b->[0] have the same argument order" ) |
337
|
|
|
|
|
|
|
if $order == 0; |
338
|
|
|
|
|
|
|
$order; |
339
|
|
|
|
|
|
|
} |
340
|
27
|
|
|
|
|
85
|
grep { defined $_->[1]{order} } @optargs |
|
73
|
|
|
|
|
250
|
|
341
|
|
|
|
|
|
|
) ]; |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
|
344
|
34
|
|
|
34
|
|
67
|
sub _add_optarg ( $self, $field, $spec ) { |
|
34
|
|
|
|
|
58
|
|
|
34
|
|
|
|
|
55
|
|
|
34
|
|
|
|
|
64
|
|
|
34
|
|
|
|
|
55
|
|
345
|
34
|
|
50
|
|
|
140
|
my $stash = $field->addons->{ +__PACKAGE__ } //= {}; |
346
|
34
|
|
50
|
|
|
158
|
my $optargs = ( $stash->{optargs} //= {} ); |
347
|
|
|
|
|
|
|
croak( sprintf( 'duplicate definition for field %s', $field->name ) ) |
348
|
34
|
50
|
|
|
|
97
|
if defined $optargs->{spec}; |
349
|
|
|
|
|
|
|
|
350
|
34
|
100
|
66
|
|
|
252
|
$spec->{required} //= !!$field->required |
351
|
|
|
|
|
|
|
if $self->inherit_required; |
352
|
34
|
|
|
|
|
126
|
$optargs->{spec} = $spec; |
353
|
34
|
|
|
|
|
177
|
return; |
354
|
|
|
|
|
|
|
} |
355
|
|
|
|
|
|
|
|
356
|
5
|
|
|
5
|
|
13065
|
use constant OptionTypeEnums => qw( ArrayRef Flag Bool Counter HashRef Int Num Str ); |
|
5
|
|
|
|
|
18
|
|
|
5
|
|
|
|
|
631
|
|
357
|
5
|
|
|
5
|
|
57
|
use constant OptionTypeMap => { map { $_ => "--$_" } OptionTypeEnums }; |
|
5
|
|
|
|
|
12
|
|
|
5
|
|
|
|
|
18
|
|
|
40
|
|
|
|
|
863
|
|
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
use constant OptionType => Enum( [ values OptionTypeMap->%* ] ) |
360
|
5
|
50
|
|
5
|
|
43
|
->plus_coercions( NonEmptySimpleStr, sub { /^--/ ? $_ : "--$_" } ); |
|
5
|
|
|
|
|
12
|
|
|
5
|
|
|
|
|
48
|
|
|
17
|
|
|
|
|
54378
|
|
361
|
|
|
|
|
|
|
|
362
|
5
|
|
|
5
|
|
26339
|
use constant ArgumentTypeEnums => qw( ArrayRef HashRef Int Num Str SubCmd ); |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
357
|
|
363
|
5
|
|
|
5
|
|
34
|
use constant ArgumentType => Enum [ArgumentTypeEnums]; |
|
5
|
|
|
|
|
22
|
|
|
5
|
|
|
|
|
31
|
|
364
|
5
|
|
|
5
|
|
16739
|
use constant ArgumentTypeMap => { map { $_ => $_ } ArgumentTypeEnums() }; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
23
|
|
|
30
|
|
|
|
|
3446
|
|
365
|
|
|
|
|
|
|
|
366
|
15
|
|
|
15
|
|
28
|
sub _resolve_type ( $field, $type_set ) { |
|
15
|
|
|
|
|
26
|
|
|
15
|
|
|
|
|
25
|
|
|
15
|
|
|
|
|
23
|
|
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
# dynamic fields don't have types |
369
|
|
|
|
|
|
|
return undef |
370
|
15
|
50
|
33
|
|
|
140
|
unless defined $field |
|
|
|
33
|
|
|
|
|
371
|
|
|
|
|
|
|
&& $field->isa( 'Form::Tiny::FieldDefinition' ) |
372
|
|
|
|
|
|
|
&& $field->has_type; |
373
|
|
|
|
|
|
|
|
374
|
15
|
|
|
|
|
38
|
my $type = $field->type; |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
# take care of top level Any. Many other types inherit (eventually) from Any, |
377
|
|
|
|
|
|
|
# so the inheritance scan below will resolve types we don't support |
378
|
|
|
|
|
|
|
# if we add Any to OptionTypeMap and ArgumentTypeMap |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
return $type_set->{Str} |
381
|
15
|
100
|
|
|
|
52
|
if index( '|Any|Path|File|Dir|', q{|} . $type->name . q{|} ) != -1; |
382
|
|
|
|
|
|
|
|
383
|
9
|
|
|
|
|
90
|
while ( defined $type ) { |
384
|
15
|
100
|
|
|
|
86
|
return $type_set->{ $type->name } if exists $type_set->{ $type->name }; |
385
|
6
|
|
|
|
|
56
|
$type = $type->parent; |
386
|
|
|
|
|
|
|
} |
387
|
|
|
|
|
|
|
|
388
|
0
|
|
|
|
|
|
return undef; |
389
|
|
|
|
|
|
|
} |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
signature_for _dsl_add_option => ( |
392
|
|
|
|
|
|
|
method => 1, |
393
|
|
|
|
|
|
|
head => 1, # field context |
394
|
|
|
|
|
|
|
bless => !!0, |
395
|
|
|
|
|
|
|
named => [ |
396
|
|
|
|
|
|
|
name => Optional [NonEmptySimpleStr], |
397
|
|
|
|
|
|
|
alias => Optional [NonEmptySimpleStr], |
398
|
|
|
|
|
|
|
comment => NonEmptySimpleStr, |
399
|
|
|
|
|
|
|
default => Optional [ Value | CodeRef ], |
400
|
|
|
|
|
|
|
required => Optional [Bool], |
401
|
|
|
|
|
|
|
hidden => Optional [Bool], |
402
|
|
|
|
|
|
|
isa => Optional [OptionType], |
403
|
|
|
|
|
|
|
isa_name => Optional [NonEmptySimpleStr], |
404
|
|
|
|
|
|
|
show_default => Optional [Bool], |
405
|
|
|
|
|
|
|
trigger => Optional [CodeRef], |
406
|
|
|
|
|
|
|
], |
407
|
|
|
|
|
|
|
); |
408
|
|
|
|
|
|
|
sub _dsl_add_option ( $self, $context, $spec ) { |
409
|
|
|
|
|
|
|
croak( q{The 'option' directive must be used after a field definition} ) |
410
|
|
|
|
|
|
|
if !defined( $context ); |
411
|
|
|
|
|
|
|
my %spec = $spec->%*; |
412
|
|
|
|
|
|
|
$spec{isa} //= _resolve_type( $context, OptionTypeMap ) |
413
|
|
|
|
|
|
|
// croak( sprintf( q{'isa' attribute not specified or resolved for %s}, $context->name ) ); |
414
|
|
|
|
|
|
|
$self->_add_optarg( $context, \%spec ); |
415
|
|
|
|
|
|
|
} |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
signature_for _dsl_add_argument => ( |
418
|
|
|
|
|
|
|
method => 1, |
419
|
|
|
|
|
|
|
head => 1, |
420
|
|
|
|
|
|
|
bless => !!0, |
421
|
|
|
|
|
|
|
named => [ |
422
|
|
|
|
|
|
|
name => Optional [NonEmptySimpleStr], |
423
|
|
|
|
|
|
|
comment => NonEmptySimpleStr, |
424
|
|
|
|
|
|
|
default => Optional [ Value | CodeRef ], |
425
|
|
|
|
|
|
|
greedy => Optional [Bool], |
426
|
|
|
|
|
|
|
fallthru => Optional [Bool], |
427
|
|
|
|
|
|
|
isa => Optional [ArgumentType], |
428
|
|
|
|
|
|
|
isa_name => Optional [NonEmptySimpleStr], |
429
|
|
|
|
|
|
|
required => Optional [Bool], |
430
|
|
|
|
|
|
|
show_default => Optional [Bool], |
431
|
|
|
|
|
|
|
order => Int, |
432
|
|
|
|
|
|
|
], |
433
|
|
|
|
|
|
|
); |
434
|
|
|
|
|
|
|
sub _dsl_add_argument ( $self, $context, $spec ) { |
435
|
|
|
|
|
|
|
croak( q{The 'argument' directive must be used after a field definition} ) |
436
|
|
|
|
|
|
|
if !defined( $context ); |
437
|
|
|
|
|
|
|
my %spec = $spec->%*; |
438
|
|
|
|
|
|
|
$spec{isa} //= _resolve_type( $context, ArgumentTypeMap ) |
439
|
|
|
|
|
|
|
// croak( sprintf( q{'isa' attribute not specified or resolved for %s}, $context->name ) ); |
440
|
|
|
|
|
|
|
$self->_add_optarg( $context, \%spec ); |
441
|
|
|
|
|
|
|
} |
442
|
|
|
|
|
|
|
|
443
|
5
|
|
|
5
|
|
45
|
use constant { INCLUDE => q{+}, EXCLUDE => q{-} }; |
|
5
|
|
|
|
|
14
|
|
|
5
|
|
|
|
|
3254
|
|
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
my sub parse_inherit_matches ( $default, $entries ) { |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
my @matches; |
448
|
|
|
|
|
|
|
my $include = $default; |
449
|
|
|
|
|
|
|
for my $entry ( $entries->@* ) { |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
if ( is_arrayref( $entry ) ) { |
452
|
|
|
|
|
|
|
push @matches, __SUB__->( $include, $entry )->@*; |
453
|
|
|
|
|
|
|
} |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
elsif ( is_regexpref( $entry ) ) { |
456
|
|
|
|
|
|
|
push @matches, [ $include eq INCLUDE, $entry ]; |
457
|
|
|
|
|
|
|
} |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
elsif ( $entry eq EXCLUDE || $entry eq EXCLUDE ) { |
460
|
|
|
|
|
|
|
$include = $entry; |
461
|
|
|
|
|
|
|
next; # avoid reset of $include to default below |
462
|
|
|
|
|
|
|
} |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
# every thing else is a regexp as a string; turn into a regexp |
465
|
|
|
|
|
|
|
else { |
466
|
|
|
|
|
|
|
push @matches, [ $include eq INCLUDE, qr/$entry/ ]; |
467
|
|
|
|
|
|
|
} |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
# reset include to default |
470
|
|
|
|
|
|
|
$include = $default; |
471
|
|
|
|
|
|
|
} |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
return \@matches; |
474
|
|
|
|
|
|
|
} |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
signature_for _dsl_optargs_opts => ( |
478
|
|
|
|
|
|
|
method => 1, |
479
|
|
|
|
|
|
|
head => 1, |
480
|
|
|
|
|
|
|
named => [ |
481
|
|
|
|
|
|
|
inherit_required => Optional [Bool], |
482
|
|
|
|
|
|
|
inherit_optargs => Optional [Bool], |
483
|
|
|
|
|
|
|
inherit_optargs_match => Optional [ArrayRef], |
484
|
|
|
|
|
|
|
nested_path_sep => Optional [Str], |
485
|
|
|
|
|
|
|
], |
486
|
|
|
|
|
|
|
); |
487
|
|
|
|
|
|
|
sub _dsl_optargs_opts ( $self, $context, $args ) { |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
croak( q{The 'optargs_opts' directive must be used before any fields are defined} ) |
490
|
|
|
|
|
|
|
if defined( $context ); |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
$self->_set_inherit_required( $args->inherit_required ) |
493
|
|
|
|
|
|
|
if $args->has_inherit_required; |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
$self->_set_inherit_optargs( $args->inherit_optargs ) |
496
|
|
|
|
|
|
|
if $args->has_inherit_optargs; |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
if ( $args->has_inherit_optargs_match ) { |
499
|
|
|
|
|
|
|
my $match = $args->inherit_optargs_match; |
500
|
|
|
|
|
|
|
$match = [$match] unless is_arrayref( $match ); |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
my $matches = parse_inherit_matches( INCLUDE, $match ); |
503
|
|
|
|
|
|
|
$self->_set_inherit_optargs_match( $matches ); |
504
|
|
|
|
|
|
|
} |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
$self->_set_nested_path_sep( $args->nested_path_sep ) |
507
|
|
|
|
|
|
|
if $args->has_nested_path_sep; |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
} |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
# |
513
|
|
|
|
|
|
|
# This file is part of CXC-Form-Tiny-Plugin-OptArgs2 |
514
|
|
|
|
|
|
|
# |
515
|
|
|
|
|
|
|
# This software is Copyright (c) 2023 by Smithsonian Astrophysical Observatory. |
516
|
|
|
|
|
|
|
# |
517
|
|
|
|
|
|
|
# This is free software, licensed under: |
518
|
|
|
|
|
|
|
# |
519
|
|
|
|
|
|
|
# The GNU General Public License, Version 3, June 2007 |
520
|
|
|
|
|
|
|
# |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
1; |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
__END__ |