line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Test::SynchHaveWant; |
2
|
|
|
|
|
|
|
|
3
|
3
|
|
|
3
|
|
95631
|
use warnings; |
|
3
|
|
|
|
|
9
|
|
|
3
|
|
|
|
|
156
|
|
4
|
3
|
|
|
3
|
|
15
|
use strict; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
104
|
|
5
|
|
|
|
|
|
|
|
6
|
3
|
|
|
3
|
|
16
|
use Test::Builder; |
|
3
|
|
|
|
|
9
|
|
|
3
|
|
|
|
|
50
|
|
7
|
3
|
|
|
3
|
|
3657
|
use Data::Dumper; |
|
3
|
|
|
|
|
74656
|
|
|
3
|
|
|
|
|
231
|
|
8
|
3
|
|
|
3
|
|
32
|
use Carp 'confess'; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
155
|
|
9
|
3
|
|
|
3
|
|
18
|
use base 'Exporter'; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
8624
|
|
10
|
|
|
|
|
|
|
our @EXPORT_OK = qw( |
11
|
|
|
|
|
|
|
have |
12
|
|
|
|
|
|
|
want |
13
|
|
|
|
|
|
|
synch |
14
|
|
|
|
|
|
|
); |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
my %DATA_SECTION_FOR; # this is the want() data |
17
|
|
|
|
|
|
|
my %NEW_DATA_FOR; # data from have(), if requested |
18
|
|
|
|
|
|
|
my %SEEK_POSITION_FOR; # where to synch the data, if requested |
19
|
|
|
|
|
|
|
my %SYNCH_WAS_CALLED; # calling have/want after this should fail |
20
|
|
|
|
|
|
|
my %TIMES_CALLED; # track how often have/want called |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=head1 NAME |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
Test::SynchHaveWant - Synchronize volatile have/want values for tests |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
=head1 VERSION |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
Version 0.01 |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
=cut |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
our $VERSION = '0.01'; |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
=head1 SYNOPSIS |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
use Test::Most; |
37
|
|
|
|
|
|
|
use Test::SynchHaveWant qw/ |
38
|
|
|
|
|
|
|
have |
39
|
|
|
|
|
|
|
want |
40
|
|
|
|
|
|
|
/; |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
my $have = some_complex_data(); |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
eq_or_diff have($have), want(), 'have and want should be the same'; |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
__DATA__ |
47
|
|
|
|
|
|
|
[ |
48
|
|
|
|
|
|
|
{ |
49
|
|
|
|
|
|
|
'bar' => [ 3, 4 ], |
50
|
|
|
|
|
|
|
'foo' => 1 |
51
|
|
|
|
|
|
|
}, |
52
|
|
|
|
|
|
|
0, |
53
|
|
|
|
|
|
|
bless( [ 'this', 'that', 'glarble', 'fetch' ], 'Foobar' ), |
54
|
|
|
|
|
|
|
] |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
If you wish to synch: |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
use Test::Most; |
59
|
|
|
|
|
|
|
use Test::SynchHaveWant qw/ |
60
|
|
|
|
|
|
|
have |
61
|
|
|
|
|
|
|
want |
62
|
|
|
|
|
|
|
synch |
63
|
|
|
|
|
|
|
/; |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
my $have = some_complex_data(); |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
eq_or_diff have($have), want(), 'have and want should be the same'; |
68
|
|
|
|
|
|
|
is have(0), want(), '0 is 0'; |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
# note that we can use normal tests |
71
|
|
|
|
|
|
|
my $want = want(); |
72
|
|
|
|
|
|
|
isa_ok $want, 'Foobar'; |
73
|
|
|
|
|
|
|
is_deeply $have($some_object), $want, '... and the object is the same'; |
74
|
|
|
|
|
|
|
synch(); |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
__DATA__ |
77
|
|
|
|
|
|
|
[ |
78
|
|
|
|
|
|
|
{ |
79
|
|
|
|
|
|
|
'bar' => [ 3, 4 ], |
80
|
|
|
|
|
|
|
'foo' => 1 |
81
|
|
|
|
|
|
|
}, |
82
|
|
|
|
|
|
|
0, |
83
|
|
|
|
|
|
|
bless( [ 'this', 'that', 'glarble', 'fetch' ], 'Foobar' ), |
84
|
|
|
|
|
|
|
] |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
=cut |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
sub _read_data_section { |
90
|
2
|
|
|
2
|
|
5
|
my $caller = shift; |
91
|
2
|
|
|
|
|
6
|
my $key = _get_key(); |
92
|
|
|
|
|
|
|
|
93
|
3
|
|
|
3
|
|
20
|
my $__DATA__ = do { no strict 'refs'; \*{"${caller}::DATA"} }; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
1000
|
|
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
13
|
|
94
|
2
|
50
|
|
|
|
11
|
unless ( defined fileno $__DATA__ ) { |
95
|
0
|
|
|
|
|
0
|
confess "__DATA__ section not found for package ($caller)"; |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
|
98
|
2
|
|
|
|
|
7
|
$SEEK_POSITION_FOR{$key} = tell $__DATA__; |
99
|
2
|
|
|
|
|
21
|
seek $__DATA__, 0, 0; |
100
|
2
|
|
|
|
|
94
|
my $data_section = join '', <$__DATA__>; |
101
|
2
|
|
|
|
|
33
|
$data_section =~ s/^.*\n__DATA__\n/\n/s; # for win32 |
102
|
2
|
|
|
|
|
7
|
$data_section =~ s/\n__END__\n.*$/\n/s; |
103
|
|
|
|
|
|
|
|
104
|
2
|
|
|
|
|
204
|
$data_section = eval $data_section; |
105
|
2
|
50
|
|
|
|
572
|
if ( my $error = $@ ) { |
106
|
0
|
|
|
|
|
0
|
confess "Error reading __DATA__ for ($caller): $error"; |
107
|
|
|
|
|
|
|
} |
108
|
2
|
50
|
50
|
|
|
42
|
unless ( 'ARRAY' eq ( ref $data_section || '' ) ) { |
109
|
0
|
|
|
|
|
0
|
confess "__DATA__ did not contain an array reference"; |
110
|
|
|
|
|
|
|
} |
111
|
2
|
|
|
|
|
10
|
$DATA_SECTION_FOR{$key} = $data_section; |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
=head1 DO NOT USE THIS CODE WITHOUT SOURCE CONTROL |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
This is C. It's very alpha code. It's dangerous code. It attempts to |
117
|
|
|
|
|
|
|
B and if it screws up, you had better be using B |
118
|
|
|
|
|
|
|
CONTROL> so you can revert. |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
That being said, if you need this code and you really, really understand |
121
|
|
|
|
|
|
|
what's going on, go ahead and use it at your own risk. |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
=head1 DESCRIPTION |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
Sometimes you have extremely volatile data/code and you I your tests are |
126
|
|
|
|
|
|
|
correct even though they've failed because the code has changed or the |
127
|
|
|
|
|
|
|
underlying data has been altered. Ordinarily, you never, never want your tests |
128
|
|
|
|
|
|
|
to be so fragile. You want to figure out some way of mocking your test data or |
129
|
|
|
|
|
|
|
isolating functional units in your code for testing. |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
The first pass I had at solving this problem was to effectively compute the |
132
|
|
|
|
|
|
|
edit distance for data structures, but even that failed as differences emerged |
133
|
|
|
|
|
|
|
over time (see L). |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
For this module, we're giving devs a chance to rewrite their test results on |
136
|
|
|
|
|
|
|
the fly, assuming that the new results of their code is correct. |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
This is generally an I. It's very stupid. Not only |
139
|
|
|
|
|
|
|
do we attempt to rewrite your __DATA__ sections, we make it very easy for |
140
|
|
|
|
|
|
|
you to have bogus tests because you may incorrectly assume that the new data |
141
|
|
|
|
|
|
|
you're returning is correct. That's why this is a B
|
142
|
|
|
|
|
|
|
EXPERIMENT>. |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
I've been asked a couple of times why I feel the need to experiment with |
145
|
|
|
|
|
|
|
writing "fragile" tests but I can't tell you due to my NDA. |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=head1 WHY IS OVID BEING STUPID? |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
Tests should not be as fragile as indicated here. You should mock up your test |
150
|
|
|
|
|
|
|
data or find ways of isolating functionality to make your tests more robust. |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
Not everyone has that luxury. If you insist that everyone does have that |
153
|
|
|
|
|
|
|
luxury, be aware that the real world of "these are the constraints I have" and |
154
|
|
|
|
|
|
|
the fantasy world of "the way I like things is the only way things should be |
155
|
|
|
|
|
|
|
done" aren't on speaking terms to one another. |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
=head1 USAGE |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
To make this work, you must have a C<__DATA__> section in your code. This |
160
|
|
|
|
|
|
|
section should contain terse L output of an array reference with each |
161
|
|
|
|
|
|
|
value being a subsequent expected test result. Every time C is called, |
162
|
|
|
|
|
|
|
the next value in this array ref is returned: |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
is have($foo), want(); # 3 |
165
|
|
|
|
|
|
|
is_deeply have($aref), want(); # ['foo','bar'] |
166
|
|
|
|
|
|
|
is have($idiot), want(); # 'ovid' |
167
|
|
|
|
|
|
|
__DATA__ |
168
|
|
|
|
|
|
|
[ |
169
|
|
|
|
|
|
|
3, |
170
|
|
|
|
|
|
|
[ qw/foo bar/ ], |
171
|
|
|
|
|
|
|
'ovid', |
172
|
|
|
|
|
|
|
] |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
The C function must be called as often as the C function (and |
175
|
|
|
|
|
|
|
in sequence) to track the values we have received. |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
If desired, the C function may be exported and called at the end of |
178
|
|
|
|
|
|
|
the test run. If any tests failed (C<< ! Test::Builder->new->is_passing >>), |
179
|
|
|
|
|
|
|
then we attempt to write all values passed to C to the C<__DATA__> |
180
|
|
|
|
|
|
|
section. |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
C will fail if have/want have been called a different number of times |
183
|
|
|
|
|
|
|
or if it has already been called. C and C will fail if |
184
|
|
|
|
|
|
|
C has already been called. |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
It goes without saying that this means you must have a deterministic order for |
187
|
|
|
|
|
|
|
your tests. Bad: |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
while ( my ( $key, $value ) = each %test ) { |
190
|
|
|
|
|
|
|
is_deeply have( some_func( $key, $value ) ), want(); |
191
|
|
|
|
|
|
|
} |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
Good: |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
foreach my $key ( sort keys %test ) { |
196
|
|
|
|
|
|
|
my $value = $test{$key}; |
197
|
|
|
|
|
|
|
is_deeply have( some_func( $key, $value ) ), want(); |
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
=head1 EXPORT |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
=head2 C |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
is have($have), want(), 'have should equal want'; |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
Ordinarily this function is a no-op. It merely returns the value it is passed. |
207
|
|
|
|
|
|
|
However, if synch is called at the end of the test run, the values passed to |
208
|
|
|
|
|
|
|
this function will be written to the data in the __DATA__ section. |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
=cut |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
sub have { |
213
|
6
|
|
|
6
|
1
|
607
|
my $have = shift; |
214
|
6
|
|
|
|
|
20
|
my $key = _get_key(); |
215
|
6
|
50
|
|
|
|
24
|
if ( exists $SYNCH_WAS_CALLED{$key} ) { |
216
|
0
|
|
|
|
|
0
|
confess "Synch was already called for ($key)"; |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
|
219
|
3
|
|
|
3
|
|
19
|
no warnings 'uninitialized'; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
566
|
|
220
|
6
|
|
|
|
|
19
|
$TIMES_CALLED{$key}{have}++; |
221
|
6
|
|
100
|
|
|
28
|
$NEW_DATA_FOR{$key} ||= []; |
222
|
6
|
|
|
|
|
1886
|
push @{ $NEW_DATA_FOR{$key} } => $have; |
|
6
|
|
|
|
|
18
|
|
223
|
6
|
|
|
|
|
34
|
return $have; |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
=head2 C |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
is have($have), want(), 'have should equal want'; |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
Returns the current expected test result. Attempting to read past the end of |
231
|
|
|
|
|
|
|
the test results will result in a fatal error. |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
=cut |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
sub want { |
236
|
7
|
|
|
7
|
1
|
19
|
my $key = _get_key(); |
237
|
7
|
50
|
|
|
|
25
|
if ( exists $SYNCH_WAS_CALLED{$key} ) { |
238
|
0
|
|
|
|
|
0
|
confess "Synch was already called for ($key)"; |
239
|
|
|
|
|
|
|
} |
240
|
|
|
|
|
|
|
|
241
|
7
|
100
|
|
|
|
23
|
unless ( exists $DATA_SECTION_FOR{$key} ) { |
242
|
2
|
|
|
|
|
11
|
_read_data_section( scalar caller ); |
243
|
|
|
|
|
|
|
} |
244
|
3
|
|
|
3
|
|
16
|
no warnings 'uninitialized'; |
|
3
|
|
|
|
|
4
|
|
|
3
|
|
|
|
|
2173
|
|
245
|
7
|
|
|
|
|
16
|
$TIMES_CALLED{$key}{want}++; |
246
|
7
|
|
|
|
|
13
|
my $data_section = $DATA_SECTION_FOR{$key}; |
247
|
7
|
100
|
|
|
|
17
|
unless (@$data_section) { |
248
|
1
|
|
|
|
|
257
|
confess("Attempt to read past end of __DATA__ for $0"); |
249
|
|
|
|
|
|
|
} |
250
|
6
|
|
|
|
|
32
|
return shift @$data_section; |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
=head2 C |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
synch(); |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
This function will attempt to take all of the values passed to have() and |
258
|
|
|
|
|
|
|
write them out to the __DATA__ section. If C and C have been |
259
|
|
|
|
|
|
|
called an unequal number of times, this function will die. |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
Will not attempt to synch the __DATA__ if the tests appear to be passing. |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
If tests are not passing, will prompt the user if they really want to synch |
264
|
|
|
|
|
|
|
tests results. Only a C<< /^\s*[Yy]/ >> is acceptable. To ensure that we don't |
265
|
|
|
|
|
|
|
block on automated systems, we have an alarm set for 10 seconds. After that, |
266
|
|
|
|
|
|
|
we merely return without attempting to synch. |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
=cut |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
sub synch { |
271
|
2
|
|
|
2
|
1
|
645
|
my $key = _get_key(); |
272
|
|
|
|
|
|
|
|
273
|
2
|
|
|
|
|
5
|
my ( $have, $want ) = @{ $TIMES_CALLED{$key} }{qw/have want/}; |
|
2
|
|
|
|
|
8
|
|
274
|
|
|
|
|
|
|
|
275
|
2
|
100
|
|
|
|
10
|
unless ( $have == $want ) { |
276
|
1
|
|
|
|
|
188
|
confess( |
277
|
|
|
|
|
|
|
"have/want not in synch: have was called $have times and want was called $want times" |
278
|
|
|
|
|
|
|
); |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
|
281
|
1
|
|
|
|
|
5
|
my $builder = Test::Builder->new; |
282
|
1
|
50
|
|
|
|
8
|
return if $builder->is_passing; |
283
|
|
|
|
|
|
|
|
284
|
0
|
|
|
|
|
0
|
print STDERR "# Really synch have/want data? (y/N) "; |
285
|
|
|
|
|
|
|
|
286
|
0
|
|
|
|
|
0
|
my $response; |
287
|
0
|
|
|
|
|
0
|
eval { |
288
|
0
|
|
|
0
|
|
0
|
local $SIG{ALRM} = sub { die "Died while bored" }; |
|
0
|
|
|
|
|
0
|
|
289
|
|
|
|
|
|
|
|
290
|
0
|
|
|
|
|
0
|
alarm 10; |
291
|
0
|
|
|
|
|
0
|
$response = ; |
292
|
0
|
|
|
|
|
0
|
alarm 0; |
293
|
|
|
|
|
|
|
}; |
294
|
0
|
0
|
|
|
|
0
|
if (my $error = $@) { |
295
|
0
|
0
|
|
|
|
0
|
return if $error =~ /Died while bored/; |
296
|
0
|
|
|
|
|
0
|
confess($error); |
297
|
|
|
|
|
|
|
} |
298
|
0
|
0
|
|
|
|
0
|
unless ( $response =~ /^\s*[yY]/ ) { |
299
|
0
|
|
|
|
|
0
|
warn "# Aborting synch ..."; |
300
|
0
|
|
|
|
|
0
|
return; |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
|
303
|
0
|
0
|
|
|
|
0
|
if ( exists $SYNCH_WAS_CALLED{$key} ) { |
304
|
0
|
|
|
|
|
0
|
confess "Synch was already called for ($key)"; |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
|
307
|
0
|
|
|
|
|
0
|
$SYNCH_WAS_CALLED{$key} = 1; |
308
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Indent = 1; |
309
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Sortkeys = 1; |
310
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Terse = 1; |
311
|
0
|
0
|
|
|
|
0
|
unless ( exists $SEEK_POSITION_FOR{$key} ) { |
312
|
0
|
|
|
|
|
0
|
confess("Panic: seek position for ($key) not found"); |
313
|
|
|
|
|
|
|
} |
314
|
0
|
|
|
|
|
0
|
my $new_data = $NEW_DATA_FOR{$key}; |
315
|
0
|
0
|
|
|
|
0
|
unless ( 'ARRAY' eq ref $new_data ) { |
316
|
0
|
|
|
|
|
0
|
confess( |
317
|
|
|
|
|
|
|
"PANIC: new data to write to __DATA__ is not an array reference"); |
318
|
|
|
|
|
|
|
} |
319
|
0
|
|
|
|
|
0
|
my $position = $SEEK_POSITION_FOR{$key}; |
320
|
|
|
|
|
|
|
|
321
|
0
|
0
|
|
|
|
0
|
open my $fh, '+<', $0 or confess "Cannot open $0 for writing: $!"; |
322
|
0
|
0
|
|
|
|
0
|
seek $fh, $position, 0 |
323
|
|
|
|
|
|
|
or confess "Cannot seek to position $position for $0: $!"; |
324
|
0
|
0
|
|
|
|
0
|
truncate $fh, tell($fh) |
325
|
|
|
|
|
|
|
or confess "Cannot truncate $0 at position $position: $!"; |
326
|
0
|
0
|
|
|
|
0
|
print $fh Dumper($new_data) or confess "Could not print new data to $0: $!"; |
327
|
0
|
0
|
|
|
|
0
|
close $fh or confess "Could not close $0: $!"; |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
# XXX eventually I may have to add to this if people start using this |
331
|
|
|
|
|
|
|
sub _get_key { |
332
|
17
|
|
|
17
|
|
48
|
return $0; |
333
|
|
|
|
|
|
|
} |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
=head1 AUTHOR |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
Curtis 'Ovid' Poe, C<< >> |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
=head1 BUGS |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
Please report any bugs or feature requests to C
|
342
|
|
|
|
|
|
|
rt.cpan.org>, or through the web interface at |
343
|
|
|
|
|
|
|
L. I will |
344
|
|
|
|
|
|
|
be notified, and then you'll automatically be notified of progress on your bug |
345
|
|
|
|
|
|
|
as I make changes. |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
=head1 SUPPORT |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command. |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
perldoc Test::SynchHaveWant |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
You can also look for information at: |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
=over 4 |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
=item * RT: CPAN's request tracker |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
L |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
=item * AnnoCPAN: Annotated CPAN documentation |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
L |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
=item * CPAN Ratings |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
L |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
=item * Search CPAN |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
L |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
=back |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
You don't really think I'm going to blame anyone else for this idiocy, do you? |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
Copyright 2011 Curtis 'Ovid' Poe. |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
384
|
|
|
|
|
|
|
under the terms of either: the GNU General Public License as published |
385
|
|
|
|
|
|
|
by the Free Software Foundation; or the Artistic License. |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
See http://dev.perl.org/licenses/ for more information. |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
=cut |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
1; |