line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Test::Inline::Script; |
2
|
|
|
|
|
|
|
# ABSTRACT: Generate the test file for a single source file |
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
#pod =pod |
5
|
|
|
|
|
|
|
#pod |
6
|
|
|
|
|
|
|
#pod =head1 DESCRIPTION |
7
|
|
|
|
|
|
|
#pod |
8
|
|
|
|
|
|
|
#pod This class is where the heavy lifting happens to actually generating a |
9
|
|
|
|
|
|
|
#pod test file takes place. Given a source filename, this modules will load |
10
|
|
|
|
|
|
|
#pod it, parse out the relavent bits, put them into order based on the tags, |
11
|
|
|
|
|
|
|
#pod and then merge them into a test file. |
12
|
|
|
|
|
|
|
#pod |
13
|
|
|
|
|
|
|
#pod =head1 METHODS |
14
|
|
|
|
|
|
|
#pod |
15
|
|
|
|
|
|
|
#pod =cut |
16
|
|
|
|
|
|
|
|
17
|
12
|
|
|
12
|
|
93
|
use strict; |
|
12
|
|
|
|
|
23
|
|
|
12
|
|
|
|
|
410
|
|
18
|
12
|
|
|
12
|
|
79
|
use List::Util (); |
|
12
|
|
|
|
|
26
|
|
|
12
|
|
|
|
|
264
|
|
19
|
12
|
|
|
12
|
|
61
|
use Params::Util qw{_ARRAY _INSTANCE}; |
|
12
|
|
|
|
|
23
|
|
|
12
|
|
|
|
|
742
|
|
20
|
12
|
|
|
12
|
|
85
|
use Algorithm::Dependency::Item (); |
|
12
|
|
|
|
|
23
|
|
|
12
|
|
|
|
|
190
|
|
21
|
12
|
|
|
12
|
|
52
|
use Algorithm::Dependency::Source (); |
|
12
|
|
|
|
|
22
|
|
|
12
|
|
|
|
|
241
|
|
22
|
12
|
|
|
12
|
|
5977
|
use Algorithm::Dependency::Ordered (); |
|
12
|
|
|
|
|
5345
|
|
|
12
|
|
|
|
|
537
|
|
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
use overload 'bool' => sub () { 1 }, |
25
|
12
|
|
|
12
|
|
119
|
'""' => 'filename'; |
|
12
|
|
|
|
|
25
|
|
|
12
|
|
|
|
|
81
|
|
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
our $VERSION = '2.214'; |
28
|
|
|
|
|
|
|
our @ISA = qw{ |
29
|
|
|
|
|
|
|
Algorithm::Dependency::Source |
30
|
|
|
|
|
|
|
Algorithm::Dependency::Item |
31
|
|
|
|
|
|
|
}; |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
# Special case, for when doing unit tests ONLY. |
34
|
|
|
|
|
|
|
# Don't throw the missing files warning. |
35
|
12
|
|
|
12
|
|
1340
|
use vars qw{$NO_MISSING_DEPENDENCIES_WARNING}; |
|
12
|
|
|
|
|
28
|
|
|
12
|
|
|
|
|
555
|
|
36
|
|
|
|
|
|
|
BEGIN { |
37
|
12
|
|
|
12
|
|
18258
|
$NO_MISSING_DEPENDENCIES_WARNING = ''; |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
##################################################################### |
45
|
|
|
|
|
|
|
# Constructor and Accessors |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
#pod =pod |
48
|
|
|
|
|
|
|
#pod |
49
|
|
|
|
|
|
|
#pod =head2 new |
50
|
|
|
|
|
|
|
#pod |
51
|
|
|
|
|
|
|
#pod my $File = Test::Inline::Script->new( $class, \@sections, $check_count ); |
52
|
|
|
|
|
|
|
#pod |
53
|
|
|
|
|
|
|
#pod The C constructor takes a class name, set of Section objects and |
54
|
|
|
|
|
|
|
#pod an optional C flag. |
55
|
|
|
|
|
|
|
#pod |
56
|
|
|
|
|
|
|
#pod Returns a Test::Inline::Script object on success. |
57
|
|
|
|
|
|
|
#pod Returns C on error. |
58
|
|
|
|
|
|
|
#pod |
59
|
|
|
|
|
|
|
#pod =cut |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
sub new { |
62
|
20
|
|
|
20
|
1
|
45
|
my $class = shift; |
63
|
20
|
50
|
|
|
|
54
|
my $_class = defined $_[0] ? shift : return undef; |
64
|
20
|
50
|
|
|
|
104
|
my $Sections = _ARRAY(shift) or return undef; |
65
|
20
|
|
100
|
|
|
75
|
my $check_count = shift || 0; |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
# Create the object |
68
|
|
|
|
|
|
|
my $self = bless { |
69
|
|
|
|
|
|
|
class => $_class, |
70
|
49
|
|
|
|
|
153
|
setup => [ grep { $_->setup } @$Sections ], |
71
|
20
|
|
|
|
|
54
|
sections => [ grep { ! $_->setup } @$Sections ], |
|
49
|
|
|
|
|
101
|
|
72
|
|
|
|
|
|
|
filename => lc "$_class.t", |
73
|
|
|
|
|
|
|
check_count => $check_count, |
74
|
|
|
|
|
|
|
# tests => undef, |
75
|
|
|
|
|
|
|
}, $class; |
76
|
20
|
|
|
|
|
460
|
$self->{filename} =~ s/::/_/g; |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
# Verify the uniqueness of the names |
79
|
20
|
50
|
|
|
|
77
|
$self->_duplicate_names and return undef; |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
# Warn if we have missing dependencies |
82
|
20
|
|
|
|
|
128
|
my $missing = $self->missing_dependencies; |
83
|
20
|
100
|
|
|
|
123
|
if ( $missing ) { |
84
|
1
|
|
|
|
|
3
|
foreach ( @$missing ) { |
85
|
1
|
50
|
|
|
|
4
|
next if $NO_MISSING_DEPENDENCIES_WARNING; |
86
|
0
|
|
|
|
|
0
|
print "Warning: Missing dependency '$_' in $self->{class}\n"; |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
# Quickly predetermine if there will be an unknown number |
91
|
|
|
|
|
|
|
# of unit tests in the file |
92
|
20
|
|
|
|
|
44
|
my $unknown = grep { ! defined $_->tests } @$Sections; |
|
49
|
|
|
|
|
104
|
|
93
|
20
|
50
|
66
|
|
|
68
|
unless ( $unknown or grep { $_->tests } @$Sections ) { |
|
27
|
|
|
|
|
52
|
|
94
|
0
|
|
|
|
|
0
|
$unknown = 1; |
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
# Flag all sections that need count checking in advance |
98
|
20
|
100
|
|
|
|
69
|
if ( $check_count ) { |
99
|
19
|
|
|
|
|
50
|
foreach my $Section ( @$Sections ) { |
100
|
44
|
100
|
|
|
|
118
|
next unless defined $Section->tests; |
101
|
34
|
100
|
100
|
|
|
136
|
next unless $unknown or $check_count > 1; |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
# Each count check is itself a test, so |
104
|
|
|
|
|
|
|
# increment the number of tests for the section |
105
|
|
|
|
|
|
|
# when we enable the check flag. |
106
|
12
|
|
|
|
|
21
|
$Section->{check_count} = 1; |
107
|
12
|
|
|
|
|
20
|
$Section->{tests}++; |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
|
111
|
20
|
|
|
|
|
134
|
$self; |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
#pod =pod |
115
|
|
|
|
|
|
|
#pod |
116
|
|
|
|
|
|
|
#pod =head2 class |
117
|
|
|
|
|
|
|
#pod |
118
|
|
|
|
|
|
|
#pod Returns the class that the test file will test |
119
|
|
|
|
|
|
|
#pod |
120
|
|
|
|
|
|
|
#pod =head2 filename |
121
|
|
|
|
|
|
|
#pod |
122
|
|
|
|
|
|
|
#pod my $filename = $File->filename; |
123
|
|
|
|
|
|
|
#pod |
124
|
|
|
|
|
|
|
#pod The C method returns the name of the output file that the tests |
125
|
|
|
|
|
|
|
#pod should be written to. For example, the class C would have the |
126
|
|
|
|
|
|
|
#pod filename value C. |
127
|
|
|
|
|
|
|
#pod |
128
|
|
|
|
|
|
|
#pod =head2 config |
129
|
|
|
|
|
|
|
#pod |
130
|
|
|
|
|
|
|
#pod my $config = $File->config; |
131
|
|
|
|
|
|
|
#pod |
132
|
|
|
|
|
|
|
#pod The C method returns the config object for the file, assuming that |
133
|
|
|
|
|
|
|
#pod it has one. If more than one are found, the first will be used, and any |
134
|
|
|
|
|
|
|
#pod additional config sections discarded. |
135
|
|
|
|
|
|
|
#pod |
136
|
|
|
|
|
|
|
#pod Returns a L object on success, or false if the |
137
|
|
|
|
|
|
|
#pod file does not contain a config section. |
138
|
|
|
|
|
|
|
#pod |
139
|
|
|
|
|
|
|
#pod =head2 setup |
140
|
|
|
|
|
|
|
#pod |
141
|
|
|
|
|
|
|
#pod my @setup = $File->setup; |
142
|
|
|
|
|
|
|
#pod |
143
|
|
|
|
|
|
|
#pod The C method returns the setup sections from the file, in the same |
144
|
|
|
|
|
|
|
#pod order as in the file. |
145
|
|
|
|
|
|
|
#pod |
146
|
|
|
|
|
|
|
#pod Returns a list of setup L objects, the null |
147
|
|
|
|
|
|
|
#pod array C<()> if the file does not contain any setup objects. |
148
|
|
|
|
|
|
|
#pod |
149
|
|
|
|
|
|
|
#pod =head2 sections |
150
|
|
|
|
|
|
|
#pod |
151
|
|
|
|
|
|
|
#pod my @sections = $File->sections; |
152
|
|
|
|
|
|
|
#pod |
153
|
|
|
|
|
|
|
#pod The C method returns all normal sections from the file, in the |
154
|
|
|
|
|
|
|
#pod same order as in the file. This may not be the order they will be written |
155
|
|
|
|
|
|
|
#pod to the test file, for that you should see the C method. |
156
|
|
|
|
|
|
|
#pod |
157
|
|
|
|
|
|
|
#pod Returns a list of L objects, or the null array |
158
|
|
|
|
|
|
|
#pod C<()> if the file does not contain any non-setup sections. |
159
|
|
|
|
|
|
|
#pod |
160
|
|
|
|
|
|
|
#pod =cut |
161
|
|
|
|
|
|
|
|
162
|
2
|
|
|
2
|
1
|
518
|
sub class { $_[0]->{class} } |
163
|
42
|
|
|
42
|
1
|
2588
|
sub filename { $_[0]->{filename} } |
164
|
0
|
0
|
|
0
|
1
|
0
|
sub config { $_[0]->{config} || '' } |
165
|
65
|
|
|
65
|
1
|
89
|
sub setup { @{$_[0]->{setup}} } |
|
65
|
|
|
|
|
162
|
|
166
|
243
|
|
|
243
|
1
|
334
|
sub sections { @{$_[0]->{sections}} } |
|
243
|
|
|
|
|
637
|
|
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
##################################################################### |
173
|
|
|
|
|
|
|
# Main Methods |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
#pod =pod |
176
|
|
|
|
|
|
|
#pod |
177
|
|
|
|
|
|
|
#pod =head2 sorted |
178
|
|
|
|
|
|
|
#pod |
179
|
|
|
|
|
|
|
#pod The C method returns all normal sections from the file, in an order |
180
|
|
|
|
|
|
|
#pod that satisfies any dependencies in the sections. |
181
|
|
|
|
|
|
|
#pod |
182
|
|
|
|
|
|
|
#pod Returns a reference to an array of L objects, |
183
|
|
|
|
|
|
|
#pod C<0> if the file does not contain any non-setup sections, or C on |
184
|
|
|
|
|
|
|
#pod error. |
185
|
|
|
|
|
|
|
#pod |
186
|
|
|
|
|
|
|
#pod =cut |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
sub sorted { |
189
|
18
|
|
|
18
|
1
|
40
|
my $self = shift; |
190
|
18
|
50
|
|
|
|
79
|
return $self->{sorted} if $self->{sorted}; |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
# Handle the simple case there there are no dependencies, |
193
|
|
|
|
|
|
|
# so we don't have to load the dependency algorithm code. |
194
|
18
|
100
|
|
|
|
88
|
unless ( map { $_->depends } $self->sections ) { |
|
37
|
|
|
|
|
137
|
|
195
|
12
|
|
|
|
|
39
|
return $self->{sorted} = [ $self->setup, $self->sections ]; |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
# Create the dependency algorithm object |
199
|
6
|
50
|
|
|
|
99
|
my $Algorithm = Algorithm::Dependency::Ordered->new( |
200
|
|
|
|
|
|
|
source => $self, |
201
|
|
|
|
|
|
|
ignore_orphans => 1, # Be lenient to non-existant dependencies |
202
|
|
|
|
|
|
|
) or return undef; |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
# Pull the schedule from the algorithm. If we get an error back, it |
205
|
|
|
|
|
|
|
# should be because there is a circular dependency. |
206
|
6
|
|
|
|
|
218
|
my $schedule = $Algorithm->schedule_all; |
207
|
6
|
50
|
|
|
|
118
|
unless ( $schedule ) { |
208
|
0
|
|
|
|
|
0
|
warn " (Failed to build $self->{class} test schedule) "; |
209
|
0
|
|
|
|
|
0
|
return undef; |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
# Index the sections by name |
213
|
6
|
|
|
|
|
20
|
my %hash = map { $_->name => $_ } grep { $_->name } $self->sections; |
|
18
|
|
|
|
|
36
|
|
|
24
|
|
|
|
|
51
|
|
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
# Merge together the setup, schedule, and anonymous parts into a |
216
|
|
|
|
|
|
|
# single sorted list. |
217
|
|
|
|
|
|
|
my @sorted = ( |
218
|
|
|
|
|
|
|
$self->setup, |
219
|
18
|
|
|
|
|
37
|
( map { $hash{$_} } @$schedule ), |
220
|
6
|
|
|
|
|
35
|
( grep { $_->anonymous } $self->sections ) |
|
24
|
|
|
|
|
51
|
|
221
|
|
|
|
|
|
|
); |
222
|
|
|
|
|
|
|
|
223
|
6
|
|
|
|
|
53
|
$self->{sorted} = \@sorted; |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
#pod =pod |
227
|
|
|
|
|
|
|
#pod |
228
|
|
|
|
|
|
|
#pod =head2 tests |
229
|
|
|
|
|
|
|
#pod |
230
|
|
|
|
|
|
|
#pod If the number of tests for all of the sections within the file are known, |
231
|
|
|
|
|
|
|
#pod then the number of tests for the entire file can also be determined. |
232
|
|
|
|
|
|
|
#pod |
233
|
|
|
|
|
|
|
#pod The C method determines if the number of tests can be known, and |
234
|
|
|
|
|
|
|
#pod if so, calculates and returns the number of tests. Returns false if the |
235
|
|
|
|
|
|
|
#pod number of tests is not known. |
236
|
|
|
|
|
|
|
#pod |
237
|
|
|
|
|
|
|
#pod =cut |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
sub tests { |
240
|
22
|
|
|
22
|
1
|
44
|
my $self = shift; |
241
|
22
|
100
|
|
|
|
60
|
return $self->{tests} if exists $self->{tests}; |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
# Add up the tests |
244
|
19
|
|
|
|
|
32
|
my $total = 0; |
245
|
19
|
|
|
|
|
50
|
foreach my $Section ( $self->setup, $self->sections ) { |
246
|
|
|
|
|
|
|
# Return undef if section has an unknown number of tests |
247
|
37
|
100
|
|
|
|
93
|
return undef unless defined $Section->tests; |
248
|
28
|
|
|
|
|
77
|
$total += $Section->tests; |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
# If the total is zero, it's probably screwed, go with "unknown" |
252
|
10
|
|
50
|
|
|
46
|
$self->{tests} = $total || undef; |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
#pod =pod |
256
|
|
|
|
|
|
|
#pod |
257
|
|
|
|
|
|
|
#pod =head2 merged_content |
258
|
|
|
|
|
|
|
#pod |
259
|
|
|
|
|
|
|
#pod The C method generates and returns the merged contents of all |
260
|
|
|
|
|
|
|
#pod the sections in the file, including the setup sections at the beginning. The |
261
|
|
|
|
|
|
|
#pod method does not return the entire file, merely the part contained in the |
262
|
|
|
|
|
|
|
#pod sections. For the full file contents, see the C method. |
263
|
|
|
|
|
|
|
#pod |
264
|
|
|
|
|
|
|
#pod Returns a string containing the merged section content on success, false |
265
|
|
|
|
|
|
|
#pod if there is no content, despite the existance of sections ( which would |
266
|
|
|
|
|
|
|
#pod have been empty ), or C on error. |
267
|
|
|
|
|
|
|
#pod |
268
|
|
|
|
|
|
|
#pod =cut |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
sub merged_content { |
271
|
22
|
|
|
22
|
1
|
41
|
my $self = shift; |
272
|
22
|
100
|
|
|
|
81
|
return $self->{content} if exists $self->{content}; |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
# Get the sorted Test::Inline::Section objects |
275
|
18
|
50
|
|
|
|
48
|
my $sorted = $self->sorted or return undef; |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
# Prepare |
278
|
18
|
|
|
|
|
44
|
$self->{_example_count} = 0; |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
# Strip out empty sections |
281
|
18
|
|
|
|
|
47
|
@$sorted = grep { $_->content =~ /\S/ } @$sorted; |
|
43
|
|
|
|
|
98
|
|
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
# Generate wrapped code chunks |
284
|
18
|
|
|
|
|
49
|
my @content = map { $self->_wrap_content($_) } @$sorted; |
|
43
|
|
|
|
|
93
|
|
285
|
18
|
50
|
|
|
|
54
|
return '' unless @content; |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
# Merge to create the core testing code |
288
|
18
|
|
|
|
|
100
|
$self->{content} = join "\n\n\n", @content; |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
# Clean up and return |
291
|
18
|
|
|
|
|
40
|
delete $self->{_example_count}; |
292
|
18
|
|
|
|
|
67
|
$self->{content}; |
293
|
|
|
|
|
|
|
} |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
# Take a single generated section of code, and wrap it |
296
|
|
|
|
|
|
|
# in the standard boilerplate. |
297
|
|
|
|
|
|
|
sub _wrap_content { |
298
|
43
|
|
|
43
|
|
62
|
my $self = shift; |
299
|
43
|
50
|
|
|
|
285
|
my $Section = _INSTANCE(shift, 'Test::Inline::Section') or return undef; |
300
|
43
|
|
|
|
|
139
|
my $code = $Section->content; |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
# Wrap in compilation test code if an example |
303
|
43
|
100
|
|
|
|
95
|
if ( $Section->example ) { |
304
|
1
|
|
|
|
|
2
|
$self->{_example_count}++; |
305
|
1
|
|
|
|
|
6
|
$code =~ s/^/ /mg; |
306
|
1
|
|
|
|
|
6
|
$code = "eval q{\n" |
307
|
|
|
|
|
|
|
. " my \$example = sub {\n" |
308
|
|
|
|
|
|
|
. " local \$^W = 0;\n" |
309
|
|
|
|
|
|
|
. $code |
310
|
|
|
|
|
|
|
. " };\n" |
311
|
|
|
|
|
|
|
. "};\n" |
312
|
|
|
|
|
|
|
. "is(\$@, '', 'Example $self->{_example_count} compiles cleanly');\n"; |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
# Wrap in scope braces unless it is a setup section |
316
|
43
|
100
|
|
|
|
132
|
unless ( $Section->setup ) { |
317
|
37
|
|
|
|
|
106
|
$code = "{\n" |
318
|
|
|
|
|
|
|
. $code |
319
|
|
|
|
|
|
|
. "}\n"; |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
# Add the count-checking code if needed |
323
|
43
|
100
|
|
|
|
123
|
if ( $Section->{check_count} ) { |
324
|
12
|
|
|
|
|
25
|
my $increase = $Section->tests - 1; |
325
|
12
|
100
|
|
|
|
31
|
my $were = $increase == 1 ? 'test was' : 'tests were'; |
326
|
12
|
|
100
|
|
|
59
|
my $section = |
327
|
|
|
|
|
|
|
$code = "\$::__tc = Test::Builder->new->current_test;\n" |
328
|
|
|
|
|
|
|
. $code |
329
|
|
|
|
|
|
|
. "is( Test::Builder->new->current_test - \$::__tc, " |
330
|
|
|
|
|
|
|
. ($increase || '0') |
331
|
|
|
|
|
|
|
. ",\n" |
332
|
|
|
|
|
|
|
. "\t'$increase $were run in the section' );\n"; |
333
|
|
|
|
|
|
|
} |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
# Add the section header |
336
|
43
|
|
|
|
|
144
|
$code = "# $Section->{begin}\n" |
337
|
|
|
|
|
|
|
. $code; |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
# Aaaaaaaand we're done |
340
|
43
|
|
|
|
|
119
|
$code; |
341
|
|
|
|
|
|
|
} |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
##################################################################### |
348
|
|
|
|
|
|
|
# Implement the Algorithm::Dependency::Source Interface |
349
|
|
|
|
|
|
|
# This is used for section-level dependency. |
350
|
|
|
|
|
|
|
# These methods, though public, are undocumented. |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
# Our implementation of Algorithm::Dependency::Source->load is a no-op |
353
|
21
|
|
|
21
|
1
|
505
|
sub load { 1 } |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
# Pull a single item by name, section in the sections for it |
356
|
|
|
|
|
|
|
sub item { |
357
|
107
|
|
|
107
|
1
|
1224
|
my $self = shift; |
358
|
107
|
50
|
|
|
|
211
|
my $name = shift or return undef; |
359
|
107
|
|
|
310
|
|
345
|
List::Util::first { $_->name eq $name } $self->sections; |
|
310
|
|
|
|
|
626
|
|
360
|
|
|
|
|
|
|
} |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
# Return, in their original order, all the items ( named sections ) |
363
|
27
|
|
|
27
|
1
|
186
|
sub items { grep { $_->name } $_[0]->sections } |
|
67
|
|
|
|
|
133
|
|
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
##################################################################### |
370
|
|
|
|
|
|
|
# Implement the Algorithm::Dependency::Item Interface |
371
|
|
|
|
|
|
|
# This is used for class-level dependency. |
372
|
|
|
|
|
|
|
# These methods, though public, are undocumented. |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
sub id { |
375
|
14
|
|
|
14
|
1
|
77
|
$_[0]->{class}; |
376
|
|
|
|
|
|
|
} |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
sub depends { |
379
|
28
|
|
|
28
|
1
|
144
|
my $self = shift; |
380
|
0
|
|
|
|
|
0
|
my %depends = map { $_ => 1 } |
381
|
28
|
|
|
|
|
58
|
map { $_->classes } |
|
46
|
|
|
|
|
95
|
|
382
|
|
|
|
|
|
|
($self->setup, $self->sections); |
383
|
28
|
|
|
|
|
71
|
keys %depends; |
384
|
|
|
|
|
|
|
} |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
##################################################################### |
391
|
|
|
|
|
|
|
# Utility Functions |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
sub _duplicate_names(@) { |
394
|
20
|
|
|
20
|
|
53
|
my $self = shift; |
395
|
20
|
|
|
|
|
65
|
my %seen = (); |
396
|
20
|
|
|
|
|
56
|
foreach ( map { $_->name } $self->sections ) { |
|
42
|
|
|
|
|
106
|
|
397
|
42
|
100
|
|
|
|
107
|
next unless $_; |
398
|
33
|
50
|
|
|
|
140
|
return 1 if $seen{$_}++; |
399
|
|
|
|
|
|
|
} |
400
|
20
|
|
|
|
|
90
|
undef; |
401
|
|
|
|
|
|
|
} |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
1; |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
__END__ |