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   1316 use v5.14;
  20         57  
4 20     20   74 use warnings;
  20         38  
  20         885  
5 20     20   141 use Carp;
  20         78  
  20         1088  
6              
7 20     20   581 use Data::Dumper;
  20         6017  
  20         22835  
8              
9             sub new {
10 51     51 0 156 my $class = shift;
11 51         400 my $obj = bless {
12             LABELS => [],
13             COUNTS => {},
14             LISTS => [],
15             OPTION => { UNIQUE => 1 },
16             ATTR => {},
17             }, $class;
18              
19 51 50       226 $obj->option(@_) if @_;
20              
21 51 50       96 if (my $initial_label = $obj->option('START')) {
22 51         147 $obj->newlabel($initial_label);
23             }
24              
25 51         173 $obj;
26             }
27              
28 328     328 0 659 sub option { splice @_, 1, 0, 'OPTION' ; goto &__attr }
  328         672  
29 0     0 0 0 sub attr { splice @_, 1, 0, 'ATTR' ; goto &__attr }
  0         0  
30             sub __attr {
31 328     328   410 my $obj = shift;
32 328         398 my $attr_name = shift;
33              
34 328 50       639 return undef if @_ < 1;
35 328 100       1280 return $obj->{$attr_name}->{+shift} if @_ == 1;
36              
37 51         152 my $hash = $obj->{$attr_name};
38 51         187 while (my($name, $value) = splice @_, 0, 2) {
39 51         204 $hash->{$name} = $value;
40             }
41              
42 51         95 $obj;
43             }
44              
45             sub exists {
46 92     92 0 125 my $obj = shift;
47 92         127 my $label = shift;
48 92         316 $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 144 my $obj = shift;
58 113         154 my $label = shift;
59 113 50       225 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         302 $obj->_createlabel($label);
66 113         155 $obj;
67             }
68              
69             sub _createlabel {
70 113     113   157 my $obj = shift;
71 113         156 my $label = shift;
72 113 50 33     184 if ($obj->option('UNIQUE') and $obj->{COUNTS}->{$label}) {
73 0         0 croak "Duplicated label: $label\n";
74             }
75 113         275 $obj->{COUNTS}->{$label}++;
76 113         163 push @{$obj->{LABELS}}, $label;
  113         232  
77 113         145 push @{$obj->{LISTS}}, [];
  113         215  
78 113         164 $obj;
79             }
80              
81             sub append {
82 335     335 0 363 my $obj = shift;
83 335         557 my($label, $line) = @_;
84 335 100 66     531 if ($obj->labels == 0 or $label ne $obj->lastlabel) {
85 62         148 $obj->newlabel($label);
86             }
87 335         448 push @{$obj->{LISTS}->[-1]}, $line;
  335         579  
88 335         490 $obj;
89             }
90              
91             sub labels {
92 488     488 0 610 my $obj = shift;
93 488 50       846 if (@_ == 0) {
94 488         511 @{$obj->{LABELS}};
  488         1311  
95             } else {
96 0         0 map { @{$obj->{LABELS}[$_]} } @_;
  0         0  
  0         0  
97             }
98             }
99              
100             sub lastlabel {
101 794     794 0 965 my $obj = shift;
102 794         2518 $obj->{LABELS}->[-1];
103             }
104              
105             sub lists {
106 31     31 0 36 my $obj = shift;
107 31 50       52 if (@_ == 0) {
108 31         35 @{$obj->{LISTS}};
  31         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 153     153 0 181 my $obj = shift;
134 153         236 my $cond = shift;
135 153         304 my @labels = $obj->labels;
136 153         197 my @index = do {
137 153 50       396 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         227 grep { $labels[$_] =~ $cond } keys @labels;
  251         1253  
145             } else {
146 40         96 grep { $labels[$_] eq $cond } keys @labels;
  88         170  
147             }
148             };
149 153         209 @{$obj->{LISTS}}[ @index ];
  153         404  
150             }
151              
152             sub collect {
153 153     153 0 232 my $obj = shift;
154 153         381 my @list = map { @$_ } $obj->match(@_);
  113         316  
155 153 100       640 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;