File Coverage

blib/lib/Config/Wild.pm
Criterion Covered Total %
statement 132 175 75.4
branch 58 96 60.4
condition 14 24 58.3
subroutine 24 31 77.4
pod 9 9 100.0
total 237 335 70.7


line stmt bran cond sub pod time code
1             package Config::Wild;
2              
3             # ABSTRACT: parse an application configuration file with wildcard keywords
4              
5 4     4   117044 use strict;
  4         14  
  4         120  
6 4     4   24 use warnings;
  4         11  
  4         216  
7              
8             our $VERSION = '2.02';
9              
10 4     4   1965 use custom::failures __PACKAGE__ . '::Error' => [ 'exists', 'read', 'parse' ];
  4         37000  
  4         57  
11              
12 4     4   1074 use Carp;
  4         13  
  4         334  
13              
14 4     4   30 use List::Util qw[ first ];
  4         13  
  4         488  
15 4     4   2038 use File::pushd;
  4         87591  
  4         266  
16 4     4   2859 use Path::Tiny qw[ path cwd ];
  4         45785  
  4         349  
17              
18 4     4   1173 use Try::Tiny;
  4         4562  
  4         278  
19              
20 4     4   1516 use Log::Any '$log';
  4         25800  
  4         28  
21              
22 4     4   8186 use namespace::clean;
  4         53903  
  4         34  
