File Coverage

blib/lib/Bio/SeqFeature/Annotated.pm
Criterion Covered Total %
statement 174 314 55.4
branch 67 168 39.8
condition 24 112 21.4
subroutine 35 52 67.3
pod 35 35 100.0
total 335 681 49.1


line stmt bran cond sub pod time code
1             # $Id$
2             #
3             # BioPerl module for Bio::SeqFeature::Annotated
4             #
5             # Please direct questions and support issues to
6             #
7             # Cared for by Allen Day
8             #
9             # Copyright Allen Day
10             #
11             # You may distribute this module under the same terms as perl itself
12              
13             # POD documentation - main docs before the code
14              
15             =head1 NAME
16              
17             Bio::SeqFeature::Annotated - PLEASE PUT SOMETHING HERE
18              
19             =head1 SYNOPSIS
20              
21             # none yet, complain to authors
22              
23             =head1 DESCRIPTION
24              
25             None yet, complain to authors.
26              
27             =head1 Implemented Interfaces
28              
29             This class implements the following interfaces.
30              
31             =over 4
32              
33             =item Bio::SeqFeatureI
34              
35             Note that this includes implementing Bio::RangeI.
36              
37             =item Bio::AnnotatableI
38              
39             =item Bio::FeatureHolderI
40              
41             Features held by a feature are essentially sub-features.
42              
43             =back
44              
45             =head1 FEEDBACK
46              
47             =head2 Mailing Lists
48              
49             User feedback is an integral part of the evolution of this and other
50             Bioperl modules. Send your comments and suggestions preferably to one
51             of the Bioperl mailing lists. Your participation is much appreciated.
52              
53             bioperl-l@bioperl.org - General discussion
54             http://bioperl.org/wiki/Mailing_lists - About the mailing lists
55              
56             =head2 Support
57              
58             Please direct usage questions or support issues to the mailing list:
59              
60             I
61              
62             rather than to the module maintainer directly. Many experienced and
63             reponsive experts will be able look at the problem and quickly
64             address it. Please include a thorough description of the problem
65             with code and data examples if at all possible.
66              
67             =head2 Reporting Bugs
68              
69             Report bugs to the Bioperl bug tracking system to help us keep track
70             the bugs and their resolution. Bug reports can be submitted via
71             the web:
72              
73             http://bugzilla.open-bio.org/
74              
75             =head1 AUTHOR - Allen Day
76              
77             Allen Day Eallenday at ucla.eduE
78              
79             =head1 APPENDIX
80              
81             The rest of the documentation details each of the object
82             methods. Internal methods are usually preceded with a _
83              
84             =cut
85              
86              
87             package Bio::SeqFeature::Annotated;
88             BEGIN {
89 3     3   100 $Bio::SeqFeature::Annotated::AUTHORITY = 'cpan:BIOPERLML';
90             }
91             $Bio::SeqFeature::Annotated::VERSION = '1.6.905';
92 3     3   15 use strict;
  3         5  
  3         55  
93              
94 3     3   883 use Bio::Annotation::Collection;
  3         8904  
  3         96  
95 3     3   378 use Bio::Annotation::OntologyTerm;
  3         15267  
  3         64  
96 3     3   267 use Bio::Annotation::Target;
  3         3921  
  3         66  
97 3     3   925 use Bio::LocatableSeq;
  3         71930  
  3         105  
98 3     3   33 use Bio::Location::Simple;
  3         6  
  3         77  
99 3     3   13 use Bio::Ontology::OntologyStore;
  3         14  
  3         73  
100 3     3   1437 use Bio::Tools::GFF;
  3         59629  
  3         126  
101 3     3   1079 use Bio::SeqFeature::AnnotationAdaptor;
  3         2858  
  3         78  
102 3     3   19 use Data::Dumper;
  3         6  
  3         164  
103 3     3   793 use URI::Escape;
  3         3837  
  3         171  
104              
105 3         978 use base qw(Bio::Root::Root
106             Bio::SeqFeature::TypedSeqFeatureI
107             Bio::AnnotatableI
108 3     3   21 Bio::FeatureHolderI);
  3         5  
