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 13     13   10688 use strict;
  13         29  
  13         452  
3 13     13   65 use warnings;
  13         29  
  13         373  
4 13     13   67 use autodie;
  13         29  
  13         89  
5              
6 13     13   70103 use App::RL -command;
  13         36  
  13         177  
7 13     13   5605 use App::RL::Common;
  13         36  
  13         408  
8              
9 13     13   67 use constant abstract => 'compare 2 chromosome runlists';
  13         29  
  13         14963  
10              
11             sub opt_spec {
12             return (
13 7     7 1 48 [ "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 46838 return "runlist compare [options] [more infiles]";
23             }
24              
25             sub description {
26 1     1 1 1011 my $desc;
27 1         4 $desc .= ucfirst(abstract) . ".\n";
28 1         3 return $desc;
29             }
30              
31             sub validate_args {
32 6     6 1 6879 my ( $self, $opt, $args ) = @_;
33              
34 6 100       13 if ( @{$args} < 2 ) {
  6         22  
35 2         5 my $message = "This command need two or more input files.\n\tIt found";
36 2         4 $message .= sprintf " [%s]", $_ for @{$args};
  2         10  
37 2         5 $message .= ".\n";
38 2         11 $self->usage_error($message);
39             }
40 4         8 for ( @{$args} ) {
  4         12  
41 7 50       226 next if lc $_ eq "stdin";
42 7 100       27 if ( !Path::Tiny::path($_)->is_file ) {
43 1         104 $self->usage_error("The input file [$_] doesn't exist.");
44             }
45             }
46              
47 3 50       154 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         8 $opt->{op} = 'intersect';
55             }
56             elsif ( $opt->{op} =~ /^xor/i ) {
57 1         3 $opt->{op} = 'xor';
58             }
59             else {
60 0         0 Carp::confess "[@{[$opt->{op}]}] invalid\n";
  0         0  
61             }
62              
63 3 50       13 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 19 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         7 my @names;
79 3 100       13 if ( $opt->{mk} ) {
80 2         11 my $yml = YAML::Syck::LoadFile( $args->[0] );
81 2         414 @names = sort keys %{$yml};
  2         14  
82              
83 2         7 for my $name (@names) {
84 10         429 $set_of->{$name} = App::RL::Common::runlist2set( $yml->{$name}, $opt->{remove} );
85 10         21 $chrs->insert( keys %{ $set_of->{$name} } );
  10         41  
86             }
87             }
88             else {
89 1         3 @names = ("__single");
90             $set_of->{__single}
91 1         7 = App::RL::Common::runlist2set( YAML::Syck::LoadFile( $args->[0] ), $opt->{remove} );
92 1         13 $chrs->insert( keys %{ $set_of->{__single} } );
  1         27  
93             }
94              
95             # file2 and more
96 3         266 my @set_singles;
97             {
98 3         6 my $argc = scalar @{$args};
  3         4  
  3         9  
99 3         10 for my $i ( 1 .. $argc - 1 ) {
100             my $s = App::RL::Common::runlist2set( YAML::Syck::LoadFile( $args->[$i] ),
101 3         12 $opt->{remove} );
102 3         15 $chrs->insert( keys %{$s} );
  3         16  
103 3         234 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         377 my $set_one = $set_of->{$name};
114              
115             # give empty set to non-existing chrs
116 11         22 for my $s ( $set_one, @set_singles ) {
117 22         112 for my $chr ( sort $chrs->members ) {
118 72 100       322 if ( !exists $s->{$chr} ) {
119 10         28 $s->{$chr} = App::RL::Common::new_set();
120             }
121             }
122             }
123              
124             # operate on each chr
125 11         26 for my $chr ( sort $chrs->members ) {
126 36         982 my $op = $opt->{op};
127 36         83 my $op_set = $set_one->{$chr}->copy;
128 36         1105 for my $s (@set_singles) {
129 36         104 $op_set = $op_set->$op( $s->{$chr} );
130             }
131 36         26643 $op_result_of->{$name}{$chr} = $op_set->runlist;
132             }
133             }
134              
135             #----------------------------#
136             # Output
137             #----------------------------#
138 3         128 my $out_fh;
139 3 50       18 if ( lc( $opt->{outfile} ) eq "stdout" ) {
140 3         12 $out_fh = *STDOUT{IO};
141             }
142             else {
143 0         0 open $out_fh, ">", $opt->{outfile};
144             }
145              
146 3 100       8 if ( $opt->{mk} ) {
147 2         5 print {$out_fh} YAML::Syck::Dump($op_result_of);
  2         15  
148             }
149             else {
150 1         2 print {$out_fh} YAML::Syck::Dump( $op_result_of->{__single} );
  1         27  
151             }
152              
153 3         367 close $out_fh;
154             }
155              
156             1;