← Index
NYTProf Performance Profile   « line view »
For ./view
  Run on Fri Jul 31 18:42:36 2015
Reported on Fri Jul 31 18:48:14 2015

Filename/var/www/foswikidev/core/lib/Foswiki/Configure/Item.pm
StatementsExecuted 9 statements in 1.39ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
11112µs24µsFoswiki::Configure::Item::::BEGIN@27Foswiki::Configure::Item::BEGIN@27
1118µs12µsFoswiki::Configure::Item::::BEGIN@28Foswiki::Configure::Item::BEGIN@28
1118µs46µsFoswiki::Configure::Item::::BEGIN@33Foswiki::Configure::Item::BEGIN@33
1114µs4µsFoswiki::Configure::Item::::BEGIN@30Foswiki::Configure::Item::BEGIN@30
0000s0sFoswiki::Configure::Item::::DESTROYFoswiki::Configure::Item::DESTROY
0000s0sFoswiki::Configure::Item::::TO_JSONFoswiki::Configure::Item::TO_JSON
0000s0sFoswiki::Configure::Item::::_matchesFoswiki::Configure::Item::_matches
0000s0sFoswiki::Configure::Item::::_parseOptionsFoswiki::Configure::Item::_parseOptions
0000s0sFoswiki::Configure::Item::::appendFoswiki::Configure::Item::append
0000s0sFoswiki::Configure::Item::::clearFoswiki::Configure::Item::clear
0000s0sFoswiki::Configure::Item::::findFoswiki::Configure::Item::find
0000s0sFoswiki::Configure::Item::::find_also_dependenciesFoswiki::Configure::Item::find_also_dependencies
0000s0sFoswiki::Configure::Item::::getAllValueKeysFoswiki::Configure::Item::getAllValueKeys
0000s0sFoswiki::Configure::Item::::getPathFoswiki::Configure::Item::getPath
0000s0sFoswiki::Configure::Item::::getSectionObjectFoswiki::Configure::Item::getSectionObject
0000s0sFoswiki::Configure::Item::::getValueObjectFoswiki::Configure::Item::getValueObject
0000s0sFoswiki::Configure::Item::::hasDeepFoswiki::Configure::Item::hasDeep
0000s0sFoswiki::Configure::Item::::newFoswiki::Configure::Item::new
0000s0sFoswiki::Configure::Item::::parseTypeParamsFoswiki::Configure::Item::parseTypeParams
0000s0sFoswiki::Configure::Item::::promoteSettingFoswiki::Configure::Item::promoteSetting
0000s0sFoswiki::Configure::Item::::pruneFoswiki::Configure::Item::prune
0000s0sFoswiki::Configure::Item::::searchFoswiki::Configure::Item::search
0000s0sFoswiki::Configure::Item::::setFoswiki::Configure::Item::set
0000s0sFoswiki::Configure::Item::::stringifyFoswiki::Configure::Item::stringify
0000s0sFoswiki::Configure::Item::::unparentFoswiki::Configure::Item::unparent
0000s0sFoswiki::Configure::Item::::visitFoswiki::Configure::Item::visit
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1# See bottom of file for license and copyright information
2
3=begin TML
4
5---++ package Foswiki::Configure::Item
6
7Abstract base class of all nodes in a configuration spec tree.
8Item is the base class for all of Section (collection) Value (an
9individual value).
10
11Objects of this class are intended to form a tree with references in
12both directions, circular references ahead.
13
14IMPORTANT: there are some naming conventions for fields that apply to
15all subclasses of this class:
16 * All internal attributes of this class are named [a-z][a-z_]*
17 i.e. lowercase alphabetic
18 * All internal attributes *that must not be serialised* (such as
19 tree pointers) are named _[a-z][a-z_]* i.e. with a
20 leading underscore.
21 * All attributes read dynamically from the .spec must be [A-Z][A-Z_]+
22
23=cut
24
25package Foswiki::Configure::Item;
26
27226µs236µs
# spent 24µs (12+12) within Foswiki::Configure::Item::BEGIN@27 which was called: # once (12µs+12µs) by Foswiki::Configure::Section::BEGIN@19 at line 27
use strict;
# spent 24µs making 1 call to Foswiki::Configure::Item::BEGIN@27 # spent 12µs making 1 call to strict::import
28224µs216µs
# spent 12µs (8+4) within Foswiki::Configure::Item::BEGIN@28 which was called: # once (8µs+4µs) by Foswiki::Configure::Section::BEGIN@19 at line 28
use warnings;
# spent 12µs making 1 call to Foswiki::Configure::Item::BEGIN@28 # spent 4µs making 1 call to warnings::import
29
30231µs14µs
# spent 4µs within Foswiki::Configure::Item::BEGIN@30 which was called: # once (4µs+0s) by Foswiki::Configure::Section::BEGIN@19 at line 30
use Foswiki::Configure::LoadSpec ();
# spent 4µs making 1 call to Foswiki::Configure::Item::BEGIN@30
31
32# Schema for dynamic attributes
3321.30ms284µs
# spent 46µs (8+38) within Foswiki::Configure::Item::BEGIN@33 which was called: # once (8µs+38µs) by Foswiki::Configure::Section::BEGIN@19 at line 33
use constant ATTRSPEC => {};
# spent 46µs making 1 call to Foswiki::Configure::Item::BEGIN@33 # spent 38µs making 1 call to constant::import
34
35sub new {
36 my ( $class, @opts ) = @_;
37
38 my $this = bless(
39 {
40 _parent => undef,
41 depth => 0,
42
43 # Serialisable attribtes
44 desc => '',
45 defined_at => undef # where it is defined [ "file", line ]
46 },
47 $class
48 );
49
50 $this->set(@opts);
51
52 return $this;
53}
54
55sub stringify {
56 my $this = shift;
57 my $s = Data::Dumper->Dump( [ $this->TO_JSON() ] );
58 $s =~ s/^.*?= //;
59 return $s;
60}
61
62sub DESTROY {
63 my $this = shift;
64
65 # Clear dynamic attributes
66 foreach my $field ( keys %{ $this->{ATTRSPEC} } ) {
67 undef $this->{$field};
68 }
69
70 # Undef unserialisable internals
71 map { undef $this->{$_} } grep { /^__/ } keys %$this;
72}
73
74=begin TML
75
76---++ ObjectMethod set(@what) / set(%what)
77 * =@what= array of key-value pairs for attributes to set e.g.
78 set(typename=> 'BLAH'). The array may be interpreted as a hash,
79 so must be even-sized.
80Add options. The default implementation supports setting keys directly,
81and also supports a special 'opts' key, which defines a string that is
82parsed according to the .spec standard for options.
83Subclasses define ATTRSPEC to declare attribute types valid for the
84entity, used while parsing this string.
85
86Note that all internal fields of this class use a leading underscore
87naming convention, while all dynamically-read attributes are all
88upper case with no leading underscore.
89
90Note that the global $RAW_VALS=1 will
91supress calling of the parsers responsible to expanding attribute
92values.
93
94When the same option is set twice in the parameters, the *second*
95value will take precedence. This allows the caller to declare defaults
96early in the list before appending options from other sources.
97
98=cut
99
100sub set {
101 my ( $this, @params ) = @_;
102
103 while ( my $k = shift(@params) ) {
104 die "Uneven sized options hash " . join( ' ', caller )
105 unless scalar(@params);
106 my $v = shift @params;
107 if ( $k eq 'opts' ) {
108 $this->_parseOptions($v);
109 }
110 else {
111 $this->{$k} = $v;
112 }
113 }
114}
115
116# Implemented by subclasses to perform type-specific attribute parsing
117sub parseTypeParams {
118 my ( $this, $str ) = @_;
119 return $str;
120}
121
122sub _parseOptions {
123 my ( $this, $str, %controls ) = @_;
124
125 # Parcel out defaults
126 while ( my ( $attr, $spec ) = each %{ $this->ATTRSPEC } ) {
127 next unless ref($spec);
128 if ( !defined $this->{$attr} && defined $spec->{default} ) {
129 if ( ref $spec->{default} eq 'ARRAY' ) {
130 @{ $this->{$attr} } = @{ $spec->{default} };
131 }
132 elsif ( ref $spec->{default} eq 'HASH' ) {
133 %{ $this->{$attr} } = %{ $spec->{default} };
134 }
135 else {
136 $this->{$attr} = $spec->{default};
137 }
138 }
139 }
140
141 # A couple of special cases, specific to Values
142 $str = $this->parseTypeParams($str);
143
144 # Parse the options
145 while ( $str =~ s/^\s*([A-Za-z0-9_]+)// ) {
146
147 my $key = $1;
148 my $spec = $this->ATTRSPEC;
149 my $remove = 0;
150 if ( $key =~ s/^NO// ) {
151 $remove = 1;
152 }
153 if ( $spec && defined $spec->{$key} && !ref( $spec->{$key} ) ) {
154
155 # Rename single-character keys
156 $key = $spec->{$key};
157 }
158 $spec = $spec->{$key};
159
160 die "Bad option '$key' in .spec before $str" unless $spec;
161 my $val;
162 if ( $str =~ s/^\s*=// ) {
163 if ( $str =~ s/^\s*(["'])(.*?[^\\])\1// ) {
164
165 # =string
166 $val = $2;
167 }
168 elsif ( $str =~ s/^\s*([A-Z0-9]+)// ) {
169
170 # =keyword or number
171 $val = $1;
172 }
173 else {
174 die "Parse error when reading .spec options at $key=$str";
175 }
176 }
177 elsif ( $spec->{openclose} ) {
178 $str =~ s/^(.*?)(\/$key|$)//;
179 $val = $1;
180 }
181 else {
182 $val = 1;
183 }
184 if ($remove) {
185 delete $this->{$key};
186 $val = undef;
187 }
188
189 if ( defined $spec->{handler}
190 && !$Foswiki::Configure::LoadSpec::RAW_VALS )
191 {
192 my $fn = $spec->{handler};
193 $this->{key} = $this->$fn( $val, $key );
194 }
195 else {
196 $this->{$key} = $val;
197 }
198 }
199 die "Parse failed at $str" unless $str =~ m/^\s*$/;
200}
201
202=begin TML
203
204---++ ObjectMethod clear(%what)
205Delete attributes set by =set=.
206
207=cut
208
209sub clear {
210 my $this = shift;
211 return unless (@_);
212
213 delete @{$this}{@_};
214}
215
216=begin TML
217
218---++ ObjectMethod append($key, $str)
219
220Concatenate $str to the string value of $key.
221
222=cut
223
224sub append {
225 my ( $this, $key, $str ) = @_;
226
227 if ( $this->{$key} ) {
228 $this->{$key} .= "\n$str";
229 }
230 else {
231 $this->{$key} .= $str;
232 }
233}
234
235=begin TML
236
237---++ ObjectMethod hasDeep($attrname) -> $boolean
238
239Determine if this item (or any sub-item if this is a collection)
240has the given boolean attribute
241
242=cut
243
244sub hasDeep {
245 my ( $this, $attrname ) = @_;
246 return $this->{$attrname};
247}
248
249=begin TML
250
251---++ ObjectMethod getAllValueKeys() -> @list
252
253Return a list of all the keys for value objects under this node.
254
255=cut
256
257sub getAllValueKeys {
258 my $this = shift;
259
260 return ();
261}
262
263=begin TML
264
265---++ ObjectMethod find_also_dependencies([$root])
266
267Find 'also' dependencies by scanning values.
268
269'also' dependencies are checker dependencies that are inferred from the
270values of DISPLAY_IF and ENABLE_IF attributes. Some 'also' dependencies
271may 'also' be explicitly declared in the CHECK clause of an item.
272
273'also' dependencies are used to trigger checks of other items when the
274value of an item they depend on changes.
275
276 * =$root= - root used to getValueObject for keys found
277
278=cut
279
280sub find_also_dependencies {
281 my ( $this, $root ) = @_;
282 die 'Subclasses must define this method';
283}
284
285=begin TML
286
287---++ ObjectMethod getPath() -> @list
288
289Get the path down to a configuration item. The path is a list of
290titles (headlines and keys).
291
292=cut
293
294sub getPath {
295 my $this = shift;
296 my @path = ();
297
298 if ( $this->{_parent} ) {
299 @path = $this->{_parent}->getPath();
300 push( @path, $this->{_parent}->{headline} )
301 if $this->{_parent}->{headline};
302 }
303 return @path;
304}
305
306=begin TML
307
308---++ ObjectMethod unparent()
309
310Unparent a configuration item. This only clears the parent of the node,
311it does not remove the node from the parent. After removing parents
312only the top-down structure remains, and methods that use the parent,
313such as getPath, will not work any more, so use with great caution.
314
315The main purpose of this method is to prepare a spec node for isolated
316use (e.g. serialisation).
317
318=cut
319
320sub unparent {
321 my $this = shift;
322 delete $this->{_parent};
323 delete $this->{_vobCache};
324}
325
326=begin TML
327
328---++ ObjectMethod prune($depth)
329
330Prunes the subtree under $this to a maximum depth of $depth, discarding
331children under that point.
332
333$depth = 0 will prune immediate children
334$depth = 1 will prune children-of-children
335
336etc.
337
338=cut
339
340sub prune {
341 my ( $this, $depth ) = @_;
342
343 # NOP
344}
345
346=begin TML
347
348---++ ObjectMethod getSectionObject($head, $depth) -> $item
349
350This gets the section object that has the heading $head and
351$this->{depth} == $depth below this item. If $depth is not given,
352will return the first headline that matches.
353
354Subclasses must provide an implementation.
355
356=cut
357
358sub getSectionObject {
359 die 'Subclasses must define this method';
360}
361
362=begin TML
363
364---++ find(%search) -> @result
365
366Find the first item that matches the search keys given in %search.
367For example, find(keys => '{Keys}') or find(headline => 'Section').
368Searches recursively. You can use the pseudo-key =parent= to look up the
369tree, and =depth= to match the depth (the spec root is at depth 0).
370
371An empty search matches the first thing found.
372If there are search terms, then the entire subtree is searched,
373but the shallowest matching node is returned.
374All search terms must be matched.
375
376=cut
377
378# True if the given configuration item matches the given search
379sub _matches {
380 my ( $this, %search ) = @_;
381
382 while ( my ( $k, $e ) = each %search ) {
383 if ( ref($e) ) {
384 return 0
385 unless ( ref( $this->{"_$k"} )
386 && $this->{"_$k"}->isa('Foswiki::Configure::Item')
387 && $this->{"_$k"}->_matches(%$e) );
388 }
389 elsif ( !defined $e ) {
390 return 0 if defined $this->{$k};
391 }
392 elsif ( !defined $this->{$k} || $this->{$k} ne $e ) {
393 return 0;
394 }
395 }
396 return 1;
397}
398
399=begin TML
400
401---++ ObjectMethod find(\%match) -> @nodes
402
403Get a list of nodes that match the given search template. The template
404is a node structure with a subset of fields filled in that must be
405matched in a node for it to be returned.
406
407Any fields can be used in searches and will match using eq, for example:
408 * =headline= - title of a section,
409 * =typename= - type of a leaf spec entry,
410 * =keys= - keys of a spec entry,
411 * =desc= - descriptive text of a section or entry.
412 * =depth= - matches the depth of a node under the root
413 (which is depth 0)
414Fields starting with _ are assumed to refer to another Foswiki::Configure::Item
415 * =parent= - a structure that will be used to match a parent (the value
416 should be another match hash that will match the parent),
417
418=cut
419
420sub find {
421 my $this = shift;
422 my %search = @_;
423
424 my $match = $this->_matches(%search);
425
426 if ($match) {
427 return ($this);
428 }
429 return ();
430}
431
432=begin TML
433
434---++ ObjectMethod search($re) -> @nodes
435
436Get a list of nodes that match the given RE. Sections match on the headline,
437Values on the keys.
438
439=cut
440
441sub search {
442 my ( $this, $re ) = @_;
443 return ();
444}
445
446=begin TML
447
448---++ ObjectMethod promoteSetting($setting) -> $boolean
449If all children of this node are tagged with the boolean attribute,
450then tag me too. Return true if the attribute is on us, false
451otherwise.
452
453=cut
454
455# Default impl assumes a leaf node
456sub promoteSetting {
457 my ( $this, $setting ) = @_;
458 return $this->{$setting};
459}
460
461=begin TML
462
463---++ ObjectMethod getValueObject($keys) -> $value
464Get the first Foswiki::Configure::Value object (leaf configuration item)
465associated with this Item. If this Item is a Value object, it will
466just return 'this'. if it is a Section, it will search the section
467(and it's subsections) for the value object with matching keys.
468
469Subclasses must define this method.
470
471=cut
472
473sub getValueObject {
474 die 'Subclasses must define this method';
475}
476
477=begin TML
478
479---++ ObjectMethod visit($visitor) -> $boolean
480Start a visit over this item.
481 * $visitor - an object that implements Foswiki::Configure::Visitor
482
483The default implementation just visits this item, and returns 1 if
484both the startVisit and the endVisit returned true.
485
486=cut
487
488sub visit {
489 my ( $this, $visitor ) = @_;
490 return 0 unless $visitor->startVisit($this);
491 return 0 unless $visitor->endVisit($this);
492 return 1;
493}
494
495=begin TML
496
497---++ ObjectMethod TO_JSON
498
499Provided so the JSON module can serialise blessed objects. Creates
500a copy of the object without internal pointers that is suitable for
501serialisation. Subclasses that add fields that need to be serialised
502*MUST* implement this method (by modifying the object returned by
503SUPER::TO_JSON to remove internal fields).
504
505=cut
506
507sub TO_JSON {
508 my $this = shift;
509 my $struct = {
510 class => ref($this),
511
512 # Don't serialise anything with a leading __
513 map { $_ => $this->{$_} } grep { !/^_/ } keys %$this
514 };
515 return $struct;
516}
517
51812µs1;
519__END__