File Coverage

blib/lib/Bio/MUST/Core/IdMapper.pm
Criterion Covered Total %
statement 83 83 100.0
branch 7 10 70.0
condition 11 14 78.5
subroutine 16 16 100.0
pod 4 5 80.0
total 121 128 94.5


line stmt bran cond sub pod time code
1             package Bio::MUST::Core::IdMapper;
2             # ABSTRACT: Id mapper for translating sequence ids
3             $Bio::MUST::Core::IdMapper::VERSION = '0.212670';
4 17     17   135 use Moose;
  17         42  
  17         225  
5 17     17   86730 use namespace::autoclean;
  17         48  
  17         175  
6              
7 17     17   2097 use autodie;
  17         43  
  17         164  
8 17     17   94303 use feature qw(say);
  17         69  
  17         1726  
9              
10 17     17   134 use Carp;
  17         83  
  17         1494  
11 17     17   121 use List::AllUtils qw(mesh uniq each_array);
  17         44  
  17         1099  
12              
13 17     17   137 use Bio::MUST::Core::Types;
  17         50  
  17         514  
14 17     17   126 use Bio::MUST::Core::Constants qw(:files);
  17         43  
  17         3504  
15 17     17   158 use aliased 'Bio::MUST::Core::SeqId';
  17         56  
  17         180  