23              
24             sub new {
25 64     64 1 38816 my $this = shift;
26 64   33     436 my $class = ref( $this ) || $this;
27              
28 64         396 my %attr = (
29             UNDEF => undef, # function to call from value when
30             # keyword not defined
31             dir => undef,
32             path => undef,
33             ExpandWild => 0, # match wildcards when expanding
34             );
35              
36 64 100       314 my $attr = ref $_[-1] eq 'HASH' ? pop @_ : {};
37              
38             ## no critic (ProhibitAccessOfPrivateData)
39             $attr{$_} = $attr->{$_}
40 64         284 for
41 43 50       308 grep { CORE::exists( $attr{$_} ) or croak( "unknown attribute: $_\n" ) }
42             keys %$attr;
43              
44             croak( "options dir and path may not both be specified\n" )
45 64 100 100     496 if defined $attr{dir} && defined $attr{path};
46              
47 63         338 my $self = {
48             wild => [], # regular expression keywords
49             abs => {}, # absolute keywords
50             attr => \%attr,
51             };
52              
53 63         174 bless $self, $class;
54              
55 63         171 my $file = shift;
56              
57 63 50       247 croak( "extra arguments passed to new. forgot a hashref?\n" )
58             if @_;
59              
60 63 100       320 $self->load( $file )
61             if $file;
62              
63 62         1426 return $self;
64             }
65              
66             sub load {
67 63     63 1 281 my ( $self, $file ) = @_;
68              
69 63 50       205 croak( 'no file specified' )
70             if !defined $file;
71              
72             my $cwd
73             = defined $self->{attr}{dir}
74             ? pushd( $self->{attr}{dir} )
75 63 100       423 : cwd;
76              
77 63         5608 $self->_read_config( $file, path( $cwd ) );
78              
79             }
80              
81             # note that Path::Tiny::path will strip ./ from ./file, so
82             # don't convert file to a P::T object until after
83             # checking for ./
84             sub _read_config {
85              
86 78     78   3403 my $self = shift;
87              
88 78         255 my ( $file, $cwd ) = @_;
89              
90 78         253 my $file_p = path( $file );
91              
92              
93             # relative to current dir or parent
94 78 100 100     5723 if ( !defined $self->{attr}{dir} && $file =~ m|^[.]{1,2}/| ) {
    100 100        
95              
96 12         65 $file_p = $cwd->child( $file );
97              
98             }
99              
100             elsif ( $self->{attr}{path} && !$file_p->is_absolute ) {
101              
102             SEARCH: {
103 20         847 $log->info( "Searching for configuration file $file_p" );
  20         100  
104              
105 20         258 for my $path ( @{ $self->{attr}{path} } ) {
  20         79  
106              
107 32         500 $file_p = path( $path, $file );
108 32 100       1700 last SEARCH if $file_p->is_file;
109              
110             }
111              
112             _log_fatal( 'Config::Wild::Error::exists', $file, "unable to find file in "
113 0         0 . join( ':', @{ $self->{attr}{path} } ) );
  0         0  
114              
115             }
116              
117             }
118              
119 78 100       1765 _log_fatal( 'Config::Wild::Error::exists', $file_p, 'unable to find file' )
120             unless $file_p->is_file;
121              
122 77 50       2176 $log->info( "Reading configuration file ", $file_p->absolute->canonpath )
123             if $log->is_info;
124              
125 77         1177 my @lines;
126              
127 77         533 local $! = 0;
128             try {
129 77     77   4972 @lines = $file_p->lines( { chomp => 1 } );
130             }
131             catch {
132 0     0   0 _log_fatal( 'Config::Wild::Error::read', $file_p, $_ );
133 77         726 };
134              
135             try {
136              
137 77     77   4423 my $line_idx = 1;
138 77         239 for my $line ( @lines ) {
139              
140             # ignore comment lines or empty lines
141 149 100       1072 next if $line =~ /^\s*\#|^\s*$/;
142              
143 131 100       473 if ( $line =~ /^\s*%include\s+(.*)/ ) {
144              
145 15         68 $self->_read_config( $1, $file_p->parent );
146              
147             }
148              
149             else {
150              
151 116 50       399 $self->_parsepair( $line )
152             or die( "can't parse line $line_idx" );
153             }
154              
155             }
156             continue {
157 149         802 ++$line_idx;
158             }
159              
160             }
161             catch {
162 0     0   0 _log_fatal( 'Config::Wild::Error::parse', $file_p, $_ );
163 77         19674 };
164              
165             }
166              
167             sub load_cmd {
168 0     0 1 0 my ( $self, $argv, $attr ) = @_;
169 0         0 my $keyword;
170              
171 0 0       0 $attr = {} unless defined $attr;
172              
173 0         0 foreach ( @$argv ) {
174 0 0 0     0 if ( $$attr{Exists}
      0        
175             && ( $keyword = ( $self->_splitpair( $_ ) )[0] )
176             && !$self->_exists( $keyword ) )
177             {
178 0         0 croak( "keyword `$keyword' doesn't exist" );
179             }
180              
181 0 0       0 $self->_parsepair( $_ ) or croak( "can't parse line $_" );
182             }
183              
184 0         0 return;
185             }
186              
187              
188             sub set {
189 116     116 1 310 my ( $self, $keyword, $value ) = @_;
190              
191 116 50 33     763 die unless defined( $keyword ) and defined( $value );
192             # so, is it a regular expression or not?
193 116 100       363 if ( $keyword =~ /\{/ ) {
194             # quote all characters outside of curly brackets.
195             $keyword = join(
196             '',
197             map {
198 4 100       20 substr( $_, 0, 1 ) ne '{'
  8         36  
199             ? quotemeta( $_ )
200             : substr( $_, 1, -1 )
201             } $keyword =~ /( [^{}]+ | {[^\}]*} )/gx
202             );
203              
204 4         10 unshift @{ $self->{wild} }, [ $keyword, $value ];
  4         17  
205             }
206             else {
207 112         441 $self->{abs}->{$keyword} = $value;
208             }
209             }
210              
211             # for backwards compatibility
212             #pod =pod
213             #pod
214             #pod =begin pod_coverage
215             #pod
216             #pod =head3 value
217             #pod
218             #pod =end pod_coverage
219             #pod
220             #pod =cut
221              
222             *value = \&get;
223              
224             sub get {
225 92     92 1 1256 my ( $self, $keyword ) = @_;
226              
227 92 50       309 croak( 'no keyword specified' )
228             if !defined $keyword;
229              
230              
231             return $self->_expand( $self->{abs}->{$keyword} )
232 92 100       483 if CORE::exists( $self->{abs}->{$keyword} );
233              
234 2         5 foreach ( @{ $self->{wild} } ) {
  2         5  
235             ## no critic (ProhibitAccessOfPrivateData)
236 3 100       60 return $self->_expand( $_->[1] ) if $keyword =~ /$_->[0]/;
237             }
238              
239             return $self->{attr}{UNDEF}->( $keyword )
240 0 0       0 if defined $self->{attr}{UNDEF};
241              
242 0         0 return;
243             }
244              
245             sub getbool {
246              
247 7     7 1 7163 require Lingua::Boolean::Tiny;
248              
249 7         31536 my $self = shift;
250              
251 7         24 return Lingua::Boolean::Tiny::boolean( $self->get( @_ ) );
252             }
253              
254             sub delete {
255 1     1 1 3 my ( $self, $keyword ) = @_;
256              
257 1 50       5 croak( 'no keyword specified' )
258             if !defined $keyword;
259              
260 1 50       4 if ( CORE::exists $self->{abs}->{$keyword} ) {
261 1         4 delete $self->{abs}->{$keyword};
262             }
263             else {
264             ## no critic (ProhibitAccessOfPrivateData)
265 0         0 $self->{wild} = grep( $_->[0] ne $keyword, @{ $self->{wild} } );
  0         0  
266             }
267 1         2 1;
268             }
269              
270             sub exists {
271 0     0 1 0 my ( $self, $keyword ) = @_;
272              
273 0 0       0 croak( 'no keyword specified' )
274             if !defined $keyword;
275              
276 0         0 return $self->_exists( $keyword );
277             }
278              
279             sub _exists {
280 0     0   0 my ( $self, $keyword ) = @_;
281              
282 0 0       0 return 1 if CORE::exists( $self->{abs}->{$keyword} );
283              
284 0         0 foreach ( @{ $self->{wild} } ) {
  0         0  
285 0 0       0 return 1 if $keyword =~ /$_->[0]/;
286             }
287              
288 0         0 undef;
289              
290             }
291              
292              
293             sub set_attr {
294 0     0 1 0 my ( $self, $attr ) = @_;
295 0         0 my ( $key, $value );
296              
297 0         0 while ( ( $key, $value ) = each %{$attr} ) {
  0         0  
298              
299             croak( "unknown attribute: `$key'" )
300 0 0       0 unless CORE::exists $self->{attr}{$key};
301              
302              
303 0         0 $self->{attr}{$key} = $value;
304             }
305              
306             }
307              
308             #========================================================================
309             #
310             # AUTOLOAD
311             #
312             # Autoload function called whenever an unresolved object method is
313             # called. If the method name relates to a defined VARIABLE, we patch
314             # in $self->get() and $self->set() to magically update the varaiable
315             # (if a parameter is supplied) and return the previous value.
316             #
317             # Thus the function can be used in the folowing ways:
318             # $cfg->variable(123); # set a new value
319             # $foo = $cfg->variable(); # get the current value
320             #
321             # Returns the current value of the variable, taken before any new value
322             # is set. Throws an exception if the variable isn't defined (i.e. doesn't
323             # exist rather than exists with an undef value) and returns undef.
324             #
325             #========================================================================
326              
327             our $AUTOLOAD;
328             sub AUTOLOAD {
329 64     64   48812 my $self = shift;
330 64         159 my $keyword;
331 64         159 my ( $oldval, $newval );
332              
333              
334             # splat the leading package name
335 64         524 ( $keyword = $AUTOLOAD ) =~ s/.*:://;
336              
337             # ignore destructor
338 64 100       636 $keyword eq 'DESTROY' && return;
339              
340 1 50       6 if ( CORE::exists( $self->{abs}->{$keyword} ) ) {
341 1         7 $oldval = $self->_expand( $self->{abs}->{$keyword} );
342             }
343             else {
344 0         0 my $found = 0;
345 0         0 foreach ( @{ $self->{wild} } ) {
  0         0  
346             ## no critic (ProhibitAccessOfPrivateData)
347 0 0       0 $oldval = $self->_expand( $_->[1] ), $found++, last
348             if $keyword =~ /$_->[0]/;
349             }
350 0 0       0 if ( !$found ) {
351             return $self->{attr}{UNDEF}->( $keyword )
352 0 0       0 if defined( $self->{attr}{UNDEF} );
353              
354 0         0 croak( "$keyword doesn't exist" );
355             }
356             }
357              
358             # set a new value if a parameter was supplied
359 1 50       6 $self->set( $keyword, $newval )
360             if defined( $newval = shift );
361              
362             # return old value
363 1         9 return $oldval;
364             }
365              
366             sub _expand {
367 93     93   279 my ( $self, $value ) = @_;
368              
369 93         204 my $stop = 0;
370 93         289 until ( $stop ) {
371 108         236 $stop = 1;
372              
373             # expand ${VAR} as environment variables
374 108 100       429 $value =~ s/\$\{(\w+)\}/defined $ENV{$1} ? $ENV{$1} : ''/ge
  3 100       34  
375             and $stop = 0;
376              
377             # expand $(VAR) as a ConfigWild variable
378 108 100       406 $value =~ s{\$\((\w+)\)} {
379 10         37 my $var = $1;
380 10 100 100     65 if ( defined $self->{abs}->{$var} ) {
    100          
381 7         48 $self->{abs}->{$var};
382             }
383              
384             elsif ( $self->{attr}{ExpandWild}
385 3     3   37 && (my $kwd = first { $var =~ $_->[0] } @{ $self->{wild} } )
  2         16  
386             ) {
387              
388 1         6 $kwd->[1];
389              
390             }
391              
392             else {
393              
394 2         9 ''
395             }
396              
397             }gex
398             and $stop = 0;
399              
400             # expand any unparenthesised/braced variables,
401             # e.g. "$var", as ConfigWild vars or environment variables.
402             # leave untouched if not
403 108 100       467 $value =~ s{\$(\w+)} {
404             defined $self->{abs}->{$1} ? $self->{abs}->{$1} :
405 2 50       28 defined $ENV{$1} ? $ENV{$1} :
    100          
406             "\$$1"
407             }gex
408             and $stop = 0;
409             }
410             # return the value
411 93         643 $value;
412             }
413              
414             sub _splitpair {
415 0     0   0 my ( $self, $pair ) = @_;
416 0         0 my ( $keyword, $value );
417              
418 0         0 $pair =~ s/^\s+//;
419 0         0 $pair =~ s/\s+$//;
420              
421 0 0       0 return 2 != ( ( $keyword, $value ) = $pair =~ /([^=\s]*)\s*=\s*(.*)/ )
422             ? ()
423             : ( $keyword, $value );
424             }
425              
426             sub _parsepair {
427 116     116   293 my ( $self, $pair ) = @_;
428              
429 116         244 my ( $keyword, $value );
430              
431 116         329 $pair =~ s/^\s+//;
432 116         431 $pair =~ s/\s+$//;
433              
434             return
435 116 50       912 if 2 != ( ( $keyword, $value ) = $pair =~ /([^=\s]*)\s*=\s*(.*)/ );
436              
437 116         466 $self->set( $keyword, $value );
438 116         406 1;
439             }
440              
441              
442             sub _log_fatal {
443              
444 1     1   48 my ( $package, $file, @err ) = @_;
445              
446 1 50       9 $file = $file->absolute->canonpath if ref $file;
447              
448 1         152 my $err = join( '', $file, ': ', @err );
449              
450 1         23 $log->error( $err );
451 1         127 $package->throw( $err );
452              
453             }
454              
455             1;
456              
457             #
458             # This file is part of Config-Wild
459             #
460             # This software is Copyright (c) 2017 by Smithsonian Astrophysical Observatory.
461             #
462             # This is free software, licensed under:
463             #
464             # The GNU General Public License, Version 3, June 2007
465             #
466              
467             =pod
468              
469             =head1 NAME
470              
471             Config::Wild - parse an application configuration file with wildcard keywords
472              
473             =head1 VERSION
474              
475             version 2.02
476              
477             =head1 SYNOPSIS
478              
479             use Config::Wild;
480             $cfg = Config::Wild->new();
481             $cfg = Config::Wild->new( $configfile, \%attr );
482              
483             =head1 DESCRIPTION
484              
485             This module reads I data pairs from a file. What sets
486             it apart from other configuration systems is that keys may contain
487             Perl regular expressions, allowing one entry to match multiple
488             requested keys.
489              
490             Configuration information in the file has the form
491              
492             key = value
493              
494             where I is a token which may contain Perl regular expressions
495             surrounded by curly brackets, e.g.
496              
497             foobar.{\d+}.name = goo
498              
499             and I is the remainder of the line after any whitespace following
500             the C<=> character is removed.
501              
502             Keys which contain regular expressions are termed I
503             keys; those without are called I keys. Wildcard
504             keys serve as templates to allow grouping of keys which have
505             the same value. For instance, say you've got a set of keys which
506             normally have the same value, but where on occasion you'd like to
507             override the default:
508              
509             p.{\d+}.foo = goo
510             p.99.foo = flabber
511              
512             I may reference environment variables or other B
513             variables via the following expressions:
514              
515             =over 4
516              
517             =item *
518              
519             Environment variables may be accessed via C<${var}>:
520              
521             foo = ${HOME}/foo
522              
523             If the variable doesn't exist, the expression is replaced with
524             an empty string.
525              
526             =item *
527              
528             Other B variables may be accessed via C<$(var)>.
529              
530             root = ${HOME}
531             foo = $(root)/foo
532              
533             If the variable doesn't exist, the expression is replaced with
534             an empty string. Variable expansions can be nested, as in
535              
536             root = /root
537             branch = $(root)/branch
538             tree = $(branch)/tree
539              
540             C will evaluate to C.
541              
542             =item *
543              
544             I type of variable may be accessed via C<$var>.
545             In this case, if I is not a B variable, it is
546             assumed to be an environment variable.
547             If the variable doesn't exist, the expression is left as is.
548              
549             =back
550              
551             Substitutions are made when the B method is called, not when
552             the values are first read in.
553              
554             Lines which begin with the C<#> character are ignored. There is also a
555             set of directives which alter where and how B reads
556             configuration information. Each directive begins with the C<%> character
557             and appears alone on a line in the config file:
558              
559             =over 4
560              
561             =item B<%include> F
562              
563             Temporarily interrupt parsing of the current configuration file, and
564             switch the input stream to the file specified via I.
565             See L.
566              
567             =back
568              
569             =head2 Finding Configuration Files
570              
571             The C and C options to the constructor determine where
572             configuration files are searched for. They are optional and may not be
573             specified in combination.
574              
575             In the following tables:
576              
577             =over
578              
579             =item *
580              
581             C is the provided path to the configuration file.
582              
583             =item *
584              
585             C
586             has been specified.
587              
588             =item *
589              
590             The file patterns are,
591              
592             /* absolute path
593             ./* ../* paths relative to the current directory
594             * all other paths
595              
596             =item *
597              
598             In the results,
599              
600             cwd the current working directory
601             path an entry in the path option array
602              
603             =back
604              
605             =head3 Files loaded via B and B
606              
607             +==========================================+
608             | | file |
609             |---------+--------------------------------|
610             | option | /* | ./* ../* | * |
611             |==========================================|
612             | default | file | cwd/file | cwd/file |
613             | path | file | cwd/file | path/file |
614             | dir | file | dir/file | dir/file |
615             +---------+------+-------------+-----------+
616              
617             =head3 Files included from other files
618              
619             C is the directory containing the file including the new
620             configuration file, e.g. the one with the C<%include> directive.
621              
622             +==========================================+
623             | | file |
624             |---------+--------------------------------|
625             | option | /* | ./* ../* | * |
626             |==========================================|
627             | default | file | incdir/file | cwd/file |
628             | path | file | incdir/file | path/file |
629             | dir | file | dir/file | dir/file |
630             +---------+------+-------------+-----------+
631              
632             =begin pod_coverage
633              
634             =head3 value
635              
636             =end pod_coverage
637              
638             =head1 METHODS
639              
640             =head2 Constructor
641              
642             =head3 new
643              
644             $cfg = Config::Wild->new( \%attr );
645             $cfg = Config::Wild->new( $config_file, \%attr );
646              
647             Create a new B object, optionally loading configuration
648             information from a file.
649              
650             See L for more information on how
651             configuration files are found.
652              
653             Additional attributes which modify the behavior of the object may be
654             specified in the passed C<%attr> hash. They may also be specified or modified after
655             object creation using the C method.
656              
657             The following attributes are available:
658              
659             =over
660              
661             =item C I
662              
663             This specifies a subroutine to be called when the value of an undefined
664             key is requested. The subroutine is passed the name of the key.
665             It should return a value, which will be returned as the value of the
666             key.
667              
668             For example,
669              
670             $cfg = Config::Wild->new( "foo.cnf", { UNDEF => \&undefined_key } );
671              
672             sub undefined_key
673             {
674             my $key = shift;
675             return 33;
676             }
677              
678             You may also use this to centralize error messages:
679              
680             sub undefined_key
681             {
682             my $key = shift;
683             die("undefined key requested: $key\n");
684             }
685              
686             To reset this to the default behavior, set C to C:
687              
688             $cfg->set_attr( UNDEF => undef );
689              
690             =item C F
691              
692             If specified, the current working directory will be changed to the
693             specified directory before a configuration file is loaded.
694              
695             See L.
696              
697             This option may not be combined with the C option.
698              
699             =item C I
700              
701             An array of paths to search for configuration files.
702              
703             See L.
704              
705             This option may not be combined with the C option.
706              
707             =item C I
708              
709             If set, when expanding C<$(var)> in key values, C will be
710             matched first against absolute keys, then against wildcard
711             keys. If not set (the default), C is matched only against the
712             absolute keys.
713              
714             =back
715              
716             =head3 load
717              
718             $cfg->load( $file );
719              
720             Load information from a configuration file into the current object.
721             New configuration values will supersede previous ones, in the
722             following complicated fashion. Absolutely specified keys will
723             overwrite previously absolutely specified values. Since it is
724             difficult to determine whether the set of keys matched by two
725             regular expressions overlap, wildcard keys are pushed onto a
726             last-in first-out (LIFO) list, so that when the application requests a
727             value, it will use search the wildcard keys in reverse order that
728             they were specified.
729              
730             It throws an exception (as a string) if an error occurred.
731              
732             See L for more information on how
733             configuration files are found.
734              
735             =head3 load_cmd
736              
737             $cfg->load_cmd( \@ARGV );
738             $cfg->load_cmd( \@ARGV,\%attr );
739              
740             Parse an array of key-value pairs (possibly command line
741             arguments), and insert them into the list of keys. It can take an
742             optional hash of attributes with the following values:
743              
744             =over 8
745              
746             =item C
747              
748             If true, the keys must already exist. An error will be returned if
749             the key isn't in the absolute list, or doesn't match against the
750             wildcards.
751              
752             =back
753              
754             It throws an exception (as a string) if an error occurred.
755              
756             =head3 set
757              
758             $cfg->set( $key, $value );
759              
760             Explicitly set a key to a value. Useful to specify keys that
761             should be available before parsing the configuration file.
762              
763             =head3 get
764              
765             $value = $cfg->get( $key );
766              
767             Return the value associated with a given key. B<$key> is
768             first matched against the absolute keys, then against the
769             wildcards. If no match is made, C is returned.
770              
771             =head3 getbool
772              
773             $value = $cfg->getbool( $key );
774              
775             Convert the value associated with a given key to a true or false value
776             using B>. B<$key> is first matched against
777             the absolute keys, then against the wildcards. If no match is made,
778             or the value could not be converted to a truth value, C is
779             returned.
780              
781             =head3 delete
782              
783             $cfg->delete( $key );
784              
785             Delete C<$key> from the list of keys (either absolute or wild)
786             stored in the object. The key must be an exact match. It is not
787             an error to delete a key which doesn't exist.
788              
789             =head3 exists
790              
791             $exists = $cfg->exists( $key );
792              
793             Returns non-zero if the given key matches against the list of
794             keys in the object, C if not.
795              
796             =head3 set_attr
797              
798             $cfg->set_attr( \%attr );
799              
800             Set object attribute. See for a list of attributes.
801              
802             =head2 Keyword-named Accessors Methods
803              
804             You may access a value by specifying the keyword as the method,
805             instead of using the B method. The following are equivalent:
806              
807             # keyword is foo
808             $foo = $cfg->get( 'foo' );
809             $foo = $cfg->foo;
810              
811             If C doesn't exist, it returns C.
812              
813             You can set a value using a similar syntax. The following are
814             equivalent, if the key already exists:
815              
816             $cfg->set( 'key', $value );
817             $cfg->key( $value );
818              
819             If the key doesn't exist, the second statement does nothing.
820              
821             It is a bit more time consuming to use these methods rather than using
822             B and B.
823              
824             =head1 LOGGING
825              
826             B uses L to log C level messages during
827             searching and reading configuration files. In the event of an error
828             during searching, reading, and parsing files, it will log C
829             level messages.
830              
831             =head1 ERRORS AND EXCEPTIONS
832              
833             For most errors, B will croak.
834              
835             If an error occurs during searching for, reading, or parsing a
836             configuration file, objects in the following classes will be thrown:
837              
838             =over
839              
840             =item *
841              
842             Config::Wild::Error::exists
843              
844             =item *
845              
846             Config::Wild::Error::read
847              
848             =item *
849              
850             Config::Wild::Error::parse
851              
852             =back
853              
854             They stringify into an appropriate error message.
855              
856             =head1 BUGS AND LIMITATIONS
857              
858             You can make new bug reports, and view existing ones, through the
859             web interface at L.
860              
861             =head1 AUTHOR
862              
863             Diab Jerius
864              
865             =head1 COPYRIGHT AND LICENSE
866              
867             This software is Copyright (c) 2017 by Smithsonian Astrophysical Observatory.
868              
869             This is free software, licensed under:
870              
871             The GNU General Public License, Version 3, June 2007
872              
873             =cut
874              
875             __END__