File Coverage

blib/lib/Getopt/EX/LabeledParam.pm
Criterion Covered Total %
statement 66 100 66.0
branch 19 34 55.8
condition 1 6 16.6
subroutine 12 17 70.5
pod 4 10 40.0
total 102 167 61.0


line stmt bran cond sub pod time code
1             package Getopt::EX::LabeledParam;
2              
3             our $VERSION = "3.03";
4              
5 9     9   4137 use v5.14;
  9         33  
6 9     9   60 use warnings;
  9         12  
  9         399  
7 9     9   36 use Carp;
  9         29  
  9         648  
8              
9 9     9   48 use Exporter 'import';
  9         13  
  9         725  
10             our @EXPORT = qw();
11             our @EXPORT_OK = qw();
12             our %EXPORT_TAGS = ( all => [ @EXPORT_OK ] );
13              
14 9     9   51 use Data::Dumper;
  9         12  
  9         461  
15 9     9   2339 use Getopt::EX::Module;
  9         17  
  9         398  
16 9     9   41 use Getopt::EX::Func qw(parse_func);
  9         21  
  9         10364  
17              
18             sub new {
19 2     2 1 22 my $class = shift;
20              
21 2         25 my $obj = bless {
22             NEWLABEL => 0,
23             CONCAT => "",
24             HASH => {},
25             LIST => [],
26             RESET => undef,
27             }, $class;
28              
29 2 50       11 $obj->configure(@_) if @_;
30              
31 2         6 $obj;
32             }
33              
34             sub configure {
35 2     2 1 5 my $obj = shift;
36 2         8 while (@_ >= 2) {
37 6         17 my($k, $v) = splice @_, 0, 2;
38 6 50 33     31 if ($k =~ /^\w/ and exists $obj->{$k}) {
39 6         18 $obj->{$k} = $v;
40             }
41             }
42 2         5 $obj;
43             }
44              
45 1     1 0 13 sub get_hash { shift->{HASH} }
46              
47             sub set_hash {
48 0     0 0 0 my $obj = shift;
49 0         0 %{ $obj->{HASH} } = @_;
  0         0  
50 0         0 $obj;
51             }
52              
53 0     0 0 0 sub list { @{ shift->{LIST} } }
  0         0  
