Dancer2
view release on metacpan or search on metacpan
t/integration/hooks/engine.t view on Meta::CPAN
use strict;
use warnings;
use Test::More;
use Test::Fatal qw<exception>;
use Plack::Test;
use HTTP::Request::Common;
use Path::Tiny ();
# Engine hooks - before_template_render and friends - do not belong to the app,
# they belong to an engine the app may not have built yet. App's add_hook
# modifier (Dancer2/Core/App.pm:714-746) handles both cases:
#
# engine already built -> register straight onto it via hook_candidates
# engine not yet built -> stash it in postponed_hooks, and
# Hookable::_add_postponed_hooks applies it when the
# engine is finally constructed
#
# Which branch is taken depends only on whether 'set template => ...' has run
# yet, because that setting's trigger builds the engine immediately. So the two
# apps below differ *only* in the order of two lines, and both must end up with
# a working hook. The postponed branch is the one that silently drops the hook
# if it regresses, and nothing about the app's own behavior would reveal it.
my $VIEWS;
BEGIN {
$VIEWS = Path::Tiny->tempdir;
$VIEWS->child('page.tt')->spew_utf8('VIEW[[% marker %]]');
}
# Hook first, engine second: exercises the postponed path.
{
package PostponedApp;
use Dancer2;
set logger => 'null';
set views => $VIEWS->stringify;
our @trace;
hook before_template_render => sub {
my $tokens = shift;
push @trace, 'before_render';
$tokens->{marker} = 'FROM-POSTPONED-HOOK';
};
hook after_template_render => sub { push @trace, 'after_render' };
# The engine is built here, after both hooks were registered.
set template => 'template_toolkit';
get '/page' => sub { template 'page' };
}
# Engine first, hook second: exercises the direct path.
{
package DirectApp;
use Dancer2;
set logger => 'null';
set views => $VIEWS->stringify;
# The engine is built here, before either hook is registered.
set template => 'template_toolkit';
our @trace;
hook before_template_render => sub {
( run in 1.766 second using v1.01-cache-2.11-cpan-54e63673c56 )