File Coverage

blib/lib/App/Fasops/Command/replace.pm
Criterion Covered Total %
statement 95 99 95.9
branch 19 24 79.1
condition 6 9 66.6
subroutine 12 12 100.0
pod 6 6 100.0
total 138 150 92.0


line stmt bran cond sub pod time code
1             package App::Fasops::Command::replace;
2 20     20   14164 use strict;
  20         50  
  20         609  
3 20     20   165 use warnings;
  20         43  
  20         704  
4 20     20   124 use autodie;
  20         43  
  20         115  
5              
6 20     20   103710 use App::Fasops -command;
  20         46  
  20         193  
7 20     20   6762 use App::RL::Common;
  20         46  
  20         533  
8 20     20   116 use App::Fasops::Common;
  20         46  
  20         23266  
9              
10             sub abstract {
11 2     2 1 46 return 'replace headers from a blocked fasta';
12             }
13              
14             sub opt_spec {
15 7     7 1 28 return ( [ "outfile|o=s", "Output filename. [stdout] for screen." ], { show_defaults => 1, } );
16             }
17              
18             sub usage_desc {
19 7     7 1 46152 return "fasops replace [options] ";
20             }
21              
22             sub description {
23 1     1 1 469 my $desc;
24 1         4 $desc .= ucfirst(abstract) . ".\n";
25 1         3 $desc .= <<'MARKDOWN';
26              
27             * are paths to axt files, .axt.gz is supported
28             * infile == stdin means reading from STDIN
29              
30             * is a tab-separated file containing more than one fields
31              
32             original_name replace_name more_replace_name
33              
34             * With one field will delete the whole alignment block
35             * With three or more fields will duplicate the whole alignment block
36              
37             MARKDOWN
38              
39 1         2 return $desc;
40             }
41              
42             sub validate_args {
43 6     6 1 3301 my ( $self, $opt, $args ) = @_;
44              
45 6 100       8 if ( @{$args} != 2 ) {
  6         19  
46 2         4 my $message = "This command need two input files.\n\tIt found";
47 2         3 $message .= sprintf " [%s]", $_ for @{$args};
  2         6  
48 2         5 $message .= ".\n";
49 2         10 $self->usage_error($message);
50             }
51 4         5 for ( @{$args} ) {
  4         9  
52 7 50       160 next if lc $_ eq "stdin";
53 7 100       21 if ( !Path::Tiny::path($_)->is_file ) {
54 1         87 $self->usage_error("The input file [$_] doesn't exist.");
55             }
56             }
57              
58 3 50       119 if ( !exists $opt->{outfile} ) {
59 0         0 $opt->{outfile} = Path::Tiny::path( $args->[0] )->absolute . ".fas";
60             }
61             }
62              
63             sub execute {
64 3     3 1 14 my ( $self, $opt, $args ) = @_;
65              
66 3         13 my $replace = App::Fasops::Common::read_replaces( $args->[1] );
67              
68 3         5 my $in_fh;
69 3 50       9 if ( lc $args->[0] eq "stdin" ) {
70 0         0 $in_fh = *STDIN{IO};
71             }
72             else {
73 3         18 $in_fh = IO::Zlib->new( $args->[0], "rb" );
74             }
75              
76 3         4104 my $out_fh;
77 3 50       10 if ( lc( $opt->{outfile} ) eq "stdout" ) {
78 3         7 $out_fh = *STDOUT{IO};
79             }
80             else {
81 0         0 open $out_fh, ">", $opt->{outfile};
82             }
83              
84             {
85 3         4 my $content = ''; # content of one block
  3         4  
86 3         5 while (1) {
87 84 100 66     415 last if $in_fh->eof and $content eq '';
88 81         2777 my $line = '';
89 81 50       194 if ( !$in_fh->eof ) {
90 81         2553 $line = $in_fh->getline;
91             }
92 81 100 66     7647 if ( ( $line eq '' or $line =~ /^\s+$/ ) and $content ne '' ) {
      66        
93 9         28 my $info_of = App::Fasops::Common::parse_block_header($content);
94 9         16 $content = '';
95              
96 9         10 my @ori_names = keys %{$info_of};
  9         22  
97              
98             my @replace_names
99 9         183 = grep { exists $info_of->{$_} } keys %{$replace};
  15         143  
  9         20  
100              
101 9 100       54 if ( @replace_names == 0 ) { # block untouched
    100          
102 5         10 for my $header (@ori_names) {
103 20         65 printf {$out_fh} ">%s\n",
104 20         358 App::RL::Common::encode_header( $info_of->{$header} );
105 20         2889 printf {$out_fh} "%s\n", $info_of->{$header}{seq};
  20         70  
106             }
107 5         112 print {$out_fh} "\n";
  5         15  
108             }
109             elsif ( @replace_names == 1 ) { # each replaces create a new block
110 3         5 my $ori_name = $replace_names[0];
111 3         5 for my $new_name ( @{ $replace->{$ori_name} } ) {
  3         8  
112 3         24 for my $header (@ori_names) {
113 12 100       223 if ( $header eq $ori_name ) {
114 3         5 printf {$out_fh} ">%s\n", $new_name;
  3         8  
115 3         42 printf {$out_fh} "%s\n", $info_of->{$header}{seq};
  3         11  
116             }
117             else {
118 9         35 printf {$out_fh} ">%s\n",
119 9         10 App::RL::Common::encode_header( $info_of->{$header} );
120 9         1274 printf {$out_fh} "%s\n", $info_of->{$header}{seq};
  9         32  
121             }
122             }
123 3         66 print {$out_fh} "\n";
  3         8  
124             }
125             }
126             else {
127 1         181 Carp::carp "Don't support multiply records in one block. @replace_names\n";
128 1         76 for my $header (@ori_names) {
129 4         15 printf {$out_fh} ">%s\n",
130 4         71 App::RL::Common::encode_header( $info_of->{$header} );
131 4         598 printf {$out_fh} "%s\n", $info_of->{$header}{seq};
  4         16  
132             }
133 1         22 print {$out_fh} "\n";
  1         3  
134             }
135              
136             }
137             else {
138 72         133 $content .= $line;
139             }
140             }
141             }
142 3         428 close $out_fh;
143 0           $in_fh->close;
144             }
145              
146             1;