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