From 9970a68dbb108d36b16595d26b827a7d63223155 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Wed, 12 Jan 2011 11:44:09 -0600 Subject: add Plack::Client::Backend as a base class --- lib/Plack/Client.pm | 30 ++++++++-------- lib/Plack/Client/Backend.pm | 66 ++++++++++++++++++++++++++++++++++ lib/Plack/Client/Backend/http.pm | 10 +++--- lib/Plack/Client/Backend/psgi_local.pm | 9 +++-- 4 files changed, 94 insertions(+), 21 deletions(-) create mode 100644 lib/Plack/Client/Backend.pm diff --git a/lib/Plack/Client.pm b/lib/Plack/Client.pm index 813351c..1ed096a 100644 --- a/lib/Plack/Client.pm +++ b/lib/Plack/Client.pm @@ -69,10 +69,13 @@ appropriate apps based on the request. ) Constructor. Takes a hash of arguments, where keys are URL schemas, and values -are backends which handle those schemas. Hashref and arrayref values are also -valid, and will be dereferenced and passed to the constructor of the default -backend for that scheme (the class C, where -C<$scheme> has dashes replaced by underscores). +are backends which handle those schemas. Backends are really just coderefs +which receive a L and return a PSGI application coderef, but +see L for a more structured way to define these. +Hashref and arrayref values are also valid, and will be dereferenced and passed +to the constructor of the default backend for that scheme (the class +C, where C<$scheme> has dashes replaced by +underscores). =cut @@ -83,27 +86,26 @@ sub new { my %backends; for my $scheme (keys %params) { my $backend = $params{$scheme}; - if (blessed($backend)) { - croak "Backends must support the app_from_request method" - unless $backend->can('app_from_request'); + if ((blessed($backend) || '') eq 'Plack::Client::Backend') { + $backends{$scheme} = $backend->as_code; + } + elsif (reftype($backend) eq 'CODE') { $backends{$scheme} = $backend; } elsif (ref($backend)) { (my $normal_scheme = $scheme) =~ s/-/_/g; my $backend_class = "Plack::Client::Backend::$normal_scheme"; Class::Load::load_class($backend_class); - croak "Backends must support the app_from_request method" - unless $backend_class->can('app_from_request'); - croak "Backend classes must have a constructor" - unless $backend_class->can('new'); + croak "Backend classes must inherit from Plack::Client::Backend" + unless $backend_class->isa('Plack::Client::Backend'); $backends{$scheme} = $backend_class->new( reftype($backend) eq 'HASH' ? %$backend : reftype($backend) eq 'ARRAY' ? @$backend : $$backend - ); + )->as_code; } else { - croak 'XXX'; + croak "Backends must be a coderef or a Plack::Client::Backend instance"; } } @@ -265,7 +267,7 @@ sub _app_from_request { my $uri = $req->env->{'plack.client.original_uri'} || $req->uri; my $backend = $self->backend($uri); - my $app = $backend->app_from_request($req); + my $app = $backend->($req); croak "Couldn't find app" unless $app; diff --git a/lib/Plack/Client/Backend.pm b/lib/Plack/Client/Backend.pm new file mode 100644 index 0000000..3ba7771 --- /dev/null +++ b/lib/Plack/Client/Backend.pm @@ -0,0 +1,66 @@ +package Plack::Client::Backend; +use strict; +use warnings; +# ABSTRACT: turns a Plack::Request into a PSGI app + +use Carp; +use Scalar::Util qw(weaken); + +use overload '&{}' => sub { shift->as_code(@_) }, fallback => 1; + +=head1 SYNOPSIS + + package My::Backend; + use base 'Plack::Client::Backend'; + + sub app_from_request { + my $self = shift; + my ($req) = @_; + return sub { ... } + } + +=head1 DESCRIPTION + +This is a base class for L backends. These backends are handlers +for a particular URL scheme, and translate a L instance into a +PSGI application coderef. + +=cut + +=method new + +Creates a new backend instance. Takes no parameters by default, but may be +overridden in subclasses. + +=cut + +sub new { + my $class = shift; + bless {}, $class; +} + +=method app_from_request + +This method is called with an argument of a L object, and +should return a PSGI application coderef. The Plack::Request object it receives +contains the actual env hash that will be passed to the application, so +backends can modify that too, if they need to. + +=cut + +sub app_from_request { + croak "Backends must implement app_from_request"; +} + +=method as_code + +Returns a coderef which will call L as a method. + +=cut + +sub as_code { + my $self = shift; + return sub { $self->app_from_request(@_) }; +} + +1; diff --git a/lib/Plack/Client/Backend/http.pm b/lib/Plack/Client/Backend/http.pm index e443385..542c2ce 100644 --- a/lib/Plack/Client/Backend/http.pm +++ b/lib/Plack/Client/Backend/http.pm @@ -5,6 +5,8 @@ use warnings; use Plack::App::Proxy; +use base 'Plack::Client::Backend'; + =head1 SYNOPSIS Plack::Client->new( @@ -30,11 +32,11 @@ Constructor. Takes no arguments. sub new { my $class = shift; - my %params = @_; + my $self = $class->SUPER::new(@_); + + $self->{proxy} = Plack::App::Proxy->new->to_app; - bless { - proxy => Plack::App::Proxy->new->to_app, - }, $class; + return $self; } sub _proxy { shift->{proxy} } diff --git a/lib/Plack/Client/Backend/psgi_local.pm b/lib/Plack/Client/Backend/psgi_local.pm index 1da572b..7bb9bcc 100644 --- a/lib/Plack/Client/Backend/psgi_local.pm +++ b/lib/Plack/Client/Backend/psgi_local.pm @@ -6,6 +6,8 @@ use warnings; use Carp; use Plack::Middleware::ContentLength; +use base 'Plack::Client::Backend'; + =head1 SYNOPSIS Plack::Client->new( @@ -43,13 +45,14 @@ A mapping of local app names to PSGI app coderefs. sub new { my $class = shift; my %params = @_; + my $self = $class->SUPER::new(@_); croak 'apps must be a hashref' if ref($params{apps}) ne 'HASH'; - bless { - apps => $params{apps}, - }, $class; + $self->{apps} = $params{apps}; + + return $self; } sub _apps { shift->{apps} } -- cgit v1.2.3