File Coverage

blib/lib/Bio/Phylo/Mediators/TaxaMediator.pm
Criterion Covered Total %
statement 74 82 90.2
branch 27 34 79.4
condition 18 21 85.7
subroutine 10 11 90.9
pod 6 6 100.0
total 135 154 87.6


line stmt bran cond sub pod time code
1             package Bio::Phylo::Mediators::TaxaMediator;
2 57     57   339 use strict;
  57         1303  
  57         1802  
3 57     57   281 use Scalar::Util qw'weaken isweak';
  57         781  
  57         3826  
4 57     57   947 use Bio::Phylo::Util::Logger ':simple';
  57         92  
  57         7170  
5 57     57   387 use Bio::Phylo::Util::Exceptions;
  57         106  
  57         1970  
6 57     57   319 use Bio::Phylo::Util::CONSTANT ':objecttypes';
  57         107  
  57         45038  
7              
8             {
9             my $self;
10             my ( @object, %id_by_type, %one_to_one, %one_to_many );
11              
12             =head1 NAME
13              
14             Bio::Phylo::Mediators::TaxaMediator - Mediator for links between taxa and other objects
15              
16             =head1 SYNOPSIS
17              
18             # no direct usage
19              
20             =head1 DESCRIPTION
21              
22             This module manages links between taxon objects and other objects linked to
23             them. It is an implementation of the Mediator design pattern (e.g. see
24             L<http://www.atug.com/andypatterns/RM.htm>,
25             L<http://home.earthlink.net/~huston2/dp/mediator.html>).
26              
27             Methods defined in this module are meant only for internal usage by Bio::Phylo.
28              
29             =head1 METHODS
30              
31             =head2 CONSTRUCTOR
32              
33             =over
34              
35             =item new()
36              
37             TaxaMediator constructor.
38              
39             Type : Constructor
40             Title : new
41             Usage : my $mediator = Bio::Phylo::Taxa::TaxaMediator->new;
42             Function: Instantiates a Bio::Phylo::Taxa::TaxaMediator
43             object.
44             Returns : A Bio::Phylo::Taxa::TaxaMediator object (singleton).
45             Args : None.
46              
47             =cut
48              
49             sub new {
50              
51             # could be child class
52 0     0 1 0 my $class = shift;
53              
54             # notify user
55 0         0 DEBUG "constructor called for '$class'";
56              
57             # singleton class
58 0 0       0 if ( not $self ) {
59 0         0 INFO "first time instantiation of singleton";
60 0         0 $self = \$class;
61 0         0 bless $self, $class;
62             }
63 0         0 return $self;
64             }
65              
66             =back
67              
68             =head2 METHODS
69              
70             =over
71              
72             =item register()
73              
74             Stores argument in invocant's cache.
75              
76             Type : Method
77             Title : register
78             Usage : $mediator->register( $obj );
79             Function: Stores an object in mediator's cache, if relevant
80             Returns : $self
81             Args : An object, $obj
82             Comments: This method is called every time an object is instantiated.
83              
84             =cut
85              
86             sub register {
87 13788     13788 1 24197 my ( $self, $obj ) = @_;
88 13788         28291 my $id = $obj->get_id;
89            
90 13788 100 66     67327 if ( ref $obj && $obj->can('_type') ) {
91 13784         34269 my $type = $obj->_type;
92            
93             # node, forest, matrix, datum, taxon, taxa
94 13784 100 100     53295 if ( $type == _NODE_ || $type == _TAXON_ || $type == _DATUM_ || $type == _TAXA_ || $type == _FOREST_ || $type == _MATRIX_ ) {
      100        
      100        
      100        
      100        
95            
96             # index by type
97 11880 100       25612 $id_by_type{$type} = {} unless $id_by_type{$type};
98 11880         27508 $id_by_type{$type}->{$id} = 1;
99              
100             # store in object cache
101 11880         19314 $object[$id] = $obj;
102            
103             # in the one-to-many relationships we only weaken the
104             # references to the many objects so that the get cleaned up
105             #Êwhen they go out of scope. When the are unregistered and
106             #Êthere is no more many object that references the one object,
107             # the one object's reference needs to be weakened as well so
108             # that it is cleaned up when it is no longer reachable from
109             # elsewhere.
110             #if ( $type != _TAXA_ && $type != _TAXON_ ) {
111 11880         34761 weaken $object[$id];
112             #}
113 11880         26102 return $self;
114             }
115             }
116             }
117              
118             =item unregister()
119              
120             Removes argument from invocant's cache.
121              
122             Type : Method
123             Title : unregister
124             Usage : $mediator->unregister( $obj );
125             Function: Cleans up mediator's cache of $obj and $obj's relations
126             Returns : $self
127             Args : An object, $obj
128             Comments: This method is called every time an object is destroyed.
129              
130             =cut
131              
132             sub unregister {
133 14624     14624 1 22361 my ( $self, $obj ) = @_;
134              
135 14624         25051 my $id = $obj->get_id;
136            
137 14624 50       25799 if ( defined $id ) {
138 14624         20787 my $taxa_id = $one_to_one{$id};
139            
140             # decrease reference count of taxa block if we are the last pointer
141             # to it
142 14624 100       22724 if ( $taxa_id ) {
143 192         260 my @others = keys %{ $one_to_many{$taxa_id} };
  192         580  
144 192 100       441 if ( @others == 1 ) {
145 125         438 weaken $object[$taxa_id];
146             }
147 192         387 delete $one_to_many{$taxa_id}->{$id};
148             }
149            
150             # remove from object cache
151 14624 100       24576 if ( exists $object[$id] ) {
152 11878         18002 delete $object[$id];
153             }
154            
155             # remove from one-to-one mapping
156 14624 100       22610 if ( exists $one_to_one{$id} ) {
157 192         268 delete $one_to_one{$id};
158             }
159            
160             # remove from one-to-many mapping if I am taxa
161 14624 100       24354 if ( exists $one_to_many{$id} ) {
162 145         290 delete $one_to_many{$id};
163             }
164            
165             }
166 14624         22651 return $self;
167             }
168              
169             =item set_link()
170              
171             Creates link between objects.
172              
173             Type : Method
174             Title : set_link
175             Usage : $mediator->set_link( -one => $obj1, -many => $obj2 );
176             Function: Creates link between objects
177             Returns : $self
178             Args : -one => $obj1 (source of a one-to-many relationship)
179             -many => $obj2 (target of a one-to-many relationship)
180             Comments: This method is called from within, for example, set_taxa
181             method calls. A call like $taxa->set_matrix( $matrix ),
182             and likewise a call like $matrix->set_taxa( $taxa ), are
183             both internally rerouted to:
184              
185             $mediator->set_link(
186             -one => $taxa,
187             -many => $matrix
188             );
189              
190             =cut
191              
192             sub set_link {
193 270     270 1 396 my $self = shift;
194 270         590 my %opt = @_;
195 270         450 my ( $one, $many ) = ( $opt{'-one'}, $opt{'-many'} );
196 270         572 my ( $one_id, $many_id ) = ( $one->get_id, $many->get_id );
197 270         540 $one_to_one{$many_id} = $one_id;
198 270 100       618 $one_to_many{$one_id} = {} unless $one_to_many{$one_id};
199              
200             # once other objects start referring to the taxon we want
201             # these references to keep the taxon "alive" until all other
202             # objects pointing to it have gone out of scope, in which
203             # case the reference must be weakened again, so that it
204             # might get cleaned up also
205 270 100       667 if (isweak($object[$one_id]) ) {
206 127         192 my $strong = $object[$one_id];
207 127         197 $object[$one_id] = $strong;
208             }
209            
210 270         581 $one_to_many{$one_id}->{$many_id} = $many->_type;
211 270         630 return $self;
212             }
213              
214             =item get_link()
215              
216             Retrieves link between objects.
217              
218             Type : Method
219             Title : get_link
220             Usage : $mediator->get_link(
221             -source => $obj,
222             -type => _CONSTANT_,
223             );
224             Function: Retrieves link between objects
225             Returns : Linked object
226             Args : -source => $obj (required, the source of the link)
227             -type => a constant from Bio::Phylo::Util::CONSTANT
228              
229             (-type is optional, used to filter returned results in
230             one-to-many query).
231              
232             Comments: This method is called from within, for example, get_taxa
233             method calls. A call like $matrix->get_taxa()
234             and likewise a call like $forest->get_taxa(), are
235             both internally rerouted to:
236              
237             $mediator->get_link(
238             -source => $self # e.g. $matrix or $forest
239             );
240              
241             A call like $taxa->get_matrices() is rerouted to:
242              
243             $mediator->get_link( -source => $taxa, -type => _MATRIX_ );
244              
245             =cut
246              
247             sub get_link {
248 808     808 1 1110 my $self = shift;
249 808         1525 my %opt = @_;
250 808         1596 my $id = $opt{'-source'}->get_id;
251              
252             # have to get many objects,
253             # i.e. source was a taxon/taxa
254 808 100       1447 if ( defined $opt{'-type'} ) {
255 48         67 my $type = $opt{'-type'};
256 48         65 my @ids = grep { $one_to_many{$id}->{$_} == $type } keys %{ $one_to_many{$id} };
  8         34  
  48         141  
257 48         89 my @result = @object[@ids];
258 48         210 return \@result;
259             }
260            
261             # have to get one object, i.e. source
262             # was something that links to taxon/taxa
263             else {
264 760 100       2395 return exists $one_to_one{$id} ? $object[$one_to_one{$id}] : undef;
265             }
266             }
267              
268             =item remove_link()
269              
270             Removes link between objects.
271              
272             Type : Method
273             Title : remove_link
274             Usage : $mediator->remove_link( -one => $obj1, -many => $obj2 );
275             Function: Removes link between objects
276             Returns : $self
277             Args : -one => $obj1 (source of a one-to-many relationship)
278             -many => $obj2 (target of a one-to-many relationship)
279              
280             (-many argument is optional)
281              
282             Comments: This method is called from within, for example,
283             unset_taxa method calls. A call like $matrix->unset_taxa()
284             is rerouted to:
285              
286             $mediator->remove_link( -many => $matrix );
287              
288             A call like $taxa->unset_matrix( $matrix ); is rerouted to:
289              
290             $mediator->remove_link( -one => $taxa, -many => $matrix );
291              
292              
293             =cut
294              
295             sub remove_link {
296 38     38 1 58 my $self = shift;
297 38         80 my %opt = @_;
298 38         71 my ( $one, $many ) = ( $opt{'-one'}, $opt{'-many'} );
299 38         89 my $many_id = $many->get_id;
300 38         56 my $one_id;
301 38 50       62 if ($one) {
302 0         0 $one_id = $one->get_id;
303             }
304             else {
305 38         117 my $target = $self->get_link( '-source' => $many );
306 38 50       86 $one_id = $target->get_id if $target;
307             }
308 38 0 33     74 delete $one_to_many{$one_id}->{$many_id} if $one_id and $one_to_many{$one_id};
309 38         83 delete $one_to_one{$many_id};
310             }
311              
312             =back
313              
314             =head1 SEE ALSO
315              
316             There is a mailing list at L<https://groups.google.com/forum/#!forum/bio-phylo>
317             for any user or developer questions and discussions.
318              
319             =over
320              
321             =item L<Bio::Phylo::Manual>
322              
323             Also see the manual: L<Bio::Phylo::Manual> and L<http://rutgervos.blogspot.com>.
324              
325             =back
326              
327             =head1 CITATION
328              
329             If you use Bio::Phylo in published research, please cite it:
330              
331             B<Rutger A Vos>, B<Jason Caravas>, B<Klaas Hartmann>, B<Mark A Jensen>
332             and B<Chase Miller>, 2011. Bio::Phylo - phyloinformatic analysis using Perl.
333             I<BMC Bioinformatics> B<12>:63.
334             L<http://dx.doi.org/10.1186/1471-2105-12-63>
335              
336             =cut
337              
338             }
339             1;