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