File Coverage

blib/lib/Bio/Phylo/Mediators/TaxaMediator.pm
Criterion Covered Total %
statement 77 85 90.5
branch 27 34 79.4
condition 18 21 85.7
subroutine 11 12 91.6
pod 6 6 100.0
total 139 158 87.9


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