File Coverage

blib/lib/GenOO/Data/File/SAM/Record.pm
Criterion Covered Total %
statement 80 88 90.9
branch 13 20 65.0
condition n/a
subroutine 27 29 93.1
pod 0 20 0.0
total 120 157 76.4


line stmt bran cond sub pod time code
1             # POD documentation - main docs before the code
2              
3             =head1 NAME
4              
5             GenOO::Data::File::SAM::Record - Object representing a record of a sam file
6              
7             =head1 SYNOPSIS
8              
9             # Object representing a record of a sam file
10              
11             # To initialize
12             my $sam_record = GenOO::Data::File::SAM::Record->new(
13             fields => [qname,flag, rname, pos, mapq, cigar,
14             rnext, pnext, tlen, seq, qual, tags]
15             );
16              
17              
18             =head1 DESCRIPTION
19              
20             This object represents a record of a sam file and offers methods for accessing the different attributes.
21             It implements several additional methods that transform original attributes in more manageable attributes.
22             eg. from the FLAG attribute the actual strand is extracted etc.
23              
24             =head1 EXAMPLES
25              
26             # Check if the record corresponds to a match
27             my $mapped = $sam_record->is_mapped;
28            
29             # Check if the record corresponds to a non match
30             my $unmapped = $sam_record->is_unmapped;
31            
32             # Parse the FLAG attribute and return 1 or -1 for the strand
33             my $strand = $sam_record->strand;
34              
35             =cut
36              
37             # Let the code begin...
38              
39             package GenOO::Data::File::SAM::Record;
40             $GenOO::Data::File::SAM::Record::VERSION = '1.5.1';
41              
42             #######################################################################
43             ####################### Load External modules #####################
44             #######################################################################
45 1     1   7 use Modern::Perl;
  1         1  
  1         10  
46 1     1   183 use autodie;
  1         2  
  1         10  
47 1     1   4252 use Moose;
  1         1  
  1         8  
48 1     1   7401 use namespace::autoclean;
  1         2  
  1         11  
