File Coverage

blib/lib/GenOO/Spliceable.pm
Criterion Covered Total %
statement 127 136 93.3
branch 28 38 73.6
condition n/a
subroutine 20 20 100.0
pod 0 9 0.0
total 175 203 86.2


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.4.6';
39 1     1   636 use Moose::Role;
  1         1  
  1         8  
40 1     1   3914 use Moose::Util::TypeConstraints;
  1         1  
  1         7  
41 1     1   1551 use namespace::autoclean;
  1         2  
  1         10  
42              
43 1     1   410 use GenOO::Exon;
  1         2  
  1         41  
44 1     1   482 use GenOO::Intron;
  1         3  
  1         40  
45 1     1   495 use GenOO::Junction;
  1         2  
  1         1310  
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 1049     1049 0 1334 my $self = shift;
93            
94 1049         2882 $self->_sanitize_splice_starts_and_stops;
95             }
96              
97             #######################################################################
98             ######################## Interface Methods ########################
99             #######################################################################
100             sub is_position_within_exon {
101 4     4 0 600 my ($self, $position) = @_;
102            
103 4         144 my $exons = $self->exons;
104 4         12 foreach my $exon (@$exons) {
105 10 100       33 if ($exon->contains_position($position)) {
106 2         8 return 1;
107             }
108             }
109 2         14 return 0;
110             }
111              
112             sub is_position_within_intron {
113 2     2 0 643 my ($self, $position) = @_;
114            
115 2         66 my $introns = $self->introns;
116 2         8 foreach my $intron (@$introns) {
117 4 100       16 if ($intron->contains_position($position)) {
118 1         5 return 1;
119             }
120             }
121 1         8 return 0;
122             }
123              
124             sub exon_exon_junctions {
125 1     1 0 646 my ($self) = @_;
126            
127 1         4 my @junctions;
128             my @junction_starts;
129 0         0 my @junction_stops;
130            
131 1         39 my $exons = $self->exons;
132 1 50       7 if (@$exons > 1) {
133 1         8 for (my $i=0;$i<@$exons-1;$i++) {
134 3         83 push @junction_starts, $$exons[$i]->stop;
135 3         77 push @junction_stops, $$exons[$i+1]->start;
136             }
137             }
138            
139 1 50       8 my $junctions_count = @junction_starts == @junction_stops ? @junction_starts : die "Junctions starts are not of the same size as junction stops\n";
140 1         8 for (my $i=0;$i<$junctions_count;$i++) {
141 3         77 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         7 return \@junctions;
151             }
152              
153             sub exonic_sequence {
154 1     1 0 598 my ($self) = @_;
155            
156 1 50       45 if (defined $self->sequence) {
157 1         3 my $exonic_sequence = '';
158            
159 1 50       35 my $seq = $self->strand == 1 ? $self->sequence : reverse($self->sequence);
160 1         2 foreach my $exon (@{$self->exons}) {
  1         27  
161 4         96 $exonic_sequence .= substr($seq, ($exon->start - $self->start), $exon->length);
162             }
163            
164 1 50       28 if ($self->strand == 1) {
165 0         0 return $exonic_sequence;
166             }
167             else {
168 1         8 return reverse($exonic_sequence);
169             }
170             }
171             }
172              
173             sub exonic_length {
174 1     1 0 628 my ($self) = @_;
175            
176 1         2 my $length = 0;
177 1         3 foreach my $exon (@{$self->exons}) {
  1         34  
178 4         97 $length += $exon->length;
179             }
180            
181 1         7 return $length;
182             }
183              
184             sub intronic_length {
185 1     1 0 671 my ($self) = @_;
186            
187 1         2 my $length = 0;
188 1         1 foreach my $intron (@{$self->introns}) {
  1         39  
189 3         73 $length += $intron->length;
190             }
191            
192 1         5 return $length;
193             }
194              
195             sub relative_exonic_position {
196 2     2 0 665 my ($self, $abs_pos) = @_;
197            
198 2 100       7 if ($self->is_position_within_exon($abs_pos)) {
199 1         26 my $relative_pos = $abs_pos - $self->start;
200 1         1 foreach my $intron (@{$self->introns}) {
  1         30  
201 1 50       24 if ($intron->stop < $abs_pos) {
202 0         0 $relative_pos -= $intron->length;
203             }
204             else {
205 1         2 last;
206             }
207             }
208 1         8 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 1111 my ($self, $splice_starts, $splice_stops) = @_;
217            
218 966         26606 $self->_set_splice_starts($splice_starts);
219 966         25677 $self->_set_splice_stops($splice_stops);
220 966         1898 $self->_sanitize_splice_starts_and_stops;
221             }
222              
223             #######################################################################
224             ####################### Private Methods ############################
225             #######################################################################
226             sub _create_exons {
227 16     16   26 my ($self) = @_;
228            
229 16         392 my $exon_starts = $self->splice_starts;
230 16         384 my $exon_stops = $self->splice_stops;
231            
232 16         17 my @exons;
233 16         29 for (my $i=0;$i<@{$exon_starts};$i++) {
  62         140  
234 46         1168 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 16         375 return \@exons;
244             }
245              
246             sub _create_introns {
247 3     3   5 my ($self) = @_;
248            
249 3         75 my $exon_starts = $self->splice_starts;
250 3         72 my $exon_stops = $self->splice_stops;
251            
252 3         3 my @introns;
253            
254 3 50       76 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         5 for (my $i=1;$i<@{$exon_starts};$i++) {
  12         24  
265 9         17 push @introns, (GenOO::Intron->new({
266             strand => $self->strand,
267             chromosome => $self->rname,
268 9         240 start => ${$exon_stops}[$i-1] + 1,
269 9         245 stop => ${$exon_starts}[$i] - 1,
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         76 return \@introns;
285             }
286              
287             sub _sanitize_splice_starts_and_stops {
288 2015     2015   2063 my ($self) = @_;
289            
290 2015         46813 my $splice_starts = $self->splice_starts;
291 2015         45560 my $splice_stops = $self->splice_stops;
292            
293 2015 50       4275 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 2015         2411 my $index = 0;
298 2015         25655 while ($index < (@$splice_starts-1)) {
299 5547 50       6989 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 5547         9971 $index++;
306             }
307             }
308             }
309              
310             #######################################################################
311             ####################### Private Routines ###########################
312             #######################################################################
313             sub _sanitize_splice_coords_within_limits {
314 6     6   7 my ($pre_splice_starts, $pre_splice_stops, $start, $stop) = @_;
315            
316 6         7 my @splice_starts;
317             my @splice_stops;
318 6         15 for (my $i=0;$i<@$pre_splice_starts;$i++) {
319 48 100       74 if ($$pre_splice_stops[$i] < $start) {
    100          
320 14         20 next;
321             }
322             elsif ($$pre_splice_starts[$i] > $stop) {
323 14         19 next;
324             }
325             else { #if the exon overlaps or is contained in the UTR5
326 20 100       27 if ($start >= $$pre_splice_starts[$i]) {
327 6         9 push @splice_starts, $start;
328             }
329             else {
330 14         12 push @splice_starts, $$pre_splice_starts[$i];
331             }
332 20 100       25 if ($stop < $$pre_splice_stops[$i]) {
333 4         8 push @splice_stops, $stop;
334             }
335             else {
336 16         25 push @splice_stops, $$pre_splice_stops[$i];
337             }
338             }
339             }
340 6         19 return \@splice_starts, \@splice_stops;
341             }
342              
343             sub _sorted_array {
344 8060     8060   6942 my $arrayref = $_;
345            
346 8060 100       5897 if (@{$arrayref} > 1){
  8060         13801  
347 3472         2965 for (my $i = 1; $i < @{$arrayref}; $i++){
  25620         33315  
348 22168 100       34740 if ($$arrayref[$i] < $$arrayref[$i-1]){
349 20         51 return 0;
350             }
351             }
352 3452         6082 return 1;
353             }
354 4588         7310 return 1;
355             }
356              
357             1;