16             with 'Bio::MUST::Core::Roles::Commentable';
17              
18              
19             # long_ids and abbr_ids public arrays
20             has $_ . '_ids' => (
21             traits => ['Array'],
22             is => 'ro',
23             isa => 'Bio::MUST::Core::Types::full_ids',
24             default => sub { [] },
25             coerce => 1,
26             writer => '_set_' . $_ . '_ids',
27             handles => {
28             'count_' . $_ . '_ids' => 'count',
29             'all_' . $_ . '_ids' => 'elements',
30             },
31             ) for qw(long abbr);
32              
33              
34             # _long_id_for and _abbr_id_for private hashes for faster mapping
35             has '_' . $_ . '_id_for' => (
36             traits => ['Hash'],
37             is => 'ro',
38             isa => 'HashRef[Str]',
39             init_arg => undef,
40             lazy => 1,
41             builder => '_build_' . $_ . '_id_for',
42             handles => {
43             $_ . '_id_for' => 'get',
44             },
45             ) for qw(long abbr);
46              
47              
48             # Note: mesh, uniq and co do not work with the 'elements' native trait,
49             # hence the option to coerce the public array refs in all the following subs
50              
51             # Note: private hashes are not updated once (lazily) built
52              
53             ## no critic (ProhibitUnusedPrivateSubroutines)
54              
55             # same note as in IdList.pm about SeqId objects
56              
57             sub _build_long_id_for {
58 14     14   29 my $self = shift;
59              
60 14         51 my @abbr_ids = map { $_->full_id } $self->all_abbr_seq_ids;
  111         2838  
61 14         422 my @long_ids = map { $_->full_id } $self->all_long_seq_ids;
  111         2847  
62              
63 14         426 return { mesh @abbr_ids, @long_ids };
64             }
65              
66             sub _build_abbr_id_for {
67 14     14   38 my $self = shift;
68              
69 14         68 my @abbr_ids = map { $_->full_id } $self->all_abbr_seq_ids;
  95         2536  
70 14         438 my @long_ids = map { $_->full_id } $self->all_long_seq_ids;
  95         2532  
71              
72 14         499 return { mesh @long_ids, @abbr_ids };
73             }
74              
75             ## use critic
76              
77              
78             sub BUILD {
79 27     27 0 63 my $self = shift;
80              
81             # TODO: check that is has any effect at all!
82 27 50       1128 carp '[BMC] Warning: long and abbreviated id list sizes differ!'
83             unless $self->count_long_ids == $self->count_abbr_ids;
84             carp '[BMC] Warning: non unique long ids!'
85 27 50       965 unless $self->count_long_ids == uniq @{ $self->long_ids };
  27         787  
86             carp '[BMC] Warning: non unique abbreviated ids!'
87 27 50       1085 unless $self->count_abbr_ids == uniq @{ $self->abbr_ids };
  27         817  
88              
89 27         790 return;
90             }
91              
92              
93             # TODO: add an alias 'all_seq_ids' to one of the two following methods?
94              
95              
96             sub all_long_seq_ids {
97 29     29 1 1394 my $self = shift;
98 29         1193 return map { SeqId->new( full_id => $_ ) } $self->all_long_ids;
  216         5963  
99             }
100              
101              
102              
103             sub all_abbr_seq_ids {
104 28     28 1 71 my $self = shift;
105 28         1089 return map { SeqId->new( full_id => $_ ) } $self->all_abbr_ids;
  206         5569  
106             }
107              
108              
109             # I/O methods
110              
111              
112             sub load {
113 4     4 1 856 my $class = shift;
114 4         9 my $infile = shift;
115 4   100     26 my $args = shift // {}; # HashRef (should not be empty...)
116              
117             # TODO: strip whitespace? also in ColorScheme? and IdList?
118 4   66     34 my $sep = $args->{sep} // qr{\t}xms;
119              
120 4         28 open my $in, '<', $infile;
121              
122 4         5155 my $mapper = $class->new();
123              
124             # Note: we now use temporary arrays because Moose coercions add a lot of
125             # overhead if pushing directly (through delegation) on the attributes
126              
127 4         13 my @long_ids;
128             my @abbr_ids;
129              
130             LINE:
131 4         2121 while (my $line = <$in>) {
132 65         130 chomp $line;
133              
134             # skip empty lines and comment lines
135 65 100 66     363 next LINE if $line =~ $EMPTY_LINE
136             || $mapper->is_comment($line);
137              
138             # extract long and abbreviated ids
139 59         229 my ($long_id, $abbr_id) = split $sep, $line;
140 59         126 push @long_ids, $long_id;
141 59         215 push @abbr_ids, $abbr_id;
142             }
143              
144 4         205 $mapper->_set_long_ids( \@long_ids );
145 4         221 $mapper->_set_abbr_ids( \@abbr_ids );
146              
147 4         107 return $mapper;
148             }
149              
150              
151              
152             sub store {
153 3     3 1 9 my $self = shift;
154 3         4 my $outfile = shift;
155 3   50     10 my $args = shift // {}; # HashRef (should not be empty...)
156              
157 3   100     15 my $sep = $args->{sep} // "\t"; # default to tab-separated
158 3   100     11 my $header = $args->{header} // 1; # default to MUST header
159              
160 3         13 open my $out, '>', $outfile;
161              
162             # note the use of a twin array iterator
163 3 100       864 print {$out} $self->header if $header;
  2         12  
164 3         7 my $ea = each_array @{ $self->long_ids }, @{ $self->abbr_ids };
  3         92  
  3         85  
165 3         27 while (my ($long_id, $abbr_id) = $ea->() ) {
166 30         47 say {$out} join $sep, $long_id, $abbr_id;
  30         134  
167             }
168              
169 3         163 return;
170             }
171              
172             # TODO: handle .nbs files from set_names_in_phylip_tree
173             # TODO: add a possible starting value of 1 for very old nbs files
174              
175             __PACKAGE__->meta->make_immutable;
176             1;
177              
178             __END__
179              
180             =pod
181              
182             =head1 NAME
183              
184             Bio::MUST::Core::IdMapper - Id mapper for translating sequence ids
185              
186             =head1 VERSION
187              
188             version 0.212670
189              
190             =head1 SYNOPSIS
191              
192             # TODO
193              
194             =head1 DESCRIPTION
195              
196             # TODO
197              
198             =head1 METHODS
199              
200             =head2 all_long_seq_ids
201              
202             =head2 all_abbr_seq_ids
203              
204             =head2 load
205              
206             =head2 store
207              
208             =head1 AUTHOR
209              
210             Denis BAURAIN <denis.baurain@uliege.be>
211              
212             =head1 COPYRIGHT AND LICENSE
213              
214             This software is copyright (c) 2013 by University of Liege / Unit of Eukaryotic Phylogenomics / Denis BAURAIN.
215              
216             This is free software; you can redistribute it and/or modify it under
217             the same terms as the Perl 5 programming language system itself.
218              
219             =cut