From e618b454887d52b4b7e420dd3d9d6237afaad538 Mon Sep 17 00:00:00 2001 From: Thomas Klausner Date: Mon, 9 Sep 2019 13:13:30 +0200 Subject: [PATCH] add lifecycle-param to wrap_if, test & document it --- lib/OX.pm | 21 +++++++- t/singleton_middleware.t | 110 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 125 insertions(+), 6 deletions(-) diff --git a/lib/OX.pm b/lib/OX.pm index 1b37dd2..ad369ff 100644 --- a/lib/OX.pm +++ b/lib/OX.pm @@ -441,6 +441,14 @@ constructor call, to avoid it being parsed as an indirect method call. If you specify a coderef as the middleware, it will call that coderef, passing in the application coderef so far, and use the result as the new application. +If you want the middleware instance to persist between requests (e.g. +because it is expensive to init, or does some package level caching), +add C<'Singleton'> to the begin of the parameters passed to C + + wrap 'Singleton', 'Plack::Middleware::Foo' => ( + bar => literal(42), + ); + =cut sub wrap { @@ -480,15 +488,24 @@ environment. For instance: =cut sub wrap_if { - my ($condition, $middleware, %deps) = @_; + my $condition = shift; + my ($lifecycle, $middleware, %deps); + if (@_ % 2) { + ($middleware, %deps) = @_; + } + else { + ($lifecycle, $middleware, %deps) = @_; + } confess "wrap_if called outside of a router block" unless $CURRENT_CLASS; - $CURRENT_CLASS->add_middleware( condition => $condition, middleware => $middleware, dependencies => \%deps, + (defined $lifecycle + ? (lifecycle => $lifecycle) + : ()), ); } diff --git a/t/singleton_middleware.t b/t/singleton_middleware.t index 5539229..a5ce97f 100644 --- a/t/singleton_middleware.t +++ b/t/singleton_middleware.t @@ -6,8 +6,9 @@ use Plack::Test; use HTTP::Request::Common; -my $called; +my $build; my $prepare_app; +my $called; { package MyApp::Foo; @@ -34,7 +35,7 @@ my $prepare_app; ); sub BUILD { - $called++; + $build++; } sub prepare_app { @@ -45,6 +46,8 @@ my $prepare_app; my $self = shift; my ($env) = @_; + $called++; + my $res = $self->app->($env); push @{ $res->[1] }, ('X-Foo' => $self->foo->foo); return $res; @@ -75,14 +78,16 @@ test_psgi client => sub { my $cb = shift; + $build = 0; $called = 0; { my $res = $cb->(GET '/'); ok($res->is_success); is($res->content, '/'); is($res->header('X-Foo'), 'FOO'); - is($called, 1); + is($build, 1); is($prepare_app, 1); + is($called, 1); } { @@ -90,8 +95,9 @@ test_psgi ok($res->is_success); is($res->content, '/'); is($res->header('X-Foo'), 'FOO'); - is($called, 2); + is($build, 2); is($prepare_app, 2); + is($called, 2); } }; @@ -119,6 +125,7 @@ test_psgi client => sub { my $cb = shift; + $build = 0; $called = 0; $prepare_app = 0; { @@ -126,17 +133,112 @@ test_psgi ok($res->is_success); is($res->content, '/'); is($res->header('X-Foo'), 'FOO'); + is($build, 1); + is($prepare_app, 1); is($called, 1); + } + + { + my $res = $cb->(GET '/'); + ok($res->is_success); + is($res->content, '/'); + is($res->header('X-Foo'), 'FOO'); + is($build, 1); + is($prepare_app, 1); + is($called, 2); + } + + { + my $res = $cb->(GET '/'); + ok($res->is_success); + is($res->content, '/'); + is($res->header('X-Foo'), 'FOO'); + is($build, 1); is($prepare_app, 1); + is($called, 3); } + }; + +{ + package MyApp3; + use OX; + + has foo => ( + is => 'ro', + isa => 'MyApp::Foo', + ); + + router as { + wrap_if sub { $_[0]->{PATH_INFO} =~ m{^/wrap/?}}, 'Singleton', 'MyApp::Middleware', (foo => 'foo'); + + route '/' => sub { + my $req = shift; + return $req->path; + }; + + route '/wrap' => sub { + my $req = shift; + return $req->path; + }; + }; +} + +test_psgi + app => MyApp3->new->to_app, + client => sub { + my $cb = shift; + $build = 0; + $prepare_app = 0; + $called = 0; { my $res = $cb->(GET '/'); ok($res->is_success); is($res->content, '/'); + is($res->header('X-Foo'), undef); + is($build, 1); + is($prepare_app, 1); + is($called, 0); + } + + { + my $res = $cb->(GET '/wrap'); + ok($res->is_success); + is($res->content, '/wrap'); is($res->header('X-Foo'), 'FOO'); + is($build, 1); + is($prepare_app, 1); is($called, 1); + } + + { + my $res = $cb->(GET '/wrap'); + ok($res->is_success); + is($res->content, '/wrap'); + is($res->header('X-Foo'), 'FOO'); + is($build, 1); + is($prepare_app, 1); + is($called, 2); + } + + { + my $res = $cb->(GET '/'); + ok($res->is_success); + is($res->content, '/'); + is($res->header('X-Foo'), undef); + is($build, 1); + is($prepare_app, 1); + is($called, 2); + } + + { + my $res = $cb->(GET '/wrap'); + ok($res->is_success); + is($res->content, '/wrap'); + is($res->header('X-Foo'), 'FOO'); + is($build, 1); is($prepare_app, 1); + is($called, 3); } };