File Coverage

blib/lib/Parse/PlainConfig.pm
Criterion Covered Total %
statement 350 368 95.1
branch 93 132 70.4
condition 32 45 71.1
subroutine 33 33 100.0
pod 9 9 100.0
total 517 587 88.0


line stmt bran cond sub pod time code
1             # Parse::PlainConfig -- Parsing Engine for Parse::PlainConfig
2             #
3             # (c) 2002 - 2016, Arthur Corliss ,
4             #
5             # $Id: lib/Parse/PlainConfig.pm, 3.04 2017/02/06 02:58:13 acorliss Exp $
6             #
7             # This software is licensed under the same terms as Perl, itself.
8             # Please see http://dev.perl.org/licenses/ for more information.
9             #
10             #####################################################################
11              
12             #####################################################################
13             #
14             # Environment definitions
15             #
16             #####################################################################
17              
18             package Parse::PlainConfig;
19              
20 8     8   127355 use 5.008;
  8         20  
21              
22 8     8   30 use strict;
  8         10  
  8         128  
23 8     8   23 use warnings;
  8         17  
  8         162  
24 8     8   22 use vars qw($VERSION);
  8         8  
  8         465  
25              
26             ($VERSION) = ( q$Revision: 3.04 $ =~ /(\d+(?:\.(\d+))+)/sm );
27              
28 8     8   4176 use Class::EHierarchy qw(:all);
  8         48574  
  8         1455  
29 8     8   3212 use Parse::PlainConfig::Constants qw(:all);
  8         9  
  8         1064  
30 8     8   2573 use Parse::PlainConfig::Settings;
  8         12  
  8         269  
31 8     8   3183 use Text::ParseWords;
  8         7841  
  8         384  
32 8     8   3151 use Text::Tabs;
  8         4359  
  8         693  
33 8     8   35 use Fcntl qw(:seek :DEFAULT);
  8         9  
  8         2290  
34 8     8   34 use Paranoid;
  8         11  
  8         266  
35 8     8   25 use Paranoid::Debug;
  8         8  
  8         322  
36 8     8   3615 use Paranoid::IO;
  8         82608  
  8         745  
37 8     8   3863 use Paranoid::IO::Line;
  8         20091  
  8         476  
38 8     8   45 use Paranoid::Input qw(:all);
  8         11  
  8         679  
39 8     8   3378 use Paranoid::Glob;
  8         27607  
  8         242  
40              
41 8     8   42 use base qw(Class::EHierarchy);
  8         11  
  8         640  
42              
43 8     8   35 use vars qw(@_properties @_methods %_parameters %_prototypes);
  8         13  
  8         906  
