3 # BioPerl module for Bio::Map::PositionHandler
5 # Cared for by Sendu Bala <bix@sendu.me.uk>
9 # You may distribute this module under the same terms as perl itself
11 # POD documentation - main docs before the code
15 Bio::Map::PositionHandler - A Position Handler Implementation
19 # This is used by modules when they want to implement being a
20 # Position or being something that has Positions (when they are
21 # a L<Bio::Map::EntityI>)
23 # Make a PositionHandler that knows about you
24 my $ph = Bio::Map::PositionHandler->new($self);
26 # Register with it so that it handles your Position-related needs
29 # If you are a position, get/set the map you are on and the marker you are
32 $ph->element($marker);
34 my $marker = $ph->element;
36 # If you are a marker, add a new position to yourself
37 $ph->add_positions($pos);
39 # And then get all your positions on a particular map
40 foreach my $pos ($ph->get_positions($map)) {
41 # do something with this Bio::Map::PositionI
44 # Or find out what maps you exist on
45 my @maps = $ph->get_other_entities;
47 # The same applies if you were a map
51 A Position Handler copes with the coordination of different Bio::Map::EntityI
52 objects, adding and removing them from each other and knowning who belongs to
53 who. These relationships between objects are based around shared Positions,
54 hence PositionHandler.
56 This PositionHandler is able to cope with Bio::Map::PositionI objects,
57 Bio::Map::MappableI objects and Bio::Map::MapI objects.
63 User feedback is an integral part of the evolution of this and other
64 Bioperl modules. Send your comments and suggestions preferably to
65 the Bioperl mailing list. Your participation is much appreciated.
67 bioperl-l@bioperl.org - General discussion
68 http://bioperl.org/wiki/Mailing_lists - About the mailing lists
72 Report bugs to the Bioperl bug tracking system to help us keep track
73 of the bugs and their resolution. Bug reports can be submitted via the
76 http://bugzilla.open-bio.org/
78 =head1 AUTHOR - Sendu Bala
84 The rest of the documentation details each of the object methods.
85 Internal methods are usually preceded with a _
89 # Let the code begin...
91 package Bio
::Map
::PositionHandler
;
94 use base
qw(Bio::Root::Root Bio::Map::PositionHandlerI);
96 # globally accessible hash, via private instance methods
99 =head2 General methods
106 Usage : my $position_handler = Bio::Map::PositionHandler->new(-self => $self);
107 Function: Get a Bio::Map::PositionHandler that knows who you are.
108 Returns : Bio::Map::PositionHandler object
109 Args : -self => Bio::Map::EntityI that is you
114 my ($class, @args) = @_;
115 my $self = $class->SUPER::new
(@args);
117 my ($you) = $self->_rearrange([qw(SELF)], @args);
119 $self->throw('Must supply -self') unless $you;
120 $self->throw('-self must be a reference (object)') unless ref($you);
121 $self->throw('This is [$you], not a Bio::Map::EntityI object') unless $you->isa('Bio::Map::EntityI');
122 $self->{_who
} = $you;
123 $self->{_rel
} = $RELATIONS;
130 Usage : $position_handler->register();
131 Function: Ask this Position Handler to look after your entity relationships.
139 my $you = $self->{_who
};
141 $self->throw("Trying to re-register [$you], which could be bad") if $you->get_position_handler->index;
143 $self->{_index
} = ++$self->{_rel
}->{assigned_indices
};
144 $self->{_rel
}->{registered
}->{$self->{_index
}} = $you;
150 Usage : my $index = $position_handler->index();
151 Function: Get the unique registry index for yourself, generated during the
152 resistration process.
160 return $self->{_index
};
166 Usage : my $entity = $position_handler->get_entity($index);
167 Function: Get the entity that corresponds to the supplied registry index.
168 Returns : Bio::Map::EntityI object
174 my ($self, $index) = @_;
175 return $self->{_rel
}->{registered
}->{$index} || $self->throw("Requested registy index '$index' but that index isn't in the registry");
178 =head2 Methods for Bio::Map::PositionI objects
185 Usage : my $map = $position_handler->map();
186 $position_handler->map($map);
187 Function: Get/Set the map you are on. You must be a Position.
188 Returns : L<Bio::Map::MapI>
189 Args : none to get, OR
190 new L<Bio::Map::MapI> to set
195 my ($self, $entity) = @_;
196 return $self->_pos_get_set($entity, 'position_maps', 'Bio::Map::MapI');
202 Usage : my $element = $position_handler->element();
203 $position_handler->element($element);
204 Function: Get/Set the map element you are for. You must be a Position.
205 Returns : L<Bio::Map::MappableI>
206 Args : none to get, OR
207 new L<Bio::Map::MappableI> to set
212 my ($self, $entity) = @_;
213 return $self->_pos_get_set($entity, 'position_elements', 'Bio::Map::MappableI');
216 =head2 Methods for all other Bio::Map::EntityI objects
222 Title : add_positions
223 Usage : $position_handler->add_positions($pos1, $pos2, ...);
224 Function: Add some positions to yourself. You can't be a position.
226 Args : Array of Bio::Map::PositionI objects
232 $self->throw('Must supply at least one Bio::Map::EntityI') unless @_ > 0;
233 my $you_index = $self->_get_you_index(0);
234 my $kind = $self->_get_kind;
236 foreach my $pos (@_) {
237 $self->_check_object($pos, 'Bio::Map::PositionI');
238 my $pos_index = $self->_get_other_index($pos);
240 $self->_pos_set($pos_index, $you_index, $kind);
246 Title : get_positions
247 Usage : my @positions = $position_handler->get_positions();
248 Function: Get all your positions. You can't be a Position.
249 Returns : Array of Bio::Map::PositionI objects
250 Args : none for all, OR
251 Bio::Map::EntityI object to limit the Positions to those that
252 are shared by you and this other entity.
257 my ($self, $entity) = @_;
258 my $you_index = $self->_get_you_index(0);
260 my @positions = keys %{$self->{_rel
}->{has
}->{$you_index}};
263 my $entity_index = $self->_get_other_index($entity);
264 my $pos_ref = $self->{_rel
}->{has
}->{$entity_index};
265 @positions = grep { $pos_ref->{$_} } @positions;
268 return map { $self->get_entity($_) } @positions;
271 =head2 purge_positions
273 Title : purge_positions
274 Usage : $position_handler->purge_positions();
275 Function: Remove all positions from yourself. You can't be a Position.
277 Args : none to remove all, OR
278 Bio::Map::PositionI object to remove only that entity, OR
279 Bio::Map::EntityI object to limit the removal to those Positions that
280 are shared by you and this other entity.
284 sub purge_positions
{
285 my ($self, $thing) = @_;
286 my $you_index = $self->_get_you_index(0);
287 my $kind = $self->_get_kind;
291 $self->throw("Must supply an object") unless ref($thing);
292 if ($thing->isa("Bio::Map::PositionI")) {
293 @pos_indices = ($self->_get_other_index($thing));
296 my $entity_index = $self->_get_other_index($thing);
297 my $pos_ref = $self->{_rel
}->{has
}->{$entity_index};
298 @pos_indices = grep { $pos_ref->{$_} } keys %{$self->{_rel
}->{has
}->{$you_index}};
302 @pos_indices = keys %{$self->{_rel
}->{has
}->{$you_index}};
305 foreach my $pos_index (@pos_indices) {
306 $self->_purge_pos_entity($pos_index, $you_index, $kind);
310 =head2 get_other_entities
312 Title : get_other_entities
313 Usage : my @entities = $position_handler->get_other_entities();
314 Function: Get all the entities that share your Positions. You can't be a
316 Returns : Array of Bio::Map::EntityI objects
321 sub get_other_entities
{
323 my $you_index = $self->_get_you_index(0);
324 my $kind = $self->_get_kind;
325 my $want = $kind eq 'position_elements' ?
'position_maps' : 'position_elements';
328 while (my ($pos_index) = each %{$self->{_rel
}->{has
}->{$you_index}}) {
329 my $entity_index = $self->{_rel
}->{$want}->{$pos_index};
330 $entities{$entity_index} = 1 if $entity_index;
333 return map { $self->get_entity($_) } keys %entities;
336 # do basic check on an object, make sure it is the right type
338 my ($self, $object, $interface) = @_;
339 $self->throw("Must supply an arguement") unless $object;
340 $self->throw("This is [$object], not an object") unless ref($object);
341 $self->throw("This is [$object], not a $interface") unless $object->isa($interface);
344 # get the object we are the handler of, its index, and throw depending on if
347 my ($self, $should_be_pos) = @_;
348 my $you = $self->{_who
};
349 if ($should_be_pos) {
350 $self->throw("This is not a Position, method invalid") unless $you->isa('Bio::Map::PositionI');
353 $self->throw("This is a Position, method invalid") if $you->isa('Bio::Map::PositionI');
358 # check an entity is registered and get its index
359 sub _get_other_index
{
360 my ($self, $entity) = @_;
361 $self->throw("Must supply an object") unless ref($entity);
362 my $index = $entity->get_position_handler->index;
363 $self->throw("Entity doesn't seem like it's been registered") unless $index;
364 $self->throw("Entity may have been registered with a different PositionHandler, can't deal with it") unless $entity eq $self->get_entity($index);
368 # which of the position hashes should we be recorded under?
371 my $you = $self->{_who
};
372 return $you->isa('Bio::Map::MapI') ?
'position_maps' : $you->isa('Bio::Map::MappableI') ?
'position_elements' : $self->throw("This is [$you] which is an unsupported kind of entity");
375 # get/set position entity
377 my ($self, $entity, $kind, $interface) = @_;
378 my $you_index = $self->_get_you_index(1);
382 $self->_check_object($entity, $interface);
383 my $new_entity_index = $self->_get_other_index($entity);
384 $entity_index = $self->_pos_set($you_index, $new_entity_index, $kind);
387 $entity_index ||= $self->{_rel
}->{$kind}->{$you_index} || 0;
389 return $self->get_entity($entity_index);
394 # set position entity
396 my ($self, $pos_index, $new_entity_index, $kind) = @_;
397 my $current_entity_index = $self->{_rel
}->{$kind}->{$pos_index} || 0;
399 if ($current_entity_index) {
400 if ($current_entity_index == $new_entity_index) {
401 return $current_entity_index;
404 $self->_purge_pos_entity($pos_index, $current_entity_index, $kind);
407 $self->{_rel
}->{has
}->{$new_entity_index}->{$pos_index} = 1;
408 $self->{_rel
}->{$kind}->{$pos_index} = $new_entity_index;
409 return $new_entity_index;
412 # disassociate position from one of its current entities
413 sub _purge_pos_entity
{
414 my ($self, $pos_index, $entity_index, $kind) = @_;
415 delete $self->{_rel
}->{has
}->{$entity_index}->{$pos_index};
416 delete $self->{_rel
}->{$kind}->{$pos_index};