| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Getopt::EX::Func; |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
our $VERSION = "3.03"; |
|
4
|
|
|
|
|
|
|
|
|
5
|
10
|
|
|
10
|
|
119673
|
use v5.14; |
|
|
10
|
|
|
|
|
32
|
|
|
6
|
10
|
|
|
10
|
|
44
|
use warnings; |
|
|
10
|
|
|
|
|
17
|
|
|
|
10
|
|
|
|
|
435
|
|
|
7
|
10
|
|
|
10
|
|
43
|
use Carp; |
|
|
10
|
|
|
|
|
16
|
|
|
|
10
|
|
|
|
|
646
|
|
|
8
|
|
|
|
|
|
|
|
|
9
|
10
|
|
|
10
|
|
41
|
use Exporter 'import'; |
|
|
10
|
|
|
|
|
25
|
|
|
|
10
|
|
|
|
|
880
|
|
|
10
|
|
|
|
|
|
|
our @EXPORT = qw(); |
|
11
|
|
|
|
|
|
|
our @EXPORT_OK = qw(parse_func callable arg2kvlist); |
|
12
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( all => [ @EXPORT_OK ] ); |
|
13
|
|
|
|
|
|
|
|
|
14
|
10
|
|
|
10
|
|
49
|
use Data::Dumper; |
|
|
10
|
|
|
|
|
15
|
|
|
|
10
|
|
|
|
|
480
|
|
|
15
|
|
|
|
|
|
|
|
|
16
|
10
|
|
|
10
|
|
48
|
use Scalar::Util qw(blessed); |
|
|
10
|
|
|
|
|
35
|
|
|
|
10
|
|
|
|
|
1885
|
|
|
17
|
|
|
|
|
|
|
sub callable { |
|
18
|
0
|
|
|
0
|
0
|
0
|
my $target = shift; |
|
19
|
0
|
0
|
|
|
|
0
|
blessed $target and $target->can('call'); |
|
20
|
|
|
|
|
|
|
} |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
sub new { |
|
23
|
8
|
|
|
8
|
0
|
15
|
my $class = shift; |
|
24
|
8
|
|
|
|
|
95
|
my $obj = bless [ @_ ], $class; |
|
25
|
|
|
|
|
|
|
} |
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
sub append { |
|
28
|
0
|
|
|
0
|
0
|
0
|
my $obj = shift; |
|
29
|
0
|
|
|
|
|
0
|
push @$obj, @_; |
|
30
|
|
|
|
|
|
|
} |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
sub call { |
|
33
|
8
|
|
|
8
|
0
|
161
|
my $obj = shift; |
|
34
|
8
|
|
|
|
|
21
|
unshift @_, @$obj; |
|
35
|
8
|
|
|
|
|
15
|
my $name = shift; |
|
36
|
|
|
|
|
|
|
|
|
37
|
10
|
|
|
10
|
|
71
|
no strict 'refs'; |
|
|
10
|
|
|
|
|
17
|
|
|
|
10
|
|
|
|
|
1008
|
|
|
38
|
8
|
|
|
|
|
106
|
goto &$name; |
|
39
|
|
|
|
|
|
|
} |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
## |
|
42
|
|
|
|
|
|
|
## Create a closure that calls the named function with preset arguments. |
|
43
|
|
|
|
|
|
|
## Used internally when parse_func is called with the 'pointer' option. |
|
44
|
|
|
|
|
|
|
## The 'package main' may be unnecessary since $name is fully qualified, |
|
45
|
|
|
|
|
|
|
## but is kept for safety in case of future changes. |
|
46
|
|
|
|
|
|
|
## |
|
47
|
|
|
|
|
|
|
sub closure { |
|
48
|
0
|
|
|
0
|
0
|
0
|
my $name = shift; |
|
49
|
0
|
|
|
|
|
0
|
my @argv = @_; |
|
50
|
|
|
|
|
|
|
sub { |
|
51
|
|
|
|
|
|
|
package main; |
|
52
|
10
|
|
|
10
|
|
66
|
no strict 'refs'; |
|
|
10
|
|
|
|
|
16
|
|
|
|
10
|
|
|
|
|
7084
|
|
|
53
|
0
|
|
|
0
|
|
0
|
unshift @_, @argv; |
|
54
|
0
|
|
|
|
|
0
|
goto &$name; |
|
55
|
|
|
|
|
|
|
} |
|
56
|
0
|
|
|
|
|
0
|
} |
|
57
|
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
## |
|
59
|
|
|
|
|
|
|
## sub { ... } |
|
60
|
|
|
|
|
|
|
## funcname(arg1,arg2,arg3=val3) |
|
61
|
|
|
|
|
|
|
## funcname=arg1,arg2,arg3=val3 |
|
62
|
|
|
|
|
|
|
## |
|
63
|
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
## |
|
65
|
|
|
|
|
|
|
## Regex to match balanced parentheses, including nested ones. |
|
66
|
|
|
|
|
|
|
## Uses recursive subpattern (?-1) to match inner parentheses. |
|
67
|
|
|
|
|
|
|
## Possessive quantifiers (++ and *+) prevent backtracking for efficiency. |
|
68
|
|
|
|
|
|
|
## |
|
69
|
|
|
|
|
|
|
my $paren_re = qr/( \( (?: [^()]++ | (?-1) )*+ \) )/x; |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
## |
|
72
|
|
|
|
|
|
|
## Key name pattern for function arguments. |
|
73
|
|
|
|
|
|
|
## Should be \w+ but currently allows more characters for historical reasons. |
|
74
|
|
|
|
|
|
|
## |
|
75
|
|
|
|
|
|
|
my $key_re = qr/[^,=*\/]+/; |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
sub parse_func { |
|
78
|
8
|
100
|
|
8
|
0
|
31
|
my $opt = ref $_[0] eq 'HASH' ? shift : {}; |
|
79
|
8
|
|
|
|
|
46
|
local $_ = shift; |
|
80
|
8
|
|
|
|
|
20
|
my $noinline = $opt->{noinline}; |
|
81
|
8
|
|
|
|
|
14
|
my $pointer = $opt->{pointer}; |
|
82
|
8
|
|
|
|
|
23
|
my $caller = caller; |
|
83
|
8
|
|
66
|
|
|
24
|
my $pkg = $opt->{PACKAGE} || $caller; |
|
84
|
|
|
|
|
|
|
|
|
85
|
8
|
|
|
|
|
16
|
my @func; |
|
86
|
|
|
|
|
|
|
|
|
87
|
8
|
100
|
66
|
|
|
528
|
if (not $noinline and /^sub\s*{/) { |
|
|
|
50
|
|
|
|
|
|
|
88
|
2
|
|
|
|
|
256
|
my $sub = eval "package $pkg; $_"; |
|
89
|
2
|
50
|
|
|
|
10
|
if ($@) { |
|
90
|
0
|
|
|
|
|
0
|
warn "Error in function -- $_ --.\n"; |
|
91
|
0
|
|
|
|
|
0
|
die $@; |
|
92
|
|
|
|
|
|
|
} |
|
93
|
2
|
50
|
|
|
|
8
|
croak "Unexpected result from eval.\n" if ref $sub ne 'CODE'; |
|
94
|
2
|
|
|
|
|
8
|
@func = ($sub); |
|
95
|
|
|
|
|
|
|
} |
|
96
|
|
|
|
|
|
|
elsif (m{^ &? (? [\w:]+ ) (? $paren_re | =.* )? $}x) { |
|
97
|
6
|
|
|
|
|
78
|
my $name = $+{name}; |
|
98
|
6
|
|
50
|
|
|
44
|
my $arg = $+{arg} // ''; |
|
99
|
6
|
|
|
|
|
15
|
$arg =~ s/^ (?| \( (.*) \) | = (.*) ) $/$1/x; |
|
100
|
6
|
100
|
|
|
|
39
|
$name =~ s/^/$pkg\::/ unless $name =~ /::/; |
|
101
|
6
|
|
|
|
|
21
|
@func = ($name, arg2kvlist($arg)); |
|
102
|
|
|
|
|
|
|
} |
|
103
|
|
|
|
|
|
|
else { |
|
104
|
0
|
|
|
|
|
0
|
return undef; |
|
105
|
|
|
|
|
|
|
} |
|
106
|
|
|
|
|
|
|
|
|
107
|
8
|
50
|
|
|
|
49
|
__PACKAGE__->new( $pointer ? closure(@func) : @func ); |
|
108
|
|
|
|
|
|
|
} |
|
109
|
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
## |
|
111
|
|
|
|
|
|
|
## convert "key1,key2,key3=val3" to (key1=>1, key2=>1, key3=>"val3") |
|
112
|
|
|
|
|
|
|
## |
|
113
|
|
|
|
|
|
|
## *= takes the rest of the string as a value |
|
114
|
|
|
|
|
|
|
## e.g., "key1,key2*=a,b,c" => (key1=>1, key2=>"a,b,c") |
|
115
|
|
|
|
|
|
|
## |
|
116
|
|
|
|
|
|
|
## /= uses the next character as a delimiter |
|
117
|
|
|
|
|
|
|
## e.g., "key1,key2/=/a,b,c/,next" => (key1=>1, key2=>"a,b,c", next=>1) |
|
118
|
|
|
|
|
|
|
## |
|
119
|
|
|
|
|
|
|
sub arg2kvlist { |
|
120
|
24
|
|
|
24
|
0
|
175821
|
my @kv; |
|
121
|
24
|
|
|
|
|
44
|
for (@_) { |
|
122
|
24
|
|
|
|
|
594
|
while (/\G \s* (?(?>${key_re})) |
|
123
|
|
|
|
|
|
|
(?: \*= (?.*) |
|
124
|
|
|
|
|
|
|
| \/= (?.) (?.*?) \g{delim} (?=,|\z) ,* |
|
125
|
|
|
|
|
|
|
| (?: = (? (?:[^,()]++ | ${paren_re})*+ ) )? ,* ) |
|
126
|
|
|
|
|
|
|
/xgcs) { |
|
127
|
34
|
|
100
|
|
|
320
|
push @kv, ( $+{key}, $+{value} // 1 ); |
|
128
|
|
|
|
|
|
|
} |
|
129
|
24
|
50
|
100
|
|
|
87
|
(pos() // 0) == length or die "parse error in \"$_\".\n"; |
|
130
|
|
|
|
|
|
|
} |
|
131
|
24
|
|
|
|
|
123
|
@kv; |
|
132
|
|
|
|
|
|
|
} |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
1; |
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
=head1 NAME |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
Getopt::EX::Func - Function call interface |
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
use Getopt::EX::Func qw(parse_func); |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
my $func = parse_func("func_name(key=value,flag)"); |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
$func->call; |
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
150
|
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
This module provides a way to create function call objects used in the |
|
152
|
|
|
|
|
|
|
L module set. |
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
For example, suppose your script has a B<--begin> option that |
|
155
|
|
|
|
|
|
|
specifies a function to call at the beginning of execution. You can |
|
156
|
|
|
|
|
|
|
implement it like this: |
|
157
|
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
use Getopt::EX::Func qw(parse_func); |
|
159
|
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
GetOptions("begin:s" => \$opt_begin); |
|
161
|
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
my $func = parse_func($opt_begin); |
|
163
|
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
$func->call; |
|
165
|
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
The user can then invoke the script as: |
|
167
|
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
% example -Mfoo --begin 'repeat(debug,msg=hello,count=2)' |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
The function C should be declared in module C or in a |
|
171
|
|
|
|
|
|
|
startup rc file such as F<~/.examplerc>. It can be implemented like |
|
172
|
|
|
|
|
|
|
this: |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
our @EXPORT = qw(repeat); |
|
175
|
|
|
|
|
|
|
sub repeat { |
|
176
|
|
|
|
|
|
|
my %opt = @_; |
|
177
|
|
|
|
|
|
|
print Dumper \%opt if $opt{debug}; |
|
178
|
|
|
|
|
|
|
say $opt{msg} for 1 .. $opt{count}; |
|
179
|
|
|
|
|
|
|
} |
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
=head1 FUNCTION SPEC |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
The C function accepts the following string formats. |
|
184
|
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
A function name can optionally be prefixed with C<&>, and parameters |
|
186
|
|
|
|
|
|
|
can be specified in two equivalent forms using parentheses or C<=>: |
|
187
|
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
func(key=value,key2=value2) |
|
189
|
|
|
|
|
|
|
func=key=value,key2=value2 |
|
190
|
|
|
|
|
|
|
&func(key=value) |
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
So the following two commands are equivalent: |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
% example --begin 'repeat(debug,msg=hello,count=2)' |
|
195
|
|
|
|
|
|
|
% example --begin 'repeat=debug,msg=hello,count=2' |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
Both will call the function as: |
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
repeat( debug => 1, msg => 'hello', count => '2' ); |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
Arguments are passed as I =E I pairs. Parameters |
|
202
|
|
|
|
|
|
|
without a value (C in this example) are assigned the value 1. |
|
203
|
|
|
|
|
|
|
Key names should only contain word characters (C<\w>: alphanumeric and |
|
204
|
|
|
|
|
|
|
underscore). Currently, any characters except C<,>, C<=>, C<*>, and |
|
205
|
|
|
|
|
|
|
C> are accepted for historical reasons, but this may change in the |
|
206
|
|
|
|
|
|
|
future. |
|
207
|
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
Commas normally separate parameters. If a value needs to contain |
|
209
|
|
|
|
|
|
|
commas, there are two ways to handle this: |
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
=over 4 |
|
212
|
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
=item Parentheses |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
Commas inside parentheses are preserved: |
|
216
|
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
func(pattern=(a,b,c),debug) |
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
This calls: |
|
220
|
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
func( pattern => '(a,b,c)', debug => 1 ); |
|
222
|
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
Note that the parentheses are included in the value. |
|
224
|
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
=item Asterisk-Equals |
|
226
|
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
Use C<*=> instead of C<=> to capture the entire remaining string as |
|
228
|
|
|
|
|
|
|
the value: |
|
229
|
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
func(debug,pattern*=a,b,c) |
|
231
|
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
This calls: |
|
233
|
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
func( debug => 1, pattern => 'a,b,c' ); |
|
235
|
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
Since C<*=> consumes the rest of the string, no parameters can follow |
|
237
|
|
|
|
|
|
|
it. |
|
238
|
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
=item Slash-Equals with Delimiter |
|
240
|
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
Use C=> followed by a delimiter character to quote a value. The |
|
242
|
|
|
|
|
|
|
first character after C=> becomes the delimiter, and the value |
|
243
|
|
|
|
|
|
|
continues until the same delimiter appears again: |
|
244
|
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
func(debug,pattern/=/a,b,c/,verbose) |
|
246
|
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
This calls: |
|
248
|
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
func( debug => 1, pattern => 'a,b,c', verbose => 1 ); |
|
250
|
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
The delimiter can be any character. Choose one that does not appear |
|
252
|
|
|
|
|
|
|
in the value: |
|
253
|
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
func(pattern/=/a,b,c/) # / as delimiter |
|
255
|
|
|
|
|
|
|
func(path/=|/usr/local/bin|) # | as delimiter for paths |
|
256
|
|
|
|
|
|
|
func(text/=:hello:world:) # : as delimiter |
|
257
|
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
For scripting, control characters like BEL (C<\x07>) or US (C<\x1f>, |
|
259
|
|
|
|
|
|
|
Unit Separator) can be used as delimiters to avoid conflicts with any |
|
260
|
|
|
|
|
|
|
printable characters: |
|
261
|
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
$delim = "\x07"; # BEL |
|
263
|
|
|
|
|
|
|
$delim = "\x1f"; # US (Unit Separator) |
|
264
|
|
|
|
|
|
|
$arg = "data/=${delim}any/chars=here,${delim}"; |
|
265
|
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
=back |
|
267
|
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
An anonymous subroutine can also be specified inline: |
|
269
|
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
% example --begin 'sub{ say "wahoo!!" }' |
|
271
|
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
The function is evaluated under C |
|
273
|
|
|
|
|
|
|
are available. |