44              
45             #####################################################################
46             #
47             # Module code follows
48             #
49             #####################################################################
50              
51             sub _initialize {
52              
53             # Purpose: Initialize config object and loads class defaults
54             # Returns: Boolean
55             # Usage: $rv = $obj->_initialize(@args);
56              
57 8     8   2534 my $obj = shift;
58 8         18 my $class = ref $obj;
59 8         15 my $rv = 1;
60 8         14 my ( $settings, %_globals, %_parameters, %_prototypes );
61              
62 8         45 pdebug( 'entering w/%s', PPCDLEVEL1, $obj );
63 8         300 pIn();
64              
65             # Create & adopt the settings object
66 8         131 $settings = new Parse::PlainConfig::Settings;
67 8         3289 $obj->adopt($settings);
68 8         960 $settings->alias('settings');
69              
70             # Read in class global settings
71 8 50       342 unless ( __PACKAGE__ eq $class ) {
72 8         26 pdebug( 'loading globals from %s', PPCDLEVEL2, $class );
73              
74             {
75 8     8   32 no strict 'refs';
  8         12  
  8         866  
  8         168  
76              
77 8         14 %_globals = %{ *{"${class}::_globals"}{HASH} }
  8         79  
78 8 50       13 if defined *{"${class}::_globals"};
  8         291  
79             }
80              
81 8 50       42 if ( scalar keys %_globals ) {
82 8         26 foreach ( keys %_globals ) {
83             pdebug( 'overriding %s with (%s)',
84 40         1379 PPCDLEVEL3, $_, $_globals{$_} );
85 40 50       827 $rv = 0 unless $settings->set( $_, $_globals{$_} );
86             }
87             }
88             }
89              
90             # Read in class parameters
91 8 50       311 unless ( __PACKAGE__ eq $class ) {
92 8         24 pdebug( 'loading parameters from %s', PPCDLEVEL2, $class );
93              
94             {
95 8     8   31 no strict 'refs';
  8         10  
  8         1154  
  8         133  
96              
97 8         11 %_parameters = %{ *{"${class}::_parameters"}{HASH} }
  8         64  
98 8 50       12 if defined *{"${class}::_parameters"};
  8         37  
99             }
100              
101 8 50       33 if ( scalar keys %_parameters ) {
102 8         36 $settings->set( 'property types', %_parameters );
103 8         345 foreach ( keys %_parameters ) {
104              
105 40         2695 pdebug( 'creating property %s', PPCDLEVEL3, $_ );
106 40 100       873 unless (
    50          
107             _declProperty(
108             $obj,
109             $_,
110             CEH_PUB | (
111             $_parameters{$_} == PPC_HDOC
112             ? PPC_SCALAR
113             : $_parameters{$_}
114             ),
115             )
116             ) {
117 0         0 $rv = 0;
118 0         0 last;
119             }
120              
121             # merge property regex
122             $settings->merge(
123 40         913 'property regexes',
124             $_,
125 40         107 qr#(\s*)(\Q$_\E)\s*\Q@{[ $settings->delimiter ]}\E\s*(.*)#s
126             );
127             }
128             }
129             }
130              
131             # Read in class prototypes
132 8 50       592 unless ( __PACKAGE__ eq $class ) {
133 8         26 pdebug( 'loading prototypes from %s', PPCDLEVEL2, $class );
134              
135             {
136 8     8   30 no strict 'refs';
  8         13  
  8         17727  
  8         149  
137              
138 8         10 %_prototypes = %{ *{"${class}::_prototypes"}{HASH} }
  8         48  
139 8 50       14 if defined *{"${class}::_prototypes"};
  8         47  
140             }
141              
142 8 50       31 if ( scalar keys %_prototypes ) {
143 8         35 $settings->set( 'prototypes', %_prototypes );
144 8         279 foreach ( keys %_prototypes ) {
145              
146             # merge property meta-data
147 16         610 $settings->merge(
148             'prototype regexes',
149             $_,
150 16         49 qr#(\s*)(\Q$_\E)\s+(\S+)\s*\Q@{[ $settings->delimiter ]}\E\s*(.*)#s
151             );
152             }
153             }
154             }
155              
156             # Read in defaults from DATA
157 8         585 $rv = $obj->parse( $obj->default );
158              
159 8         49 pOut();
160 8         40 pdebug( 'leaving w/rv: %s', PPCDLEVEL1, $rv );
161              
162 8         181 return $rv;
163             }
164              
165             sub settings {
166              
167             # Purpose: Returns object reference to the settings object
168             # Returns: Object reference
169             # Usage: $settings = $obj->settings;
170              
171 153     153 1 137 my $obj = shift;
172              
173 153         327 return $obj->getByAlias('settings');
174             }
175              
176             sub default {
177              
178             # Purpose: Returns the DATA block from the calling
179             # Returns: Array
180             # Usage: @lines = $obj->_getData;
181              
182 15     15 1 363 my $obj = shift;
183 15         37 my $class = ref $obj;
184 15         18 my ( $fn, @chunk, @lines );
185              
186 15         41 pdebug( 'entering', PPCDLEVEL2 );
187 15         172 pIn();
188              
189 15         74 $class =~ s#::#/#sg;
190 15         28 $class .= '.pm';
191 15         36 $fn = $INC{$class};
192              
193 15         40 pdebug( 'attempting to read from %s', PPCDLEVEL3, $fn );
194 15 50       340 if ( popen( $fn, O_RDONLY ) ) {
195              
196             # Read in file
197 15   66     5389 while ( sip( $fn, @chunk ) and @chunk ) { push @lines, @chunk }
  15         16762  
198              
199             # empty all lines prior to __DATA__
200 15   100     9184 while ( @lines and $lines[0] !~ /^\s*__DATA__\s*$/s ) {
201 495         1331 shift @lines;
202             }
203 15         22 shift @lines;
204              
205             # empty all lines after __END__
206 15 100 100     160 if ( @lines and grep /^\s*__END__\s*$/s, @lines ) {
207 4   66     26 while ( @lines and $lines[-1] !~ /^\s*__END__\s*$/s ) {
208 16         61 pop @lines;
209             }
210 4         5 pop @lines;
211             }
212 15         57 pseek( $fn, 0, SEEK_SET );
213             }
214              
215 15         1758 pOut();
216 15         69 pdebug( 'leaving w/%s lines', PPCDLEVEL2, scalar @lines );
217              
218 15 100       475 return wantarray ? @lines : join '', @lines;
219             }
220              
221             sub get {
222              
223             # Purpose: Returns the value of the specified parameter
224             # Returns: Scalar/List/Hash
225             # Usage: $val = $obj->get('foo');
226              
227 66     66 1 12576 my $obj = shift;
228 66         75 my $p = shift;
229 66         61 my $valp;
230              
231 66         133 pdebug( 'entering w/%s', PPCDLEVEL1, $p );
232 66         1378 pIn();
233              
234 66 50       321 if ( defined $p ) {
235 66         165 $valp = scalar grep /^\Q$p\E$/s, $obj->properties;
236             }
237             $obj->error(
238 66 100       2447 pdebug( 'specified invalid parameter name: %s', PPCDLEVEL1, $p ) )
239             unless $valp;
240              
241 66         112 pOut();
242 66         306 pdebug( 'leaving', PPCDLEVEL1 );
243              
244 66 100       777 return $valp ? $obj->SUPER::get($p) : undef;
245             }
246              
247             sub set {
248              
249             # Purpose: Assigns the desired values to the specified parameter
250             # Returns: Boolean
251             # Usage: $rv = $obj->set($prop, @values);
252              
253 14     14 1 1584 my $obj = shift;
254 14         21 my $p = shift;
255 14         23 my @vals = @_;
256 14         34 my %propTypes = $obj->settings->propertyTypes;
257 14         444 my ( $valp, $rv );
258              
259 14         37 pdebug( 'entering w/(%s)(%s)', PPCDLEVEL1, $p, @vals );
260 14         368 pIn();
261              
262 14 50       84 if ( defined $p ) {
263 14         34 $valp = scalar grep /^\Q$p\E$/s, $obj->properties;
264             }
265             $obj->error(
266 14 100       490 pdebug( 'specified invalid parameter name: %s', PPCDLEVEL1, $p ) )
267             unless $valp;
268              
269 14 100       51 if ($valp) {
270 11 50       29 if (@vals) {
271              
272             # Set whatever's assigned
273 11         32 $rv = $obj->SUPER::set( $p, @vals );
274             } else {
275              
276             # Assume that no values means empty/undef
277 0 0 0     0 if ( $propTypes{$p} == PPC_SCALAR or $propTypes{$p} == PPC_HDOC )
278             {
279 0         0 $rv = $obj->SUPER::set( $p, undef );
280             } else {
281 0         0 $rv = $obj->empty($p);
282             }
283             }
284             }
285              
286 14         432 pOut();
287 14         68 pdebug( 'leaving', PPCDLEVEL1 );
288              
289 14 100       199 return $valp ? $rv : undef;
290             }
291              
292             sub _snarfBlock (\@\$\$$) {
293              
294             # Purpose: Finds and returns the block with the value
295             # string extracted.
296             # Returns: Boolean
297             # Usage: $rv = _snarfBlock(@lines, $val);
298              
299 102     102   93 my $lref = shift;
300 102         84 my $pref = shift;
301 102         81 my $vref = shift;
302 102         76 my $settings = shift;
303 102         251 my $obj = $settings->parent;
304 102         1122 my %regex = $settings->propertyRegexes;
305 102         3177 my %pregex = $settings->prototypeRegexes;
306 102         2577 my %propTypes = $settings->propertyTypes;
307 102         2810 my %prototypes = $settings->prototypes;
308 102         2590 my $subi = $settings->subindentation;
309 102         2307 my ( $rv, $indent, $prop, $proto, $trailer, $iwidth, $line, $preg );
310              
311 102         181 pdebug( 'entering', PPCDLEVEL2 );
312 102         1069 pIn();
313              
314             # Match line to a property/prototype declaration
315             #
316             # First try to match against properties
317 102         502 foreach ( keys %regex ) {
318 383 100       5471 if ( $$lref[0] =~ /^$regex{$_}$/s ) {
319 61         184 ( $indent, $prop, $trailer ) = ( $1, $2, $3 );
320 61         52 $rv = 1;
321 61         70 shift @$lref;
322 61         93 last;
323             }
324             }
325 102 50 66     467 unless ( $rv and defined $prop and length $prop ) {
      66        
326 41         75 foreach ( keys %pregex ) {
327 66 100       890 if ( $$lref[0] =~ /^$pregex{$_}$/s ) {
328 37         122 ( $indent, $proto, $prop, $trailer ) = ( $1, $2, $3, $4 );
329 37         41 $rv = 1;
330 37         40 shift @$lref;
331 37         71 last;
332             }
333             }
334             }
335              
336             # Define all prototyped properties
337 102 100 66     286 if ( defined $proto and length $proto ) {
338 37 50 33     140 if ( defined $prop and length $prop ) {
339              
340 37 100       75 if ( exists $regex{$prop} ) {
341 2         8 $obj->error(
342             pdebug(
343             'token (%s) for prototype (%s) attempted to override property',
344             PPCDLEVEL1,
345             $prop,
346             $proto
347             ) );
348 2         5 $rv = 0;
349             } else {
350              
351 35 100       62 if ( exists $propTypes{$prop} ) {
352              
353             # Make sure they haven't been previously defined,
354             # or if they have, they match the same type
355 19 100       63 unless ( $propTypes{$prop} == $prototypes{$proto} ) {
356 2         4 $rv = 0;
357 2         7 $obj->error(
358             pdebug(
359             'prototype mismatch with previous declaration: %s',
360             PPCDLEVEL1,
361             $proto
362             ) );
363             pdebug( 'current type: %s prototype: %s',
364             PPCDLEVEL1, $propTypes{$prop},
365 2         8 $prototypes{$proto} );
366             }
367             } else {
368              
369             # Create a new property
370 16         43 pdebug( 'creating property based on prototype %s: %s',
371             PPCDLEVEL3, $proto, $prop );
372              
373             $rv = _declProperty(
374             $obj,
375             $prop,
376             CEH_PUB | (
377             $prototypes{$proto} == PPC_HDOC
378             ? PPC_SCALAR
379 16 50       425 : $prototypes{$proto}
380             ),
381             );
382              
383             # Record the prop type
384 16 50       405 if ($rv) {
385             $settings->merge( 'property types',
386 16         54 $prop, $propTypes{$prop} = $prototypes{$proto} );
387 16         566 ($preg) =
388             $settings->subset( 'prototype registry', $proto );
389 16 100       498 $preg = [] unless defined $preg;
390 16         25 push @$preg, $prop;
391 16         39 $settings->merge( 'prototype registry',
392             $proto => $preg );
393             } else {
394 0         0 $obj->error(
395             pdebug(
396             'failed to declare prototype: %s %s',
397             PPCDLEVEL1, $proto, $prop
398             ) );
399             }
400             }
401             }
402             } else {
403 0         0 $obj->error(
404             pdebug(
405             'invalid token used for prototype %s: %s', PPCDLEVEL1,
406             $proto, $prop
407             ) );
408 0         0 $rv = 0;
409             }
410             }
411              
412             # Grab additional lines as needed
413 102 100       601 if ($rv) {
414              
415 94 100       175 if ( $propTypes{$prop} == PPC_HDOC ) {
416              
417             # Snarf all lines until we hit the HDOC marker
418 15         23 $rv = 0;
419 15         42 while (@$lref) {
420 60         89 $line = shift @$lref;
421 60 100       80 if ( $line =~ /^\s*\Q@{[ $settings->hereDoc ]}\E\s*$/s ) {
  60         128  
422 15         402 $rv = 1;
423 15         24 last;
424             } else {
425 45         1464 $line =~ s/^\s{1,$subi}//s;
426 45         136 $trailer .= $line;
427             }
428             }
429              
430             # Error out if we never found the marker
431             $obj->error(
432 15 50       39 pdebug( 'failed to find the here doc marker', PPCDLEVEL1 ) )
433             unless $rv;
434              
435             } else {
436              
437             # All non-HDOCs are handled the same
438 79 50       137 $iwidth = defined $indent ? length $indent : 0;
439 79         169 while (@$lref) {
440              
441             # We're done if this is a line break
442 138 100       387 last if $$lref[0] =~ /^\s*$/s;
443              
444             # We're also done if indentation isn't greater
445             # than the parameter declaration line
446 75         170 ($indent) = ( $$lref[0] =~ /^(\s*)/s );
447 75 100 66     269 last if !defined $indent or $iwidth >= length $indent;
448              
449             # Append content to the trailer
450 60         83 $line = shift @$lref;
451 60         287 $line =~ s/^\s{1,$subi}//s;
452 60         115 pchomp($line);
453 60         838 $trailer .= $line;
454             }
455             }
456 94 50       400 $trailer =~ s/\s+$//s if defined $trailer;
457             }
458              
459 102 100       156 if ($rv) {
460 94         265 pchomp($trailer);
461 94         1612 ( $$pref, $$vref ) = ( $prop, $trailer );
462 94         225 pdebug( 'extracted value for %s: %s', PPCDLEVEL3, $prop, $trailer );
463             }
464              
465 102         2256 pOut();
466 102         466 pdebug( 'leaving w/rv: %s', PPCDLEVEL2, $rv );
467              
468 102         2023 return $rv;
469             }
470              
471             sub _snarfProp {
472              
473             # Purpose: Takes the property value and parses according to its type,
474             # then merges it
475             # Returns: Boolean
476             # Usage: $rv = _snarfProp($obj, $prop, $val);
477              
478 94     94   91 my $obj = shift;
479 94         85 my $prop = shift;
480 94         117 my $val = shift;
481 94         154 my $settings = $obj->settings;
482 94         2060 my %propTypes = $settings->propertyTypes;
483 94         2982 my $ldelim = $settings->listDelimiter;
484 94         2272 my $hdelim = $settings->hashDelimiter;
485 94         2115 my $rv = 1;
486 94         71 my @elements;
487              
488 94         168 pdebug( 'entering w/(%s)(%s)', PPCDLEVEL2, $prop, $val );
489 94         2036 pIn();
490              
491 94 100 100     653 if ( $propTypes{$prop} == PPC_HDOC
492             or $propTypes{$prop} == PPC_SCALAR ) {
493              
494             # Here Docs and scalars are merged as-is
495 34         103 $obj->SUPER::set( $prop, $val );
496              
497             } else {
498              
499 60 100       102 if ( $propTypes{$prop} == PPC_ARRAY ) {
500              
501             # Split into a list
502 45         240 @elements = quotewords( qr/\Q$ldelim\E/s, 0, $val );
503 45         3747 foreach (@elements) { s/^\s+//s; s/\s+$//s; }
  102         126  
  102         141  
504              
505             } else {
506              
507             # Split into a hash
508 15         230 @elements =
509             quotewords( qr/(?:\Q$ldelim\E|\Q$hdelim\E)/s, 0, $val );
510 15         3897 foreach (@elements) { s/^\s+//s; s/\s+$//s; }
  120         133  
  120         171  
511              
512             }
513              
514             # merge the list value
515 60         143 pdebug( 'storing in %s: %s', PPCDLEVEL3, $prop, @elements );
516 60         1903 $obj->empty($prop);
517 60         1671 $obj->SUPER::set( $prop, @elements );
518             }
519              
520 94         3273 pOut();
521 94         400 pdebug( 'leaving w/rv: %s', PPCDLEVEL2, $rv );
522              
523 94         2054 return $rv;
524             }
525              
526             sub parse {
527              
528             # Purpose: Parses passed content and extracts values
529             # Returns: Boolean
530             # Usage: $rv = $obj->parse(@lines);
531              
532 25     25 1 1006 my $obj = shift;
533 25         124 my @lines = @_;
534 25         73 my $settings = $obj->settings;
535 25         683 my $delim = $settings->delimiter;
536 25         732 my $cre = qr#^\s*\Q@{[ $settings->comment ]}\E#s;
  25         68  
537 25         1116 my $rv = 1;
538 25         30 my ( $text, $prop, $value, $glob );
539              
540 25         58 pdebug( 'entering', PPCDLEVEL1 );
541 25         275 pIn();
542              
543             # Some preprocessing of lines
544 25 100       145 if (@lines) {
545 23         69 $tabstop = $settings->tabStop;
546 23         641 @lines = expand(@lines);
547 23         2461 foreach (@lines) {
548 433 100 66     2506 $text =
549             ( defined $text and length $text )
550             ? join "\n", $text, split NEWLINE_REGEX, $_
551             : join "\n", split NEWLINE_REGEX, $_;
552             }
553             }
554              
555 25         61 while (@lines) {
556              
557             # Skip comments and empty lines
558 313 100 100     1136 if ( $lines[0] =~ /^$cre/s
559 194         1246 or $lines[0] =~ /^\s*(?:@{[ NEWLINE_REGEX ]})?$/s ) {
560 210         168 shift @lines;
561 210         392 next;
562             }
563              
564             # Handle "include" statements
565 103 100       238 if ( $lines[0] =~ /^\s*include\s+(.+?)\s*$/s ) {
566 1         13 $glob = new Paranoid::Glob globs => [$1];
567 1         367 shift @lines;
568 1 50       8 $rv = 0 unless $obj->read($glob);
569 1         3 next;
570             }
571              
572             # See if we have property block
573 102 100       194 if ( _snarfBlock( @lines, $prop, $value, $settings ) ) {
574              
575             # Parse the block (but preserve earlier errors)
576 94 50       155 $rv = 0 unless _snarfProp( $obj, $prop, $value );
577              
578             } else {
579              
580 8         25 pdebug( 'discarding invalid input: %s', PPCDLEVEL1, $lines[0] );
581 8         137 shift @lines;
582 8         24 $rv = 0;
583             }
584             }
585              
586 25         58 pOut();
587 25         117 pdebug( 'leaving w/rv: %s', PPCDLEVEL1, $rv );
588              
589 25         481 return $rv;
590             }
591              
592             sub read {
593              
594             # Purpose: Reads the passed file(s)
595             # Returns: Boolean
596             # Usage: $rv = $obj->read($filename);
597              
598 5     5 1 1106 my $obj = shift;
599 5         22 my $source = shift;
600 5         8 my ( $rv, @lines );
601              
602 5         14 pdebug( 'entering w/%s', PPCDLEVEL1, $source );
603 5         99 pIn();
604              
605 5 50       45 if (@_) {
    100          
    50          
606              
607             # Work all entries passed if handed a list
608 0         0 $rv = $obj->read($source);
609 0 0       0 foreach (@_) { $rv = 0 unless $obj->read($_) }
  0         0  
610              
611             } elsif ( ref $source eq '' ) {
612              
613             # Treat all non-reference files as filenames
614 4 50       22 if ( slurp( $source, @lines ) ) {
615 4         6128 $rv = $obj->parse(@lines);
616 4 50       14 pdebug( 'errors parsing %s', PPCDLEVEL1, $source ) unless $rv;
617             } else {
618 0         0 $obj->error(
619             pdebug(
620             'failed to read %s: %s', PPCDLEVEL1,
621             $source, Paranoid::ERROR() ) );
622             }
623              
624             } elsif ( ref $source eq 'Paranoid::Glob' ) {
625              
626             # Handle Paranoid globs specially
627 1         1 $rv = 1;
628 1 50       4 foreach (@$source) { $rv = 0 unless $obj->read($_) }
  1         4  
629              
630             } else {
631              
632             # Handle everything else as if it was a glob
633 0 0       0 if ( slurp( $source, @lines ) ) {
634 0         0 $rv = $obj->parse(@lines);
635 0 0       0 pdebug( 'errors parsing %s', PPCDLEVEL1, $source ) unless $rv;
636             } else {
637 0         0 $obj->error(
638             pdebug(
639             'failed to read %s: %s', PPCDLEVEL1,
640             $source, Paranoid::ERROR() ) );
641             }
642             }
643              
644 5         14 pOut();
645 5         22 pdebug( 'leaving w/rv: %s', PPCDLEVEL1, $rv );
646              
647 5         105 return $rv;
648             }
649              
650             sub reset {
651              
652             # Purpose: Resets configuration state to defaults
653             # Returns: Boolean
654             # Usage: $rv = $obj->reset;
655              
656 6     6 1 2072 my $obj = shift;
657 6         17 my $settings = $obj->settings;
658 6         150 my %propTypes = $settings->propertyTypes;
659 6         202 my $rv;
660              
661 6         76 pdebug( 'entering', PPCDLEVEL1 );
662 6         130 pIn();
663              
664             # empty all property values
665 6         39 foreach ( keys %propTypes ) {
666 41         972 pdebug( 'clearing merged values for %s', PPCDLEVEL2, $_ );
667 41 100 100     810 if ( $propTypes{$_} == PPC_SCALAR or $propTypes{$_} == PPC_HDOC ) {
668 19         46 $obj->SUPER::set( $_, undef );
669             } else {
670 22         53 $obj->empty($_);
671             }
672             }
673 6         326 $rv = $obj->parse( $obj->default );
674              
675 6         34 pOut();
676 6         33 pdebug( 'leaving w/rv: %s', PPCDLEVEL1, $rv );
677              
678 6         125 return $rv;
679             }
680              
681             sub prototyped {
682              
683             # Purpose: Returns a list of properties that were created with
684             # prototypes
685             # Returns: Array
686             # Usage: @protos = $obj->prototyped;
687              
688 3     3 1 1257 my $obj = shift;
689 3         3 my $proto = shift;
690 3         4 my ( %preg, @prval );
691              
692 3         7 pdebug( 'entering w/%s', PPCDLEVEL1, $proto );
693 3         65 pIn();
694              
695 3         14 %preg = $obj->settings->get('prototype registry');
696              
697 3 100 66     167 if ( defined $proto and length $proto ) {
698 2 50       5 if ( exists $preg{$proto} ) {
699 2         4 @prval = @{ $preg{$proto} };
  2         5  
700             } else {
701 0         0 pdebug( 'no prototype properties declared w/%s',
702             PPCDLEVEL2, $proto );
703             }
704             } else {
705 1         3 pdebug( 'dumping all declared prototyped properties', PPCDLEVEL2 );
706 1         12 foreach ( keys %preg ) { push @prval, @{ $preg{$_} } }
  2         3  
  2         4  
707             }
708              
709 3         7 pOut();
710 3         14 pdebug( 'leaving w/%s', PPCDLEVEL1, @prval );
711              
712 3         71 return @prval;
713             }
714              
715             sub error {
716              
717             # Purpose: Sets/gets the last error message
718             # Returns: Scalar/undef
719             # Usage: $errStr = $obj->error;
720             # Usage: $errStr = $obj->error($msg);
721              
722 11     11 1 251 my $obj = shift;
723 11         13 my $msg = shift;
724              
725 11 50       21 if ( defined $msg ) {
726 11         77 $obj->settings->set( 'error', $msg );
727             } else {
728 0         0 $msg = $obj->settings->get('error');
729             }
730              
731 11         692 return $msg;
732             }
733              
734             1;
735              
736             __END__