File Coverage

blib/lib/App/sdif/LabelStack.pm
Criterion Covered Total %
statement 76 140 54.2
branch 16 36 44.4
condition 3 6 50.0
subroutine 16 25 64.0
pod 0 19 0.0
total 111 226 49.1


line stmt bran cond sub pod time code
1             package App::sdif::LabelStack;
2              
3 14     14   1872 use v5.14;
  14         54  
4 14     14   105 use warnings;
  14         31  
  14         878  
5 14     14   207 use Carp;
  14         41  
  14         1084  
6              
7 14     14   832 use Data::Dumper;
  14         17725  
  14         26141  
8              
9             sub new {
10 45     45 0 114 my $class = shift;
11 45         345 my $obj = bless {
12             LABELS => [],
13             COUNTS => {},
14             LISTS => [],
15             OPTION => { UNIQUE => 1 },
16             ATTR => {},
17             }, $class;
18              
19 45 50       263 $obj->option(@_) if @_;
20              
21 45 50       90 if (my $initial_label = $obj->option('START')) {
22 45         113 $obj->newlabel($initial_label);
23             }
24              
25 45         131 $obj;
26             }
27              
28 288     288 0 606 sub option { splice @_, 1, 0, 'OPTION' ; goto &__attr }
  288         628  
29 0     0 0 0 sub attr { splice @_, 1, 0, 'ATTR' ; goto &__attr }
  0         0  
