File Coverage

blib/lib/Config/Easy.pm
Criterion Covered Total %
statement 139 150 92.6
branch 58 70 82.8
condition 10 13 76.9
subroutine 14 16 87.5
pod 0 7 0.0
total 221 256 86.3


line stmt bran cond sub pod time code
1 3     3   32702 use strict;
  3         7  
  3         695  
2             package Config::Easy;
3 3     3   305 use Carp qw/croak/;
  3         5  
  3         435  
4              
5             our $VERSION = "0.2";
6             our %C;
7             my ($fname, $fromfile, $atline, $expanded);
8 3     3   18 use constant STRICT => " strict"; # key for strict_hash emulation
  3         12  
  3         1514  
9             # the leading space makes sure
10             # that it won't collide with another.
11              
12             sub import {
13 3     3   7783 my ($call_pkg, $call_file, $call_line) = caller;
14             {
15             #
16             # export %C to the caller's package
17             #
18 3 100       8 unless ($fromfile) {
  3         15  
19 2         4 $fromfile = $call_file;
20 2         4 $atline = $call_line;
21             }
22 3     3   187 no strict 'refs';
  3         21  
  3         10779  
23 3         20 *{"$call_pkg\::C"} = \%C;
  3         67  
24 3         8 *{"$call_pkg\::config_eval"} = \&config_eval;
  3         61  
25             }
26 3         8 my $module = shift;
27             #
28             # give warnings
29             # if we either have already processed
30             # a configuration file and we were given another one
31             # OR
32             # if we weren't given one and we need one.
33             #
34 3 100       13 if (@_) {
35 2 50       6 if ($fname) {
36 0         0 my $extra_fname = shift;
37 0         0 die "In $call_file at line $call_line ",
38             "there is no need to say:\n\n ",
39             "use Config::Easy '$extra_fname';\n\n",
40             "Simply say:\n\n",
41             " use Config::Easy;\n\n",
42             "We have already processed '$fname' in $fromfile ",
43             "at line $atline.\n\n";
44             } else {
45 2         4 $fname = shift; # normal case
46             }
47             } else {
48 1 50       5 if ($fname) {
49 1         56 return; # normal case
50             } else {
51 0         0 die "Config::Easy: Must provide a default configuration file.\n";
52             }
53             }
54              
55             #
56             # is there a command line option -F with a filename?
57             # it will override any $fname above.
58             #
59 2         10 for (my $i = 0; $i < @ARGV; ++$i) {
60 3 100       13 if ($ARGV[$i] =~ /^-F/) {
61 1         1 my $n;
62 1 50       3 if ($ARGV[$i] =~ /^-F(\w+)/) {
63 0         0 $n = 1;
64 0         0 $fname = $1;
65             } else {
66 1 50       3 if ($fname = $ARGV[$i+1]) {
67 1         2 $n = 2;
68             } else {
69 0         0 die "missing file name after -F!\n";
70             }
71             }
72 1         3 splice @ARGV, $i, $n;
73 1         2 last;
74             }
75             }
76 2         5 _init();
77 2         8 args();
78 2         5 expand();
79             }
80              
81             sub new {
82 3     3 0 594 my ($pkg, $file) = @_;
83              
84 3 50       12 die "Must supply filename to Config::Easy->new\n"
85             unless $file;
86 3         6 $fname = $file;
87 3         5 my $self = {};
88 3         9 $self->{STRICT} = 1;
89 3         11 _init($self);
90 3         13 return bless $self, $pkg;
91             }
92              
93             #
94             # enforce the strict hash for this Config::Easy object
95             #
96             sub strict {
97 0     0 0 0 my ($self) = shift;
98 0         0 $self->{STRICT} = 1;
99             }
100              
101             #
102             # relax the strict hash for this Config::Easy object
103             #
104             sub no_strict {
105 0     0 0 0 my ($self) = shift;
106 0         0 $self->{STRICT} = 0;
107             }
108              
109             sub get {
110 7     7 0 960 my ($self) = shift;
111              
112 7 100       23 expand($self) unless $expanded;
113 7 100 66     49 if (@_ and $self->{STRICT}) {
114 6         13 for my $key (@_) {
115 7 50       28 croak "key '$key' does not exist"
116             unless exists $self->{$key};
117             }
118             }
119 6         32 return (@_)? @{$self}{@_}: # wow!
  1         8  
120 7 100       31 %{$self};
121             }
122              
123             #
124             # we have already set $fname - one way or another
125             #
126             sub _init {
127 5     5   8 my ($self) = @_; # may be set or not
128 5 50       219 open IN, $fname or die "cannot open $fname: $!\n";
129 5         21 my ($k, $v, $contline, $delim);
130 5         8 local $_; # in case it is used elsewhere!
131 5         87 while () {
132 64         86 chomp;
133 64         220 s/^\s*//; # trim leading blanks
134 64         120 s/(?
135 64 100       228 next unless /\S/; # skip entirely blank lines
136             # process continuation lines
137 48 100       331 while (s/(\s*)\\\s*$/(length($1) >= 1)? " ": ""/e) {
  15         70  
138 15         30 $contline = ;
139 15 50       32 last unless defined $contline;
140 15         53 $contline =~ s/^\s*//; # trim leading blanks
141 15         27 $contline =~ s/(?
142 15         77 $_ .= $contline;
143             }
144 48         148 ($k, $v) = split /\s+/, $_, 2;
145 48 100       110 if ($v eq "-") {
146 3         7 $v = "";
147 3         12 while () {
148 12 100       30 last if /^\./;
149 9         16 s/[ \t]+$//; # trim trailing tab/space not newline
150 9         22 $v .= $_;
151             }
152 3         8 $v = _process($v, 1); # add a new line if not a
153             # reference or a quoted string
154 3 100       12 if ($self) {
155 1         3 $self->{$k} = $v;
156             } else {
157 2         5 $C{$k} = $v;
158             }
159 3         25 next;
160             }
161             #
162             # do we need to get more lines to satisfy
163             # an unmatched leading ', ", [ or { in the value?
164             #
165 45         70 $delim = substr $v, 0, 1;
166 45         54 $delim =~ tr/[{/]}/;
167 45 100 100     332 if ((index qq!'"]}!, $delim) >= 0
168             and $v !~ /$delim\s*$/)
169             {
170 9         19 $v .= "\n"; # add back the newline we chomped
171 9         12 while (1) {
172 27         37 $contline = ;
173 27 50       59 last unless defined $contline;
174 27         37 $contline =~ s/(?
175 27         33 $v .= $contline;
176 27 100       258 last if $v =~ /$delim\s*$/;
177             }
178             }
179 45         88 $v = _process($v);
180 45 100       84 if ($self) {
181 17         118 $self->{$k} = $v;
182             } else {
183 28         133 $C{$k} = $v;
184             }
185             }
186 5         61 close IN;
187             }
188              
189             #
190             # get overriding key=value pairs on the command line
191             # unless that argument begins with a -- in conformance
192             # with Getopt::Long conventions.
193             #
194             sub args {
195 3     3 0 10 my ($self) = @_; # may be set or not
196 3         6 my ($arg, @NEWARGV);
197 0         0 my ($k, $v);
198              
199 3         15 while ($arg = shift @ARGV) {
200 8 100       20 if ($arg eq "--") {
201 2         6 push @NEWARGV, "--", @ARGV;
202 2         3 last;
203             }
204 6 100 66     49 if ((($k, $v) = $arg =~ /^(.*)=(.*)$/) and $k !~ /^--/) {
205 4 100       22 warn "warning: no '$k' key in config file to override\n"
    50          
206             unless ($self)? exists $self->{$k}:
207             exists $C{$k};
208 4         8 $v = _process($v);
209 4 100       10 if ($self) {
210 2         10 $self->{$k} = $v;
211             } else {
212 2         6 $C{$k} = $v;
213             }
214             } else {
215 2         6 push @NEWARGV, $arg;
216             }
217             }
218 3         13 @ARGV = @NEWARGV;
219             }
220              
221             #
222             # substitute definitions for unescaped $vars
223             # this is the first time I've used (needed)
224             # a negative lookbehind assertion!
225             # we needed it to provide for a real dollar sign by
226             # escaping it.
227             #
228             sub expand {
229 3     3 0 5 my ($self) = @_;
230 3   100     17 my $href = $self || \%C;
231 3         21 for my $k (keys %$href) {
232 46         88 $href->{$k} =~ s/(?
233 6 50       102 /(exists $href->{$1})? $href->{$1}: ""
234             /xeg;
235 46         97 $href->{$k} =~ s/\\([\$#])/$1/g; # \$ to $ and \# to #
236             }
237 3         2199 $expanded = 1;
238             }
239              
240             sub _process {
241 52     52   74 my ($v, $newline) = @_;
242              
243 52         391 $v =~ s/\s*$//; # trim trailing blanks
244              
245 52 100       376 if ($v =~ /^\s*\[\s*(.*?)\s*\]$/sm) { # ref to anonymous array
    100          
    100          
246 9         64 return [ split /\s+/, $1 ];
247             }
248             elsif ($v =~ /^\s*\{\s*(.*?)\s*\}$/sm) { # ref to anonymous hash
249 6         57 return { split /\s+/, $1 };
250             }
251             elsif ($v =~ /^\s*(["'])(.*)\1$/sm) { # quoted with matching " or '
252 6         107 return $2;
253             } else {
254 31 100       63 $v .= "\n" if $newline;
255 31         68 return $v;
256             }
257             }
258              
259             sub config_eval {
260 2     2 0 2680 my $self;
261 2 50       27 $self = shift if ref $_[0]; # called as method or not?
262 3     3   31 no strict 'refs';
  3         7  
  3         412  
263 2   50     14 my $href = $self || \%C;
264 2 100       12 @_ = keys %$href unless @_;
265             package main; # how to use caller's package?
266 2         5 for my $k (@_) {
267 16         60 $href->{$k} =~ s/\$(\w+)/${$1}/eg;
  2         3  
  2         16  
268             }
269 3     3   15 use strict 'refs';
  3         7  
  3         443  
270             }
271              
272             1;
273              
274             =head1 NAME
275            
276             Config::Easy - Access to a simple key-value configuration file.
277              
278             =head1 SYNOPSIS
279              
280             Typical usage:
281              
282             conf.txt contains:
283             -------
284             # vital information
285             name Harriet
286             city San Francisco
287              
288             # options
289             verbose 1 # 0 or 1
290             -------
291              
292             use Config::Easy 'conf.txt';
293              
294             print "$C{name}\n" if $C{verbose};
295              
296             Or for an object oriented approach:
297              
298             use Config::Easy();
299              
300             my $c = Config::Easy->new('conf.txt');
301              
302             print $c->get('name'), "\n"
303             if $c->get('verbose');
304              
305             For more details see the section OBJECT.
306              
307             =head1 DESCRIPTION
308              
309             The statement:
310              
311             use Config::Easy "conf.txt";
312              
313             will take the file named "conf.txt" in the current
314             directory as the default configuration file.
315              
316             Lines from the file have leading and trailing blanks trimmed.
317             Comments begin with # and continue to the end of the line.
318             Entirely blank lines are ignored.
319              
320             Lines are divided into key and value at the first
321             white space on the line. These key-value pairs are inserted
322             into the %C hash which is then exported into the current package.
323              
324             # personal information
325             empname Harold
326             ssn 123-45-6789
327             phone 876-555-1212
328              
329             print "$C{empname} - $C{ssn}\n";
330              
331             The name is the minimal %C to visually emphasize the key name.
332              
333             The file 'conf.txt' can be overridden with a -F command line option.
334              
335             % prog -F newconf
336              
337             It can also be C<-Fnewconf>, if you wish.
338              
339             To use a configuration file in the same directory as
340             the perl script itself you can use the core module FindBin:
341              
342             use FindBin;
343             use Config::Easy "$FindBin::Bin/conf.txt";
344              
345             =head1 COMMAND LINE ARGUMENTS
346              
347             Command line arguments are scanned looking for any with
348             an equals sign in them.
349              
350             % prog name=Mathilda status=okay
351              
352             These arguments are extracted (removed from @ARGV),
353             parsed into key=value and inserted into the %C hash.
354             They will override any values in the configuration file.
355             A warning is emitted if the key did not appear in the file.
356              
357             This parsing of arguments will stop at an argument of '--'.
358              
359             % prog name=Mary -- num=3
360              
361             '-- num=3' can be processed by 'prog' itself.
362              
363             =head1 ACCESS ELSEWHERE
364              
365             If you want access to the configuration hash from
366             other files simply put:
367              
368             use Config::Easy;
369              
370             at the top of those files; the %C hash will again
371             be exported into the current package. You need to have:
372              
373             use Config::Easy 'conf.txt';
374              
375             only once in the main file before anyone needs to look
376             at the %C hash.
377              
378             =head1 STRICT
379              
380             Installing the module Tie::StrictHash will protect against
381             the common problem of misspelling of a key name:
382              
383             use Config::Easy 'conf';
384             use Tie::StrictHash;
385             strict_hash %C;
386              
387             print "name is $C{emplname}\n";
388              
389             % prog
390             key 'emplname' does not exist at prog line 5
391             %
392              
393             If there is access from other files you need
394             the strict_hash call only in the main file.
395              
396             =head1 CONTINUATION LINES
397              
398             Lines ending with backslash are continued
399             onto the next line. This allows:
400              
401             ids 45 \
402             67 \ # middle value
403             89
404              
405             instead of:
406              
407             ids 45 67 89
408              
409             Leading blanks on continuation lines are trimmed.
410             Any blanks before the backslash are converted to a single blank.
411              
412             =head1 STRING SUBSTITUTION
413              
414             For a simple string substitution mechanism:
415              
416             name Harold
417             place here
418             phrase I'm $name and I'm $place.
419              
420             This would yield:
421              
422             $C{phrase} = "I'm Harold and I'm here.";
423              
424             You can escape an actual dollar sign with a backslash '\'.
425              
426             There is also a way to interpolate I (or rather I) variables into
427             a configuration value.
428              
429             In the configuration file:
430              
431             path /a/b/c.\$date.gz # the dollar sign is escaped
432              
433             In the code:
434              
435             print $C{path}; # /a/b/c.$date.gz
436             our $date = "20040102";
437             config_eval;
438             print $C{path}; # /a/b/c.20040102.gz
439              
440             The exported function 'config_eval' will interpolate
441             'our' (not 'my') variables from the main package into the %C values.
442             You can give config_eval a list of which keys to evaluate, if you wish.
443              
444             config_eval qw/path trigger/;
445              
446             =head1 QUOTED VALUES
447              
448             Leading and trailing blanks in the value are normally trimmed.
449             If you I want such things
450             quote the value field with single or double quotes.
451             The quotes will be trimmed off for you.
452              
453             foo " big one "
454             bar ' yeah '
455              
456             If you want an actual # in the value escape it
457             with a backslash.
458              
459             title The \# of hits.
460              
461             =head1 MULTIPLE VALUES
462              
463             Multiple valued values are possible by
464             using references to anonymous arrays and hashes.
465             This syntax in the configuration file:
466              
467             colors [ red yellow blue green ]
468              
469             will effectively do this:
470              
471             $C{colors} = [ qw(red yellow blue green) ];
472              
473             In your program you can have:
474              
475             for my $c (@{$C{colors}}) {
476             ...
477             }
478              
479             or
480              
481             print $C{colors}[2];
482              
483             Similarily:
484              
485             ages { joe 45 \
486             betty 47 \
487             mary 13 \ # their daughter
488             }
489              
490             does this:
491              
492             $C{ages} = { joe => 45,
493             betty => 47
494             mary => 13,
495             };
496              
497             In both cases neither the values nor the keys can have internal blanks.
498             If you need this you could use underscores for this purpose
499             and replace them with blanks later.
500              
501             If a value begins with ', ", [, or { and does
502             not end with the matching delimiter then further
503             lines will be read until such a line is found.
504             This makes the syntax cleaner and more maintainable:
505              
506             ages {
507             joe 45
508             betty 47
509             mary 13 # their daughter
510             }
511              
512             =head1 MULTI-LINE VALUES
513              
514             If you wish a single value to span multiple lines:
515              
516             story -
517             Once upon a time
518             there was a fellow named
519             $name who lived peacefully
520             in the town of $city.
521             .
522              
523             If the value is '-' alone, it indicates that the real
524             value is all following lines up until a period '.' is seen on
525             a line by itself. String substitution will still take
526             place. $C{story} from above will have 4 embedded newlines.
527              
528             =head1 OBJECT
529              
530             Some may object to their namespace being 'polluted' with the
531             %C hash or find the name %C too cryptic.
532             They also may not like command line arguments being parsed
533             and extracted by any module except those named Getopt::*.
534              
535             For these users there is a pure object oriented interface:
536              
537             use Config::Easy(); # the () is required so that
538             # nothing is done at import() time.
539             my $c = Config::Easy->new('conf.txt');
540              
541             $c->args; # parse command line arguments (optional)
542              
543             #
544             # the get method can be called in several ways
545             #
546             print "name is ", $c->get('name'), "\n"; # the key 'name'
547              
548             my ($age, $status) = $c->get(qw/ age status /); # two at once
549              
550             my %config = $c->get; # gets entire hash
551             print $config{name};
552              
553             You I have multiple instances of the Config::Easy object.
554              
555             The get method enforces 'strict' behavior. If you use
556             a key name that does not occur in the configuration file
557             it will die with an error message.
558              
559             print $c->get("oops");
560              
561             % prog
562             key 'oops' does not exist at prog line 10.
563              
564             Methods 'strict' and 'no_strict' turn this behavior on and off.
565              
566             'config_eval' is a method to interpolate 'our' variables. See
567             STRING SUBSTITUTION above.
568              
569             =head1 SEE ALSO
570              
571             Tie::StrictHash protects against misspelling of key names.
572              
573             Getopt::Easy is a clear and simple alternative
574             to Getopt::Std and Getopt::Long.
575              
576             Date::Simple is an elegant way of dealing with dates.
577              
578             =head1 AUTHOR
579              
580             Jon Bjornstad
581              
582             =cut