File Coverage

blib/lib/CracTools/Interval/Query/File.pm
Criterion Covered Total %
statement 95 107 88.7
branch 17 34 50.0
condition 6 15 40.0
subroutine 12 13 92.3
pod 1 1 100.0
total 131 170 77.0


line stmt bran cond sub pod time code
1             package CracTools::Interval::Query::File;
2              
3             {
4             $CracTools::Interval::Query::File::DIST = 'CracTools';
5             }
6             # ABSTRACT: Acts like CracTools::Interval::Query but read interval from files and return lines of the file matching the query.
7             $CracTools::Interval::Query::File::VERSION = '1.251';
8 2     2   13821 use strict;
  2         4  
  2         47  
9 2     2   10 use warnings;
  2         4  
  2         51  
10              
11 2     2   10 use Fcntl qw( SEEK_SET );
  2         4  
  2         83  
12 2     2   11 use Carp;
  2         3  
  2         100  
13              
14 2     2   693 use parent 'CracTools::Interval::Query';
  2         464  
  2         8  
15              
16              
17             sub new {
18 1     1 1 2671 my $class = shift;
19              
20             # Call parent constructor
21 1         8 my $self = $class->SUPER::new(@_);
22              
23 1         3 my %args = @_;
24              
25 1         3 my $file = $args{file};
26 1 50       3 croak "Missing file" unless defined $file;
27              
28 1         3 my $get_interval_sub = $args{get_interval_sub};
29              
30 1         2 my $header_skip = "#";
31 1 50       6 $header_skip = $args{header_skip} if defined $args{header_skip};
32              
33 1 50       3 if(!defined $get_interval_sub) {
34 1         3 my $type = $args{type};
35 1 50       3 croak "Missing type" unless defined $type;
36 1 50       5 if($type =~ /gff/i) {
    0          
    0          
37 1         3 $get_interval_sub = \&_getIntervalsFromGFFLine;
38             } elsif($type =~ /sam/i) {
39 0         0 $get_interval_sub = \&_getIntervalsFromSAMLine;
40 0         0 $header_skip = "@";
41             } elsif($type =~ /bed/i) {
42 0         0 $get_interval_sub = \&_getIntervalsFromBEDLine;
43 0         0 $header_skip = "track";
44             } else {
45 0         0 croak "Undefined type ($type)";
46             }
47             }
48              
49 1         4 $self->{get_interval_sub} = $get_interval_sub;
50 1         3 $self->{header_skip} = $header_skip;
51 1         2 $self->{file} = $file;
52              
53 1         5 $self->_init();
54              
55 1         3 return $self;
56             }
57              
58              
59             sub _getIntervals {
60 0     0   0 my ($self,$line) = @_;
61 0         0 my $intervals = $self->{get_interval_sub}->($line);
62 0 0       0 foreach (@$intervals) {$_->{strand} = 1 if !defined $_->{strand};}
  0         0  
63 0         0 return $intervals;
64             }
65              
66              
67             sub _getLine {
68 36     36   65 my ($self,$seek_pos) = @_;
69 36         59 my $fh = $self->{filehandle};
70 36         99 seek($fh,$seek_pos,SEEK_SET);
71 36         145 my $line = <$fh>;
72 36         65 chomp($line);
73 36         119 return $line;
74             }
75              
76              
77             sub _processReturnValue {
78 36     36   64 my $self = shift;
79 36         53 my $val = shift;
80 36         74 return $self->_getLine($val);
81             }
82              
83             sub _init {
84 1     1   3 my $self = shift;
85              
86 1 50       5 open(my $fh ,$self->{file}) or die ("Cannot open file ".$self->{file});
87              
88 1         39 my $curr_pos = tell($fh);
89 1         2 my $header_line = 1;
90              
91 1         14 while(<$fh>) {
92              
93             # skip headers
94 9 100       21 if($header_line) {
95 1 50       12 if($_ =~ /^$self->{header_skip}/) {
96 0         0 next;
97             } else {
98 1         3 $header_line = 0;
99             }
100             }
101              
102 9         15 my $pos = $curr_pos;
103 9         21 my $intervals = $self->{get_interval_sub}->($_);
104              
105 9         20 foreach my $i (@$intervals) {
106 9 50 33     49 if(defined $i->{low} && defined $i->{high} && defined $i->{seqname}) {
      33        
107              
108             # Add strand to default if not defined
109 9 50       21 $i->{strand} = 1 unless defined $i->{strand};
110              
111             # We do not want any "chr" string before the reference sequence value
112 9         18 $i->{seqname} =~ s/^chr//;
113              
114 9         25 $self->addInterval($i->{seqname},$i->{low},$i->{high},$i->{strand},$pos);
115             }
116             }
117              
118 9         38 $curr_pos = tell($fh);
119             }
120              
121 1         3 $self->{filehandle} = $fh;
122             }
123              
124              
125              
126             sub _getIntervalsFromGFFLine {
127 10     10   27 my $line = shift;
128 10         31 my @fields = split("\t",$line,8);
129 10         29 return [{ seqname => $fields[0],
130             low => $fields[3],
131             high => $fields[4],
132             strand => CracTools::Utils::convertStrand($fields[6]),
133             }];
134             }
135              
136             sub _getIntervalsFromSAMLine {
137 1     1   910 my $line = shift;
138 1         7 my @fields = split("\t",$line,7);
139 1         10 my $strand = 1;
140 1 50       5 if($fields[1] & 16) {
141 0         0 $strand = -1;
142             }
143 1         3 my $low = $fields[3];
144 1         2 my $high = $low;
145 1         2 my $intervals = [];
146 1         5 my $i = 0;
147 1         8 my @chunks = $fields[5] =~ /(\d+\D)/g;
148 1         4 foreach (@chunks) {
149 3         11 my ($nb,$op) = $_ =~ /(\d+)(\D)/;
150 3 100 66     21 if( $op eq 'N' || $op eq 'D' ) {
    50 33        
      33        
151 1         5 $intervals->[$i] = { seqname => $fields[2],
152             low => $low,
153             high =>$high,
154             strand => $strand,
155             };
156 1         2 $i++;
157 1         2 $low = $high + $nb;
158 1         3 $high = $low;
159             } elsif ($op ne 'S' || $op ne 'H' || $op ne 'I') {
160 2         6 $high += $nb;
161             }
162             }
163             # Add the last chunk
164 1         4 $intervals->[$i] = { seqname => $fields[2],
165             low => $low,
166             high =>$high,
167             strand => $strand,
168             };
169 1         4 return $intervals;
170             }
171              
172              
173             sub _getIntervalsFromBEDLine {
174 2     2   2339 my $line = shift;
175 2         9 my @fields = split("\t",$line,13);
176 2 100       9 if(@fields < 12) {
177 1         8 return [{ seqname => $fields[0], low => $fields[1]+1, high => $fields[2] }];
178             } else {
179 1         3 my $intervals = [];
180 1         3 my $low = $fields[1];
181 1         2 my $high;
182 1         3 my @block_size = split(',',$fields[10]);
183 1         4 my @block_start = split(',',$fields[11]);
184 1         5 for(my $i = 0; $i < $fields[9]; $i++) {
185 2         5 $low += $block_start[$i];
186 2         3 $high = $low + $block_size[$i];
187 2         7 $intervals->[$i] = { seqname => $fields[0],
188             low => $low + 1,
189             high => $high,
190             strand => CracTools::Utils::convertStrand($fields[5]),
191             };
192             }
193 1         4 return $intervals;
194             }
195             }
196              
197             1;
198              
199             __END__