File Coverage

blib/lib/Config/General/Extended.pm
Criterion Covered Total %
statement 46 137 33.5
branch 18 76 23.6
condition 1 6 16.6
subroutine 11 20 55.0
pod 13 14 92.8
total 89 253 35.1


line stmt bran cond sub pod time code
1             #
2             # Config::General::Extended - special Class based on Config::General
3             #
4             # Copyright (c) 2000-2022 Thomas Linden .
5             # All Rights Reserved. Std. disclaimer applies.
6             # Licensed under the Artistic License 2.0.
7             #
8              
9             # namespace
10             package Config::General::Extended;
11              
12             # yes we need the hash support of new() in 1.18 or higher!
13 1     1   7 use Config::General 1.18;
  1         32  
  1         81  
14              
15 1     1   5 use FileHandle;
  1         2  
  1         5  
16 1     1   362 use Carp;
  1         1  
  1         71  
17              
18             # inherit new() and so on from Config::General
19             our @ISA = qw(Config::General);
20              
21 1     1   4 use strict;
  1         2  
  1         1597  
22              
23              
24             $Config::General::Extended::VERSION = "2.07";
25              
26              
27             sub new {
28 0     0 1 0 croak "Deprecated method Config::General::Extended::new() called.\n"
29             ."Use Config::General::new() instead and set the -ExtendedAccess flag.\n";
30             }
31              
32              
33             sub getbypath {
34 0     0 0 0 my ($this, $path) = @_;
35 0         0 my $xconfig = $this->{config};
36 0         0 $path =~ s#^/##;
37 0         0 $path =~ s#/$##;
38 0         0 my @pathlist = split /\//, $path;
39 0         0 my $index;
40 0         0 foreach my $element (@pathlist) {
41 0 0       0 if($element =~ /^([^\[]*)\[(\d+)\]$/) {
42 0         0 $element = $1;
43 0         0 $index = $2;
44             }
45             else {
46 0         0 $index = undef;
47             }
48              
49 0 0       0 if(ref($xconfig) eq "ARRAY") {
    0          
50 0         0 return {};
51             }
52             elsif (! exists $xconfig->{$element}) {
53 0         0 return {};
54             }
55              
56 0 0       0 if(ref($xconfig->{$element}) eq "ARRAY") {
57 0 0       0 if(! defined($index) ) {
58             #croak "$element is an array but you didn't specify an index to access it!\n";
59 0         0 $xconfig = $xconfig->{$element};
60             }
61             else {
62 0 0       0 if(exists $xconfig->{$element}->[$index]) {
63 0         0 $xconfig = $xconfig->{$element}->[$index];
64             }
65             else {
66 0         0 croak "$element doesn't have an element with index $index!\n";
67             }
68             }
69             }
70             else {
71 0         0 $xconfig = $xconfig->{$element};
72             }
73             }
74              
75 0         0 return $xconfig;
76             }
77              
78             sub obj {
79             #
80             # returns a config object from a given key
81             # or from the current config hash if the $key does not exist
82             # or an empty object if the content of $key is empty.
83             #
84 4     4 1 675 my($this, $key) = @_;
85              
86             # just create the empty object, just in case
87 4         6 my $empty = $this->SUPER::new( -ExtendedAccess => 1, -ConfigHash => {}, %{$this->{Params}} );
  4         24  
88              
89 4 50       11 if (exists $this->{config}->{$key}) {
90 4 50       15 if (!$this->{config}->{$key}) {
    50          
    50          
91             # be cool, create an empty object!
92 0         0 return $empty
93             }
94             elsif (ref($this->{config}->{$key}) eq "ARRAY") {
95 0         0 my @objlist;
96 0         0 foreach my $element (@{$this->{config}->{$key}}) {
  0         0  
97 0 0       0 if (ref($element) eq "HASH") {
98             push @objlist,
99             $this->SUPER::new( -ExtendedAccess => 1,
100             -ConfigHash => $element,
101 0         0 %{$this->{Params}} );
  0         0  
102             }
103             else {
104 0 0       0 if ($this->{StrictObjects}) {
105 0         0 croak "element in list \"$key\" does not point to a hash reference!\n";
106             }
107             # else: skip this element
108             }
109             }
110 0         0 return \@objlist;
111             }
112             elsif (ref($this->{config}->{$key}) eq "HASH") {
113             return $this->SUPER::new( -ExtendedAccess => 1,
114 4         8 -ConfigHash => $this->{config}->{$key}, %{$this->{Params}} );
  4         16  
115             }
116             else {
117             # nothing supported
118 0 0       0 if ($this->{StrictObjects}) {
119 0         0 croak "key \"$key\" does not point to a hash reference!\n";
120             }
121             else {
122             # be cool, create an empty object!
123 0         0 return $empty;
124             }
125             }
126             }
127             else {
128             # even return an empty object if $key does not exist
129 0         0 return $empty;
130             }
131             }
132              
133              
134             sub value {
135             #
136             # returns a value of the config hash from a given key
137             # this can be a hashref or a scalar
138             #
139 3     3 1 10 my($this, $key, $value) = @_;
140 3 50       5 if (defined $value) {
141 0         0 $this->{config}->{$key} = $value;
142             }
143             else {
144 3 50       4 if (exists $this->{config}->{$key}) {
145 3         6 return $this->{config}->{$key};
146             }
147             else {
148 0 0       0 if ($this->{StrictObjects}) {
149 0         0 croak "Key \"$key\" does not exist within current object\n";
150             }
151             else {
152 0         0 return "";
153             }
154             }
155             }
156             }
157              
158              
159             sub hash {
160             #
161             # returns a value of the config hash from a given key
162             # as hash
163             #
164 0     0 1 0 my($this, $key) = @_;
165 0 0       0 if (exists $this->{config}->{$key}) {
166 0         0 return %{$this->{config}->{$key}};
  0         0  
167             }
168             else {
169 0 0       0 if ($this->{StrictObjects}) {
170 0         0 croak "Key \"$key\" does not exist within current object\n";
171             }
172             else {
173 0         0 return ();
174             }
175             }
176             }
177              
178              
179             sub array {
180             #
181             # returns a value of the config hash from a given key
182             # as array
183             #
184 0     0 1 0 my($this, $key) = @_;
185 0 0       0 if (exists $this->{config}->{$key}) {
186 0         0 return @{$this->{config}->{$key}};
  0         0  
187             }
188 0 0       0 if ($this->{StrictObjects}) {
189 0         0 croak "Key \"$key\" does not exist within current object\n";
190             }
191             else {
192 0         0 return ();
193             }
194             }
195              
196              
197              
198             sub is_hash {
199             #
200             # return true if the given key contains a hashref
201             #
202 3     3 1 342 my($this, $key) = @_;
203 3 50       6 if (exists $this->{config}->{$key}) {
204 3 100       10 if (ref($this->{config}->{$key}) eq "HASH") {
205 1         2 return 1;
206             }
207             else {
208 2         8 return;
209             }
210             }
211             else {
212 0         0 return;
213             }
214             }
215              
216              
217              
218             sub is_array {
219             #
220             # return true if the given key contains an arrayref
221             #
222 2     2 1 4 my($this, $key) = @_;
223 2 50       5 if (exists $this->{config}->{$key}) {
224 2 50       5 if (ref($this->{config}->{$key}) eq "ARRAY") {
225 0         0 return 1;
226             }
227             else {
228 2         4 return;
229             }
230             }
231             else {
232 0         0 return;
233             }
234             }
235              
236              
237             sub is_scalar {
238             #
239             # returns true if the given key contains a scalar(or number)
240             #
241 0     0 1 0 my($this, $key) = @_;
242 0 0 0     0 if (exists $this->{config}->{$key} && !ref($this->{config}->{$key})) {
243 0         0 return 1;
244             }
245 0         0 return;
246             }
247              
248              
249              
250             sub exists {
251             #
252             # returns true if the key exists
253             #
254 0     0 1 0 my($this, $key) = @_;
255 0 0       0 if (exists $this->{config}->{$key}) {
256 0         0 return 1;
257             }
258             else {
259 0         0 return;
260             }
261             }
262              
263              
264             sub keys {
265             #
266             # returns all keys under in the hash of the specified key, if
267             # it contains keys (so it must be a hash!)
268             #
269 3     3 1 283 my($this, $key) = @_;
270 3 50 33     18 if (!$key) {
    50          
271 0 0       0 if (ref($this->{config}) eq "HASH") {
272 0         0 return map { $_ } keys %{$this->{config}};
  0         0  
  0         0  
273             }
274             else {
275 0         0 return ();
276             }
277             }
278             elsif (exists $this->{config}->{$key} && ref($this->{config}->{$key}) eq "HASH") {
279 3         4 return map { $_ } keys %{$this->{config}->{$key}};
  5         14  
  3         11  
280             }
281             else {
282 0         0 return ();
283             }
284             }
285              
286              
287             sub delete {
288             #
289             # delete the given key from the config, if any
290             # and return what is deleted (just as 'delete $hash{key}' does)
291             #
292 0     0 1 0 my($this, $key) = @_;
293 0 0       0 if (exists $this->{config}->{$key}) {
294 0         0 return delete $this->{config}->{$key};
295             }
296             else {
297 0         0 return undef;
298             }
299             }
300              
301              
302              
303              
304             sub configfile {
305             #
306             # sets or returns the config filename
307             #
308 0     0 1 0 my($this,$file) = @_;
309 0 0       0 if ($file) {
310 0         0 $this->{configfile} = $file;
311             }
312 0         0 return $this->{configfile};
313             }
314              
315             sub find {
316 0     0 1 0 my $this = shift;
317 0         0 my $key = shift;
318 0 0       0 return undef unless $this->exists($key);
319 0 0       0 if (@_) {
320 0         0 return $this->obj($key)->find(@_);
321             }
322             else {
323 0         0 return $this->obj($key);
324             }
325             }
326              
327             sub AUTOLOAD {
328             #
329             # returns the representing value, if it is a scalar.
330             #
331 4     4   29 my($this, $value) = @_;
332 4         7 my $key = $Config::General::Extended::AUTOLOAD; # get to know how we were called
333 4         35 $key =~ s/.*:://; # remove package name!
334              
335 4 100       12 if (defined $value) {
    50          
336             # just set $key to $value!
337 2         7 $this->{config}->{$key} = $value;
338             }
339             elsif (exists $this->{config}->{$key}) {
340 2 50       4 if ($this->is_hash($key)) {
    50          
341 0         0 croak "Key \"$key\" points to a hash and cannot be automatically accessed\n";
342             }
343             elsif ($this->is_array($key)) {
344 0         0 croak "Key \"$key\" points to an array and cannot be automatically accessed\n";
345             }
346             else {
347 2         5 return $this->{config}->{$key};
348             }
349             }
350             else {
351 0 0       0 if ($this->{StrictObjects}) {
352 0         0 croak "Key \"$key\" does not exist within current object\n";
353             }
354             else {
355             # be cool
356 0         0 return undef; # bugfix rt.cpan.org#42331
357             }
358             }
359             }
360              
361             sub DESTROY {
362 11     11   943 my $this = shift;
363 11         217 $this = ();
364             }
365              
366             # keep this one
367             1;
368              
369              
370              
371              
372              
373             =head1 NAME
374              
375             Config::General::Extended - Extended access to Config files
376              
377              
378             =head1 SYNOPSIS
379              
380             use Config::General;
381              
382             $conf = Config::General->new(
383             -ConfigFile => 'configfile',
384             -ExtendedAccess => 1
385             );
386              
387             =head1 DESCRIPTION
388              
389             This is an internal module which makes it possible to use object
390             oriented methods to access parts of your config file.
391              
392             Normally you don't call it directly.
393              
394             =head1 METHODS
395              
396             =over
397              
398             =item configfile('filename')
399              
400             Set the filename to be used by B to "filename". It returns the current
401             configured filename if called without arguments.
402              
403              
404             =item obj('key')
405              
406             Returns a new object (of Config::General::Extended Class) from the given key.
407             Short example:
408             Assume you have the following config:
409              
410            
411            
412             age 23
413            
414            
415             age 56
416            
417            
418            
419             blah blubber
420             blah gobble
421             leer
422            
423              
424             and already read it in using B, then you can get a
425             new object from the "individual" block this way:
426              
427             $individual = $conf->obj("individual");
428              
429             Now if you call B on I<$individual> (just for reference) you would get:
430              
431             $VAR1 = (
432             martin => { age => 13 }
433             );
434              
435             Or, here is another use:
436              
437             my $individual = $conf->obj("individual");
438             foreach my $person ($conf->keys("individual")) {
439             $man = $individual->obj($person);
440             print "$person is " . $man->value("age") . " years old\n";
441             }
442              
443             See the discussion on B and B below.
444              
445             If the key from which you want to create a new object is empty, an empty
446             object will be returned. If you run the following on the above config:
447              
448             $obj = $conf->obj("other")->obj("leer");
449              
450             Then $obj will be empty, just like if you have had run this:
451              
452             $obj = Config::General::Extended->new( () );
453              
454             Read operations on this empty object will return nothing or even fail.
455             But you can use an empty object for I a new config using write
456             operations, i.e.:
457              
458             $obj->someoption("value");
459              
460             See the discussion on B below.
461              
462             If the key points to a list of hashes, a list of objects will be
463             returned. Given the following example config:
464              
465            
466             name = max
467            
468            
469             name = bea
470            
471              
472             you could write code like this to access the list the OOP way:
473              
474             my $objlist = $conf->obj("option");
475             foreach my $option (@{$objlist}) {
476             print $option->name;
477             }
478              
479             Please note that the list will be returned as a reference to an array.
480              
481             Empty elements or non-hash elements of the list, if any, will be skipped.
482              
483             =item hash('key')
484              
485             This method returns a hash(if it B one!) from the config which is referenced by
486             "key". Given the sample config above you would get:
487              
488             my %sub_hash = $conf->hash("individual");
489             print Dumper(\%sub_hash);
490             $VAR1 = {
491             martin => { age => 13 }
492             };
493              
494             =item array('key')
495              
496             This the equivalent of B mentioned above, except that it returns an array.
497             Again, we use the sample config mentioned above:
498              
499             $other = $conf->obj("other");
500             my @blahs = $other->array("blah");
501             print Dumper(\@blahs);
502             $VAR1 = [ "blubber", "gobble" ];
503              
504              
505             =item value('key')
506              
507             This method returns the scalar value of a given key. Given the following sample
508             config:
509              
510             name = arthur
511             age = 23
512              
513             you could do something like that:
514              
515             print $conf->value("name") . " is " . $conf->value("age") . " years old\n";
516              
517              
518              
519             You can use this method also to set the value of "key" to something if you give over
520             a hash reference, array reference or a scalar in addition to the key. An example:
521              
522             $conf->value("key", \%somehash);
523             # or
524             $conf->value("key", \@somearray);
525             # or
526             $conf->value("key", $somescalar);
527              
528             Please note, that this method does not complain about existing values within "key"!
529              
530             =item is_hash('key') is_array('key') is_scalar('key')
531              
532             As seen above, you can access parts of your current config using hash, array or scalar
533             methods. But you are right if you guess, that this might become problematic, if
534             for example you call B on a key which is in real not a hash but a scalar. Under
535             normal circumstances perl would refuse this and die.
536              
537             To avoid such behavior you can use one of the methods is_hash() is_array() is_scalar() to
538             check if the value of "key" is really what you expect it to be.
539              
540             An example(based on the config example from above):
541              
542             if($conf->is_hash("individual") {
543             $individual = $conf->obj("individual");
544             }
545             else {
546             die "You need to configure a "individual" block!\n";
547             }
548              
549              
550             =item exists('key')
551              
552             This method returns just true if the given key exists in the config.
553              
554              
555             =item keys('key')
556              
557             Returns an array of the keys under the specified "key". If you use the example
558             config above you could do that:
559              
560             print Dumper($conf->keys("individual");
561             $VAR1 = [ "martin", "joseph" ];
562              
563             If no key name was supplied, then the keys of the object itself will be returned.
564              
565             You can use this method in B loops as seen in an example above(obj() ).
566              
567              
568             =item delete('key')
569              
570             This method removes the given key and all associated data from the internal
571             hash structure. If 'key' contained data, then this data will be returned,
572             otherwise undef will be returned.
573              
574             =item find(@list)
575              
576             Given a list of nodes, ->find will search for a tree that branches in
577             just this way, returning the Config::General::Extended object it finds
578             at the bottom if it exists. You can also search partway down the tree
579             and ->find should return where you left off.
580              
581             For example, given the values B and the following
582             tree ( tags omitted for brevity):
583              
584            
585            
586             ...
587            
588            
589             ...
590            
591             BAR = shoo
592              
593             B will find the object at I with the value BAR = shoo and
594             return it.
595              
596              
597              
598             =back
599              
600              
601             =head1 AUTOLOAD METHODS
602              
603             Another useful feature is implemented in this class using the B feature
604             of perl. If you know the keynames of a block within your config, you can access to
605             the values of each individual key using the method notation. See the following example
606             and you will get it:
607              
608             We assume the following config:
609              
610            
611             name = Moser
612             prename = Peter
613             birth = 12.10.1972
614            
615              
616             Now we read it in and process it:
617              
618             my $conf = Config::General::Extended->new("configfile");
619             my $person = $conf->obj("person");
620             print $person->prename . " " . $person->name . " is " . $person->age . " years old\n";
621              
622             This notation supports only scalar values! You need to make sure, that the block
623             does not contain any subblock or multiple identical options(which will become
624             an array after parsing)!
625              
626             If you access a non-existent key this way, Config::General will croak an error.
627             You can turn this behavior off by setting B<-StrictObjects> to 0 or "no". In
628             this case undef will be returned.
629              
630             Of course you can use this kind of methods for writing data too:
631              
632             $person->name("Neustein");
633              
634             This changes the value of the "name" key to "Neustein". This feature behaves exactly like
635             B, which means you can assign hash or array references as well and that existing
636             values under the given key will be overwritten.
637              
638              
639             =head1 COPYRIGHT
640              
641             Copyright (c) 2000-2022 Thomas Linden
642              
643             This library is free software; you can redistribute it and/or
644             modify it under the terms of the Artistic License 2.0.
645              
646              
647             =head1 BUGS
648              
649             none known yet.
650              
651              
652             =head1 AUTHOR
653              
654             Thomas Linden
655              
656             =head1 VERSION
657              
658             2.07
659              
660             =cut
661