File Coverage

lib/Config/Mini.pm
Criterion Covered Total %
statement 65 143 45.4
branch 15 44 34.0
condition 9 23 39.1
subroutine 9 19 47.3
pod 8 14 57.1
total 106 243 43.6


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Config::Mini - Very simple INI-style configuration parser
4              
5              
6             =head1 SAMPLE CONFIGURATION
7              
8             In your config file:
9              
10             # this is a comment
11             # these will go in section [general] which is the default
12             foo = bar
13             baz = buz
14            
15             [section1]
16             key1 = val1
17             key2 = val2
18            
19             [section2]
20             key3 = val3
21             key4 = arrayvalue
22             key4 = arrayvalue2
23             key4 = arrayvalue3
24            
25              
26             =head1 USAGE
27              
28             In your perl code:
29              
30             use Config::Mini;
31             my $config = Config::Mini->new ('sample.conf');
32             print "These are the sections which are defined in the config file:\n";
33             print join "\n", $config->sections();
34              
35             # will print 'arrayvalue'
36             print $config->section ('section2')->{'key4'};
37             print $config->section ('section2')->{'__key4'}->[2];
38              
39              
40             =head1 %directives
41              
42             By default, L turns sections into hashes. For instance, the following
43             section:
44              
45             [test]
46             foo = bar
47             foo = bar2
48             baz = buz
49            
50             Will be turned into:
51              
52             {
53             foo => 'bar',
54             baz => 'buz',
55             __foo => [ 'bar', 'bar2' ],
56             __baz => [ 'buz' ],
57             }
58            
59             When you write your own objects, having this convention is fine. However, you may want to instantiate
60             other objects from CPAN than your own. For example, a L is constructed like this in Perl:
61              
62             $memd = Cache::Memcached->new {
63             'servers' => [ "10.0.0.15:11211", "10.0.0.15:11212", "10.0.0.17:11211" ]
64             'debug' => 0,
65             'compress_threshold' => 10_000,
66             };
67            
68            
69             So having the following config won't do:
70              
71             [cache]
72             %package = Cache::Memcached
73             servers = 10.0.0.15:11211
74             servers = 10.0.0.15:11212
75             servers = 10.0.0.17:11211
76             debug = 0
77             compress_threshold = 10_000
78              
79             Because L expects 'servers' to be an array, not a scalar.
80              
81              
82             In this case, you can do the following:
83              
84             [cache]
85             %package = Cache::Memcached
86             @servers = 10.0.0.15:11211
87             @servers = 10.0.0.15:11212
88             @servers = 10.0.0.17:11211
89             debug = 0
90             compress_threshold = 10_000
91              
92              
93             This will let L know that 'servers' is meant to be an array reference.
94              
95             If you want, you can also let it know that debug and compress_threshold are just scalars
96             so it doesn't create the '__debug' and '__compress_threshold' attributes, using the dollar
97             symbol:
98              
99             [cache]
100             %package = Cache::Memcached
101             @servers = 10.0.0.15:11211
102             @servers = 10.0.0.15:11212
103             @servers = 10.0.0.17:11211
104             $debug = 0
105             $compress_threshold = 10_000
106              
107             The only problem now is that your configuration file is seriously starting to look like Perl,
108             so I would recommend using these 'tricks' only where it's 100% necessary.
109              
110              
111             =head1 %include, %package, %constructor
112              
113             You can use the following commands:
114              
115             =head2 %include /path/to/file
116              
117             Will include /path/to/file. Relative paths are supported (it will act as if you were chdir'ed
118             to the current config file location), but wildcards at not (well, not yet).
119              
120              
121             =head2 %package My::Package::Name
122              
123             Will attempt to create an object rather than a file name. For example:
124              
125             [database]
126             %package = Rose::DB
127             %constructor = register_db
128             domain = development
129             type = main
130             driver = mysql
131             database = dev_db
132             host = localhost
133             username = devuser
134             password = mysecret
135              
136              
137             =head2 %constructor constructor_name
138              
139             Most Perl objects use new() for their constructor method, however sometimes
140             the constructor is called something else. If %constructor is specified, then
141             it will be called instead of new()
142              
143              
144             =head2 %hashref = true
145              
146             Some folks prefer to construct their objects this way:
147              
148             my $object = Foo->new ( { %args } );
149            
150             Instead of
151              
152             my $object = Foo->new ( %args );
153              
154             This directive allows you to accomodate them (Cache::Cache comes to mind).
155             So for example, you'd have:
156              
157             [cache]
158             %package = Cache::FileCache
159             %hashref = true
160             namespace = MyNamespace
161             default_expires_in = 600
162              
163              
164             =head2 %args = key1 key2 key3
165              
166             Some modules have constructors where you don't pass a hash, but a simple list of
167             arguments. For example:
168              
169             File::BLOB->from_file( 'filename.txt' );
170            
171             In this case, you can do:
172              
173             [fileblob]
174             %package = File::Blob
175             %constructor = from_file
176             %args filename
177             filename = filename.txt
178              
179              
180             =cut
181             package Config::Mini;
182 2     2   104851 use File::Spec;
  2         6  
  2         66  
