File Coverage

blib/lib/App/RL/Command/compare.pm
Criterion Covered Total %
statement 88 94 93.6
branch 18 24 75.0
condition n/a
subroutine 11 11 100.0
pod 5 5 100.0
total 122 134 91.0


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