Commit | Line | Data |
---|---|---|
b4514920 CG |
1 | package Test2::API::Context; |
2 | use strict; | |
3 | use warnings; | |
4 | ||
35014935 | 5 | our $VERSION = '1.302035'; |
b4514920 CG |
6 | |
7 | ||
8 | use Carp qw/confess croak longmess/; | |
9 | use Scalar::Util qw/weaken/; | |
10 | use Test2::Util qw/get_tid try pkg_to_file get_tid/; | |
11 | ||
12 | use Test2::Util::Trace(); | |
13 | use Test2::API(); | |
14 | ||
15 | # Preload some key event types | |
16 | my %LOADED = ( | |
17 | map { | |
18 | my $pkg = "Test2::Event::$_"; | |
19 | my $file = "Test2/Event/$_.pm"; | |
20 | require $file unless $INC{$file}; | |
21 | ( $pkg => $pkg, $_ => $pkg ) | |
22 | } qw/Ok Diag Note Plan Bail Exception Waiting Skip Subtest/ | |
23 | ); | |
24 | ||
25 | use Test2::Util::ExternalMeta qw/meta get_meta set_meta delete_meta/; | |
26 | use Test2::Util::HashBase qw{ | |
27 | stack hub trace _on_release _depth _is_canon _is_spawn _aborted | |
28 | errno eval_error child_error | |
29 | }; | |
30 | ||
31 | # Private, not package vars | |
32 | # It is safe to cache these. | |
33 | my $ON_RELEASE = Test2::API::_context_release_callbacks_ref(); | |
34 | my $CONTEXTS = Test2::API::_contexts_ref(); | |
35 | ||
36 | sub init { | |
37 | my $self = shift; | |
38 | ||
39 | confess "The 'trace' attribute is required" | |
40 | unless $self->{+TRACE}; | |
41 | ||
42 | confess "The 'hub' attribute is required" | |
43 | unless $self->{+HUB}; | |
44 | ||
45 | $self->{+_DEPTH} = 0 unless defined $self->{+_DEPTH}; | |
46 | ||
47 | $self->{+ERRNO} = $! unless exists $self->{+ERRNO}; | |
48 | $self->{+EVAL_ERROR} = $@ unless exists $self->{+EVAL_ERROR}; | |
49 | $self->{+CHILD_ERROR} = $? unless exists $self->{+CHILD_ERROR}; | |
50 | } | |
51 | ||
52 | sub snapshot { bless {%{$_[0]}, _is_canon => undef, _is_spawn => undef, _aborted => undef}, __PACKAGE__ } | |
53 | ||
54 | sub restore_error_vars { | |
55 | my $self = shift; | |
56 | ($!, $@, $?) = @$self{+ERRNO, +EVAL_ERROR, +CHILD_ERROR}; | |
57 | } | |
58 | ||
59 | sub DESTROY { | |
60 | return unless $_[0]->{+_IS_CANON} || $_[0]->{+_IS_SPAWN}; | |
61 | return if $_[0]->{+_ABORTED} && ${$_[0]->{+_ABORTED}}; | |
62 | my ($self) = @_; | |
63 | ||
64 | my $hub = $self->{+HUB}; | |
65 | my $hid = $hub->{hid}; | |
66 | ||
67 | # Do not show the warning if it looks like an exception has been thrown, or | |
68 | # if the context is not local to this process or thread. | |
69 | if($self->{+EVAL_ERROR} eq $@ && $hub->is_local) { | |
70 | my $frame = $self->{+_IS_SPAWN} || $self->{+TRACE}->frame; | |
71 | warn <<" EOT"; | |
72 | A context appears to have been destroyed without first calling release(). | |
73 | Based on \$@ it does not look like an exception was thrown (this is not always | |
74 | a reliable test) | |
75 | ||
76 | This is a problem because the global error variables (\$!, \$@, and \$?) will | |
77 | not be restored. In addition some release callbacks will not work properly from | |
78 | inside a DESTROY method. | |
79 | ||
80 | Here are the context creation details, just in case a tool forgot to call | |
81 | release(): | |
82 | File: $frame->[1] | |
83 | Line: $frame->[2] | |
84 | Tool: $frame->[3] | |
85 | ||
86 | Cleaning up the CONTEXT stack... | |
87 | EOT | |
88 | } | |
89 | ||
90 | return if $self->{+_IS_SPAWN}; | |
91 | ||
92 | # Remove the key itself to avoid a slow memory leak | |
93 | delete $CONTEXTS->{$hid}; | |
94 | $self->{+_IS_CANON} = undef; | |
95 | ||
96 | if (my $cbk = $self->{+_ON_RELEASE}) { | |
97 | $_->($self) for reverse @$cbk; | |
98 | } | |
99 | if (my $hcbk = $hub->{_context_release}) { | |
100 | $_->($self) for reverse @$hcbk; | |
101 | } | |
102 | $_->($self) for reverse @$ON_RELEASE; | |
103 | } | |
104 | ||
105 | # release exists to implement behaviors like die-on-fail. In die-on-fail you | |
106 | # want to die after a failure, but only after diagnostics have been reported. | |
107 | # The ideal time for the die to happen is when the context is released. | |
108 | # Unfortunately die does not work in a DESTROY block. | |
109 | sub release { | |
110 | my ($self) = @_; | |
111 | ||
112 | ($!, $@, $?) = @$self{+ERRNO, +EVAL_ERROR, +CHILD_ERROR} and return $self->{+_IS_SPAWN} = undef | |
113 | if $self->{+_IS_SPAWN}; | |
114 | ||
115 | croak "release() should not be called on context that is neither canon nor a child" | |
116 | unless $self->{+_IS_CANON}; | |
117 | ||
118 | my $hub = $self->{+HUB}; | |
119 | my $hid = $hub->{hid}; | |
120 | ||
121 | croak "context thinks it is canon, but it is not" | |
122 | unless $CONTEXTS->{$hid} && $CONTEXTS->{$hid} == $self; | |
123 | ||
124 | # Remove the key itself to avoid a slow memory leak | |
125 | $self->{+_IS_CANON} = undef; | |
126 | delete $CONTEXTS->{$hid}; | |
127 | ||
128 | if (my $cbk = $self->{+_ON_RELEASE}) { | |
129 | $_->($self) for reverse @$cbk; | |
130 | } | |
131 | if (my $hcbk = $hub->{_context_release}) { | |
132 | $_->($self) for reverse @$hcbk; | |
133 | } | |
134 | $_->($self) for reverse @$ON_RELEASE; | |
135 | ||
136 | # Do this last so that nothing else changes them. | |
137 | # If one of the hooks dies then these do not get restored, this is | |
138 | # intentional | |
139 | ($!, $@, $?) = @$self{+ERRNO, +EVAL_ERROR, +CHILD_ERROR}; | |
140 | ||
141 | return; | |
142 | } | |
143 | ||
144 | sub do_in_context { | |
145 | my $self = shift; | |
146 | my ($sub, @args) = @_; | |
147 | ||
148 | # We need to update the pid/tid and error vars. | |
149 | my $clone = $self->snapshot; | |
150 | @$clone{+ERRNO, +EVAL_ERROR, +CHILD_ERROR} = ($!, $@, $?); | |
151 | $clone->{+TRACE} = $clone->{+TRACE}->snapshot; | |
152 | $clone->{+TRACE}->set_pid($$); | |
153 | $clone->{+TRACE}->set_tid(get_tid()); | |
154 | ||
155 | my $hub = $clone->{+HUB}; | |
156 | my $hid = $hub->hid; | |
157 | ||
158 | my $old = $CONTEXTS->{$hid}; | |
159 | ||
160 | $clone->{+_IS_CANON} = 1; | |
161 | $CONTEXTS->{$hid} = $clone; | |
162 | weaken($CONTEXTS->{$hid}); | |
163 | my ($ok, $err) = &try($sub, @args); | |
164 | my ($rok, $rerr) = try { $clone->release }; | |
165 | delete $clone->{+_IS_CANON}; | |
166 | ||
167 | if ($old) { | |
168 | $CONTEXTS->{$hid} = $old; | |
169 | weaken($CONTEXTS->{$hid}); | |
170 | } | |
171 | else { | |
172 | delete $CONTEXTS->{$hid}; | |
173 | } | |
174 | ||
175 | die $err unless $ok; | |
176 | die $rerr unless $rok; | |
177 | } | |
178 | ||
179 | sub done_testing { | |
180 | my $self = shift; | |
181 | $self->hub->finalize($self->trace, 1); | |
182 | return; | |
183 | } | |
184 | ||
185 | sub throw { | |
186 | my ($self, $msg) = @_; | |
187 | ${$self->{+_ABORTED}}++ if $self->{+_ABORTED}; | |
188 | $self->release if $self->{+_IS_CANON} || $self->{+_IS_SPAWN}; | |
189 | $self->trace->throw($msg); | |
190 | } | |
191 | ||
192 | sub alert { | |
193 | my ($self, $msg) = @_; | |
194 | $self->trace->alert($msg); | |
195 | } | |
196 | ||
197 | sub send_event { | |
198 | my $self = shift; | |
199 | my $event = shift; | |
200 | my %args = @_; | |
201 | ||
202 | my $pkg = $LOADED{$event} || $self->_parse_event($event); | |
203 | ||
204 | $self->{+HUB}->send( | |
205 | $pkg->new( | |
206 | trace => $self->{+TRACE}->snapshot, | |
207 | %args, | |
208 | ) | |
209 | ); | |
210 | } | |
211 | ||
212 | sub build_event { | |
213 | my $self = shift; | |
214 | my $event = shift; | |
215 | my %args = @_; | |
216 | ||
217 | my $pkg = $LOADED{$event} || $self->_parse_event($event); | |
218 | ||
219 | $pkg->new( | |
220 | trace => $self->{+TRACE}->snapshot, | |
221 | %args, | |
222 | ); | |
223 | } | |
224 | ||
225 | sub ok { | |
226 | my $self = shift; | |
227 | my ($pass, $name, $diag) = @_; | |
228 | ||
229 | my $hub = $self->{+HUB}; | |
230 | ||
231 | my $e = bless { | |
232 | trace => bless( {%{$self->{+TRACE}}}, 'Test2::Util::Trace'), | |
233 | pass => $pass, | |
234 | name => $name, | |
235 | }, 'Test2::Event::Ok'; | |
236 | $e->init; | |
237 | ||
238 | $hub->send($e); | |
239 | return $e if $pass; | |
240 | ||
241 | $self->failure_diag($e); | |
242 | ||
243 | if ($diag && @$diag) { | |
244 | $self->diag($_) for @$diag | |
245 | } | |
246 | ||
247 | return $e; | |
248 | } | |
249 | ||
250 | sub failure_diag { | |
251 | my $self = shift; | |
252 | my ($e) = @_; | |
253 | ||
254 | # This behavior is inherited from Test::Builder which injected a newline at | |
255 | # the start of the first diagnostics when the harness is active, but not | |
256 | # verbose. This is important to keep the diagnostics from showing up | |
257 | # appended to the existing line, which is hard to read. In a verbose | |
258 | # harness there is no need for this. | |
259 | my $prefix = $ENV{HARNESS_ACTIVE} && !$ENV{HARNESS_IS_VERBOSE} ? "\n" : ""; | |
260 | ||
261 | # Figure out the debug info, this is typically the file name and line | |
262 | # number, but can also be a custom message. If no trace object is provided | |
263 | # then we have nothing useful to display. | |
264 | my $name = $e->name; | |
265 | my $trace = $e->trace; | |
266 | my $debug = $trace ? $trace->debug : "[No trace info available]"; | |
267 | ||
268 | # Create the initial diagnostics. If the test has a name we put the debug | |
269 | # info on a second line, this behavior is inherited from Test::Builder. | |
270 | my $msg = defined($name) | |
271 | ? qq[${prefix}Failed test '$name'\n$debug.\n] | |
272 | : qq[${prefix}Failed test $debug.\n]; | |
273 | ||
274 | $self->diag($msg); | |
275 | } | |
276 | ||
277 | sub skip { | |
278 | my $self = shift; | |
279 | my ($name, $reason, @extra) = @_; | |
280 | $self->send_event( | |
281 | 'Skip', | |
282 | name => $name, | |
283 | reason => $reason, | |
284 | pass => 1, | |
285 | @extra, | |
286 | ); | |
287 | } | |
288 | ||
289 | sub note { | |
290 | my $self = shift; | |
291 | my ($message) = @_; | |
292 | $self->send_event('Note', message => $message); | |
293 | } | |
294 | ||
295 | sub diag { | |
296 | my $self = shift; | |
297 | my ($message) = @_; | |
298 | my $hub = $self->{+HUB}; | |
299 | $self->send_event( | |
300 | 'Diag', | |
301 | message => $message, | |
302 | ); | |
303 | } | |
304 | ||
305 | sub plan { | |
306 | my ($self, $max, $directive, $reason) = @_; | |
307 | ${$self->{+_ABORTED}}++ if $self->{+_ABORTED} && $directive && $directive =~ m/^(SKIP|skip_all)$/; | |
308 | $self->send_event('Plan', max => $max, directive => $directive, reason => $reason); | |
309 | } | |
310 | ||
311 | sub bail { | |
312 | my ($self, $reason) = @_; | |
313 | ${$self->{+_ABORTED}}++ if $self->{+_ABORTED}; | |
314 | $self->send_event('Bail', reason => $reason); | |
315 | } | |
316 | ||
317 | sub _parse_event { | |
318 | my $self = shift; | |
319 | my $event = shift; | |
320 | ||
321 | my $pkg; | |
322 | if ($event =~ m/^\+(.*)/) { | |
323 | $pkg = $1; | |
324 | } | |
325 | else { | |
326 | $pkg = "Test2::Event::$event"; | |
327 | } | |
328 | ||
329 | unless ($LOADED{$pkg}) { | |
330 | my $file = pkg_to_file($pkg); | |
331 | my ($ok, $err) = try { require $file }; | |
332 | $self->throw("Could not load event module '$pkg': $err") | |
333 | unless $ok; | |
334 | ||
335 | $LOADED{$pkg} = $pkg; | |
336 | } | |
337 | ||
338 | confess "'$pkg' is not a subclass of 'Test2::Event'" | |
339 | unless $pkg->isa('Test2::Event'); | |
340 | ||
341 | $LOADED{$event} = $pkg; | |
342 | ||
343 | return $pkg; | |
344 | } | |
345 | ||
346 | 1; | |
347 | ||
348 | __END__ | |
349 | ||
350 | =pod | |
351 | ||
352 | =encoding UTF-8 | |
353 | ||
354 | =head1 NAME | |
355 | ||
356 | Test2::API::Context - Object to represent a testing context. | |
357 | ||
358 | =head1 DESCRIPTION | |
359 | ||
360 | The context object is the primary interface for authors of testing tools | |
361 | written with L<Test2>. The context object represents the context in | |
362 | which a test takes place (File and Line Number), and provides a quick way to | |
363 | generate events from that context. The context object also takes care of | |
364 | sending events to the correct L<Test2::Hub> instance. | |
365 | ||
366 | =head1 SYNOPSIS | |
367 | ||
368 | In general you will not be creating contexts directly. To obtain a context you | |
369 | should always use C<context()> which is exported by the L<Test2::API> module. | |
370 | ||
371 | use Test2::API qw/context/; | |
372 | ||
373 | sub my_ok { | |
374 | my ($bool, $name) = @_; | |
375 | my $ctx = context(); | |
376 | $ctx->ok($bool, $name); | |
377 | $ctx->release; # You MUST do this! | |
378 | return $bool; | |
379 | } | |
380 | ||
381 | Context objects make it easy to wrap other tools that also use context. Once | |
382 | you grab a context, any tool you call before releasing your context will | |
383 | inherit it: | |
384 | ||
385 | sub wrapper { | |
386 | my ($bool, $name) = @_; | |
387 | my $ctx = context(); | |
388 | $ctx->diag("wrapping my_ok"); | |
389 | ||
390 | my $out = my_ok($bool, $name); | |
391 | $ctx->release; # You MUST do this! | |
392 | return $out; | |
393 | } | |
394 | ||
395 | =head1 CRITICAL DETAILS | |
396 | ||
397 | =over 4 | |
398 | ||
399 | =item you MUST always use the context() sub from Test2::API | |
400 | ||
401 | Creating your own context via C<< Test2::API::Context->new() >> will almost never | |
402 | produce a desirable result. Use C<context()> which is exported by L<Test2>. | |
403 | ||
404 | There are a handful of cases where a tool author may want to create a new | |
405 | context by hand, which is why the C<new> method exists. Unless you really know | |
406 | what you are doing you should avoid this. | |
407 | ||
408 | =item You MUST always release the context when done with it | |
409 | ||
410 | Releasing the context tells the system you are done with it. This gives it a | |
411 | chance to run any necessary callbacks or cleanup tasks. If you forget to | |
412 | release the context it will try to detect the problem and warn you about it. | |
413 | ||
414 | =item You MUST NOT pass context objects around | |
415 | ||
416 | When you obtain a context object it is made specifically for your tool and any | |
417 | tools nested within. If you pass a context around you run the risk of polluting | |
418 | other tools with incorrect context information. | |
419 | ||
420 | If you are certain that you want a different tool to use the same context you | |
421 | may pass it a snapshot. C<< $ctx->snapshot >> will give you a shallow clone of | |
422 | the context that is safe to pass around or store. | |
423 | ||
424 | =item You MUST NOT store or cache a context for later | |
425 | ||
426 | As long as a context exists for a given hub, all tools that try to get a | |
427 | context will get the existing instance. If you try to store the context you | |
428 | will pollute other tools with incorrect context information. | |
429 | ||
430 | If you are certain that you want to save the context for later, you can use a | |
431 | snapshot. C<< $ctx->snapshot >> will give you a shallow clone of the context | |
432 | that is safe to pass around or store. | |
433 | ||
434 | C<context()> has some mechanisms to protect you if you do cause a context to | |
435 | persist beyond the scope in which it was obtained. In practice you should not | |
436 | rely on these protections, and they are fairly noisy with warnings. | |
437 | ||
438 | =item You SHOULD obtain your context as soon as possible in a given tool | |
439 | ||
440 | You never know what tools you call from within your own tool will need a | |
441 | context. Obtaining the context early ensures that nested tools can find the | |
442 | context you want them to find. | |
443 | ||
444 | =back | |
445 | ||
446 | =head1 METHODS | |
447 | ||
448 | =over 4 | |
449 | ||
450 | =item $ctx->done_testing; | |
451 | ||
452 | Note that testing is finished. If no plan has been set this will generate a | |
453 | Plan event. | |
454 | ||
455 | =item $clone = $ctx->snapshot() | |
456 | ||
457 | This will return a shallow clone of the context. The shallow clone is safe to | |
458 | store for later. | |
459 | ||
460 | =item $ctx->release() | |
461 | ||
462 | This will release the context. This runs cleanup tasks, and several important | |
463 | hooks. It will also restore C<$!>, C<$?>, and C<$@> to what they were when the | |
464 | context was created. | |
465 | ||
466 | B<Note:> If a context is acquired more than once an internal refcount is kept. | |
467 | C<release()> decrements the ref count, none of the other actions of | |
468 | C<release()> will occur unless the refcount hits 0. This means only the last | |
469 | call to C<release()> will reset C<$?>, C<$!>, C<$@>,and run the cleanup tasks. | |
470 | ||
471 | =item $ctx->throw($message) | |
472 | ||
473 | This will throw an exception reporting to the file and line number of the | |
474 | context. This will also release the context for you. | |
475 | ||
476 | =item $ctx->alert($message) | |
477 | ||
478 | This will issue a warning from the file and line number of the context. | |
479 | ||
480 | =item $stack = $ctx->stack() | |
481 | ||
482 | This will return the L<Test2::API::Stack> instance the context used to find | |
483 | the current hub. | |
484 | ||
485 | =item $hub = $ctx->hub() | |
486 | ||
58818a66 CG |
487 | This will return the L<Test2::Hub> instance the context recognizes as the |
488 | current one to which all events should be sent. | |
b4514920 CG |
489 | |
490 | =item $dbg = $ctx->trace() | |
491 | ||
492 | This will return the L<Test2::Util::Trace> instance used by the context. | |
493 | ||
494 | =item $ctx->do_in_context(\&code, @args); | |
495 | ||
496 | Sometimes you have a context that is not current, and you want things to use it | |
497 | as the current one. In these cases you can call | |
498 | C<< $ctx->do_in_context(sub { ... }) >>. The codeblock will be run, and | |
499 | anything inside of it that looks for a context will find the one on which the | |
500 | method was called. | |
501 | ||
502 | This B<DOES NOT> affect context on other hubs, only the hub used by the context | |
503 | will be affected. | |
504 | ||
505 | my $ctx = ...; | |
506 | $ctx->do_in_context(sub { | |
507 | my $ctx = context(); # returns the $ctx the sub is called on | |
508 | }); | |
509 | ||
510 | B<Note:> The context will actually be cloned, the clone will be used instead of | |
58818a66 | 511 | the original. This allows the thread id, process id, and error variables to be correct without |
b4514920 CG |
512 | modifying the original context. |
513 | ||
514 | =item $ctx->restore_error_vars() | |
515 | ||
516 | This will set C<$!>, C<$?>, and C<$@> to what they were when the context was | |
517 | created. There is no localization or anything done here, calling this method | |
518 | will actually set these vars. | |
519 | ||
520 | =item $! = $ctx->errno() | |
521 | ||
522 | The (numeric) value of C<$!> when the context was created. | |
523 | ||
524 | =item $? = $ctx->child_error() | |
525 | ||
526 | The value of C<$?> when the context was created. | |
527 | ||
528 | =item $@ = $ctx->eval_error() | |
529 | ||
530 | The value of C<$@> when the context was created. | |
531 | ||
532 | =back | |
533 | ||
534 | =head2 EVENT PRODUCTION METHODS | |
535 | ||
536 | =over 4 | |
537 | ||
538 | =item $event = $ctx->ok($bool, $name) | |
539 | ||
540 | =item $event = $ctx->ok($bool, $name, \@diag) | |
541 | ||
542 | This will create an L<Test2::Event::Ok> object for you. If C<$bool> is false | |
543 | then an L<Test2::Event::Diag> event will be sent as well with details about the | |
544 | failure. If you do not want automatic diagnostics you should use the | |
545 | C<send_event()> method directly. | |
546 | ||
547 | The C<\@diag> can contain diagnostics messages you wish to have displayed in the | |
548 | event of a failure. For a passing test the diagnostics array will be ignored. | |
549 | ||
550 | =item $event = $ctx->note($message) | |
551 | ||
552 | Send an L<Test2::Event::Note>. This event prints a message to STDOUT. | |
553 | ||
554 | =item $event = $ctx->diag($message) | |
555 | ||
556 | Send an L<Test2::Event::Diag>. This event prints a message to STDERR. | |
557 | ||
558 | =item $event = $ctx->plan($max) | |
559 | ||
560 | =item $event = $ctx->plan(0, 'SKIP', $reason) | |
561 | ||
562 | This can be used to send an L<Test2::Event::Plan> event. This event | |
563 | usually takes either a number of tests you expect to run. Optionally you can | |
564 | set the expected count to 0 and give the 'SKIP' directive with a reason to | |
565 | cause all tests to be skipped. | |
566 | ||
567 | =item $event = $ctx->skip($name, $reason); | |
568 | ||
569 | Send an L<Test2::Event::Skip> event. | |
570 | ||
571 | =item $event = $ctx->bail($reason) | |
572 | ||
573 | This sends an L<Test2::Event::Bail> event. This event will completely | |
574 | terminate all testing. | |
575 | ||
576 | =item $event = $ctx->send_event($Type, %parameters) | |
577 | ||
578 | This lets you build and send an event of any type. The C<$Type> argument should | |
579 | be the event package name with C<Test2::Event::> left off, or a fully | |
580 | qualified package name prefixed with a '+'. The event is returned after it is | |
581 | sent. | |
582 | ||
583 | my $event = $ctx->send_event('Ok', ...); | |
584 | ||
585 | or | |
586 | ||
587 | my $event = $ctx->send_event('+Test2::Event::Ok', ...); | |
588 | ||
589 | =item $event = $ctx->build_event($Type, %parameters) | |
590 | ||
591 | This is the same as C<send_event()>, except it builds and returns the event | |
592 | without sending it. | |
593 | ||
594 | =back | |
595 | ||
596 | =head1 HOOKS | |
597 | ||
598 | There are 2 types of hooks, init hooks, and release hooks. As the names | |
599 | suggest, these hooks are triggered when contexts are created or released. | |
600 | ||
601 | =head2 INIT HOOKS | |
602 | ||
603 | These are called whenever a context is initialized. That means when a new | |
604 | instance is created. These hooks are B<NOT> called every time something | |
605 | requests a context, just when a new one is created. | |
606 | ||
607 | =head3 GLOBAL | |
608 | ||
609 | This is how you add a global init callback. Global callbacks happen for every | |
610 | context for any hub or stack. | |
611 | ||
612 | Test2::API::test2_add_callback_context_init(sub { | |
613 | my $ctx = shift; | |
614 | ... | |
615 | }); | |
616 | ||
617 | =head3 PER HUB | |
618 | ||
619 | This is how you add an init callback for all contexts created for a given hub. | |
620 | These callbacks will not run for other hubs. | |
621 | ||
622 | $hub->add_context_init(sub { | |
623 | my $ctx = shift; | |
624 | ... | |
625 | }); | |
626 | ||
627 | =head3 PER CONTEXT | |
628 | ||
629 | This is how you specify an init hook that will only run if your call to | |
630 | C<context()> generates a new context. The callback will be ignored if | |
631 | C<context()> is returning an existing context. | |
632 | ||
633 | my $ctx = context(on_init => sub { | |
634 | my $ctx = shift; | |
635 | ... | |
636 | }); | |
637 | ||
638 | =head2 RELEASE HOOKS | |
639 | ||
640 | These are called whenever a context is released. That means when the last | |
641 | reference to the instance is about to be destroyed. These hooks are B<NOT> | |
642 | called every time C<< $ctx->release >> is called. | |
643 | ||
644 | =head3 GLOBAL | |
645 | ||
646 | This is how you add a global release callback. Global callbacks happen for every | |
647 | context for any hub or stack. | |
648 | ||
649 | Test2::API::test2_add_callback_context_release(sub { | |
650 | my $ctx = shift; | |
651 | ... | |
652 | }); | |
653 | ||
654 | =head3 PER HUB | |
655 | ||
656 | This is how you add a release callback for all contexts created for a given | |
657 | hub. These callbacks will not run for other hubs. | |
658 | ||
659 | $hub->add_context_release(sub { | |
660 | my $ctx = shift; | |
661 | ... | |
662 | }); | |
663 | ||
664 | =head3 PER CONTEXT | |
665 | ||
666 | This is how you add release callbacks directly to a context. The callback will | |
667 | B<ALWAYS> be added to the context that gets returned, it does not matter if a | |
668 | new one is generated, or if an existing one is returned. | |
669 | ||
670 | my $ctx = context(on_release => sub { | |
671 | my $ctx = shift; | |
672 | ... | |
673 | }); | |
674 | ||
675 | =head1 THIRD PARTY META-DATA | |
676 | ||
677 | This object consumes L<Test2::Util::ExternalMeta> which provides a consistent | |
678 | way for you to attach meta-data to instances of this class. This is useful for | |
58818a66 | 679 | tools, plugins, and other extensions. |
b4514920 CG |
680 | |
681 | =head1 SOURCE | |
682 | ||
683 | The source code repository for Test2 can be found at | |
684 | F<http://github.com/Test-More/test-more/>. | |
685 | ||
686 | =head1 MAINTAINERS | |
687 | ||
688 | =over 4 | |
689 | ||
690 | =item Chad Granum E<lt>exodist@cpan.orgE<gt> | |
691 | ||
692 | =back | |
693 | ||
694 | =head1 AUTHORS | |
695 | ||
696 | =over 4 | |
697 | ||
698 | =item Chad Granum E<lt>exodist@cpan.orgE<gt> | |
699 | ||
700 | =item Kent Fredric E<lt>kentnl@cpan.orgE<gt> | |
701 | ||
702 | =back | |
703 | ||
704 | =head1 COPYRIGHT | |
705 | ||
706 | Copyright 2016 Chad Granum E<lt>exodist@cpan.orgE<gt>. | |
707 | ||
708 | This program is free software; you can redistribute it and/or | |
709 | modify it under the same terms as Perl itself. | |
710 | ||
711 | See F<http://dev.perl.org/licenses/> | |
712 | ||
713 | =cut |