File Coverage

blib/lib/GenOO/Spliceable.pm
Criterion Covered Total %
statement 128 136 94.1
branch 28 38 73.6
condition n/a
subroutine 20 20 100.0
pod 0 9 0.0
total 176 203 86.7


line stmt bran cond sub pod time code
1             # POD documentation - main docs before the code
2              
3             =head1 NAME
4              
5             GenOO::Spliceable - Role for a region that can be spliced
6              
7             =head1 SYNOPSIS
8              
9             # This role provides regions with the splicing attributes and methods
10            
11             =head1 DESCRIPTION
12              
13             An object that consumes this role gets splicing attributes and methods such as exons and
14             introns. The key attributes of this class are "splice_starts" and "splice_stops"
15             which are sorted arrays of coordinates that define the intervals for exons.
16            
17             -------------EXON_1----------- ------------EXON_2------------
18             SPLICE_START_1...SPLICE_STOP_1...INTRON...SPLICE_START_2...SPLICE_STOP_2...INTRON...
19              
20             =head1 EXAMPLES
21              
22             # Get the location information on the reference sequence
23             $obj_with_role->exons;
24             $obj_with_role->introns;
25            
26             # Check if a position is within an exon or an intron
27             $obj_with_role->is_position_within_exon(120); # 1/0
28             $obj_with_role->is_position_within_intron(120); # 0/1
29            
30             # Get the length of the exonic region
31             $obj_with_role->exonic_length;
32              
33             =cut
34              
35             # Let the code begin...
36              
37             package GenOO::Spliceable;
38             $GenOO::Spliceable::VERSION = '1.5.2';
39 1     1   787 use Moose::Role;
  1         2  
  1         8  
40 1     1   5474 use Moose::Util::TypeConstraints;
  1         2  
  1         9  
41 1     1   2287 use namespace::autoclean;
  1         2  
  1         11  
42              
43 1     1   638 use GenOO::Exon;
  1         3  
  1         48  
44 1     1   635 use GenOO::Intron;
  1         6  
  1         61  
45 1     1   636 use GenOO::Junction;
  1         4  
  1         1887  
