From: John Napiorkowski Date: Fri, 26 Sep 2014 21:57:36 +0000 (-0500) Subject: evolve the stash middleware a bit. add a test case for tracking future growth X-Git-Tag: 5.90079_001~28 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Runtime.git;a=commitdiff_plain;h=4b0b748949f8aef8309806de2387296b17e5673d evolve the stash middleware a bit. add a test case for tracking future growth --- diff --git a/Changes b/Changes index 4dd30c5..527659e 100644 --- a/Changes +++ b/Changes @@ -5,6 +5,9 @@ existing Plack conventions. - Modify Catayst::Response->from_psgi_response to allow the first argument to be an object that does ->as_psgi. + - Modified Catayst::Middleware::Stash to be a shallow copy in $env. Added some + docs. Added a test case to make sure stash keys added in a child application + don't bubble back up to the main application. 5.90073 - 2014-09-23 - Fixed a regression caused by the last release where we broke what happened diff --git a/lib/Catalyst.pm b/lib/Catalyst.pm index 23ac3ad..f83616c 100644 --- a/lib/Catalyst.pm +++ b/lib/Catalyst.pm @@ -495,6 +495,18 @@ Catalyst). # stash is automatically passed to the view for use in a template $c->forward( 'MyApp::View::TT' ); +The stash hash is currently stored in the PSGI C<$env> and is managed by +L. Since it's part of the C<$env> items in +the stash can be accessed in sub applications mounted under your main +L application. For example if you delegate the response of an +action to another L application, that sub application will have +access to all the stash keys of the main one, and if can of course add +more keys of its own. However those new keys will not 'bubble' back up +to the main application. + +For more information the best thing to do is to review the test case: +t/middleware-stash.t in the distribution /t directory. + =cut sub stash { diff --git a/lib/Catalyst/Middleware/Stash.pm b/lib/Catalyst/Middleware/Stash.pm index 170fa11..e99285c 100644 --- a/lib/Catalyst/Middleware/Stash.pm +++ b/lib/Catalyst/Middleware/Stash.pm @@ -9,12 +9,12 @@ use Carp 'croak'; our @EXPORT_OK = qw(stash get_stash); -sub PSGI_KEY { 'Catalyst.Stash.v1' }; +sub PSGI_KEY () { 'Catalyst.Stash.v1' } sub get_stash { my $env = shift; - return $env->{&PSGI_KEY} || - _init_stash_in($env); + return $env->{+PSGI_KEY} || + croak "You requested a stash, but one does not exist."; } sub stash { @@ -38,16 +38,13 @@ sub _create_stash { }; } -sub _init_stash_in { - my ($env) = @_; - return $env->{&PSGI_KEY} ||= - _create_stash; -} - sub call { my ($self, $env) = @_; - _init_stash_in($env); - return $self->app->($env); + my $new_env = +{ %$env }; + my %stash = %{ ($env->{+PSGI_KEY} || sub {})->() || +{} }; + + $new_env->{+PSGI_KEY} = _create_stash( \%stash ); + return $self->app->($new_env); } =head1 TITLE @@ -63,6 +60,15 @@ alone distribution We store a coderef under the C which can be dereferenced with key values or nothing to access the underly hashref. +The stash middleware is designed so that you can 'nest' applications that +use it. If for example you have a L application that is called +by a controller under a parent L application, the child application +will inherit the full stash of the parent BUT any new keys added by the child +will NOT bubble back up to the parent. However, children of children will. + +For more information the current test case t/middleware-stash.t is the best +documentation. + =head1 SUBROUTINES This class defines the following subroutines. @@ -104,7 +110,7 @@ clients. Stash key / value are stored in memory. ["I found $stashed in the stash!"]]; }; -If the stash does not yet exist, we initialize one and return that. +If the stash does not yet exist, an exception is thrown. =head1 METHODS diff --git a/t/middleware-stash.t b/t/middleware-stash.t new file mode 100644 index 0000000..e35e9ef --- /dev/null +++ b/t/middleware-stash.t @@ -0,0 +1,52 @@ +use warnings; +use strict; + +{ + + package MyAppChild::Controller::User; + $INC{'MyAppChild/Controller/User.pm'} = __FILE__; + + use base 'Catalyst::Controller'; + use Test::More; + + sub stash :Local { + my ($self, $c) = @_; + $c->stash->{inner} = "inner"; + $c->res->body( "inner: ${\$c->stash->{inner}}, outer: ${\$c->stash->{outer}}"); + + is_deeply [sort {$a cmp $b} keys($c->stash)], ['inner','outer'], 'both keys in stash'; + } + + package MyAppChild; + $INC{'MyAppChild.pm'} = __FILE__; + + use Catalyst; + MyAppChild->setup; + + package MyAppParent::Controller::User; + $INC{'MyAppParent/Controller/User.pm'} = __FILE__; + + use base 'Catalyst::Controller'; + use Test::More; + + sub stash :Local { + my ($self, $c) = @_; + $c->stash->{outer} = "outer"; + $c->res->from_psgi_response( MyAppChild->to_app->($c->req->env) ); + + is_deeply [keys($c->stash)], ['outer'], 'only one key in stash'; + } + + package MyAppParent; + use Catalyst; + MyAppParent->setup; + +} + +use Test::More; +use Catalyst::Test 'MyAppParent'; + +my $res = request '/user/stash'; +is $res->content, 'inner: inner, outer: outer', 'got expected response'; + +done_testing;