File Coverage

blib/lib/App/RL/Command/position.pm
Criterion Covered Total %
statement 78 84 92.8
branch 30 40 75.0
condition n/a
subroutine 11 11 100.0
pod 6 6 100.0
total 125 141 88.6


line stmt bran cond sub pod time code
1             package App::RL::Command::position;
2 15     15   21295 use strict;
  15         1197  
  15         5832  
3 15     15   137 use warnings;
  15         38  
  15         608  
4 15     15   99 use autodie;
  15         31  
  15         124  
5              
6 15     15   97896 use App::RL -command;
  15         50  
  15         272  
7 15     15   7825 use App::RL::Common;
  15         44  
  15         23209  
8              
9             sub abstract {
10 2     2 1 93 return 'compare runlists against positions';
11             }
12              
13             sub opt_spec {
14             return (
15 7     7 1 91 [ "outfile|o=s", "output filename. [stdout] for screen" ],
16             [ "op=s", "operations: overlap, non-overlap or superset", { default => "overlap" } ],
17             [ "remove|r", "remove 'chr0' from chromosome names" ],
18             { show_defaults => 1, }
19             );
20             }
21              
22             sub usage_desc {
23 7     7 1 83876 return "runlist position [options] ";
24             }
25              
26             sub description {
27 1     1 1 1057 my $desc;
28 1         6 $desc .= ucfirst(abstract) . ".\n";
29 1         21 $desc .= <<'MARKDOWN';
30              
31             Genome positions:
32              
33             I:1-100 # Preferred format
34             I(+):90-150 # Strand will be omitted
35             S288c.I(-):190-200 # Species names will be omitted
36              
37             MARKDOWN
38              
39 1         5 return $desc;
40             }
41              
42             sub validate_args {
43 6     6 1 9432 my ( $self, $opt, $args ) = @_;
44              
45 6 100       20 if ( @{$args} < 2 ) {
  6         57  
46 2         9 my $message = "This command need two input files.\n\tIt found";
47 2         7 $message .= sprintf " [%s]", $_ for @{$args};
  2         18  
48 2         9 $message .= ".\n";
49 2         21 $self->usage_error($message);
50             }
51 4         15 for ( @{$args} ) {
  4         15  
52 7 50       432 next if lc $_ eq "stdin";
53 7 100       45 if ( !Path::Tiny::path($_)->is_file ) {
54 1         180 $self->usage_error("The input file [$_] doesn't exist.");
55             }
56             }
57              
58 3 100       265 if ( $opt->{op} =~ /^overlap/i ) {
    100          
    50          
59 1         6 $opt->{op} = 'overlap';
60             }
61             elsif ( $opt->{op} =~ /^non/i ) {
62 1         3 $opt->{op} = 'non-overlap';
63             }
64             elsif ( $opt->{op} =~ /^superset/i ) {
65 1         8 $opt->{op} = 'superset';
66             }
67             else {
68 0         0 Carp::confess "[@{[$opt->{op}]}] invalid\n";
  0         0  
69             }
70              
71 3 50       23 if ( !exists $opt->{outfile} ) {
72 0         0 $opt->{outfile} = Path::Tiny::path( $args->[0] )->absolute . "." . $opt->{op} . ".yml";
73             }
74             }
75              
76             sub execute {
77 3     3 1 35 my ( $self, $opt, $args ) = @_;
78              
79             #----------------------------#
80             # Loading
81             #----------------------------#
82 3         53 my $chrs = Set::Scalar->new;
83              
84             my $set_single
85 3         508 = App::RL::Common::runlist2set( YAML::Syck::LoadFile( $args->[0] ), $opt->{remove} );
86 3         57 $chrs->insert( keys %{$set_single} );
  3         64  
87              
88             #----------------------------#
89             # Reading and Output
90             #----------------------------#
91 3         655 my $in_fh = IO::Zlib->new( $args->[1], "rb" );
92              
93 3         6502 my $out_fh;
94 3 50       20 if ( lc( $opt->{outfile} ) eq "stdout" ) {
95 3         16 $out_fh = *STDOUT;
96             }
97             else {
98 0         0 open $out_fh, ">", $opt->{outfile};
99             }
100              
101 3         33 while ( !$in_fh->eof ) {
102 15         8931 my $line = $in_fh->getline;
103 15 50       3658 next if substr( $line, 0, 1 ) eq "#";
104 15         50 chomp $line;
105              
106 15         62 my $info = App::RL::Common::decode_header($line);
107 15 50       51 next unless App::RL::Common::info_is_valid($info);
108              
109 15 50       69 $info->{chr} =~ s/chr0?//i if $opt->{remove};
110 15         55 my $cur_positions = App::RL::Common::new_set();
111 15         244 $cur_positions->add_pair( $info->{start}, $info->{end} );
112              
113 15 100       1201 if ( $opt->{op} eq "overlap" ) {
114 5 50       40 if ( $chrs->has( $info->{chr} ) ) {
115 5         122 my $chr_single = $set_single->{ $info->{chr} };
116 5 100       48 if ( $chr_single->intersect($cur_positions)->is_not_empty ) {
117 2         1174 printf {$out_fh} "%s\n", App::RL::Common::encode_header($info);
  2         17  
118             }
119             }
120             }
121              
122 15 100       1911 if ( $opt->{op} eq "non-overlap" ) {
123 5 50       31 if ( $chrs->has( $info->{chr} ) ) {
124 5         119 my $chr_single = $set_single->{ $info->{chr} };
125 5 100       47 if ( $chr_single->intersect($cur_positions)->is_empty ) {
126 3         1567 printf {$out_fh} "%s\n", App::RL::Common::encode_header($info);
  3         25  
127             }
128             }
129             else {
130 0         0 printf {$out_fh} "%s\n", App::RL::Common::encode_header($info);
  0         0  
131             }
132             }
133              
134 15 100       1407 if ( $opt->{op} eq "superset" ) {
135 5 50       36 if ( $chrs->has( $info->{chr} ) ) {
136 5         137 my $chr_single = $set_single->{ $info->{chr} };
137 5 100       52 if ( $chr_single->superset($cur_positions) ) {
138 2         16777 printf {$out_fh} "%s\n", App::RL::Common::encode_header($info);
  2         66  
139             }
140             }
141             }
142             }
143              
144 3         824 $in_fh->close;
145 3         799 close $out_fh;
146             }
147              
148             1;