File Coverage

Bio/Annotation/Collection.pm
Criterion Covered Total %
statement 80 172 46.5
branch 27 62 43.5
condition 4 9 44.4
subroutine 14 27 51.8
pod 22 22 100.0
total 147 292 50.3


line stmt bran cond sub pod time code
1             #
2             # BioPerl module for Bio::Annotation::Collection.pm
3             #
4             # Please direct questions and support issues to
5             #
6             # Cared for by Ewan Birney
7             #
8             # Copyright Ewan Birney
9             #
10             # You may distribute this module under the same terms as perl itself
11              
12             # POD documentation - main docs before the code
13              
14             =head1 NAME
15              
16             Bio::Annotation::Collection - Default Perl implementation of
17             AnnotationCollectionI
18              
19             =head1 SYNOPSIS
20              
21             # get an AnnotationCollectionI somehow, eg
22              
23             $ac = $seq->annotation();
24              
25             foreach $key ( $ac->get_all_annotation_keys() ) {
26             @values = $ac->get_Annotations($key);
27             foreach $value ( @values ) {
28             # value is an Bio::AnnotationI, and defines a "as_text" method
29             print "Annotation ",$key," stringified value ",$value->as_text,"\n";
30              
31             # also defined hash_tree method, which allows data orientated
32             # access into this object
33             $hash = $value->hash_tree();
34             }
35             }
36              
37             =head1 DESCRIPTION
38              
39             Bioperl implementation for Bio::AnnotationCollectionI
40              
41             =head1 FEEDBACK
42              
43             =head2 Mailing Lists
44              
45             User feedback is an integral part of the evolution of this and other
46             Bioperl modules. Send your comments and suggestions preferably to one
47             of the Bioperl mailing lists. Your participation is much appreciated.
48              
49             bioperl-l@bioperl.org - General discussion
50             http://bioperl.org/wiki/Mailing_lists - About the mailing lists
51              
52             =head2 Support
53              
54             Please direct usage questions or support issues to the mailing list:
55              
56             I
57              
58             rather than to the module maintainer directly. Many experienced and
59             reponsive experts will be able look at the problem and quickly
60             address it. Please include a thorough description of the problem
61             with code and data examples if at all possible.
62              
63             =head2 Reporting Bugs
64              
65             Report bugs to the Bioperl bug tracking system to help us keep track
66             the bugs and their resolution. Bug reports can be submitted via
67             the web:
68              
69             https://github.com/bioperl/bioperl-live/issues
70              
71             =head1 AUTHOR - Ewan Birney
72              
73             Email birney@ebi.ac.uk
74              
75             =head1 APPENDIX
76              
77             The rest of the documentation details each of the object
78             methods. Internal methods are usually preceded with a _
79              
80             =cut
81              
82              
83             # Let the code begin...
84              
85              
86             package Bio::Annotation::Collection;
87              
88 187     187   1485 use strict;
  187         374  
  187         6067  
89              
90             # Object preamble - inherits from Bio::Root::Root
91              
92 187     187   44793 use Bio::Annotation::TypeManager;
  187         466  
  187         4810  
93 187     187   47059 use Bio::Annotation::SimpleValue;
  187         387  
  187         5146  
94              
95              
96 187     187   1012 use base qw(Bio::Root::Root Bio::AnnotationCollectionI Bio::AnnotationI);
  187         332  
  187         52900  
