File Coverage

blib/lib/Bio/Polloc/Polloc/Config.pm
Criterion Covered Total %
statement 162 200 81.0
branch 52 98 53.0
condition 10 22 45.4
subroutine 21 23 91.3
pod 6 6 100.0
total 251 349 71.9


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Bio::Polloc::Polloc::Config - Handles .cfg files
4              
5             =head1 AUTHOR - Luis M. Rodriguez-R
6              
7             Email lmrodriguezr at gmail dot com
8              
9             =head1 DESCRIPTION
10              
11             See the scripts folder (.bme files) for examples of the expected
12             syntaxis.
13              
14             =cut
15              
16             package Bio::Polloc::Polloc::Config;
17 5     5   25 use base qw(Bio::Polloc::Polloc::Root Bio::Polloc::Polloc::IO);
  5         11  
  5         623  
18 5     5   27 use strict;
  5         10  
  5         38405  
19             our $VERSION = 1.0503; # [a-version] from Bio::Polloc::Polloc::Version
20              
21              
22             =head1 GLOBALS
23              
24             Global variables controling the behavior of the package
25              
26             =over
27              
28             =cut
29              
30             our($CFGMAXDEPTH, $CFGCURDEPTH);
31              
32             =item CFGMAXDEPTH
33              
34             Maximum depth of variables replacement
35              
36             =cut
37              
38             $CFGMAXDEPTH = 7 unless defined $CFGMAXDEPTH;
39              
40             =item CFGCURDEPTH
41              
42             Current depth of replacement (internal var)
43              
44             =back
45              
46             =cut
47              
48             $CFGCURDEPTH = 0;
49              
50             =head1 APPENDIX
51              
52             Methods provided by the package
53              
54             =head2 new
55              
56             =over
57              
58             =item
59              
60             Initialization method.
61              
62             =item Arguments
63              
64             =over
65              
66             =item -spaces I<arr of str>
67              
68             A reference to an array of strings, each containing a namespace to be
69             parsed.
70              
71             =item -noparse I<bool (int)>
72              
73             If set to true, does not automatically parse the file on creation. If so,
74             the L<parse> function must be manually called.
75              
76             =back
77              
78             =back
79              
80             =cut
81              
82             sub new {
83 5     5 1 15 my($caller,@args) = @_;
84 5         38 my $self = $caller->SUPER::new(@args);
85 5         21 $self->_initialize(@args);
86 5         24 return $self;
87             }
88              
89             =head2 parse
90              
91             =over
92              
93             =item
94              
95             Parses the configuration file.
96              
97             =item Throws
98              
99             L<Bio::Polloc::Polloc::IOException> on parsing error.
100              
101             =back
102              
103             =cut
104              
105             sub parse {
106 5     5 1 12 my($self,@args) = @_;
107              
108 5         11 $CFGCURDEPTH = 0;
109 5         7 my $onspace = "";
110 5         9 my @spaces = @{$self->spaces};
  5         71  
111 5         52 $self->debug("The fine art of parsing (".$self->resource.")...");
112 5         48 while(my $line = $self->_readline){
113 270         523 $line = $self->_filter_line($line);
114 270 100       975 next if $line =~ /^\s*$/;
115 200 100       585 if($line =~ m/^\[\s*([\w\.]+)\s*\]$/){
    100          
    100          
    50          
116             # [ space ]
117 20         92 $self->debug("[$onspace] Space: $line");
118 20         51 $onspace = $self->_parse_space($1);
119             }elsif( !$self->_space_required($onspace) ){
120             # Ignore space
121 73         272 $self->debug("[$onspace] Ignored: $line");
122 73         232 next;
123             }elsif($line =~ m/^([\w\.]+)\s*=\s*(.*)$/){
124 27         121 $self->debug("[$onspace] Key-value pair: $line");
125             # key = value
126 27         122 $self->_save(-space=>$onspace, -key=>$1, -value=>$2);
127             }elsif($line =~ m/^([\w\.]+)(\s+(.*))?$/){
128 80         343 $self->debug("[$onspace] Token: $line");
129             # token body || token
130             # Note that 'key = value' also fits this expresion because body
131             # is anything, but it has been already ruled out.
132 80         316 $self->_execute_token(-space=>$onspace, -token=>$1, -body=>$3);
133             }else{
134 0         0 $self->throw("Unable to parse configuration file ".$self->file,
135             $line, "Bio::Polloc::Polloc::IOException");
136             }
137             }
138 5         57 $self->close();
139 5         25 $self->_reparse();
140 5         24 $self->_execute_postparse();
141             }
142              
143             =head2 spaces
144              
145             =over
146              
147             =item
148              
149             Gets/sets the spaces to be parsed.
150              
151             =back
152              
153             =cut
154              
155             sub spaces {
156 201     201 1 227 my $self = shift;
157 201 100       443 $self->{'_spaces'} = ['.'] unless defined $self->{'_spaces'};
158 201         447 while ( my $a = shift ) {
159 11 50       16 for my $s (@{ ref($a) =~ /array/i ? $a : [$a] }){
  11         47  
160 11         14 push @{$self->{'_spaces'}}, $self->_parse_space($s);
  11         31  
161             }
162             }
163 201         454 return $self->{'_spaces'};
164             }
165              
166             =head2 value
167              
168             =over
169              
170             =item
171              
172             Gets the value of a given key.
173              
174             =item Arguments
175              
176             =over
177              
178             =item -key I<str>
179              
180             The key (can contain namespace).
181              
182             =item -space I<str>
183              
184             The namespace.
185              
186             =item -mandatory I<bool (int)>
187              
188             If true, dies if not found.
189              
190             =item -noalert I<bool (int)>
191              
192             If true, does not alert if not found.
193              
194             =back
195              
196             =item Throws
197              
198             L<Bio::Polloc::Polloc::Error> If not found and mandatory.
199              
200             =back
201              
202             =cut
203              
204             sub value {
205 27     27 1 91 my($self,@args) = @_;
206 27         137 my($key, $space, $mandatory, $noalert) =
207             $self->_rearrange([qw(KEY SPACE MANDATORY NOALERT)],@args);
208 27 50       88 return unless $key;
209 27         99 $key = $self->_parse_key(-key=>$key, -space=>$space);
210 27         111 my $alias = $self->alias($key);
211 27 50       67 if($alias){
212 0         0 $self->debug("Retrieving value by alias ($key -> $alias)");
213 0         0 return $self->value($alias);
214             }
215 27 50       95 unless(defined $self->{'_data'}->{$key}){
216 0 0       0 $self->throw("Unable to find a value for the key", $key) if $mandatory;
217 0 0       0 $self->warn("Unable to find a value for the key", $key) unless $noalert;
218             }
219 27         107 return $self->{'_data'}->{$key};
220             }
221              
222             =head2 all_keys
223              
224             =over
225              
226             =item
227              
228             Gets all the stored keys.
229              
230             =item Arguments
231              
232             =over
233              
234             =item -space I<str>
235              
236             The parent space. By default C<.>.
237              
238             =back
239              
240             =item Returns
241              
242             All the keys within the space (array of str).
243              
244             =back
245              
246             =cut
247              
248             sub all_keys {
249 2     2 1 8 my($self,@args) = @_;
250 2         13 my($space) = $self->_rearrange([qw(SPACE)], @args);
251 2   50     9 $space||= '.';
252 2         7 $space = $self->_parse_space($space);
253 2         5 return grep { /^$space/ } keys %{ $self->{'_data'} };
  12         65  
  2         11  
254             }
255              
256             =head2 alias
257              
258             =over
259              
260             =item
261              
262             A key by alias.
263              
264             =item Arguments
265              
266             =over
267              
268             =item -from I<str>
269              
270             The B<from> key name.
271              
272             =item -to I<str>
273              
274             The B<to> key name.
275              
276             =back
277              
278             =item Throws
279              
280             L<Bio::Polloc::Polloc::Error> if any of the two keys is empty.
281              
282             =back
283              
284             =cut
285              
286             sub alias {
287 27     27 1 54 my($self,@args) = @_;
288 27         104 my($from,$to) = $self->_rearrange([qw(FROM TO)], @args);
289 27   100     109 $self->{'_alias'} ||= {};
290              
291 27 50       52 return unless $from;
292 27         58 my $k = $self->_parse_key($from);
293 27 50       62 $k or $self->throw("Illegal virual key as alias", $from);
294 27 50       60 if(defined $to){
295 0         0 my $d = $self->_parse_key($to);
296 0         0 $self->debug("Saving alias ($k -> $d)");
297 0 0       0 $d or $self->throw("Illegal target key to create alias", $to);
298 0         0 $self->{'_alias'}->{$k} = $d;
299             }
300 27         73 return $self->{'_alias'}->{$k};
301             }
302              
303             =head1 INTERNAL METHODS
304              
305             Methods intended to be used only within the scope of Bio::Polloc::*
306              
307             =head2 _filter_line
308              
309             =over
310              
311             =item
312              
313             Removes comments from lines and lines with spaces only.
314              
315             =back
316              
317             =cut
318              
319             sub _filter_line {
320 270     270   383 my($self,$line) = @_;
321              
322 270         361 chomp($line);
323 270         299 $line =~ s/^#.*//;
324 270         301 $line =~ s/\s#.*//;
325 270         406 $line =~ s/^\s+//;
326 270         600 $line =~ s/\s+$//;
327              
328 270         508 return $line;
329             }
330              
331             =head2 _save
332              
333             =over
334              
335             =item
336              
337             Saves a key/value pair.
338              
339             =item Arguments
340              
341             =over
342              
343             =item -space I<str>
344              
345             The namespace
346              
347             =item -key I<str>
348              
349             The name of the key (can contain the namespace before a dot (.) if not
350             explicitly provided).
351              
352             =item -value I<str>
353              
354             The value.
355              
356             =back
357              
358             =item Returns
359              
360             The (uniform) key of the saved pair. If array or list, the key and the value.
361              
362             =back
363              
364             =cut
365              
366             sub _save {
367 32     32   125 my($self,@args) = @_;
368 32         153 my($space,$key,$value) = $self->_rearrange([qw(SPACE KEY VALUE)], @args);
369 32 50       93 return unless $key;
370            
371             # Parse key
372 32         112 $key = $self->_parse_key(-space=>$space, -key=>$key);
373            
374             # Parse value
375 32 50       301 if( !$value ){
    50          
    100          
    100          
    50          
376 0         0 $value = "";
377             }elsif($value =~ m/^(true|false)$/i){
378 0         0 $value = ("true" eq lc $value);
379             }elsif($value =~ m/^[\d\.Ee+\-]+$/){
380 8         19 $value += 0;
381             }elsif($value =~ m/^'(.*)'$/){
382 3         9 $value = $1;
383 3         9 $value =~ s/\$\{/\$\\{/;
384             }elsif($value =~ m/^"(.*)"$/ ){
385 21         47 $value = $1;
386 21 100       70 push @{$self->{'_reparse'}}, $key if $value =~ /\$\{[\w\.]+\}/;
  5         18  
387             }else{
388 0         0 $self->throw("Bad value on configuration file ".$self->resource,
389             $value, "Bio::Polloc::Polloc::IOException");
390             }
391 32         89 $self->{'_data'}->{$key} = $value;
392              
393 32 50       199 return wantarray ? ($key,$value) : $key;
394             }
395              
396             =head2 _parse_space
397              
398             =over
399              
400             =item
401              
402             Parses (cleans) the name of a namespace.
403              
404             =item Arguments
405              
406             The namespace to parse.
407              
408             =item Returns
409              
410             The parsed (uniform) namespace.
411              
412             =back
413              
414             =cut
415              
416             sub _parse_space {
417 431     431   538 my($self, $space) = @_;
418 431 100       844 return '.' unless defined $space;
419 358         513 my $out = lc $space;
420 358 100       926 $out = "." . $out unless $out =~ m/^\./;
421 358 50       1219 $self->throw("Invalid space name <$out>", $space) unless $out =~ m/^[\w\.]+(\.\*)?$/i;
422 358         730 return $out;
423             }
424              
425             =head2 _space_required
426              
427             =over
428              
429             =item
430              
431             Indicates whether a namespace is required. I<I.e.>, if the user explicitly
432             requiested the space, any child or any parent.
433              
434             =item Arguments
435              
436             The namespace.
437              
438             =item Returns
439              
440             Boolean (int).
441              
442             =back
443              
444             =cut
445              
446             sub _space_required {
447 180     180   234 my($self,$space) = @_;
448 180         294 $space = $self->_parse_space($space);
449             # Top-level space
450            
451 180         209 for my $req_space ( @{ $self->spaces } ) {
  180         325  
452 449 50 33     5334 return $req_space if (
      66        
      33        
453             # Explicitly required space
454             ($req_space eq $space) ||
455             # Among children of a required space.*
456             ($req_space =~ m/^(.+)\.\*$/ &&
457             $space =~ m/^$1\.[^\.]+/) ||
458             # Parent of some required space
459             ($space =~ m/^$req_space\..*/)
460             );
461             }
462 73         185 return 0;
463             }
464              
465             =head2 _execute_token
466              
467             =over
468              
469             =item
470              
471             Executes a token expected to map to a function.
472              
473             =item Arguments
474              
475             =over
476              
477             =item -token I<str>
478              
479             The token (can contains namespace if not explicitly passed).
480              
481             =item -space I<str>
482              
483             The namespace of the token.
484              
485             =item -body I<str>
486              
487             A reference to an array containing the arguments to be passed to the
488             function.
489              
490             =back
491              
492             =back
493              
494             =cut
495              
496             sub _execute_token {
497 80     80   268 my($self,@args) = @_;
498 80         298 my ($token, $space, $body) = $self->_rearrange([qw(TOKEN SPACE BODY)], @args);
499 80         321 $token = $self->_parse_key(-key=>$token, -space=>$space);
500 80         352 $self->debug("Running $token with $body");
501 80 50       204 defined $self->_get_handle_function($token) or
502             $self->throw("Any handle function for the called token", $token);
503 80         287 my $hf = $self->_get_handle_function($token);
504 80 50       312 ref($hf) =~ /HASH/i or
505             $self->throw("Unexpected type of stored function", $hf);
506 80 50 33     364 defined $hf->{'-obj'} && defined $hf->{'-fun'} or
507             $self->throw("Incomplete function $token, imposible to complete call", $hf);
508 80         105 eval {
509 80         100 my $obj = $hf->{'-obj'};
510 80         106 my $fun = $hf->{'-fun'};
511 80         303 $obj->$fun($body, $hf->{'-defaults'});
512             };
513 80 50       203 if( $@ ){
514 0         0 $self->throw("Error calling $token [$body]:\n$@", $hf);
515             }
516 80         448 return;
517             }
518              
519             =head2 _execute_postparse
520              
521             =over
522              
523             =item
524              
525             Executes registered functions to be launched once parsing is finnished.
526              
527             =back
528              
529             =cut
530              
531             sub _execute_postparse {
532 5     5   13 my($self,@args) = @_;
533 5         21 $self->debug("Running postparse functions");
534 5         10 for my $fn ( @{$self->_postparse_functions} ){
  5         22  
535 0 0       0 next unless defined $fn; # This should never happens
536 0 0       0 ref($fn) =~ /HASH/i or $self->throw("Unexpected type of stored function", $fn);
537 0 0 0     0 defined $fn->{'-obj'} && defined $fn->{'-fun'} or
538             $self->throw("Incomplete function, imposible to complete call", $fn);
539 0         0 eval {
540 0         0 my $obj = $fn->{'-obj'};
541 0         0 my $fun = $fn->{'-fun'};
542 0         0 $obj->$fun($fn->{'-defaults'});
543             };
544 0 0       0 if( $@ ){
545 0         0 $self->throw("Error calling lambda function (for postparse):\n$@", $fn);
546             }
547             }
548 5         44 return;
549             }
550              
551             =head2 _register_handle_function
552              
553             =over
554              
555             =item
556              
557             Register a handle function (for tokens).
558              
559             =item Arguments
560              
561             =over
562              
563             =item -token I<str>
564              
565             Token (can contain namespace).
566              
567             =item -obj I<ref to obj>
568              
569             Reference to the object *containing* the function.
570              
571             =item -fun I<str>
572              
573             Name of the function (note that this is the name of the
574             function within the object, not a reference to the function
575             itself).
576              
577             =item -defaults I<ref to arr>
578              
579             Default parameters to be passed to the function after the
580             body.
581              
582             =item -space I<str>
583              
584             Namespace of the token.
585              
586             =back
587              
588             =back
589              
590             =cut
591              
592             sub _register_handle_function {
593 31     31   81 my($self,@args) = @_;
594 31         119 my($token, $obj, $fun, $defaults, $space) =
595             $self->_rearrange([qw(TOKEN OBJ FUN DEFAULTS SPACE)], @args);
596 31         135 $token = $self->_parse_key(-key=>$token, -space=>$space);
597 31         113 my $hf = {-obj=>$obj, -fun=>$fun, -defaults=>$defaults};
598 31         68 $self->_handle_functions;
599 31         132 $self->{'_handle_functions'}->{$token} = $hf;
600             }
601              
602             =head2 _register_postparse_function
603              
604             =over
605              
606             =item
607              
608             Registers a function to be launched once parsing is complete.
609              
610             =item Arguments
611              
612             =over
613              
614             =item -obj I<ref to obj>
615              
616             The object containing the function.
617              
618             =item -fun I<str>
619              
620             The name of the function within the object.
621              
622             =item -defaults I<ref to arr>
623              
624             The parameters to be passed to the function.
625              
626             =back
627              
628             =back
629              
630             =cut
631              
632             sub _register_postparse_function {
633 0     0   0 my($self,@args) = @_;
634 0         0 my($obj, $fun, $defaults) = $self->_rearrange([qw(OBJ FUN DEFAULTS)], @args);
635 0         0 my $hf = {-obj=>$obj, -fun=>$fun, -defaults=>$defaults};
636 0         0 $self->_postparse_functions;
637 0         0 push @{$self->{'_postparse_functions'}}, $hf;
  0         0  
638             }
639              
640             =head2 _handle_functions
641              
642             =over
643              
644             =item
645              
646             Gets the collection of functions to handle tokens.
647              
648             =back
649              
650             =cut
651              
652             sub _handle_functions {
653 191     191   259 my($self,@args) = @_;
654 191 100       420 $self->{'_handle_functions'} = {} unless defined $self->{'_handle_functions'};
655 191         362 return $self->{'_handle_functions'};
656             }
657              
658             =head2 _postparse_functions
659              
660             =over
661              
662             =item
663              
664             Gets the collection of functions to be launched after parsing.
665              
666             =back
667              
668             =cut
669              
670             sub _postparse_functions {
671 5     5   16 my($self,@args) = @_;
672 5 50       26 $self->{'_postparse_functions'} = [] unless defined $self->{'_postparse_functions'};
673 5         20 return $self->{'_postparse_functions'};
674             }
675              
676             =head2 _get_handle_function
677              
678             =over
679              
680             =item
681              
682             Gets the handle function for the given token.
683              
684             =item Arguments
685              
686             =over
687              
688             =item -token I<str>
689              
690             The token.
691              
692             =back
693              
694             =back
695              
696             =cut
697              
698             sub _get_handle_function {
699 160     160   292 my($self,@args) = @_;
700 160         525 my($token) = $self->_rearrange([qw(TOKEN)], @args);
701 160         381 $self->_handle_functions;
702 160         465 return $self->{'_handle_functions'}->{$token};
703             }
704              
705             =head2 _reparse
706              
707             =over
708              
709             =item
710              
711             Parses recursively all values until no references to other vars last or
712             the maximum depth is reached, whatever happens first.
713              
714             =back
715              
716             =cut
717              
718             sub _reparse {
719 10     10   19 my($self,@args) = @_;
720 10 50       38 $self->{'_reparse'} = [] unless defined $self->{'_reparse'};
721 10         16 my @reparse = @{$self->{'_reparse'}};
  10         26  
722 10         21 $self->{'_reparse'} = [];
723 10 100       40 return unless $#reparse>=0;
724 5 50       26 if($CFGCURDEPTH++ >= $CFGMAXDEPTH){
725 0         0 $self->warn("Maximum depth reached, some unparsed variables left");
726 0         0 return;
727             }
728 5         15 for my $key (@reparse){
729 5 50       15 next unless $key;
730 5         18 my $v = $self->value($key);
731 5         39 while($v =~ m/\$\{([\w\.]+)\}/){
732 5         14 my $k2 = $1;
733 5         19 my $v2 = $self->value($k2);
734 5         110 $v =~ s/\$\{$k2\}/$v2/g;
735             }
736 5         35 $self->_save(-key=>$key, -value=>"\"$v\"");
737             }
738            
739 5         36 $self->_reparse(@args);
740             }
741              
742             =head2 _parse_key
743              
744             =over
745              
746             =item
747              
748             Parses a key and returns its uniform name.
749              
750             =item Arguments
751              
752             =over
753              
754             =item -key I<str>
755              
756             The key name (can contain namespace if not explicitly set).
757              
758             =item -space I<str>
759              
760             The namespace.
761              
762             =back
763              
764             =back
765              
766             =cut
767              
768             sub _parse_key {
769 218     218   465 my($self,@args) = @_;
770 218         728 my($key,$space) = $self->_rearrange([qw(KEY SPACE)], @args);
771 218 50       568 $key or $self->throw("Got an empty key to parse, illegal action", $key,
772             "Bio::Polloc::Polloc::IOException");
773 218         292 $key = lc $key;
774 218         434 $space = $self->_parse_space($space);
775 218 100 66     1165 $key = $space . "." . $key if $space && $key !~ /^\./;
776 218         319 $key =~ s/\.\./\./g;
777 218         249 $key =~ s/\.\./\./g;
778 218 50       672 $self->throw("Bad key or token on configuration file ".$self->resource, $key,
779             "Bio::Polloc::Polloc::IOException")
780             unless $key=~m/^[\w\.]+$/;
781 218         540 return $key;
782             }
783              
784             =head2 _key_alias
785              
786             =over
787              
788             =item
789              
790             Creates an alias for a key based on a string input. See L<alias>.
791              
792             =item Arguments
793              
794             A string containing the name of the B<from> key, one or more spaces and the name
795             of the B<to> string. Can contain surrounding spaces.
796              
797             =item Throws
798              
799             L<Bio::Polloc::Polloc::Error> if empty string or not properly formatted.
800              
801             =back
802              
803             =cut
804              
805             sub _key_alias {
806 0     0   0 my($self,$body,@args) = @_;
807 0 0       0 $body or $self->throw("Empty body for alias", $body);
808 0         0 $body =~ s/^\s*//;
809 0         0 $body =~ s/\s*$//;
810 0         0 my($from,$to) = split /\s+/, $body;
811 0 0       0 $from or $self->throw("Any virtual key on alias", $body);
812 0 0       0 $to or $self->throw("Any target key on alias", $body);
813 0         0 $self->alias($from, $to);
814             }
815              
816             =head2 _initialize
817              
818             =cut
819              
820             sub _initialize {
821 5     5   15 my($self,@args) = @_;
822 5         46 $self->_initialize_io(@args);
823 5         29 my($spaces, $noparse) = $self->_rearrange([qw(SPACES NOPARSE)], @args);
824 5         15 $self->{'_data'} = {};
825 5         23 $self->spaces($spaces);
826 5         29 $self->_register_handle_function(
827             -obj=>$self,
828             -fun=>"_key_alias",
829             -token=>".alias"
830             );
831 5 50       19 $self->parse(@args) unless $noparse;
832             }
833              
834              
835             1;