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   351 use strict;
  57         110  
  57         1766  
3 57     57   297 use Scalar::Util qw'weaken isweak';
  57         114  
  57         3249  
4 57     57   310 use Bio::Phylo::Util::Logger ':simple';
  57         102  
  57         6628  
5 57     57   376 use Bio::Phylo::Util::Exceptions;
  57         119  
  57         2127  
6 57     57   327 use Bio::Phylo::Util::CONSTANT ':objecttypes';
  57         110  
  57         45690  
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,
25             L).
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 11208     11208 1 19467 my ( $self, $obj ) = @_;
88 11208         24058 my $id = $obj->get_id;
89            
90 11208 100 66     52775 if ( ref $obj && $obj->can('_type') ) {
91 11204         27400 my $type = $obj->_type;
92            
93             # node, forest, matrix, datum, taxon, taxa
94 11204 100 100     45465 if ( $type == _NODE_ || $type == _TAXON_ || $type == _DATUM_ || $type == _TAXA_ || $type == _FOREST_ || $type == _MATRIX_ ) {
      100        
      100        
      100        
      100        
95            
96             # index by type
97 9345 100       22173 $id_by_type{$type} = {} unless $id_by_type{$type};
98 9345         20209 $id_by_type{$type}->{$id} = 1;
99              
100             # store in object cache
101 9345         16686 $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 9345         26439 weaken $object[$id];
112             #}
113 9345         20716 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 12044     12044 1 18822 my ( $self, $obj ) = @_;
134              
135 12044         21425 my $id = $obj->get_id;
136            
137 12044 50       22438 if ( defined $id ) {
138 12044         17710 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 12044 100       19858 if ( $taxa_id ) {
143 192         276 my @others = keys %{ $one_to_many{$taxa_id} };
  192         653  
144 192 100       492 if ( @others == 1 ) {
145 125         504 weaken $object[$taxa_id];
146             }
147 192         418 delete $one_to_many{$taxa_id}->{$id};
148             }
149            
150             # remove from object cache
151 12044 100       20728 if ( exists $object[$id] ) {
152 9343         14182 delete $object[$id];
153             }
154            
155             # remove from one-to-one mapping
156 12044 100       19030 if ( exists $one_to_one{$id} ) {
157 192         298 delete $one_to_one{$id};
158             }
159            
160             # remove from one-to-many mapping if I am taxa
161 12044 100       19690 if ( exists $one_to_many{$id} ) {
162 145         323 delete $one_to_many{$id};
163             }
164            
165             }
166 12044         20309 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 452 my $self = shift;
194 270         643 my %opt = @_;
195 270         498 my ( $one, $many ) = ( $opt{'-one'}, $opt{'-many'} );
196 270         614 my ( $one_id, $many_id ) = ( $one->get_id, $many->get_id );
197 270         593 $one_to_one{$many_id} = $one_id;
198 270 100       713 $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       729 if (isweak($object[$one_id]) ) {
206 127         210 my $strong = $object[$one_id];
207 127         220 $object[$one_id] = $strong;
208             }
209            
210 270         699 $one_to_many{$one_id}->{$many_id} = $many->_type;
211 270         698 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 1227 my $self = shift;
249 808         1608 my %opt = @_;
250 808         1811 my $id = $opt{'-source'}->get_id;
251              
252             # have to get many objects,
253             # i.e. source was a taxon/taxa
254 808 100       1656 if ( defined $opt{'-type'} ) {
255 48         68 my $type = $opt{'-type'};
256 48         59 my @ids = grep { $one_to_many{$id}->{$_} == $type } keys %{ $one_to_many{$id} };
  8         17  
  48         130  
257 48         82 my @result = @object[@ids];
258 48         197 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       3511 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 55 my $self = shift;
297 38         69 my %opt = @_;
298 38         74 my ( $one, $many ) = ( $opt{'-one'}, $opt{'-many'} );
299 38         75 my $many_id = $many->get_id;
300 38         57 my $one_id;
301 38 50       62 if ($one) {
302 0         0 $one_id = $one->get_id;
303             }
304             else {
305 38         71 my $target = $self->get_link( '-source' => $many );
306 38 50       70 $one_id = $target->get_id if $target;
307             }
308 38 0 33     69 delete $one_to_many{$one_id}->{$many_id} if $one_id and $one_to_many{$one_id};
309 38         74 delete $one_to_one{$many_id};
310             }
311              
312             =back
313              
314             =head1 SEE ALSO
315              
316             There is a mailing list at L
317             for any user or developer questions and discussions.
318              
319             =over
320              
321             =item L
322              
323             Also see the manual: L and L.
324              
325             =back
326              
327             =head1 CITATION
328              
329             If you use Bio::Phylo in published research, please cite it:
330              
331             B, B, B, B
332             and B, 2011. Bio::Phylo - phyloinformatic analysis using Perl.
333             I B<12>:63.
334             L
335              
336             =cut
337              
338             }
339             1;