use strict;
use Carp ();
use overload '&{}' => sub { shift->to_app(@_) }, fallback => 1;
__PACKAGE__->mk_accessors(qw/app/);
sub import {
my $class = shift;
if (@_) {
Carp::carp("use Plack::Middleware qw(Foo) is deprecated. See perldoc Plack::Builder");
}
}
sub wrap {
my($self, $app, @args) = @_;
if (ref $self) {
$self->{app} = $app;
} else {
$self = $self->new({ app => $app, @args });
}
return $self->to_app;
}
sub to_app {
my $self = shift;
return sub { $self->call(@_) };
}
sub response_cb {
my($self, $res, $cb) = @_;
my $body_filter = sub {
my($cb, $res) = @_;
my $filter_cb = $cb->($res);
# If response_cb returns a callback, treat it as a $body filter
if (defined $filter_cb && ref $filter_cb eq 'CODE') {
if (defined $res->[2]) {
my $body = $res->[2];
my $getline = ref $body eq 'ARRAY' ? sub { shift @$body } : sub { $body->getline };
$res->[2] = Plack::Util::inline_object
getline => sub { $filter_cb->($getline->()) },
close => sub { $body->close if ref $body ne 'ARRAY' };
} else {
return $filter_cb;
}
}
};
if (ref $res eq 'ARRAY') {
$body_filter->($cb, $res);
return $res;
} elsif (ref $res eq 'CODE') {
return sub {
my $respond = shift;
$res->(sub {
my $res = shift;
my $filter_cb = $body_filter->($cb, $res);
if ($filter_cb) {
my $writer = $respond->($res);
if ($writer) {
return Plack::Util::inline_object
write => sub { $writer->write($filter_cb->(@_)) },
close => sub { $writer->write($filter_cb->(undef)); $writer->close };
}
} else {
return $respond->($res);
}
});
};
}
return $res;
}
1;
__END__
=head1 NAME
Plack::Middleware - Base class for easy-to-use PSGI middleware
=head1 SYNOPSIS
package Plack::Middleware::Foo;
use parent qw( Plack::Middleware );
sub call {
my($self, $env) = @_;
# Do something with $env
# $self->app is the original app
my $res = $self->app->($env);
# Do something with $res
return $res;
}
# then in app.psgi
use Plack::Builder;
my $app = sub { ... } # as usual
builder {
enable "Plack::Middleware::Foo";
enable "Plack::Middleware::Bar", %options;
$app;
};
=head1 DESCRIPTION
Plack::Middleware is an utility base class to write PSGI
middleware. All you have to do is to inherit from Plack::Middleware
and then implement the callback C<call> method (or C<to_app> method
that would return the PSGI code reference) to do the actual work. You
can use C<< $self->app >> to call the original (wrapped) application.
See L<Plack::Builder> how to actually enable middlewares in your
I<.psgi> application file using the DSL. If you do not like our
builder DSL, you can also use C<wrap> method to wrap your application
with a middleware:
use Plack::Middleware::Foo;
my $app = sub { ... };
$app = Plack::Middleware::Foo->wrap($app, %options);
$app = Plack::Middleware::Bar->wrap($app, %options);
Note also Plack::Middleware object is callable, by overloading the
code dereference, so:
package Plack::Middleware::Foo;
use parent qw(Plack::Middleware);
sub call { ... }
my $app = Plack::Middleware::Foo->new;
C<$app> here is an object but can be used as a PSGI application as
well, since C<< $app->($env) >> just calls C<< $app->call($env) >>
internally.
=head1 SEE ALSO
L<Plack> L<Plack::Builder>
=cut