Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions lib/OX.pm
Original file line number Diff line number Diff line change
Expand Up @@ -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>

wrap 'Singleton', 'Plack::Middleware::Foo' => (
bar => literal(42),
);

=cut

sub wrap {
Expand Down Expand Up @@ -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)
: ()),
);
}

Expand Down
110 changes: 106 additions & 4 deletions t/singleton_middleware.t
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ use Plack::Test;

use HTTP::Request::Common;

my $called;
my $build;
my $prepare_app;
my $called;

{
package MyApp::Foo;
Expand All @@ -34,7 +35,7 @@ my $prepare_app;
);

sub BUILD {
$called++;
$build++;
}

sub prepare_app {
Expand All @@ -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;
Expand Down Expand Up @@ -75,23 +78,26 @@ 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);
}

{
my $res = $cb->(GET '/');
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);
}
};

Expand Down Expand Up @@ -119,24 +125,120 @@ test_psgi
client => sub {
my $cb = shift;

$build = 0;
$called = 0;
$prepare_app = 0;
{
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, 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);
}
};

Expand Down