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 20     20   1369 use v5.14;
  20         58  
4 20     20   78 use warnings;
  20         30  
  20         829  
5 20     20   123 use Carp;
  20         91  
  20         1137  
6              
7 20     20   655 use Data::Dumper;
  20         7646  
  20         24123  
8              
9             sub new {
10 51     51 0 71 my $class = shift;
11 51         361 my $obj = bless {
12             LABELS => [],
13             COUNTS => {},
14             LISTS => [],
15             OPTION => { UNIQUE => 1 },
16             ATTR => {},
17             }, $class;
18              
19 51 50       183 $obj->option(@_) if @_;
20              
21 51 50       87 if (my $initial_label = $obj->option('START')) {
22 51         104 $obj->newlabel($initial_label);
23             }
24              
25 51         107 $obj;
26             }
27              
28 328     328 0 505 sub option { splice @_, 1, 0, 'OPTION' ; goto &__attr }
  328         501  
29 0     0 0 0 sub attr { splice @_, 1, 0, 'ATTR' ; goto &__attr }
  0         0  
30             sub __attr {
31 328     328   389 my $obj = shift;
32 328         340 my $attr_name = shift;
33              
34 328 50       441 return undef if @_ < 1;
35 328 100       960 return $obj->{$attr_name}->{+shift} if @_ == 1;
36              
37 51         108 my $hash = $obj->{$attr_name};
38 51         150 while (my($name, $value) = splice @_, 0, 2) {
39 51         181 $hash->{$name} = $value;
40             }
41              
42 51         87 $obj;
43             }
44              
45             sub exists {
46 92     92 0 103 my $obj = shift;
47 92         99 my $label = shift;
48 92         313 $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 113     113 0 119 my $obj = shift;
58 113         148 my $label = shift;
59 113 50       161 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 113         247 $obj->_createlabel($label);
66 113         123 $obj;
67             }
68              
69             sub _createlabel {
70 113     113   122 my $obj = shift;
71 113         127 my $label = shift;
72 113 50 33     151 if ($obj->option('UNIQUE') and $obj->{COUNTS}->{$label}) {
73 0         0 croak "Duplicated label: $label\n";
74             }
75 113         207 $obj->{COUNTS}->{$label}++;
76 113         126 push @{$obj->{LABELS}}, $label;
  113         212  
77 113         124 push @{$obj->{LISTS}}, [];
  113         154  
78 113         135 $obj;
79             }
80              
81             sub append {
82 335     335 0 360 my $obj = shift;
83 335         469 my($label, $line) = @_;
84 335 100 66     424 if ($obj->labels == 0 or $label ne $obj->lastlabel) {
85 62         111 $obj->newlabel($label);
86             }
87 335         346 push @{$obj->{LISTS}->[-1]}, $line;
  335         530  
88 335         503 $obj;
89             }
90              
91             sub labels {
92 488     488 0 466 my $obj = shift;
93 488 50       637 if (@_ == 0) {
94 488         446 @{$obj->{LABELS}};
  488         1053  
95             } else {
96 0         0 map { @{$obj->{LABELS}[$_]} } @_;
  0         0  
  0         0  
97             }
98             }
99              
100             sub lastlabel {
101 794     794 0 797 my $obj = shift;
102 794         2006 $obj->{LABELS}->[-1];
103             }
104              
105             sub lists {
106 31     31 0 35 my $obj = shift;
107 31 50       54 if (@_ == 0) {
108 31         33 @{$obj->{LISTS}};
  31         74  
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 153     153 0 168 my $obj = shift;
134 153         182 my $cond = shift;
135 153         352 my @labels = $obj->labels;
136 153         195 my @index = do {
137 153 50       340 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 113         220 grep { $labels[$_] =~ $cond } keys @labels;
  251         1112  
145             } else {
146 40         55 grep { $labels[$_] eq $cond } keys @labels;
  88         158  
147             }
148             };
149 153         176 @{$obj->{LISTS}}[ @index ];
  153         353  
150             }
151              
152             sub collect {
153 153     153 0 258 my $obj = shift;
154 153         289 my @list = map { @$_ } $obj->match(@_);
  113         298  
155 153 100       568 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;