File Coverage

lib/Config/Proxy/Node/Section.pm
Criterion Covered Total %
statement 56 80 70.0
branch 8 12 66.6
condition 0 3 0.0
subroutine 13 17 76.4
pod 11 12 91.6
total 88 124 70.9


line stmt bran cond sub pod time code
1             package Config::Proxy::Node::Section;
2 7     7   3604 use strict;
  7         16  
  7         251  
3 7     7   32 use warnings;
  7         11  
  7         333  
4 7     7   49 use parent 'Config::Proxy::Node';
  7         19  
  7         54  
5 7     7   365 use Carp;
  7         15  
  7         9295  
6              
7             =head1 NAME
8              
9             Config::Proxy::Node::Section - proxy configuration section
10              
11             =head1 DESCRIPTION
12              
13             Objects of this class represent a C
(or a C),
14             in a proxy configuration file. A section is a statement that can contain
15             sub-statements.
16              
17             =cut
18              
19             sub new {
20 65     65 0 841 my $class = shift;
21 65         198 my $self = $class->SUPER::new(@_);
22 65         205 $self->{_tree} = [];
23 65         133 return $self;
24             }
25              
26             =head1 ATTRIBUTES
27              
28             =head2 is_section
29              
30             Always true.
31              
32             =cut
33              
34 256     256 1 736 sub is_section { 1 }
35              
36             =head1 METHODS
37              
38             =head2 kw
39              
40             Returns the configuration keyword.
41              
42             =head2 argv
43              
44             Returns the list of arguments to the configuration keyword.
45              
46             =head2 arg
47              
48             $s = $node->arg($n)
49              
50             Returns the B<$n>th argument.
51              
52             =head2 orig
53              
54             Returns original line as it appeared in the configuration file.
55              
56             =head2 locus
57              
58             Returns the location of this statement in the configuration file (the
59             B object).
60              
61             =head2 append_node
62              
63             $section->append_node(@nodes);
64              
65             Takes a list of objects of B derived classes as
66             arguments. Adds these objects after the last node in the subtree in this
67             section.
68              
69             =cut
70              
71             sub append_node {
72 143     143 1 211 my $self = shift;
73 143         177 my $n = @{$self->{_tree}};
  143         271  
74 143         376 push @{$self->{_tree}},
75             map {
76 143         207 $_->parent($self);
  143         486  
77 143         463 $_->index($n++);
78 143         693 $_
79             } @_;
80             }
81              
82             =head2 append_node_nonempty
83              
84             $section->append_node_nonempty(@nodes);
85              
86             Same as B, but adds new nodes after the last non-empty
87             node in the subtree.
88              
89             =cut
90              
91             sub append_node_nonempty {
92 0     0 1 0 my $self = shift;
93 0         0 my $n = $#{$self->{_tree}};
  0         0  
94 0   0     0 while ($n >= 0 && $self->{_tree}[$n]->is_empty) {
95 0         0 $n--;
96             }
97 0         0 $self->insert_node($n+1, @_);
98             }
99              
100             =head2 insert_node
101              
102             $section->insert_node($idx, @nodes);
103              
104             Inserts B<@nodes> after subnode in position B<$idx> (0-based).
105              
106             =cut
107              
108             sub insert_node {
109 0     0 1 0 my $self = shift;
110 0         0 my $n = shift;
111 0         0 my $i = $n;
112 0         0 splice @{$self->{_tree}}, $n, 0,
113             map {
114 0         0 $_->parent($self);
  0         0  
115 0         0 $_->index($i++);
116 0         0 $_
117             } @_;
118 0         0 for (; $i < @{$self->{_tree}}; $i++) {
  0         0  
119 0         0 $self->{_tree}[$i]->index($i);
120             }
121             }
122              
123             =head2 delete_node
124              
125             $section->delete_node($i);
126              
127             Deletes B<$i>th subnode from the B<$section>.
128              
129             =cut
130              
131             sub delete_node {
132 5     5 1 11 my ($self, $n) = @_;
133 5         7 splice @{$self->{_tree}}, $n, 1;
  5         22  
134 5         9 for (; $n < @{$self->{_tree}}; $n++) {
  5         16  
135 0         0 $self->{_tree}[$n]->index($n);
136             }
137 5         17 $self->root->mark_dirty;
138             }
139              
140             =head2 mark_dirty
141              
142             A dummy method provided so that delete_node doesn't bail out when
143             root is a section (e.g. when removing node from a partially constructed
144             tree).
145              
146             =cut
147              
148       5 1   sub mark_dirty {
149             }
150              
151             =head2 tree
152              
153             @nodes = $section->tree;
154              
155             Returns subnodes as a list of B derived objects.
156              
157             $node = $section->tree($i);
158              
159             Returns B<$i>th subnode from the B<$section>. Use negative $i to
160             index array from its end, e.g.
161              
162             $section->tree(-1)
163              
164             returns last element.
165              
166             =cut
167              
168             sub tree {
169 170     170 1 316 my ($self, $n) = @_;
170 170 100       363 if (defined($n)) {
171 83 50       164 if ($n < 0) {
172 83         101 $n += @{$self->{_tree}};
  83         197  
173             }
174 83 50       121 return undef if $n >= @{$self->{_tree}};
  83         179  
175 83         248 return $self->{_tree}[$n];
176             }
177 87         108 return @{shift->{_tree}}
  87         435  
178             };
179              
180             =head2 first
181              
182             $node = $section->first;
183              
184             Returns first node from the section. It is a shortcut for
185              
186             $section->tree(0)
187              
188             =cut
189              
190             sub first {
191 0     0 1 0 my ($self) = @_;
192 0         0 return $self->tree(0)
193             }
194              
195             =head2 last
196              
197             $node = $section->last
198              
199             Returns last node from the section. It is a shortcut for
200              
201             $section->tree(-1)
202              
203             =cut
204              
205             sub last {
206 81     81 1 134 my ($self) = @_;
207 81         167 return $self->tree(-1)
208             }
209              
210             =head2 ends_in_empty
211              
212             $bool = $section->ends_in_empty
213              
214             Returns true if the last node in the list of sub-nodes in B<$section> is
215             an empty node.
216              
217             =cut
218              
219             sub ends_in_empty {
220 0     0 1 0 my $self = shift;
221 0         0 while ($self->is_section) {
222 0         0 $self = $self->tree(-1);
223             }
224 0         0 return $self->is_empty;
225             }
226            
227             my %match = (
228             name => sub {
229             my ($node, $value) = @_;
230             return $node->kw && $node->kw eq $value;
231             },
232             name_ci => sub {
233             my ($node, $value) = @_;
234             return $node->kw && lc($node->kw) eq lc($value);
235             },
236             arg => sub {
237             my ($node, $value) = @_;
238             my $arg = $node->arg($value->{n});
239             return $arg && $arg eq $value->{v};
240             },
241             section => sub {
242             my $node = shift;
243             return $node->is_section;
244             },
245             statement => sub {
246             my $node = shift;
247             return $node->is_statement;
248             },
249             comment => sub {
250             my $node = shift;
251             return $node->is_comment;
252             },
253             is => sub {
254             my ($node, $value) = @_;
255             return ref($node) eq $value;
256             },
257             code => sub {
258             my ($node, $value) = @_;
259             return &{$value}($node);
260             }
261             );
262              
263             =head2 select
264              
265             @nodes = $section->select(%cond);
266              
267             Returns nodes from B<$section> that match conditions in B<%cond>. Valid
268             conditions are:
269              
270             =over 4
271              
272             =item B> I<$s>
273              
274             Node matches if its keyword (B) equals I<$s>.
275              
276             =item B> I<$s>
277              
278             Same as B, but strict comparison is case-insensitive.
279              
280             =item B> B<{ n =E> I<$n>, B =E I<$s> B<}>
281              
282             Node matches if its I<$n>th argument equals I<$s>.
283              
284             =item B
> I<$bool>
285              
286             Node matches if it is (or is not, if I<$bool> is false) a section.
287              
288             =item B> I<$bool>
289              
290             Node matches if it is (not) a simple statement.
291              
292             =item B> I<$bool>
293              
294             Node matches if it is (not) a comment.
295              
296             =item B> I<$class>
297              
298             Node matches if it is of the given class, i.e. B.
299              
300             =item B $func>
301              
302             Node matches if the function B<$func> returns true. The function is
303             called with B<$node> as its argument.
304              
305             =back
306              
307             Multiple conditions are checked in the order of their appearance in the
308             argument list and are joined by the short-circuit logical C.
309              
310             For example, to return all B statements from a HAProxy
311             configuration:
312              
313             @fe = $section->select(name => 'frontend');
314              
315             To return the frontend named C:
316              
317             ($fe) = $section->select( name => 'frontend',
318             arg => { n => 0, v => 'in' } );
319              
320             =cut
321              
322             sub select {
323 7     7 1 15 my $self = shift;
324 7         13 my @prog;
325 7         28 while (my $p = shift) {
326 9 50       54 my $arg = shift or croak "missing argument";
327 9 50       31 my $m = $match{$p} or croak "unknown matcher: $p";
328 9         41 push @prog, [ $m, $arg ];
329             }
330 7         28 grep { _test_node($_, @prog) } $self->tree;
  27         51  
331             }
332              
333             sub _test_node {
334 27     27   69 my $node = shift;
335 27         216 foreach my $f (@_) {
336 31 100       51 return 0 unless &{$f->[0]}($node, $f->[1]);
  31         53  
337             }
338 8         30 return 1;
339             }
340              
341             =head1 SEE ALSO
342              
343             L, L, L.
344              
345             =cut
346              
347             1;