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.05 2017/02/06 10:36:37 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   123453 use 5.008;
  8         17  
21              
22 8     8   25 use strict;
  8         10  
  8         119  
23 8     8   22 use warnings;
  8         11  
  8         163  
24 8     8   23 use vars qw($VERSION);
  8         9  
  8         473  
25              
26             ($VERSION) = ( q$Revision: 3.05 $ =~ /(\d+(?:\.(\d+))+)/sm );
27              
28 8     8   4223 use Class::EHierarchy qw(:all);
  8         47320  
  8         1136  
29 8     8   2582 use Parse::PlainConfig::Constants qw(:all);
  8         11  
  8         971  
30 8     8   2462 use Parse::PlainConfig::Settings;
  8         11  
  8         317  
31 8     8   3080 use Text::ParseWords;
  8         7347  
  8         374  
32 8     8   3051 use Text::Tabs;
  8         4164  
  8         625  
33 8     8   33 use Fcntl qw(:seek :DEFAULT);
  8         8  
  8         2105  
34 8     8   33 use Paranoid;
  8         9  
  8         250  
35 8     8   24 use Paranoid::Debug;
  8         7  
  8         333  
36 8     8   3516 use Paranoid::IO;
  8         79674  
  8         585  
37 8     8   3302 use Paranoid::IO::Line;
  8         19528  
  8         464  
38 8     8   41 use Paranoid::Input qw(:all);
  8         9  
  8         639  
39 8     8   3407 use Paranoid::Glob;
  8         26816  
  8         291  
40              
41 8     8   38 use base qw(Class::EHierarchy);
  8         7  
  8         518  