183 2     2   9 use warnings;
  2         3  
  2         60  
184 2     2   10 use strict;
  2         7  
  2         4130  
185              
186             our $IncludeCount = 0;
187             our $VERSION = '0.04';
188             our %CONF = ();
189             our $OBJS = {};
190              
191              
192              
193             =head2 my $config = Config::Mini->new ($config_file);
194              
195             Creates a new L object.
196              
197             =cut
198             sub new
199             {
200 0     0 1 0 my $class = shift;
201 0         0 my $file = shift;
202 0         0 local %CONF = ();
203 0         0 local $OBJS = {};
204 0         0 parse_file ($file);
205            
206 0         0 my $self = bless {}, $class;
207 0         0 foreach my $key (keys %Config::Mini::CONF)
208             {
209 0   0     0 $self->{$key} ||= Config::Mini::instantiate ($key);
210             }
211            
212 0         0 return $self;
213             }
214              
215              
216             =head2 @config_sections = $config->sections();
217              
218             Returns a list of section names.
219              
220             =cut
221             sub sections
222             {
223 0     0 1 0 my $self = shift;
224 0         0 return $self->section (@_);
225             }
226              
227              
228             =head2 my $hash = $config->section ($section_name);
229              
230             Returns a hashref (or an object) which represents this config section.
231              
232             =cut
233             sub section
234             {
235 0     0 1 0 my $self = shift;
236 0         0 my $key = shift;
237 0 0       0 defined $key and return $self->{$key};
238 0         0 return keys %{$self};
  0         0  
239             }
240              
241              
242             =head1 FUNCTIONAL STYLE
243              
244             If you don't want to use the OO-style, you can use the functions below.
245              
246              
247             =head2 Config::Mini::parse_file ($filename)
248              
249             Parses config file $filename
250              
251             =cut
252             sub parse_file
253             {
254 0     0 1 0 my $file = shift;
255 0         0 local $IncludeCount = 0;
256 0         0 my @data = read_data ($file);
257 0         0 parse_data (@data);
258             }
259              
260              
261              
262             sub read_data
263             {
264 0     0 0 0 my $file = shift;
265 0 0       0 $IncludeCount > 10 and return;
266 0         0 $IncludeCount++;
267            
268 0 0       0 open FP, "$file" or die "Cannot read-open $file";
269 0         0 my @lines = ;
270 0         0 close FP;
271            
272 0         0 my @res = ();
273 0         0 foreach my $line (@lines)
274             {
275 0         0 chomp ($line);
276 0 0       0 $line =~ /^\%include\s+/ ? push @res, read_data_include ($file, $line) : push @res, $line;
277             }
278              
279 0         0 $IncludeCount--;
280 0         0 return @res;
281             }
282              
283              
284             sub read_data_include
285             {
286 0     0 0 0 my $file = shift;
287 0         0 my $line = shift;
288 0         0 $line =~ s/\%include\s+//;
289            
290 0 0       0 if ($line =~ /^\//)
291             {
292 0         0 $file = $line;
293             }
294             else
295             {
296 0         0 ($file) = $file =~ /^(.*)\//;
297 0         0 $file = File::Spec->rel2abs ($file);
298 0         0 $file .= "/$line";
299             }
300            
301 0         0 return read_data ($file);
302             }
303              
304              
305             =head2 Config::Mini::parse_data (@data)
306              
307             Parses @data
308              
309             =cut
310             sub parse_data
311             {
312 2     2 1 33 my @lines = map { split /\n/ } @_;
  2         26  
313              
314 2         6 my $current = 'general';
315 2         7 my $count = 0;
316 2         4 for (@lines)
317             {
318 24         22 $count++;
319              
320 24         31 s/\r//g;
321 24         26 s/\n//g;
322 24         60 s/^\s+//;
323 24         48 s/\s+$//;
324 24 100       40 $_ || next;
325              
326 20         24 my $orig = $_;
327              
328 20         21 s/#.*//;
329 20         30 s/^\s+//;
330 20         33 s/\s+$//;
331 20 50       739 $_ || next;
332              
333 20 100       50 /^\[.+\]/ and do {
334 4         18 ($current) = $_ =~ /^\[(.+)\]/;
335 4   50     41 $CONF{$current} ||= {};
336 4         7 next;
337             };
338              
339 16 50       63 /^.+=.+$/ and do {
340 16         58 my ($key, $value) = split /\s*=\s*/, $_, 2;
341 16   100     78 $CONF{$current}->{$key} ||= [];
342 16         18 push @{$CONF{$current}->{$key}}, $value;
  16         36  
343 16         35 next;
344             };
345            
346 0         0 print STDERR "ConfigParser: Cannot parse >>>$orig<<< (line $count)\n";
347             }
348             }
349              
350              
351             sub set_config
352             {
353 0     0 0 0 my $section = shift;
354 0         0 my $key = shift;
355 0   0     0 $CONF{$section} ||= {};
356              
357 0 0       0 if (defined $key) { $CONF{$section}->{$key} = \@_ }
  0         0  
358 0         0 else { delete $CONF{$section}->{$key} }
359            
360 0 0       0 delete $CONF{$section} unless (keys %{$CONF{$section}});
  0         0  
361 0         0 delete $OBJS->{$section};
362             }
363              
364              
365             sub delete_section
366             {
367 0     0 0 0 my $section = shift;
368 0         0 delete $CONF{$section};
369             }
370              
371              
372             sub write_file
373             {
374 0     0 0 0 my $filename = shift;
375 0 0       0 open FP, ">$filename" or die "Cannot write-open $filename!";
376 0 0       0 if ($CONF{general})
377             {
378 0         0 write_file_section ('general', $CONF{'general'});
379             }
380 0         0 for my $key (sort keys %CONF)
381             {
382 0 0       0 $key eq 'general' and next;
383 0         0 write_file_section ($key, $CONF{$key});
384             }
385             }
386              
387              
388             sub write_file_section
389             {
390 0     0 0 0 my $name = shift;
391 0         0 my $hash = shift;
392 0         0 print FP "[$name]\n";
393 0         0 for my $key (sort keys %{$hash})
  0         0  
394             {
395 0         0 for my $item (@{$hash->{$key}})
  0         0  
396             {
397 0         0 print FP "$key=$item\n";
398             }
399             }
400 0         0 print FP "\n";
401             }
402              
403              
404             =head2 Config::Mini::get ($context, $key)
405              
406             Returns the value for $key in $context.
407              
408             Returns the value as an array if the requested value is an array.
409              
410             Return the first value otherwise.
411              
412             =cut
413             sub get
414             {
415 7     7 1 22 my $con = shift;
416 7         11 my $key = shift;
417 7 100       68 return wantarray ? @{$CONF{$con}->{$key}} : $CONF{$con}->{$key}->[0];
  1         6  
418             }
419              
420              
421             =head2 Config::Mini::instantiate ($context)
422              
423             If $context is used to describe an object, Config::Mini will try to instantiate it.
424              
425             If $section contains a "package" attribute, Config::Mini will try to load that package and call
426             a new() method to instantiate the object.
427              
428             Otherwise, it will simply return a hash reference.
429              
430             Values can be considered as a scalar or an array. Hence, Config::Mini uses
431             for scalar values and '__' for array values.
432              
433             =cut
434             sub instantiate
435             {
436 2     2 1 3 my $section = shift;
437 2 50       8 $CONF{$section} || return;
438            
439 2   33     24 $OBJS->{$section} ||= do {
440 2         5 my $config = $CONF{$section};
441 2         3 my %args = ();
442 2         3 foreach my $key (keys %{$config})
  2         8  
443             {
444 6 50       20 if ($key =~ s/^\@//)
    50          
445             {
446 0         0 $args{$key} = $config->{"\@$key"};
447             }
448             elsif ($key =~ s/^\$//)
449             {
450 0         0 $args{$key} = $config->{"\$$key"}->[0];
451             }
452             else
453             {
454 6         12 $args{$key} = $config->{$key}->[0];
455 6         16 $args{"__$key"} = $config->{$key};
456             }
457             }
458              
459 2   50     11 my $cons = delete $args{'%constructor'} || 'new';
460 2   50     12 my $class = delete $args{'%package'} || $args{package} || return \%args;
461 2         4 my $args = delete $args{'%args'};
462 2   50     10 my $noargs = delete $args{'%noargs'} || 'false';
463            
464 2     1   177 eval "use $class";
  1     1   431  
  0         0  
  0         0  
  1         991  
  0            
  0            
465 2 50 33     28 defined $@ and $@ and warn $@;
466            
467 2   50     15 my $hashref = delete $args{'%hashref'} || 'false';
468            
469 0         0 my @args = $args ?
470 2 50       15 ( map { $args{$_} } split /\s+/, $args ) :
471             ( %args );
472            
473 2 50       23 if ( lc ($noargs) eq 'true' ) { $class->$cons() }
  0 50       0  
474 0         0 elsif ( lc ($hashref) eq 'true' ) { $class->$cons ( { @args } ) }
475 2         23 else { $class->$cons ( @args ) }
476             };
477            
478 2         48 return $OBJS->{$section};
479             }
480              
481              
482             =head2 Config::Mini::select ($regex)
483              
484             Selects all section entries matching $regex, and returns a list of instantiated
485             objects using instantiate() for each of them.
486              
487             =cut
488             sub select
489             {
490 1     1 1 6 my $regex = shift;
491 1         32 return map { instantiate ($_) }
  2         8  
492             grep /$regex/, keys %CONF;
493             }
494              
495              
496             1;
497              
498              
499             __END__