File Coverage

blib/lib/Bio/Polloc/LocusI.pm
Criterion Covered Total %
statement 121 199 60.8
branch 51 116 43.9
condition 16 59 27.1
subroutine 25 35 71.4
pod 28 28 100.0
total 241 437 55.1


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Bio::Polloc::LocusI - Interface of C<Bio::Polloc::Locus::*> objects
4              
5             =head1 AUTHOR - Luis M. Rodriguez-R
6              
7             Email lmrodriguezr at gmail dot com
8              
9             =head1 IMPLEMENTS OR EXTENDS
10              
11             =over
12              
13             =item *
14              
15             L<Bio::Polloc::Polloc::Root>
16              
17             =back
18              
19             =cut
20              
21             package Bio::Polloc::LocusI;
22 10     10   54 use strict;
  10         20  
  10         328  
23 10     10   49 use base qw(Bio::Polloc::Polloc::Root);
  10         28  
  10         702  
24 10     10   7609 use Bio::Polloc::RuleI;
  10         19  
  10         241  
25 10     10   52 use Bio::Polloc::Polloc::IO;
  10         17  
  10         204  
26 10     10   59 use List::Util qw(min max);
  10         14  
  10         27449  
27             our $VERSION = 1.0503; # [a-version] from Bio::Polloc::Polloc::Version
28              
29              
30             =head1 PUBLIC METHODS
31              
32             Methods provided by the package
33              
34             =cut
35              
36             =head2 new
37              
38             The basic initialization method
39              
40             =cut
41              
42             sub new {
43 87     87 1 449 my($caller,@args) = @_;
44 87   33     296 my $class = ref($caller) || $caller;
45            
46 87 50       170 if($class !~ m/Bio::Polloc::Locus::(\S+)/){
47 87         392 my $bme = Bio::Polloc::Polloc::Root->new(@args);
48 87         331 my($type) = $bme->_rearrange([qw(TYPE)], @args);
49            
50 87 50       220 if($type){
51 87         191 $type = Bio::Polloc::LocusI->_qualify_type($type);
52 87 50       452 $class = "Bio::Polloc::Locus::" . $type if $type;
53             }
54             }
55              
56 87 50       396 if($class =~ m/Bio::Polloc::Locus::(\S+)/){
57 87         96 my $load = 0;
58 87 50       267 if(Bio::Polloc::RuleI->_load_module($class)){
    0          
59 87         124 $load = $class;
60             }elsif(Bio::Polloc::RuleI->_load_module("Bio::Polloc::Locus::generic")){
61 0         0 $load = "Bio::Polloc::Locus::generic";
62             }
63            
64 87 50       180 if($load){
65 87         293 my $self = $load->SUPER::new(@args);
66 87         352 $self->debug("Got the LocusI class $load");
67 87         453 my($from,$to,$strand,$name,$rule,$seq,
68             $id,$family,$source,$comments,$genome,$seqname) =
69             $self->_rearrange(
70             [qw(FROM TO STRAND NAME RULE SEQ ID FAMILY SOURCE COMMENTS GENOME SEQNAME)],
71             @args);
72 87         350 $self->from($from);
73 87         157 $self->to($to);
74 87         213 $self->strand($strand);
75 87         194 $self->name($name);
76 87         154 $self->rule($rule);
77 87         166 $self->seq($seq);
78 87         158 $self->id($id);
79 87         152 $self->family($family);
80 87         157 $self->source($source);
81 87         181 $self->comments($comments);
82 87         260 $self->genome($genome);
83 87         163 $self->seq_name($seqname);
84 87         259 $self->_initialize(@args);
85 87         416 return $self;
86            
87             }
88            
89 0         0 my $bme = Bio::Polloc::Polloc::Root->new(@args);
90 0         0 $bme->throw("Impossible to load the module", $class);
91             }
92 0         0 my $bme = Bio::Polloc::Polloc::Root->new(@args);
93 0         0 $bme->throw("Impossible to load the proper Bio::Polloc::LocusI class with ".
94             "[".join("; ",@args)."]", $class);
95             }
96              
97             =head2 type
98              
99             Gets/sets the type of rule
100              
101             B<Arguments>
102              
103             Value (str). Can be: pattern, profile, repeat, similarity, coding. composition, crispr
104             Some variations can be introduced, like case variations or short versions like B<patt>
105             or B<rep>.
106              
107             B<Return>
108              
109             Value (str). The type of the rule, or null if undefined. The value returned is undef
110             or a string from the above list, regardless of the input variations.
111              
112             B<Throws>
113              
114             L<Bio::Polloc::Polloc::Error> if an unsupported type is received.
115              
116             =cut
117              
118             sub type {
119 87     87 1 133 my($self,$value) = @_;
120 87 50       164 if($value){
121 87         164 my $v = $self->_qualify_type($value);
122 87 50       174 $self->throw("Attempting to set an invalid type of locus",$value) unless $v;
123 87         176 $self->{'_type'} = $v;
124             }
125 87         182 return $self->{'_type'};
126             }
127              
128             =head2 genome
129              
130             Sets/gets the source genome as a L<Bio::Polloc::Genome> object.
131              
132             B<Throws>
133              
134             L<Bio::Polloc::Polloc::Error> if unexpected type.
135              
136             =cut
137              
138             sub genome {
139 92     92 1 108 my($self,$value) = @_;
140 92 100       177 $self->{'_genome'} = $value if defined $value;
141 92 100       224 return unless defined $self->{'_genome'};
142 2 50 33     28 $self->throw("Unexpected type of genome", $self->{'_genome'})
143             unless UNIVERSAL::can($self->{'_genome'},'isa')
144             and $self->{'_genome'}->isa('Bio::Polloc::Genome');
145 2         7 return $self->{'_genome'};
146             }
147              
148             =head2 name
149              
150             Sets/gets the name of the locus
151              
152             B<Arguments>
153              
154             Name (str), the name to set
155              
156             B<Returns>
157              
158             The name (str or undef)
159              
160             =cut
161              
162             sub name {
163 95     95 1 115 my($self,$value) = @_;
164 95 100       199 $self->{'_name'} = $value if defined $value;
165 95         153 return $self->{'_name'};
166             }
167              
168              
169             =head2 aliases
170              
171             Gets the alias names
172              
173             B<Returns>
174              
175             Aliases (arr reference or undef)
176              
177             =cut
178              
179 3     3 1 12 sub aliases { return shift->{'_aliases'}; }
180              
181              
182             =head2 add_alias
183              
184             B<Arguments>
185              
186             One or more alias names (str)
187              
188             =cut
189              
190             sub add_alias {
191 0     0 1 0 my($self,@values) = @_;
192 0   0     0 $self->{'_aliases'} ||= [];
193 0         0 push(@{$self->{'_aliases'}}, @values);
  0         0  
194             }
195              
196             =head2 parents
197              
198             Gets the parent features or loci
199              
200             B<Returns>
201              
202             Parents (arr reference or undef)
203              
204             =cut
205              
206 3     3 1 20 sub parents { return shift->{'_parents'}; }
207              
208             =head2 add_parent
209              
210             B<Arguments>
211              
212             One or more parent object (C<Bio::Polloc::LocusI>)
213              
214             B<Throws>
215              
216             L<Bio::Polloc::Polloc::Error> if some argument is not L<Bio::Polloc::LocusI>
217              
218             =cut
219              
220             sub add_parent {
221 0     0 1 0 my($self,@values) = @_;
222 0   0     0 $self->{'_parents'} ||= [];
223 0 0       0 for(@values){ $self->throw("Illegal parent class '".ref($_)."'",$_)
  0         0  
224             unless $_->isa('Bio::Polloc::LocusI') }
225 0         0 push(@{$self->{'_aliases'}}, @values);
  0         0  
226             }
227              
228             =head2 target
229              
230             Gets/sets the target of the alignment, if the feature is some alignment
231              
232             B<Arguments>
233              
234             =over
235              
236             =item -id
237              
238             The ID of the target sequence
239              
240             =item -from
241              
242             The start on the target sequence
243              
244             =item -to
245              
246             The end on the target sequence
247              
248             =item -strand
249              
250             The strand of the target sequence
251              
252             =back
253              
254             B<Returns>
255              
256             A hash reference like C<{B<id>=E<gt>id, B<from>=E<gt>from, B<to>=E<gt>to,
257             B<strand>=E<gt>strand}>
258              
259             =cut
260              
261             sub target {
262 3     3 1 4 my($self,@args) = @_;
263 3 50       14 if($#args>=0){
264 0         0 my($id,$from,$to,$strand) = $self->_rearrange([qw(ID FROM TO STRAND)], @args);
265 0         0 $self->{'_target'} = {'id'=>$id, 'from'=>$from, 'to'=>$to, 'strand'=>$strand};
266             }
267 3         13 return $self->{'_target'};
268             }
269              
270             =head2 comments
271              
272             Gets/sets the comments on the locus, newline-separated
273              
274             B<Arguments>
275              
276             New comments to add (str)
277              
278             B<Returns>
279              
280             Comments (str)
281              
282             =cut
283              
284             sub comments {
285 267     267 1 421 my($self,@comments) = @_;
286 267 100       510 if($#comments>=0){
287 261   100     762 $self->{'_comments'} ||= "";
288 261 100       397 for(@comments) { $self->{'_comments'} .= "\n" . $_ if defined $_ }
  472         1341  
289 261         593 $self->{'_comments'} =~ s/^\n+//;
290 261         507 $self->{'_comments'} =~ s/\n+$//; #<- Just in case it gets an empty comment
291             }
292 267         622 return $self->{'_comments'};
293             }
294              
295             =head2 xrefs
296              
297             Gets the cross references of the locus
298              
299             B<Returns>
300              
301             Array reference or undef
302              
303             =cut
304              
305 3     3 1 11 sub xrefs { return shift->{'_xrefs'} }
306              
307             =head2 add_xref
308              
309             Adds a cross reference
310              
311             B<Arguments>
312              
313             One or more cross references in GFF3 format
314              
315             =cut
316              
317             sub add_xref {
318 0     0 1 0 my $self = shift;
319 0   0     0 $self->{'_xrefs'} ||= [];
320 0 0       0 push @{$self->{'_xrefs'}}, @_ if $#_>=0;
  0         0  
321             }
322              
323             =head2 ontology_terms_str
324              
325             Gets the ontology terms as explicit strings
326              
327             B<Returns>
328              
329             Array reference or undef
330              
331             =cut
332              
333 3     3 1 11 sub ontology_terms_str{ return shift->{'_ontology_terms_str'} }
334              
335             =head2 add_ontology_term_str
336              
337             Adds an ontology term by string
338              
339             B<Arguments>
340              
341             One or more strings
342              
343             =cut
344              
345             sub add_ontology_term_str {
346 0     0 1 0 my $self = shift;
347 0 0       0 push @{$self->{'_ontology_terms_str'}}, @_ if $#_>=0;
  0         0  
348             }
349              
350              
351             =head2 from
352              
353             Gets/sets the B<from> position
354              
355             B<Arguments>
356              
357             Position (int, optional)
358              
359             B<Returns>
360              
361             The B<from> position (int, -1 if undefined)
362              
363             =cut
364              
365             sub from {
366 90     90 1 143 my($self,$value) = @_;
367 90   100     380 $self->{'_from'} ||= -1;
368 90 100       257 $self->{'_from'} = $value+0 if defined $value;
369 90         137 return $self->{'_from'};
370             }
371              
372              
373             =head2 to
374              
375             Gets/sets the B<to> position
376              
377             B<Arguments>
378              
379             Position (int, optional)
380              
381             B<Returns>
382              
383             The B<to> position (int, -1 if undefined)
384              
385             =cut
386              
387             sub to {
388 90     90 1 141 my($self,$value) = @_;
389 90   100     321 $self->{'_to'} ||= -1;
390 90 100       198 $self->{'_to'} = $value+0 if defined $value;
391 90         134 return $self->{'_to'};
392             }
393              
394             =head2 length
395              
396             Gets the length of the locus.
397              
398             B<Returns>
399              
400             I<int> or C<undef>.
401              
402             =cut
403              
404             sub length {
405 0     0 1 0 my $self = shift;
406 0 0 0     0 return unless defined $self->from and defined $self->to;
407 0         0 return abs($self->to - $self->from);
408             }
409              
410             =head2 id
411              
412             Gets/sets the ID of the locus
413              
414             B<Arguments>
415              
416             ID (str)
417              
418             B<Returns>
419              
420             ID (str)
421              
422             =cut
423              
424             sub id {
425 4482     4482 1 6639 my($self,$value) = @_;
426 4482 100       7505 $self->{'_id'} = $value if defined $value;
427 4482         15618 return $self->{'_id'};
428             }
429              
430              
431             =head2 family
432              
433             Sets/gets the family of features. I<I.e.>, a name identifying the type of locus.
434             A common family is B<CDS>, but other families can be defined. Note that the family
435             is not qualified by the software used for the prediction (use C<source()> for that).
436              
437             B<Arguments>
438              
439             The family (str, optional)
440              
441             B<Returns>
442              
443             The family (str)
444              
445             B<Note>
446              
447             This method tries to locate the family by looking (in that order) at:
448              
449             =over
450              
451             =item 1
452              
453             The explicitly defined family.
454              
455             =item 2
456              
457             The prefix of the ID (asuming it was produced by some L<Bio::Polloc::RuleI> object).
458              
459             =item 3
460              
461             The type of the rule (if the rule is defined).
462              
463             =item 4
464              
465             If any of the former options work, returns B<unknown>.
466              
467             =back
468              
469             =cut
470              
471             sub family {
472 160     160 1 210 my($self,$value) = @_;
473 160 100       351 $self->{'_family'} = $value if defined $value;
474 160 50 33     379 unless(defined $self->{'_family'} or not defined $self->id){
475 0 0       0 if($self->id =~ m/(.*):\d+\.\d+/){
476 0         0 $self->{'_family'} = $1;
477             }
478             }
479 160 50 33     329 $self->{'_family'} = $self->rule->type if not defined $self->{'_family'} and defined $self->rule;
480 160 50       289 return 'unknown' unless defined $self->{'_family'};
481 160         303 return $self->{'_family'};
482             }
483              
484             =head2 source
485              
486             Sets/gets the source of the feature. For example, the software used.
487              
488             B<Arguments>
489              
490             The source (str, optional).
491              
492             B<Returns>
493              
494             The source (str).
495              
496             B<Note>
497              
498             This method tries to locate the source looking (in that order) at:
499              
500             =over
501              
502             =item 1
503              
504             The explicitly defined value.
505              
506             =item 2
507              
508             The source of the rule (if defined).
509              
510             =item 3
511              
512             If any of the above, returns B<polloc>.
513              
514             =back
515              
516             =cut
517              
518             sub source {
519 92     92 1 111 my($self,$value) = @_;
520 92 100       253 $self->{'_source'} = $value if defined $value;
521 92 50 33     251 $self->{'_source'} = $self->rule->source
522             if not defined $self->{'_source'} and defined $self->rule;
523 92 50       156 return 'polloc' if not defined $self->{'_source'};
524 92         139 return $self->{'_source'};
525             }
526              
527             =head2 strand
528              
529             Gets/sets the strand
530              
531             B<Arguments>
532              
533             Strand (str: B<+>, B<-> or B<.>)
534              
535             B<Returns>
536              
537             The strand (str)
538              
539             =cut
540              
541             sub strand {
542 90     90 1 106 my($self,$value) = @_;
543 90   100     346 $self->{'_strand'} ||= '.';
544 90 100       217 $self->{'_strand'} = $value if defined $value;
545 90         126 return $self->{'_strand'};
546             }
547              
548             =head2 rule
549              
550             Gets/sets the origin rule
551              
552             B<Arguments>
553              
554             A L<Bio::Polloc::RuleI> object
555              
556             B<Returns>
557              
558             A L<Bio::Polloc::RuleI> object
559              
560             B<Throws>
561              
562             L<Bio::Polloc::Polloc::Error> if the argument is not of the proper class
563              
564             =cut
565              
566             sub rule {
567 87     87 1 95 my($self,$value) = @_;
568 87 50       156 if(defined $value){
569 0 0       0 $self->throw("Unexpected class of argument '".ref($value)."'",$value)
570             unless $value->isa('Bio::Polloc::RuleI');
571 0         0 $self->{'_rule'} = $value;
572             }
573 87         108 return $self->{'_rule'};
574             }
575              
576              
577             =head2 score
578              
579             Sets/gets the score of the feature. Most loci implement
580             different score functions, and it's often read-only.
581              
582             B<Returns>
583              
584             The score (float)
585              
586             B<Throws>
587              
588             L<Bio::Polloc::Polloc::NotImplementedException> if not implemented
589              
590             =cut
591              
592             sub score {
593 0     0 1 0 my($self,$value) = @_;
594 0         0 my $k = '_score';
595 0 0       0 $self->{$k} = $value if defined $value;
596 0         0 return $self->{$k};
597             }
598              
599             =head2 seq
600              
601             Sets/gets the sequence
602              
603             B<Arguments>
604              
605             The sequence (Bio::Seq object, optional)
606              
607             B<Returns>
608              
609             The sequence (Bio::Seq object or undef)
610              
611             B<Throws>
612              
613             L<Bio::Polloc::Polloc::Error> if the sequence is not Bio::Seq
614              
615             B<Note>
616              
617             This method returns the full original sequence, not the piece of sequence with the target
618              
619             =cut
620             sub seq {
621 87     87 1 131 my($self,$seq) = @_;
622 87 50       147 if(defined $seq){
623 0 0 0     0 $self->throw("Illegal type of sequence", $seq)
624             unless UNIVERSAL::can($seq, 'isa') and $seq->isa('Bio::Seq');
625 0         0 $self->{'_seq'} = $seq;
626             }
627 87 50 33     387 if(not defined $self->{'_seq'} and defined $self->{'_seq_name'} and defined $self->genome){
      33        
628 0         0 $self->{'_seq'} = $self->genome->search_sequence($self->seq_name);
629             }
630 87         117 return $self->{'_seq'};
631             }
632              
633             =head2 seq_name
634              
635             Gets/sets the name of the sequence
636              
637             B<Arguments>
638              
639             The name of the sequence (str, optional).
640              
641             B<Returns>
642              
643             The name of the sequence (str or C<undef>).
644              
645             =cut
646              
647             sub seq_name {
648 96     96 1 132 my($self, $value) = @_;
649 96 100       220 $self->{'_seq_name'} = $value if defined $value;
650 96 50 33     245 if(not defined $self->{'_seq_name'} and defined $self->seq){
651 0         0 $self->{'_seq_name'} = $self->seq->display_id;
652             }
653 96         159 return $self->{'_seq_name'};
654             }
655              
656             =head2 stringify
657              
658             B<Purpose>
659              
660             To provide an easy method for the (str) description of any L<Bio::Polloc::LocusI> object.
661              
662             B<Returns>
663              
664             The stringified object (str, off course)
665              
666             =cut
667              
668             sub stringify {
669 0     0 1 0 my($self,@args) = @_;
670 0         0 my $out = ucfirst $self->type;
671 0 0       0 $out.= " '" . $self->id . "'" if defined $self->id;
672 0         0 $out.= " at [". $self->from. "..". $self->to . $self->strand ."]";
673 0         0 return $out;
674             }
675              
676             =head2 context_seq
677              
678             Extracts a sequence from the context of the locus
679              
680             B<Arguments>
681              
682             All the following arguments are mandatory, and must be passed in that order:
683              
684             =over
685              
686             =item *
687              
688             ref I<int> :
689             -1 to use the start as reference (useful for upstream sequences),
690             +1 to use the end as reference (useful for downstream sequences),
691             0 to use the start as start reference and the end as end reference
692              
693             =item *
694              
695             from I<int> : The relative start position.
696              
697             =item *
698              
699             to I<int> : The relative end position.
700              
701             =back
702              
703             B<Returns>
704              
705             A L<Bio::Seq> object.
706              
707             =cut
708              
709             sub context_seq {
710 0     0 1 0 my ($self, $ref, $from, $to) = @_;
711 0         0 $self->_load_module('Bio::Polloc::GroupCriteria');
712 0 0 0     0 return unless defined $self->seq and defined $self->from and defined $self->to;
      0        
713 0         0 my $seq;
714 0         0 my ($start, $end);
715 0         0 my $revcom = 0;
716 0 0       0 if($ref < 0){
    0          
717 0 0 0     0 if($self->strand eq '?' or $self->strand eq '+'){
718             # (500..0)--------------->*[* >> ft >> ]
719 0         0 $start = $self->from - $from; $end = $self->from - $to;
  0         0  
720             }else{
721             # [ << ft << *]*<-----------------(500..0)
722 0         0 $start = $self->to + $to; $end = $self->to + $from; $revcom = !$revcom;
  0         0  
  0         0  
723             }
724             }elsif($ref > 0){
725 0 0 0     0 if($self->strand eq '?' or $self->strand eq '+'){
726             # [ >> ft >> *]*<-----------------(500..0)
727 0         0 $start = $self->to + $to; $end = $self->to + $from; $revcom = !$revcom;
  0         0  
  0         0  
728             }else{
729             # (500..0)--------------->*[* << ft << ]
730 0         0 $start = $self->from - $from; $end = $self->from - $to;
  0         0  
731             }
732             }else{
733 0 0 0     0 if($self->strand eq '?' or $self->strand eq '+'){
734 0         0 $start = $self->from + $from; $end = $self->to + $from;
  0         0  
735             }else{
736 0         0 $start = $self->to - $from; $end = $self->from - $to;
  0         0  
737             }
738             }
739 0         0 $start = max(1, $start);
740 0         0 $end = min($self->seq->length, $end);
741 0 0       0 $self->debug("Extracting context ".
    0          
742             (defined $self->seq->display_id?$self->seq->display_id:'').
743             "[$start..$end] ".($revcom?"-":"+"));
744 0         0 $seq = Bio::Polloc::GroupCriteria->_build_subseq($self->seq, $start, $end);
745 0 0       0 return unless defined $seq;
746 0 0       0 $seq = $seq->revcom if $revcom;
747 0         0 return $seq;
748             }
749              
750             =head2 distance
751              
752             Calculates the distance (referring to diversity, not genomic position) with the
753             given locus.
754              
755             B<Arguments>
756              
757             =over
758              
759             =item -locus I<Bio::Polloc::LocusI object>
760              
761             The locus to compare with. Most of the locus types require this locus to be of
762             the same type.
763              
764             =item -locusref I<Bio::Polloc::LocusI object>
765              
766             The reference locus. If set, replaces the loaded object as reference.
767              
768             =back
769              
770             B<Returns>
771              
772             Float. The distance with the given locus. Most types will return a distance ranging
773             from one to zero.
774              
775             B<Note>
776              
777             See the documentation for additional arguments and precisions.
778              
779             B<Throws>
780              
781             L<Bio::Polloc::Polloc::NotImplementedException> if not implemented by the correspondig class.
782              
783             =cut
784              
785 0     0 1 0 sub distance { $_[0]->throw("score",$_[0],"Bio::Polloc::Polloc::NotImplementedException") }
786              
787              
788             =head1 INTERNAL METHODS
789              
790             Methods intended to be used only within the scope of Bio::Polloc::*
791              
792             =head2 _qualify_type
793              
794             Uniformizes the distinct names that every type can receive
795              
796             B<Arguments>
797              
798             The requested type (str)
799              
800             B<Returns>
801              
802             The qualified type (str or undef)
803              
804             =cut
805              
806             sub _qualify_type {
807 261     261   339 my($self,$value) = @_;
808 261 50       431 return unless $value;
809 261         324 $value = lc $value;
810 261 50       509 $value = "pattern" if $value=~/^(patt(ern)?)$/;
811 261 50       441 $value = "profile" if $value=~/^(prof(ile)?)$/;
812 261 100       607 $value = "repeat" if $value=~/^(rep(eat)?)$/;
813 261 50       814 $value = "similarity" if $value=~/^((sequence)?sim(ilarity)?|homology|ident(ity)?)$/;
814 261 50       439 $value = "coding" if $value=~/^(cod|cds)$/;
815 261 50       513 $value = "composition" if $value=~/^(comp(osition)?|content)$/;
816 261         546 return $value;
817             # TRUST IT! if $value =~ /^(pattern|profile|repeat|similarity|coding|composition|crispr)$/;
818             }
819              
820             =head2 _initialize
821              
822             =cut
823              
824             sub _initialize {
825 0     0     my $self = shift;
826 0           $self->throw("_initialize", $self, "Bio::Polloc::Polloc::NotImplementedException");
827             }
828              
829             1;