30             sub __attr {
31 288     288   449 my $obj = shift;
32 288         472 my $attr_name = shift;
33              
34 288 50       550 return undef if @_ < 1;
35 288 100       1159 return $obj->{$attr_name}->{+shift} if @_ == 1;
36              
37 45         107 my $hash = $obj->{$attr_name};
38 45         182 while (my($name, $value) = splice @_, 0, 2) {
39 45         216 $hash->{$name} = $value;
40             }
41              
42 45         109 $obj;
43             }
44              
45             sub exists {
46 84     84 0 150 my $obj = shift;
47 84         120 my $label = shift;
48 84         352 $obj->{COUNTS}->{$label};
49             }
50              
51             sub count {
52 0     0 0 0 my $obj = shift;
53 0         0 scalar @{$obj->{LISTS}};
  0         0  
54             }
55              
56             sub newlabel {
57 99     99 0 133 my $obj = shift;
58 99         168 my $label = shift;
59 99 50       219 if (my $order = $obj->option('ORDER')) {
60 0         0 for my $l (@$order) {
61 0 0       0 last if $l eq $label;
62 0 0       0 $obj->exists($l) or $obj->_createlabel($l);
63             }
64             }
65 99         263 $obj->_createlabel($label);
66 99         138 $obj;
67             }
68              
69             sub _createlabel {
70 99     99   139 my $obj = shift;
71 99         145 my $label = shift;
72 99 50 33     173 if ($obj->option('UNIQUE') and $obj->{COUNTS}->{$label}) {
73 0         0 croak "Duplicated label: $label\n";
74             }
75 99         296 $obj->{COUNTS}->{$label}++;
76 99         147 push @{$obj->{LABELS}}, $label;
  99         276  
77 99         140 push @{$obj->{LISTS}}, [];
  99         224  
78 99         158 $obj;
79             }
80              
81             sub append {
82 231     231 0 372 my $obj = shift;
83 231         437 my($label, $line) = @_;
84 231 100 66     445 if ($obj->labels == 0 or $label ne $obj->lastlabel) {
85 54         116 $obj->newlabel($label);
86             }
87 231         364 push @{$obj->{LISTS}->[-1]}, $line;
  231         560  
88 231         455 $obj;
89             }
90              
91             sub labels {
92 366     366 0 520 my $obj = shift;
93 366 50       1485 if (@_ == 0) {
94 366         509 @{$obj->{LABELS}};
  366         1225  
95             } else {
96 0         0 map { @{$obj->{LABELS}[$_]} } @_;
  0         0  
  0         0  
97             }
98             }
99              
100             sub lastlabel {
101 570     570 0 857 my $obj = shift;
102 570         2242 $obj->{LABELS}->[-1];
103             }
104              
105             sub lists {
106 30     30 0 40 my $obj = shift;
107 30 50       56 if (@_ == 0) {
108 30         39 @{$obj->{LISTS}};
  30         82  
109             } else {
110 0         0 map { @{$obj->{LISTS}[$_]} } @_;
  0         0  
  0         0  
111             }
112             }
113              
114             sub blocks {
115 0     0 0 0 my $obj = shift;
116 0         0 map { join '', @$_ } $obj->lists;
  0         0  
117             }
118              
119             sub listpair {
120 0     0 0 0 my $obj = shift;
121 0         0 my @labels = $obj->labels;
122 0         0 map { $labels[$_] => $obj->{LISTS}[$_] } keys @labels;
  0         0  
123             }
124              
125             sub blockpair {
126 0     0 0 0 my $obj = shift;
127 0         0 my @labels = $obj->labels;
128 0         0 my @blocks = $obj->blocks;
129 0         0 map { $labels[$_] => $blocks[$_] } keys @labels;
  0         0  
130             }
131              
132             sub match {
133 135     135 0 205 my $obj = shift;
134 135         211 my $cond = shift;
135 135         331 my @labels = $obj->labels;
136 135         194 my @index = do {
137 135 50       398 if (ref($cond) eq 'CODE') {
    100          
138             grep {
139 0         0 local $_ = $labels[$_];
  0         0  
140 0         0 $cond->();
141             }
142             keys @labels;
143             } elsif (ref $cond eq 'Regexp') {
144 105         247 grep { $labels[$_] =~ $cond } keys @labels;
  231         1311  
145             } else {
146 30         64 grep { $labels[$_] eq $cond } keys @labels;
  66         174  
147             }
148             };
149 135         235 @{$obj->{LISTS}}[ @index ];
  135         436  
150             }
151              
152             sub collect {
153 135     135 0 303 my $obj = shift;
154 135         309 my @list = map { @$_ } $obj->match(@_);
  99         344  
155 135 100       638 wantarray ? @list : join '', @list;
156             }
157              
158             sub push {
159 0     0 0   my $obj = CORE::shift;
160 0 0         croak "Invalid argument." if @_ % 2;
161 0           while (my($label, $data) = splice @_, 0, 2) {
162 0           CORE::push @{$obj->{LABELS}}, $label;
  0            
163 0           CORE::push @{$obj->{LISTS}}, $data;
  0            
164 0           $obj->{COUNTS}{$label}++;
165             }
166 0           $obj;
167             }
168              
169             sub pop {
170 0     0 0   my $obj = CORE::shift;
171 0 0         return () if $obj->count == 0;
172 0           my $label = CORE::pop @{$obj->{LABELS}};
  0            
173 0           my $entry = CORE::pop @{$obj->{LISTS}};
  0            
174 0           $obj->{COUNTS}{$label}--;
175 0           ($label, $entry);
176             }
177              
178             sub unshift {
179 0     0 0   my $obj = CORE::shift;
180 0 0         croak "Invalid argument." if @_ % 2;
181 0           while (my($label, $data) = splice @_, 0, 2) {
182 0           CORE::unshift @{$obj->{LABELS}}, $label;
  0            
183 0           CORE::unshift @{$obj->{LISTS}}, $data;
  0            
184 0           $obj->{COUNTS}{$label}++;
185             }
186 0           $obj;
187             }
188              
189             sub shift {
190 0     0 0   my $obj = CORE::shift;
191 0 0         return () if $obj->count == 0;
192 0           my $label = CORE::shift @{$obj->{LABELS}};
  0            
193 0           my $entry = CORE::shift @{$obj->{LISTS}};
  0            
194 0           $obj->{COUNTS}{$label}--;
195 0           ($label, $entry);
196             }
197              
198             1;