42              
43 8     8   31 use vars qw(@_properties @_methods %_parameters %_prototypes);
  8         11  
  8         869  
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   2316 my $obj = shift;
58 8         20 my $class = ref $obj;
59 8         13 my $rv = 1;
60 8         11 my ( $settings, %_globals, %_parameters, %_prototypes );
61              
62 8         40 pdebug( 'entering w/%s', PPCDLEVEL1, $obj );
63 8         304 pIn();
64              
65             # Create & adopt the settings object
66 8         127 $settings = new Parse::PlainConfig::Settings;
67 8         3234 $obj->adopt($settings);
68 8         951 $settings->alias('settings');
69              
70             # Read in class global settings
71 8 50       341 unless ( __PACKAGE__ eq $class ) {
72 8         28 pdebug( 'loading globals from %s', PPCDLEVEL2, $class );
73              
74             {
75 8     8   30 no strict 'refs';
  8         8  
  8         771  
  8         170  
76              
77 8         13 %_globals = %{ *{"${class}::_globals"}{HASH} }
  8         67  
78 8 50       9 if defined *{"${class}::_globals"};
  8         273  
79             }
80              
81 8 50       39 if ( scalar keys %_globals ) {
82 8         23 foreach ( keys %_globals ) {
83             pdebug( 'overriding %s with (%s)',
84 40         1348 PPCDLEVEL3, $_, $_globals{$_} );
85 40 50       832 $rv = 0 unless $settings->set( $_, $_globals{$_} );
86             }
87             }
88             }
89              
90             # Read in class parameters
91 8 50       341 unless ( __PACKAGE__ eq $class ) {
92 8         21 pdebug( 'loading parameters from %s', PPCDLEVEL2, $class );
93              
94             {
95 8     8   30 no strict 'refs';
  8         9  
  8         1114  
  8         136  
96              
97 8         10 %_parameters = %{ *{"${class}::_parameters"}{HASH} }
  8         54  
98 8 50       14 if defined *{"${class}::_parameters"};
  8         39  
99             }
100              
101 8 50       28 if ( scalar keys %_parameters ) {
102 8         44 $settings->set( 'property types', %_parameters );
103 8         302 foreach ( keys %_parameters ) {
104              
105 40         2694 pdebug( 'creating property %s', PPCDLEVEL3, $_ );
106 40 100       849 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         955 'property regexes',
124             $_,
125 40         93 qr#(\s*)(\Q$_\E)\s*\Q@{[ $settings->delimiter ]}\E\s*(.*)#s
126             );
127             }
128             }
129             }
130              
131             # Read in class prototypes
132 8 50       587 unless ( __PACKAGE__ eq $class ) {
133 8         24 pdebug( 'loading prototypes from %s', PPCDLEVEL2, $class );
134              
135             {
136 8     8   29 no strict 'refs';
  8         8  
  8         16743  
  8         150  
137              
138 8         11 %_prototypes = %{ *{"${class}::_prototypes"}{HASH} }
  8         45  
139 8 50       13 if defined *{"${class}::_prototypes"};
  8         50  
140             }
141              
142 8 50       28 if ( scalar keys %_prototypes ) {
143 8         34 $settings->set( 'prototypes', %_prototypes );
144 8         281 foreach ( keys %_prototypes ) {
145              
146             # merge property meta-data
147 16         599 $settings->merge(
148             'prototype regexes',
149             $_,
150 16         41 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         646 $rv = $obj->parse( $obj->default );
158              
159 8         43 pOut();
160 8         41 pdebug( 'leaving w/rv: %s', PPCDLEVEL1, $rv );
161              
162 8         155 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 126 my $obj = shift;
172              
173 153         318 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 326 my $obj = shift;
183 15         32 my $class = ref $obj;
184 15         17 my ( $fn, @chunk, @lines );
185              
186 15         40 pdebug( 'entering', PPCDLEVEL2 );
187 15         172 pIn();
188              
189 15         72 $class =~ s#::#/#sg;
190 15         28 $class .= '.pm';
191 15         32 $fn = $INC{$class};
192              
193 15         42 pdebug( 'attempting to read from %s', PPCDLEVEL3, $fn );
194 15 50       327 if ( popen( $fn, O_RDONLY ) ) {
195              
196             # Read in file
197 15   66     5244 while ( sip( $fn, @chunk ) and @chunk ) { push @lines, @chunk }
  15         16182  
198              
199             # empty all lines prior to __DATA__
200 15   100     9311 while ( @lines and $lines[0] !~ /^\s*__DATA__\s*$/s ) {
201 495         1359 shift @lines;
202             }
203 15         24 shift @lines;
204              
205             # empty all lines after __END__
206 15 100 100     151 if ( @lines and grep /^\s*__END__\s*$/s, @lines ) {
207 4   66     25 while ( @lines and $lines[-1] !~ /^\s*__END__\s*$/s ) {
208 16         54 pop @lines;
209             }
210 4         4 pop @lines;
211             }
212 15         53 pseek( $fn, 0, SEEK_SET );
213             }
214              
215 15         1741 pOut();
216 15         70 pdebug( 'leaving w/%s lines', PPCDLEVEL2, scalar @lines );
217              
218 15 100       457 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 13729 my $obj = shift;
228 66         73 my $p = shift;
229 66         59 my $valp;
230              
231 66         140 pdebug( 'entering w/%s', PPCDLEVEL1, $p );
232 66         1403 pIn();
233              
234 66 50       313 if ( defined $p ) {
235 66         158 $valp = scalar grep /^\Q$p\E$/s, $obj->properties;
236             }
237             $obj->error(
238 66 100       2423 pdebug( 'specified invalid parameter name: %s', PPCDLEVEL1, $p ) )
239             unless $valp;
240              
241 66         113 pOut();
242 66         297 pdebug( 'leaving', PPCDLEVEL1 );
243              
244 66 100       787 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 1733 my $obj = shift;
254 14         20 my $p = shift;
255 14         24 my @vals = @_;
256 14         31 my %propTypes = $obj->settings->propertyTypes;
257 14         472 my ( $valp, $rv );
258              
259 14         37 pdebug( 'entering w/(%s)(%s)', PPCDLEVEL1, $p, @vals );
260 14         357 pIn();
261              
262 14 50       120 if ( defined $p ) {
263 14         36 $valp = scalar grep /^\Q$p\E$/s, $obj->properties;
264             }
265             $obj->error(
266 14 100       520 pdebug( 'specified invalid parameter name: %s', PPCDLEVEL1, $p ) )
267             unless $valp;
268              
269 14 100       46 if ($valp) {
270 11 50       26 if (@vals) {
271              
272             # Set whatever's assigned
273 11         31 $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         409 pOut();
287 14         64 pdebug( 'leaving', PPCDLEVEL1 );
288              
289 14 100       194 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   100 my $lref = shift;
300 102         78 my $pref = shift;
301 102         84 my $vref = shift;
302 102         86 my $settings = shift;
303 102         248 my $obj = $settings->parent;
304 102         1111 my %regex = $settings->propertyRegexes;
305 102         3167 my %pregex = $settings->prototypeRegexes;
306 102         2586 my %propTypes = $settings->propertyTypes;
307 102         2857 my %prototypes = $settings->prototypes;
308 102         2531 my $subi = $settings->subindentation;
309 102         2333 my ( $rv, $indent, $prop, $proto, $trailer, $iwidth, $line, $preg );
310              
311 102         187 pdebug( 'entering', PPCDLEVEL2 );
312 102         1039 pIn();
313              
314             # Match line to a property/prototype declaration
315             #
316             # First try to match against properties
317 102         506 foreach ( keys %regex ) {
318 378 100       5456 if ( $$lref[0] =~ /^$regex{$_}$/s ) {
319 61         175 ( $indent, $prop, $trailer ) = ( $1, $2, $3 );
320 61         56 $rv = 1;
321 61         64 shift @$lref;
322 61         87 last;
323             }
324             }
325 102 50 66     461 unless ( $rv and defined $prop and length $prop ) {
      66        
326 41         78 foreach ( keys %pregex ) {
327 64 100       818 if ( $$lref[0] =~ /^$pregex{$_}$/s ) {
328 37         120 ( $indent, $proto, $prop, $trailer ) = ( $1, $2, $3, $4 );
329 37         36 $rv = 1;
330 37         40 shift @$lref;
331 37         61 last;
332             }
333             }
334             }
335              
336             # Define all prototyped properties
337 102 100 66     280 if ( defined $proto and length $proto ) {
338 37 50 33     131 if ( defined $prop and length $prop ) {
339              
340 37 100       81 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         4 $rv = 0;
349             } else {
350              
351 35 100       49 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       59 unless ( $propTypes{$prop} == $prototypes{$proto} ) {
356 2         4 $rv = 0;
357 2         6 $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         42 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       401 : $prototypes{$proto}
380             ),
381             );
382              
383             # Record the prop type
384 16 50       399 if ($rv) {
385             $settings->merge( 'property types',
386 16         52 $prop, $propTypes{$prop} = $prototypes{$proto} );
387 16         547 ($preg) =
388             $settings->subset( 'prototype registry', $proto );
389 16 100       504 $preg = [] unless defined $preg;
390 16         24 push @$preg, $prop;
391 16         31 $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       600 if ($rv) {
414              
415 94 100       165 if ( $propTypes{$prop} == PPC_HDOC ) {
416              
417             # Snarf all lines until we hit the HDOC marker
418 15         24 $rv = 0;
419 15         39 while (@$lref) {
420 60         90 $line = shift @$lref;
421 60 100       76 if ( $line =~ /^\s*\Q@{[ $settings->hereDoc ]}\E\s*$/s ) {
  60         114  
422 15         411 $rv = 1;
423 15         25 last;
424             } else {
425 45         1468 $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       36 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       141 $iwidth = defined $indent ? length $indent : 0;
439 79         130 while (@$lref) {
440              
441             # We're done if this is a line break
442 138 100       371 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         160 ($indent) = ( $$lref[0] =~ /^(\s*)/s );
447 75 100 66     272 last if !defined $indent or $iwidth >= length $indent;
448              
449             # Append content to the trailer
450 60         85 $line = shift @$lref;
451 60         260 $line =~ s/^\s{1,$subi}//s;
452 60         117 pchomp($line);
453 60         838 $trailer .= $line;
454             }
455             }
456 94 50       372 $trailer =~ s/\s+$//s if defined $trailer;
457             }
458              
459 102 100       156 if ($rv) {
460 94         212 pchomp($trailer);
461 94         1562 ( $$pref, $$vref ) = ( $prop, $trailer );
462 94         219 pdebug( 'extracted value for %s: %s', PPCDLEVEL3, $prop, $trailer );
463             }
464              
465 102         2438 pOut();
466 102         433 pdebug( 'leaving w/rv: %s', PPCDLEVEL2, $rv );
467              
468 102         1998 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   80 my $obj = shift;
479 94         95 my $prop = shift;
480 94         105 my $val = shift;
481 94         164 my $settings = $obj->settings;
482 94         2055 my %propTypes = $settings->propertyTypes;
483 94         2954 my $ldelim = $settings->listDelimiter;
484 94         2268 my $hdelim = $settings->hashDelimiter;
485 94         2192 my $rv = 1;
486 94         80 my @elements;
487              
488 94         176 pdebug( 'entering w/(%s)(%s)', PPCDLEVEL2, $prop, $val );
489 94         2073 pIn();
490              
491 94 100 100     666 if ( $propTypes{$prop} == PPC_HDOC
492             or $propTypes{$prop} == PPC_SCALAR ) {
493              
494             # Here Docs and scalars are merged as-is
495 34         138 $obj->SUPER::set( $prop, $val );
496              
497             } else {
498              
499 60 100       98 if ( $propTypes{$prop} == PPC_ARRAY ) {
500              
501             # Split into a list
502 45         239 @elements = quotewords( qr/\Q$ldelim\E/s, 0, $val );
503 45         3685 foreach (@elements) { s/^\s+//s; s/\s+$//s; }
  102         126  
  102         138  
504              
505             } else {
506              
507             # Split into a hash
508 15         220 @elements =
509             quotewords( qr/(?:\Q$ldelim\E|\Q$hdelim\E)/s, 0, $val );
510 15         3718 foreach (@elements) { s/^\s+//s; s/\s+$//s; }
  120         130  
  120         164  
511              
512             }
513              
514             # merge the list value
515 60         131 pdebug( 'storing in %s: %s', PPCDLEVEL3, $prop, @elements );
516 60         1926 $obj->empty($prop);
517 60         1609 $obj->SUPER::set( $prop, @elements );
518             }
519              
520 94         3220 pOut();
521 94         391 pdebug( 'leaving w/rv: %s', PPCDLEVEL2, $rv );
522              
523 94         2076 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 1001 my $obj = shift;
533 25         124 my @lines = @_;
534 25         65 my $settings = $obj->settings;
535 25         685 my $delim = $settings->delimiter;
536 25         704 my $cre = qr#^\s*\Q@{[ $settings->comment ]}\E#s;
  25         62  
537 25         819 my $rv = 1;
538 25         27 my ( $text, $prop, $value, $glob );
539              
540 25         55 pdebug( 'entering', PPCDLEVEL1 );
541 25         274 pIn();
542              
543             # Some preprocessing of lines
544 25 100       136 if (@lines) {
545 23         62 $tabstop = $settings->tabStop;
546 23         624 @lines = expand(@lines);
547 23         2472 foreach (@lines) {
548 433 100 66     2472 $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         54 while (@lines) {
556              
557             # Skip comments and empty lines
558 313 100 100     1145 if ( $lines[0] =~ /^$cre/s
559 194         1252 or $lines[0] =~ /^\s*(?:@{[ NEWLINE_REGEX ]})?$/s ) {
560 210         164 shift @lines;
561 210         396 next;
562             }
563              
564             # Handle "include" statements
565 103 100       264 if ( $lines[0] =~ /^\s*include\s+(.+?)\s*$/s ) {
566 1         10 $glob = new Paranoid::Glob globs => [$1];
567 1         279 shift @lines;
568 1 50       5 $rv = 0 unless $obj->read($glob);
569 1         3 next;
570             }
571              
572             # See if we have property block
573 102 100       193 if ( _snarfBlock( @lines, $prop, $value, $settings ) ) {
574              
575             # Parse the block (but preserve earlier errors)
576 94 50       139 $rv = 0 unless _snarfProp( $obj, $prop, $value );
577              
578             } else {
579              
580 8         22 pdebug( 'discarding invalid input: %s', PPCDLEVEL1, $lines[0] );
581 8         134 shift @lines;
582 8         23 $rv = 0;
583             }
584             }
585              
586 25         51 pOut();
587 25         125 pdebug( 'leaving w/rv: %s', PPCDLEVEL1, $rv );
588              
589 25         487 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 1059 my $obj = shift;
599 5         7 my $source = shift;
600 5         5 my ( $rv, @lines );
601              
602 5         11 pdebug( 'entering w/%s', PPCDLEVEL1, $source );
603 5         100 pIn();
604              
605 5 50       40 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       17 if ( slurp( $source, @lines ) ) {
615 4         6012 $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       3 foreach (@$source) { $rv = 0 unless $obj->read($_) }
  1         5  
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         11 pOut();
645 5         22 pdebug( 'leaving w/rv: %s', PPCDLEVEL1, $rv );
646              
647 5         100 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 2168 my $obj = shift;
657 6         17 my $settings = $obj->settings;
658 6         151 my %propTypes = $settings->propertyTypes;
659 6         201 my $rv;
660              
661 6         64 pdebug( 'entering', PPCDLEVEL1 );
662 6         122 pIn();
663              
664             # empty all property values
665 6         38 foreach ( keys %propTypes ) {
666 41         1050 pdebug( 'clearing merged values for %s', PPCDLEVEL2, $_ );
667 41 100 100     829 if ( $propTypes{$_} == PPC_SCALAR or $propTypes{$_} == PPC_HDOC ) {
668 19         49 $obj->SUPER::set( $_, undef );
669             } else {
670 22         51 $obj->empty($_);
671             }
672             }
673 6         295 $rv = $obj->parse( $obj->default );
674              
675 6         31 pOut();
676 6         32 pdebug( 'leaving w/rv: %s', PPCDLEVEL1, $rv );
677              
678 6         117 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 1724 my $obj = shift;
689 3         5 my $proto = shift;
690 3         3 my ( %preg, @prval );
691              
692 3         7 pdebug( 'entering w/%s', PPCDLEVEL1, $proto );
693 3         67 pIn();
694              
695 3         16 %preg = $obj->settings->get('prototype registry');
696              
697 3 100 66     170 if ( defined $proto and length $proto ) {
698 2 50       4 if ( exists $preg{$proto} ) {
699 2         4 @prval = @{ $preg{$proto} };
  2         6  
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         2  
  2         5  
707             }
708              
709 3         6 pOut();
710 3         14 pdebug( 'leaving w/%s', PPCDLEVEL1, @prval );
711              
712 3         73 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 242 my $obj = shift;
723 11         11 my $msg = shift;
724              
725 11 50       18 if ( defined $msg ) {
726 11         80 $obj->settings->set( 'error', $msg );
727             } else {
728 0         0 $msg = $obj->settings->get('error');
729             }
730              
731 11         639 return $msg;
732             }
733              
734             1;
735              
736             __END__