File Coverage

blib/lib/Parse/PlainConfig.pm
Criterion Covered Total %
statement 368 386 95.3
branch 97 136 71.3
condition 35 48 72.9
subroutine 36 36 100.0
pod 9 9 100.0
total 545 615 88.6


line stmt bran cond sub pod time code
1             # Parse::PlainConfig -- Parsing Engine for Parse::PlainConfig
2             #
3             # (c) 2002 - 2023, Arthur Corliss ,
4             #
5             # $Id: lib/Parse/PlainConfig.pm, 3.06 2023/09/23 19:24:20 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 10     10   759682 use 5.008;
  10         125  
21              
22 10     10   57 use strict;
  10         19  
  10         198  
23 10     10   44 use warnings;
  10         18  
  10         251  
24 10     10   52 use vars qw($VERSION);
  10         18  
  10         846  
25              
26             ($VERSION) = ( q$Revision: 3.06 $ =~ /(\d+(?:\.(\d+))+)/sm );
27              
28 10     10   7683 use Class::EHierarchy qw(:all);
  10         93691  
  10         1897  
29 10     10   4829 use Parse::PlainConfig::Constants qw(:all);
  10         28  
  10         1492  
30 10     10   4551 use Parse::PlainConfig::Settings;
  10         27  
  10         464  
31 10     10   5329 use Text::ParseWords;
  10         13762  
  10         631  
32 10     10   5137 use Text::Tabs;
  10         8212  
  10         1064  
33 10     10   90 use Fcntl qw(:seek :DEFAULT);
  10         21  
  10         3764  
34 10     10   75 use Paranoid;
  10         48  
  10         491  
35 10     10   75 use Paranoid::Debug;
  10         29  
  10         779  
36 10     10   6574 use Paranoid::IO;
  10         155861  
  10         1042  
37 10     10   5704 use Paranoid::IO::Line;
  10         35722  
  10         736  
38 10     10   75 use Paranoid::Input qw(:all);
  10         24  
  10         1017  
39 10     10   5243 use Paranoid::Glob;
  10         53175  
  10         512  
40              
41 10     10   72 use base qw(Class::EHierarchy);
  10         21  
  10         832  
42              
43 10     10   81 use vars qw(@_properties @_methods %_parameters %_prototypes);
  10         26  
  10         940  
