File Coverage

blib/lib/App/vl.pm
Criterion Covered Total %
statement 114 117 97.4
branch 27 30 90.0
condition 13 13 100.0
subroutine 18 20 90.0
pod 5 5 100.0
total 177 185 95.6


line stmt bran cond sub pod time code
1             package App::vl;
2 3     3   238445 use strict;
  3         25  
  3         90  
3 3     3   15 use warnings;
  3         5  
  3         88  
4 3     3   2367 use Getopt::Long qw/GetOptionsFromArray/;
  3         36741  
  3         16  
5 3     3   2095 use IO::Pager;
  3         32985  
  3         4595  
6              
7             our $VERSION = '0.01';
8              
9             sub new {
10 10     10 1 44595 my $class = shift;
11 10         28 my @argv = @_;
12              
13 10         28 bless {
14             _opt => $class->_parse_opt(@argv),
15             _labels => [],
16             _column_length_list => [],
17             }, $class;
18             }
19              
20             sub opt {
21 106     106 1 161 my ($self, $key) = @_;
22              
23 106         320 return $self->{_opt}{$key};
24             }
25              
26             sub labels {
27 32     32 1 58 my ($self, $value) = @_;
28              
29 32 100       52 if ($value) {
30 10         19 $self->{_labels} = $value;
31 10         14 return $self;
32             }
33             else {
34 22         65 return $self->{_labels};
35             }
36             }
37              
38             sub column_length_list {
39 19     19 1 30 my ($self, $value) = @_;
40              
41 19 100       31 if ($value) {
42 10         17 $self->{_column_length_list} = $value;
43 10         23 return $self;
44             }
45             else {
46 9         21 return $self->{_column_length_list};
47             }
48             }
49              
50             sub run {
51 10     10 1 21 my $self = shift;
52              
53 10         32 my $header = ;
54 10         18 chomp $header;
55              
56 10         30 $self->_parse_header($header);
57              
58 10         20 my $line_count = 0;
59              
60 10 50       17 my $io = $self->opt('no_pager') ? *STDOUT : new IO::Pager;
61 10         22 my $grep = $self->opt('grep');
62              
63 10         38 while (my $line = ) {
64 12         22 $line_count++;
65 12         18 chomp $line;
66 12 100 100     48 next if $grep && $line !~ m!\Q$grep\E!i;
67 11         19 $io->print($self->opt('line_char') x 10 . " $line_count " . $self->opt('line_char') x 20 . "\n");
68 11 50       474 next if $line eq '';
69 11 100       53 my $elements = $self->opt('ps')
70             ? $self->_parse_ps_line($line)
71             : $self->_parse_line($line);
72 11         22 $self->_show_elements($io, $elements);
73             }
74             }
75              
76             sub _parse_header {
77 10     10   24 my ($self, $header) = @_;
78              
79 10         21 my $one_space_table = $self->_is_one_space_table($header);
80 10 100       27 if (!$one_space_table) {
81 8         49 $header =~ s/([^\s])\s([^\s])/$1\\$2/g;
82             }
83              
84 10         19 my (@labels, @column_length_list);
85              
86 10         39 while ($header =~ s/(\s*([^\s]+)\s*)//) {
87 41         98 my ($full_label, $label) = ($1, $2);
88 41 100       78 $label =~ s/\\/ /g unless $one_space_table;
89 41         60 push @labels, $label;
90 41         145 push @column_length_list, length $full_label;
91             }
92              
93 10         26 $self->labels($self->_sort_label(\@labels));
94 10         22 $self->column_length_list(\@column_length_list);
95             }
96              
97             sub _is_one_space_table {
98 10     10   18 my ($self, $header) = @_;
99              
100 10         15 my @spaces;
101 10         59 while ($header =~ s/(\s+)//) {
102 41         171 push @spaces, $1;
103             }
104              
105 10         34 my $one_space = 0;
106 10         21 for my $space (@spaces) {
107 41 100       76 $one_space++ if length $space == 1;
108             }
109              
110 10 100 100     49 return 1 if $#spaces >= 3 && $#spaces / 2 <= $one_space; # roughly
111             }
112              
113             sub _sort_label {
114 10     10   17 my ($self, $labels) = @_;
115              
116 10         15 my $max = 0;
117 10         14 for my $label (@{$labels}) {
  10         17  
118 41         48 my $len = length($label);
119 41 100       84 $max = $len if $max < $len;
120             }
121              
122 10         11 for my $label (@{$labels}) {
  10         18  
123 41         95 $label = ' ' x ($max - length $label) . "$label" . $self->opt('separator');
124             }
125              
126 10         27 return $labels;
127             }
128              
129             sub _parse_ps_line {
130 2     2   6 my ($self, $line) = @_;
131              
132 2         20 $line =~ s/^\s+//g;
133 2         7 my @elements = split /\s+/, $line, $#{$self->labels} + 1;
  2         5  
134              
135 2         7 return \@elements;
136             }
137              
138             sub _parse_line {
139 9     9   20 my ($self, $line) = @_;
140              
141 9         18 my $column_length_list = $self->column_length_list;
142 9         15 my $limit = $#{$self->labels};
  9         15  
143              
144 9         11 my @elements;
145              
146 9         14 my $offset = 0;
147              
148 9         26 for my $i (0..$limit) {
149 29 100       62 my $element = $i != $limit ? substr $line, $offset, $column_length_list->[$i] : substr $line, $offset;
150 29         48 push @elements, $element;
151 29         48 $offset += $column_length_list->[$i];
152             }
153              
154 9         19 return \@elements;
155             }
156              
157             sub _show_elements {
158 11     11   34 my ($self, $io, $elements) = @_;
159              
160 11         29 my $label_filter_regexp = $self->_label_filter_regexp();
161 11         18 my $labels = $self->labels;
162              
163 11         14 my $col = 0;
164              
165 11         14 for my $element (@{$elements}) {
  11         21  
166 44 100 100     115 if (!$label_filter_regexp || $labels->[$col] =~ $label_filter_regexp) {
167 42         129 $element =~ s/^\s+//g;
168 42         102 $element =~ s/\s+$//g;
169 42         155 $io->print("$labels->[$col]$element\n");
170             }
171 44         962 $col++;
172             }
173             }
174              
175             sub _label_filter_regexp {
176 11     11   19 my ($self) = @_;
177              
178 11 100       19 return if !$self->opt('label');
179              
180 1         4 my $regexp = join '|', map { quotemeta $_ } split /\,/, $self->opt('label');
  1         5  
181              
182 1         7 $regexp = sprintf('(?:%s)', $regexp);
183              
184 1         13 return qr/$regexp/i;
185             }
186              
187             sub _parse_opt {
188 10     10   20 my ($class, @argv) = @_;
189              
190 10         17 my $opt = {};
191              
192             GetOptionsFromArray(
193             \@argv,
194             'no-pager' => \$opt->{no_pager},
195             'grep=s' => \$opt->{grep},
196             'label=s' => \$opt->{label},
197             'ps' => \$opt->{ps},
198             'separator=s' => \$opt->{separator},
199             'line-char=s' => \$opt->{line_char},
200             'h|help' => sub {
201 0     0   0 $class->_show_usage(1);
202             },
203             'v|version' => sub {
204 0     0   0 print "$0 $VERSION\n";
205 0         0 exit 1;
206             },
207 10 50       99 ) or $class->_show_usage(2);
208              
209 10   100     7418 $opt->{separator} ||= ': ';
210 10   100     40 $opt->{line_char} ||= '*';
211              
212 10         83 return $opt;
213             }
214              
215             sub _show_usage {
216 1     1   141 my ($class, $exitval) = @_;
217              
218 1         547 require Pod::Usage;
219 1         50015 Pod::Usage::pod2usage(-exitval => $exitval);
220             }
221              
222             1;
223              
224             __END__