109              
110             our %tagclass = (
111             comment => 'Bio::Annotation::Comment',
112             dblink => 'Bio::Annotation::DBLink',
113             description => 'Bio::Annotation::SimpleValue',
114             gene_name => 'Bio::Annotation::SimpleValue',
115             ontology_term => 'Bio::Annotation::OntologyTerm',
116             reference => 'Bio::Annotation::Reference',
117             __DEFAULT__ => 'Bio::Annotation::SimpleValue',
118             );
119              
120             our %tag2text = (
121             'Bio::Annotation::Comment' => 'text',
122             'Bio::Annotation::DBLink' => 'primary_id',
123             'Bio::Annotation::SimpleValue' => 'value',
124             'Bio::Annotation::SimpleValue' => 'value',
125             'Bio::Annotation::OntologyTerm' => 'name',
126             'Bio::Annotation::Reference' => 'title',
127             __DEFAULT__ => 'value',
128             );
129              
130             ######################################
131             #get_SeqFeatures
132             #display_name
133             #primary_tag
134             #source_tag x with warning
135             #has_tag
136             #get_tag_values
137             #get_tagset_values
138             #get_all_tags
139             #attach_seq
140             #seq x
141             #entire_seq x
142             #seq_id
143             #gff_string
144             #_static_gff_handler
145             #start x
146             #end x
147             #strand x
148             #location
149             #primary_id
150              
151             =head1 PREAMBLE
152              
153             Okay, where to start...
154              
155             The original idea for this class appears to lump all SeqFeatureI data
156             (primary_tag, source_tag, etc) into AnnotationI objects into an
157             Bio::Annotation::Collection. The type is then checked against SOFA.
158              
159             There have been several requests to have type checking be optionally run.
160              
161             Bio::FeatureHolderI::create_hierarchy_from_ParentIDs
162             Bio::FeatureHolderI::feature_count
163             Bio::FeatureHolderI::get_all_SeqFeatures
164             Bio::FeatureHolderI::set_ParentIDs_from_hierarchy
165             Bio::RangeI::contains
166             Bio::RangeI::disconnected_ranges
167             Bio::RangeI::equals
168             Bio::RangeI::intersection
169             Bio::RangeI::offsetStranded
170             Bio::RangeI::overlap_extent
171             Bio::RangeI::overlaps
172             Bio::RangeI::subtract
173             Bio::RangeI::union
174             Bio::SeqFeature::Annotated::Dumper
175             Bio::SeqFeature::Annotated::MAX_TYPE_CACHE_MEMBERS
176             Bio::SeqFeature::Annotated::add_Annotation
177             Bio::SeqFeature::Annotated::add_SeqFeature
178             Bio::SeqFeature::Annotated::add_tag_value
179             Bio::SeqFeature::Annotated::add_target
180             Bio::SeqFeature::Annotated::annotation
181             Bio::SeqFeature::Annotated::attach_seq
182             Bio::SeqFeature::Annotated::display_name
183             Bio::SeqFeature::Annotated::each_target
184             Bio::SeqFeature::Annotated::end
185             Bio::SeqFeature::Annotated::entire_seq
186             Bio::SeqFeature::Annotated::frame
187             Bio::SeqFeature::Annotated::from_feature
188             Bio::SeqFeature::Annotated::get_Annotations
189             Bio::SeqFeature::Annotated::get_SeqFeatures
190             Bio::SeqFeature::Annotated::get_all_tags
191             Bio::SeqFeature::Annotated::get_tag_values
192             Bio::SeqFeature::Annotated::get_tagset_values
193             Bio::SeqFeature::Annotated::has_tag
194             Bio::SeqFeature::Annotated::length
195             Bio::SeqFeature::Annotated::location
196             Bio::SeqFeature::Annotated::name
197             Bio::SeqFeature::Annotated::new
198             Bio::SeqFeature::Annotated::phase
199             Bio::SeqFeature::Annotated::primary_tag
200             Bio::SeqFeature::Annotated::remove_Annotations
201             Bio::SeqFeature::Annotated::remove_SeqFeatures
202             Bio::SeqFeature::Annotated::remove_tag
203             Bio::SeqFeature::Annotated::score
204             Bio::SeqFeature::Annotated::seq
205             Bio::SeqFeature::Annotated::seq_id
206             Bio::SeqFeature::Annotated::source
207             Bio::SeqFeature::Annotated::source_tag
208             Bio::SeqFeature::Annotated::start
209             Bio::SeqFeature::Annotated::strand
210             Bio::SeqFeature::Annotated::type
211             Bio::SeqFeature::Annotated::uri_escape
212             Bio::SeqFeature::Annotated::uri_unescape
213             Bio::SeqFeature::TypedSeqFeatureI::croak
214             Bio::SeqFeature::TypedSeqFeatureI::ontology_term
215             Bio::SeqFeatureI::generate_unique_persistent_id
216             Bio::SeqFeatureI::gff_string
217             Bio::SeqFeatureI::primary_id
218             Bio::SeqFeatureI::spliced_seq
219              
220             =cut
221              
222             sub new {
223 59     59 1 131 my ( $caller, @args) = @_;
224 59         260 my ($self) = $caller->SUPER::new(@args);
225              
226 59         643 $self->_initialize(@args);
227              
228 59         137 return $self;
229             }
230              
231             sub _initialize {
232 59     59   130 my ($self,@args) = @_;
233 59         314 my ($start, $end, $strand, $frame, $phase, $score,
234             $name, $annot, $location,
235             $display_name, # deprecate
236             $seq_id, $type,$source,$feature
237             ) =
238             $self->_rearrange([qw(START
239             END
240             STRAND
241             FRAME
242             PHASE
243             SCORE
244             NAME
245             ANNOTATION
246             LOCATION
247             DISPLAY_NAME
248             SEQ_ID
249             TYPE
250             SOURCE
251             FEATURE
252             )], @args);
253 59 100       452 defined $start && $self->start($start);
254 59 100       140 defined $end && $self->end($end);
255 59 100       152 defined $strand && $self->strand($strand);
256 59 50       137 defined $frame && $self->frame($frame);
257 59 50       108 defined $phase && $self->phase($phase);
258 59 50       121 defined $score && $self->score($score);
259 59 50 33     236 defined $source && ref($source) ? $self->source($source) : $self->source_tag($source);
260 59 50 33     877 defined $type && ref($type) ? $self->type($type) : $self->primary_tag($type);
261 59 50       124 defined $location && $self->location($location);
262 59 50       109 defined $annot && $self->annotation($annot);
263 59 50       112 defined $feature && $self->from_feature($feature);
264              
265 59 50 33     124 if( defined($display_name) && defined($name) ){
266 0         0 $self->throw('Cannot define (-id and -seq_id) or (-name and -display_name) attributes');
267             }
268 59 50       105 defined $seq_id && $self->seq_id($seq_id);
269 59 50 0     227 defined ($name || $display_name) && $self->name($name || $display_name);
      33        
270             }
271              
272             =head1 ATTRIBUTE ACCESSORS FOR Bio::SeqFeature::Annotated
273              
274             =cut
275              
276             =head2 from_feature
277              
278             Usage: $obj->from_feature($myfeature);
279             Desc : initialize this object with the contents of another feature
280             object. Useful for converting objects like
281             L to this class
282             Ret : nothing meaningful
283             Args : a single object of some other feature type,
284             Side Effects: throws error on failure
285             Example:
286              
287             =cut
288              
289             sub from_feature {
290 0     0 1 0 my ($self,$feat,%opts) = @_;
291            
292             # should deal with any SeqFeatureI implementation (i.e. we don't want to
293             # automatically force a OO-heavy implementation on all classes)
294 0 0 0     0 ref($feat) && ($feat->isa('Bio::SeqFeatureI'))
295             or $self->throw('invalid arguments to from_feature');
296            
297             #TODO: add overrides in opts for these values, so people don't have to screw up their feature object
298             #if they don't want to
299            
300             ### set most of the data
301 0         0 foreach my $fieldname (qw/ start end strand frame score location seq_id source_tag primary_tag/) {
302             #no strict 'refs'; #using symbolic refs, yes, but using them for methods is allowed now
303 0         0 $self->$fieldname( $feat->$fieldname );
304             }
305              
306             # now pick up the annotations/tags of the other feature
307             # We'll use AnnotationAdaptor to convert everything over
308              
309 0         0 my %no_copy = map {$_ => 1} qw/seq_id source type frame phase score/;
  0         0  
310 0         0 my $adaptor = Bio::SeqFeature::AnnotationAdaptor->new(-feature => $feat);
311 0         0 for my $key ( $adaptor->get_all_annotation_keys() ) {
312 0 0       0 next if $no_copy{$key};
313 0         0 my @values = $adaptor->get_Annotations($key);
314 0         0 @values = _aggregate_scalar_annotations(\%opts,$key,@values);
315 0         0 foreach my $val (@values) {
316 0         0 $self->add_Annotation($key,$val)
317             }
318             }
319             }
320             #given a key and its values, make the values into
321             #Bio::Annotation::\w+ objects
322              
323             sub _aggregate_scalar_annotations {
324 0     0   0 my ($opts,$key,@values) = @_;
325              
326             #anything that's not an object, make it a SimpleValue
327 0 0       0 @values = map { ref($_) ? $_ : Bio::Annotation::SimpleValue->new(-value => $_) } @values;
  0         0  
328              
329             #try to make Target objects
330 0 0 0     0 if($key eq 'Target' && (@values == 3 || @values == 4)
    0 0        
    0 0        
    0 0        
331 0         0 && @values == grep {$_->isa('Bio::Annotation::SimpleValue')} @values
332             ) {
333 0         0 @values = map {$_->value} @values;
  0         0  
334             #make a strand if it doesn't have one, enforcing start <= end
335 0 0       0 if(@values == 3) {
336 0 0       0 if($values[1] <= $values[2]) {
337 0         0 $values[3] = '+';
338             } else {
339 0         0 @values[1,2] = @values[2,1];
340 0         0 $values[3] = '-';
341             }
342             }
343 0         0 return ( Bio::Annotation::Target->new( -target_id => $values[0],
344             -start => $values[1],
345             -end => $values[2],
346             -strand => $values[3],
347             )
348             );
349             }
350             #try to make DBLink objects
351             elsif($key eq 'dblink' || $key eq 'Dbxref') {
352             return map {
353 0 0       0 if( /:/ ) { #convert to a DBLink if it has a colon in it
  0         0  
354 0         0 my ($db,$id) = split /:/,$_->value;
355 0         0 Bio::Annotation::DBLink->new( -database => $db,
356             -primary_id => $id,
357             );
358             } else { #otherwise leave as a SimpleValue
359 0         0 $_
360             }
361             } @values;
362             }
363             #make OntologyTerm objects
364             elsif($key eq 'Ontology_term') {
365 0         0 return map { Bio::Annotation::OntologyTerm->new(-identifier => $_->value) } @values
  0         0  
366             }
367             #make Comment objects
368             elsif($key eq 'comment') {
369 0         0 return map { Bio::Annotation::Comment->new( -text => $_->value ) } @values;
  0         0  
370             }
371              
372 0         0 return @values;
373             }
374              
375              
376             =head2 seq_id()
377              
378             Usage : $obj->seq_id($newval)
379             Function: holds a string corresponding to the unique
380             seq_id of the sequence underlying the feature
381             (e.g. database accession or primary key).
382             Returns : string representing the seq_id.
383             Args : on set, some string or a Bio::Annotation::SimpleValue object.
384              
385             =cut
386              
387             sub seq_id {
388 69     69 1 5607 my($self,$val) = @_;
389 69 100       176 if (defined($val)) {
390 59         96 my $term = undef;
391 59 50 0     119 if (!ref($val)) {
    0          
392 59         199 $term = Bio::Annotation::SimpleValue->new(-value => uri_unescape($val));
393             } elsif (ref($val) && $val->isa('Bio::Annotation::SimpleValue')) {
394 0         0 $term = $val;
395             }
396 59 50 33     4047 if (!defined($term) || ($term->value =~ /^>/)) {
397 0         0 $self->throw('give seq_id() a scalar or Bio::Annotation::SimpleValue object, not '.$val);
398             }
399 59         503 $self->remove_Annotations('seq_id');
400 59         1092 $self->add_Annotation('seq_id', $term);
401             }
402              
403 69 50       2291 $self->seq_id('.') unless $self->get_Annotations('seq_id'); # make sure we always have something
404              
405 69         140 return ($self->get_Annotations('seq_id'))[0]->value;
406             }
407              
408             =head2 name()
409              
410             Usage : $obj->name($newval)
411             Function: human-readable name for the feature.
412             Returns : value of name (a scalar)
413             Args : on set, new value (a scalar or undef, optional)
414              
415             =cut
416              
417             sub name {
418 0     0 1 0 my($self,$val) = @_;
419 0 0       0 $self->{'name'} = $val if defined($val);
420 0         0 return $self->{'name'};
421             }
422              
423             =head2 type()
424              
425             Usage : $obj->type($newval)
426             Function: a SOFA type for the feature.
427             Returns : Bio::Annotation::OntologyTerm object representing the type.
428             NB: to get a string, use primary_tag().
429             Args : on set, Bio::Annotation::OntologyTerm object.
430             NB: to set a string (SOFA name or identifier), use primary_tag()
431              
432             =cut
433              
434 3     3   3302 use constant MAX_TYPE_CACHE_MEMBERS => 20;
  3         5  
  3         6230  
