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