File Coverage

blib/lib/App/Fasops/Command/join.pm
Criterion Covered Total %
statement 82 87 94.2
branch 17 22 77.2
condition 7 9 77.7
subroutine 12 12 100.0
pod 6 6 100.0
total 124 136 91.1


line stmt bran cond sub pod time code
1             package App::Fasops::Command::join;
2 20     20   13671 use strict;
  20         56  
  20         635  
3 20     20   172 use warnings;
  20         432  
  20         549  
4 20     20   106 use autodie;
  20         44  
  20         117  
5              
6 20     20   104974 use App::Fasops -command;
  20         551  
  20         258  
7 20     20   6873 use App::RL::Common;
  20         44  
  20         521  
8 20     20   111 use App::Fasops::Common;
  20         37  
  20         20047  
9              
10             sub abstract {
11 2     2 1 51 return 'join multiple blocked fasta files by common target';
12             }
13              
14             sub opt_spec {
15             return (
16 4     4 1 24 [ "outfile|o=s", "Output filename. [stdout] for screen" ],
17             [ "name|n=s", "According to this species. Default is the first one" ],
18             { show_defaults => 1, }
19             );
20             }
21              
22             sub usage_desc {
23 4     4 1 44422 return "fasops join [options] [more infiles]";
24             }
25              
26             sub description {
27 1     1 1 770 my $desc;
28 1         5 $desc .= ucfirst(abstract) . ".\n";
29 1         3 $desc .= <<'MARKDOWN';
30              
31             * are paths to axt files, .axt.gz is supported
32             * infile == stdin means reading from STDIN
33              
34             MARKDOWN
35              
36 1         3 return $desc;
37             }
38              
39             sub validate_args {
40 3     3 1 2685 my ( $self, $opt, $args ) = @_;
41              
42 3 100       5 if ( !@{$args} ) {
  3         14  
43 1         3 my $message = "This command need one or more input files.\n\tIt found";
44 1         2 $message .= sprintf " [%s]", $_ for @{$args};
  1         4  
45 1         4 $message .= ".\n";
46 1         11 $self->usage_error($message);
47             }
48 2         5 for ( @{$args} ) {
  2         6  
49 4 50       112 next if lc $_ eq "stdin";
50 4 100       15 if ( !Path::Tiny::path($_)->is_file ) {
51 1         120 $self->usage_error("The input file [$_] doesn't exist.");
52             }
53             }
54              
55 1 50       52 if ( !exists $opt->{outfile} ) {
56             $opt->{outfile}
57 0         0 = Path::Tiny::path( $args->[0] )->absolute . ".join.fas";
58             }
59             }
60              
61             sub execute {
62 1     1 1 9 my ( $self, $opt, $args ) = @_;
63              
64 1         3 my $out_fh;
65 1 50       6 if ( lc( $opt->{outfile} ) eq "stdout" ) {
66 1         4 $out_fh = *STDOUT{IO};
67             }
68             else {
69 0         0 open $out_fh, ">", $opt->{outfile};
70             }
71              
72 1         12 tie my %block_of, "Tie::IxHash";
73 1         23 for my $infile ( @{$args} ) {
  1         4  
74 3         322 my $in_fh;
75 3 50       13 if ( lc $infile eq "stdin" ) {
76 0         0 $in_fh = *STDIN{IO};
77             }
78             else {
79 3         18 $in_fh = IO::Zlib->new( $infile, "rb" );
80             }
81              
82 3         4953 my $content = ''; # content of one block
83 3         6 while (1) {
84 18 100 100     177 last if $in_fh->eof and $content eq '';
85 15         1073 my $line = '';
86 15 100       50 if ( !$in_fh->eof ) {
87 12         500 $line = $in_fh->getline;
88             }
89 15 100 66     2792 if ( ( $line eq '' or $line =~ /^\s+$/ ) and $content ne '' ) {
      66        
90 3         14 my $info_of = App::Fasops::Common::parse_block($content);
91 3         7 $content = '';
92              
93             # set $opt->{name} to the first one of the first block
94 3 50       11 if ( !defined $opt->{name} ) {
95 0         0 ( $opt->{name} ) = keys %{$info_of};
  0         0  
96             }
97              
98             # target name
99 3         13 my $header = App::RL::Common::encode_header( $info_of->{ $opt->{name} } );
100              
101 3 100       470 if ( exists $block_of{$header} ) {
102             my @other_names
103 2         12 = grep { $_ ne $opt->{name} } keys %{$info_of};
  4         41  
  2         6  
104 2         8 for my $name (@other_names) {
105 2         6 $block_of{$header}->{$name} = $info_of->{$name};
106             }
107             }
108             else {
109 1         10 $block_of{$header} = $info_of;
110             }
111             }
112             else {
113 12         75 $content .= $line;
114             }
115             }
116 3         495 $in_fh->close;
117             }
118              
119 1         131 for my $header ( keys %block_of ) {
120 1         22 my $info_of = $block_of{$header};
121              
122 1         11 my @names = keys %{$info_of};
  1         5  
123              
124 1         26 for my $name (@names) {
125 4         97 my $info = $info_of->{$name};
126 4         26 printf {$out_fh} ">%s\n", App::RL::Common::encode_header($info);
  4         16  
127 4         666 printf {$out_fh} "%s\n", $info->{seq};
  4         20  
128             }
129 1         80 print {$out_fh} "\n";
  1         5  
130             }
131              
132 1         22 close $out_fh;
133             }
134              
135             1;