[Catalyst-commits] r13851 - trunk/examples/CatalystAdvent/root/2010/pen

t0m at dev.catalyst.perl.org t0m at dev.catalyst.perl.org
Tue Dec 14 23:47:24 GMT 2010


Author: t0m
Date: 2010-12-14 23:47:24 +0000 (Tue, 14 Dec 2010)
New Revision: 13851

Added:
   trunk/examples/CatalystAdvent/root/2010/pen/clousres_in_the_stash.pod
Log:
First article

Added: trunk/examples/CatalystAdvent/root/2010/pen/clousres_in_the_stash.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2010/pen/clousres_in_the_stash.pod	                        (rev 0)
+++ trunk/examples/CatalystAdvent/root/2010/pen/clousres_in_the_stash.pod	2010-12-14 23:47:24 UTC (rev 13851)
@@ -0,0 +1,123 @@
+=head1 Stuffing your stash with closures
+
+=head2 The stash
+
+Every request in Catalyst has a I<stash>, which is scoped to that request.
+It's accessed with the C<< $c->stash >> accessor inside Catalyst, and made
+available within whatever View you are using in your application.
+
+For the purposes of this article, I'll concentrate on L<Template>, i.e. TT,
+but this technique is widely applicable.
+
+The usual pattern is to stash various data (simple scalars, objects, arrays, etc)
+during the course of your request, and you can then retrieve them (and for more
+complex data, like objects, call methods on them), once inside your template.
+
+=head3 Example of trivial usage
+
+    sub foo : Local {
+        my ($self, $c) = @_;
+        $c->stash( things => $c->model('DB::Things')->search({ bar => $c->request->param('bar') }) );
+    }
+    
+    ....
+    
+    <ul>
+    [% FOREACH thing IN things.all %]
+        <li>[% thing.name %]</li>
+    [% END %]
+    </ul>
+
+=head2 Stashing closures
+
+So, you can stash simple scalars, arrays and hashes (and then iterate through them later),
+objects (which you can then call methods on later), but less obviously, you can stash code
+references, and then call that code later..
+
+=head3 Trivial example
+
+    sub foo : Local {
+        my ($self, $c) = @_;
+        $c->stash( thing => sub { return 'quux' } );
+    }
+    
+    ....
+    
+    [% thing() %]
+    prints:
+    quux
+
+=head2 So what's this useful for?
+
+Well, less trivial cases, of course!!
+
+    $c->stash( uri_for_secure => sub { my $uri = $c->uri_for(@_); $uri->scheme('https'); return $uri } );
+    
+    [% c.uri_for_secure(...your normal params here...) %]
+
+Hey, that's useful, eh?
+
+=head2 Danger Will Robinson!!!
+
+B<THE EXAMPLE ABOVE IS UNSAFE>. It causes circular references!
+
+Closing over C<< $c >> (i.e. making a sub reference that includes C<< $c >> inside it),
+and then putting it into a data structure C<< $c->stash >> which is directly
+connected to C<< $c >>, causes a loop, meaning that perl won't B<ever> de-allocate
+the memory.
+
+If you do this once per request, then your application will quickly run out of memory!!
+
+=head2 ContextClosure
+
+    with 'Catalyst::Component::ContextClosure';
+
+    sub foo : Local {
+        my ($self, $c) = @_;
+        $c->stash(
+            uri_with_secure => $self->make_context_closure(sub {
+                my ($c) = @_;
+                my $uri = $c->uri_for(@_);
+                $uri->scheme('https');
+                return $uri;
+            },
+            $c)
+        );
+    }
+    
+Whilst this looks somewhat more baroqe than the previous version, it won't leak any
+memory, and is tremendously useful.
+
+=head2 Further thoughts and ideas.
+
+The great thing about a stashed closure is that you can have entirely different implementations
+of it for different parts of your site (without needing to add a method on your MyApp object with
+horrible conditional logic in it).
+
+If you're using Chained dispatch, then you can fill in a default closure at the base of your
+chain (for generic requests), and replace it with more specific versions later in the dispatch cycle
+for more specific / customised parts of your application.
+
+As the closures are code refs, it is in fact entirely possible to further customise them by wrapping
+them inside another code ref which does some further work.
+
+For example:
+
+    my $old = $c->stash->{uri_with_secure};
+    $c->stash( uri_with_secure => sub { my $uri = $old->(@_); $uri->path('/sekrit' . $uri->path); return $uri });
+    
+    ....
+    
+    [% uri_with_secure('...') %] => forces https, adds /sekrit to the front of any paths generated by uri_for
+
+=head2 Conclusion
+
+I hope this short article has opened your eyes to the potential useages for closures to clean up
+repeated template logic fragments within your application, and given you some ideas for alternatative
+ways to abstract specific fragments of display logic which don't really belong in your application templates.
+
+=head2 Author
+
+Tomas (t0m) Doran C<< <bobtfish at bobtfish.net> >>.
+
+=cut




More information about the Catalyst-commits mailing list