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.5.1';
39 1     1   637 use Moose::Role;
  1         2  
  1         7  
40 1     1   4137 use Moose::Util::TypeConstraints;
  1         2  
  1         7  
41 1     1   1557 use namespace::autoclean;
  1         1  
  1         8  
42              
43 1     1   441 use GenOO::Exon;
  1         2  
  1         37  
44 1     1   509 use GenOO::Intron;
  1         4  
  1         43  
45 1     1   451 use GenOO::Junction;
  1         2  
  1         1245  
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 1510 my $self = shift;
93            
94 1053         3907 $self->_sanitize_splice_starts_and_stops;
95             }
96              
97             #######################################################################
98             ######################## Interface Methods ########################
99             #######################################################################
100             sub is_position_within_exon {
101 4     4 0 1196 my ($self, $position) = @_;
102            
103 4         125 my $exons = $self->exons;
104 4         7 foreach my $exon (@$exons) {
105 10 100       32 if ($exon->contains_position($position)) {
106 2         8 return 1;
107             }
108             }
109 2         6 return 0;
110             }
111              
112             sub is_position_within_intron {
113 2     2 0 826 my ($self, $position) = @_;
114            
115 2         56 my $introns = $self->introns;
116 2         9 foreach my $intron (@$introns) {
117 4 100       14 if ($intron->contains_position($position)) {
118 1         5 return 1;
119             }
120             }
121 1         3 return 0;
122             }
123              
124             sub exon_exon_junctions {
125 1     1 0 887 my ($self) = @_;
126            
127 1         2 my @junctions;
128             my @junction_starts;
129 0         0 my @junction_stops;
130            
131 1         29 my $exons = $self->exons;
132 1 50       5 if (@$exons > 1) {
133 1         7 for (my $i=0;$i<@$exons-1;$i++) {
134 3         66 push @junction_starts, $$exons[$i]->stop;
135 3         76 push @junction_stops, $$exons[$i+1]->start;
136             }
137             }
138            
139 1 50       3 my $junctions_count = @junction_starts == @junction_stops ? @junction_starts : die "Junctions starts are not of the same size as junction stops\n";
140 1         6 for (my $i=0;$i<$junctions_count;$i++) {
141 3         72 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         6 return \@junctions;
151             }
152              
153             sub exonic_sequence {
154 1     1 0 1265 my ($self) = @_;
155            
156 1 50       42 if (defined $self->sequence) {
157 1         1 my $exonic_sequence = '';
158            
159 1 50       32 my $seq = $self->strand == 1 ? $self->sequence : reverse($self->sequence);
160 1         3 foreach my $exon (@{$self->exons}) {
  1         37  
161 4         142 $exonic_sequence .= substr($seq, ($exon->start - $self->start), $exon->length);
162             }
163            
164 1 50       43 if ($self->strand == 1) {
165 0         0 return $exonic_sequence;
166             }
167             else {
168 1         11 return reverse($exonic_sequence);
169             }
170             }
171             }
172              
173             sub exonic_length {
174 1     1 0 972 my ($self) = @_;
175            
176 1         6 my $length = 0;
177 1         2 foreach my $exon (@{$self->exons}) {
  1         50  
178 4         144 $length += $exon->length;
179             }
180            
181 1         8 return $length;
182             }
183              
184             sub intronic_length {
185 1     1 0 1316 my ($self) = @_;
186            
187 1         4 my $length = 0;
188 1         3 foreach my $intron (@{$self->introns}) {
  1         49  
189 3         93 $length += $intron->length;
190             }
191            
192 1         8 return $length;
193             }
194              
195             sub relative_exonic_position {
196 2     2 0 864 my ($self, $abs_pos) = @_;
197            
198 2 100       7 if ($self->is_position_within_exon($abs_pos)) {
199 1         21 my $relative_pos = $abs_pos - $self->start;
200 1         1 foreach my $intron (@{$self->introns}) {
  1         23  
201 1 50       22 if ($intron->stop < $abs_pos) {
202 0         0 $relative_pos -= $intron->length;
203             }
204             else {
205 1         2 last;
206             }
207             }
208 1         7 return $relative_pos;
209             }
210             else {
211 1         8 return undef;
212             }
213             }
214              
215             sub set_splice_starts_and_stops {
216 966     966 0 1230 my ($self, $splice_starts, $splice_stops) = @_;
217            
218 966         27709 $self->_set_splice_starts($splice_starts);
219 966         27182 $self->_set_splice_stops($splice_stops);
220 966         2047 $self->_sanitize_splice_starts_and_stops;
221             }
222              
223             #######################################################################
224             ####################### Private Methods ############################
225             #######################################################################
226             sub _create_exons {
227 20     20   30 my ($self) = @_;
228            
229 20         660 my $exon_starts = $self->splice_starts;
230 20         630 my $exon_stops = $self->splice_stops;
231            
232 20         30 my @exons;
233 20         42 for (my $i=0;$i<@{$exon_starts};$i++) {
  74         174  
234 54         1884 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         646 return \@exons;
244             }
245              
246             sub _create_introns {
247 3     3   6 my ($self) = @_;
248            
249 3         87 my $exon_starts = $self->splice_starts;
250 3         76 my $exon_stops = $self->splice_stops;
251            
252 3         6 my @introns;
253            
254 3 50       82 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         8 for (my $i=1;$i<@{$exon_starts};$i++) {
  12         27  
265             push @introns, (GenOO::Intron->new({
266             strand => $self->strand,
267             chromosome => $self->rname,
268 9         17 start => ${$exon_stops}[$i-1] + 1,
269 9         259 stop => ${$exon_starts}[$i] - 1,
  9         235  
270             part_of => $self,
271             }));
272             }
273            
274 3 50       79 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         78 return \@introns;
285             }
286              
287             sub _sanitize_splice_starts_and_stops {
288 2019     2019   2628 my ($self) = @_;
289            
290 2019         54144 my $splice_starts = $self->splice_starts;
291 2019         50809 my $splice_stops = $self->splice_stops;
292            
293 2019 50       4150 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         2534 my $index = 0;
298 2019         29000 while ($index < (@$splice_starts-1)) {
299 5551 50       6339 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         9968 $index++;
306             }
307             }
308             }
309              
310             #######################################################################
311             ####################### Private Routines ###########################
312             #######################################################################
313             sub _sanitize_splice_coords_within_limits {
314 6     6   10 my ($pre_splice_starts, $pre_splice_stops, $start, $stop) = @_;
315            
316 6         13 my @splice_starts;
317             my @splice_stops;
318 6         21 for (my $i=0;$i<@$pre_splice_starts;$i++) {
319 48 100       144 if ($$pre_splice_stops[$i] < $start) {
    100          
320 14         17 next;
321             }
322             elsif ($$pre_splice_starts[$i] > $stop) {
323 14         20 next;
324             }
325             else { #if the exon overlaps or is contained in the UTR5
326 20 100       28 if ($start >= $$pre_splice_starts[$i]) {
327 6         14 push @splice_starts, $start;
328             }
329             else {
330 14         16 push @splice_starts, $$pre_splice_starts[$i];
331             }
332 20 100       30 if ($stop < $$pre_splice_stops[$i]) {
333 4         10 push @splice_stops, $stop;
334             }
335             else {
336 16         34 push @splice_stops, $$pre_splice_stops[$i];
337             }
338             }
339             }
340 6         27 return \@splice_starts, \@splice_stops;
341             }
342              
343             sub _sorted_array {
344 8076     8076   7591 my $arrayref = $_;
345            
346 8076 100       5742 if (@{$arrayref} > 1){
  8076         14094  
347 3488         3046 for (my $i = 1; $i < @{$arrayref}; $i++){
  25652         30517  
348 22184 100       32170 if ($$arrayref[$i] < $$arrayref[$i-1]){
349 20         44 return 0;
350             }
351             }
352 3468         5865 return 1;
353             }
354 4588         7848 return 1;
355             }
356              
357             1;