File Coverage

blib/lib/App/RL/Command/position.pm
Criterion Covered Total %
statement 83 89 93.2
branch 30 40 75.0
condition n/a
subroutine 11 11 100.0
pod 5 5 100.0
total 129 145 88.9


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