54              
55             sub push_list {
56 0     0 0 0 my $obj = shift;
57 0         0 for (@_) {
58 0 0 0     0 if (defined $obj->{RESET} and $_ eq $obj->{RESET}) {
59 0         0 @{ $obj->{LIST} } = ();
  0         0  
60             } else {
61 0         0 push @{ $obj->{LIST} }, $_;
  0         0  
62             }
63             }
64 0         0 $obj;
65             }
66              
67             sub set_list {
68 0     0 0 0 my $obj = shift;
69 0         0 @{ $obj->{LIST} } = @_;
  0         0  
70 0         0 $obj;
71             }
72              
73             sub append {
74 0     0 1 0 my $obj = shift;
75 0         0 for my $item (@_) {
76 0 0       0 if (ref $item eq 'ARRAY') {
    0          
77 0         0 push @{$obj->{LIST}}, @$item;
  0         0  
78             }
79             elsif (ref $item eq 'HASH') {
80 0         0 while (my($k, $v) = each %$item) {
81 0         0 $obj->{HASH}->{$k} = $v;
82             }
83             }
84             else {
85 0         0 push @{$obj->{LIST}}, $item;
  0         0  
86             }
87             }
88             }
89              
90             sub load_params {
91 6     6 1 6074 my $obj = shift;
92              
93 6         27 my $re_field = qr/[\w\*\?]+/;
94             map {
95 11         25 my $spec = pop @$_;
96 11         15 my @spec;
97 11         40 while ($spec =~ s/\&([:\w]+ (?: \( [^)]* \) )? ) ;?//x) { # &func
98 5         34 push @spec, parse_func({ PACKAGE => 'main' }, $1);
99             }
100 11 100       58 if ($spec =~ s/\b(sub\s*{.*)//) { # sub { ... }
101 2         21 push @spec, parse_func({ PACKAGE => 'main' }, $1);
102             }
103 11 100       29 push @spec, $spec if $spec ne '';
104 11 50       32 my $c = @spec > 1 ? [ @spec ] : @spec == 1 ? $spec[0] : "";
    100          
105 11 50       23 if (@$_ == 0) {
106 0         0 $obj->push_list($c);
107             }
108             else {
109             map {
110 22 100       84 if ($c =~ /^\++(.*)/) { # LABEL=+ATTR
    100          
111 9         19 $obj->{HASH}->{$_} .= $obj->{CONCAT} . "$1";
112             }
113             elsif ($c =~ /^\-+(.*)$/i) { # LABEL=-ATTR
114 2         5 my $chars = $1 =~ s/(?=\W)/\\/gr;
115 2         16 $obj->{HASH}->{$_} =~ s/[$chars]+//g;
116             }
117             else {
118 11         58 $obj->{HASH}->{$_} = $c;
119             }
120             }
121             map {
122             # plain label
123 11 100       19 if (not /\W/) {
  11         34  
124 5 50       33 if (exists $obj->{HASH}->{$_}) {
125 5         16 $_;
126             } else {
127 0 0       0 if ($obj->{NEWLABEL}) {
128 0         0 $_;
129             } else {
130 0         0 warn "$_: Unknown label\n";
131 0         0 ();
132             }
133             }
134             }
135             # wild card
136             else {
137 6         6 my @labels = match_glob($_, keys %{$obj->{HASH}});
  6         13  
138 6 50       11 if (@labels == 0) {
139 0         0 warn "$_: Unmatched label\n";
140             }
141 6         13 @labels;
142             }
143             }
144             @$_;
145             }
146             }
147             map {
148 11 50       183 if (my @field = /\G($re_field)=/gp) {
149 11         45 [ @field, ${^POSTMATCH} ];
150             } else {
151 0         0 [ $_ ];
152             }
153             }
154             map {
155 6         16 m/( (?: $re_field= )*
  11         474  
156             (?: .* \b sub \s* \{ .*
157             | (?: \([^)]*\) | [^,\s] )+
158             )
159             )/gx;
160             }
161             @_;
162              
163 6         27 $obj;
164             }
165              
166             sub match_glob {
167 6     6 0 8 local $_ = shift;
168 6         7 s/\?/./g;
169 6         11 s/\*/.*/g;
170 6         46 my $regex = qr/^$_$/;
171 6         11 grep { $_ =~ $regex } @_;
  36         96  
172             }
173              
174             1;
175              
176             =head1 NAME
177              
178             Getopt::EX::LabeledParam - Labeled parameter handling
179              
180              
181             =head1 SYNOPSIS
182              
183             GetOptions('colormap|cm:s' => @opt_colormap);
184              
185             # default values
186             my %colormap = ( FILE => 'DR', LINE => 'Y', TEXT => '' );
187             my @colors = qw( /544 /545 /445 /455 /545 /554 );
188              
189             require Getopt::EX::LabeledParam;
190             my $cmap = Getopt::EX::LabeledParam
191             ->new( NEWLABEL => 0,
192             HASH => \%colormap,
193             LIST => \@colors )
194             ->load_params(@opt_colormap);
195              
196              
197             =head1 DESCRIPTION
198              
199             This module implements the super class of L.
200              
201             Parameters can be given in two ways: one as a labeled table, and one as an
202             indexed list.
203              
204             The handler maintains hash and list objects, and labeled values are stored
205             in the hash, while non-label values are in the list automatically. Users can mix
206             both specifications.
207              
208             When the value field has a special form of a function call, a
209             L object is created and stored for that entry. See the
210             L section in L for more details.
211              
212             =head2 HASH
213              
214             Basically, labeled parameter is defined by B
215              
216             FILE=R
217              
218             Definitions can be connected by commas (C<,>):
219              
220             FILE=R,LINE=G
221              
222             Multiple labels can be set for same value:
223              
224             FILE=LINE=TEXT=R
225              
226             Wildcards C<*> and C can be used in label names, and they match
227             existing hash key names. If labels C and C exist
228             in the hash,
229              
230             *FILE=R
231              
232             and
233              
234             OLD_FILE=NEW_FILE=R
235              
236             produces the same result.
237              
238             If the B part starts with a plus (C<+>) character, it is appended to the
239             current value. At this time, the C string is inserted before the
240             additional string. The default C string is empty, so use the
241             configure method to set it. If the B part starts with a minus (C<->)
242             character, the following characters are deleted from the current value.
243              
244             =head2 LIST
245              
246             If the B
247             stored in the list object. For example,
248              
249             R,G,B,C,M,Y
250              
251             makes six entries in the list. The list object is accessed by index
252             rather than by label.
253              
254             =head1 METHODS
255              
256             =over 4
257              
258             =item B
259              
260             =item B
261              
262             =over 4
263              
264             =item B =E I
265              
266             =item B =E I
267              
268             B and B references can be set by the B or B
269             method. You can provide default settings for the hash and list, and it is
270             usually easier to access those values directly rather than through
271             class methods.
272              
273             =item B =E 0/1
274              
275             By default, B does not create a new entry in the hash table,
276             and absent labels are ignored. Setting the B parameter to true makes
277             it possible to create a new hash entry.
278              
279             =item B =E I
280              
281             Set the concatenation string inserted before appending a string.
282              
283             =item B =E I
284              
285             Set the B mark. Undefined by default. If this reset string is
286             found in a list-type argument, the list is reset to empty.
287              
288             =back
289              
290             =item B I
291              
292             Load the option list into the object.
293              
294             =item B HASHREF or LIST
295              
296             Provides a simple interface to append a colormap hash or color list. If a
297             hash reference is given, all entries of the hash are appended to the
298             colormap. Otherwise, they are appended to the anonymous color list.
299              
300             =back
301              
302             =head1 SEE ALSO
303              
304             L
305              
306             # LocalWords: CONCAT hashref listref NEWLABEL HASHREF colormap