File Coverage

blib/lib/App/RL/Command/compare.pm
Criterion Covered Total %
statement 86 92 93.4
branch 18 24 75.0
condition n/a
subroutine 11 11 100.0
pod 6 6 100.0
total 121 133 90.9


line stmt bran cond sub pod time code
1             package App::RL::Command::compare;
2 15     15   18156 use strict;
  15         49  
  15         661  
3 15     15   106 use warnings;
  15         45  
  15         653  
4 15     15   100 use autodie;
  15         38  
  15         132  
5              
6 15     15   103915 use App::RL -command;
  15         70  
  15         326  
7 15     15   8391 use App::RL::Common;
  15         46  
  15         24271  
8              
9             sub abstract {
10 2     2 1 102 return 'compare 2 chromosome runlists';
11             }
12              
13             sub opt_spec {
14             return (
15 7     7 1 97 [ "outfile|o=s", "output filename. [stdout] for screen" ],
16             [ "op=s", "operations: intersect, union, diff or xor", { default => "intersect" } ],
17             [ "remove|r", "remove 'chr0' from chromosome names" ],
18             [ "mk", "*first* YAML file contains multiple sets of runlists" ],
19             { show_defaults => 1, }
20             );
21             }
22              
23             sub usage_desc {
24 7     7 1 77741 return "runlist compare [options] [more infiles]";
25             }
26              
27             sub description {
28 1     1 1 1389 my $desc;
29 1         4 $desc .= ucfirst(abstract) . ".\n";
30 1         5 return $desc;
31             }
32              
33             sub validate_args {
34 6     6 1 9687 my ( $self, $opt, $args ) = @_;
35              
36 6 100       16 if ( @{$args} < 2 ) {
  6         35  
37 2         6 my $message = "This command need two or more input files.\n\tIt found";
38 2         4 $message .= sprintf " [%s]", $_ for @{$args};
  2         12  
39 2         10 $message .= ".\n";
40 2         19 $self->usage_error($message);
41             }
42 4         16 for ( @{$args} ) {
  4         19  
43 7 50       368 next if lc $_ eq "stdin";
44 7 100       41 if ( !Path::Tiny::path($_)->is_file ) {
45 1         157 $self->usage_error("The input file [$_] doesn't exist.");
46             }
47             }
48              
49 3 50       265 if ( $opt->{op} =~ /^dif/i ) {
    50          
    100          
    50          
50 0         0 $opt->{op} = 'diff';
51             }
52             elsif ( $opt->{op} =~ /^uni/i ) {
53 0         0 $opt->{op} = 'union';
54             }
55             elsif ( $opt->{op} =~ /^int/i ) {
56 2         11 $opt->{op} = 'intersect';
57             }
58             elsif ( $opt->{op} =~ /^xor/i ) {
59 1         6 $opt->{op} = 'xor';
60             }
61             else {
62 0         0 Carp::confess "[@{[$opt->{op}]}] invalid\n";
  0         0  
63             }
64              
65 3 50       23 if ( !exists $opt->{outfile} ) {
66 0         0 $opt->{outfile} = Path::Tiny::path( $args->[0] )->absolute . "." . $opt->{op} . ".yml";
67             }
68             }
69              
70             sub execute {
71 3     3 1 29 my ( $self, $opt, $args ) = @_;
72              
73             #----------------------------#
74             # Loading
75             #----------------------------#
76 3         52 my $chrs = Set::Scalar->new;
77              
78             # file1
79 3         473 my $set_of = {};
80 3         9 my @names;
81 3 100       13 if ( $opt->{mk} ) {
82 2         16 my $yml = YAML::Syck::LoadFile( $args->[0] );
83 2         635 @names = sort keys %{$yml};
  2         18  
84              
85 2         9 for my $name (@names) {
86 10         580 $set_of->{$name} = App::RL::Common::runlist2set( $yml->{$name}, $opt->{remove} );
87 10         27 $chrs->insert( keys %{ $set_of->{$name} } );
  10         75  
88             }
89             }
90             else {
91 1         4 @names = ("__single");
92             $set_of->{__single}
93 1         6 = App::RL::Common::runlist2set( YAML::Syck::LoadFile( $args->[0] ), $opt->{remove} );
94 1         25 $chrs->insert( keys %{ $set_of->{__single} } );
  1         49  
95             }
96              
97             # file2 and more
98 3         366 my @set_singles;
99             {
100 3         10 my $argc = scalar @{$args};
  3         8  
  3         11  
101 3         19 for my $i ( 1 .. $argc - 1 ) {
102             my $s = App::RL::Common::runlist2set( YAML::Syck::LoadFile( $args->[$i] ),
103 3         23 $opt->{remove} );
104 3         18 $chrs->insert( keys %{$s} );
  3         27  
105 3         324 push @set_singles, $s;
106             }
107             }
108              
109             #----------------------------#
110             # Operating
111             #----------------------------#
112 3         12 my $op_result_of = { map { $_ => {} } @names };
  11         27  
113              
114 3         10 for my $name (@names) {
115 11         424 my $set_one = $set_of->{$name};
116              
117             # give empty set to non-existing chrs
118 11         27 for my $s ( $set_one, @set_singles ) {
119 22         136 for my $chr ( sort $chrs->members ) {
120 72 100       386 if ( !exists $s->{$chr} ) {
121 10         42 $s->{$chr} = App::RL::Common::new_set();
122             }
123             }
124             }
125              
126             # operate on each chr
127 11         33 for my $chr ( sort $chrs->members ) {
128 36         1222 my $op = $opt->{op};
129 36         95 my $op_set = $set_one->{$chr}->copy;
130 36         1372 for my $s (@set_singles) {
131 36         146 $op_set = $op_set->$op( $s->{$chr} );
132             }
133 36         31944 $op_result_of->{$name}{$chr} = $op_set->runlist;
134             }
135             }
136              
137             #----------------------------#
138             # Output
139             #----------------------------#
140 3         126 my $out_fh;
141 3 50       20 if ( lc( $opt->{outfile} ) eq "stdout" ) {
142 3         16 $out_fh = *STDOUT{IO};
143             }
144             else {
145 0         0 open $out_fh, ">", $opt->{outfile};
146             }
147              
148 3 100       12 if ( $opt->{mk} ) {
149 2         4 print {$out_fh} YAML::Syck::Dump($op_result_of);
  2         19  
150             }
151             else {
152 1         3 print {$out_fh} YAML::Syck::Dump( $op_result_of->{__single} );
  1         31  
153             }
154              
155 3         436 close $out_fh;
156             }
157              
158             1;