97              
98              
99             =head2 new
100              
101             Title : new
102             Usage : $coll = Bio::Annotation::Collection->new()
103             Function: Makes a new Annotation::Collection object.
104             Returns : Bio::Annotation::Collection
105             Args : none
106              
107             =cut
108              
109             sub new{
110 2267     2267 1 6902 my ($class,@args) = @_;
111              
112 2267         5438 my $self = $class->SUPER::new(@args);
113              
114 2267         5732 $self->{'_annotation'} = {};
115 2267         7442 $self->_typemap(Bio::Annotation::TypeManager->new());
116              
117 2267         4259 return $self;
118             }
119              
120              
121             =head1 L implementing methods
122              
123             =cut
124              
125             =head2 get_all_annotation_keys
126              
127             Title : get_all_annotation_keys
128             Usage : $ac->get_all_annotation_keys()
129             Function: gives back a list of annotation keys, which are simple text strings
130             Returns : list of strings
131             Args : none
132              
133             =cut
134              
135             sub get_all_annotation_keys{
136 179     179 1 300 my ($self) = @_;
137 179         208 return keys %{$self->{'_annotation'}};
  179         615  
138             }
139              
140             =head2 get_Annotations
141              
142             Title : get_Annotations
143             Usage : my @annotations = $collection->get_Annotations('key')
144             Function: Retrieves all the Bio::AnnotationI objects for one or more
145             specific key(s).
146              
147             If no key is given, returns all annotation objects.
148              
149             The returned objects will have their tagname() attribute set to
150             the key under which they were attached, unless the tagname was
151             already set.
152              
153             Returns : list of Bio::AnnotationI - empty if no objects stored for a key
154             Args : keys (list of strings) for annotations (optional)
155              
156             =cut
157              
158             sub get_Annotations{
159 2854     2854 1 18091 my ($self,@keys) = @_;
160              
161 2854         3768 my @anns = ();
162 2854 100       5433 @keys = $self->get_all_annotation_keys() unless @keys;
163 2854         4828 foreach my $key (@keys) {
164 3085 100       6045 if(exists($self->{'_annotation'}->{$key})) {
165             push(@anns,
166             map {
167 3768 100       7495 $_->tagname($key) if ! $_->tagname(); $_;
  3768         7950  
168 2023         2403 } @{$self->{'_annotation'}->{$key}});
  2023         4083  
169             }
170             }
171 2854         6216 return @anns;
172             }
173              
174              
175             =head2 get_nested_Annotations
176              
177             Title : get_nested_Annotations
178             Usage : my @annotations = $collection->get_nested_Annotations(
179             '-key' => \@keys,
180             '-recursive => 1);
181             Function: Retrieves all the Bio::AnnotationI objects for one or more
182             specific key(s). If -recursive is set to true, traverses the nested
183             annotation collections recursively and returns all annotations
184             matching the key(s).
185              
186             If no key is given, returns all annotation objects.
187              
188             The returned objects will have their tagname() attribute set to
189             the key under which they were attached, unless the tagname was
190             already set.
191              
192             Returns : list of Bio::AnnotationI - empty if no objects stored for a key
193             Args : -keys => arrayref of keys to search for (optional)
194             -recursive => boolean, whether or not to recursively traverse the
195             nested annotations and return annotations with matching keys.
196              
197             =cut
198              
199             sub get_nested_Annotations {
200 0     0 1 0 my ($self, @args) = @_;
201 0         0 my ($keys, $recursive) = $self->_rearrange([qw(KEYS RECURSIVE)], @args);
202 0         0 $self->verbose(1);
203            
204 0         0 my @anns = ();
205             # if not recursive behave exactly like get_Annotations()
206 0 0       0 if (!$recursive) {
207 0 0       0 my @keys = $keys? @$keys : $self->get_all_annotation_keys();
208 0         0 foreach my $key (@keys) {
209 0 0       0 if(exists($self->{'_annotation'}->{$key})) {
210             push(@anns,
211             map {
212 0 0       0 $_->tagname($key) if ! $_->tagname(); $_;
  0         0  
213 0         0 } @{$self->{'_annotation'}->{$key}});
  0         0  
214             }
215             }
216             }
217             # if recursive search for keys recursively
218             else {
219 0         0 my @allkeys = $self->get_all_annotation_keys();
220 0         0 foreach my $key (@allkeys) {
221 0         0 my $keymatch = 0;
222 0         0 foreach my $searchkey (@$keys) {
223 0 0       0 if ($key eq $searchkey) { $keymatch = 1;}
  0         0  
224             }
225 0 0       0 if ($keymatch) {
226 0 0       0 if(exists($self->{'_annotation'}->{$key})) {
227             push(@anns,
228             map {
229 0 0       0 $_->tagname($key) if ! $_->tagname(); $_;
  0         0  
230 0         0 } @{$self->{'_annotation'}->{$key}});
  0         0  
231             }
232             }
233             else {
234 0         0 my @annotations = @{$self->{'_annotation'}->{$key}};
  0         0  
235 0         0 foreach (@annotations) {
236 0 0       0 if ($_->isa("Bio::AnnotationCollectionI")) {
237 0         0 push (@anns,
238             $_->get_nested_Annotations('-keys' => $keys, '-recursive' => 1)
239             );
240             }
241             }
242             }
243             }
244             }
245 0         0 return @anns;
246             }
247              
248             =head2 get_all_Annotations
249              
250             Title : get_all_Annotations
251             Usage :
252             Function: Similar to get_Annotations, but traverses and flattens nested
253             annotation collections. This means that collections in the
254             tree will be replaced by their components.
255              
256             Keys will not be passed on to nested collections. I.e., if the
257             tag name of a nested collection matches the key, it will be
258             flattened in its entirety.
259              
260             Hence, for un-nested annotation collections this will be identical
261             to get_Annotations.
262             Example :
263             Returns : an array of L compliant objects
264             Args : keys (list of strings) for annotations (optional)
265              
266              
267             =cut
268              
269             sub get_all_Annotations{
270 7     7 1 285 my ($self,@keys) = @_;
271              
272             return map {
273 7 100       14 $_->isa("Bio::AnnotationCollectionI") ?
  30         101  
274             $_->get_all_Annotations() : $_;
275             } $self->get_Annotations(@keys);
276             }
277              
278              
279             =head2 get_num_of_annotations
280              
281             Title : get_num_of_annotations
282             Usage : my $count = $collection->get_num_of_annotations()
283             Function: Returns the count of all annotations stored in this collection
284             Returns : integer
285             Args : none
286              
287              
288             =cut
289              
290             sub get_num_of_annotations{
291 1     1 1 4 my ($self) = @_;
292 1         4 my $count = 0;
293 1         3 map { $count += scalar @$_ } values %{$self->{'_annotation'}};
  1         6  
  1         6  
294 1         4 return $count;
295             }
296              
297             =head1 Implementation specific functions - mainly for adding
298              
299             =cut
300              
301             =head2 add_Annotation
302              
303             Title : add_Annotation
304             Usage : $self->add_Annotation('reference',$object);
305             $self->add_Annotation($object,'Bio::MyInterface::DiseaseI');
306             $self->add_Annotation($object);
307             $self->add_Annotation('disease',$object,'Bio::MyInterface::DiseaseI');
308             Function: Adds an annotation for a specific key.
309              
310             If the key is omitted, the object to be added must provide a value
311             via its tagname().
312              
313             If the archetype is provided, this and future objects added under
314             that tag have to comply with the archetype and will be rejected
315             otherwise.
316              
317             Returns : none
318             Args : annotation key ('disease', 'dblink', ...)
319             object to store (must be Bio::AnnotationI compliant)
320             [optional] object archetype to map future storage of object
321             of these types to
322              
323             =cut
324              
325             sub add_Annotation{
326 6619     6619 1 13165 my ($self,$key,$object,$archetype) = @_;
327            
328             # if there's no key we use the tagname() as key
329 6619 50 66     23702 if(ref($key) && $key->isa("Bio::AnnotationI") && (!ref($object))) {
      66        
330 2798 50       5002 $archetype = $object if defined($object);
331 2798         3214 $object = $key;
332 2798         4895 $key = $object->tagname();
333 2798 50       4882 $key = $key->name() if ref($key); # OntologyTermI
334 2798 50       4547 $self->throw("Annotation object must have a tagname if key omitted")
335             unless $key;
336             }
337              
338 6619 50       11065 if( !defined $object ) {
339 0         0 $self->throw("Must have at least key and object in add_Annotation");
340             }
341              
342 6619 50       11647 if( !ref $object ) {
343 0         0 $self->throw("Must add an object. Use Bio::Annotation::{Comment,SimpleValue,OntologyTerm} for simple text additions");
344             }
345              
346 6619 50       18056 if( !$object->isa("Bio::AnnotationI") ) {
347 0         0 $self->throw("object must be AnnotationI compliant, otherwise we won't add it!");
348             }
349              
350             # ok, now we are ready! If we don't have an archetype, set it
351             # from the type of the object
352              
353 6619 50       11336 if( !defined $archetype ) {
354 6619         8899 $archetype = ref $object;
355             }
356              
357             # check typemap, storing if needed.
358 6619         11984 my $stored_map = $self->_typemap->type_for_key($key);
359              
360 6619 100       12067 if( defined $stored_map ) {
361             # check validity, irregardless of archetype. A little cheeky
362             # this means isa stuff is executed correctly
363              
364 4151 50       6767 if( !$self->_typemap()->is_valid($key,$object) ) {
365 0         0 $self->throw("Object $object was not valid with key $key. ".
366             "If you were adding new keys in, perhaps you want to make use\n".
367             "of the archetype method to allow registration to a more basic type");
368             }
369             } else {
370 2468         4102 $self->_typemap->_add_type_map($key,$archetype);
371             }
372              
373             # we are ok to store
374              
375 6619 100       14699 if( !defined $self->{'_annotation'}->{$key} ) {
376 2946         5918 $self->{'_annotation'}->{$key} = [];
377             }
378              
379 6619         7618 push(@{$self->{'_annotation'}->{$key}},$object);
  6619         14622  
380              
381 6619         17516 return 1;
382             }
383              
384             =head2 remove_Annotations
385              
386             Title : remove_Annotations
387             Usage :
388             Function: Remove the annotations for the specified key from this collection.
389             Example :
390             Returns : an array Bio::AnnotationI compliant objects which were stored
391             under the given key(s)
392             Args : the key(s) (tag name(s), one or more strings) for which to
393             remove annotations (optional; if none given, flushes all
394             annotations)
395              
396              
397             =cut
398              
399             sub remove_Annotations{
400 34     34 1 58 my ($self, @keys) = @_;
401              
402 34 100       72 @keys = $self->get_all_annotation_keys() unless @keys;
403 34         64 my @anns = $self->get_Annotations(@keys);
404             # flush
405 34         48 foreach my $key (@keys) {
406 34         55 delete $self->{'_annotation'}->{$key};
407 34         73 delete $self->{'_typemap'}->{'_type'}->{$key};
408             }
409 34         66 return @anns;
410             }
411              
412             =head2 flatten_Annotations
413              
414             Title : flatten_Annotations
415             Usage :
416             Function: Flattens part or all of the annotations in this collection.
417              
418             This is a convenience method for getting the flattened
419             annotation for the given keys, removing the annotation for
420             those keys, and adding back the flattened array.
421              
422             This should not change anything for un-nested collections.
423             Example :
424             Returns : an array Bio::AnnotationI compliant objects which were stored
425             under the given key(s)
426             Args : list of keys (strings) the annotation for which to flatten,
427             defaults to all keys if not given
428              
429              
430             =cut
431              
432             sub flatten_Annotations{
433 1     1 1 436 my ($self,@keys) = @_;
434              
435 1         3 my @anns = $self->get_all_Annotations(@keys);
436 1         4 my @origanns = $self->remove_Annotations(@keys);
437 1         3 foreach (@anns) {
438 7         10 $self->add_Annotation($_);
439             }
440 1         5 return @origanns;
441             }
442              
443             =head1 Bio::AnnotationI methods implementations
444              
445             This is to allow nested annotation: you can use a collection as an
446             annotation object for an annotation collection.
447              
448             =cut
449              
450             =head2 as_text
451              
452             Title : as_text
453             Usage :
454             Function: See L
455             Example :
456             Returns : a string
457             Args : none
458              
459              
460             =cut
461              
462             sub as_text{
463 0     0 1 0 my $self = shift;
464              
465 0         0 my $txt = "Collection consisting of ";
466 0         0 my @texts = ();
467 0         0 foreach my $ann ($self->get_Annotations()) {
468 0         0 push(@texts, $ann->as_text());
469             }
470 0 0       0 if(@texts) {
471 0         0 $txt .= join(", ", map { '['.$_.']'; } @texts);
  0         0  
472             } else {
473 0         0 $txt .= "no elements";
474             }
475 0         0 return $txt;
476             }
477              
478             =head2 display_text
479              
480             Title : display_text
481             Usage : my $str = $ann->display_text();
482             Function: returns a string. Unlike as_text(), this method returns a string
483             formatted as would be expected for te specific implementation.
484              
485             One can pass a callback as an argument which allows custom text
486             generation; the callback is passed the current instance and any text
487             returned
488             Example :
489             Returns : a string
490             Args : [optional] callback
491              
492             =cut
493              
494             {
495             # this just calls the default display_text output for
496             # any AnnotationI
497             my $DEFAULT_CB = sub {
498             my $obj = shift;
499             my $txt;
500             foreach my $ann ($obj->get_Annotations()) {
501             $txt .= $ann->display_text()."\n";
502             }
503             return $txt;
504             };
505              
506             sub display_text {
507 0     0 1 0 my ($self, $cb) = @_;
508 0   0     0 $cb ||= $DEFAULT_CB;
509 0 0       0 $self->throw("") if ref $cb ne 'CODE';
510 0         0 return $cb->($self);
511             }
512             }
513              
514              
515             =head2 hash_tree
516              
517             Title : hash_tree
518             Usage :
519             Function: See L
520             Example :
521             Returns : a hash reference
522             Args : none
523              
524              
525             =cut
526              
527             sub hash_tree{
528 0     0 1 0 my $self = shift;
529 0         0 my $tree = {};
530              
531 0         0 foreach my $key ($self->get_all_annotation_keys()) {
532             # all contained objects will support hash_tree()
533             # (they are AnnotationIs)
534 0         0 $tree->{$key} = [$self->get_Annotations($key)];
535             }
536 0         0 return $tree;
537             }
538              
539             =head2 tagname
540              
541             Title : tagname
542             Usage : $obj->tagname($newval)
543             Function: Get/set the tagname for this annotation value.
544              
545             Setting this is optional. If set, it obviates the need to
546             provide a tag to Bio::AnnotationCollectionI when adding
547             this object. When obtaining an AnnotationI object from the
548             collection, the collection will set the value to the tag
549             under which it was stored unless the object has a tag
550             stored already.
551              
552             Example :
553             Returns : value of tagname (a scalar)
554             Args : new value (a scalar, optional)
555              
556              
557             =cut
558              
559             sub tagname{
560 9     9 1 13 my $self = shift;
561              
562 9 100       14 return $self->{'tagname'} = shift if @_;
563 8         18 return $self->{'tagname'};
564             }
565              
566              
567             =head1 Backward compatible functions
568              
569             Functions put in for backward compatibility with old
570             Bio::Annotation.pm stuff
571              
572             =cut
573              
574             =head2 description
575              
576             Title : description
577             Usage :
578             Function:
579             Example :
580             Returns :
581             Args :
582              
583              
584             =cut
585              
586             sub description{
587 0     0 1 0 my ($self,$value) = @_;
588              
589 0         0 $self->deprecated("Using old style annotation call on new Annotation::Collection object");
590              
591 0 0       0 if( defined $value ) {
592 0         0 my $val = Bio::Annotation::SimpleValue->new();
593 0         0 $val->value($value);
594 0         0 $self->add_Annotation('description',$val);
595             }
596              
597 0         0 my ($desc) = $self->get_Annotations('description');
598            
599             # If no description tag exists, do not attempt to call value on undef:
600 0 0       0 return $desc ? $desc->value : undef;
601             }
602              
603              
604             =head2 add_gene_name
605              
606             Title : add_gene_name
607             Usage :
608             Function:
609             Example :
610             Returns :
611             Args :
612              
613              
614             =cut
615              
616             sub add_gene_name{
617 0     0 1 0 my ($self,$value) = @_;
618              
619 0         0 $self->deprecated("Old style add_gene_name called on new style Annotation::Collection");
620              
621 0         0 my $val = Bio::Annotation::SimpleValue->new();
622 0         0 $val->value($value);
623 0         0 $self->add_Annotation('gene_name',$val);
624             }
625              
626             =head2 each_gene_name
627              
628             Title : each_gene_name
629             Usage :
630             Function:
631             Example :
632             Returns :
633             Args :
634              
635              
636             =cut
637              
638             sub each_gene_name{
639 0     0 1 0 my ($self) = @_;
640              
641 0         0 $self->deprecated("Old style each_gene_name called on new style Annotation::Collection");
642              
643 0         0 my @out;
644 0         0 my @gene = $self->get_Annotations('gene_name');
645              
646 0         0 foreach my $g ( @gene ) {
647 0         0 push(@out,$g->value);
648             }
649              
650 0         0 return @out;
651             }
652              
653             =head2 add_Reference
654              
655             Title : add_Reference
656             Usage :
657             Function:
658             Example :
659             Returns :
660             Args :
661              
662              
663             =cut
664              
665             sub add_Reference{
666 0     0 1 0 my ($self, @values) = @_;
667              
668 0         0 $self->deprecated("add_Reference (old style Annotation) on new style Annotation::Collection");
669            
670             # Allow multiple (or no) references to be passed, as per old method
671 0         0 foreach my $value (@values) {
672 0         0 $self->add_Annotation('reference',$value);
673             }
674             }
675              
676             =head2 each_Reference
677              
678             Title : each_Reference
679             Usage :
680             Function:
681             Example :
682             Returns :
683             Args :
684              
685              
686             =cut
687              
688             sub each_Reference{
689 0     0 1 0 my ($self) = @_;
690              
691 0         0 $self->deprecated("each_Reference (old style Annotation) on new style Annotation::Collection");
692            
693 0         0 return $self->get_Annotations('reference');
694             }
695              
696              
697             =head2 add_Comment
698              
699             Title : add_Comment
700             Usage :
701             Function:
702             Example :
703             Returns :
704             Args :
705              
706              
707             =cut
708              
709             sub add_Comment{
710 0     0 1 0 my ($self,$value) = @_;
711              
712 0         0 $self->deprecated("add_Comment (old style Annotation) on new style Annotation::Collection");
713              
714 0         0 $self->add_Annotation('comment',$value);
715              
716             }
717              
718             =head2 each_Comment
719              
720             Title : each_Comment
721             Usage :
722             Function:
723             Example :
724             Returns :
725             Args :
726              
727              
728             =cut
729              
730             sub each_Comment{
731 0     0 1 0 my ($self) = @_;
732              
733 0         0 $self->deprecated("each_Comment (old style Annotation) on new style Annotation::Collection");
734            
735 0         0 return $self->get_Annotations('comment');
736             }
737              
738              
739              
740             =head2 add_DBLink
741              
742             Title : add_DBLink
743             Usage :
744             Function:
745             Example :
746             Returns :
747             Args :
748              
749              
750             =cut
751              
752             sub add_DBLink{
753 0     0 1 0 my ($self,$value) = @_;
754              
755 0         0 $self->deprecated("add_DBLink (old style Annotation) on new style Annotation::Collection");
756              
757 0         0 $self->add_Annotation('dblink',$value);
758              
759             }
760              
761             =head2 each_DBLink
762              
763             Title : each_DBLink
764             Usage :
765             Function:
766             Example :
767             Returns :
768             Args :
769              
770              
771             =cut
772              
773             sub each_DBLink{
774 0     0 1 0 my ($self) = @_;
775              
776 0         0 $self->deprecated("each_DBLink (old style Annotation) on new style Annotation::Collection - use get_Annotations('dblink')");
777            
778 0         0 return $self->get_Annotations('dblink');
779             }
780              
781              
782              
783             =head1 Implementation management functions
784              
785             =cut
786              
787             =head2 _typemap
788              
789             Title : _typemap
790             Usage : $obj->_typemap($newval)
791             Function:
792             Example :
793             Returns : value of _typemap
794             Args : newvalue (optional)
795              
796              
797             =cut
798              
799             sub _typemap{
800 15510     15510   20483 my ($self,$value) = @_;
801 15510 100       22330 if( defined $value) {
802 2272         3518 $self->{'_typemap'} = $value;
803             }
804 15510         32046 return $self->{'_typemap'};
805              
806             }
807              
808             1;