[Catalyst-commits] r14470 - trunk/examples/CatalystAdvent/root/2013
dpetrov at dev.catalyst.perl.org
dpetrov at dev.catalyst.perl.org
Mon Dec 2 08:16:07 GMT 2013
Author: dpetrov
Date: 2013-12-02 08:16:06 +0000 (Mon, 02 Dec 2013)
New Revision: 14470
Added:
trunk/examples/CatalystAdvent/root/2013/1.pod
trunk/examples/CatalystAdvent/root/2013/2.pod
trunk/examples/CatalystAdvent/root/2013/3.pod
trunk/examples/CatalystAdvent/root/2013/4.pod
trunk/examples/CatalystAdvent/root/2013/5.pod
trunk/examples/CatalystAdvent/root/2013/6.pod
trunk/examples/CatalystAdvent/root/2013/7.pod
trunk/examples/CatalystAdvent/root/2013/8.pod
trunk/examples/CatalystAdvent/root/2013/9.pod
Removed:
trunk/examples/CatalystAdvent/root/2013/01.pod
trunk/examples/CatalystAdvent/root/2013/02.pod
trunk/examples/CatalystAdvent/root/2013/03.pod
trunk/examples/CatalystAdvent/root/2013/04.pod
trunk/examples/CatalystAdvent/root/2013/05.pod
trunk/examples/CatalystAdvent/root/2013/06.pod
trunk/examples/CatalystAdvent/root/2013/07.pod
trunk/examples/CatalystAdvent/root/2013/08.pod
trunk/examples/CatalystAdvent/root/2013/09.pod
Modified:
trunk/examples/CatalystAdvent/root/2013/10.pod
trunk/examples/CatalystAdvent/root/2013/11.pod
trunk/examples/CatalystAdvent/root/2013/12.pod
trunk/examples/CatalystAdvent/root/2013/13.pod
trunk/examples/CatalystAdvent/root/2013/14.pod
trunk/examples/CatalystAdvent/root/2013/15.pod
Log:
Fix title names and pod filenames for 1..9
Deleted: trunk/examples/CatalystAdvent/root/2013/01.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/01.pod 2013-12-02 02:42:17 UTC (rev 14469)
+++ trunk/examples/CatalystAdvent/root/2013/01.pod 2013-12-02 08:16:06 UTC (rev 14470)
@@ -1,172 +0,0 @@
-=head1 Title
-
-Perl Catalyst in 2013 - The Year in Review!
-
-=head1 Overview
-
-Introduction to Advent 2013 and a review of all the things we accomplished.
-
-=head1 Welcome to Perl Catalyst Advent 2013!
-
-Its that time once again where the Perl hackers and stakeholders of various
-projects come together to congratulates themselves a bit for all the time and
-effort spent over the past year. So we review a bit, and we try to share our
-knowledge with people that are seeking to learn it. And we have a bit of fun
-at the same time!
-
-We need to remember that this is a time of year which is traditionally associated
-with giving gifts and receiving them graciously. But in a larger sense the gifts
-have already been sent along. Because for those of us involved in Free / Open
-source software, every act of participation is a gift. Whether you write code,
-fix documentation, submit test reports or just advocate on twitter, blogs, or
-whatever, you are gifting time and effort. That's in my mind one of the top
-gifts a person can give, since our time is one of our most precious and limited
-resources. To give that away is a pretty big deal in my book. And for those
-who choose Free / Open source, well I think its very cool to be part of a
-ethical movement like this whose focus is the betterment of all by working in
-common for those things with are common to all. Things like Perl, L<PSGI>,
-L<Moose> and of course lets not forget L<Catalyst>!
-
-So lets take a brief spin through the main events for L<Catalyst> in 2013!
-
-=head1 Main accomplishments
-
-Here's a brief rundown of some of the stuff that was added and changed in
-L<Catalyst> in 2013. This is just the highlights, you should checkout
-the Changes file for more details:
-
-L<https://metacpan.org/source/JJNAPIORK/Catalyst-Runtime-5.90051/Changes>
-
-=over 4
-
-=item HTTP Method Matching
-
-We added new action attributes that let you constrain on the expected HTTP
-method. For example:
-
- sub start : ChainedParent
- PathPrefix CaptureArgs(0) { }
-
- sub list_users : Chained('start')
- GET PathPart('') Args(0) { }
-
- sub add_users : Chained('start')
- POST PathPart('') Args(0) { }
-
-See L<Catalyst::Controller/GET> for more.
-
-=item Unicode in Core
-
-Just turn on the switch and you'll be sure to have greatly improved ability to
-handle utf8 encoding.
-
- $c->config->{encoding} = 'UTF-8'
-
-=item Handle the PSGI writer object for more control on output
-
-Useful for streaming and working with event loops, or just for when you want
-more control on how content is returned.
-
-=item Support for accessing IO streams when allowed.
-
-Use this for when you want to do websockets or long polling.
-
-=item Support PSGI middleware in configuration
-
-Lets you declare middleware as part of your L<Catalyst> application
-
-=item Added 'global data handlers' for parsing request content
-
-Lets you handle more than classic form POST parameters. Yes, this mean
-L<Catalyst> now handlers JSON POST out of the box!
-
-=item Mount a PSGI response
-
-Now your actions can mount PSGI applications and return PSGI reponses
-directly. Great for when you want to graft into you L<Catalyst> application
-bits of other frameworks such as L<Web::Simple> or L<Web::Machine> (or even
-other L<Catalyst> applications.)
-
-=item Constrain Actions on HTTP Request Content-Type
-
-Lets you constrain an action to a particular HTTP request content type. This
-lets you have one action that handles form data and another that handles JSON.
-Useful for building web APIs and is a nice augmentation of what you get with
-L<Catalyst::Action::REST>
-
-=item Configuration flag to use Hash::MultiValue for Request Parameters
-
-Lets you use L<Hash::MultiValue> for query and body parameters, which can solve
-some situtations when you are not sure if incoming parameters are scalar or
-arrays. Very commonly used on other L<Plack> based systems.
-
-=back
-
-And there was a lot of under the hood stuff as well. We cleared out that nasty
-Regexp based dispatch stuff into its own repo (makes it easier to remove later on).
-We did a bunch of stuff to make sure we'd play nice with other Plack applications
-that L<Catalyst> might dispatch to (such as making sure input is properly
-buffered). Ether (who works with me at Campus Explorer) dug in deep and cleaned
-up some old and no longer good practice Moosisms (replacing them with new, shiny
-Moosey goodness). And quite a few people checked in docs and other improvements.
-
-Here's a nice chart of people that checked in code to the L<Catalyst> repo:
-
-L<https://github.com/perl-catalyst/catalyst-runtime/graphs/contributors?from=2013-01-01&to=2013-11-16&type=c>
-
-And that doesn't count people that checked in code to other important bits of
-the ecosystem. Lots of people contributed doc patches and fixes to stuff around
-the session and authentication as well. So '++' to all of you!
-
-Excited to learn more? Well, go check out the docs, ponder test cases and look
-forward to more upcoming advent articles where we hope to cover all this and
-more!
-
-=head1 Project management
-
-In order to facilitate more participation, we mirrored the main L<Catalyst> git
-repository over on Github (see: L<https://github.com/perl-catalyst/>). This
-repository mirrors the canonical repository which for the time being will remain
-on shadowgit (L<catagits at git.shadowcat.co.uk:Catalyst-Runtime.git>). And we
-setup TravisCI on the github repo in order to help us track problems with
-changes (thanks Chris Weyl L<https://metacpan.org/author/RSRCHBOY> for the help
-with that).
-
-In addition we setup a Questhub for helping us to track and discuss possible
-changes to L<Catalyst> (See L<http://questhub.io/realm/perl/explore/latest/tag/catalyst>)
-
-I've also tried to blog as much as possible, and be sure to announce the
-important bits on the mailing list and in many cases I've tried to make use of
-external sites like Reddit and social media.
-
-Lastly we tried to be a little more transparent regarding what we are targeting
-for L<Catalyst> changes. We had several named development cycles ( Zombie-boomstick,
-Sicilian-buttercup and Hamburg) which all had targeted goals, announcements,
-as much discussion as I could squeeze out of the community and retrospectives.
-
-I personally believe that open source works best when it works for all of us
-and the best way I can think to do that is to try and make everything as
-transparent as possible. I believe we succeeded in that, and I hope we can
-build on that into the coming year.
-
-=head1 Summary
-
-2013 was another big year for L<Catalyst>. We worked hard at making it even
-more flexible and useful out of the box by exposing more L<PSGI> and grafting
-in a few missing bits. I expect 2014 to be even a bigger year as we look hard
-at L<Catalyst> and try to find a strong direction that lets it remain the best
-full stack web application framework for Perl!
-
-=head1 For More Information
-
-CPAN: L<Catalyst>
-Github: L<https://github.com/perl-catalyst/>
-Code Repository: L<catagits at git.shadowcat.co.uk:Catalyst-Runtime.git>
-Questhub: L<http://questhub.io/realm/perl/explore/latest/tag/catalyst>
-Mailing List Info: L<http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst>
-
-=head1 Author
-
-Your Name <your at email.com> | IRC nick
-
-=cut
Deleted: trunk/examples/CatalystAdvent/root/2013/02.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/02.pod 2013-12-02 02:42:17 UTC (rev 14469)
+++ trunk/examples/CatalystAdvent/root/2013/02.pod 2013-12-02 08:16:06 UTC (rev 14470)
@@ -1,278 +0,0 @@
-=head1 Title
-
-Roll your own Catalyst Controller with Mooselike imports
-
-=head1 Overview
-
-Learn how to create a custom Catalyst base controller with Mooselike
-imported keywords and more.
-
-=head1 Introduction
-
-Most L<Catalyst> applications of a certain age and complexity have a lot of
-controllers. Quite often your controllers have excessive boilerplate code
-even before you add anything related to your business logic. Here's the
-canonical controller as often documented.
-
- package MyApp::Controller::MyController;
-
- use Moose;
- use namespace::autoclean;
-
- BEGIN { extends 'Catalyst::Controller' }
-
- ## -- Your code
-
- __PACKAGE__->meta->make_immutable
-
-I've always disliked how the C<extends> needs to be in a BEGIN block, which is
-a side effect of how L<MooseX::MethodAttributes> works with the existing code
-base as ported to L<Moose> several years ago. It just looks odd and is a
-surprise to people new (and even old) to the framework. People generally just
-cargo cult it.
-
-Additionally every action typically starts by shifting or slurping the same
-arguments:
-
- sub my_action :Action {
- my ($self, $c) = @_'
- }
-
-And that's before you add in any of a number of things special to your logic.
-Is there anything we can do to centralize some of this boilerplate? And what
-if you like to use a handful of other syntax enhancing modules like
-L<Function::Parameters> or L<CatalystX::Syntax::Action>? If you wanted that,
-you'd end up with a controller something like:
-
- package MyApp::Controller;
-
- use Moose;
- BEGIN { extends 'Catalyst::Controller' }
-
- use Function::Parameters;
- use CatalystX::Syntax::Action;
- use namespace::autoclean;
-
- ## -- You custom actions and methods
-
- __PACKAGE__->meta->make_immutable;
-
-And doing this allows you to write a controller like this:
-
- package MyApp::Controller::Root;
-
- use Moose;
- BEGIN { extends 'Catalyst::Controller' }
-
- use Function::Parameters;
- use CatalystX::Syntax::Action;
- use namespace::autoclean;
-
- has 'test_attribute' => (
- is=>'ro',
- default=>'example value');
-
- method generate_helloworld { 'Hello world!' }
-
- action helloworld : GET Path('/helloworld') {
- $ctx->res->body( $self->generate_helloworld);
- }
-
- action echo($arg) : GET Path('/echo') Args(1) {
- $ctx->res->body( $arg );
- }
-
- 1;
-
-=head1 Moose and Import::Into to the Rescue!
-
-Our goal is to take the controller example from above and reduce it so that
-you can just do:
-
- package MyApp::Controller;
-
- use MyApp::ControllerObject;
-
- ## -- You custom actions and methods
-
- __PACKAGE__->meta->make_immutable;
-
-This yields an example controller like so:
-
- package MyApp::Controller::Root;
-
- use MyApp::ControllerObject;
-
- has 'test_attribute' => (
- is=>'ro',
- default=>'example value');
-
- method generate_helloworld { 'Hello world!' }
-
- action helloworld : GET Path('/helloworld') {
- $ctx->res->body( $self->generate_helloworld);
- }
-
- action echo($arg) : GET Path('/echo') Args(1) {
- $ctx->res->body( $arg );
- }
-
-L<Catalyst> is build on L<Moose> so out of the box you get some built in
-features that allow you to create a custom Controller object class that slurps
-up everything you get with L<Moose> and allows you to add in whatever it is you
-like. along with L<Import::Into>'s consistent interface for importing features
-into your package, its very trivial to make a custom controller that does all
-we want (and can easily be extended to do much more, if you think that is wise).
-
-So, what would C<MyApp::ControllerObject> look like? Lets take a look a the
-full code and then do a walkdown:
-
- package MyApp::ControllerObject;
-
- use strict;
- use warnings;
-
- use Moose::Exporter;
- use Import::Into;
- use Module::Runtime;
-
- my ($import, $unimport, $init_meta) =
- Moose::Exporter->build_import_methods( also => ['Moose'] );
-
- sub importables {
- 'Function::Parameters',
- 'CatalystX::Syntax::Action',
- 'namespace::autoclean',
- }
-
- sub base_class { 'Catalyst::Controller' }
-
- sub init_meta {
- my ($class, @args) = @_;
- Moose->init_meta( @args,
- base_class => $class->base_class );
- goto $init_meta if $init_meta;
- }
-
- sub import {
- use_module($_)->import::into(scalar caller)
- for shift->importables;
- goto $import;
- }
-
- 1;
-
-So you can see there's not a lot of needed code to do this, mostly because of
-all the existing art that the L<Moose> cabal put into making extending L<Moose>
-easy, and because of the wonder clean, consistent API that L<Import::Into>
-gives you. Let's take it again from the top:
-
- package MyApp::ControllerObject;
-
- use strict;
- use warnings;
-
- use Moose::Exporter;
- use Import::Into;
- use Module::Runtime;
-
-So we setup the module namespace and use three modules (plus the ever present
-L<strict> and L<warnings> pragmas) which brings in all the required functionality.
-L<Moose::Exporter> sets us up with a Moosey import and later on you will see
-it lets us import all the normal Moose goodies. L<Import::Info> provides a clean,
-consistent interface for importing a module features into a package other than
-your own (used to inject syntax and pragmas into a calling system). Lastly, we
-use L<Module::Runtime> to make it easy to dynamically load modules in running
-code.
-
- my ($import, $unimport, $init_meta) =
- Moose::Exporter->build_import_methods( also => ['Moose'] );
-
-Here we use L<Moose::Exporter> to build for use some coderefs to handle how to
-properly import and initialize L<Moose>
-
- sub importables {
- 'Function::Parameters',
- 'CatalystX::Syntax::Action',
- 'namespace::autoclean',
- }
-
- sub base_class { 'Catalyst::Controller' }
-
-Here's the features we want imported into our controllers, and the base controller
-we want to use. I wrote it out as a separate function to make it easy for you to
-use and for people to subclass and override. You can add here whatever you want
-(but I recommend sanity, and remember too much magic can make it hard to debug
-stuff down the road).
-
- sub init_meta {
- my ($class, @args) = @_;
- Moose->init_meta( @args,
- base_class => $class->base_class );
- goto $init_meta if $init_meta;
- }
-
-This method gets called at startup and it initializes L<Moose> and sets the actual
-base class. This way when you do C<use MyApp::ControllerObject> you are already
-inheriting from L<Catalyst::Controller>.
-
- sub import {
- use_module($_)->import::into(scalar caller)
- for shift->importables;
- goto $import;
- }
-
-Here's where the bulk of the action is. AS you should recall, when you write
-code like:
-
- use MyApp::ControllerObject;
-
-That loads the code representing that namespace, and then calls the C<import>
-method on it. So we loop through each module we want to import, make sure it
-is loaded via C<use_module> and then use the interface that L<Import::Into>
-gives us. After that, we forward on to the C<import> coderef that
-L<Moose::Exporter> setup for us early on.
-
-Oh, what's up with that C<goto>? Yeah, generally C<goto> is evil, but this is
-a secondary use of C<goto> which is a lot like a subroutine call, but it acts more
-like a subroutine swap (nothing is added to the callstack, and @_ is preserved).
-So its nothing to worry about!
-
-And that is it!
-See the code on Github for a full example distribution you can review:
-L<https://github.com/perl-catalyst/2013-Advent-Staging/tree/master/MyApp-ControllerObject>
-
-This has a full sample distribution with test cases and all that. So take a
-look to see the bigger picture.
-
-=head1 Summary
-
-We reviewed one approach to using built in features of L<Moose>, the object
-system upon which L<Catalyst> is built, to reduce boilerplate when several
-desired features are needed across a large project. Along with L<Import::Into>'s
-simple and consistent API, you now have all you need to reduce boilerplate
-code in your larger Perl L<Catalyst> projects!
-
-=head1 Limitations and Concerns
-
-Although this method does allow one to centralize some boilerplate, I highly
-recommend being careful with the amount of extra behavior you place in this
-common class, as excessive magic can ultimately cause confusion and make it
-harder to debug issue. This method is not intended as a replacement for
-proper use of standard Perl design (Roles, etc).
-
-=head1 More Information
-
-I recommend reading the excellent documentation for extending L<Moose> via
-its build in exporter, L<Moose::Exporter> as well as any of the related
-documentation in the L<Moose> distribution, as well as the following:
-
-L<Catalyst>, L<Moose>, L<Import::Into>, L<Function::Parameters>,
-L<namespace::autoclean>, L<CatalystX::Syntax::Action>
-
-=head1 Author
-
-John Napiorkowski L<email:jjnapiork at cpan.org>
-
-=cut
-
Deleted: trunk/examples/CatalystAdvent/root/2013/03.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/03.pod 2013-12-02 02:42:17 UTC (rev 14469)
+++ trunk/examples/CatalystAdvent/root/2013/03.pod 2013-12-02 08:16:06 UTC (rev 14470)
@@ -1,145 +0,0 @@
-=head1 Title
-
-HTTP Method Matching in Catalyst
-
-=head1 Overview
-
-A quick example of how to use the HTTP Method matching feature
-in L<Catalyst> along with some tips and caveats.
-
-=head1 Introduction
-
-Beginning in the v5.90020 release of L<Catalyst> we introduced into core the
-ability to match your controller actions to incoming HTTP method verbs. It
-does this by extending the standard L<Catalyst> approach of using subroutine
-attributes to tag your actions with 'metadata' that the dispatcher uses to
-figure out how to assign a given incoming request to a controller and action.
-Generic and shortcut attributes are allowed, and in addition we support some
-of the common approaches to use HTTP extended headers to 'tunnel' a method
-verb for the cases when the client is restricted (such as is common in many
-browsers to only support GET and POST).
-
-=head1 Why dispatch on HTTP Methods?
-
-Most modern web frameworks give you some high level ability to match an
-incoming request based on its HTTP verb. Programmers find it useful for
-a variety of tasks, from crafting RESTful APIs to allowing one to just have
-more meaningful URLs. L<Catalyst> has allowed this via a few add on
-distributions but often people don't find them. Having this feature in core
-means one can perform those tasks 'out of the box'. It also means that we
-can count on the presence of that ability as we continue to craft L<Catalyst>
-core codebase into the future.
-
-=head1 How Does it Work?
-
-Let's look at an example action:
-
- sub is_get : Method('GET') Path('/example') { ... }
- sub is_any : Path('/example') { ... }
-
-In this case the URL '/example' would get executed by the C<is_get> method
-of this controller when the HTTP method is a GET and by the C<is_any> method
-for all other cases. The generical uses is "Method($verb)" where $verb is
-any standard or custom value that shows up in the HTTP method header. Since
-several are common, we provide some shortcuts:
-
- sub is_get : GET Path('/example') { ... }
- sub is_post : POST Path('/example') { ... }
- sub is_put : PUT Path('/example') { ... }
- sub is_delete : DELETE Path('/example') { ... }
-
-In these cases the '/example' url would get mapped to the action as expected
-by the incoming HTTP method verb. Finally, you may add more than one method
-matching attribute:
-
- sub post_and_put : POST PUT Path('/example) { ... }
-
-=head1 HTTP Extended Header Tunneling
-
-Since not all clients support a rich HTTP method vocabulary (classic HTML
-forms come to mind, since they typically only support GET and POST) it has
-become standard practice to use HTTP extended headers to 'tunnel' a verb
-not supported by a given client over one that does. For example, one might
-use this feature to tunnel a DELETE or PUT over a POST.
-
-For broad compatibility, we support HTTP method tunneling over the following
-HTTP headers:
-
-=over 4
-
-=item X-HTTP-Method (Microsoft)
-
-=item X-HTTP-Method-Override (Google/GData)
-
-=item X-METHOD-OVERRIDE (IBM)
-
-=item x-tunneled-method (used in many other similar systems on CPAN)
-
-=back
-
-Typically you won't need to set these headers yourself, they are usually
-created for you by the Javascript or similar toolkits but you should be aware
-of there function so you are not caught by surprise when they are active.
-
-=head1 A Full Example
-
-An example controller:
-
- package MyApp::Controller::Root;
-
- use base 'Catalyst::Controller';
-
- sub is_get : GET Path('/test') { pop->res->body('GET') }
-
- sub is_post : POST Path('/test') { pop->res->body('POST') }
-
- sub is_put : PUT Path('/test') { pop->res->body('PUT') }
-
- sub is_delete : DELETE Path('/test') { pop->res->body('DELETE') }
-
- 1;
-
-And the test case for this:
-
- use Test::Most;
- use Catalyst::Test 'MyApp';
- use HTTP::Request::Common qw(GET PUT POST DELETE);
-
- is request(GET '/test')->content, 'GET';
- is request(PUT '/test')->content, 'PUT';
- is request(POST '/test')->content, 'POST';
- is request(DELETE '/test')->content, 'DELETE';
-
- done_testing;
-
-You can see the full application source on Github:
-L<https://github.com/perl-catalyst/2013-Advent-Staging/tree/master/HTTP-Method-Matching>.
-
-=head1 Caveats and Gotchas
-
-You should remember that Catalyst will typically match on the first action
-that meets the minimum requirement. This means you need to put you more
-specific matches 'higher' in the controller than the catchall actions. When
-running L<Catalyst> in debug mode (via CATALYST_DEBUG=1, for example) the
-initial informations screen now contains information about what HTTP methods a
-given action will try to match, so that should help you figure out if something
-is going wrong.
-
-Also, this feature does not attempt to set some standard HTTP header information
-in the response regarding which methods are and are not allowed (as does for
-example L<Web::Machine>. If you are trying to create a strong, RESTful API
-you should not forget to set the response HTTP headers around allowed HTTP
-methods in your controller code.
-
-=head1 Summary
-
-HTTP Method Matching in core L<Catalyst> gives you a bit more flexibility
-to craft how the dispatcher maps incoming requests to your actions. Although
-the feature has limitations it should prove useful when mapping complex
-client server interactions.
-
-=head1 Author
-
-John Napiorkowski L<email:jjnapiork at cpan.org>
-
-=cut
Deleted: trunk/examples/CatalystAdvent/root/2013/04.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/04.pod 2013-12-02 02:42:17 UTC (rev 14469)
+++ trunk/examples/CatalystAdvent/root/2013/04.pod 2013-12-02 08:16:06 UTC (rev 14470)
@@ -1,344 +0,0 @@
-=head1 Title
-
-Using PSGI Integration in Catalyst: Middleware and More
-
-=head1 Overview
-
-This is an example application that shows you how to use the
-new L<Catalyst> support for PSGI middleware, and why you might
-want to use it.
-
-=head1 Introduction
-
-Modern versions of L<Catalyst> use L<Plack> as the underlying engine to
-connect your application to an http server. This means that you can take
-advantage of the full L<Plack> software ecosystem to grow your application
-and to better componentize and re-use your code.
-
-Middleware is a large part of this ecosystem. L<Plack::Middleware> wraps your
-PSGI application with additional functionality, such as adding Sessions ( as in
-L<Plack::Middleware::Session>), Debugging (as in L<Plack::Middleware::Debug>)
-and logging (as in L<Plack::Middleware::LogDispatch> or
-L<Plack::Middleware::Log4Perl>).
-
-Generally you can enable middleware in your C<psgi> file, as in the following
-example
-
- #!/usr/bin/env plackup
-
- use strict;
- use warnings;
-
- use MyApp::Web; ## Your subclass of 'Catalyst'
- use Plack::Builder;
-
- builder {
-
- enable 'Debug';
- enable 'Session', store => 'File';
-
- mount '/' => MyApp::Web->psgi_app;
-
- };
-
-Here we are using our C<psgi> file and tools that come with L<Plack> in order
-to enable L<Plack::Middleware::Debug> and L<Plack::Middleware::Session>. This
-is a nice, clean approach that cleanly separates your L<Catalyst> application
-from enabled middleware.
-
-However there may be cases when you'd rather enable middleware via you L<Catalyst>
-application, rather in a stand alone file. For example, you may wish to let your
-L<Catalyst> application have control over the middleware configuration, so that
-you could enable certain middleware in production, and others development. You
-can do this with an external C<.psgi> file, but it can get complex and ugly fast
-if your use of middleware is complex. Also, if middleware is part of the way
-your application works, it makes sense from a design viewpoint for the middleware
-to be part of the application rather than a layer on top.
-
-Starting on v5.90050, L<Catalyst> allows you to add middleware as part of your
-normal setup and configuration. Let's port the above example:
-
- package MyApp::Web;
-
- use Catalyst;
-
- __PACKAGE__->config(
- psgi_middleware => [
- 'Debug',
- 'Session' => {store => 'File'},
- ]);
-
-C<psgi_middleware> is just a key in your application configuration, so you can
-use other tools in the configuration ecosystem (such as
-L<Catalyst::Plugin::ConfigLoader>) to manage it. The key takes an ArrayRef
-where elements can be the name of distribution under L<Plack::Middleware> (the
-named middleware C<Debug> would refer to L<Plack::Middleware::Debug>, an
-instance of a middleware object, a subroutine reference for inlined middlware
-or middleware under your application namespace. The following is all correctly
-formed:
-
- __PACKAGE__->config(
- 'psgi_middleware', [
- 'Debug',
- '+MyApp::Custom',
- $stacktrace_middleware,
- 'Session' => {store => 'File'},
- sub {
- my $app = shift;
- return sub {
- my $env = shift;
- $env->{myapp.customkey} = 'helloworld';
- $app->($env);
- },
- },
- ],
- );
-
-See L<Catalyst/PSGI-MIDDLEWARE> for more details.
-
-=head1 Why Use Middleware?
-
-Use middleware in cases where there is existing middleware who's functionality
-you want to reuse in your L<Catalyst> application, or when you have some logic
-that is global to the request / response cycle that you wish to isolate. Very
-often when you are thinking of writing a L<Catalyst::Plugin> or hacking into
-L<Catalyst::Request> / L<Catalyst::Response> or you are using controller end
-actions to modify the outgoing response, then middleware might be a better
-choice.
-
-=head1 How Does it Work?
-
-Think of middleware as layers in an onion, with you application at the center.
-As a request comes in, you go down each layer in the onion til you hit the
-the application. Then, as you go out, you pass each layer again (but this time
-from the center outward).
-
-So as the request comes in, your middleware can access and alter the psgi $env.
-On the way out it can alter the response.
-
-You can even use middleware as a way to produce responses (such as to have a
-default not found page, or to catch exceptions that your application throws)
-or to redirect the flow of the request to a totally different application.
-For example, you might wish to port your old application to run on L<Catalyst>;
-you can wrap some middleware to send the request to your new L<Catalyst> based
-application, and if it returns a 'not found' response, allow it to continue on
-to the old application. In this way you can port your website to a modern
-framework 'url by url' rather than try to do a ground up redo in one release.
-
-See L<Plack::Middleware> for more on middleware.
-
-=head1 A Full Example
-
-Let's build a L<Catalyst> application that uses middleware to redirect some
-of the requests to a L<Web::Simple> application. A good use for something
-like this could be a case when you have some time sensitive responses, such
-as autocomplete or similar json API and your L<Catalyst> application has too
-much overhead (sessions, authentication, etc.) To make it more fun, lets
-have the L<Web::Simple> application use some components from your main
-L<Catalyst> application (lets say to use the L<Catalyst> view) so we can see
-how this approach lets you mix and match the best of both worlds.
-
-Full example code can be found here:
-
-L<https://github.com/perl-catalyst/2013-Advent-Staging/tree/master/PSGI-Middleware>
-
-Let's start with the application class:
-
- package MyApp::Web;
-
- use Catalyst;
- use MyApp::Web::Simple;
-
- __PACKAGE__->config(
- psgi_middleware => [
- 'Delegate' => { psgi_app =>
- MyApp::Web::Simple->new(
- app => __PACKAGE__
- )->to_psgi_app },
- ]);
-
- __PACKAGE__->setup;
-
-So there's a few things going on here but the gist of it is that we are saying
-this application uses the 'Delegate' middleware. Since we didn't specify the
-full middleware namespace, it will look first for L<MyApp::Web::Middleware::Delegate>
-and then L<Plack::Middleware::Delegate> (this is so that you can wrap and customize
-existing middleware, should you choose). In this case there is a
-C<MyApp::Web::Middleware::Delegate> so that gets passed a single parameterized
-argument, which in this case is pointing to your L<Web::Simple> based
-application. That, BTW has an argument which points back to your L<Catalyst>
-application, but we'll look at that in a bit! Lets look at our custom middleware:
-
- package MyApp::Web::Middleware::Delegate;
-
- use strict;
- use warnings;
- use base 'Plack::Middleware';
- use Plack::Util::Accessor 'psgi_app';
-
- sub call {
- my ($self, $env) = @_;
- my $psgi_response = $self->psgi_app->($env);
-
- return $psgi_response->[0] == 404 ?
- $self->app->($env) : $psgi_response;
- }
-
-Since L<Catalyst> is L<Moose> based, we tend to use L<Moose> quite a bit, however
-in the case of this middleware there's no reason to not just follow how most other
-middleware projects work and just inherit from L<Plack::Middleware>.
-
-There's one function of important here, which middleware expects you to define,
-which is C<call>. This function is basically that onion layer I spoke of before
-where you get the C<PSGI> $env on the way in, and then access to the $psgi_response
-on the way out.
-
-What this code is saying is, "I get $env and pass it to C<psgi_app> (which is
-the L<Web::Simple> application that got added in the L<Catalyst> application
-configuration) and if that application returns a code 404 (Not Found) then send
-$env along to the L<Catalyst> application, otherwise use the L<Web::Simple>
-response and short circuit calling L<Catalyst>."
-
-BTW, this functionality is not unlike what you might see with some common
-middleware on CPAN (such as L<Plack::App::Cascade>) but I thought it instructive
-to write our own, just for learning.
-
-Ok great, lets look at the nice and speedy L<Web::Simple> application!
-
- package MyApp::Web::Simple;
-
- use Web::Simple;
-
- has 'app' => (is=>'ro', required=>1);
-
- sub render_hello {
- my ($self, $where) = @_;
- return $self->app->view('HTML')->render($self->app,
- 'hello.html', {where=>'web-simple'} );
- }
-
- sub dispatch_request {
- my $self = shift;
- sub (/websimple-hello) {
- [ 200, [ 'Content-type', 'text/html' ],
- [$self->render_hello]
- ],
- },
- }
-
-Basically L<Web::Simple> will handle the URL "/websimple-hello" and return a
-404 Not Found response for anything else (the 404 Not Foundis actually built
-into L<Web::Simple>, unlike L<Catalyst> where the default is to not return
-anything at all.)
-
-When rendering the response it uses the HTML View you defined in the base
-L<Catalyst> application. So you can use a similar technique to share views
-and models between applications and frameworks but all running under the same
-core application. Lets glance at the View template (hello.html):
-
- <html>
- <head>
- <title>Hello From [% where %]</title>
- </head>
- <body>
- <h1>Hello From [% where %]</h1>
- </body>
- </html>
-
-Not a complicated template, but it gets the idea across. This expects one
-variable C<where> which in L<Catalyst> gets stuffed into the stash, but in
-L<Web::Simple> we just add it to the C<render> arguments of the view.
-
-Other possible uses for this approach code be:
-
-=over 4
-
-=item Using L<Web::Machine> to handle your API
-
-L<Web::Machine> has great support for writing truely RESTful applications. What
-it doesn't have is L<Catalyst>'s great ability to bring data from lots of
-models, or to generate HTML views. This way you can use the best tool for the
-given job without be forced to given up the ease and structure of L<Catalyst>.
-
-=item Converting a legacy application to run on L<Catalyst>
-
-This lets you port your web application over 'url by url'. You can even use
-this to help you refactor an existing L<Catalyst> application that has gotten
-a bit more crusty over the years than you'd prefer.
-
-=back
-
-Other ideas might commend themselves to you. Lets see the L<Catalyst> side
-of things and look at the controller:
-
-package MyApp::Web::Controller::Root;
-
- use Moose;
- use MooseX::MethodAttributes;
-
- extends 'Catalyst::Controller';
-
- sub start : Chained('/')
- PathPrefix CaptureArgs(0)
- {
- my ($self, $ctx) = @_;
- }
-
- sub hello : Chained('start')
- PathPart('catalyst-hello') Args(0)
- {
- my ($self, $ctx) = @_;
- $ctx->stash(where=>'Catalyst');
- $ctx->forward($ctx->view('HTML'));
- }
-
- __PACKAGE__->config(namespace => '' );
- __PACKAGE__->meta->make_immutable;
-
-The chaining here might be a bit gratuitious but you get the idea I hope.
-Finallty lets see the test cases to make sure everything works as expected:
-
- use Test::Most;
- use Catalyst::Test 'MyApp::Web';
-
- ok( get('/catalyst-hello') =~ /Catalyst/ );
- ok( get('/websimple-hello') =~ /web-simple/ );
-
- done_testing;
-
-Go see the linked code on Github:
-
-L<https://github.com/perl-catalyst/2013-Advent-Staging/tree/master/PSGI-Middleware>
-
-For more code and more tests to see how the whole distribution is put
-together.
-
-=head1 Final Comments
-
-I personally see a big role for middleware in future L<Catalyst>. When
-it comes down to it, the idea of a L<Plack::Component> (which is the
-parent class of L<Plack::Middleware>) is not terrible different from
-L<Catalyst::Component>...
-
-Stay tuned!
-
-=head1 Also See
-
-L<Catalyst::Plugin::EnableMiddleware> gives you similar functionality for
-older versions of L<Catalyst>.
-
-=head1 Summary
-
-Middleware is another way to build and extend your L<Catalyst> based
-applications. It can be used to bring functionality from other common
-code (opensource or otherwise) and it opens the door to new approaches
-to solving many existing problems. Next time you need better control
-over your L<Catalyst> request and response, or you think of using a
-global plugin, ask yourself if middleware might not be the better option.
-
-
-=head1 Author
-
-John Napiorkowski L<email:jjnapiork at cpan.org>
-
-=cut
Deleted: trunk/examples/CatalystAdvent/root/2013/05.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/05.pod 2013-12-02 02:42:17 UTC (rev 14469)
+++ trunk/examples/CatalystAdvent/root/2013/05.pod 2013-12-02 08:16:06 UTC (rev 14470)
@@ -1,124 +0,0 @@
-=head1 Title
-
-Using the L<Hash::MultiValue> configuration option in L<Catalyst>
-
-=head1 Overview
-
-L<Catalyst> has always supported HTML POST form parameters and
-query parameters using a simple API via the L<Catalyst::Request>
-object. However this API has a flaw when said parameters can be
-multi, leading to ackward boilerplate defensive code. The L<Plack>
-community introduced L<Hash::MultiValue> as one approach to better
-manage this issue. Starting in version 5.90050, L<Catalyst> lets
-you use L<Hash::MultiValue> via a configuration option so that you
-may use this approach in your L<Catalyst> code as well.
-
-=head1 Introduction
-
-Have you ever written code like this:
-
- sub myaction :Path(something) {
- my $p = (my $c = pop)->request->body_parameters;
- my @vals = ref $p->{field} eq 'ARRAY'
- ? @{$p->{field}}
- : ($p->{field});
- }
-
-You might write code like this if the incoming body (or query) parameters can
-be single or arrays. You might have a form with checkboxes or with select with
-multiple options. In that case you need to do that ugly dance of checking to
-see if the field is an arrayref or a single value.
-
-One solution to this problem is to use an instance of L<Hash::MultiValue> to
-contain your field parameters. L<Hash::MultiValue> comes out of L<Plack> and
-was a Perlish port of a similar class in the Python WSGI framework C<Webob>.
-Its one way to approach this problem, since it gives you a consistent API
-to dealing with query and form parameters.
-
-=head1 How Does it Work?
-
-Instead of $c->request->body_parameters (and ->query_parameters) containing
-a simple hash whose values could be single or could be an arrayref, we use
-an instance of L<Hash::MultiValue> instead. You enable this as a global
-L<Catalyst> configuration option, for example:
-
- package MyApp;
-
- use Catalyst;
-
- __PACKAGE__->config(use_hash_multivalue_in_request=>1);
- __PACKAGE__->setup;
-
-Now, whenever you call for request parameters, we build an instance of
-L<Hash::MultiValue> and store that instead of the HashRef that classic versions
-of L<Catalyst> uses. L<Hash::MultiValue> has an API that lets you get the
-values of field keys in a consistent manner no matter what the actual underlying
-values are. In additional, it uses overloading to support the classic 'as an
-arrayref' interface, which works just like L<Catalyst> does today, except it
-will always return a single value (whichever the last one was). This is likely
-a preferable behavior than the current, which can give you one or the other
-and leading your code to error out in those cases. Here's an example:
-
- # suppose incoming POST parameters are such
-
- name: John
- age: 25
- age: 44
-
- sub myaction :Path(something) {
- my $p = (my $c = pop)->request->body_parameters;
-
- {
- my $name = $p->{name}; # 'John'
- my $age = $p->{age}; # 44
- }
-
- {
- my $name = $p->get('name'); # 'John'
- my $age = $p->get('age'); # 44
- }
-
- my @ages = $p->get_all('age'); # 26,44
- }
-
-The approach is arguable less prone to error and reduces the need to write
-defensive code to figure out when form parameters are single values or are
-array referenences.
-
-=head1 A Full Example
-
-See the example application
-
-L<https://github.com/perl-catalyst/2013-Advent-Staging/tree/master/Hash-MuliValue>
-
-For more help and test cases.
-
-=head1 Caveats and Gotchas
-
-Although L<Hash::MultiValue> overloads to support the 'as hashref' interface,
-it is quite likely to have different values in the multi field case, and as a
-result it might break existing code (or reveal previously undetected issues
-with your code, depending on your outlook).
-
-if you are in the habit of modifying the parameter hashref directly (for example
-adding or deleting keys) like so:
-
- $c->req->body_parameters->{some_new_field} = 'bogus field';
-
-That won't work with L<Hash::MultiValue> which instead offers an API for adding
-and deleting fields in a consistent way.
-
-=head1 Summary
-
-L<Hash::MultiValue> is an approach to better encapsulate access to classic HTML
-form POST and query parameters. It provides a consistent API and smooths over
-some common issues you might have with the existing L<Catalyst> approach. If
-so, you can enable this new feature with a single, global configuration option!
-
-=head1 Also See
-
-=head1 Author
-
-John Napiorkowski L<email:jjnapiork at cpan.org>
-
-=cut
Deleted: trunk/examples/CatalystAdvent/root/2013/06.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/06.pod 2013-12-02 02:42:17 UTC (rev 14469)
+++ trunk/examples/CatalystAdvent/root/2013/06.pod 2013-12-02 08:16:06 UTC (rev 14470)
@@ -1,130 +0,0 @@
-=head1 Title
-
-Using Body Data Handlers in Catalyst
-
-=head1 Overview
-
-The v5.90050 Release of Catalyst introduced a new way to process request body
-content. Out of the box L<Catalyst> now offers basic support for request
-content types of JSON and some of the more common approaches to nesting data
-structures in HTML form parameters. You can modify how this works globally
-by adding support for additional types or overriding default types.
-
-=head1 Introduction
-
-L<Catalyst> has supported classic HTML Form type POST parameters, as well
-as GET request query parameters for a long time. Although the built in support
-has a few gotchas (many of which we fixed by allowing you to configure
-L<Hash::MultiValue> as field storage for request parameters) it has generally
-served well.
-
-However times have changed quite a bit since L<Catalyst> was first put on CPAN.
-Common alternatives for client - server communication, typically using JSON,
-are the order of the day, and its normal for a web framework to support at
-least that out of the box. L<Catalyst> has long met this need via the external
-framework L<Catalyst::Action::REST> which is a toolkit for parsing and rendering
-various types of content. However L<Catalyst::Action::REST> can quite often be
-a lot more than you need. If you are just trying to support AJAXy style HTML
-form submission and validation, you probably don't want all the extra bits and
-structure that L<Catalyst::Action::REST> gives you. So, starting in version
-5.90050, L<Catalyst> has a new system for parsing common incoming request
-bodies, which out of the box will support JSON as well as the more common
-idioms for nested form parameters. We'll take a look out how this works for
-JSON request bodies and how you can modify and augment this new 'body data'
-system
-
-=head1 How Does it Work?
-
-There's two parts to the system. The first is part of L<Catalyst> application
-class, and takes the form of a new configuration option and key C<data_handlers>.
-It works like this:
-
- package MyApp;
-
- use Catalyst;
-
- __PACKAGE__->config(
- data_handlers => {
- 'application/json' => sub {
- # $_ is localized to a readable filehandle of the request body content.
- },
- },
- );
-
-Basically L<Catalyst> defines a new global configuration option C<data_handlers>
-which is a hashref where the key is a standard MIME content-type and the value
-is a subroutine reference that is intended to parse that content type.
-
-The subroutine reference has C<$_> localized to the filehandle of the request
-body content, so you can read the content any way you like (you can use non
-blocking techniques should an event loop exist although it is doubtful that
-will help much since the filehandle has already been fully buffered).
-
-There is no defined return type. You can return a parsed data as a hashref
-or return an object, whatever makes sense for the content type and the size
-you are dealing with. For example, here's the code for the built in JSON
-parsing:
-
- 'application/json' => sub {
- Class::Load::load_first_existing_class('JSON::MaybeXS', 'JSON')
- ->can('decode_json')->(do { local $/; $_->getline });
- },
-
-Basically we just slurp up the JSON in one big line and parse it all in one
-go. Please note this might not be the best approach if the incoming JSON
-is expected to be very large!
-
-Your hashref under C<data_handlers> can include as many types as you deem
-required, and you can override the build in JSON parsing since we apply
-you customizations ontop of the defaults.
-
-So, how do you access this new parsed content? We've added a new attributes
-to L<Catalyst::Request> called C<body_data>. This attribute is lazy, so
-unless you actually ask for it, we don't attempt to parse any request content
-against the defined L<data_handlers>. So if you wrote a ton of your own
-JSON decoding stuff, and/or are using L<Catalyst::Action::REST> you can
-keep on doing that without any impact at all on your request overhead.
-
-Here's how this could look in you controller. Lets assume the incoming is
-C<application/json> like "{'name':'Jason','age':'25'}":
-
- sub update_user : POST Path(/User) Consumes(JSON) {
- my $p = (my $c = pop)->req->body_data;
- $c->res->body("My name is $posted->{name} and my age is $p->{age}");
- }
-
-Basically this is very similar to the request object's C<body_parameters>
-method but is data focused on alternative POSTed or PUT request content.
-
-The built in JSON decoder just returns a hashref, which is similar to many
-other frameworks but there's nothing stopping you from returning any type
-of scalar reference, including an object.
-
-So that's really it!
-
-=head1 Caveats, gotchas...
-
-Although unicode is supported out of the box with L<Catalyst> information
-in the C<$_> localized filehandle is basically just as it comes from the
-client. You may need to do additional decoding. This might change in
-the future, but in the absence of clear requirements the authors felt it best
-to not guess to far in advance.
-
-=head1 Summary
-
-Starting in version 5.90050, L<Catalyst> offers useful support for JSON
-POSTed content out of the box, reducing one's need to lean on heavier
-addins such as L<Catalyst::Action::REST> while maintaining our desire
-to keep L<Catalyst> modular and flexible.
-
-=head1 For More Information
-
-Setting data handler configutation: L<Catalyst/DATA-HANDLERS>
-
-Accessing the parsed content: L<Catalyst::Request/req-body_data>
-
-=head1 Author
-
-John Napiorkowski L<email:jjnapiork at cpan.org>
-
-=cut
Deleted: trunk/examples/CatalystAdvent/root/2013/07.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/07.pod 2013-12-02 02:42:17 UTC (rev 14469)
+++ trunk/examples/CatalystAdvent/root/2013/07.pod 2013-12-02 08:16:06 UTC (rev 14470)
@@ -1,332 +0,0 @@
-=head1 Title
-
-How To Hack On Catalyst Core - Adding $response->from_psgi_response
-
-=head1 Overview
-
-A lot of people want to contribute to the L<Catalyst> project, but get scared
-off due to an assumption that the code is highly complex and requires an
-experts touch. This article will review how we added the feature that allows
-a L<Catalyst::Response> to be filled from the response of a PSGI appliction.
-
-See L<Catalyst::Response/from_psgi_response> for more.
-
-=head1 Introduction
-
-L<Catalyst> has been L<PSGI> native for a while, but to date has not really
-taken much advantage of that fact beyond the ability to use L<Plack> based
-web servers in replacement of the L<Catalyst::Engine> namespace. This is not a
-small think to be sure, but it would be great if L<Catalyst> could not flex its
-L<PSGI> abilities even more. One thing that would be possible is for L<Catalyst>
-to allow one to populate a reponse via a L<Plack::App> such as L<Plack::App::File>
-(which would make a possible replacement for L<Catalyst::Plugin::Static::Simple>).
-Or you could use L<Catalyst> to mount other frameworks, such as L<Web::Machine>
-which excel in a particular domain such as building RESTful APIs.
-
-So, how can one do this? Let's look into it!
-
-=head1 Prequisite Tasks
-
-Two features added to L<Catalyst> in previous releases where necessary to
-perform this task properly. The first was to allow one to have more control
-over how we write output to the server and out to the requesting client. This
-was the feature to expose the writer filehandle, and it was primarily added
-to make it easier to write asynchronous and/or streaming output, although as
-we will see, that feature enabled us to do stuff we'd not thought of at that
-point.
-
-See L<Catalyst::Response/res-write_fh> for more on using $Response->write_fh.
-
-This was needed as we will see later to make sure we could properly deal with
-a streaming or delayed PSGI response. Without it we'd be forced to fully buffer
-the response, which would be a shame since L<Catalyst> can support these types
-of responses.
-
-For more information see L<PSGI/Delayed-Response-and-Streaming-Body>.
-
-The second feature was added as a development version of this summer past, and
-it supports adding an input buffer object should one not exist in the case
-where the underlying L<Plack> engine does not provide one. This is needed because
-L<Catalyst> slurps up any POST or PUT content that might be part of the request
-and that means that any PSGI application that gets called later on won't get
-that (in other words it won't have access to POSTed form parameters or file
-uploads). Some PSGI webservers like L<Starman> provide a readable, buffered
-filehandle of this request content, others (like ModPerl and FastCGI) do not.
-This leads to issues where some code works fine in development (when you are
-using L<Starman>) but then break in a FastCGI (or *shudder* mod_perl) setup.
-So now in newer versions of L<Catalyst> when it is slurping up the request
-content, if we notice there is no input buffer, we create one so that anyone
-that needs it down the line will get access to it.
-
-Between these two features we have everything in L<Catalyst> we need to complete
-this task.
-
-=head1 The Test Cases
-
-Prior to working on this task, I wrote out the minimal test cases in the form
-of a new controller test. Here's a version of those test cases:
-
- package TestFromPSGI::Controller::Root;
-
- use base 'Catalyst::Controller';
-
- sub from_psgi_array : Local {
- my ($self, $c) = @_;
- my $res = sub {
- my ($env) = @_;
- return [200, ['Content-Type'=>'text/plain'],
- [qw/hello world today/]];
- }->($c->req->env);
-
- $c->res->from_psgi_response($res);
- }
-
- sub from_psgi_code : Local {
- my ($self, $c) = @_;
-
- my $res = sub {
- my ($env) = @_;
- return sub {
- my $responder = shift;
- return $responder->([200, ['Content-Type'=>'text/plain'],
- [qw/hello world today2/]]);
- };
- }->($c->req->env);
-
- $c->res->from_psgi_response($res);
- }
-
- sub from_psgi_code_itr : Local {
- my ($self, $c) = @_;
- my $res = sub {
- my ($env) = @_;
- return sub {
- my $responder = shift;
- my $writer = $responder->([200, ['Content-Type'=>'text/plain']]);
- $writer->write('hello');
- $writer->write('world');
- $writer->write('today3');
- $writer->close;
- };
- }->($c->req->env);
-
- $c->res->from_psgi_response($res);
- }
-
-So if you go and read the L<PSGI> documentation, you know there's three types
-of responses we need to deal with. The first is the classic PSGI example
-of a tuple (ArrayRef of Status, Headers and BodyArray/Body Filehandle). The
-second and third are variations of delayed response. These types of responses
-return a coderef instead of a tuple and can including streaming types of
-responses (see the third action C<from_psgi_code_itr> for example of this).
-
-Ok, so we created what are now failing test cases. Lets write the method to
-make them pass!
-
-=head1 The Code
-
-Let's take a look at the full method added to L<Catalyst::Response> and then
-well do a walkthrough:
-
- sub from_psgi_response {
- my ($self, $psgi_res) = @_;
- if(ref $psgi_res eq 'ARRAY') {
- my ($status, $headers, $body) = @$psgi_res;
- $self->status($status);
- $self->headers(HTTP::Headers->new(@$headers));
- if(ref $body eq 'ARRAY') {
- $self->body(join '', grep defined, @$body);
- } else {
- $self->body($body);
- }
- } elsif(ref $psgi_res eq 'CODE') {
- $psgi_res->(sub {
- my $response = shift;
- my ($status, $headers, $maybe_body) = @$response;
- $self->status($status);
- $self->headers(HTTP::Headers->new(@$headers));
- if($maybe_body) {
- if(ref $maybe_body eq 'ARRAY') {
- $self->body(join '', grep defined, @$maybe_body);
- } else {
- $self->body($maybe_body);
- }
- } else {
- return $self->write_fh;
- }
- });
- } else {
- die "You can't set a Catalyst response from that, expect a valid PSGI response";
- }
- }
-
-The example usage is as follows:
-
- package MyApp::Web::Controller::Test;
-
- use base 'Catalyst::Controller';
- use Plack::App::Directory;
-
- my $app = Plack::App::Directory
- ->new({ root => "/path/to/htdocs" })
- ->to_app;
-
- sub myaction :Local {
- my ($self, $c) = @_;
- $c->response->from_psgi_response(
- $app->($c->request->env));
- }
-
-So basically given a L<PSGI> response, as you would get from running it against
-the current $env (part of the L<PSGI> specification), let that response be
-the response that L<Catalyst> returns. We could use a bit of sugar here to
-make it easier to mount the L<PSGI> application under the current action
-namespace (for example) but this really is the minimal viable useful feature
-upon which all that coould later be built, should we find it useful to do so.
-
-Alll things being equal, I'd prefer to see this method refactored a bit, rather
-than one big method with so many conditionals. However I was concerned about
-adding to the L<Catalyst::Response> namespace, particularly since the request
-object is something L<Catalyst> explicitly makes public and replacable. We have
-no idea whats going on in the darkpan, so its best to err on the side of making
-the smallest footprint in the code that we can.
-
-=head1 Code Walkthrough
-
-Starting from the top:
-
- sub from_psgi_response {
- my ($self, $psgi_res) = @_;
-
-Declare the new method and slurp up the expected arguments. In this case we
-expect just a single argument which is the L<PSGI> compliant response. This
-is sure to be a reference of some type, but we'll need to inspect it a bit
-to figure out the correct handling:
-
- if(ref $psgi_res eq 'ARRAY') {
- my ($status, $headers, $body) = @$psgi_res;
- $self->status($status);
- $self->headers(HTTP::Headers->new(@$headers));
-
-So if you recall from the test case, we know that the L<PSGI> response is going
-to be an ArrayRef or a CodeRef. Let's handle the easy case first, since if the
-response is an ArrayRef that means its all complete and we can just map it to
-the L<Catalyst::Response> directly. As you can see mapping the C<status> and
-C<headers> is straightforward. Let's see the code to map the C<body>:
-
- if(ref $body eq 'ARRAY') {
- $self->body(join '', grep defined, @$body);
- } else {
- $self->body($body);
- }
-
-This is a bit more tricky since the C<body> can be a filehandle like object
-or an ArrayRef. L<Catalyst> allows for string bodies or filehandles, which
-means in the case of it being an ArrayRef we need to flatten it to a string.
-
-I seriously considered changing L<Catalyst> to allow for a ArrayRef body,
-but in the end I felt it was too much risk for what seemed like small reward
-at this time. Perhaps in a future release?
-
-So, what about the second case, when the L<PSGI> response is a coderef?
-
- } elsif(ref $psgi_res eq 'CODE') {
-
-The specification says when the response is a coderef (this is considered a
-delayed response) the server should obtain the actual response by calling that
-coderef with coderef of its own. In this case since L<Catalyst> is hosting the
-L<PSGI> application, we can consider it the server for now. Lets build the
-coderef we want to pass to the delayed response (if you look at L<PSGI> and
-related L<Plack> examples, this second coderef is often call the responder,
-and conventionally called $responder or $respond in code examples).
-
- $psgi_res->(sub {
- my $response = shift;
- my ($status, $headers, $maybe_body) = @$response;
- $self->status($status);
- $self->headers(HTTP::Headers->new(@$headers));
-
-The L<PSGI> application that is returning a delayed response has two options
-but the both start the same way. It must call the $responder coderef with
-at least the first two parts of the classic L<PSGI> tuple, the C<status> and
-C<headers>. It then may or may not return the C<body> arrayref or filehandle
-at this point. If you refer back to the test case we wrote for L<Catalyst>
-you can see what such an application would look like:
-
- my $psgi_app = sub {
- my $responder = shift;
- return $responder->([200, ['Content-Type'=>'text/plain'],
- [qw/hello world today2/]]);
- };
-
-In this example the L<PSGI> application is returning the full tuple. This
-is the case we handle first:
-
- if($maybe_body) {
- if(ref $maybe_body eq 'ARRAY') {
- $self->body(join '', grep defined, @$maybe_body);
- } else {
- $self->body($maybe_body);
- }
- }
-
-Here we find that the C<body> is ready to go, so we do the "is it an arrayref
-or a filehandle" dance again and then we are done.
-
-However there's yet one final option. The L<PSGI> application may choose to
-not return the C<body> immediately. You would do this in cases where the
-body response is streamed, or if you are running the application in an event
-loop and the body is being created in response to events (such as the result
-of a database query). In this case, the $responder coderef is expected to
-return a L<PSGI> writer object, which does at least two methods, C<write> and
-C<close>. This way your application can continue to stream output via the
-C<write> method and when its done you call C<close>.
-
-Its actually a bit more complicated, since ideally you'd also monitor for the
-case where you lose the connection between the client and server, but for ease
-of illustration, lets assume the streaming response is just like in the test
-case above:
-
- my $psgi_app = sub {
- my $responder = shift;
- my $writer = $responder->([200, ['Content-Type'=>'text/plain']]);
- $writer->write('hello');
- $writer->write('world');
- $writer->write('today3');
- $writer->close;
- };
-
-This is a very trivial case, but it shows the basics of the interface. How do
-we handle this?
-
- else {
- return $self->write_fh;
- }
-
-The C<write_fh> accessor of L<Catalyst::Response> gives you the raw writer
-object which has been passed down to L<Catalyst> from the server under which
-it runs. All such objects must do the C<write> and C<close> methods but the
-actual clase of the object will be specific to the server you are running
-L<Catalyst> on. The C<writer> object gets returned up to the delayed L<PSGI>
-application via the C<responder> for that case when the application does not
-provide the full C<body>.
-
-And that's the walkthrough!
-
-=head1 Prior Art
-
-Much of the inspiration and incentive to do this work came from
-L<Catalyst::Action::FromPSGI>
-
-=head1 Summary
-
-Diving into Catalyst codebase can be a bit daunting, due to its age and how its
-changed over the years. By detailing the steps involved in extending L<Catalyst>
-its our hope you will have a better understanding of the process and have an
-easier time should you try yourself.
-
-=head1 Author
-
-John Napiorkowski L<email:jjnapiork at cpan.org>
-
-=cut
Deleted: trunk/examples/CatalystAdvent/root/2013/08.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/08.pod 2013-12-02 02:42:17 UTC (rev 14469)
+++ trunk/examples/CatalystAdvent/root/2013/08.pod 2013-12-02 08:16:06 UTC (rev 14470)
@@ -1,170 +0,0 @@
-=head1 Title
-
-Matching Actions on Request Content Types
-
-=head1 Overview
-
-A quick example of how to use the Request Content Type matching feature
-in L<Catalyst> version 5.90050+.
-
-=head1 Introduction
-
-Beginning in the v5.90050 release of L<Catalyst> we introduced into core the
-ability to match your controller actions to the content types of incoming
-HTTP requests. This allows you to match actions to the contents of the
-HTTP request content type header. As a result, you can dispatch to your
-actions based on if the incoming request is a JSON post, a classic form
-data post, or some other type.
-
-=head1 Why dispatch on Request Content Type?
-
-Modern web developers consider RESTful principles when crafting web APIs
-and in creating meaninful URL structures for thier websites. One core principle
-of REST is that a given resource (in this case a URL) can have many
-representations (HTML, XML, JSON, etc.) In the past, many people used a
-L<Catalyst> addin, L<Catalyst::Action::REST>, which provided a toolkit to
-deserialize many different content types and provide them to an action. This
-works well and we still recommend L<Catalyst::Action::REST> for this and for
-many of its other features. However there are cases when you want to process
-things differently depending on the request content type. In addition, there
-might be times when you don't need all the power and features of
-L<Catalyst::Action::REST> but still want to dispatch on incoming request types
-(for example you might have a website with a form and you'd like to support
-both JSON and classic HTML POSTing). In those cases the ability to dispatch to
-a given action based on matching a content type is useful.
-
-=head1 How Does it Work?
-
-Let's look at some example actions:
-
- sub as_json : POST Path('/echo')
- Consumes('application/json') { ... }
-
- sub as_formdata : POST Path('/echo')
- Consumes('application/x-www-form-urlencoded') { ... }
-
-In this example the same URL ('/echo') would be server by either JSON or by
-classic form data. The L<Catalyst> dispatcher will choose the correct action
-based on the information tagged to the action by the subroutine attribute
-C<Consumes>. The generic form of usages is "Consumes($type)" where $type is
-a standard content type. Here's a few of the more common types you might
-encounter:
-
-=over 4
-
-=item application/json
-
-JSON encoded data "{'message' : 'hello'}"
-
-=item application/x-www-form-urlencoded
-
-HTML form post
-
-=item multipart/form-data
-
-Form posting with file uploads
-
-=back
-
-Since there's several content types that are in common usage, we provide
-shortcuts, which work in the form "Consumes($shortcut)" where $shortcut is:
-
- JSON => 'application/json',
- JS => 'application/javascript',
- PERL => 'application/perl',
- HTML => 'text/html',
- XML => 'text/xml',
- Plain => 'text/plain',
- UrlEncoded => 'application/x-www-form-urlencoded',
- Multipart => 'multipart/form-data',
- HTMLForm => ['application/x-www-form-urlencoded','multipart/form-data'],
-
-And would look like:
-
- sub as_json : POST Path('/echo')
- Consumes(JSON) { ... }
-
- sub as_formdata : POST Path('/echo')
- Consumes(HTMLForm) { ... }
-
-As with other such subroutine attributes, you can match more than one on a
-given action (which does an OR style match).
-
- sub is_more_than_one
- : Chained('start')
- : Consumes(UrlEncoded)
- : Consumes(Multipart)
-
-See L<Catalyst::Controller/Consumes> and L<Catalyst::ActionRole::ConsumesContent>
-for more details and examples.
-
-=head1 A Full Example
-
-An example controller:
-
- package MyApp::Controller::Root;
-
- use base 'Catalyst::Controller';
-
- sub as_json : POST Path('/echo')
- Consumes('application/json') {
- my ($self, $c) = @_;
- $c->response->body(
- $c->request->body_data->{message});
-
- }
-
- sub formdata : POST Path('/echo')
- Consumes('application/x-www-form-urlencoded') {
- my ($self, $c) = @_;
- $c->response->body(
- $c->request->body_parameters->{message});
- }
-
-You should note the use the new L<Catalyst::Request> method C<body_data>
-to parsing incoming JSON. This was added in v5.90050 in the Fall of 2013.
-For more information on C<body_data> see L<Catalyst::Request/req-body_data>
-and L<Catalyst/DATA-HANDLERS>.
-
-The test case for this controller:
-
- use Test::Most;
- use Catalyst::Test 'MyApp';
- use HTTP::Request::Common;
- use JSON::MaybeXS;
-
- {
- ok my $req = POST '/echo',
- Content_Type => 'application/json',
- Content => encode_json +{message=>'test'};
-
- ok my $res = request $req;
-
- is $res->content, 'test', 'Handles JSON post';
- }
-
- {
- ok my $req = POST '/echo', [message=>'test'];
- ok my $res = request $req;
-
- is $res->content, 'test', 'Handles classic HTML post';
- }
-
- done_testing;
-
-You can see the full application source on Github:
-
-L<https://github.com/perl-catalyst/2013-Advent-Staging>.
-
-=head1 Summary
-
-Request content matching is a useful feature to have in Core L<Catalyst> which
-lets you make more meaningful URLs. It also plays nice with existing addons
-such as L<Catalyst::Action::REST> when you are using L<Catalyst> to craft your
-web APIs.
-
-=head1 Author
-
-John Napiorkowski L<email:jjnapiork at cpan.org>
-
-=cut
Deleted: trunk/examples/CatalystAdvent/root/2013/09.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/09.pod 2013-12-02 02:42:17 UTC (rev 14469)
+++ trunk/examples/CatalystAdvent/root/2013/09.pod 2013-12-02 08:16:06 UTC (rev 14470)
@@ -1,330 +0,0 @@
-=head1 TITLE
-
-An Example Catalyst Plugin - Catalyst::Plugin::RunRequest
-
-=head1 OVERVIEW
-
-Port L<Web::Simple>'s feature C<run_test_request> to a L<Catalyst> plugin.
-
-=head1 INTRODUCTION
-
-Generally I tell people there are few good reasons to write a L<Catalyst::Plugin>.
-As a unit of reusability, its a pretty heavy hammer, since a plugin become part
-of your application and context, that means its available everywhere all the time
-and of course it also means that your $c and $app are a little bigger memory wise
-and you incur any startup penalties for every single request. With so many ways
-to wrap and reuse functionality (as a Model, ControllerRole or ActionRole, for
-example) there's nearly never a good reason to write a Plugin. And now that
-L<Catalyst> is L<PSGI> native, I usually say anything related to the global
-request or response is probably better off written as L<Plack::Middleware>.
-
-However, if you are looking for something that is global, and is related to
-application functionality, a plugin is still a rational option. Here's an
-example plugin I did that mimics some functionality from another Perl web
-framework, L<Web::Simple>.
-
-=head1 Web::Simple::Application->run_test_request
-
-L<Web::Simple> has a neat feature that makes it easy to run a sample request
-in a test case or via the command line. We'll leave the CLI for now (its a bit
-trickier based on the way L<Catalyst> does setup) but as it turns out, mimicing
-the underlying function is very easy to do. It would make a rational plugin and
-its also a good opportunity to review some of Catalyst's PSGI guts.
-
-Here's how it works in L<Web::Simple>. You write a basic web application
-like so:
-
- package MyWSApp;
-
- use Web::Simple;
-
- sub dispatch_request {
- sub (GET + /helloworld) {
- [ 200, [ 'Content-type', 'text/plain' ], [ 'Hello world!' ] ]
- },
- sub (POST + /echo + %:val=) {
- [ 200, [ 'Content-type', 'text/plain' ], [ $_{val} ] ]
- },
- }
-
- __PACKAGE__->run_if_script;
-
-Now, in a test case you could write:
-
- use Test::Most;
- use MyWSApp;
-
- {
- ok my $http_response = MyWSApp->run_test_request(GET '/helloworld');
- is $http_response->content, 'Hello world!';
- }
-
- {
- ok my $http_response = MyWSApp->run_test_request(POST '/echo', [val=>'posted']);
- is $http_response->content, 'posted';
- }
-
- {
- ok my $http_response = MyWSApp->run_test_request('GET' => '/helloworld');
- is $http_response->content, 'Hello world!';
- }
-
- {
- ok my $http_response = MyWSApp->run_test_request('POST' => '/echo', {val=>'posted'});
- is $http_response->content, 'posted';
- }
-
- done_testing;
-
-In L<Web::Simple> the C<run_test_request> method accepts either a L<HTTP::Request>
-object (built by hand or via L<HTTP::Request::Common> which is my personal
-favored approach) or it can take a data structure so you don't need to load any
-additional modules (if you look carefully at the given example, its very similar
-to the L<HTTP::Request::Common> style code). The idea here is to take any sort
-of L<HTTP::Request> and get the L<HTTP::Response> out of it.
-
-So that's nice, concise and simple. Sure, L<Catalyst::Runtime> ships with
-L<Catalyst::Test> and there's even more powerful testing options on CPAN, but
-there's something to say for having a straightup solution when writing trival
-test cases, or for when you want to demo some code. So, let's write a plugin
-for L<Catalyst> that does this!
-
-=head1 The Plugin
-
-Lets take this line by line. Lets assume you've create a proper directory
-structure for a Perl distribution (look for links to Github near the end of the
-post for examples) for a new L<Catalyst> plugin called
-'Catalyst::Plugin::RunTestRequest'. Here's the start of the file that would go
-in 'lib/Catalyst/Plugin/RunTestRequest.pm'.
-
- package Catalyst::Plugin::RunTestRequest;
-
- use Moose::Role;
-
- requires 'psgi_app';
-
-In the post L<Moose> port of L<Catalyst> world, its best to write a new plugin
-as a L<Moose::Role>. We specify this role can only be composed into a class
-that has the C<psgi_app> method, which we'll see in moment is needed by the
-new method we are adding to your application class.
-
-Next, let's write the method that will be composed into your application
-subclass:
-
- sub run_test_request {
- my ($self, @req) = @_;
- my $http_request = $_test_request_spec_to_http_request->(@req);
-
- require HTTP::Message::PSGI;
- my $psgi_env = HTTP::Message::PSGI::req_to_psgi($http_request);
- my $psgi_response = $self->psgi_app->($psgi_env);
- my $http_response = HTTP::Message::PSGI::res_from_psgi($psgi_response);
-
- return $http_response;
- }
-
-The first two lines creates the method and slurps up incoming args. We will
-normalize C<@req> via an anonymous subroutine so that we are always dealing
-with an instance of L<HTTP::Request> (and I've simply cribbed a similiarly
-named method from L<Web::Simple::Application>, so I won't go into it, just give
-a big shout out to the L<Web::Simple> cabal). I'll link to the full file at
-the end of the article.
-
-Followed by the required module L<HTTP::Message::PSGI> which lets us convert
-between the various types of requests and responses we'll need to deal with.
-We C<require> this module rather than declare it as a C<use> near the top of
-the file so that we can avoid loading it in the cases when this method is
-never called (thereby saving a bit of memory) and it we also don't call the
-modules C<import> method, so we avoid importing unneeded functions into our
-namespace.
-
-Next we take the normalized L<HTTP::Request> and convert it into a HashRef
-that conforms to the L<PSGI> specification. We pass this to the C<psgi_app>
-method, which is returning a L<PSGI> application, basically a coderef that
-wants that $psgi_env we just made. This is the coderef that kicks off the
-full L<Catalyst> request / response cycle. It returns a $psgi_response,
-which we then convert to a L<HTTP::Response>. Which gets returned to the
-caller.
-
-The full plugin looks like this (and again see links to Github near the end).
-
- package Catalyst::Plugin::RunTestRequest;
-
- use Moose::Role;
-
- requires 'psgi_app';
-
- our $VERSION = '0.001';
-
- ## Block of code gratuitously stolen from Web::Simple::Application
- my $_test_request_spec_to_http_request = sub {
- my ($method, $path, @rest) = @_;
-
- # if it's a reference, assume a request object
- return $method if ref($method);
-
- if ($path =~ s/^(.*?)\@//) {
- my $basic = $1;
- require MIME::Base64;
- unshift @rest, 'Authorization:', 'Basic '.MIME::Base64::encode($basic);
- }
-
- require HTTP::Request;
-
- my $request = HTTP::Request->new($method => $path);
-
- my @params;
-
- while (my ($header, $value) = splice(@rest, 0, 2)) {
- unless ($header =~ s/:$//) {
- push @params, $header, $value;
- }
- $header =~ s/_/-/g;
- if ($header eq 'Content') {
- $request->content($value);
- } else {
- $request->headers->push_header($header, $value);
- }
- }
-
- if (($method eq 'POST' or $method eq 'PUT') and @params) {
- my $content = do {
- require URI;
- my $url = URI->new('http:');
- $url->query_form(@params);
- $url->query;
- };
- $request->header('Content-Type' => 'application/x-www-form-urlencoded');
- $request->header('Content-Length' => length($content));
- $request->content($content);
- }
-
- return $request;
- };
-
- sub run_test_request {
- my ($self, @req) = @_;
- my $http_request = $_test_request_spec_to_http_request->(@req);
-
- require HTTP::Message::PSGI;
- my $psgi_env = HTTP::Message::PSGI::req_to_psgi($http_request);
- my $psgi_response = $self->psgi_app->($psgi_env);
- my $http_response = HTTP::Message::PSGI::res_from_psgi($psgi_response);
-
- return $http_response;
- }
-
- 1;
-
-There's not a lot to it, most if it is the normalization code that lets you
-have a bit of flexibility using the method. Lets build a quick application.
-
-Here's the application class:
-
- package MyCatApp;
-
- use Catalyst 'RunTestRequest';
-
- __PACKAGE__->setup;
-
-L<Catalyst> seems to get a bad rap as needing a lot of boilerplate, but really
-that's all you need for this simple application. Lets make a controller:
-
- package MyCatApp::Controller::Root;
-
- use base 'Catalyst::Controller';
-
- sub root : GET Path('/helloworld') {
- pop->res->body('Hello world!');
- }
-
- sub test_post : POST Path('/echo') {
- my ($self, $c) = @_;
- $c->res->body( $c->req->body_parameters->{val} );
- }
-
- 1;
-
-Again, there's not a lot of work here. Its realy not many more lines than the
-L<Web::Simple> version, but its spread across more files. That would make more
-sense down the road when you application has 20 controllers and nearly 100
-URL endpoints, but for a simple, demo app like this its still not too bad :)
-
-To be fair, L<Web::Simple> is nice that it has built in support for matching
-on a POST parameter and gives you a default 'not found page', so we'd need
-a little more code to be completely comparable, but this is good enough for a
-demo.
-
-Lets look at the test case. It looks nearly the same as the L<Web::Simple>
-one:
-
- use HTTP::Request::Common;
- use Test::Most;
- use MyCatApp;
-
- {
- ok my $http_response = MyCatApp->run_test_request(GET '/helloworld');
- is $http_response->content, 'Hello world!';
- }
-
- {
- ok my $http_response = MyCatApp->run_test_request(POST '/echo', [val=>'posted']);
- is $http_response->content, 'posted';
- }
-
- {
- ok my $http_response = MyCatApp->run_test_request('GET' => '/helloworld');
- is $http_response->content, 'Hello world!';
- }
-
- {
- ok my $http_response = MyCatApp->run_test_request('POST' => '/echo', {val=>'posted'});
- is $http_response->content, 'posted';
- }
-
- done_testing;
-
-And that's really it! Here's the full application with test cases and
-organized as a proper CPAN style distribution:
-
-L<https://github.com/perl-catalyst/2013-Advent-Staging/tree/master/Catalyst-Plugin-RunTestRequest>
-
-=head1 Limitations
-
-Since we run the L<HTTP::Request> (or request specification) directly against
-the C<psgi_app> method of L<Catalyst> if you are using a standalone C<psgi>
-file that declares additional middleware or URL mountpoints, those additional
-bits will not be tested. If you are using middleware are a critical part of
-your L<Catalyst> application, I recommend using the the new middleware
-configuration option: L<Catalyst\PSGI-MIDDLEWARE>. For mounting PSGI
-applications you may prefer to consider L<Catalyst::Response\from_psgi_response>
-or look at the following independent distributions of you are on an older
-version of L<Catalyst>.
-
-L<Catalyst::Plugin::EnableMiddleware>, L<Catalyst::Action::FromPSGI>.
-
-=head1 What other things could you do with this?
-
-I've never loved the way L<Catalyst::Plugin::SubRequest> worked. It would be
-very easy to rewrite or offer another approach using this.
-
-It might be nice to have a sort of commandline REPL that let you run test
-requests against your L<Catalyst> application, with a full request/response
-trace.
-
-=head1 Summary
-
-We reviewed when one might wish to write a L<Catalyst> plugin, what such a
-plugin looks like. We also took a look at how the L<PSGI> underpinnings of
-L<Catalyst> provide a useful gateway to provide novel features.
-
-=head1 For More Information
-
-L<Catalyst>
-
-=head1 Author
-
-John Napiorkowski L<email:jjnapiork at cpan.org>
-
-=cut
-
Copied: trunk/examples/CatalystAdvent/root/2013/1.pod (from rev 14469, trunk/examples/CatalystAdvent/root/2013/01.pod)
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/1.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2013/1.pod 2013-12-02 08:16:06 UTC (rev 14470)
@@ -0,0 +1,170 @@
+=head1 Perl Catalyst in 2013 - The Year in Review!
+
+=head1 Overview
+
+Introduction to Advent 2013 and a review of all the things we accomplished.
+
+=head1 Welcome to Perl Catalyst Advent 2013!
+
+Its that time once again where the Perl hackers and stakeholders of various
+projects come together to congratulates themselves a bit for all the time and
+effort spent over the past year. So we review a bit, and we try to share our
+knowledge with people that are seeking to learn it. And we have a bit of fun
+at the same time!
+
+We need to remember that this is a time of year which is traditionally associated
+with giving gifts and receiving them graciously. But in a larger sense the gifts
+have already been sent along. Because for those of us involved in Free / Open
+source software, every act of participation is a gift. Whether you write code,
+fix documentation, submit test reports or just advocate on twitter, blogs, or
+whatever, you are gifting time and effort. That's in my mind one of the top
+gifts a person can give, since our time is one of our most precious and limited
+resources. To give that away is a pretty big deal in my book. And for those
+who choose Free / Open source, well I think its very cool to be part of a
+ethical movement like this whose focus is the betterment of all by working in
+common for those things with are common to all. Things like Perl, L<PSGI>,
+L<Moose> and of course lets not forget L<Catalyst>!
+
+So lets take a brief spin through the main events for L<Catalyst> in 2013!
+
+=head1 Main accomplishments
+
+Here's a brief rundown of some of the stuff that was added and changed in
+L<Catalyst> in 2013. This is just the highlights, you should checkout
+the Changes file for more details:
+
+L<https://metacpan.org/source/JJNAPIORK/Catalyst-Runtime-5.90051/Changes>
+
+=over 4
+
+=item HTTP Method Matching
+
+We added new action attributes that let you constrain on the expected HTTP
+method. For example:
+
+ sub start : ChainedParent
+ PathPrefix CaptureArgs(0) { }
+
+ sub list_users : Chained('start')
+ GET PathPart('') Args(0) { }
+
+ sub add_users : Chained('start')
+ POST PathPart('') Args(0) { }
+
+See L<Catalyst::Controller/GET> for more.
+
+=item Unicode in Core
+
+Just turn on the switch and you'll be sure to have greatly improved ability to
+handle utf8 encoding.
+
+ $c->config->{encoding} = 'UTF-8'
+
+=item Handle the PSGI writer object for more control on output
+
+Useful for streaming and working with event loops, or just for when you want
+more control on how content is returned.
+
+=item Support for accessing IO streams when allowed.
+
+Use this for when you want to do websockets or long polling.
+
+=item Support PSGI middleware in configuration
+
+Lets you declare middleware as part of your L<Catalyst> application
+
+=item Added 'global data handlers' for parsing request content
+
+Lets you handle more than classic form POST parameters. Yes, this mean
+L<Catalyst> now handlers JSON POST out of the box!
+
+=item Mount a PSGI response
+
+Now your actions can mount PSGI applications and return PSGI reponses
+directly. Great for when you want to graft into you L<Catalyst> application
+bits of other frameworks such as L<Web::Simple> or L<Web::Machine> (or even
+other L<Catalyst> applications.)
+
+=item Constrain Actions on HTTP Request Content-Type
+
+Lets you constrain an action to a particular HTTP request content type. This
+lets you have one action that handles form data and another that handles JSON.
+Useful for building web APIs and is a nice augmentation of what you get with
+L<Catalyst::Action::REST>
+
+=item Configuration flag to use Hash::MultiValue for Request Parameters
+
+Lets you use L<Hash::MultiValue> for query and body parameters, which can solve
+some situtations when you are not sure if incoming parameters are scalar or
+arrays. Very commonly used on other L<Plack> based systems.
+
+=back
+
+And there was a lot of under the hood stuff as well. We cleared out that nasty
+Regexp based dispatch stuff into its own repo (makes it easier to remove later on).
+We did a bunch of stuff to make sure we'd play nice with other Plack applications
+that L<Catalyst> might dispatch to (such as making sure input is properly
+buffered). Ether (who works with me at Campus Explorer) dug in deep and cleaned
+up some old and no longer good practice Moosisms (replacing them with new, shiny
+Moosey goodness). And quite a few people checked in docs and other improvements.
+
+Here's a nice chart of people that checked in code to the L<Catalyst> repo:
+
+L<https://github.com/perl-catalyst/catalyst-runtime/graphs/contributors?from=2013-01-01&to=2013-11-16&type=c>
+
+And that doesn't count people that checked in code to other important bits of
+the ecosystem. Lots of people contributed doc patches and fixes to stuff around
+the session and authentication as well. So '++' to all of you!
+
+Excited to learn more? Well, go check out the docs, ponder test cases and look
+forward to more upcoming advent articles where we hope to cover all this and
+more!
+
+=head1 Project management
+
+In order to facilitate more participation, we mirrored the main L<Catalyst> git
+repository over on Github (see: L<https://github.com/perl-catalyst/>). This
+repository mirrors the canonical repository which for the time being will remain
+on shadowgit (L<catagits at git.shadowcat.co.uk:Catalyst-Runtime.git>). And we
+setup TravisCI on the github repo in order to help us track problems with
+changes (thanks Chris Weyl L<https://metacpan.org/author/RSRCHBOY> for the help
+with that).
+
+In addition we setup a Questhub for helping us to track and discuss possible
+changes to L<Catalyst> (See L<http://questhub.io/realm/perl/explore/latest/tag/catalyst>)
+
+I've also tried to blog as much as possible, and be sure to announce the
+important bits on the mailing list and in many cases I've tried to make use of
+external sites like Reddit and social media.
+
+Lastly we tried to be a little more transparent regarding what we are targeting
+for L<Catalyst> changes. We had several named development cycles ( Zombie-boomstick,
+Sicilian-buttercup and Hamburg) which all had targeted goals, announcements,
+as much discussion as I could squeeze out of the community and retrospectives.
+
+I personally believe that open source works best when it works for all of us
+and the best way I can think to do that is to try and make everything as
+transparent as possible. I believe we succeeded in that, and I hope we can
+build on that into the coming year.
+
+=head1 Summary
+
+2013 was another big year for L<Catalyst>. We worked hard at making it even
+more flexible and useful out of the box by exposing more L<PSGI> and grafting
+in a few missing bits. I expect 2014 to be even a bigger year as we look hard
+at L<Catalyst> and try to find a strong direction that lets it remain the best
+full stack web application framework for Perl!
+
+=head1 For More Information
+
+CPAN: L<Catalyst>
+Github: L<https://github.com/perl-catalyst/>
+Code Repository: L<catagits at git.shadowcat.co.uk:Catalyst-Runtime.git>
+Questhub: L<http://questhub.io/realm/perl/explore/latest/tag/catalyst>
+Mailing List Info: L<http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst>
+
+=head1 Author
+
+Your Name <your at email.com> | IRC nick
+
+=cut
Modified: trunk/examples/CatalystAdvent/root/2013/10.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/10.pod 2013-12-02 02:42:17 UTC (rev 14469)
+++ trunk/examples/CatalystAdvent/root/2013/10.pod 2013-12-02 08:16:06 UTC (rev 14470)
@@ -1,7 +1,5 @@
-=head1 Title
+=head1 Nonblocking and Streaming
-Nonblocking and Streaming
-
=head1 Overview
Modern versions of L<Catalyst> allow you to take charge of how your
Modified: trunk/examples/CatalystAdvent/root/2013/11.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/11.pod 2013-12-02 02:42:17 UTC (rev 14469)
+++ trunk/examples/CatalystAdvent/root/2013/11.pod 2013-12-02 08:16:06 UTC (rev 14470)
@@ -1,7 +1,5 @@
-=head1 Title
+=head1 Nonblocking and Streaming
-Nonblocking and Streaming
-
=head1 Overview
Modern versions of L<Catalyst> allow you to take charge of how your
Modified: trunk/examples/CatalystAdvent/root/2013/12.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/12.pod 2013-12-02 02:42:17 UTC (rev 14469)
+++ trunk/examples/CatalystAdvent/root/2013/12.pod 2013-12-02 08:16:06 UTC (rev 14470)
@@ -1,7 +1,5 @@
-=head1 Title
+=head1 Nonblocking and Streaming
-Nonblocking and Streaming
-
=head1 Overview
Modern versions of L<Catalyst> allow you to take charge of how your
Modified: trunk/examples/CatalystAdvent/root/2013/13.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/13.pod 2013-12-02 02:42:17 UTC (rev 14469)
+++ trunk/examples/CatalystAdvent/root/2013/13.pod 2013-12-02 08:16:06 UTC (rev 14470)
@@ -1,7 +1,5 @@
-=head1 Title
+=head1 Nonblocking and Streaming
-Nonblocking and Streaming
-
=head1 Overview
Modern versions of L<Catalyst> allow you to take charge of how your
Modified: trunk/examples/CatalystAdvent/root/2013/14.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/14.pod 2013-12-02 02:42:17 UTC (rev 14469)
+++ trunk/examples/CatalystAdvent/root/2013/14.pod 2013-12-02 08:16:06 UTC (rev 14470)
@@ -1,7 +1,5 @@
-=head1 Title
+=head1 Streaming Nonblocking Files
-Streaming Nonblocking Files
-
=head1 Overview
Use Nonblocking IO and an Event Loop to concurrently stream a large file.
Modified: trunk/examples/CatalystAdvent/root/2013/15.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/15.pod 2013-12-02 02:42:17 UTC (rev 14469)
+++ trunk/examples/CatalystAdvent/root/2013/15.pod 2013-12-02 08:16:06 UTC (rev 14470)
@@ -1,7 +1,5 @@
-=head1 Title
+=head1 A Websocket's Echo Server in L<Catalyst>
-A Websocket's Echo Server in L<Catalyst>
-
=head1 Overview
This past year L<Catalyst> got the basics of support for long / persistent
Copied: trunk/examples/CatalystAdvent/root/2013/2.pod (from rev 14469, trunk/examples/CatalystAdvent/root/2013/02.pod)
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/2.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2013/2.pod 2013-12-02 08:16:06 UTC (rev 14470)
@@ -0,0 +1,276 @@
+=head1 Roll your own Catalyst Controller with Mooselike imports
+
+=head1 Overview
+
+Learn how to create a custom Catalyst base controller with Mooselike
+imported keywords and more.
+
+=head1 Introduction
+
+Most L<Catalyst> applications of a certain age and complexity have a lot of
+controllers. Quite often your controllers have excessive boilerplate code
+even before you add anything related to your business logic. Here's the
+canonical controller as often documented.
+
+ package MyApp::Controller::MyController;
+
+ use Moose;
+ use namespace::autoclean;
+
+ BEGIN { extends 'Catalyst::Controller' }
+
+ ## -- Your code
+
+ __PACKAGE__->meta->make_immutable
+
+I've always disliked how the C<extends> needs to be in a BEGIN block, which is
+a side effect of how L<MooseX::MethodAttributes> works with the existing code
+base as ported to L<Moose> several years ago. It just looks odd and is a
+surprise to people new (and even old) to the framework. People generally just
+cargo cult it.
+
+Additionally every action typically starts by shifting or slurping the same
+arguments:
+
+ sub my_action :Action {
+ my ($self, $c) = @_'
+ }
+
+And that's before you add in any of a number of things special to your logic.
+Is there anything we can do to centralize some of this boilerplate? And what
+if you like to use a handful of other syntax enhancing modules like
+L<Function::Parameters> or L<CatalystX::Syntax::Action>? If you wanted that,
+you'd end up with a controller something like:
+
+ package MyApp::Controller;
+
+ use Moose;
+ BEGIN { extends 'Catalyst::Controller' }
+
+ use Function::Parameters;
+ use CatalystX::Syntax::Action;
+ use namespace::autoclean;
+
+ ## -- You custom actions and methods
+
+ __PACKAGE__->meta->make_immutable;
+
+And doing this allows you to write a controller like this:
+
+ package MyApp::Controller::Root;
+
+ use Moose;
+ BEGIN { extends 'Catalyst::Controller' }
+
+ use Function::Parameters;
+ use CatalystX::Syntax::Action;
+ use namespace::autoclean;
+
+ has 'test_attribute' => (
+ is=>'ro',
+ default=>'example value');
+
+ method generate_helloworld { 'Hello world!' }
+
+ action helloworld : GET Path('/helloworld') {
+ $ctx->res->body( $self->generate_helloworld);
+ }
+
+ action echo($arg) : GET Path('/echo') Args(1) {
+ $ctx->res->body( $arg );
+ }
+
+ 1;
+
+=head1 Moose and Import::Into to the Rescue!
+
+Our goal is to take the controller example from above and reduce it so that
+you can just do:
+
+ package MyApp::Controller;
+
+ use MyApp::ControllerObject;
+
+ ## -- You custom actions and methods
+
+ __PACKAGE__->meta->make_immutable;
+
+This yields an example controller like so:
+
+ package MyApp::Controller::Root;
+
+ use MyApp::ControllerObject;
+
+ has 'test_attribute' => (
+ is=>'ro',
+ default=>'example value');
+
+ method generate_helloworld { 'Hello world!' }
+
+ action helloworld : GET Path('/helloworld') {
+ $ctx->res->body( $self->generate_helloworld);
+ }
+
+ action echo($arg) : GET Path('/echo') Args(1) {
+ $ctx->res->body( $arg );
+ }
+
+L<Catalyst> is build on L<Moose> so out of the box you get some built in
+features that allow you to create a custom Controller object class that slurps
+up everything you get with L<Moose> and allows you to add in whatever it is you
+like. along with L<Import::Into>'s consistent interface for importing features
+into your package, its very trivial to make a custom controller that does all
+we want (and can easily be extended to do much more, if you think that is wise).
+
+So, what would C<MyApp::ControllerObject> look like? Lets take a look a the
+full code and then do a walkdown:
+
+ package MyApp::ControllerObject;
+
+ use strict;
+ use warnings;
+
+ use Moose::Exporter;
+ use Import::Into;
+ use Module::Runtime;
+
+ my ($import, $unimport, $init_meta) =
+ Moose::Exporter->build_import_methods( also => ['Moose'] );
+
+ sub importables {
+ 'Function::Parameters',
+ 'CatalystX::Syntax::Action',
+ 'namespace::autoclean',
+ }
+
+ sub base_class { 'Catalyst::Controller' }
+
+ sub init_meta {
+ my ($class, @args) = @_;
+ Moose->init_meta( @args,
+ base_class => $class->base_class );
+ goto $init_meta if $init_meta;
+ }
+
+ sub import {
+ use_module($_)->import::into(scalar caller)
+ for shift->importables;
+ goto $import;
+ }
+
+ 1;
+
+So you can see there's not a lot of needed code to do this, mostly because of
+all the existing art that the L<Moose> cabal put into making extending L<Moose>
+easy, and because of the wonder clean, consistent API that L<Import::Into>
+gives you. Let's take it again from the top:
+
+ package MyApp::ControllerObject;
+
+ use strict;
+ use warnings;
+
+ use Moose::Exporter;
+ use Import::Into;
+ use Module::Runtime;
+
+So we setup the module namespace and use three modules (plus the ever present
+L<strict> and L<warnings> pragmas) which brings in all the required functionality.
+L<Moose::Exporter> sets us up with a Moosey import and later on you will see
+it lets us import all the normal Moose goodies. L<Import::Info> provides a clean,
+consistent interface for importing a module features into a package other than
+your own (used to inject syntax and pragmas into a calling system). Lastly, we
+use L<Module::Runtime> to make it easy to dynamically load modules in running
+code.
+
+ my ($import, $unimport, $init_meta) =
+ Moose::Exporter->build_import_methods( also => ['Moose'] );
+
+Here we use L<Moose::Exporter> to build for use some coderefs to handle how to
+properly import and initialize L<Moose>
+
+ sub importables {
+ 'Function::Parameters',
+ 'CatalystX::Syntax::Action',
+ 'namespace::autoclean',
+ }
+
+ sub base_class { 'Catalyst::Controller' }
+
+Here's the features we want imported into our controllers, and the base controller
+we want to use. I wrote it out as a separate function to make it easy for you to
+use and for people to subclass and override. You can add here whatever you want
+(but I recommend sanity, and remember too much magic can make it hard to debug
+stuff down the road).
+
+ sub init_meta {
+ my ($class, @args) = @_;
+ Moose->init_meta( @args,
+ base_class => $class->base_class );
+ goto $init_meta if $init_meta;
+ }
+
+This method gets called at startup and it initializes L<Moose> and sets the actual
+base class. This way when you do C<use MyApp::ControllerObject> you are already
+inheriting from L<Catalyst::Controller>.
+
+ sub import {
+ use_module($_)->import::into(scalar caller)
+ for shift->importables;
+ goto $import;
+ }
+
+Here's where the bulk of the action is. AS you should recall, when you write
+code like:
+
+ use MyApp::ControllerObject;
+
+That loads the code representing that namespace, and then calls the C<import>
+method on it. So we loop through each module we want to import, make sure it
+is loaded via C<use_module> and then use the interface that L<Import::Into>
+gives us. After that, we forward on to the C<import> coderef that
+L<Moose::Exporter> setup for us early on.
+
+Oh, what's up with that C<goto>? Yeah, generally C<goto> is evil, but this is
+a secondary use of C<goto> which is a lot like a subroutine call, but it acts more
+like a subroutine swap (nothing is added to the callstack, and @_ is preserved).
+So its nothing to worry about!
+
+And that is it!
+See the code on Github for a full example distribution you can review:
+L<https://github.com/perl-catalyst/2013-Advent-Staging/tree/master/MyApp-ControllerObject>
+
+This has a full sample distribution with test cases and all that. So take a
+look to see the bigger picture.
+
+=head1 Summary
+
+We reviewed one approach to using built in features of L<Moose>, the object
+system upon which L<Catalyst> is built, to reduce boilerplate when several
+desired features are needed across a large project. Along with L<Import::Into>'s
+simple and consistent API, you now have all you need to reduce boilerplate
+code in your larger Perl L<Catalyst> projects!
+
+=head1 Limitations and Concerns
+
+Although this method does allow one to centralize some boilerplate, I highly
+recommend being careful with the amount of extra behavior you place in this
+common class, as excessive magic can ultimately cause confusion and make it
+harder to debug issue. This method is not intended as a replacement for
+proper use of standard Perl design (Roles, etc).
+
+=head1 More Information
+
+I recommend reading the excellent documentation for extending L<Moose> via
+its build in exporter, L<Moose::Exporter> as well as any of the related
+documentation in the L<Moose> distribution, as well as the following:
+
+L<Catalyst>, L<Moose>, L<Import::Into>, L<Function::Parameters>,
+L<namespace::autoclean>, L<CatalystX::Syntax::Action>
+
+=head1 Author
+
+John Napiorkowski L<email:jjnapiork at cpan.org>
+
+=cut
+
Copied: trunk/examples/CatalystAdvent/root/2013/3.pod (from rev 14469, trunk/examples/CatalystAdvent/root/2013/03.pod)
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/3.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2013/3.pod 2013-12-02 08:16:06 UTC (rev 14470)
@@ -0,0 +1,143 @@
+=head1 HTTP Method Matching in Catalyst
+
+=head1 Overview
+
+A quick example of how to use the HTTP Method matching feature
+in L<Catalyst> along with some tips and caveats.
+
+=head1 Introduction
+
+Beginning in the v5.90020 release of L<Catalyst> we introduced into core the
+ability to match your controller actions to incoming HTTP method verbs. It
+does this by extending the standard L<Catalyst> approach of using subroutine
+attributes to tag your actions with 'metadata' that the dispatcher uses to
+figure out how to assign a given incoming request to a controller and action.
+Generic and shortcut attributes are allowed, and in addition we support some
+of the common approaches to use HTTP extended headers to 'tunnel' a method
+verb for the cases when the client is restricted (such as is common in many
+browsers to only support GET and POST).
+
+=head1 Why dispatch on HTTP Methods?
+
+Most modern web frameworks give you some high level ability to match an
+incoming request based on its HTTP verb. Programmers find it useful for
+a variety of tasks, from crafting RESTful APIs to allowing one to just have
+more meaningful URLs. L<Catalyst> has allowed this via a few add on
+distributions but often people don't find them. Having this feature in core
+means one can perform those tasks 'out of the box'. It also means that we
+can count on the presence of that ability as we continue to craft L<Catalyst>
+core codebase into the future.
+
+=head1 How Does it Work?
+
+Let's look at an example action:
+
+ sub is_get : Method('GET') Path('/example') { ... }
+ sub is_any : Path('/example') { ... }
+
+In this case the URL '/example' would get executed by the C<is_get> method
+of this controller when the HTTP method is a GET and by the C<is_any> method
+for all other cases. The generical uses is "Method($verb)" where $verb is
+any standard or custom value that shows up in the HTTP method header. Since
+several are common, we provide some shortcuts:
+
+ sub is_get : GET Path('/example') { ... }
+ sub is_post : POST Path('/example') { ... }
+ sub is_put : PUT Path('/example') { ... }
+ sub is_delete : DELETE Path('/example') { ... }
+
+In these cases the '/example' url would get mapped to the action as expected
+by the incoming HTTP method verb. Finally, you may add more than one method
+matching attribute:
+
+ sub post_and_put : POST PUT Path('/example) { ... }
+
+=head1 HTTP Extended Header Tunneling
+
+Since not all clients support a rich HTTP method vocabulary (classic HTML
+forms come to mind, since they typically only support GET and POST) it has
+become standard practice to use HTTP extended headers to 'tunnel' a verb
+not supported by a given client over one that does. For example, one might
+use this feature to tunnel a DELETE or PUT over a POST.
+
+For broad compatibility, we support HTTP method tunneling over the following
+HTTP headers:
+
+=over 4
+
+=item X-HTTP-Method (Microsoft)
+
+=item X-HTTP-Method-Override (Google/GData)
+
+=item X-METHOD-OVERRIDE (IBM)
+
+=item x-tunneled-method (used in many other similar systems on CPAN)
+
+=back
+
+Typically you won't need to set these headers yourself, they are usually
+created for you by the Javascript or similar toolkits but you should be aware
+of there function so you are not caught by surprise when they are active.
+
+=head1 A Full Example
+
+An example controller:
+
+ package MyApp::Controller::Root;
+
+ use base 'Catalyst::Controller';
+
+ sub is_get : GET Path('/test') { pop->res->body('GET') }
+
+ sub is_post : POST Path('/test') { pop->res->body('POST') }
+
+ sub is_put : PUT Path('/test') { pop->res->body('PUT') }
+
+ sub is_delete : DELETE Path('/test') { pop->res->body('DELETE') }
+
+ 1;
+
+And the test case for this:
+
+ use Test::Most;
+ use Catalyst::Test 'MyApp';
+ use HTTP::Request::Common qw(GET PUT POST DELETE);
+
+ is request(GET '/test')->content, 'GET';
+ is request(PUT '/test')->content, 'PUT';
+ is request(POST '/test')->content, 'POST';
+ is request(DELETE '/test')->content, 'DELETE';
+
+ done_testing;
+
+You can see the full application source on Github:
+L<https://github.com/perl-catalyst/2013-Advent-Staging/tree/master/HTTP-Method-Matching>.
+
+=head1 Caveats and Gotchas
+
+You should remember that Catalyst will typically match on the first action
+that meets the minimum requirement. This means you need to put you more
+specific matches 'higher' in the controller than the catchall actions. When
+running L<Catalyst> in debug mode (via CATALYST_DEBUG=1, for example) the
+initial informations screen now contains information about what HTTP methods a
+given action will try to match, so that should help you figure out if something
+is going wrong.
+
+Also, this feature does not attempt to set some standard HTTP header information
+in the response regarding which methods are and are not allowed (as does for
+example L<Web::Machine>. If you are trying to create a strong, RESTful API
+you should not forget to set the response HTTP headers around allowed HTTP
+methods in your controller code.
+
+=head1 Summary
+
+HTTP Method Matching in core L<Catalyst> gives you a bit more flexibility
+to craft how the dispatcher maps incoming requests to your actions. Although
+the feature has limitations it should prove useful when mapping complex
+client server interactions.
+
+=head1 Author
+
+John Napiorkowski L<email:jjnapiork at cpan.org>
+
+=cut
Copied: trunk/examples/CatalystAdvent/root/2013/4.pod (from rev 14469, trunk/examples/CatalystAdvent/root/2013/04.pod)
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/4.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2013/4.pod 2013-12-02 08:16:06 UTC (rev 14470)
@@ -0,0 +1,342 @@
+=head1 Using PSGI Integration in Catalyst: Middleware and More
+
+=head1 Overview
+
+This is an example application that shows you how to use the
+new L<Catalyst> support for PSGI middleware, and why you might
+want to use it.
+
+=head1 Introduction
+
+Modern versions of L<Catalyst> use L<Plack> as the underlying engine to
+connect your application to an http server. This means that you can take
+advantage of the full L<Plack> software ecosystem to grow your application
+and to better componentize and re-use your code.
+
+Middleware is a large part of this ecosystem. L<Plack::Middleware> wraps your
+PSGI application with additional functionality, such as adding Sessions ( as in
+L<Plack::Middleware::Session>), Debugging (as in L<Plack::Middleware::Debug>)
+and logging (as in L<Plack::Middleware::LogDispatch> or
+L<Plack::Middleware::Log4Perl>).
+
+Generally you can enable middleware in your C<psgi> file, as in the following
+example
+
+ #!/usr/bin/env plackup
+
+ use strict;
+ use warnings;
+
+ use MyApp::Web; ## Your subclass of 'Catalyst'
+ use Plack::Builder;
+
+ builder {
+
+ enable 'Debug';
+ enable 'Session', store => 'File';
+
+ mount '/' => MyApp::Web->psgi_app;
+
+ };
+
+Here we are using our C<psgi> file and tools that come with L<Plack> in order
+to enable L<Plack::Middleware::Debug> and L<Plack::Middleware::Session>. This
+is a nice, clean approach that cleanly separates your L<Catalyst> application
+from enabled middleware.
+
+However there may be cases when you'd rather enable middleware via you L<Catalyst>
+application, rather in a stand alone file. For example, you may wish to let your
+L<Catalyst> application have control over the middleware configuration, so that
+you could enable certain middleware in production, and others development. You
+can do this with an external C<.psgi> file, but it can get complex and ugly fast
+if your use of middleware is complex. Also, if middleware is part of the way
+your application works, it makes sense from a design viewpoint for the middleware
+to be part of the application rather than a layer on top.
+
+Starting on v5.90050, L<Catalyst> allows you to add middleware as part of your
+normal setup and configuration. Let's port the above example:
+
+ package MyApp::Web;
+
+ use Catalyst;
+
+ __PACKAGE__->config(
+ psgi_middleware => [
+ 'Debug',
+ 'Session' => {store => 'File'},
+ ]);
+
+C<psgi_middleware> is just a key in your application configuration, so you can
+use other tools in the configuration ecosystem (such as
+L<Catalyst::Plugin::ConfigLoader>) to manage it. The key takes an ArrayRef
+where elements can be the name of distribution under L<Plack::Middleware> (the
+named middleware C<Debug> would refer to L<Plack::Middleware::Debug>, an
+instance of a middleware object, a subroutine reference for inlined middlware
+or middleware under your application namespace. The following is all correctly
+formed:
+
+ __PACKAGE__->config(
+ 'psgi_middleware', [
+ 'Debug',
+ '+MyApp::Custom',
+ $stacktrace_middleware,
+ 'Session' => {store => 'File'},
+ sub {
+ my $app = shift;
+ return sub {
+ my $env = shift;
+ $env->{myapp.customkey} = 'helloworld';
+ $app->($env);
+ },
+ },
+ ],
+ );
+
+See L<Catalyst/PSGI-MIDDLEWARE> for more details.
+
+=head1 Why Use Middleware?
+
+Use middleware in cases where there is existing middleware who's functionality
+you want to reuse in your L<Catalyst> application, or when you have some logic
+that is global to the request / response cycle that you wish to isolate. Very
+often when you are thinking of writing a L<Catalyst::Plugin> or hacking into
+L<Catalyst::Request> / L<Catalyst::Response> or you are using controller end
+actions to modify the outgoing response, then middleware might be a better
+choice.
+
+=head1 How Does it Work?
+
+Think of middleware as layers in an onion, with you application at the center.
+As a request comes in, you go down each layer in the onion til you hit the
+the application. Then, as you go out, you pass each layer again (but this time
+from the center outward).
+
+So as the request comes in, your middleware can access and alter the psgi $env.
+On the way out it can alter the response.
+
+You can even use middleware as a way to produce responses (such as to have a
+default not found page, or to catch exceptions that your application throws)
+or to redirect the flow of the request to a totally different application.
+For example, you might wish to port your old application to run on L<Catalyst>;
+you can wrap some middleware to send the request to your new L<Catalyst> based
+application, and if it returns a 'not found' response, allow it to continue on
+to the old application. In this way you can port your website to a modern
+framework 'url by url' rather than try to do a ground up redo in one release.
+
+See L<Plack::Middleware> for more on middleware.
+
+=head1 A Full Example
+
+Let's build a L<Catalyst> application that uses middleware to redirect some
+of the requests to a L<Web::Simple> application. A good use for something
+like this could be a case when you have some time sensitive responses, such
+as autocomplete or similar json API and your L<Catalyst> application has too
+much overhead (sessions, authentication, etc.) To make it more fun, lets
+have the L<Web::Simple> application use some components from your main
+L<Catalyst> application (lets say to use the L<Catalyst> view) so we can see
+how this approach lets you mix and match the best of both worlds.
+
+Full example code can be found here:
+
+L<https://github.com/perl-catalyst/2013-Advent-Staging/tree/master/PSGI-Middleware>
+
+Let's start with the application class:
+
+ package MyApp::Web;
+
+ use Catalyst;
+ use MyApp::Web::Simple;
+
+ __PACKAGE__->config(
+ psgi_middleware => [
+ 'Delegate' => { psgi_app =>
+ MyApp::Web::Simple->new(
+ app => __PACKAGE__
+ )->to_psgi_app },
+ ]);
+
+ __PACKAGE__->setup;
+
+So there's a few things going on here but the gist of it is that we are saying
+this application uses the 'Delegate' middleware. Since we didn't specify the
+full middleware namespace, it will look first for L<MyApp::Web::Middleware::Delegate>
+and then L<Plack::Middleware::Delegate> (this is so that you can wrap and customize
+existing middleware, should you choose). In this case there is a
+C<MyApp::Web::Middleware::Delegate> so that gets passed a single parameterized
+argument, which in this case is pointing to your L<Web::Simple> based
+application. That, BTW has an argument which points back to your L<Catalyst>
+application, but we'll look at that in a bit! Lets look at our custom middleware:
+
+ package MyApp::Web::Middleware::Delegate;
+
+ use strict;
+ use warnings;
+ use base 'Plack::Middleware';
+ use Plack::Util::Accessor 'psgi_app';
+
+ sub call {
+ my ($self, $env) = @_;
+ my $psgi_response = $self->psgi_app->($env);
+
+ return $psgi_response->[0] == 404 ?
+ $self->app->($env) : $psgi_response;
+ }
+
+Since L<Catalyst> is L<Moose> based, we tend to use L<Moose> quite a bit, however
+in the case of this middleware there's no reason to not just follow how most other
+middleware projects work and just inherit from L<Plack::Middleware>.
+
+There's one function of important here, which middleware expects you to define,
+which is C<call>. This function is basically that onion layer I spoke of before
+where you get the C<PSGI> $env on the way in, and then access to the $psgi_response
+on the way out.
+
+What this code is saying is, "I get $env and pass it to C<psgi_app> (which is
+the L<Web::Simple> application that got added in the L<Catalyst> application
+configuration) and if that application returns a code 404 (Not Found) then send
+$env along to the L<Catalyst> application, otherwise use the L<Web::Simple>
+response and short circuit calling L<Catalyst>."
+
+BTW, this functionality is not unlike what you might see with some common
+middleware on CPAN (such as L<Plack::App::Cascade>) but I thought it instructive
+to write our own, just for learning.
+
+Ok great, lets look at the nice and speedy L<Web::Simple> application!
+
+ package MyApp::Web::Simple;
+
+ use Web::Simple;
+
+ has 'app' => (is=>'ro', required=>1);
+
+ sub render_hello {
+ my ($self, $where) = @_;
+ return $self->app->view('HTML')->render($self->app,
+ 'hello.html', {where=>'web-simple'} );
+ }
+
+ sub dispatch_request {
+ my $self = shift;
+ sub (/websimple-hello) {
+ [ 200, [ 'Content-type', 'text/html' ],
+ [$self->render_hello]
+ ],
+ },
+ }
+
+Basically L<Web::Simple> will handle the URL "/websimple-hello" and return a
+404 Not Found response for anything else (the 404 Not Foundis actually built
+into L<Web::Simple>, unlike L<Catalyst> where the default is to not return
+anything at all.)
+
+When rendering the response it uses the HTML View you defined in the base
+L<Catalyst> application. So you can use a similar technique to share views
+and models between applications and frameworks but all running under the same
+core application. Lets glance at the View template (hello.html):
+
+ <html>
+ <head>
+ <title>Hello From [% where %]</title>
+ </head>
+ <body>
+ <h1>Hello From [% where %]</h1>
+ </body>
+ </html>
+
+Not a complicated template, but it gets the idea across. This expects one
+variable C<where> which in L<Catalyst> gets stuffed into the stash, but in
+L<Web::Simple> we just add it to the C<render> arguments of the view.
+
+Other possible uses for this approach code be:
+
+=over 4
+
+=item Using L<Web::Machine> to handle your API
+
+L<Web::Machine> has great support for writing truely RESTful applications. What
+it doesn't have is L<Catalyst>'s great ability to bring data from lots of
+models, or to generate HTML views. This way you can use the best tool for the
+given job without be forced to given up the ease and structure of L<Catalyst>.
+
+=item Converting a legacy application to run on L<Catalyst>
+
+This lets you port your web application over 'url by url'. You can even use
+this to help you refactor an existing L<Catalyst> application that has gotten
+a bit more crusty over the years than you'd prefer.
+
+=back
+
+Other ideas might commend themselves to you. Lets see the L<Catalyst> side
+of things and look at the controller:
+
+package MyApp::Web::Controller::Root;
+
+ use Moose;
+ use MooseX::MethodAttributes;
+
+ extends 'Catalyst::Controller';
+
+ sub start : Chained('/')
+ PathPrefix CaptureArgs(0)
+ {
+ my ($self, $ctx) = @_;
+ }
+
+ sub hello : Chained('start')
+ PathPart('catalyst-hello') Args(0)
+ {
+ my ($self, $ctx) = @_;
+ $ctx->stash(where=>'Catalyst');
+ $ctx->forward($ctx->view('HTML'));
+ }
+
+ __PACKAGE__->config(namespace => '' );
+ __PACKAGE__->meta->make_immutable;
+
+The chaining here might be a bit gratuitious but you get the idea I hope.
+Finallty lets see the test cases to make sure everything works as expected:
+
+ use Test::Most;
+ use Catalyst::Test 'MyApp::Web';
+
+ ok( get('/catalyst-hello') =~ /Catalyst/ );
+ ok( get('/websimple-hello') =~ /web-simple/ );
+
+ done_testing;
+
+Go see the linked code on Github:
+
+L<https://github.com/perl-catalyst/2013-Advent-Staging/tree/master/PSGI-Middleware>
+
+For more code and more tests to see how the whole distribution is put
+together.
+
+=head1 Final Comments
+
+I personally see a big role for middleware in future L<Catalyst>. When
+it comes down to it, the idea of a L<Plack::Component> (which is the
+parent class of L<Plack::Middleware>) is not terrible different from
+L<Catalyst::Component>...
+
+Stay tuned!
+
+=head1 Also See
+
+L<Catalyst::Plugin::EnableMiddleware> gives you similar functionality for
+older versions of L<Catalyst>.
+
+=head1 Summary
+
+Middleware is another way to build and extend your L<Catalyst> based
+applications. It can be used to bring functionality from other common
+code (opensource or otherwise) and it opens the door to new approaches
+to solving many existing problems. Next time you need better control
+over your L<Catalyst> request and response, or you think of using a
+global plugin, ask yourself if middleware might not be the better option.
+
+
+=head1 Author
+
+John Napiorkowski L<email:jjnapiork at cpan.org>
+
+=cut
Copied: trunk/examples/CatalystAdvent/root/2013/5.pod (from rev 14469, trunk/examples/CatalystAdvent/root/2013/05.pod)
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/5.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2013/5.pod 2013-12-02 08:16:06 UTC (rev 14470)
@@ -0,0 +1,122 @@
+=head1 Using the L<Hash::MultiValue> configuration option in L<Catalyst>
+
+=head1 Overview
+
+L<Catalyst> has always supported HTML POST form parameters and
+query parameters using a simple API via the L<Catalyst::Request>
+object. However this API has a flaw when said parameters can be
+multi, leading to ackward boilerplate defensive code. The L<Plack>
+community introduced L<Hash::MultiValue> as one approach to better
+manage this issue. Starting in version 5.90050, L<Catalyst> lets
+you use L<Hash::MultiValue> via a configuration option so that you
+may use this approach in your L<Catalyst> code as well.
+
+=head1 Introduction
+
+Have you ever written code like this:
+
+ sub myaction :Path(something) {
+ my $p = (my $c = pop)->request->body_parameters;
+ my @vals = ref $p->{field} eq 'ARRAY'
+ ? @{$p->{field}}
+ : ($p->{field});
+ }
+
+You might write code like this if the incoming body (or query) parameters can
+be single or arrays. You might have a form with checkboxes or with select with
+multiple options. In that case you need to do that ugly dance of checking to
+see if the field is an arrayref or a single value.
+
+One solution to this problem is to use an instance of L<Hash::MultiValue> to
+contain your field parameters. L<Hash::MultiValue> comes out of L<Plack> and
+was a Perlish port of a similar class in the Python WSGI framework C<Webob>.
+Its one way to approach this problem, since it gives you a consistent API
+to dealing with query and form parameters.
+
+=head1 How Does it Work?
+
+Instead of $c->request->body_parameters (and ->query_parameters) containing
+a simple hash whose values could be single or could be an arrayref, we use
+an instance of L<Hash::MultiValue> instead. You enable this as a global
+L<Catalyst> configuration option, for example:
+
+ package MyApp;
+
+ use Catalyst;
+
+ __PACKAGE__->config(use_hash_multivalue_in_request=>1);
+ __PACKAGE__->setup;
+
+Now, whenever you call for request parameters, we build an instance of
+L<Hash::MultiValue> and store that instead of the HashRef that classic versions
+of L<Catalyst> uses. L<Hash::MultiValue> has an API that lets you get the
+values of field keys in a consistent manner no matter what the actual underlying
+values are. In additional, it uses overloading to support the classic 'as an
+arrayref' interface, which works just like L<Catalyst> does today, except it
+will always return a single value (whichever the last one was). This is likely
+a preferable behavior than the current, which can give you one or the other
+and leading your code to error out in those cases. Here's an example:
+
+ # suppose incoming POST parameters are such
+
+ name: John
+ age: 25
+ age: 44
+
+ sub myaction :Path(something) {
+ my $p = (my $c = pop)->request->body_parameters;
+
+ {
+ my $name = $p->{name}; # 'John'
+ my $age = $p->{age}; # 44
+ }
+
+ {
+ my $name = $p->get('name'); # 'John'
+ my $age = $p->get('age'); # 44
+ }
+
+ my @ages = $p->get_all('age'); # 26,44
+ }
+
+The approach is arguable less prone to error and reduces the need to write
+defensive code to figure out when form parameters are single values or are
+array referenences.
+
+=head1 A Full Example
+
+See the example application
+
+L<https://github.com/perl-catalyst/2013-Advent-Staging/tree/master/Hash-MuliValue>
+
+For more help and test cases.
+
+=head1 Caveats and Gotchas
+
+Although L<Hash::MultiValue> overloads to support the 'as hashref' interface,
+it is quite likely to have different values in the multi field case, and as a
+result it might break existing code (or reveal previously undetected issues
+with your code, depending on your outlook).
+
+if you are in the habit of modifying the parameter hashref directly (for example
+adding or deleting keys) like so:
+
+ $c->req->body_parameters->{some_new_field} = 'bogus field';
+
+That won't work with L<Hash::MultiValue> which instead offers an API for adding
+and deleting fields in a consistent way.
+
+=head1 Summary
+
+L<Hash::MultiValue> is an approach to better encapsulate access to classic HTML
+form POST and query parameters. It provides a consistent API and smooths over
+some common issues you might have with the existing L<Catalyst> approach. If
+so, you can enable this new feature with a single, global configuration option!
+
+=head1 Also See
+
+=head1 Author
+
+John Napiorkowski L<email:jjnapiork at cpan.org>
+
+=cut
Copied: trunk/examples/CatalystAdvent/root/2013/6.pod (from rev 14469, trunk/examples/CatalystAdvent/root/2013/06.pod)
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/6.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2013/6.pod 2013-12-02 08:16:06 UTC (rev 14470)
@@ -0,0 +1,128 @@
+=head1 Using Body Data Handlers in Catalyst
+
+=head1 Overview
+
+The v5.90050 Release of Catalyst introduced a new way to process request body
+content. Out of the box L<Catalyst> now offers basic support for request
+content types of JSON and some of the more common approaches to nesting data
+structures in HTML form parameters. You can modify how this works globally
+by adding support for additional types or overriding default types.
+
+=head1 Introduction
+
+L<Catalyst> has supported classic HTML Form type POST parameters, as well
+as GET request query parameters for a long time. Although the built in support
+has a few gotchas (many of which we fixed by allowing you to configure
+L<Hash::MultiValue> as field storage for request parameters) it has generally
+served well.
+
+However times have changed quite a bit since L<Catalyst> was first put on CPAN.
+Common alternatives for client - server communication, typically using JSON,
+are the order of the day, and its normal for a web framework to support at
+least that out of the box. L<Catalyst> has long met this need via the external
+framework L<Catalyst::Action::REST> which is a toolkit for parsing and rendering
+various types of content. However L<Catalyst::Action::REST> can quite often be
+a lot more than you need. If you are just trying to support AJAXy style HTML
+form submission and validation, you probably don't want all the extra bits and
+structure that L<Catalyst::Action::REST> gives you. So, starting in version
+5.90050, L<Catalyst> has a new system for parsing common incoming request
+bodies, which out of the box will support JSON as well as the more common
+idioms for nested form parameters. We'll take a look out how this works for
+JSON request bodies and how you can modify and augment this new 'body data'
+system
+
+=head1 How Does it Work?
+
+There's two parts to the system. The first is part of L<Catalyst> application
+class, and takes the form of a new configuration option and key C<data_handlers>.
+It works like this:
+
+ package MyApp;
+
+ use Catalyst;
+
+ __PACKAGE__->config(
+ data_handlers => {
+ 'application/json' => sub {
+ # $_ is localized to a readable filehandle of the request body content.
+ },
+ },
+ );
+
+Basically L<Catalyst> defines a new global configuration option C<data_handlers>
+which is a hashref where the key is a standard MIME content-type and the value
+is a subroutine reference that is intended to parse that content type.
+
+The subroutine reference has C<$_> localized to the filehandle of the request
+body content, so you can read the content any way you like (you can use non
+blocking techniques should an event loop exist although it is doubtful that
+will help much since the filehandle has already been fully buffered).
+
+There is no defined return type. You can return a parsed data as a hashref
+or return an object, whatever makes sense for the content type and the size
+you are dealing with. For example, here's the code for the built in JSON
+parsing:
+
+ 'application/json' => sub {
+ Class::Load::load_first_existing_class('JSON::MaybeXS', 'JSON')
+ ->can('decode_json')->(do { local $/; $_->getline });
+ },
+
+Basically we just slurp up the JSON in one big line and parse it all in one
+go. Please note this might not be the best approach if the incoming JSON
+is expected to be very large!
+
+Your hashref under C<data_handlers> can include as many types as you deem
+required, and you can override the build in JSON parsing since we apply
+you customizations ontop of the defaults.
+
+So, how do you access this new parsed content? We've added a new attributes
+to L<Catalyst::Request> called C<body_data>. This attribute is lazy, so
+unless you actually ask for it, we don't attempt to parse any request content
+against the defined L<data_handlers>. So if you wrote a ton of your own
+JSON decoding stuff, and/or are using L<Catalyst::Action::REST> you can
+keep on doing that without any impact at all on your request overhead.
+
+Here's how this could look in you controller. Lets assume the incoming is
+C<application/json> like "{'name':'Jason','age':'25'}":
+
+ sub update_user : POST Path(/User) Consumes(JSON) {
+ my $p = (my $c = pop)->req->body_data;
+ $c->res->body("My name is $posted->{name} and my age is $p->{age}");
+ }
+
+Basically this is very similar to the request object's C<body_parameters>
+method but is data focused on alternative POSTed or PUT request content.
+
+The built in JSON decoder just returns a hashref, which is similar to many
+other frameworks but there's nothing stopping you from returning any type
+of scalar reference, including an object.
+
+So that's really it!
+
+=head1 Caveats, gotchas...
+
+Although unicode is supported out of the box with L<Catalyst> information
+in the C<$_> localized filehandle is basically just as it comes from the
+client. You may need to do additional decoding. This might change in
+the future, but in the absence of clear requirements the authors felt it best
+to not guess to far in advance.
+
+=head1 Summary
+
+Starting in version 5.90050, L<Catalyst> offers useful support for JSON
+POSTed content out of the box, reducing one's need to lean on heavier
+addins such as L<Catalyst::Action::REST> while maintaining our desire
+to keep L<Catalyst> modular and flexible.
+
+=head1 For More Information
+
+Setting data handler configutation: L<Catalyst/DATA-HANDLERS>
+
+Accessing the parsed content: L<Catalyst::Request/req-body_data>
+
+=head1 Author
+
+John Napiorkowski L<email:jjnapiork at cpan.org>
+
+=cut
Copied: trunk/examples/CatalystAdvent/root/2013/7.pod (from rev 14469, trunk/examples/CatalystAdvent/root/2013/07.pod)
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/7.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2013/7.pod 2013-12-02 08:16:06 UTC (rev 14470)
@@ -0,0 +1,330 @@
+=head1 How To Hack On Catalyst Core - Adding $response->from_psgi_response
+
+=head1 Overview
+
+A lot of people want to contribute to the L<Catalyst> project, but get scared
+off due to an assumption that the code is highly complex and requires an
+experts touch. This article will review how we added the feature that allows
+a L<Catalyst::Response> to be filled from the response of a PSGI appliction.
+
+See L<Catalyst::Response/from_psgi_response> for more.
+
+=head1 Introduction
+
+L<Catalyst> has been L<PSGI> native for a while, but to date has not really
+taken much advantage of that fact beyond the ability to use L<Plack> based
+web servers in replacement of the L<Catalyst::Engine> namespace. This is not a
+small think to be sure, but it would be great if L<Catalyst> could not flex its
+L<PSGI> abilities even more. One thing that would be possible is for L<Catalyst>
+to allow one to populate a reponse via a L<Plack::App> such as L<Plack::App::File>
+(which would make a possible replacement for L<Catalyst::Plugin::Static::Simple>).
+Or you could use L<Catalyst> to mount other frameworks, such as L<Web::Machine>
+which excel in a particular domain such as building RESTful APIs.
+
+So, how can one do this? Let's look into it!
+
+=head1 Prequisite Tasks
+
+Two features added to L<Catalyst> in previous releases where necessary to
+perform this task properly. The first was to allow one to have more control
+over how we write output to the server and out to the requesting client. This
+was the feature to expose the writer filehandle, and it was primarily added
+to make it easier to write asynchronous and/or streaming output, although as
+we will see, that feature enabled us to do stuff we'd not thought of at that
+point.
+
+See L<Catalyst::Response/res-write_fh> for more on using $Response->write_fh.
+
+This was needed as we will see later to make sure we could properly deal with
+a streaming or delayed PSGI response. Without it we'd be forced to fully buffer
+the response, which would be a shame since L<Catalyst> can support these types
+of responses.
+
+For more information see L<PSGI/Delayed-Response-and-Streaming-Body>.
+
+The second feature was added as a development version of this summer past, and
+it supports adding an input buffer object should one not exist in the case
+where the underlying L<Plack> engine does not provide one. This is needed because
+L<Catalyst> slurps up any POST or PUT content that might be part of the request
+and that means that any PSGI application that gets called later on won't get
+that (in other words it won't have access to POSTed form parameters or file
+uploads). Some PSGI webservers like L<Starman> provide a readable, buffered
+filehandle of this request content, others (like ModPerl and FastCGI) do not.
+This leads to issues where some code works fine in development (when you are
+using L<Starman>) but then break in a FastCGI (or *shudder* mod_perl) setup.
+So now in newer versions of L<Catalyst> when it is slurping up the request
+content, if we notice there is no input buffer, we create one so that anyone
+that needs it down the line will get access to it.
+
+Between these two features we have everything in L<Catalyst> we need to complete
+this task.
+
+=head1 The Test Cases
+
+Prior to working on this task, I wrote out the minimal test cases in the form
+of a new controller test. Here's a version of those test cases:
+
+ package TestFromPSGI::Controller::Root;
+
+ use base 'Catalyst::Controller';
+
+ sub from_psgi_array : Local {
+ my ($self, $c) = @_;
+ my $res = sub {
+ my ($env) = @_;
+ return [200, ['Content-Type'=>'text/plain'],
+ [qw/hello world today/]];
+ }->($c->req->env);
+
+ $c->res->from_psgi_response($res);
+ }
+
+ sub from_psgi_code : Local {
+ my ($self, $c) = @_;
+
+ my $res = sub {
+ my ($env) = @_;
+ return sub {
+ my $responder = shift;
+ return $responder->([200, ['Content-Type'=>'text/plain'],
+ [qw/hello world today2/]]);
+ };
+ }->($c->req->env);
+
+ $c->res->from_psgi_response($res);
+ }
+
+ sub from_psgi_code_itr : Local {
+ my ($self, $c) = @_;
+ my $res = sub {
+ my ($env) = @_;
+ return sub {
+ my $responder = shift;
+ my $writer = $responder->([200, ['Content-Type'=>'text/plain']]);
+ $writer->write('hello');
+ $writer->write('world');
+ $writer->write('today3');
+ $writer->close;
+ };
+ }->($c->req->env);
+
+ $c->res->from_psgi_response($res);
+ }
+
+So if you go and read the L<PSGI> documentation, you know there's three types
+of responses we need to deal with. The first is the classic PSGI example
+of a tuple (ArrayRef of Status, Headers and BodyArray/Body Filehandle). The
+second and third are variations of delayed response. These types of responses
+return a coderef instead of a tuple and can including streaming types of
+responses (see the third action C<from_psgi_code_itr> for example of this).
+
+Ok, so we created what are now failing test cases. Lets write the method to
+make them pass!
+
+=head1 The Code
+
+Let's take a look at the full method added to L<Catalyst::Response> and then
+well do a walkthrough:
+
+ sub from_psgi_response {
+ my ($self, $psgi_res) = @_;
+ if(ref $psgi_res eq 'ARRAY') {
+ my ($status, $headers, $body) = @$psgi_res;
+ $self->status($status);
+ $self->headers(HTTP::Headers->new(@$headers));
+ if(ref $body eq 'ARRAY') {
+ $self->body(join '', grep defined, @$body);
+ } else {
+ $self->body($body);
+ }
+ } elsif(ref $psgi_res eq 'CODE') {
+ $psgi_res->(sub {
+ my $response = shift;
+ my ($status, $headers, $maybe_body) = @$response;
+ $self->status($status);
+ $self->headers(HTTP::Headers->new(@$headers));
+ if($maybe_body) {
+ if(ref $maybe_body eq 'ARRAY') {
+ $self->body(join '', grep defined, @$maybe_body);
+ } else {
+ $self->body($maybe_body);
+ }
+ } else {
+ return $self->write_fh;
+ }
+ });
+ } else {
+ die "You can't set a Catalyst response from that, expect a valid PSGI response";
+ }
+ }
+
+The example usage is as follows:
+
+ package MyApp::Web::Controller::Test;
+
+ use base 'Catalyst::Controller';
+ use Plack::App::Directory;
+
+ my $app = Plack::App::Directory
+ ->new({ root => "/path/to/htdocs" })
+ ->to_app;
+
+ sub myaction :Local {
+ my ($self, $c) = @_;
+ $c->response->from_psgi_response(
+ $app->($c->request->env));
+ }
+
+So basically given a L<PSGI> response, as you would get from running it against
+the current $env (part of the L<PSGI> specification), let that response be
+the response that L<Catalyst> returns. We could use a bit of sugar here to
+make it easier to mount the L<PSGI> application under the current action
+namespace (for example) but this really is the minimal viable useful feature
+upon which all that coould later be built, should we find it useful to do so.
+
+Alll things being equal, I'd prefer to see this method refactored a bit, rather
+than one big method with so many conditionals. However I was concerned about
+adding to the L<Catalyst::Response> namespace, particularly since the request
+object is something L<Catalyst> explicitly makes public and replacable. We have
+no idea whats going on in the darkpan, so its best to err on the side of making
+the smallest footprint in the code that we can.
+
+=head1 Code Walkthrough
+
+Starting from the top:
+
+ sub from_psgi_response {
+ my ($self, $psgi_res) = @_;
+
+Declare the new method and slurp up the expected arguments. In this case we
+expect just a single argument which is the L<PSGI> compliant response. This
+is sure to be a reference of some type, but we'll need to inspect it a bit
+to figure out the correct handling:
+
+ if(ref $psgi_res eq 'ARRAY') {
+ my ($status, $headers, $body) = @$psgi_res;
+ $self->status($status);
+ $self->headers(HTTP::Headers->new(@$headers));
+
+So if you recall from the test case, we know that the L<PSGI> response is going
+to be an ArrayRef or a CodeRef. Let's handle the easy case first, since if the
+response is an ArrayRef that means its all complete and we can just map it to
+the L<Catalyst::Response> directly. As you can see mapping the C<status> and
+C<headers> is straightforward. Let's see the code to map the C<body>:
+
+ if(ref $body eq 'ARRAY') {
+ $self->body(join '', grep defined, @$body);
+ } else {
+ $self->body($body);
+ }
+
+This is a bit more tricky since the C<body> can be a filehandle like object
+or an ArrayRef. L<Catalyst> allows for string bodies or filehandles, which
+means in the case of it being an ArrayRef we need to flatten it to a string.
+
+I seriously considered changing L<Catalyst> to allow for a ArrayRef body,
+but in the end I felt it was too much risk for what seemed like small reward
+at this time. Perhaps in a future release?
+
+So, what about the second case, when the L<PSGI> response is a coderef?
+
+ } elsif(ref $psgi_res eq 'CODE') {
+
+The specification says when the response is a coderef (this is considered a
+delayed response) the server should obtain the actual response by calling that
+coderef with coderef of its own. In this case since L<Catalyst> is hosting the
+L<PSGI> application, we can consider it the server for now. Lets build the
+coderef we want to pass to the delayed response (if you look at L<PSGI> and
+related L<Plack> examples, this second coderef is often call the responder,
+and conventionally called $responder or $respond in code examples).
+
+ $psgi_res->(sub {
+ my $response = shift;
+ my ($status, $headers, $maybe_body) = @$response;
+ $self->status($status);
+ $self->headers(HTTP::Headers->new(@$headers));
+
+The L<PSGI> application that is returning a delayed response has two options
+but the both start the same way. It must call the $responder coderef with
+at least the first two parts of the classic L<PSGI> tuple, the C<status> and
+C<headers>. It then may or may not return the C<body> arrayref or filehandle
+at this point. If you refer back to the test case we wrote for L<Catalyst>
+you can see what such an application would look like:
+
+ my $psgi_app = sub {
+ my $responder = shift;
+ return $responder->([200, ['Content-Type'=>'text/plain'],
+ [qw/hello world today2/]]);
+ };
+
+In this example the L<PSGI> application is returning the full tuple. This
+is the case we handle first:
+
+ if($maybe_body) {
+ if(ref $maybe_body eq 'ARRAY') {
+ $self->body(join '', grep defined, @$maybe_body);
+ } else {
+ $self->body($maybe_body);
+ }
+ }
+
+Here we find that the C<body> is ready to go, so we do the "is it an arrayref
+or a filehandle" dance again and then we are done.
+
+However there's yet one final option. The L<PSGI> application may choose to
+not return the C<body> immediately. You would do this in cases where the
+body response is streamed, or if you are running the application in an event
+loop and the body is being created in response to events (such as the result
+of a database query). In this case, the $responder coderef is expected to
+return a L<PSGI> writer object, which does at least two methods, C<write> and
+C<close>. This way your application can continue to stream output via the
+C<write> method and when its done you call C<close>.
+
+Its actually a bit more complicated, since ideally you'd also monitor for the
+case where you lose the connection between the client and server, but for ease
+of illustration, lets assume the streaming response is just like in the test
+case above:
+
+ my $psgi_app = sub {
+ my $responder = shift;
+ my $writer = $responder->([200, ['Content-Type'=>'text/plain']]);
+ $writer->write('hello');
+ $writer->write('world');
+ $writer->write('today3');
+ $writer->close;
+ };
+
+This is a very trivial case, but it shows the basics of the interface. How do
+we handle this?
+
+ else {
+ return $self->write_fh;
+ }
+
+The C<write_fh> accessor of L<Catalyst::Response> gives you the raw writer
+object which has been passed down to L<Catalyst> from the server under which
+it runs. All such objects must do the C<write> and C<close> methods but the
+actual clase of the object will be specific to the server you are running
+L<Catalyst> on. The C<writer> object gets returned up to the delayed L<PSGI>
+application via the C<responder> for that case when the application does not
+provide the full C<body>.
+
+And that's the walkthrough!
+
+=head1 Prior Art
+
+Much of the inspiration and incentive to do this work came from
+L<Catalyst::Action::FromPSGI>
+
+=head1 Summary
+
+Diving into Catalyst codebase can be a bit daunting, due to its age and how its
+changed over the years. By detailing the steps involved in extending L<Catalyst>
+its our hope you will have a better understanding of the process and have an
+easier time should you try yourself.
+
+=head1 Author
+
+John Napiorkowski L<email:jjnapiork at cpan.org>
+
+=cut
Copied: trunk/examples/CatalystAdvent/root/2013/8.pod (from rev 14469, trunk/examples/CatalystAdvent/root/2013/08.pod)
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/8.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2013/8.pod 2013-12-02 08:16:06 UTC (rev 14470)
@@ -0,0 +1,168 @@
+=head1 Matching Actions on Request Content Types
+
+=head1 Overview
+
+A quick example of how to use the Request Content Type matching feature
+in L<Catalyst> version 5.90050+.
+
+=head1 Introduction
+
+Beginning in the v5.90050 release of L<Catalyst> we introduced into core the
+ability to match your controller actions to the content types of incoming
+HTTP requests. This allows you to match actions to the contents of the
+HTTP request content type header. As a result, you can dispatch to your
+actions based on if the incoming request is a JSON post, a classic form
+data post, or some other type.
+
+=head1 Why dispatch on Request Content Type?
+
+Modern web developers consider RESTful principles when crafting web APIs
+and in creating meaninful URL structures for thier websites. One core principle
+of REST is that a given resource (in this case a URL) can have many
+representations (HTML, XML, JSON, etc.) In the past, many people used a
+L<Catalyst> addin, L<Catalyst::Action::REST>, which provided a toolkit to
+deserialize many different content types and provide them to an action. This
+works well and we still recommend L<Catalyst::Action::REST> for this and for
+many of its other features. However there are cases when you want to process
+things differently depending on the request content type. In addition, there
+might be times when you don't need all the power and features of
+L<Catalyst::Action::REST> but still want to dispatch on incoming request types
+(for example you might have a website with a form and you'd like to support
+both JSON and classic HTML POSTing). In those cases the ability to dispatch to
+a given action based on matching a content type is useful.
+
+=head1 How Does it Work?
+
+Let's look at some example actions:
+
+ sub as_json : POST Path('/echo')
+ Consumes('application/json') { ... }
+
+ sub as_formdata : POST Path('/echo')
+ Consumes('application/x-www-form-urlencoded') { ... }
+
+In this example the same URL ('/echo') would be server by either JSON or by
+classic form data. The L<Catalyst> dispatcher will choose the correct action
+based on the information tagged to the action by the subroutine attribute
+C<Consumes>. The generic form of usages is "Consumes($type)" where $type is
+a standard content type. Here's a few of the more common types you might
+encounter:
+
+=over 4
+
+=item application/json
+
+JSON encoded data "{'message' : 'hello'}"
+
+=item application/x-www-form-urlencoded
+
+HTML form post
+
+=item multipart/form-data
+
+Form posting with file uploads
+
+=back
+
+Since there's several content types that are in common usage, we provide
+shortcuts, which work in the form "Consumes($shortcut)" where $shortcut is:
+
+ JSON => 'application/json',
+ JS => 'application/javascript',
+ PERL => 'application/perl',
+ HTML => 'text/html',
+ XML => 'text/xml',
+ Plain => 'text/plain',
+ UrlEncoded => 'application/x-www-form-urlencoded',
+ Multipart => 'multipart/form-data',
+ HTMLForm => ['application/x-www-form-urlencoded','multipart/form-data'],
+
+And would look like:
+
+ sub as_json : POST Path('/echo')
+ Consumes(JSON) { ... }
+
+ sub as_formdata : POST Path('/echo')
+ Consumes(HTMLForm) { ... }
+
+As with other such subroutine attributes, you can match more than one on a
+given action (which does an OR style match).
+
+ sub is_more_than_one
+ : Chained('start')
+ : Consumes(UrlEncoded)
+ : Consumes(Multipart)
+
+See L<Catalyst::Controller/Consumes> and L<Catalyst::ActionRole::ConsumesContent>
+for more details and examples.
+
+=head1 A Full Example
+
+An example controller:
+
+ package MyApp::Controller::Root;
+
+ use base 'Catalyst::Controller';
+
+ sub as_json : POST Path('/echo')
+ Consumes('application/json') {
+ my ($self, $c) = @_;
+ $c->response->body(
+ $c->request->body_data->{message});
+
+ }
+
+ sub formdata : POST Path('/echo')
+ Consumes('application/x-www-form-urlencoded') {
+ my ($self, $c) = @_;
+ $c->response->body(
+ $c->request->body_parameters->{message});
+ }
+
+You should note the use the new L<Catalyst::Request> method C<body_data>
+to parsing incoming JSON. This was added in v5.90050 in the Fall of 2013.
+For more information on C<body_data> see L<Catalyst::Request/req-body_data>
+and L<Catalyst/DATA-HANDLERS>.
+
+The test case for this controller:
+
+ use Test::Most;
+ use Catalyst::Test 'MyApp';
+ use HTTP::Request::Common;
+ use JSON::MaybeXS;
+
+ {
+ ok my $req = POST '/echo',
+ Content_Type => 'application/json',
+ Content => encode_json +{message=>'test'};
+
+ ok my $res = request $req;
+
+ is $res->content, 'test', 'Handles JSON post';
+ }
+
+ {
+ ok my $req = POST '/echo', [message=>'test'];
+ ok my $res = request $req;
+
+ is $res->content, 'test', 'Handles classic HTML post';
+ }
+
+ done_testing;
+
+You can see the full application source on Github:
+
+L<https://github.com/perl-catalyst/2013-Advent-Staging>.
+
+=head1 Summary
+
+Request content matching is a useful feature to have in Core L<Catalyst> which
+lets you make more meaningful URLs. It also plays nice with existing addons
+such as L<Catalyst::Action::REST> when you are using L<Catalyst> to craft your
+web APIs.
+
+=head1 Author
+
+John Napiorkowski L<email:jjnapiork at cpan.org>
+
+=cut
Copied: trunk/examples/CatalystAdvent/root/2013/9.pod (from rev 14469, trunk/examples/CatalystAdvent/root/2013/09.pod)
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/9.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2013/9.pod 2013-12-02 08:16:06 UTC (rev 14470)
@@ -0,0 +1,328 @@
+=head1 An Example Catalyst Plugin - Catalyst::Plugin::RunRequest
+
+=head1 OVERVIEW
+
+Port L<Web::Simple>'s feature C<run_test_request> to a L<Catalyst> plugin.
+
+=head1 INTRODUCTION
+
+Generally I tell people there are few good reasons to write a L<Catalyst::Plugin>.
+As a unit of reusability, its a pretty heavy hammer, since a plugin become part
+of your application and context, that means its available everywhere all the time
+and of course it also means that your $c and $app are a little bigger memory wise
+and you incur any startup penalties for every single request. With so many ways
+to wrap and reuse functionality (as a Model, ControllerRole or ActionRole, for
+example) there's nearly never a good reason to write a Plugin. And now that
+L<Catalyst> is L<PSGI> native, I usually say anything related to the global
+request or response is probably better off written as L<Plack::Middleware>.
+
+However, if you are looking for something that is global, and is related to
+application functionality, a plugin is still a rational option. Here's an
+example plugin I did that mimics some functionality from another Perl web
+framework, L<Web::Simple>.
+
+=head1 Web::Simple::Application->run_test_request
+
+L<Web::Simple> has a neat feature that makes it easy to run a sample request
+in a test case or via the command line. We'll leave the CLI for now (its a bit
+trickier based on the way L<Catalyst> does setup) but as it turns out, mimicing
+the underlying function is very easy to do. It would make a rational plugin and
+its also a good opportunity to review some of Catalyst's PSGI guts.
+
+Here's how it works in L<Web::Simple>. You write a basic web application
+like so:
+
+ package MyWSApp;
+
+ use Web::Simple;
+
+ sub dispatch_request {
+ sub (GET + /helloworld) {
+ [ 200, [ 'Content-type', 'text/plain' ], [ 'Hello world!' ] ]
+ },
+ sub (POST + /echo + %:val=) {
+ [ 200, [ 'Content-type', 'text/plain' ], [ $_{val} ] ]
+ },
+ }
+
+ __PACKAGE__->run_if_script;
+
+Now, in a test case you could write:
+
+ use Test::Most;
+ use MyWSApp;
+
+ {
+ ok my $http_response = MyWSApp->run_test_request(GET '/helloworld');
+ is $http_response->content, 'Hello world!';
+ }
+
+ {
+ ok my $http_response = MyWSApp->run_test_request(POST '/echo', [val=>'posted']);
+ is $http_response->content, 'posted';
+ }
+
+ {
+ ok my $http_response = MyWSApp->run_test_request('GET' => '/helloworld');
+ is $http_response->content, 'Hello world!';
+ }
+
+ {
+ ok my $http_response = MyWSApp->run_test_request('POST' => '/echo', {val=>'posted'});
+ is $http_response->content, 'posted';
+ }
+
+ done_testing;
+
+In L<Web::Simple> the C<run_test_request> method accepts either a L<HTTP::Request>
+object (built by hand or via L<HTTP::Request::Common> which is my personal
+favored approach) or it can take a data structure so you don't need to load any
+additional modules (if you look carefully at the given example, its very similar
+to the L<HTTP::Request::Common> style code). The idea here is to take any sort
+of L<HTTP::Request> and get the L<HTTP::Response> out of it.
+
+So that's nice, concise and simple. Sure, L<Catalyst::Runtime> ships with
+L<Catalyst::Test> and there's even more powerful testing options on CPAN, but
+there's something to say for having a straightup solution when writing trival
+test cases, or for when you want to demo some code. So, let's write a plugin
+for L<Catalyst> that does this!
+
+=head1 The Plugin
+
+Lets take this line by line. Lets assume you've create a proper directory
+structure for a Perl distribution (look for links to Github near the end of the
+post for examples) for a new L<Catalyst> plugin called
+'Catalyst::Plugin::RunTestRequest'. Here's the start of the file that would go
+in 'lib/Catalyst/Plugin/RunTestRequest.pm'.
+
+ package Catalyst::Plugin::RunTestRequest;
+
+ use Moose::Role;
+
+ requires 'psgi_app';
+
+In the post L<Moose> port of L<Catalyst> world, its best to write a new plugin
+as a L<Moose::Role>. We specify this role can only be composed into a class
+that has the C<psgi_app> method, which we'll see in moment is needed by the
+new method we are adding to your application class.
+
+Next, let's write the method that will be composed into your application
+subclass:
+
+ sub run_test_request {
+ my ($self, @req) = @_;
+ my $http_request = $_test_request_spec_to_http_request->(@req);
+
+ require HTTP::Message::PSGI;
+ my $psgi_env = HTTP::Message::PSGI::req_to_psgi($http_request);
+ my $psgi_response = $self->psgi_app->($psgi_env);
+ my $http_response = HTTP::Message::PSGI::res_from_psgi($psgi_response);
+
+ return $http_response;
+ }
+
+The first two lines creates the method and slurps up incoming args. We will
+normalize C<@req> via an anonymous subroutine so that we are always dealing
+with an instance of L<HTTP::Request> (and I've simply cribbed a similiarly
+named method from L<Web::Simple::Application>, so I won't go into it, just give
+a big shout out to the L<Web::Simple> cabal). I'll link to the full file at
+the end of the article.
+
+Followed by the required module L<HTTP::Message::PSGI> which lets us convert
+between the various types of requests and responses we'll need to deal with.
+We C<require> this module rather than declare it as a C<use> near the top of
+the file so that we can avoid loading it in the cases when this method is
+never called (thereby saving a bit of memory) and it we also don't call the
+modules C<import> method, so we avoid importing unneeded functions into our
+namespace.
+
+Next we take the normalized L<HTTP::Request> and convert it into a HashRef
+that conforms to the L<PSGI> specification. We pass this to the C<psgi_app>
+method, which is returning a L<PSGI> application, basically a coderef that
+wants that $psgi_env we just made. This is the coderef that kicks off the
+full L<Catalyst> request / response cycle. It returns a $psgi_response,
+which we then convert to a L<HTTP::Response>. Which gets returned to the
+caller.
+
+The full plugin looks like this (and again see links to Github near the end).
+
+ package Catalyst::Plugin::RunTestRequest;
+
+ use Moose::Role;
+
+ requires 'psgi_app';
+
+ our $VERSION = '0.001';
+
+ ## Block of code gratuitously stolen from Web::Simple::Application
+ my $_test_request_spec_to_http_request = sub {
+ my ($method, $path, @rest) = @_;
+
+ # if it's a reference, assume a request object
+ return $method if ref($method);
+
+ if ($path =~ s/^(.*?)\@//) {
+ my $basic = $1;
+ require MIME::Base64;
+ unshift @rest, 'Authorization:', 'Basic '.MIME::Base64::encode($basic);
+ }
+
+ require HTTP::Request;
+
+ my $request = HTTP::Request->new($method => $path);
+
+ my @params;
+
+ while (my ($header, $value) = splice(@rest, 0, 2)) {
+ unless ($header =~ s/:$//) {
+ push @params, $header, $value;
+ }
+ $header =~ s/_/-/g;
+ if ($header eq 'Content') {
+ $request->content($value);
+ } else {
+ $request->headers->push_header($header, $value);
+ }
+ }
+
+ if (($method eq 'POST' or $method eq 'PUT') and @params) {
+ my $content = do {
+ require URI;
+ my $url = URI->new('http:');
+ $url->query_form(@params);
+ $url->query;
+ };
+ $request->header('Content-Type' => 'application/x-www-form-urlencoded');
+ $request->header('Content-Length' => length($content));
+ $request->content($content);
+ }
+
+ return $request;
+ };
+
+ sub run_test_request {
+ my ($self, @req) = @_;
+ my $http_request = $_test_request_spec_to_http_request->(@req);
+
+ require HTTP::Message::PSGI;
+ my $psgi_env = HTTP::Message::PSGI::req_to_psgi($http_request);
+ my $psgi_response = $self->psgi_app->($psgi_env);
+ my $http_response = HTTP::Message::PSGI::res_from_psgi($psgi_response);
+
+ return $http_response;
+ }
+
+ 1;
+
+There's not a lot to it, most if it is the normalization code that lets you
+have a bit of flexibility using the method. Lets build a quick application.
+
+Here's the application class:
+
+ package MyCatApp;
+
+ use Catalyst 'RunTestRequest';
+
+ __PACKAGE__->setup;
+
+L<Catalyst> seems to get a bad rap as needing a lot of boilerplate, but really
+that's all you need for this simple application. Lets make a controller:
+
+ package MyCatApp::Controller::Root;
+
+ use base 'Catalyst::Controller';
+
+ sub root : GET Path('/helloworld') {
+ pop->res->body('Hello world!');
+ }
+
+ sub test_post : POST Path('/echo') {
+ my ($self, $c) = @_;
+ $c->res->body( $c->req->body_parameters->{val} );
+ }
+
+ 1;
+
+Again, there's not a lot of work here. Its realy not many more lines than the
+L<Web::Simple> version, but its spread across more files. That would make more
+sense down the road when you application has 20 controllers and nearly 100
+URL endpoints, but for a simple, demo app like this its still not too bad :)
+
+To be fair, L<Web::Simple> is nice that it has built in support for matching
+on a POST parameter and gives you a default 'not found page', so we'd need
+a little more code to be completely comparable, but this is good enough for a
+demo.
+
+Lets look at the test case. It looks nearly the same as the L<Web::Simple>
+one:
+
+ use HTTP::Request::Common;
+ use Test::Most;
+ use MyCatApp;
+
+ {
+ ok my $http_response = MyCatApp->run_test_request(GET '/helloworld');
+ is $http_response->content, 'Hello world!';
+ }
+
+ {
+ ok my $http_response = MyCatApp->run_test_request(POST '/echo', [val=>'posted']);
+ is $http_response->content, 'posted';
+ }
+
+ {
+ ok my $http_response = MyCatApp->run_test_request('GET' => '/helloworld');
+ is $http_response->content, 'Hello world!';
+ }
+
+ {
+ ok my $http_response = MyCatApp->run_test_request('POST' => '/echo', {val=>'posted'});
+ is $http_response->content, 'posted';
+ }
+
+ done_testing;
+
+And that's really it! Here's the full application with test cases and
+organized as a proper CPAN style distribution:
+
+L<https://github.com/perl-catalyst/2013-Advent-Staging/tree/master/Catalyst-Plugin-RunTestRequest>
+
+=head1 Limitations
+
+Since we run the L<HTTP::Request> (or request specification) directly against
+the C<psgi_app> method of L<Catalyst> if you are using a standalone C<psgi>
+file that declares additional middleware or URL mountpoints, those additional
+bits will not be tested. If you are using middleware are a critical part of
+your L<Catalyst> application, I recommend using the the new middleware
+configuration option: L<Catalyst\PSGI-MIDDLEWARE>. For mounting PSGI
+applications you may prefer to consider L<Catalyst::Response\from_psgi_response>
+or look at the following independent distributions of you are on an older
+version of L<Catalyst>.
+
+L<Catalyst::Plugin::EnableMiddleware>, L<Catalyst::Action::FromPSGI>.
+
+=head1 What other things could you do with this?
+
+I've never loved the way L<Catalyst::Plugin::SubRequest> worked. It would be
+very easy to rewrite or offer another approach using this.
+
+It might be nice to have a sort of commandline REPL that let you run test
+requests against your L<Catalyst> application, with a full request/response
+trace.
+
+=head1 Summary
+
+We reviewed when one might wish to write a L<Catalyst> plugin, what such a
+plugin looks like. We also took a look at how the L<PSGI> underpinnings of
+L<Catalyst> provide a useful gateway to provide novel features.
+
+=head1 For More Information
+
+L<Catalyst>
+
+=head1 Author
+
+John Napiorkowski L<email:jjnapiork at cpan.org>
+
+=cut
+
More information about the Catalyst-commits
mailing list