File Coverage

blib/lib/GenOO/Data/File/SAM/Record.pm
Criterion Covered Total %
statement 77 85 90.5
branch 13 20 65.0
condition n/a
subroutine 27 29 93.1
pod 0 20 0.0
total 117 154 75.9


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.4.6';
41              
42             #######################################################################
43             ####################### Load External modules #####################
44             #######################################################################
45 1     1   6 use Modern::Perl;
  1         1  
  1         9  
46 1     1   149 use autodie;
  1         1  
  1         9  
47 1     1   3828 use Moose;
  1         2  
  1         9  
48 1     1   6359 use namespace::autoclean;
  1         2  
  1         10  
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 1054 my ($self) = @_;
140            
141 2         81 return $self->fields->[0];
142             }
143              
144             sub flag { # Int [0,216-1] bitwise FLAG
145 2041     2041 0 2134 my ($self) = @_;
146            
147 2041         50510 return $self->fields->[1];
148             }
149              
150             sub rname { # String \*|[!-()+-<>-~][!-~]* Reference sequence NAME
151 647     647 0 1285 my ($self) = @_;
152            
153 647         15456 return $self->fields->[2];
154             }
155              
156             sub pos { # Int [0,229-1] 1-based leftmost mapping POSition
157 48     48 0 711 my ($self) = @_;
158            
159 48         1224 return $self->fields->[3];
160             }
161              
162             sub mapq { # Int [0,28-1] MAPping Quality
163 2     2 0 604 my ($self) = @_;
164            
165 2         73 return $self->fields->[4];
166             }
167              
168             sub cigar { # String \*|([0-9]+[MIDNSHPX=])+ CIGAR string
169 196     196 0 813 my ($self) = @_;
170            
171 196         5864 return $self->fields->[5];
172             }
173              
174             sub rnext { # String \*|=|[!-()+-<>-~][!-~]* Ref. name of the mate/next segment
175 2     2 0 717 my ($self) = @_;
176            
177 2         97 return $self->fields->[6];
178             }
179              
180             sub pnext { # Int [0,229-1] Position of the mate/next segment
181 2     2 0 868 my ($self) = @_;
182            
183 2         73 return $self->fields->[7];
184             }
185              
186             sub tlen { # Int [-229+1,229-1] observed Template LENgth
187 2     2 0 660 my ($self) = @_;
188            
189 2         72 return $self->fields->[8];
190             }
191              
192             sub seq { # String \*|[A-Za-z=.]+ segment SEQuence
193 29     29 0 688 my ($self) = @_;
194            
195 29         782 return $self->fields->[9];
196             }
197              
198             sub qual { # String [!-~]+ ASCII of Phred-scaled base QUALity+33
199 2     2 0 654 my ($self) = @_;
200            
201 2         88 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 636 my ($self) = @_;
212            
213 8 50       219 if (defined $self->strand) {
    0          
214 8 100       192 if ($self->strand == 1) {
    50          
215 5         9 return $self->seq;
216             }
217             elsif ($self->strand == -1) {
218 3         8 my $seq = reverse($self->seq);
219 3         7 $seq =~ tr/ATGCUatgcu/TACGAtacga/;
220 3         8 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 666 my ($self) = @_;
233            
234 19         36 return CORE::length($self->seq); # using seq to avoid costs of query_seq
235             }
236              
237             sub tag {
238 43     43 0 643 my ($self, $tag_id) = @_;
239            
240 43 50       1266 if (defined $self->tags) {
241 43         1070 return $self->tags->{$tag_id};
242             }
243             }
244              
245             sub mdz {
246 32     32 0 27 my ($self) = @_;
247            
248 32         51 return $self->tag('MD:Z');
249             }
250              
251             sub to_string {
252 1     1 0 724 my ($self) = @_;
253            
254 1         50 return $self->join_fields("\t");
255             }
256              
257             sub is_mapped {
258 1349     1349 0 1721 my ($self) = @_;
259            
260 1349 100       1832 if ($self->flag & 4) {
261 337         9591 return 0;
262             }
263             else {
264 1012         20034 return 1;
265             }
266             }
267              
268             sub is_unmapped {
269 3     3 0 618 my ($self) = @_;
270            
271 3 100       9 if ($self->flag & 4) {
272 1         4 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   10 my ($self) = @_;
296            
297 6         165 return $self->length;
298             }
299              
300             sub _calculate_start {
301 46     46   46 my ($self) = @_;
302            
303 46         80 return $self->pos - 1;
304             }
305              
306             sub _calculate_stop {
307 13     13   15 my ($self) = @_;
308            
309 13         354 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   653 my ($self) = @_;
314            
315 687 100       889 if ($self->flag & 16) {
    100          
316 319         7711 return -1;
317             }
318             elsif ($self->is_mapped) {
319 365         8777 return 1;
320             }
321             else {
322 3         76 return undef;
323             }
324             }
325              
326             sub _read_tags {
327 28     28   38 my ($self) = @_;
328            
329 28         25 my %tags;
330            
331 28         1034 my @tags_array = @{$self->fields}[11..$self->count_fields-1];
  28         709  
332 28         52 foreach my $tag_var (@tags_array) {
333 63         130 my ($tag, $tag_type, $tag_value) = split(/:/,$tag_var);
334 63         152 $tags{"$tag:$tag_type"} = $tag_value;
335             }
336            
337 28         738 return \%tags;
338             }
339              
340              
341             #######################################################################
342             ############################ Finalize #############################
343             #######################################################################
344             __PACKAGE__->meta->make_immutable;
345              
346             1;