435             sub type {
436 155     155 1 280 my($self,$val) = @_;
437 155 100       315 if(defined($val)){
438 58         93 my $term = undef;
439              
440 58 50 33     313 if(!ref($val)){
    50          
441 0         0 $self->throw("give type() a Bio::Annotation::OntologyTerm object, not a string");
442             }
443             elsif(ref($val) && $val->isa('Bio::Annotation::OntologyTerm')){
444 58         89 $term = $val;
445             }
446             else {
447             #we have the wrong type of object
448 0         0 $self->throw('give type() a SOFA term name, identifier, or Bio::Annotation::OntologyTerm object, not '.$val);
449             }
450 58         149 $self->remove_Annotations('type');
451 58         1049 $self->add_Annotation('type',$term);
452             }
453            
454 155         2412 return $self->get_Annotations('type');
455             }
456              
457             =head2 source()
458              
459             Usage : $obj->source($newval)
460             Function: holds the source of the feature.
461             Returns : a Bio::Annotation::SimpleValue representing the source.
462             NB: to get a string, use source_tag()
463             Args : on set, a Bio::Annotation::SimpleValue object.
464             NB: to set a string, use source_tag()
465              
466             =cut
467              
468             sub source {
469 240     240 1 4096 my($self,$val) = @_;
470              
471 240 100       429 if (defined($val)) {
472 116         160 my $term;
473 116 50 33     630 if (!ref($val)) {
    50          
474 0         0 $self->throw("give source() a Bio::Annotation::SimpleValue object, not a string");
475             #$term = Bio::Annotation::SimpleValue->new(-value => uri_unescape($val));
476             } elsif (ref($val) && $val->isa('Bio::Annotation::SimpleValue')) {
477 116         178 $term = $val;
478             } else {
479 0         0 $self->throw('give source() a scalar or Bio::Annotation::SimpleValue object, not '.$val);
480             }
481 116         279 $self->remove_Annotations('source');
482 116         3637 $self->add_Annotation('source', $term);
483             }
484            
485 240 100       4825 unless ($self->get_Annotations('source')) {
486 59         235 $self->source(Bio::Annotation::SimpleValue->new(-value => '.'));
487             }
488 240         427 return $self->get_Annotations('source');
489             }
490              
491             =head2 score()
492              
493             Usage : $score = $feat->score()
494             $feat->score($score)
495             Function: holds a value corresponding to the score of the feature.
496             Returns : a string representing the score.
497             Args : on set, a scalar or a Bio::Annotation::SimpleValue object.
498              
499             =cut
500              
501             sub score {
502 66     66 1 5061 my $self = shift;
503 66         93 my $val = shift;
504              
505 66 100       159 if(defined($val)){
506 58         78 my $term = undef;
507 58 50 0     133 if (!ref($val)) {
    0          
508 58         165 $term = Bio::Annotation::SimpleValue->new(-value => $val);
509             } elsif (ref($val) && $val->isa('Bio::Annotation::SimpleValue')) {
510 0         0 $term = $val;
511             }
512              
513 58 50 33     3351 if ($term->value ne '.' &&
      66        
514             (!defined($term) || ($term->value !~ /^[+-]?\d+\.?\d*(e-\d+)?/))) {
515 0         0 $self->throw("'$val' is not a valid score");
516             }
517 58         521 $self->remove_Annotations('score');
518 58         1112 $self->add_Annotation('score', $term);
519             }
520              
521 66 100       2279 $self->score('.') unless scalar($self->get_Annotations('score')); # make sure we always have something
522              
523 66         137 return ($self->get_Annotations('score'))[0]->display_text;
524             }
525              
526             =head2 phase()
527              
528             Usage : $phase = $feat->phase()
529             $feat->phase($phase)
530             Function: get/set on phase information
531             Returns : a string 0,1,2,'.'
532             Args : on set, one of 0,1,2,'.' or a Bio::Annotation::SimpleValue
533             object holding one of 0,1,2,'.' as its value.
534              
535             =cut
536              
537             sub phase {
538 57     57 1 79 my $self = shift;
539 57         96 my $val = shift;
540              
541 57 50       124 if(defined($val)){
542 57         78 my $term = undef;
543 57 50 0     112 if (!ref($val)) {
    0          
544 57         155 $term = Bio::Annotation::SimpleValue->new(-value => $val);
545             } elsif (ref($val) && $val->isa('Bio::Annotation::SimpleValue')) {
546 0         0 $term = $val;
547             }
548 57 50 33     3388 if (!defined($term) || ($term->value !~ /^[0-2.]$/)) {
549 0         0 $self->throw("'$val' is not a valid phase");
550             }
551 57         529 $self->remove_Annotations('phase');
552 57         1047 $self->add_Annotation('phase', $term);
553             }
554              
555 57 50       2217 $self->phase('.') unless $self->get_Annotations('phase'); # make sure we always have something
556            
557 57         108 return ($self->get_Annotations('phase'))[0]->value;
558             }
559              
560              
561             =head2 frame()
562              
563             Usage : $frame = $feat->frame()
564             $feat->frame($phase)
565             Function: get/set on phase information
566             Returns : a string 0,1,2,'.'
567             Args : on set, one of 0,1,2,'.' or a Bio::Annotation::SimpleValue
568             object holding one of 0,1,2,'.' as its value.
569              
570             =cut
571              
572             sub frame {
573 0     0 1 0 my $self = shift;
574 0         0 my $val = shift;
575              
576 0 0       0 if(defined($val)){
577 0         0 my $term = undef;
578 0 0 0     0 if (!ref($val)) {
    0          
579 0         0 $term = Bio::Annotation::SimpleValue->new(-value => $val);
580             } elsif (ref($val) && $val->isa('Bio::Annotation::SimpleValue')) {
581 0         0 $term = $val;
582             }
583 0 0 0     0 if (!defined($term) || ($term->value !~ /^[0-2.]$/)) {
584 0         0 $self->throw("'$val' is not a valid frame");
585             }
586 0         0 $self->remove_Annotations('frame');
587 0         0 $self->add_Annotation('frame', $term);
588             }
589              
590 0 0       0 $self->frame('.') unless $self->get_Annotations('frame'); # make sure we always have something
591            
592 0         0 return ($self->get_Annotations('frame'))[0]->value;
593             }
594              
595             ############################################################
596              
597             =head1 SHORTCUT METHODS TO ACCESS Bio::AnnotatableI INTERFACE METHODS
598              
599             =cut
600              
601             =head2 add_Annotation()
602              
603             Usage :
604             Function: $obj->add_Annotation() is a shortcut to $obj->annotation->add_Annotation
605             Returns :
606             Args :
607              
608             =cut
609              
610             sub add_Annotation {
611 507     507 1 948 my ($self,@args) = @_;
612 507         788 return $self->annotation->add_Annotation(@args);
613             }
614              
615             =head2 remove_Annotations()
616              
617             Usage :
618             Function: $obj->remove_Annotations() is a shortcut to $obj->annotation->remove_Annotations
619             Returns :
620             Args :
621              
622             =cut
623              
624             sub remove_Annotations {
625 348     348 1 616 my ($self,@args) = @_;
626 348         581 return $self->annotation->remove_Annotations(@args);
627             }
628              
629             ############################################################
630              
631             =head1 INTERFACE METHODS FOR Bio::SeqFeatureI
632              
633             Note that no methods are deprecated. Any SeqFeatureI methods must return
634             strings (no objects).
635              
636             =cut
637              
638             =head2 display_name()
639              
640             =cut
641              
642             sub display_name {
643 0     0 1 0 my $self = shift;
644 0         0 return $self->name(@_);
645             }
646              
647             =head2 primary_tag()
648              
649             =cut
650              
651             sub primary_tag {
652 97     97 1 13279 my $self = shift;
653 97 100       237 if (@_) {
654 59         86 my $val = shift;
655 59         75 my $term;
656 59 50 33     232 if(!ref($val) && $val){
657             #we have a plain text annotation coming in. try to map it to SOFA.
658              
659 0         0 our %__type_cache; #a little cache of plaintext types we've already seen
660              
661             #clear our cache if it gets too big
662 0 0       0 if(scalar(keys %__type_cache) > MAX_TYPE_CACHE_MEMBERS) {
663 0         0 %__type_cache = ();
664             }
665              
666             #set $term to either a cached value, or look up a new one, throwing
667             #up if not found
668 0         0 my $anntext = $val;
669 0 0       0 if ($__type_cache{$anntext}) {
670 0         0 $term = $__type_cache{$anntext};
671             } else {
672 0         0 my $sofa = Bio::Ontology::OntologyStore->get_instance->get_ontology('Sequence Ontology OBO');
673 0 0       0 my ($soterm) = $anntext =~ /^\D+:\d+$/ #does it look like an ident?
674             ? ($sofa->find_terms(-identifier => $anntext))[0] #yes, lookup by ident
675             : ($sofa->find_terms(-name => $anntext))[0]; #no, lookup by name
676             #throw if it's not in SOFA
677 0 0       0 unless($soterm){
678 0         0 $self->throw("couldn't find a SOFA term matching type '$val'.");
679             }
680 0         0 my $newterm = Bio::Annotation::OntologyTerm->new;
681 0         0 $newterm->term($soterm);
682 0         0 $term = $newterm;
683             }
684            
685 0         0 $self->type($term);
686             }
687             }
688            
689 97   100     227 my $t = $self->type() || return;
690 38         102 return $t->name;
691             }
692              
693             =head2 source_tag()
694              
695             =cut
696              
697             sub source_tag {
698 124     124 1 5373 my $self = shift;
699 124 100       270 if (@_) {
700 116         172 my $val = shift;
701 116 100 66     389 if(!ref($val) && $val){
702 57         126 my $term = Bio::Annotation::SimpleValue->new(-value => uri_unescape($val));
703 57         3591 $self->source($term);
704             }
705             }
706 124   50     251 my $t = $self->source() || return;
707 124         271 return $t->display_text;
708             }
709              
710              
711             =head2 attach_seq()
712              
713             Usage : $sf->attach_seq($seq)
714             Function: Attaches a Bio::Seq object to this feature. This
715             Bio::Seq object is for the *entire* sequence: ie
716             from 1 to 10000
717             Returns : TRUE on success
718             Args : a Bio::PrimarySeqI compliant object
719              
720             =cut
721              
722             sub attach_seq {
723 0     0 1 0 my ($self, $seq) = @_;
724              
725 0 0 0     0 if ( ! ($seq && ref($seq) && $seq->isa("Bio::PrimarySeqI")) ) {
      0        
726 0         0 $self->throw("Must attach Bio::PrimarySeqI objects to SeqFeatures");
727             }
728              
729 0         0 $self->{'seq'} = $seq;
730              
731             # attach to sub features if they want it
732 0         0 foreach ( $self->get_SeqFeatures() ) {
733 0         0 $_->attach_seq($seq);
734             }
735 0         0 return 1;
736             }
737              
738             =head2 seq()
739              
740             Usage : $tseq = $sf->seq()
741             Function: returns a truncated version of seq() with bounds matching this feature
742             Returns : sub seq (a Bio::PrimarySeqI compliant object) on attached sequence
743             bounded by start & end, or undef if there is no sequence attached
744             Args : none
745              
746             =cut
747              
748             sub seq {
749 0     0 1 0 my ($self) = @_;
750              
751 0 0       0 return unless defined($self->entire_seq());
752              
753 0         0 my $seq = $self->entire_seq->trunc($self->start(), $self->end());
754              
755 0 0 0     0 if ( defined $self->strand && $self->strand == -1 ) {
756 0         0 $seq = $seq->revcom;
757             }
758              
759 0         0 return $seq;
760             }
761              
762             =head2 entire_seq()
763              
764             Usage : $whole_seq = $sf->entire_seq()
765             Function: gives the entire sequence that this seqfeature is attached to
766             Returns : a Bio::PrimarySeqI compliant object, or undef if there is no
767             sequence attached
768             Args : none
769              
770             =cut
771              
772             sub entire_seq {
773 0     0 1 0 return shift->{'seq'};
774             }
775              
776             ############################################################
777              
778             =head1 INTERFACE METHODS FOR Bio::RangeI
779              
780             as inherited via Bio::SeqFeatureI
781              
782             =cut
783              
784             =head2 length()
785              
786             Usage : $feature->length()
787             Function: Get the feature length computed as $feat->end - $feat->start + 1
788             Returns : integer
789             Args : none
790              
791             =cut
792              
793             sub length {
794 0     0 1 0 my $self = shift;
795 0         0 return $self->end() - $self->start() + 1;
796             }
797              
798             =head2 start()
799              
800             Usage : $obj->start($newval)
801             Function: Get/set on the start coordinate of the feature
802             Returns : integer
803             Args : on set, new value (a scalar or undef, optional)
804              
805             =cut
806              
807             sub start {
808 164     164 1 6395 my ($self,$value) = @_;
809 164         301 return $self->location->start($value);
810             }
811              
812             =head2 end()
813              
814             Usage : $obj->end($newval)
815             Function: Get/set on the end coordinate of the feature
816             Returns : integer
817             Args : on set, new value (a scalar or undef, optional)
818              
819             =cut
820              
821             sub end {
822 164     164 1 7356 my ($self,$value) = @_;
823 164         288 return $self->location->end($value);
824             }
825              
826             =head2 strand()
827              
828             Usage : $strand = $feat->strand($newval)
829             Function: get/set on strand information, being 1,-1 or 0
830             Returns : -1,1 or 0
831             Args : on set, new value (a scalar or undef, optional)
832              
833             =cut
834              
835             sub strand {
836 67     67 1 5144 my $self = shift;
837 67         122 return $self->location->strand(@_);
838             }
839              
840              
841             ############################################################
842              
843             =head1 INTERFACE METHODS FOR Bio::FeatureHolderI
844              
845             This includes methods for retrieving, adding, and removing
846             features. Since this is already a feature, features held by this
847             feature holder are essentially sub-features.
848              
849             =cut
850              
851             =head2 get_SeqFeatures
852              
853             Usage : @feats = $feat->get_SeqFeatures();
854             Function: Returns an array of Bio::SeqFeatureI objects
855             Returns : An array
856             Args : none
857              
858             =cut
859              
860             sub get_SeqFeatures {
861 6 100   6 1 4002 return @{ shift->{'sub_array'} || []};
  6         48  
862             }
863              
864             =head2 add_SeqFeature()
865              
866             Usage : $feat->add_SeqFeature($subfeat);
867             $feat->add_SeqFeature($subfeat,'EXPAND')
868             Function: adds a SeqFeature into the subSeqFeature array.
869             with no 'EXPAND' qualifer, subfeat will be tested
870             as to whether it lies inside the parent, and throw
871             an exception if not.
872              
873             If EXPAND is used, the parent''s start/end/strand will
874             be adjusted so that it grows to accommodate the new
875             subFeature
876             Example :
877             Returns : nothing
878             Args : a Bio::SeqFeatureI object
879              
880             =cut
881              
882             sub add_SeqFeature {
883 24     24 1 49 my ($self,$val, $expand) = @_;
884              
885 24 50       46 return unless $val;
886              
887 24 50 33     133 if ((!ref($val)) || !$val->isa('Bio::SeqFeatureI') ) {
888 0 0       0 $self->throw((ref($val) ? ref($val) : $val)
889             ." does not implement Bio::SeqFeatureI.");
890             }
891              
892 24 50 33     68 if($expand && ($expand eq 'EXPAND')) {
893 0         0 $self->_expand_region($val);
894             } else {
895 24 50       127 if ( !$self->contains($val) ) {
896 0         0 $self->warn("$val is not contained within parent feature, and expansion is not valid, ignoring.");
897 0         0 return;
898             }
899             }
900              
901 24         404 push(@{$self->{'sub_array'}},$val);
  24         103  
902             }
903              
904             =head2 remove_SeqFeatures()
905              
906             Usage : $obj->remove_SeqFeatures
907             Function: Removes all sub SeqFeatures. If you want to remove only a subset,
908             remove that subset from the returned array, and add back the rest.
909             Returns : The array of Bio::SeqFeatureI implementing sub-features that was
910             deleted from this feature.
911             Args : none
912              
913             =cut
914              
915             sub remove_SeqFeatures {
916 0     0 1 0 my ($self) = @_;
917              
918 0 0       0 my @subfeats = @{$self->{'sub_array'} || []};
  0         0  
919 0         0 $self->{'sub_array'} = []; # zap the array.
920 0         0 return @subfeats;
921             }
922              
923             ############################################################
924              
925             =head1 INTERFACE METHODS FOR Bio::AnnotatableI
926              
927             =cut
928              
929             =head2 annotation()
930              
931             Usage : $obj->annotation($annot_obj)
932             Function: Get/set the annotation collection object for annotating this
933             feature.
934             Returns : A Bio::AnnotationCollectionI object
935             Args : newvalue (optional)
936              
937             =cut
938              
939             sub annotation {
940 1946     1946 1 2730 my ($obj,$value) = @_;
941              
942             # we are smart if someone references the object and there hasn't been
943             # one set yet
944 1946 100 66     5896 if(defined $value || ! defined $obj->{'annotation'} ) {
945 59 50       267 $value = Bio::Annotation::Collection->new() unless ( defined $value );
946 59         3192 $obj->{'annotation'} = $value;
947             }
948 1946         4382 return $obj->{'annotation'};
949             }
950              
951             ############################################################
952              
953             =head2 location()
954              
955             Usage : my $location = $seqfeature->location()
956             Function: returns a location object suitable for identifying location
957             of feature on sequence or parent feature
958             Returns : Bio::LocationI object
959             Args : [optional] Bio::LocationI object to set the value to.
960              
961             =cut
962              
963             sub location {
964 395     395 1 579 my($self, $value ) = @_;
965              
966 395 50       974 if (defined($value)) {
    100          
967 0 0 0     0 unless (ref($value) and $value->isa('Bio::LocationI')) {
968 0         0 $self->throw("object $value pretends to be a location but ".
969             "does not implement Bio::LocationI");
970             }
971 0         0 $self->{'location'} = $value;
972             }
973             elsif (! $self->{'location'}) {
974             # guarantees a real location object is returned every time
975 59         233 $self->{'location'} = Bio::Location::Simple->new();
976             }
977 395         3850 return $self->{'location'};
978             }
979              
980             =head2 add_target()
981              
982             Usage : $seqfeature->add_target(Bio::LocatableSeq->new(...));
983             Function: adds a target location on another reference sequence for this feature
984             Returns : true on success
985             Args : a Bio::LocatableSeq object
986              
987             =cut
988              
989             sub add_target {
990 0     0 1 0 my ($self,$seq) = @_;
991 0 0 0     0 $self->throw("$seq is not a Bio::LocatableSeq, bailing out") unless ref($seq) and seq->isa('Bio::LocatableSeq');
992 0         0 push @{ $self->{'targets'} }, $seq;
  0         0  
993 0         0 return $seq;
994             }
995              
996             =head2 each_target()
997              
998             Usage : @targets = $seqfeature->each_target();
999             Function: Returns a list of Bio::LocatableSeqs which are the locations of this object.
1000             To obtain the "primary" location, see L.
1001             Returns : a list of 0..N Bio::LocatableSeq objects
1002             Args : none
1003              
1004             =cut
1005              
1006             sub each_target {
1007 0     0 1 0 my ($self) = @_;
1008 0 0       0 return $self->{'targets'} ? @{ $self->{'targets'} } : ();
  0         0  
1009             }
1010              
1011             =head2 _expand_region
1012              
1013             Title : _expand_region
1014             Usage : $self->_expand_region($feature);
1015             Function: Expand the total region covered by this feature to
1016             accomodate for the given feature.
1017              
1018             May be called whenever any kind of subfeature is added to this
1019             feature. add_SeqFeature() already does this.
1020             Returns :
1021             Args : A Bio::SeqFeatureI implementing object.
1022              
1023             =cut
1024              
1025             sub _expand_region {
1026 0     0   0 my ($self, $feat) = @_;
1027 0 0       0 if(! $feat->isa('Bio::SeqFeatureI')) {
1028 0         0 $self->warn("$feat does not implement Bio::SeqFeatureI");
1029             }
1030             # if this doesn't have start/end set - forget it!
1031 0 0 0     0 if((! defined($self->start())) && (! defined $self->end())) {
1032 0         0 $self->start($feat->start());
1033 0         0 $self->end($feat->end());
1034 0 0       0 $self->strand($feat->strand) unless defined($self->strand());
1035             # $self->strand($feat->strand) unless $self->strand();
1036             } else {
1037 0         0 my $range = $self->union($feat);
1038 0         0 $self->start($range->start);
1039 0         0 $self->end($range->end);
1040 0         0 $self->strand($range->strand);
1041             }
1042             }
1043              
1044             =head2 get_Annotations
1045              
1046             Usage : my $parent = $obj->get_Annotations('Parent');
1047             my @parents = $obj->get_Annotations('Parent');
1048             Function: a wrapper around Bio::Annotation::Collection::get_Annotations().
1049             Returns : returns annotations as
1050             Bio::Annotation::Collection::get_Annotations() does, but
1051             additionally returns a single scalar in scalar context
1052             instead of list context so that if an annotation tag
1053             contains only a single value, you can do:
1054              
1055             $parent = $feature->get_Annotations('Parent');
1056              
1057             instead of:
1058              
1059             ($parent) = ($feature->get_Annotations('Parent'))[0];
1060              
1061             if the 'Parent' tag has multiple values and is called in a
1062             scalar context, the number of annotations is returned.
1063              
1064             Args : an annotation tag name.
1065              
1066             =cut
1067              
1068             sub get_Annotations {
1069 1079     1079 1 1467 my $self = shift;
1070              
1071 1079         1644 my @annotations = $self->annotation->get_Annotations(@_);
1072              
1073 1079 100       29295 if(wantarray){
    100          
1074 222         568 return @annotations;
1075             } elsif(scalar(@annotations) == 1){
1076 714         1787 return $annotations[0];
1077             } else {
1078 143         368 return scalar(@annotations);
1079             }
1080             }
1081              
1082             =head1 Bio::SeqFeatureI implemented methods
1083              
1084             These are specialized implementations of SeqFeatureI methods which call the
1085             internal Bio::Annotation::AnnotationCollection object. Just prior to the 1.5
1086             release the below methods were moved from Bio::SeqFeatureI to Bio::AnnotatableI,
1087             and having Bio::SeqFeatureI inherit Bio::AnnotatableI. This behavior forced all
1088             Bio::SeqFeatureI-implementing classes to use Bio::AnnotationI objects for any
1089             data. It is the consensus of the core developers that this be rolled back in
1090             favor of a more flexible approach by rolling back the above changes and making
1091             this class Bio::AnnotatableI. The SeqFeatureI tag-related methods are
1092             reimplemented in order to approximate the same behavior as before.
1093              
1094             The methods below allow mapping of the "get_tag_values()"-style annotation
1095             access to Bio::AnnotationCollectionI. These need not be implemented in a
1096             Bio::AnnotationCollectionI compliant class, as they are built on top of the
1097             methods. For usage, see Bio::SeqFeatureI.
1098              
1099             =cut
1100              
1101             =head2 has_tag
1102              
1103             =cut
1104              
1105             sub has_tag {
1106 0     0 1 0 my ($self,$tag) = @_;
1107 0         0 return scalar($self->annotation->get_Annotations($tag));
1108             }
1109              
1110             =head2 add_tag_value
1111              
1112             =cut
1113              
1114             sub add_tag_value {
1115 0     0 1 0 my ($self,$tag,@vals) = @_;
1116              
1117 0         0 foreach my $val (@vals){
1118 0   0     0 my $class = $tagclass{$tag} || $tagclass{__DEFAULT__};
1119 0         0 my $slot = $tag2text{$class};
1120              
1121 0         0 my $a = $class->new();
1122 0         0 $a->$slot($val);
1123              
1124 0         0 $self->annotation->add_Annotation($tag,$a);
1125             }
1126              
1127 0         0 return 1;
1128             }
1129              
1130             =head2 get_tag_values
1131              
1132             Usage : @annotations = $obj->get_tag_values($tag)
1133             Function: returns annotations corresponding to $tag
1134             Returns : a list of scalars
1135             Args : tag name
1136              
1137             =cut
1138              
1139             sub get_tag_values {
1140 1     1 1 503 my ($self,$tag) = @_;
1141 1 50 33     9 if(!$tagclass{$tag} && $self->annotation->get_Annotations($tag)){
1142             #new tag, haven't seen it yet but it exists. add to registry
1143 1         26 my($proto) = $self->annotation->get_Annotations($tag);
1144             # we can only register if there's a method known for obtaining the value
1145 1 50       21 if (exists($tag2text{ref($proto)})) {
1146 1         4 $tagclass{$tag} = ref($proto);
1147             }
1148             }
1149              
1150 1   33     4 my $slot = $tag2text{ $tagclass{$tag} || $tagclass{__DEFAULT__} };
1151            
1152 1         3 return map { $_->$slot } $self->annotation->get_Annotations($tag);
  1         20  
1153             }
1154              
1155             =head2 get_tagset_values
1156              
1157             Usage : @annotations = $obj->get_tagset_values($tag1,$tag2)
1158             Function: returns annotations corresponding to a list of tags.
1159             this is a convenience method equivalent to multiple calls
1160             to get_tag_values with each tag in the list.
1161             Returns : a list of Bio::AnnotationI objects.
1162             Args : a list of tag names
1163              
1164             =cut
1165              
1166             sub get_tagset_values {
1167 8     8 1 7680 my ($self,@tags) = @_;
1168 8         24 my @r = ();
1169 8         24 foreach my $tag (@tags){
1170 8   33     72 my $slot = $tag2text{ $tagclass{$tag} || $tagclass{__DEFAULT__} };
1171 8         30 push @r, map { $_->$slot } $self->annotation->get_Annotations($tag);
  4         156  
1172             }
1173 8         104 return @r;
1174             }
1175              
1176             =head2 get_all_tags
1177              
1178             Usage : @tags = $obj->get_all_tags()
1179             Function: returns a list of annotation tag names.
1180             Returns : a list of tag names
1181             Args : none
1182              
1183             =cut
1184              
1185             sub get_all_tags {
1186 0     0 1   my ($self,@args) = @_;
1187 0           return $self->annotation->get_all_annotation_keys(@args);
1188             }
1189              
1190             =head2 remove_tag
1191              
1192             Usage : See remove_Annotations().
1193             Function:
1194             Returns :
1195             Args :
1196             Note : Contrary to what the name suggests, this method removes
1197             all annotations corresponding to $tag, not just a
1198             single anntoation.
1199              
1200             =cut
1201              
1202             sub remove_tag {
1203 0     0 1   my ($self,@args) = @_;
1204 0           return $self->annotation->remove_Annotations(@args);
1205             }
1206              
1207             1;