← 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/Attrs.pm
StatementsExecuted 48994 statements in 53.9ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
17867421.3ms35.3msFoswiki::Attrs::::newFoswiki::Attrs::new
15931113.1ms13.1msFoswiki::Attrs::::_unfriendlyFoswiki::Attrs::_unfriendly
3755827.16ms7.16msFoswiki::Attrs::::removeFoswiki::Attrs::remove
4311912µs912µsFoswiki::Attrs::::_friendlyFoswiki::Attrs::_friendly
1011118µs118µsFoswiki::Attrs::::stringifyFoswiki::Attrs::stringify
11112µs25µsFoswiki::Attrs::::BEGIN@47Foswiki::Attrs::BEGIN@47
1118µs33µsFoswiki::Attrs::::BEGIN@49Foswiki::Attrs::BEGIN@49
1118µs12µsFoswiki::Attrs::::BEGIN@48Foswiki::Attrs::BEGIN@48
1114µs4µsFoswiki::Attrs::::BEGIN@51Foswiki::Attrs::BEGIN@51
0000s0sFoswiki::Attrs::::TO_JSONFoswiki::Attrs::TO_JSON
0000s0sFoswiki::Attrs::::extractValueFoswiki::Attrs::extractValue
0000s0sFoswiki::Attrs::::findFirstOccurenceAttrsFoswiki::Attrs::findFirstOccurenceAttrs
0000s0sFoswiki::Attrs::::getFoswiki::Attrs::get
0000s0sFoswiki::Attrs::::isEmptyFoswiki::Attrs::isEmpty
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::Attrs
6
7Class of attribute sets, designed for parsing and storing attribute values
8from a macro e.g. =%<nop>MACRO{"joe" fred="bad" joe="mad"}%=
9
10An attribute set is a hash containing an entry for each parameter. The
11default parameter (unnamed quoted string) is named <code>_<nop>DEFAULT</code> in the hash.
12
13Attributes declared later in the string will override those of the same
14name defined earlier. The one exception to this is the _DEFAULT key, where
15the _first_ instance is always taken.
16
17As well as the default Foswiki syntax (parameter values double-quoted)
18this class also parses single-quoted values, unquoted spaceless
19values, spaces around the =, and commas as well as spaces separating values.
20The extended syntax has to be enabled by passing the =$friendly= parameter
21to =new=.
22
23*Since* _date_ indicates where functions or parameters have been added since
24the baseline of the API (TWiki release 4.2.3). The _date_ indicates the
25earliest date of a Foswiki release that will support that function or
26parameter.
27
28*Deprecated* _date_ indicates where a function or parameters has been
29[[http://en.wikipedia.org/wiki/Deprecation][deprecated]]. Deprecated
30functions will still work, though they should
31_not_ be called in new plugins and should be replaced in older plugins
32as soon as possible. Deprecated parameters are simply ignored in Foswiki
33releases after _date_.
34
35*Until* _date_ indicates where a function or parameter has been removed.
36The _date_ indicates the latest date at which Foswiki releases still supported
37the function or parameter.
38
39=cut
40
41# THIS PACKAGE IS PART OF THE PUBLISHED API USED BY EXTENSION AUTHORS.
42# DO NOT CHANGE THE EXISTING APIS (well thought out extensions are OK)
43# AND ENSURE ALL POD DOCUMENTATION IS COMPLETE AND ACCURATE.
44
45package Foswiki::Attrs;
46
47225µs238µs
# spent 25µs (12+13) within Foswiki::Attrs::BEGIN@47 which was called: # once (12µs+13µs) by Foswiki::PageCache::BEGIN@61 at line 47
use strict;
# spent 25µs making 1 call to Foswiki::Attrs::BEGIN@47 # spent 13µs making 1 call to strict::import
48222µs216µs
# spent 12µs (8+4) within Foswiki::Attrs::BEGIN@48 which was called: # once (8µs+4µs) by Foswiki::PageCache::BEGIN@61 at line 48
use warnings;
# spent 12µs making 1 call to Foswiki::Attrs::BEGIN@48 # spent 4µs making 1 call to warnings::import
49243µs257µs
# spent 33µs (8+24) within Foswiki::Attrs::BEGIN@49 which was called: # once (8µs+24µs) by Foswiki::PageCache::BEGIN@61 at line 49
use Assert;
# spent 33µs making 1 call to Foswiki::Attrs::BEGIN@49 # spent 24µs making 1 call to Exporter::import
50
51
# spent 4µs within Foswiki::Attrs::BEGIN@51 which was called: # once (4µs+0s) by Foswiki::PageCache::BEGIN@61 at line 56
BEGIN {
5218µs if ( $Foswiki::cfg{UseLocale} ) {
53 require locale;
54 import locale();
55 }
5611.13ms14µs}
# spent 4µs making 1 call to Foswiki::Attrs::BEGIN@51
57
58# Used in interpolation an regexes, so constant not appropriate
591500nsour $MARKER = "\0";
60
61=begin TML
62
63---++ ClassMethod new ($string) => \%attrsObjectRef
64
65 * =$string= - String containing attribute specification
66
67Parse a standard attribute string containing name=value pairs and create a new
68attributes object. The value may be a word or a quoted string. If there is an
69error during parsing, the parse will complete but $attrs->{_ERROR} will be
70set in the new object. $attrs->{_RAW} will always contain the full unprocessed
71$string.
72
73=cut
74
75
# spent 35.3ms (21.3+14.0) within Foswiki::Attrs::new which was called 1786 times, avg 20µs/call: # 1075 times (14.8ms+7.46ms) by Foswiki::Templates::readTemplate at line 320 of /var/www/foswikidev/core/lib/Foswiki/Templates.pm, avg 21µs/call # 397 times (3.72ms+4.01ms) by Foswiki::_expandMacroOnTopicRendering at line 3434 of /var/www/foswikidev/core/lib/Foswiki.pm, avg 19µs/call # 308 times (2.77ms+2.43ms) by Foswiki::Templates::expandTemplate at line 135 of /var/www/foswikidev/core/lib/Foswiki/Templates.pm, avg 17µs/call # 2 times (31µs+43µs) by Foswiki::Store::Rcs::Handler::_getTOPICINFO at line 274 of /var/www/foswikidev/core/lib/Foswiki/Store/Rcs/Handler.pm, avg 37µs/call # 2 times (18µs+32µs) by Foswiki::Func::extractParameters at line 3141 of /var/www/foswikidev/core/lib/Foswiki/Func.pm, avg 25µs/call # once (14µs+46µs) by Foswiki::_expandMacroOnTopicRendering at line 3441 of /var/www/foswikidev/core/lib/Foswiki.pm # once (10µs+6µs) by Foswiki::Templates::_expandTrivialTemplate at line 111 of /var/www/foswikidev/core/lib/Foswiki/Templates.pm
sub new {
7617861.40ms my ( $class, $string, $friendly ) = @_;
7717861.68ms my $this = bless( {}, $class );
78
7917861.23ms $this->{_RAW} = $string;
80
811786555µs return $this unless defined($string);
82
83 # Escapes
841636847µs $string =~ s/\\'/\x01/g;
851636411µs $string =~ s/\\"/\x02/g;
86
871636574µs43912µs if ($friendly) {
# spent 912µs making 43 calls to Foswiki::Attrs::_friendly, avg 21µs/call
88 _friendly( $this, $string );
89 }
90 else {
9115931.70ms159313.1ms _unfriendly( $this, $string );
# spent 13.1ms making 1593 calls to Foswiki::Attrs::_unfriendly, avg 8µs/call
92 }
9316362.02ms for ( values %$this ) {
9436601.02ms s/\x01/'/g;
9536601.84ms s/\x02/"/g;
96 }
9716363.37ms return $this;
98}
99
100
# spent 13.1ms within Foswiki::Attrs::_unfriendly which was called 1593 times, avg 8µs/call: # 1593 times (13.1ms+0s) by Foswiki::Attrs::new at line 91, avg 8µs/call
sub _unfriendly {
1011593683µs my ( $this, $string ) = @_;
102
1031593327µs my $first = 1;
104
10515934.64ms if ( $string =~ s/^\s*\"(.*?)\"\s*(?=[a-z0-9_]+\s*=\s*\"|$)//si ) {
106 $this->{_DEFAULT} = $1;
107 }
10815937.52ms while ( $string =~ m/\S/s ) {
109
110 # name="value" pairs
1119233.59ms if ( $string =~ s/^\s*([a-z0-9_]+)\s*=\s*\"(.*?)\"//is ) {
112356481µs $this->{$1} = $2;
11335682µs $first = 0;
114 }
115
116 # simple double-quoted value with no name, sets the default
117 elsif ( $string =~ s/^\s*\"(.*?)\"//s ) {
11823µs $this->{_DEFAULT} = $1
119 unless defined( $this->{_DEFAULT} );
1202800ns $first = 0;
121 }
122
123 # Unquoted string not matching any recognised structure
124 # SMELL: unchecked implicit untaint?
125 elsif ( $string =~ m/^\s*(.*?)\s*$/s ) {
126565634µs $this->{_DEFAULT} = $1 if ($first);
1275651.49ms last;
128 }
129 }
130}
131
132
# spent 912µs within Foswiki::Attrs::_friendly which was called 43 times, avg 21µs/call: # 43 times (912µs+0s) by Foswiki::Attrs::new at line 87, avg 21µs/call
sub _friendly {
1334323µs my ( $this, $string ) = @_;
134
135438µs my $first = 1;
136
1374366µs while ( $string =~ m/\S/s ) {
138
139 # name="value" pairs
140104599µs if ( $string =~ s/^[\s,]*([a-z0-9_]+)\s*=\s*\"(.*?)\"//is ) {
1415679µs $this->{$1} = $2;
1425613µs $first = 0;
143 }
144
145 # simple double-quoted value with no name, sets the default
146 elsif ( $string =~ s/^[\s,]*\"(.*?)\"//s ) {
1474258µs $this->{_DEFAULT} = $1
148 unless defined( $this->{_DEFAULT} );
1494213µs $first = 0;
150 }
151
152 # name='value' pairs
153 elsif ( $string =~ s/^[\s,]*([a-z0-9_]+)\s*=\s*'(.*?)'//is ) {
154 $this->{$1} = $2;
155 }
156
157 # name=value pairs
158 elsif ( $string =~ s/^[\s,]*([a-z0-9_]+)\s*=\s*([^\s,\}\'\"]*)//is ) {
159 $this->{$1} = $2;
160 }
161
162 # simple single-quoted value with no name, sets the default
163 elsif ( $string =~ s/^[\s,]*'(.*?)'//s ) {
164 $this->{_DEFAULT} = $1
165 unless defined( $this->{_DEFAULT} );
166 }
167
168 # simple name with no value (boolean, or _DEFAULT)
169 elsif ( $string =~ s/^[\s,]*([a-z][a-z0-9_]*)\b//is ) {
170 my $key = $1;
171 $this->{$key} = 1;
172 }
173
174 # otherwise the whole string - sans padding - is the default
175 else {
176
177 # SMELL: unchecked implicit untaint?
178 if ( $string =~ m/^\s*(.*?)\s*$/s
179 && !defined( $this->{_DEFAULT} ) )
180 {
181 $this->{_DEFAULT} = $1;
182 }
183 last;
184 }
185 }
18643113µs return $this;
187}
188
189=begin TML
190
191---++ ObjectMethod isEmpty() -> boolean
192
193Return false if attribute set is not empty.
194
195=cut
196
197sub isEmpty {
198 my $this = shift;
199
200 foreach my $k ( keys %$this ) {
201 return 0 if $k ne '_RAW';
202 }
203 return 1;
204}
205
206=begin TML
207
208---++ ObjectMethod remove($key) -> $value
209
210 * =$key= - Attribute to remove
211Remove an attr value from the map, return old value. After a call to
212=remove= the attribute is no longer defined.
213
214=cut
215
216
# spent 7.16ms within Foswiki::Attrs::remove which was called 3755 times, avg 2µs/call: # 1075 times (2.51ms+0s) by Foswiki::Templates::readTemplate at line 324 of /var/www/foswikidev/core/lib/Foswiki/Templates.pm, avg 2µs/call # 1075 times (1.92ms+0s) by Foswiki::Templates::readTemplate at line 325 of /var/www/foswikidev/core/lib/Foswiki/Templates.pm, avg 2µs/call # 309 times (631µs+0s) by Foswiki::Templates::tmplP at line 163 of /var/www/foswikidev/core/lib/Foswiki/Templates.pm, avg 2µs/call # 309 times (601µs+0s) by Foswiki::Templates::tmplP at line 162 of /var/www/foswikidev/core/lib/Foswiki/Templates.pm, avg 2µs/call # 309 times (495µs+0s) by Foswiki::Templates::tmplP at line 164 of /var/www/foswikidev/core/lib/Foswiki/Templates.pm, avg 2µs/call # 309 times (455µs+0s) by Foswiki::Templates::tmplP at line 165 of /var/www/foswikidev/core/lib/Foswiki/Templates.pm, avg 1µs/call # 309 times (440µs+0s) by Foswiki::Templates::tmplP at line 166 of /var/www/foswikidev/core/lib/Foswiki/Templates.pm, avg 1µs/call # 60 times (114µs+0s) by Foswiki::INCLUDE at line 374 of /var/www/foswikidev/core/lib/Foswiki/Macros/INCLUDE.pm, avg 2µs/call
sub remove {
21737551.35ms my ( $this, $attr ) = @_;
21837551.10ms my $val = $this->{$attr};
21937551.74ms delete( $this->{$attr} ) if ( exists $this->{$attr} );
220375511.3ms return $val;
221}
222
223=begin TML
224
225---++ ObjectMethod stringify() -> $string
226
227Generate a printed form for the map, using strict
228attribute syntax, with only the single-quote extension
229syntax observed (no {} brackets, though).
230
231=cut
232
233
# spent 118µs within Foswiki::Attrs::stringify which was called 10 times, avg 12µs/call: # 10 times (118µs+0s) by Foswiki::INCLUDE at line 369 of /var/www/foswikidev/core/lib/Foswiki/Macros/INCLUDE.pm, avg 12µs/call
sub stringify {
234103µs my $this = shift;
235101µs my $key;
236102µs my @ss;
2371035µs foreach $key ( sort keys %$this ) {
2382117µs if ( $key ne '_ERROR' && $key ne '_RAW' ) {
239117µs my $es = ( $key eq '_DEFAULT' ) ? '' : $key . '=';
240117µs my $val = $this->{$key};
241116µs $val =~ s/"/\\"/g;
2421117µs push( @ss, $es . '"' . $val . '"' );
243 }
244 }
2451038µs return join( ' ', @ss );
246}
247
248=begin TML
249
250---++ ObjectMethod TO_JSON() -> \%map
251
252Support for the JSON cpan module
253
254=cut
255
256sub TO_JSON {
257 my $this = shift;
258 my %res;
259 while ( my ( $k, $v ) = each %$this ) {
260 $res{$k} = $v;
261 }
262 return \%res;
263}
264
265=begin TML
266
267---++ StaticMethod findFirstOccurenceAttrs($macro, $text) -> $args
268
269Extract the first occurence of a macro from the text, taking into
270account balancing %{}%'s. For example, given $macro=X and $text="X%Y{%X{%X{}%}%}%Y"
271it will return "%X{}%". Given $text="%X%" it will return ''. Given "YYY" it
272will return undef, because neither "%X%" nor "%X{}%" occur.
273
274=cut
275
276sub findFirstOccurenceAttrs {
277 my ( $macro, $text ) = @_;
278 return undef unless $text =~ m/\%${macro}[%{]/s;
279 my @queue = split( /(%[A-Za-z0-9_]*{|}%|\%${macro}\%)/, $text );
280 my $eat = 0;
281 my $eaten = '';
282 while ( scalar(@queue) ) {
283 my $token = shift @queue;
284 if ($eat) {
285 if ( $token =~ m/^%[A-Za-z0-9_]*{$/ ) {
286 $eat++;
287 }
288 elsif ( $eat && $token eq '}%' ) {
289 $eat--;
290 return $eaten if ( !$eat );
291 }
292 $eaten .= $token;
293 }
294 else {
295 if ( $token eq "\%${macro}%" ) {
296 return '';
297 }
298 elsif ( $token eq "\%${macro}\{" ) {
299 $eat = 1;
300 }
301 }
302 }
303 return '';
304}
305
306# ---++ StaticMethod extractValue() -> $string
307#
308# Legacy support, formerly known as extractNameValuePair. This
309# static method uses context information to determine how a value
310# string is to be parsed. For example, if you have an attribute string
311# like this:
312#
313# "abc def="ghi" jkl" def="qqq"
314#
315# then call extractValue( "def" ), it will return "ghi".
316
317sub extractValue {
318 my ( $str, $name ) = @_;
319
320 my $value = '';
321 return $value unless ($str);
322 $str =~ s/\\\"/\\$MARKER/g; # escape \"
323
324 if ($name) {
325
326 # format is: %VAR{ ... name = "value" }%
327 if ( $str =~ m/(^|[^\S])$name\s*=\s*\"([^\"]*)\"/ ) {
328 $value = $2 if defined $2; # distinguish between '' and "0"
329 }
330
331 }
332 else {
333
334 # test if format: { "value" ... }
335 # SMELL: unchecked implicit untaint?
336 if ( $str =~
337 m/(^|\=\s*\"[^\"]*\")\s*\"(.*?)\"\s*([a-z0-9_]+\s*=\s*\"|$)/ )
338 {
339
340 # is: %VAR{ "value" }%
341 # or: %VAR{ "value" param="etc" ... }%
342 # or: %VAR{ ... = "..." "value" ... }%
343 # Note: "value" may contain embedded double quotes
344 $value = $2 if defined $2; # distinguish between '' and "0";
345
346 }
347 elsif ( ( $str =~ m/^\s*[a-z0-9_]+\s*=\s*\"([^\"]*)/ ) && ($1) ) {
348
349 # is: %VAR{ name = "value" }%
350 # do nothing, is not a standalone var
351
352 }
353 else {
354
355 # format is: %VAR{ value }%
356 $value = $str;
357 }
358 }
359 $value =~ s/\\$MARKER/\"/g; # resolve \"
360 return $value;
361}
362
363# ---++ ObjectMethod get($key) -> $value
364#
365# | $key | Attribute to get |
366# Get an attr value from the map.
367#
368# Synonymous with $attrs->{$key}. Retained mainly for compatibility with
369# the old AttrsContrib.
370sub get {
371 my ( $this, $field ) = @_;
372 return $this->{$field};
373}
374
37513µs1;
376__END__