44              
45             #####################################################################
46             #
47             # Module code follows
48             #
49             #####################################################################
50              
51             sub _findAllClasses {
52              
53             # Purpose: Returns a list of all parent class names
54             # Returns: Array of scalars
55             # Usage: @pclasses = _findAllClasses(ref $obj);
56              
57 42     42   118 my $class = shift;
58 42         80 my ( @classes, %c, $c, @rv );
59              
60 42         137 subPreamble( PPCDLEVEL3, '$', $class );
61              
62             # Pull all parent class and recursively loop
63             {
64 10     10   67 no strict 'refs';
  10         18  
  10         2519  
  42         4066  
65              
66 42 50       81 if ( defined *{"${class}::ISA"}{ARRAY} ) {
  42         244  
67              
68 42         71 foreach $c ( @{ *{"${class}::ISA"}{ARRAY} } ) {
  42         51  
  42         155  
69 32         183 push @classes, _findAllClasses($c);
70             }
71              
72             push @classes, $class
73             if scalar @classes
74 30         139 or grep { $_ eq __PACKAGE__ }
75 42 100 100     137 @{ *{"${class}::ISA"}{ARRAY} };
  40         54  
  40         178  
76             }
77             }
78              
79             # Consolidate redundant entries
80 42         109 foreach $c (@classes) {
81 14 50       61 push @rv, $c unless exists $c{$c};
82 14         35 $c{$c} = 1;
83             }
84              
85 42         144 subPostamble( PPCDLEVEL3, '@', @rv );
86              
87 42         3279 return @rv;
88             }
89              
90             sub _initialize {
91              
92             # Purpose: Initialize config object and loads class defaults
93             # Returns: Boolean
94             # Usage: $rv = $obj->_initialize(@args);
95              
96 10     10   4942 my $obj = shift;
97 10         32 my $class = ref $obj;
98 10         20 my $rv = 1;
99 10         31 my ( @classes, $settings, %new, %_globals, %_parameters, %_prototypes );
100              
101 10         52 subPreamble( PPCDLEVEL1, '$$', $obj, $class );
102              
103             # Create & adopt the settings object
104 10         1888 $settings = new Parse::PlainConfig::Settings;
105 10         7722 $obj->adopt($settings);
106 10         1848 $settings->alias('settings');
107              
108             # Get a list of all parent classes
109 10         815 @classes = ( _findAllClasses($class) );
110              
111             # Read in class global settings
112 10 50       50 unless ( __PACKAGE__ eq $class ) {
113              
114 10         55 foreach $class (@classes) {
115 12 50       144 if ( defined *{"${class}::_globals"} ) {
  12         56  
116 12         61 pdebug( 'loading globals from %s', PPCDLEVEL2, $class );
117              
118             {
119 10     10   76 no strict 'refs';
  10         20  
  10         1415  
  12         492  
120              
121 12         37 %new = %{ *{"${class}::_globals"}{HASH} };
  12         19  
  12         104  
122             }
123              
124 12 100       66 if ( scalar keys %new ) {
125 10         78 foreach ( keys %new ) {
126 50         3015 $_globals{$_} = $new{$_};
127             pdebug( 'overriding %s with (%s)',
128 50         168 PPCDLEVEL3, $_, $_globals{$_} );
129 50 50       2263 $rv = 0 unless $settings->set( $_, $_globals{$_} );
130             }
131             }
132             }
133             }
134              
135 10         528 foreach $class (@classes) {
136 12 50       247 if ( defined *{"${class}::_parameters"} ) {
  12         58  
137 12         44 pdebug( 'loading parameters from %s', PPCDLEVEL2, $class );
138              
139             {
140 10     10   75 no strict 'refs';
  10         29  
  10         2109  
  12         496  
141              
142 12         26 %new = %{ *{"${class}::_parameters"}{HASH} };
  12         20  
  12         113  
143             }
144              
145 12 50       70 if ( scalar keys %new ) {
146 12         64 %_parameters = ( %_parameters, %new );
147 12         76 $settings->set( 'property types', %_parameters );
148 12         832 foreach ( keys %new ) {
149              
150 52         5573 pdebug( 'creating property %s', PPCDLEVEL3, $_ );
151 52 100       2402 unless (
    50          
152             _declProperty(
153             $obj, $_,
154             CEH_PUB | (
155             $_parameters{$_} == PPC_HDOC
156             ? PPC_SCALAR
157             : $_parameters{$_}
158             ),
159             )
160             ) {
161 0         0 $rv = 0;
162 0         0 last;
163             }
164              
165             # merge property regex
166             $settings->merge(
167 52         2136 'property regexes',
168             $_,
169 52         176 qr#(\s*)(\Q$_\E)\s*\Q@{[ $settings->delimiter ]}\E\s*(.*)#s
170             );
171             }
172             }
173             }
174              
175 12 50       1448 if ( defined *{"${class}::_prototypes"} ) {
  12         68  
176 12         48 pdebug( 'loading prototypes from %s', PPCDLEVEL2, $class );
177              
178             {
179 10     10   78 no strict 'refs';
  10         19  
  10         32939  
  12         522  
180              
181 12         25 %new = %{ *{"${class}::_prototypes"}{HASH} };
  12         21  
  12         83  
182             }
183              
184 12 50       48 if ( scalar keys %new ) {
185 12         96 %_prototypes = ( %_prototypes, %new );
186 12         76 $settings->set( 'prototypes', %_prototypes );
187 12         824 foreach ( keys %new ) {
188              
189             # merge property meta-data
190 22         1293 $settings->merge(
191             'prototype regexes',
192             $_,
193 22         65 qr#(\s*)(\Q$_\E)\s+(\S+)\s*\Q@{[ $settings->delimiter ]}\E\s*(.*)#s
194             );
195             }
196             }
197             }
198             }
199             }
200              
201             # Store all parent classes
202 10         1247 $settings->set( '_ppcClasses', @classes );
203              
204             # Load the defaults
205 10         643 $rv = $obj->parse( $obj->default );
206              
207 10         258 subPostamble( PPCDLEVEL1, '$', $rv );
208              
209 10         1311 return $rv;
210             }
211              
212             sub settings {
213              
214             # Purpose: Returns object reference to the settings object
215             # Returns: Object reference
216             # Usage: $settings = $obj->settings;
217              
218 203     203 1 324 my $obj = shift;
219              
220 203         540 return $obj->getByAlias('settings');
221             }
222              
223             sub _default {
224              
225             # Purpose: Returns the DATA block from the calling
226             # Returns: Array
227             # Usage: @lines = $obj->_default;
228              
229 23     23   56 my $obj = shift;
230 23         56 my $class = shift;
231 23         52 my ( $fn, @chunk, @lines );
232              
233 23         84 subPreamble( PPCDLEVEL2, '$', $obj );
234              
235 23         2119 $class =~ s#::#/#sg;
236 23         63 $class .= '.pm';
237 23         72 $fn = $INC{$class};
238              
239 23         71 pdebug( 'attempting to read from %s', PPCDLEVEL3, $fn );
240 23 50       929 if ( popen( $fn, O_RDONLY ) ) {
241              
242             # Read in file
243 23   66     22767 while ( sip( $fn, @chunk ) and @chunk ) { push @lines, @chunk }
  23         95845  
244              
245             # empty all lines prior to __DATA__
246 23   100     74043 while ( @lines and $lines[0] !~ /^\s*__DATA__\s*$/s ) {
247 711         2207 shift @lines;
248             }
249 23         55 shift @lines;
250              
251             # empty all lines after __END__
252 23 100 100     313 if ( @lines and grep /^\s*__END__\s*$/s, @lines ) {
253 12   66     59 while ( @lines and $lines[-1] !~ /^\s*__END__\s*$/s ) {
254 48         165 pop @lines;
255             }
256 12         23 pop @lines;
257             }
258 23         93 pseek( $fn, 0, SEEK_SET );
259             }
260              
261 23         11485 subPostamble( PPCDLEVEL2, '@', @lines );
262              
263 23 50       3146 return wantarray ? @lines : join '', @lines;
264             }
265              
266             sub default {
267              
268             # Purpose: Returns the DATA block from the specified class,
269             # or the object class if not specified
270             # Returns: Array
271             # Usage: @lines = $obj->default;
272             # Usage: @lines = $obj->default($class);
273              
274 19     19 1 1528 my $obj = shift;
275 19         107 my @classes = $obj->getByAlias('settings')->get('_ppcClasses');
276 19         1739 my ( $class, @rv );
277              
278 19         81 subPreamble( PPCDLEVEL1, '$', $obj );
279              
280 19         2012 foreach $class (@classes) {
281 23         126 push @rv, $obj->_default($class);
282             }
283              
284 19         97 subPostamble( PPCDLEVEL1, '@', @rv );
285              
286 19         2603 return @rv;
287             }
288              
289             sub get {
290              
291             # Purpose: Returns the value of the specified parameter
292             # Returns: Scalar/List/Hash
293             # Usage: $val = $obj->get('foo');
294              
295 78     78 1 28342 my $obj = shift;
296 78         137 my $p = shift;
297 78         183 my $valp;
298              
299 78         264 subPreamble( PPCDLEVEL1, '$$', $obj, $p );
300              
301 78 50       9011 if ( defined $p ) {
302 78         269 $valp = scalar grep /^\Q$p\E$/s, $obj->properties;
303             }
304             $obj->error(
305 78 100       4311 pdebug( 'specified invalid parameter name: %s', PPCDLEVEL1, $p ) )
306             unless $valp;
307              
308 78         241 subPostamble( PPCDLEVEL1, '' );
309              
310 78 100       4915 return $valp ? $obj->SUPER::get($p) : undef;
311             }
312              
313             sub set {
314              
315             # Purpose: Assigns the desired values to the specified parameter
316             # Returns: Boolean
317             # Usage: $rv = $obj->set($prop, @values);
318              
319 17     17 1 3187 my $obj = shift;
320 17         45 my $p = shift;
321 17         48 my @vals = @_;
322 17         57 my %propTypes = $obj->settings->propertyTypes;
323 17         957 my ( $valp, $rv );
324              
325 17         63 subPreamble( PPCDLEVEL1, '$$@', $obj, $p, @vals );
326              
327 17 50       2319 if ( defined $p ) {
328 17         80 $valp = scalar grep /^\Q$p\E$/s, $obj->properties;
329             }
330             $obj->error(
331 17 100       952 pdebug( 'specified invalid parameter name: %s', PPCDLEVEL1, $p ) )
332             unless $valp;
333              
334 17 100       71 if ($valp) {
335 13 50       48 if (@vals) {
336              
337             # Set whatever's assigned
338 13         47 $rv = $obj->SUPER::set( $p, @vals );
339             } else {
340              
341             # Assume that no values means empty/undef
342 0 0 0     0 if ( $propTypes{$p} == PPC_SCALAR
343             or $propTypes{$p} == PPC_HDOC ) {
344 0         0 $rv = $obj->SUPER::set( $p, undef );
345             } else {
346 0         0 $rv = $obj->empty($p);
347             }
348             }
349             }
350              
351 17 100       977 subPostamble( PPCDLEVEL1, '$', $valp ? $rv : undef );
352              
353 17 100       1848 return $valp ? $rv : undef;
354             }
355              
356             sub _snarfBlock (\@\$\$$) {
357              
358             # Purpose: Finds and returns the block with the value
359             # string extracted.
360             # Returns: Boolean
361             # Usage: $rv = _snarfBlock(@lines, $val);
362              
363 138     138   225 my $lref = shift;
364 138         219 my $pref = shift;
365 138         184 my $vref = shift;
366 138         205 my $settings = shift;
367 138         474 my $obj = $settings->parent;
368 138         2396 my %regex = $settings->propertyRegexes;
369 138         7409 my %pregex = $settings->prototypeRegexes;
370 138         6413 my %propTypes = $settings->propertyTypes;
371 138         6677 my %prototypes = $settings->prototypes;
372 138         6350 my $subi = $settings->subindentation;
373 138         5889 my ( $rv, $indent, $prop, $proto, $trailer, $iwidth, $line, $preg );
374              
375 138         426 subPreamble( PPCDLEVEL2, '$$$$', $lref, $pref, $vref, $settings );
376              
377             # Match line to a property/prototype declaration
378             #
379             # First try to match against properties
380 138         16556 foreach ( keys %regex ) {
381 590 100       11374 if ( $$lref[0] =~ /^$regex{$_}$/s ) {
382 79         417 ( $indent, $prop, $trailer ) = ( $1, $2, $3 );
383 79         134 $rv = 1;
384 79         153 shift @$lref;
385 79         184 last;
386             }
387             }
388 138 50 66     709 unless ( $rv and defined $prop and length $prop ) {
      66        
389 59         183 foreach ( keys %pregex ) {
390 99 100       1694 if ( $$lref[0] =~ /^$pregex{$_}$/s ) {
391 54         286 ( $indent, $proto, $prop, $trailer ) = ( $1, $2, $3, $4 );
392 54         89 $rv = 1;
393 54         127 shift @$lref;
394 54         134 last;
395             }
396             }
397             }
398              
399             # Define all prototyped properties
400 138 100 66     490 if ( defined $proto and length $proto ) {
401 54 50 33     297 if ( defined $prop and length $prop ) {
402              
403 54 100       152 if ( exists $regex{$prop} ) {
404 3         14 $obj->error(
405             pdebug(
406             'token (%s) for prototype (%s) attempted to override property',
407             PPCDLEVEL1,
408             $prop,
409             $proto
410             ) );
411 3         8 $rv = 0;
412             } else {
413              
414 51 100       115 if ( exists $propTypes{$prop} ) {
415              
416             # Make sure they haven't been previously defined,
417             # or if they have, they match the same type
418 27 100       104 unless ( $propTypes{$prop} == $prototypes{$proto} ) {
419 3         9 $rv = 0;
420 3         12 $obj->error(
421             pdebug(
422             'prototype mismatch with previous declaration: %s',
423             PPCDLEVEL1,
424             $proto
425             ) );
426             pdebug( 'current type: %s prototype: %s',
427             PPCDLEVEL1, $propTypes{$prop},
428 3         17 $prototypes{$proto} );
429             }
430             } else {
431              
432             # Create a new property
433 24         113 pdebug( 'creating property based on prototype %s: %s',
434             PPCDLEVEL3, $proto, $prop );
435              
436             $rv = _declProperty(
437             $obj, $prop,
438             CEH_PUB | (
439             $prototypes{$proto} == PPC_HDOC
440             ? PPC_SCALAR
441 24 50       1233 : $prototypes{$proto}
442             ),
443             );
444              
445             # Record the prop type
446 24 50       1056 if ($rv) {
447             $settings->merge( 'property types',
448 24         194 $prop, $propTypes{$prop} = $prototypes{$proto} );
449 24         1366 ($preg) =
450             $settings->subset( 'prototype registry', $proto );
451 24 100       1231 $preg = [] unless defined $preg;
452 24         56 push @$preg, $prop;
453 24         63 $settings->merge( 'prototype registry',
454             $proto => $preg );
455             } else {
456 0         0 $obj->error(
457             pdebug(
458             'failed to declare prototype: %s %s',
459             PPCDLEVEL1, $proto, $prop
460             ) );
461             }
462             }
463             }
464             } else {
465 0         0 $obj->error(
466             pdebug(
467             'invalid token used for prototype %s: %s', PPCDLEVEL1,
468             $proto, $prop
469             ) );
470 0         0 $rv = 0;
471             }
472             }
473              
474             # Grab additional lines as needed
475 138 100       1473 if ($rv) {
476              
477 127 100       311 if ( $propTypes{$prop} == PPC_HDOC ) {
478              
479             # Snarf all lines until we hit the HDOC marker
480 18         45 $rv = 0;
481 18         81 while (@$lref) {
482 72         179 $line = shift @$lref;
483 72 100       158 if ( $line =~ /^\s*\Q@{[ $settings->hereDoc ]}\E\s*$/s ) {
  72         187  
484 18         862 $rv = 1;
485 18         49 last;
486             } else {
487 54         2986 $line =~ s/^\s{1,$subi}//s;
488 54         230 $trailer .= $line;
489             }
490             }
491              
492             # Error out if we never found the marker
493             $obj->error(
494 18 50       77 pdebug( 'failed to find the here doc marker', PPCDLEVEL1 ) )
495             unless $rv;
496              
497             } else {
498              
499             # All non-HDOCs are handled the same
500 109 50       272 $iwidth = defined $indent ? length $indent : 0;
501 109         255 while (@$lref) {
502              
503             # We're done if this is a line break
504 180 100       715 last if $$lref[0] =~ /^\s*$/s;
505              
506             # We're also done if indentation isn't greater
507             # than the parameter declaration line
508 93         312 ($indent) = ( $$lref[0] =~ /^(\s*)/s );
509 93 100 66     374 last if !defined $indent or $iwidth >= length $indent;
510              
511             # Append content to the trailer
512 72         171 $line = shift @$lref;
513 72         448 $line =~ s/^\s{1,$subi}//s;
514 72         239 pchomp($line);
515 72         1667 $trailer .= $line;
516             }
517             }
518 127 50       757 $trailer =~ s/\s+$//s if defined $trailer;
519             }
520              
521 138 100       361 if ($rv) {
522 127         457 pchomp($trailer);
523 127         3547 ( $$pref, $$vref ) = ( $prop, $trailer );
524 127         340 pdebug( 'extracted value for %s: %s', PPCDLEVEL3, $prop, $trailer );
525             }
526              
527 138         6410 subPostamble( PPCDLEVEL2, '$', $rv );
528              
529 138         13442 return $rv;
530             }
531              
532             sub _snarfProp {
533              
534             # Purpose: Takes the property value and parses according to its type,
535             # then merges it
536             # Returns: Boolean
537             # Usage: $rv = _snarfProp($obj, $prop, $val);
538              
539 127     127   206 my $obj = shift;
540 127         203 my $prop = shift;
541 127         261 my $val = shift;
542 127         346 my $settings = $obj->settings;
543 127         4787 my %propTypes = $settings->propertyTypes;
544 127         6724 my $ldelim = $settings->listDelimiter;
545 127         5551 my $hdelim = $settings->hashDelimiter;
546 127         5408 my $rv = 1;
547 127         188 my @elements;
548              
549 127         402 subPreamble( PPCDLEVEL2, '$$$', $obj, $prop, $val );
550              
551 127 100 100     15900 if ( $propTypes{$prop} == PPC_HDOC
552             or $propTypes{$prop} == PPC_SCALAR ) {
553              
554             # Here Docs and scalars are merged as-is
555 55         207 $obj->SUPER::set( $prop, $val );
556              
557             } else {
558              
559 72 100       203 if ( $propTypes{$prop} == PPC_ARRAY ) {
560              
561             # Split into a list
562 54         385 @elements = quotewords( qr/\Q$ldelim\E/s, 0, $val );
563 54         6655 foreach (@elements) { s/^\s+//s; s/\s+$//s; }
  123         261  
  123         295  
564              
565             } else {
566              
567             # Split into a hash
568 18         339 @elements =
569             quotewords( qr/(?:\Q$ldelim\E|\Q$hdelim\E)/s, 0, $val );
570 18         6726 foreach (@elements) { s/^\s+//s; s/\s+$//s; }
  144         291  
  144         333  
571              
572             }
573              
574             # merge the list value
575 72         252 pdebug( 'storing in %s: %s', PPCDLEVEL3, $prop, @elements );
576 72         4755 $obj->empty($prop);
577 72         3342 $obj->SUPER::set( $prop, @elements );
578             }
579              
580 127         8189 subPostamble( PPCDLEVEL2, '$', $rv );
581              
582 127         12983 return $rv;
583             }
584              
585             sub parse {
586              
587             # Purpose: Parses passed content and extracts values
588             # Returns: Boolean
589             # Usage: $rv = $obj->parse(@lines);
590              
591 31     31 1 2441 my $obj = shift;
592 31         193 my @lines = @_;
593 31         101 my $settings = $obj->settings;
594 31         1259 my $delim = $settings->delimiter;
595 31         1559 my $cre = qr#^\s*\Q@{[ $settings->comment ]}\E#s;
  31         96  
596 31         1782 my $rv = 1;
597 31         67 my ( $text, $prop, $value, $glob );
598              
599 31         119 subPreamble( PPCDLEVEL1, '$@', $obj, @lines );
600              
601             # Some preprocessing of lines
602 31 100       4335 if (@lines) {
603 29         110 $tabstop = $settings->tabStop;
604 29         1477 @lines = expand(@lines);
605 29         5350 foreach (@lines) {
606 559 100 66     4501 $text =
607             ( defined $text and length $text )
608             ? join "\n", $text, split NEWLINE_REGEX, $_
609             : join "\n", split NEWLINE_REGEX, $_;
610             }
611             }
612              
613 31         112 while (@lines) {
614              
615             # Skip comments and empty lines
616 415 100 100     2405 if ( $lines[0] =~ /^$cre/s
617 260         2257 or $lines[0] =~ /^\s*(?:@{[ NEWLINE_REGEX ]})?$/s ) {
618 276         482 shift @lines;
619 276         711 next;
620             }
621              
622             # Handle "include" statements
623 139 100       502 if ( $lines[0] =~ /^\s*include\s+(.+?)\s*$/s ) {
624 1         15 $glob = new Paranoid::Glob globs => [$1];
625 1         656 shift @lines;
626 1 50       7 $rv = 0 unless $obj->read($glob);
627 1         6 next;
628             }
629              
630             # See if we have property block
631 138 100       377 if ( _snarfBlock( @lines, $prop, $value, $settings ) ) {
632              
633             # Parse the block (but preserve earlier errors)
634 127 50       306 $rv = 0 unless _snarfProp( $obj, $prop, $value );
635              
636             } else {
637              
638 11         70 pdebug( 'discarding invalid input: %s', PPCDLEVEL1, $lines[0] );
639 11         452 shift @lines;
640 11         38 $rv = 0;
641             }
642             }
643              
644 31         124 subPostamble( PPCDLEVEL1, '$', $rv );
645              
646 31         3036 return $rv;
647             }
648              
649             sub read {
650              
651             # Purpose: Reads the passed file(s)
652             # Returns: Boolean
653             # Usage: $rv = $obj->read($filename);
654              
655 5     5 1 1494 my $obj = shift;
656 5         12 my $source = shift;
657 5         207 my ( $rv, @lines );
658              
659 5         26 subPreamble( PPCDLEVEL1, '$$', $obj, $source );
660              
661 5 50       600 if (@_) {
    100          
    50          
662              
663             # Work all entries passed if handed a list
664 0         0 $rv = $obj->read($source);
665 0 0       0 foreach (@_) { $rv = 0 unless $obj->read($_) }
  0         0  
666              
667             } elsif ( ref $source eq '' ) {
668              
669             # Treat all non-reference files as filenames
670 4 50       17 if ( slurp( $source, @lines ) ) {
671 4         21431 $rv = $obj->parse(@lines);
672 4 50       21 pdebug( 'errors parsing %s', PPCDLEVEL1, $source ) unless $rv;
673             } else {
674 0         0 $obj->error(
675             pdebug(
676             'failed to read %s: %s', PPCDLEVEL1,
677             $source, Paranoid::ERROR() ) );
678             }
679              
680             } elsif ( ref $source eq 'Paranoid::Glob' ) {
681              
682             # Handle Paranoid globs specially
683 1         2 $rv = 1;
684 1 50       4 foreach (@$source) { $rv = 0 unless $obj->read($_) }
  1         4  
685              
686             } else {
687              
688             # Handle everything else as if it was a glob
689 0 0       0 if ( slurp( $source, @lines ) ) {
690 0         0 $rv = $obj->parse(@lines);
691 0 0       0 pdebug( 'errors parsing %s', PPCDLEVEL1, $source ) unless $rv;
692             } else {
693 0         0 $obj->error(
694             pdebug(
695             'failed to read %s: %s', PPCDLEVEL1,
696             $source, Paranoid::ERROR() ) );
697             }
698             }
699              
700 5         18 subPostamble( PPCDLEVEL1, '$', $rv );
701              
702 5         504 return $rv;
703             }
704              
705             sub reset {
706              
707             # Purpose: Resets configuration state to defaults
708             # Returns: Boolean
709             # Usage: $rv = $obj->reset;
710              
711 7     7 1 5136 my $obj = shift;
712 7         39 my $settings = $obj->settings;
713 7         301 my %propTypes = $settings->propertyTypes;
714 7         389 my $rv;
715              
716 7         39 subPreamble( PPCDLEVEL1, '$', $obj );
717              
718             # empty all property values
719 7         817 foreach ( keys %propTypes ) {
720 51         2522 pdebug( 'clearing merged values for %s', PPCDLEVEL2, $_ );
721 51 100 100     2262 if ( $propTypes{$_} == PPC_SCALAR or $propTypes{$_} == PPC_HDOC ) {
722 25         75 $obj->SUPER::set( $_, undef );
723             } else {
724 26         91 $obj->empty($_);
725             }
726             }
727 7         346 $rv = $obj->parse( $obj->default );
728              
729 7         59 subPostamble( PPCDLEVEL1, '$', $rv );
730              
731 7         790 return $rv;
732             }
733              
734             sub prototyped {
735              
736             # Purpose: Returns a list of properties that were created with
737             # prototypes
738             # Returns: Array
739             # Usage: @protos = $obj->prototyped;
740             # Usage: @protos = $obj->prototyped($proto);
741              
742 6     6 1 5387 my $obj = shift;
743 6         11 my $proto = shift;
744 6         12 my ( %preg, @prval );
745              
746 6         21 subPreamble( PPCDLEVEL1, '$$', $obj, $proto );
747              
748 6         739 %preg = $obj->settings->get('prototype registry');
749              
750 6 100 66     572 if ( defined $proto and length $proto ) {
751 4 50       14 if ( exists $preg{$proto} ) {
752 4         7 @prval = @{ $preg{$proto} };
  4         10  
753             } else {
754 0         0 pdebug( 'no prototype properties declared w/%s',
755             PPCDLEVEL2, $proto );
756             }
757             } else {
758 2         19 pdebug( 'dumping all declared prototyped properties', PPCDLEVEL2 );
759 2         81 foreach ( keys %preg ) { push @prval, @{ $preg{$_} } }
  5         9  
  5         13  
760             }
761              
762 6         22 subPostamble( PPCDLEVEL1, '@', @prval );
763              
764 6         601 return @prval;
765             }
766              
767             sub error {
768              
769             # Purpose: Sets/gets the last error message
770             # Returns: Scalar/undef
771             # Usage: $errStr = $obj->error;
772             # Usage: $errStr = $obj->error($msg);
773              
774 15     15 1 706 my $obj = shift;
775 15         28 my $msg = shift;
776              
777 15 50       42 if ( defined $msg ) {
778 15         36 $obj->settings->set( 'error', $msg );
779             } else {
780 0         0 $msg = $obj->settings->get('error');
781             }
782              
783 15         1597 return $msg;
784             }
785              
786             1;
787              
788             __END__