line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Text::Table::Read::RelationOn::Tiny; |
2
|
|
|
|
|
|
|
|
3
|
9
|
|
|
9
|
|
523441
|
use 5.010_001; |
|
9
|
|
|
|
|
98
|
|
4
|
9
|
|
|
9
|
|
51
|
use strict; |
|
9
|
|
|
|
|
17
|
|
|
9
|
|
|
|
|
181
|
|
5
|
9
|
|
|
9
|
|
58
|
use warnings; |
|
9
|
|
|
|
|
44
|
|
|
9
|
|
|
|
|
298
|
|
6
|
9
|
|
|
9
|
|
3662
|
use autodie; |
|
9
|
|
|
|
|
120770
|
|
|
9
|
|
|
|
|
38
|
|
7
|
|
|
|
|
|
|
|
8
|
9
|
|
|
9
|
|
51999
|
use Carp; |
|
9
|
|
|
|
|
20
|
|
|
9
|
|
|
|
|
683
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
# The following must be on the same line to ensure that $VERSION is read |
11
|
|
|
|
|
|
|
# correctly by PAUSE and installer tools. See docu of 'version'. |
12
|
9
|
|
|
9
|
|
4203
|
use version 0.77; our $VERSION = version->declare("v2.2.4"); |
|
9
|
|
|
|
|
14878
|
|
|
9
|
|
|
|
|
57
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
sub new { |
16
|
68
|
|
|
68
|
1
|
40482
|
my $class = shift; |
17
|
68
|
50
|
|
|
|
186
|
$class = ref($class) if ref($class); |
18
|
68
|
100
|
|
|
|
410
|
croak("Odd number of arguments") if @_ % 2; |
19
|
67
|
|
|
|
|
175
|
my %args = @_; |
20
|
67
|
|
100
|
|
|
299
|
my $inc = delete $args{inc} // "X"; |
21
|
67
|
|
100
|
|
|
220
|
my $noinc = delete $args{noinc} // ""; |
22
|
67
|
|
|
|
|
129
|
my $set = delete $args{set}; |
23
|
67
|
|
|
|
|
107
|
my $eqs = delete $args{eqs}; |
24
|
67
|
|
|
|
|
114
|
my $ext = delete $args{ext}; |
25
|
67
|
|
|
|
|
121
|
my $elem_ids = delete $args{elem_ids}; |
26
|
67
|
100
|
|
|
|
235
|
croak(join(", ", sort(keys(%args))) . ": unexpected argument") if %args; |
27
|
66
|
100
|
|
|
|
271
|
croak("inc: must be a scalar") if ref($inc); |
28
|
65
|
100
|
|
|
|
252
|
croak("noinc: must be a scalar") if ref($noinc); |
29
|
64
|
|
|
|
|
420
|
s/^\s+// for ($inc, $noinc); |
30
|
64
|
|
|
|
|
223
|
s/\s+$// for ($inc, $noinc); |
31
|
64
|
100
|
|
|
|
232
|
croak("inc and noinc must be different") if $inc eq $noinc; |
32
|
63
|
100
|
100
|
|
|
366
|
croak("'|' is not allowed for inc or noinc") if $inc eq '|' || $noinc eq '|'; |
33
|
61
|
|
|
|
|
168
|
my $self = {inc => $inc, |
34
|
|
|
|
|
|
|
noinc => $noinc, |
35
|
|
|
|
|
|
|
}; |
36
|
61
|
100
|
|
|
|
137
|
if (defined($set)) { |
37
|
48
|
|
|
|
|
65
|
my %seen; |
38
|
48
|
100
|
|
|
|
218
|
croak("set: must be an array reference") if ref($set) ne 'ARRAY'; |
39
|
47
|
|
|
|
|
65
|
my $cnt = 1; |
40
|
47
|
|
|
|
|
90
|
foreach my $e (@$set) { |
41
|
152
|
100
|
|
|
|
229
|
if (ref($e)) { |
42
|
21
|
100
|
|
|
|
124
|
croak("set: entry $cnt: invalid") if ref($e) ne 'ARRAY'; |
43
|
20
|
100
|
|
|
|
162
|
croak("set: entry $cnt: array not allowed if eqs is specified") if $eqs; |
44
|
19
|
100
|
|
|
|
24
|
croak("set: entry $cnt: array entry must not be empty") if !@{$e}; |
|
19
|
|
|
|
|
198
|
|
45
|
17
|
|
|
|
|
29
|
foreach my $sub_e (@$e) { |
46
|
35
|
100
|
100
|
|
|
325
|
croak("set: entry $cnt: subarray contains invalid entry") |
47
|
|
|
|
|
|
|
if ref($sub_e) || !defined($sub_e); |
48
|
32
|
100
|
|
|
|
376
|
croak("set: '$sub_e': duplicate element") if exists($seen{$sub_e}); |
49
|
28
|
|
|
|
|
50
|
$seen{$sub_e} = undef; |
50
|
|
|
|
|
|
|
} |
51
|
|
|
|
|
|
|
} else { |
52
|
131
|
100
|
|
|
|
361
|
croak("set: entry $cnt: invalid") if !defined($e); |
53
|
130
|
100
|
|
|
|
317
|
croak("set: '$e': duplicate element") if exists($seen{$e}); |
54
|
129
|
|
|
|
|
201
|
$seen{$e} = undef; |
55
|
|
|
|
|
|
|
} |
56
|
139
|
|
|
|
|
191
|
++$cnt; |
57
|
|
|
|
|
|
|
} |
58
|
34
|
|
|
|
|
94
|
$self->{prespec} = 1; |
59
|
|
|
|
|
|
|
} else { |
60
|
13
|
100
|
|
|
|
108
|
croak("eqs: not allowed without argument 'set'") if defined($eqs); |
61
|
12
|
|
|
|
|
37
|
$self->{prespec} = ""; |
62
|
|
|
|
|
|
|
} |
63
|
46
|
100
|
|
|
|
118
|
if (defined($elem_ids)) { |
64
|
13
|
100
|
100
|
|
|
269
|
croak("elem_ids: not allowed without arguments 'set' and 'ext'") if !(defined($ext) && |
65
|
|
|
|
|
|
|
defined($set)); |
66
|
10
|
100
|
|
|
|
96
|
croak("elem_ids: must be a hash ref") if ref($elem_ids) ne 'HASH'; |
67
|
|
|
|
|
|
|
} |
68
|
42
|
|
|
|
|
104
|
my $elems; |
69
|
|
|
|
|
|
|
my $tabElems; # elems to be used in table --> indes in @elems |
70
|
42
|
|
|
|
|
0
|
my $eqIds; |
71
|
42
|
100
|
|
|
|
141
|
if ($ext) { |
|
|
100
|
|
|
|
|
|
72
|
12
|
100
|
|
|
|
25
|
if ($set) { |
73
|
11
|
|
|
|
|
22
|
foreach my $e (@$set) { |
74
|
42
|
100
|
|
|
|
144
|
croak("set: no subarray allowed if 'ext' is specified") if ref($e); |
75
|
|
|
|
|
|
|
} |
76
|
10
|
100
|
|
|
|
23
|
if ($elem_ids) { |
77
|
8
|
100
|
|
|
|
113
|
croak("elem_ids: wrong number of entries") if keys(%$elem_ids) != @$set; |
78
|
7
|
|
|
|
|
16
|
foreach my $e (@$set) { |
79
|
24
|
|
|
|
|
46
|
my $e_id = $elem_ids->{$e}; |
80
|
24
|
100
|
|
|
|
190
|
croak("elem_ids: '$e': missing value") if !defined($e_id); |
81
|
22
|
100
|
100
|
|
|
339
|
croak("elem_ids: '$e': entry has wrong value") if ($e_id !~ /^\d$/ || |
|
|
|
100
|
|
|
|
|
82
|
|
|
|
|
|
|
!defined($set->[$e_id]) || |
83
|
|
|
|
|
|
|
$set->[$e_id] ne $e); |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
} else { |
86
|
2
|
|
|
|
|
9
|
my $idx = 0; |
87
|
2
|
|
|
|
|
6
|
$elem_ids = {map {$_ => $idx++} @$set}; |
|
14
|
|
|
|
|
26
|
|
88
|
|
|
|
|
|
|
} |
89
|
4
|
|
|
|
|
8
|
$elems = $set; |
90
|
|
|
|
|
|
|
} else { |
91
|
1
|
|
|
|
|
74
|
croak("ext: not allowed without argument 'set'") |
92
|
|
|
|
|
|
|
} |
93
|
4
|
|
|
|
|
19
|
%$tabElems = %$elem_ids; |
94
|
|
|
|
|
|
|
} elsif (ref($set)) { |
95
|
21
|
|
|
|
|
48
|
my @elems; # elems |
96
|
|
|
|
|
|
|
my %ids; # indices in basic elems |
97
|
21
|
|
|
|
|
0
|
my @eqs_tmp; |
98
|
|
|
|
|
|
|
|
99
|
21
|
|
|
|
|
41
|
foreach my $entry (@$set) { |
100
|
75
|
100
|
|
|
|
115
|
if (ref($entry)) { |
101
|
5
|
|
|
|
|
10
|
push(@elems, $entry->[0]); |
102
|
5
|
|
|
|
|
9
|
$ids{$entry->[0]} = $#elems; |
103
|
5
|
|
|
|
|
11
|
for (my $j = 1; $j < @$entry; ++$j) { |
104
|
4
|
|
|
|
|
6
|
my $ent_j = $entry->[$j]; |
105
|
4
|
|
|
|
|
7
|
push(@elems, $ent_j); |
106
|
4
|
|
|
|
|
8
|
$ids{$ent_j} = $#elems; |
107
|
|
|
|
|
|
|
} |
108
|
5
|
100
|
|
|
|
14
|
push(@eqs_tmp, $entry) if @$entry > 1; |
109
|
|
|
|
|
|
|
} else { |
110
|
70
|
|
|
|
|
114
|
push(@elems, $entry); |
111
|
70
|
|
|
|
|
138
|
$ids{$entry} = $#elems; |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
} |
114
|
21
|
50
|
66
|
|
|
71
|
croak("Internal error") if (defined($eqs) && @eqs_tmp); # Should never happen. |
115
|
21
|
100
|
|
|
|
42
|
$eqs = \@eqs_tmp if @eqs_tmp; |
116
|
21
|
|
|
|
|
102
|
($elems, $elem_ids, $tabElems, $eqIds) = (\@elems, \%ids, {%ids}, {}); |
117
|
|
|
|
|
|
|
} |
118
|
34
|
100
|
|
|
|
126
|
if (defined($eqs)) { |
119
|
14
|
100
|
|
|
|
123
|
croak("eqs: must be an array ref") if ref($eqs) ne 'ARRAY'; |
120
|
13
|
|
|
|
|
22
|
my %eqIds; # idx => array of equivalent idxes |
121
|
|
|
|
|
|
|
my %seen; |
122
|
13
|
|
|
|
|
20
|
foreach my $eqArray (@{$eqs}) { |
|
13
|
|
|
|
|
27
|
|
123
|
28
|
100
|
|
|
|
138
|
croak("eqs: each entry must be an array ref") if ref($eqArray) ne 'ARRAY'; |
124
|
27
|
100
|
|
|
|
31
|
next if !@{$eqArray}; |
|
27
|
|
|
|
|
51
|
|
125
|
25
|
|
|
|
|
37
|
foreach my $entry (@{$eqArray}) { |
|
25
|
|
|
|
|
40
|
|
126
|
57
|
100
|
|
|
|
181
|
croak("eqs: subentry contains a non-scalar") if ref($entry); |
127
|
56
|
100
|
|
|
|
159
|
croak("eqs: subentry undefined") if !defined($entry); |
128
|
55
|
100
|
|
|
|
254
|
croak("eqs: '$entry': unknown element") if !exists($elem_ids->{$entry}); |
129
|
53
|
100
|
|
|
|
251
|
croak("eqs: '$entry': duplicate element") if exists($seen{$entry}); |
130
|
51
|
|
|
|
|
84
|
$seen{$entry} = undef; |
131
|
|
|
|
|
|
|
} |
132
|
19
|
100
|
|
|
|
28
|
next if @{$eqArray} == 1; |
|
19
|
|
|
|
|
39
|
|
133
|
14
|
|
|
|
|
21
|
my @tmp = @{$eqArray}; |
|
14
|
|
|
|
|
32
|
|
134
|
14
|
|
|
|
|
19
|
my @eqArray; |
135
|
14
|
|
|
|
|
41
|
$eqIds{$tabElems->{shift(@tmp)}} = \@eqArray; |
136
|
14
|
|
|
|
|
21
|
foreach my $e (@tmp) { |
137
|
27
|
|
|
|
|
66
|
push(@eqArray, delete $tabElems->{$e}); |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
} |
140
|
6
|
|
|
|
|
15
|
$eqIds = \%eqIds; |
141
|
|
|
|
|
|
|
} |
142
|
26
|
|
|
|
|
66
|
@{$self}{qw(elems elem_ids tab_elems eq_ids)} = ($elems, $elem_ids, $tabElems, $eqIds); |
|
26
|
|
|
|
|
87
|
|
143
|
26
|
|
|
|
|
106
|
return bless($self, $class); |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
# |
148
|
|
|
|
|
|
|
# $self->$_reset() - set (matrix elems elem_ids tab_elems eq_ids) to |
149
|
|
|
|
|
|
|
# empty structures |
150
|
|
|
|
|
|
|
# $self->$_reset(1) - set (matrix elems elem_ids tab_elems eq_ids) to |
151
|
|
|
|
|
|
|
# undef |
152
|
|
|
|
|
|
|
my $_reset = sub { |
153
|
|
|
|
|
|
|
@{$_[0]}{qw(matrix elems elem_ids tab_elems eq_ids)} = |
154
|
|
|
|
|
|
|
$_[1] ? ( {}, [], {}, {}, {}) : ((undef) x 5); |
155
|
|
|
|
|
|
|
}; |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
# just a function, not a method. |
159
|
|
|
|
|
|
|
sub _rule_pos_array_f { |
160
|
17
|
|
|
17
|
|
34
|
my ($str) = @_; |
161
|
17
|
|
|
|
|
20
|
my @rule_pos; |
162
|
17
|
|
|
|
|
33
|
my $idx = index($str, '|'); |
163
|
17
|
|
|
|
|
40
|
while($idx != -1) { |
164
|
84
|
|
|
|
|
117
|
push(@rule_pos, $idx); |
165
|
84
|
|
|
|
|
146
|
$idx = index($str, '|', $idx + 1); |
166
|
|
|
|
|
|
|
} |
167
|
17
|
|
|
|
|
50
|
return \@rule_pos; |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
# just a function, not a method. |
171
|
|
|
|
|
|
|
sub _int_array_cmp { |
172
|
9
|
|
|
9
|
|
22
|
my ($arr1, $arr2) = @_; |
173
|
9
|
100
|
|
|
|
195
|
return !1 if @$arr1 != @$arr2; |
174
|
7
|
|
|
|
|
22
|
for (my $i = 0; $i < @$arr1; ++$i) { |
175
|
36
|
100
|
|
|
|
211
|
return !1 if $arr1->[$i] != $arr2->[$i]; |
176
|
|
|
|
|
|
|
} |
177
|
6
|
|
|
|
|
16
|
return 1; |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
# just a function, not a method. |
181
|
|
|
|
|
|
|
sub _parse_header_f { |
182
|
67
|
|
|
67
|
|
155
|
my ($header, $pedantic) = @_; |
183
|
67
|
|
|
|
|
248
|
$header =~ s/\s+$//; |
184
|
67
|
|
|
|
|
119
|
my @rule_pos; |
185
|
67
|
100
|
|
|
|
151
|
if ($pedantic) { |
186
|
9
|
100
|
|
|
|
129
|
substr($header, -1, 1) eq '|' or croak("'$header': Wrong header format"); |
187
|
|
|
|
|
|
|
} |
188
|
66
|
100
|
|
|
|
428
|
$header =~ s/^\s*\|.*?\|\s*// or croak("'$header': Wrong header format"); |
189
|
65
|
100
|
|
|
|
385
|
my @elem_array = $header eq "|" ? ('') : split(/\s*\|\s*/, $header); |
190
|
65
|
100
|
|
|
|
171
|
return ([], {}) if $header eq ""; |
191
|
63
|
|
|
|
|
96
|
my $index = 0; |
192
|
63
|
|
|
|
|
98
|
my %elem_ids; |
193
|
63
|
|
|
|
|
122
|
foreach my $name (@elem_array) { |
194
|
183
|
100
|
|
|
|
496
|
croak("'$name': duplicate name in header") if exists($elem_ids{$name}); |
195
|
181
|
|
|
|
|
341
|
$elem_ids{$name} = $index++; |
196
|
|
|
|
|
|
|
} |
197
|
61
|
|
|
|
|
193
|
return (\@elem_array, \%elem_ids); |
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
my $_parse_row = sub { |
202
|
|
|
|
|
|
|
my $self = shift; |
203
|
|
|
|
|
|
|
my $row = shift; |
204
|
|
|
|
|
|
|
my ($inc, $noinc) = @{$self}{qw(inc noinc)}; |
205
|
|
|
|
|
|
|
$row =~ s/^\|\s*([^|]*?)\s*\|\s*// or croak("Wrong row format: '$row'"); |
206
|
|
|
|
|
|
|
my $rowElem = $1; |
207
|
|
|
|
|
|
|
my @rowContents; |
208
|
|
|
|
|
|
|
if ($row ne "") { |
209
|
|
|
|
|
|
|
$row =~ s/\s*\|\s*$//; |
210
|
|
|
|
|
|
|
my @entries = $row eq "" ? ("") : split(/\s*\|\s*/, $row, -1); |
211
|
|
|
|
|
|
|
foreach my $entry (@entries) { |
212
|
|
|
|
|
|
|
if ($entry eq $inc) { |
213
|
|
|
|
|
|
|
push(@rowContents, 1); |
214
|
|
|
|
|
|
|
} elsif ($entry eq $noinc) { |
215
|
|
|
|
|
|
|
push(@rowContents, ""); |
216
|
|
|
|
|
|
|
} else { |
217
|
|
|
|
|
|
|
croak("'$entry': unexpected entry"); |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
return ($rowElem, \@rowContents); |
222
|
|
|
|
|
|
|
}; |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
my $_parse_table = sub { |
226
|
|
|
|
|
|
|
my $self = shift; |
227
|
|
|
|
|
|
|
my ($lines, $allow_subset, $pedantic) = @_; |
228
|
|
|
|
|
|
|
my $index = 0; |
229
|
|
|
|
|
|
|
for (; $index < @$lines; ++$index) { # skip heading empty lines |
230
|
|
|
|
|
|
|
last if $lines->[$index] =~ /\S/; |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
if ($index == @$lines) { |
233
|
|
|
|
|
|
|
$self->$_reset(1); |
234
|
|
|
|
|
|
|
return; |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
my ($h_elems, $h_ids) = _parse_header_f($lines->[$index], $pedantic); |
237
|
|
|
|
|
|
|
my ($sep_line, $rule_pos); |
238
|
|
|
|
|
|
|
if ($pedantic) { |
239
|
|
|
|
|
|
|
($sep_line = $lines->[$index]) =~ s/\s+$//; |
240
|
|
|
|
|
|
|
$rule_pos = _rule_pos_array_f($sep_line); |
241
|
|
|
|
|
|
|
for (my $i = 0; $i < @$rule_pos - 1; ++$i) { |
242
|
|
|
|
|
|
|
my ($b, $e) = @{$rule_pos}[$i, $i + 1]; |
243
|
|
|
|
|
|
|
substr($sep_line, $b, 1, '+') if $i; |
244
|
|
|
|
|
|
|
my $d = $e - $b; |
245
|
|
|
|
|
|
|
next unless $d > 1; |
246
|
|
|
|
|
|
|
--$d; |
247
|
|
|
|
|
|
|
substr($sep_line, $b + 1, $d, '-' x $d); |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
my $elem_ids; |
251
|
|
|
|
|
|
|
my %rows; |
252
|
|
|
|
|
|
|
my @rowElems; # To keep oder of additional row elements, if any. |
253
|
|
|
|
|
|
|
for (++$index; $index < @$lines; ++$index) { |
254
|
|
|
|
|
|
|
(my $line = $lines->[$index]) =~ s/\s+$//; |
255
|
|
|
|
|
|
|
last if $line eq q{}; |
256
|
|
|
|
|
|
|
if ($pedantic) { |
257
|
|
|
|
|
|
|
$line =~ /\S/; |
258
|
|
|
|
|
|
|
$-[0] == $rule_pos->[0] or croak("Wrong indentation at line " . ($index + 1)); |
259
|
|
|
|
|
|
|
} |
260
|
|
|
|
|
|
|
if ($line =~ /^\s*\|-/) { |
261
|
|
|
|
|
|
|
if ($pedantic) { |
262
|
|
|
|
|
|
|
$line eq $sep_line or croak("Invalid row separator at line " . ($index + 1)); |
263
|
|
|
|
|
|
|
} |
264
|
|
|
|
|
|
|
next; |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
if ($pedantic) { |
267
|
|
|
|
|
|
|
_int_array_cmp(_rule_pos_array_f($line), $rule_pos) or |
268
|
|
|
|
|
|
|
croak("Wrong row format at line " . ($index + 1)); |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
$line =~ s/^\s*//; |
271
|
|
|
|
|
|
|
my ($rowElem, $rowContent) = $self->$_parse_row($line); |
272
|
|
|
|
|
|
|
croak("'$rowElem': duplicate element in first column") if exists($rows{$rowElem}); |
273
|
|
|
|
|
|
|
$rows{$rowElem} = $rowContent; |
274
|
|
|
|
|
|
|
push(@rowElems, $rowElem); |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
if ($self->{prespec}) { |
277
|
|
|
|
|
|
|
my $tab_elems = $self->{tab_elems}; |
278
|
|
|
|
|
|
|
$elem_ids = $self->{elem_ids}; |
279
|
|
|
|
|
|
|
foreach my $elem (keys(%{$h_ids})) { |
280
|
|
|
|
|
|
|
croak("'$elem': unknown element in table") if !exists($tab_elems->{$elem}); |
281
|
|
|
|
|
|
|
} |
282
|
|
|
|
|
|
|
foreach my $elem (keys(%rows)) { |
283
|
|
|
|
|
|
|
croak("'$elem': unknown element in table") if !exists($tab_elems->{$elem}); |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
if (!$allow_subset) { |
286
|
|
|
|
|
|
|
foreach my $elem (keys(%{$tab_elems})) { |
287
|
|
|
|
|
|
|
croak("'$elem': column missing for element") if !exists($h_ids->{$elem}); |
288
|
|
|
|
|
|
|
croak("'$elem': row missing for element" ) if !exists($rows{$elem}); |
289
|
|
|
|
|
|
|
} |
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
} else { |
292
|
|
|
|
|
|
|
if ($allow_subset) { |
293
|
|
|
|
|
|
|
foreach my $rowElem (@rowElems) { |
294
|
|
|
|
|
|
|
if (!exists($h_ids->{$rowElem})) { |
295
|
|
|
|
|
|
|
$h_ids->{$rowElem} = @{$h_elems}; |
296
|
|
|
|
|
|
|
push(@{$h_elems}, $rowElem); |
297
|
|
|
|
|
|
|
} |
298
|
|
|
|
|
|
|
} |
299
|
|
|
|
|
|
|
} else { |
300
|
|
|
|
|
|
|
croak("Number of elements in header does not match number of elemens in row") |
301
|
|
|
|
|
|
|
if keys(%{$h_ids}) != keys(%rows); |
302
|
|
|
|
|
|
|
foreach my $elem (keys(%{$h_ids})) { |
303
|
|
|
|
|
|
|
croak("'$elem': row missing for element") if !exists($rows{$elem}); |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
my %tmp = %{$h_ids}; |
307
|
|
|
|
|
|
|
@{$self}{qw(elems elem_ids tab_elems eq_ids)} = ($h_elems, $h_ids, \%tmp, {}); |
308
|
|
|
|
|
|
|
$elem_ids = $h_ids; |
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
my $eq_ids = $self->{eq_ids}; |
311
|
|
|
|
|
|
|
my %matrix; |
312
|
|
|
|
|
|
|
while (my ($rowElem, $rowContents) = each(%rows)) { |
313
|
|
|
|
|
|
|
my %new_row; |
314
|
|
|
|
|
|
|
for (my $i = 0; $i < @{$rowContents}; $i++) { |
315
|
|
|
|
|
|
|
if ($rowContents->[$i]) { |
316
|
|
|
|
|
|
|
my $e_id = $elem_ids->{$h_elems->[$i]}; |
317
|
|
|
|
|
|
|
$new_row{$e_id} = undef; |
318
|
|
|
|
|
|
|
if (exists($eq_ids->{$e_id})) { |
319
|
|
|
|
|
|
|
foreach my $eq_id (@{$eq_ids->{$e_id}}) { |
320
|
|
|
|
|
|
|
$new_row{$eq_id} = undef |
321
|
|
|
|
|
|
|
} |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
} |
324
|
|
|
|
|
|
|
} |
325
|
|
|
|
|
|
|
if (%new_row) { |
326
|
|
|
|
|
|
|
$matrix{$elem_ids->{$rowElem}} = \%new_row; |
327
|
|
|
|
|
|
|
if (exists($eq_ids->{$rowElem})) { |
328
|
|
|
|
|
|
|
foreach my $eq_id (@{$eq_ids->{$rowElem}}) { |
329
|
|
|
|
|
|
|
$matrix{$eq_id} = {%new_row}; |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
} |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
} |
334
|
|
|
|
|
|
|
$self->{matrix} = \%matrix; |
335
|
|
|
|
|
|
|
return; |
336
|
|
|
|
|
|
|
}; |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
sub get { |
340
|
79
|
|
|
79
|
1
|
23613
|
my $self = shift; |
341
|
79
|
100
|
|
|
|
364
|
croak("Odd number of arguments") if @_ % 2; |
342
|
78
|
|
|
|
|
231
|
my %args = @_; |
343
|
78
|
|
|
|
|
157
|
my $allow_subset = delete $args{allow_subset}; |
344
|
78
|
|
|
|
|
139
|
my $pedantic = delete $args{pedantic}; |
345
|
78
|
100
|
|
|
|
261
|
croak("Missing argument 'src'") if !@_; |
346
|
77
|
|
66
|
|
|
279
|
my $src = delete $args{src} // croak("Invalid value argument for 'src'"); |
347
|
76
|
100
|
|
|
|
312
|
croak(join(", ", sort(keys(%args))) . ": unexpected argument") if %args; |
348
|
74
|
|
|
|
|
109
|
my $inputArray; |
349
|
74
|
100
|
|
|
|
286
|
if (ref($src)) { |
|
|
100
|
|
|
|
|
|
350
|
39
|
100
|
|
|
|
165
|
croak("Invalid value argument for 'src'") if ref($src) ne 'ARRAY'; |
351
|
38
|
|
|
|
|
62
|
foreach my $e (@{$src}) { |
|
38
|
|
|
|
|
98
|
|
352
|
170
|
100
|
66
|
|
|
528
|
croak("src: each entry must be a defined scalar") if (ref($e) || !defined($e)); |
353
|
|
|
|
|
|
|
} |
354
|
37
|
|
|
|
|
73
|
$inputArray = $src; |
355
|
|
|
|
|
|
|
} elsif ($src !~ /\n/) { |
356
|
4
|
|
|
|
|
26
|
open(my $h, '<', $src); |
357
|
4
|
|
|
|
|
4007
|
$inputArray = [<$h>]; |
358
|
4
|
|
|
|
|
30
|
close($h); |
359
|
|
|
|
|
|
|
} else { |
360
|
31
|
|
|
|
|
197
|
$inputArray = [split(/\n/, $src)]; |
361
|
|
|
|
|
|
|
} |
362
|
72
|
100
|
|
|
|
1407
|
$self->$_reset() if !$self->{prespec}; |
363
|
72
|
|
|
|
|
263
|
$self->$_parse_table($inputArray, $allow_subset, $pedantic); |
364
|
43
|
100
|
|
|
|
169
|
return wantarray ? @{$self}{qw(matrix elems elem_ids)} : $self; |
|
20
|
|
|
|
|
136
|
|
365
|
|
|
|
|
|
|
} |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
|
368
|
3
|
100
|
|
3
|
1
|
1598
|
sub inc {croak("Unexpected argument(s)") if @_ > 1; $_[0]->{inc};} |
|
2
|
|
|
|
|
16
|
|
369
|
3
|
100
|
|
3
|
1
|
631
|
sub noinc {croak("Unexpected argument(s)") if @_ > 1; $_[0]->{noinc};} |
|
2
|
|
|
|
|
10
|
|
370
|
12
|
100
|
|
12
|
1
|
595
|
sub prespec {croak("Unexpected argument(s)") if @_ > 1; $_[0]->{prespec};} |
|
11
|
|
|
|
|
68
|
|
371
|
32
|
100
|
|
32
|
1
|
7728
|
sub elems {croak("Unexpected argument(s)") if @_ > 1; $_[0]->{elems};} |
|
31
|
|
|
|
|
163
|
|
372
|
40
|
100
|
|
40
|
1
|
673
|
sub elem_ids {croak("Unexpected argument(s)") if @_ > 1; $_[0]->{elem_ids};} |
|
39
|
|
|
|
|
144
|
|
373
|
29
|
50
|
|
29
|
1
|
11165
|
sub tab_elems {croak("Unexpected argument(s)") if @_ > 1; $_[0]->{tab_elems};} |
|
29
|
|
|
|
|
138
|
|
374
|
19
|
50
|
|
19
|
1
|
83
|
sub eq_ids {croak("Unexpected argument(s)") if @_ > 1; $_[0]->{eq_ids};} |
|
19
|
|
|
|
|
91
|
|
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
sub matrix { |
378
|
26
|
|
|
26
|
1
|
1342
|
my $self = shift; |
379
|
26
|
100
|
|
|
|
156
|
croak("Odd number of arguments") if @_ % 2; |
380
|
25
|
|
|
|
|
56
|
my %args = @_; |
381
|
25
|
|
|
|
|
54
|
my $bless = delete $args{bless}; |
382
|
25
|
100
|
|
|
|
126
|
croak("Unexpected argument(s)") if %args; |
383
|
24
|
100
|
|
|
|
76
|
return if !$self->{matrix}; |
384
|
22
|
100
|
|
|
|
72
|
bless($self->{matrix}, "Text::Table::Read::RelationOn::Tiny::_Relation_Matrix") if $bless; |
385
|
22
|
|
|
|
|
155
|
return $self->{matrix}; |
386
|
|
|
|
|
|
|
} |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
sub matrix_named { |
390
|
11
|
|
|
11
|
1
|
1895
|
my $self = shift; |
391
|
11
|
100
|
|
|
|
95
|
croak("Odd number of arguments") if @_ % 2; |
392
|
10
|
|
|
|
|
31
|
my %args = @_; |
393
|
10
|
|
|
|
|
23
|
my $bless = delete $args{bless}; |
394
|
10
|
100
|
|
|
|
85
|
croak("Unexpected argument(s)") if %args; |
395
|
|
|
|
|
|
|
|
396
|
9
|
|
|
|
|
25
|
my ($matrix, $elems) = @{$self}{qw(matrix elems)}; |
|
9
|
|
|
|
|
25
|
|
397
|
9
|
100
|
|
|
|
29
|
return if !$matrix; |
398
|
7
|
|
|
|
|
13
|
my $matrix_named = {}; |
399
|
7
|
100
|
|
|
|
29
|
bless($matrix_named, "Text::Table::Read::RelationOn::Tiny::_Relation_Matrix") if $bless; |
400
|
7
|
|
|
|
|
15
|
while (my ($rowElemIdx, $rowContents) = each(%{$matrix})) { |
|
25
|
|
|
|
|
81
|
|
401
|
18
|
|
|
|
|
28
|
$matrix_named->{$elems->[$rowElemIdx]} = {map {$elems->[$_] => undef} keys(%{$rowContents})}; |
|
77
|
|
|
|
|
182
|
|
|
18
|
|
|
|
|
37
|
|
402
|
|
|
|
|
|
|
} |
403
|
7
|
|
|
|
|
67
|
return $matrix_named; |
404
|
|
|
|
|
|
|
} |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
{ |
409
|
|
|
|
|
|
|
package Text::Table::Read::RelationOn::Tiny::_Relation_Matrix; |
410
|
|
|
|
|
|
|
|
411
|
4
|
|
66
|
4
|
|
1213
|
sub related { return exists($_[0]->{$_[1]}) && exists($_[0]->{$_[1]}->{$_[2]}); } |
412
|
|
|
|
|
|
|
} |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
1; # End of Text::Table::Read::RelationOn::Tiny |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
__END__ |