49              
50              
51             #######################################################################
52             ####################### Interface attributes ######################
53             #######################################################################
54             has 'fields' => (
55             traits => ['Array'],
56             is => 'ro',
57             isa => 'ArrayRef[Str]',
58             default => sub { [] },
59             handles => {
60             all_fields => 'elements',
61             add_field => 'push',
62             map_fields => 'map',
63             filter_fields => 'grep',
64             find_field => 'first',
65             get_field => 'get',
66             join_fields => 'join',
67             count_fields => 'count',
68             has_fields => 'count',
69             has_no_fields => 'is_empty',
70             sorted_fields => 'sort',
71             },
72             required => 1,
73             );
74              
75             has 'tags' => (
76             is => 'ro',
77             builder => '_read_tags',
78             init_arg => undef,
79             lazy => 1,
80             );
81              
82             has 'alignment_length' => (
83             is => 'ro',
84             builder => '_calculate_alignment_length',
85             init_arg => undef,
86             lazy => 1,
87             );
88              
89             has 'start' => (
90             is => 'ro',
91             builder => '_calculate_start',
92             init_arg => undef,
93             lazy => 1,
94             );
95              
96             has 'stop' => (
97             is => 'ro',
98             builder => '_calculate_stop',
99             init_arg => undef,
100             lazy => 1,
101             );
102              
103             has 'strand' => (
104             is => 'ro',
105             builder => '_calculate_strand',
106             init_arg => undef,
107             lazy => 1,
108             );
109              
110             has 'copy_number' => (
111             is => 'ro',
112             default => 1,
113             lazy => 1
114             );
115              
116             has 'extra' => (
117             is => 'rw',
118             init_arg => undef,
119             );
120              
121              
122             #######################################################################
123             ########################## Consumed Roles #########################
124             #######################################################################
125             with
126             'GenOO::Region' => {
127             -alias => { mid_position => 'region_mid_position' },
128             -excludes => 'mid_position',
129             },
130             'GenOO::Data::File::SAM::CigarAndMDZ' => {
131             };
132              
133              
134              
135             #######################################################################
136             ######################## Interface Methods ########################
137             #######################################################################
138             sub qname { # String [!-?A-~]f1,255g Query template NAME
139 2     2 0 1255 my ($self) = @_;
140            
141 2         94 return $self->fields->[0];
142             }
143              
144             sub flag { # Int [0,216-1] bitwise FLAG
145 2041     2041 0 2735 my ($self) = @_;
146            
147 2041         46528 return $self->fields->[1];
148             }
149              
150             sub rname { # String \*|[!-()+-<>-~][!-~]* Reference sequence NAME
151 647     647 0 1754 my ($self) = @_;
152            
153 647         13485 return $self->fields->[2];
154             }
155              
156             sub pos { # Int [0,229-1] 1-based leftmost mapping POSition
157 48     48 0 1276 my ($self) = @_;
158            
159 48         1550 return $self->fields->[3];
160             }
161              
162             sub mapq { # Int [0,28-1] MAPping Quality
163 2     2 0 751 my ($self) = @_;
164            
165 2         85 return $self->fields->[4];
166             }
167              
168             sub cigar { # String \*|([0-9]+[MIDNSHPX=])+ CIGAR string
169 196     196 0 978 my ($self) = @_;
170            
171 196         6661 return $self->fields->[5];
172             }
173              
174             sub rnext { # String \*|=|[!-()+-<>-~][!-~]* Ref. name of the mate/next segment
175 2     2 0 827 my ($self) = @_;
176            
177 2         79 return $self->fields->[6];
178             }
179              
180             sub pnext { # Int [0,229-1] Position of the mate/next segment
181 2     2 0 1211 my ($self) = @_;
182            
183 2         98 return $self->fields->[7];
184             }
185              
186             sub tlen { # Int [-229+1,229-1] observed Template LENgth
187 2     2 0 1187 my ($self) = @_;
188            
189 2         98 return $self->fields->[8];
190             }
191              
192             sub seq { # String \*|[A-Za-z=.]+ segment SEQuence
193 29     29 0 1031 my ($self) = @_;
194            
195 29         1028 return $self->fields->[9];
196             }
197              
198             sub qual { # String [!-~]+ ASCII of Phred-scaled base QUALity+33
199 2     2 0 1247 my ($self) = @_;
200            
201 2         98 return $self->fields->[10];
202             }
203              
204             sub sequence {
205 0     0 0 0 my ($self) = @_;
206              
207 0         0 return $self->seq;
208             }
209              
210             sub query_seq {
211 8     8 0 1193 my ($self) = @_;
212            
213 8 50       201 if (defined $self->strand) {
    0          
214 8 100       186 if ($self->strand == 1) {
    50          
215 5         9 return $self->seq;
216             }
217             elsif ($self->strand == -1) {
218 3         11 my $seq = reverse($self->seq);
219 3         6 $seq =~ tr/ATGCUatgcu/TACGAtacga/;
220 3         13 return $seq;
221             }
222             }
223             elsif ($self->is_unmapped) {
224 0         0 return $self->seq;
225             }
226             else {
227 0         0 return undef;
228             }
229             }
230              
231             sub query_length {
232 19     19 0 1250 my ($self) = @_;
233            
234 19         41 return CORE::length($self->seq); # using seq to avoid costs of query_seq
235             }
236              
237             sub tag {
238 43     43 0 997 my ($self, $tag_id) = @_;
239            
240 43 50       1536 if (defined $self->tags) {
241 43         1335 return $self->tags->{$tag_id};
242             }
243             }
244              
245             sub mdz {
246 32     32 0 32 my ($self) = @_;
247            
248 32         52 return $self->tag('MD:Z');
249             }
250              
251             sub to_string {
252 1     1 0 1177 my ($self) = @_;
253            
254 1         390 return $self->join_fields("\t");
255             }
256              
257             sub is_mapped {
258 1349     1349 0 2342 my ($self) = @_;
259            
260 1349 100       1721 if ($self->flag & 4) {
261 337         9524 return 0;
262             }
263             else {
264 1012         17237 return 1;
265             }
266             }
267              
268             sub is_unmapped {
269 3     3 0 893 my ($self) = @_;
270            
271 3 100       5 if ($self->flag & 4) {
272 1         5 return 1;
273             }
274             else {
275 2         7 return 0;
276             }
277             }
278              
279             sub is_secondary {
280 0     0 0 0 my ($self) = @_;
281            
282 0 0       0 if ($self->flag & 256) {
283 0         0 return 1;
284             }
285             else {
286 0         0 return 0;
287             }
288             }
289              
290              
291             #######################################################################
292             ######################### Private methods ##########################
293             #######################################################################
294             sub _calculate_alignment_length {
295 6     6   8 my ($self) = @_;
296            
297 6         129 return $self->length;
298             }
299              
300             sub _calculate_start {
301 46     46   51 my ($self) = @_;
302            
303 46         86 return $self->pos - 1;
304             }
305              
306             sub _calculate_stop {
307 13     13   16 my ($self) = @_;
308            
309 13         334 return $self->start + $self->M_count + $self->D_count + $self->N_count + $self->EQ_count + $self->X_count + $self->P_count - 1;
310             }
311              
312             sub _calculate_strand {
313 687     687   626 my ($self) = @_;
314            
315 687 100       762 if ($self->flag & 16) {
    100          
316 319         7013 return -1;
317             }
318             elsif ($self->is_mapped) {
319 365         7966 return 1;
320             }
321             else {
322 3         83 return undef;
323             }
324             }
325              
326             sub _read_tags {
327 28     28   30 my ($self) = @_;
328            
329 28         29 my %tags;
330            
331 28         1220 my @tags_array = @{$self->fields}[11..$self->count_fields-1];
  28         923  
332 28         55 foreach my $tag_var (@tags_array) {
333 63         200 $tag_var =~ /([A-Za-z][A-Za-z0-9]):([AifZHB]):(.+)/;
334 63         101 my $tag = $1;
335 63         69 my $tag_type = $2;
336 63         87 my $tag_value = $3;
337 63         188 $tags{"$tag:$tag_type"} = $tag_value;
338             }
339            
340 28         958 return \%tags;
341             }
342              
343              
344             #######################################################################
345             ############################ Finalize #############################
346             #######################################################################
347             __PACKAGE__->meta->make_immutable;
348              
349             1;