46              
47             # Define new data type
48             subtype 'SortedArrayRef', as 'ArrayRef', where { _sorted_array() };
49              
50             # Define coercions to new data type
51             coerce 'SortedArrayRef', from 'ArrayRef', via { [sort {$a <=> $b} @{$_}] };
52             coerce 'SortedArrayRef', from 'Str' , via { [sort {$a <=> $b} (split(/\D+/,$_))] };
53              
54             # Define attributes
55             has 'splice_starts' => (
56             isa => 'SortedArrayRef',
57             is => 'ro',
58             writer => '_set_splice_starts',
59             required => 1,
60             coerce => 1
61             );
62              
63             has 'splice_stops' => (
64             isa => 'SortedArrayRef',
65             is => 'ro',
66             writer => '_set_splice_stops',
67             required => 1,
68             coerce => 1
69             );
70              
71             has 'exons' => (
72             isa => 'ArrayRef',
73             is => 'ro',
74             builder => '_create_exons',
75             init_arg => undef,
76             lazy => 1,
77             );
78              
79             has 'introns' => (
80             isa => 'ArrayRef',
81             is => 'ro',
82             builder => '_create_introns',
83             init_arg => undef,
84             lazy => 1,
85             );
86              
87             # Define consumed roles
88             with 'GenOO::Region';
89              
90              
91             sub BUILD {
92 1053     1053 0 2134 my $self = shift;
93            
94 1053         3512 $self->_sanitize_splice_starts_and_stops;
95             }
96              
97             #######################################################################
98             ######################## Interface Methods ########################
99             #######################################################################
100             sub is_position_within_exon {
101 4     4 0 1212 my ($self, $position) = @_;
102            
103 4         137 my $exons = $self->exons;
104 4         18 foreach my $exon (@$exons) {
105 10 100       41 if ($exon->contains_position($position)) {
106 2         12 return 1;
107             }
108             }
109 2         9 return 0;
110             }
111              
112             sub is_position_within_intron {
113 2     2 0 1214 my ($self, $position) = @_;
114            
115 2         73 my $introns = $self->introns;
116 2         13 foreach my $intron (@$introns) {
117 4 100       21 if ($intron->contains_position($position)) {
118 1         7 return 1;
119             }
120             }
121 1         6 return 0;
122             }
123              
124             sub exon_exon_junctions {
125 1     1 0 1245 my ($self) = @_;
126            
127 1         10 my @junctions;
128             my @junction_starts;
129 1         0 my @junction_stops;
130            
131 1         47 my $exons = $self->exons;
132 1 50       12 if (@$exons > 1) {
133 1         6 for (my $i=0;$i<@$exons-1;$i++) {
134 3         102 push @junction_starts, $$exons[$i]->stop;
135 3         92 push @junction_stops, $$exons[$i+1]->start;
136             }
137             }
138            
139 1 50       7 my $junctions_count = @junction_starts == @junction_stops ? @junction_starts : die "Junctions starts are not of the same size as junction stops\n";
140 1         11 for (my $i=0;$i<$junctions_count;$i++) {
141 3         101 push @junctions, GenOO::Junction->new(
142             species => $self->species,
143             strand => $self->strand,
144             chromosome => $self->chromosome,
145             start => $junction_starts[$i],
146             stop => $junction_stops[$i],
147             part_of => $self,
148             );
149             }
150 1         13 return \@junctions;
151             }
152              
153             sub exonic_sequence {
154 1     1 0 1175 my ($self) = @_;
155            
156 1 50       77 if (defined $self->sequence) {
157 1         9 my $exonic_sequence = '';
158            
159 1 50       36 my $seq = $self->strand == 1 ? $self->sequence : reverse($self->sequence);
160 1         3 foreach my $exon (@{$self->exons}) {
  1         26  
161 4         112 $exonic_sequence .= substr($seq, ($exon->start - $self->start), $exon->length);
162             }
163            
164 1 50       27 if ($self->strand == 1) {
165 0         0 return $exonic_sequence;
166             }
167             else {
168 1         9 return reverse($exonic_sequence);
169             }
170             }
171             }
172              
173             sub exonic_length {
174 1     1 0 1212 my ($self) = @_;
175            
176 1         2 my $length = 0;
177 1         3 foreach my $exon (@{$self->exons}) {
  1         35  
178 4         103 $length += $exon->length;
179             }
180            
181 1         9 return $length;
182             }
183              
184             sub intronic_length {
185 1     1 0 1207 my ($self) = @_;
186            
187 1         8 my $length = 0;
188 1         4 foreach my $intron (@{$self->introns}) {
  1         40  
189 3         86 $length += $intron->length;
190             }
191            
192 1         8 return $length;
193             }
194              
195             sub relative_exonic_position {
196 2     2 0 1174 my ($self, $abs_pos) = @_;
197            
198 2 100       9 if ($self->is_position_within_exon($abs_pos)) {
199 1         27 my $relative_pos = $abs_pos - $self->start;
200 1         3 foreach my $intron (@{$self->introns}) {
  1         25  
201 1 50       25 if ($intron->stop < $abs_pos) {
202 0         0 $relative_pos -= $intron->length;
203             }
204             else {
205 1         3 last;
206             }
207             }
208 1         6 return $relative_pos;
209             }
210             else {
211 1         5 return undef;
212             }
213             }
214              
215             sub set_splice_starts_and_stops {
216 966     966 0 2006 my ($self, $splice_starts, $splice_stops) = @_;
217            
218 966         29265 $self->_set_splice_starts($splice_starts);
219 966         27795 $self->_set_splice_stops($splice_stops);
220 966         2061 $self->_sanitize_splice_starts_and_stops;
221             }
222              
223             #######################################################################
224             ####################### Private Methods ############################
225             #######################################################################
226             sub _create_exons {
227 20     20   52 my ($self) = @_;
228            
229 20         538 my $exon_starts = $self->splice_starts;
230 20         490 my $exon_stops = $self->splice_stops;
231            
232 20         34 my @exons;
233 20         34 for (my $i=0;$i<@{$exon_starts};$i++) {
  74         181  
234 54         1394 push @exons, GenOO::Exon->new({
235             strand => $self->strand,
236             chromosome => $self->rname,
237             start => $$exon_starts[$i],
238             stop => $$exon_stops[$i],
239             part_of => $self
240             });
241             }
242            
243 20         519 return \@exons;
244             }
245              
246             sub _create_introns {
247 3     3   7 my ($self) = @_;
248            
249 3         78 my $exon_starts = $self->splice_starts;
250 3         75 my $exon_stops = $self->splice_stops;
251            
252 3         4 my @introns;
253            
254 3 50       75 if ($self->start < $$exon_starts[0]) {
255 0         0 push @introns, GenOO::Intron->new({
256             strand => $self->strand,
257             chromosome => $self->rname,
258             start => $self->start,
259             stop => $$exon_starts[0] - 1,
260             part_of => $self,
261             });
262             }
263            
264 3         7 for (my $i=1;$i<@{$exon_starts};$i++) {
  12         28  
265             push @introns, (GenOO::Intron->new({
266             strand => $self->strand,
267             chromosome => $self->rname,
268 9         23 start => ${$exon_stops}[$i-1] + 1,
269 9         222 stop => ${$exon_starts}[$i] - 1,
  9         238  
270             part_of => $self,
271             }));
272             }
273            
274 3 50       78 if ($self->stop > $$exon_stops[-1]) {
275 0         0 push @introns, (GenOO::Intron->new({
276             strand => $self->strand,
277             chromosome => $self->rname,
278             start => $$exon_stops[-1] + 1,
279             stop => $self->stop,
280             part_of => $self,
281             }));
282             }
283            
284 3         86 return \@introns;
285             }
286              
287             sub _sanitize_splice_starts_and_stops {
288 2019     2019   3406 my ($self) = @_;
289            
290 2019         50179 my $splice_starts = $self->splice_starts;
291 2019         48136 my $splice_stops = $self->splice_stops;
292            
293 2019 50       5000 if (@$splice_starts != @$splice_stops) {
294 0         0 die "Error: Spice starts array is not of the same size as splice_stops (".scalar @$splice_starts."!=".scalar @$splice_stops.")\n";
295             }
296            
297 2019         2918 my $index = 0;
298 2019         26283 while ($index < (@$splice_starts-1)) {
299 5551 50       8789 if ($$splice_stops[$index] == $$splice_starts[$index+1] - 1) {
300 0         0 $$splice_stops[$index] = $$splice_stops[$index+1];
301 0         0 splice @$splice_starts, $index+1, 1;
302 0         0 splice @$splice_stops, $index+1, 1;
303             }
304             else {
305 5551         11105 $index++;
306             }
307             }
308             }
309              
310             #######################################################################
311             ####################### Private Routines ###########################
312             #######################################################################
313             sub _sanitize_splice_coords_within_limits {
314 6     6   18 my ($pre_splice_starts, $pre_splice_stops, $start, $stop) = @_;
315            
316 6         11 my @splice_starts;
317             my @splice_stops;
318 6         19 for (my $i=0;$i<@$pre_splice_starts;$i++) {
319 48 100       87 if ($$pre_splice_stops[$i] < $start) {
    100          
320 14         25 next;
321             }
322             elsif ($$pre_splice_starts[$i] > $stop) {
323 14         25 next;
324             }
325             else { #if the exon overlaps or is contained in the UTR5
326 20 100       33 if ($start >= $$pre_splice_starts[$i]) {
327 6         14 push @splice_starts, $start;
328             }
329             else {
330 14         22 push @splice_starts, $$pre_splice_starts[$i];
331             }
332 20 100       31 if ($stop < $$pre_splice_stops[$i]) {
333 4         11 push @splice_stops, $stop;
334             }
335             else {
336 16         35 push @splice_stops, $$pre_splice_stops[$i];
337             }
338             }
339             }
340 6         41 return \@splice_starts, \@splice_stops;
341             }
342              
343             sub _sorted_array {
344 8076     8076   10328 my $arrayref = $_;
345            
346 8076 100       9473 if (@{$arrayref} > 1){
  8076         16163  
347 3488         4672 for (my $i = 1; $i < @{$arrayref}; $i++){
  25652         40285  
348 22184 100       39918 if ($$arrayref[$i] < $$arrayref[$i-1]){
349 20         52 return 0;
350             }
351             }
352 3468         6838 return 1;
353             }
354 4588         8446 return 1;
355             }
356              
357             1;