remove trailing whitespace
Graham Knop [Tue, 22 Jan 2019 17:59:52 +0000 (18:59 +0100)]
22 files changed:
lib/Catalyst/Manual.pm
lib/Catalyst/Manual/Actions.pod
lib/Catalyst/Manual/CatalystAndMoose.pod
lib/Catalyst/Manual/Components.pod
lib/Catalyst/Manual/Deployment/Apache/mod_perl.pod
lib/Catalyst/Manual/Deployment/DevelopmentServer.pod
lib/Catalyst/Manual/Deployment/SharedHosting.pod
lib/Catalyst/Manual/ExtendingCatalyst.pod
lib/Catalyst/Manual/Intro.pod
lib/Catalyst/Manual/Tutorial.pod
lib/Catalyst/Manual/Tutorial/01_Intro.pod
lib/Catalyst/Manual/Tutorial/02_CatalystBasics.pod
lib/Catalyst/Manual/Tutorial/03_MoreCatalystBasics.pod
lib/Catalyst/Manual/Tutorial/04_BasicCRUD.pod
lib/Catalyst/Manual/Tutorial/05_Authentication.pod
lib/Catalyst/Manual/Tutorial/06_Authorization.pod
lib/Catalyst/Manual/Tutorial/07_Debugging.pod
lib/Catalyst/Manual/Tutorial/08_Testing.pod
lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD/09_FormBuilder.pod
lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD/09_FormFu.pod
lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD/09_FormHandler.pod
lib/Catalyst/Manual/Tutorial/10_Appendices.pod

index f969cd3..1c4bb33 100644 (file)
@@ -1,4 +1,4 @@
-# Manual.pm 
+# Manual.pm
 # Copyright (c) 2006 Jonathan Rockway <jrockway@cpan.org>
 
 package Catalyst::Manual;
@@ -22,7 +22,7 @@ Catalyst::Manual - The Catalyst developer's manual
 
 Install L<Task::Catalyst::Tutorial|Task::Catalyst::Tutorial> to
 install all the dependencies you need to follow along with the
-Tutorial.  You can also refer to 
+Tutorial.  You can also refer to
 L<Catalyst::Manual::Tutorial::Intro|Catalyst::Manual::Tutorial::01_Intro>
 for more information on installation options.
 
@@ -72,10 +72,10 @@ For additional information on Catalyst, there are currently two books available:
 
 =item *
 
-The Definitive Guide to Catalyst: Writing Extendable, Scalable and 
+The Definitive Guide to Catalyst: Writing Extendable, Scalable and
 Maintainable Perl-Based Web Applications
 
-By: Kieren Diment, Matt Trout 
+By: Kieren Diment, Matt Trout
 Available July 12, 2009
 ISBN 10: 1-4302-2365-0
 ISBN 13: 978-1-4302-2365-8
index 41247c8..0e0bb19 100644 (file)
@@ -1,6 +1,6 @@
 =head1 NAME
 
-Catalyst::Manual::Actions - Catalyst Reusable Actions 
+Catalyst::Manual::Actions - Catalyst Reusable Actions
 
 =head1 DESCRIPTION
 
@@ -17,7 +17,7 @@ them.
 This is pretty simple. Actions work just like the normal dispatch
 attributes you are used to, like Local or Private:
 
-  sub Hello :Local :ActionClass('SayBefore') { 
+  sub Hello :Local :ActionClass('SayBefore') {
        $c->res->output( 'Hello '.$c->stash->{what} );
   }
 
@@ -38,7 +38,7 @@ the Action class:
   package Catalyst::Action::MyAction;
   use Moose;
   use namespace::autoclean;
-  
+
   extends 'Catalyst::Action';
 
   before 'execute' => sub {
@@ -75,7 +75,7 @@ would make the example above look like this:
       my ( $self, $controller, $c, $test ) = @_;
       $c->stash->{foo} = 'bar';
   };
-  
+
   1;
 
 and this would be used in a controller like this:
@@ -95,7 +95,7 @@ and this would be used in a controller like this:
 
 =head2 Catalyst::Action::RenderView
 
-This is meant to decorate end actions. It's similar in operation to 
+This is meant to decorate end actions. It's similar in operation to
 L<Catalyst::Plugin::DefaultEnd>, but allows you to decide on an action
 level rather than on an application level where it should be run.
 
index 3d0b957..a228c16 100644 (file)
@@ -73,7 +73,7 @@ slightly limits the gains that could be had by wielding the full power
 of L<Moose> attributes.
 
 Most of the accessors to information gathered during compile time (such
-as configuration) are managed by C<Catalyst::ClassData>, which is a 
+as configuration) are managed by C<Catalyst::ClassData>, which is a
 L<Moose>-aware version of L<Class::Data::Inheritable> but not compatible
 with L<MooseX::ClassAttribute>.
 
@@ -115,7 +115,7 @@ the actions themselves are declared:
       use namespace::autoclean;
 
       BEGIN { extends 'Catalyst::Controller'; }
-      
+
 =head2 Controller Roles
 
 It is possible to use roles to apply method modifiers on controller actions
@@ -126,8 +126,8 @@ themselves. For example
     use Moose;
     use namespace::autoclean;
     BEGIN { extends 'Catalyst::Controller' };
-    
-    sub foo : Local { 
+
+    sub foo : Local {
         my ($self, $c) = @_;
         $c->res->body('Hello ');
     }
@@ -135,24 +135,24 @@ themselves. For example
         my ($self, $c) = @_;
         $c->res->body($c->res->body . 'World');
     };
-    
+
 It is possible to have action methods with attributes inside Moose roles, using
 L<MooseX::MethodAttributes>, example:
 
     package MyApp::ControllerRole;
     use MooseX::MethodAttributes::Role;
     use namespace::autoclean;
-    
+
     sub foo : Local {
         my ($self, $c) = @_;
         ...
     }
-    
+
     package MyApp::Controller::Foo;
     use Moose;
     use namespace::autoclean;
     BEGIN { extends 'Catalyst::Controller' };
-    
+
     with 'MyApp::ControllerRole';
 
 =head1 AUTHORS
index 8acd2c4..ff33214 100644 (file)
@@ -143,7 +143,7 @@ This module implements the Catalyst::Authentication API for L<Apache::AuthTkt>.
 
 =head4 L<Catalyst::Authentication::Store::DBI>
 
-Allows you to use a plain L<DBI> database connection to identify users. 
+Allows you to use a plain L<DBI> database connection to identify users.
 
 =head4 L<Catalyst::Authentication::Store::Htpasswd>
 
index 7296890..22da178 100644 (file)
@@ -99,7 +99,7 @@ this has not been confirmed):
         use lib '/var/www/MyApp/lib';
         use MyApp;
     </Perl>
-    
+
     <Location />
         SetHandler          modperl
         PerlResponseHandler MyApp
index 23de797..ca4f32a 100644 (file)
@@ -47,7 +47,7 @@ different apps served on the same host.
 =head2 Other web servers
 
 The proxy configuration above can also be replicated with a different
-frontend server or proxy, such as varnish, nginx, or lighttpd. 
+frontend server or proxy, such as varnish, nginx, or lighttpd.
 
 =head1 AUTHORS
 
index fa3b2b6..fe91770 100644 (file)
@@ -36,7 +36,7 @@ myapp_fastcgi.fcgi and/or use a SetHandler directive):
   RewriteRule ^(.*)$ script/myapp_fastcgi.pl/$1 [PT,L]
 
 Now C<http://mydomain.com/> should now Just Work. Congratulations, now
-you can tell your friends about your new website. 
+you can tell your friends about your new website.
 
 =head1 AUTHORS
 
index 3cc5967..97c31b6 100644 (file)
@@ -312,10 +312,10 @@ method. The execute method of the action will naturally call the
 methods code. You can surround this by overriding the method in a
 subclass:
 
-  package Catalyst::Action::MyFoo; 
+  package Catalyst::Action::MyFoo;
   use Moose;
   use namespace::autoclean;
-  use MRO::Compat; 
+  use MRO::Compat;
   extends 'Catalyst::Action';
 
   sub execute {
@@ -329,12 +329,12 @@ subclass:
   1;
 
 We are using L<MRO::Compat> to ensure that you have the next::method
-call, from L<Class::C3> (in older perls), or natively (if you are using 
-perl 5.10) to re-dispatch to the original C<execute> method in the 
+call, from L<Class::C3> (in older perls), or natively (if you are using
+perl 5.10) to re-dispatch to the original C<execute> method in the
 L<Catalyst::Action> class.
 
 The Catalyst dispatcher handles an incoming request and, depending
-upon the dispatch type, will call the appropriate target or chain. 
+upon the dispatch type, will call the appropriate target or chain.
 From time to time it asks the actions themselves, or through the
 controller, if they would match the current request. That's what the
 C<match> method does.  So by overriding this, you can change on what
@@ -343,7 +343,7 @@ the action will match and add new matching criteria.
 For example, the action class below will make the action only match on
 Mondays:
 
-  package Catalyst::Action::OnlyMondays; 
+  package Catalyst::Action::OnlyMondays;
   use Moose;
   use namespace::autoclean;
   use MRO::Compat;
@@ -466,7 +466,7 @@ with some custom actions by sub-classing it:
   package MyApp::Controller::Foo;
   use Moose;
   use namespace::autoclean;
-  
+
   BEGIN { extends 'MyApp::Base::Controller::ModelBase'; }
 
   __PACKAGE__->config( model_name => 'DB::Foo',
@@ -537,7 +537,7 @@ Here is some example code for a fictional view:
   package Catalyst::View::MyView;
   use Moose;
   use namespace::autoclean;
-  
+
   extends 'Catalyst::View';
 
   sub process {
@@ -637,7 +637,7 @@ A simple example like this is actually better as a L<Moose> role, for example:
       if (!blessed($_[0]) || !$_[0]->isa('Catalyst::Action'));
     return $uri;
   };
-  
+
 Note that Catalyst will load any Moose Roles in the plugin list,
 and apply them to your application class.
 
@@ -660,13 +660,13 @@ Here is a stub C<COMPONENT> method:
   package CatalystX::Component::Foo;
   use Moose;
   use namespace::autoclean;
-  
+
   extends 'Catalyst::Component';
 
   sub COMPONENT {
       my $class = shift;
       # Note: $app is like $c, but since the application isn't fully
-      # initialized, we don't want to call it $c yet.  $config 
+      # initialized, we don't want to call it $c yet.  $config
       # is a hashref of config options possibly set on this component.
       my ($app, $config) = @_;
 
index da1d8db..7bff03f 100644 (file)
@@ -1333,7 +1333,7 @@ If you don't want or need these features then it's perfectly acceptable
         $c->stash->{message} = 'Hello World!';
         $self->check_message( $c, 'test1' );
     }
-    
+
     sub check_message {
         my ( $self, $c, $first_argument ) = @_;
         # do something...
index 12d343b..31eec39 100644 (file)
@@ -65,7 +65,7 @@ L<Appendices|Catalyst::Manual::Tutorial::10_Appendices>
 
 =back
 
-Final code tarballs for each chapter of the tutorial are available at 
+Final code tarballs for each chapter of the tutorial are available at
 L<http://dev.catalyst.perl.org/repos/Catalyst/trunk/examples/Tutorial/>.
 
 
@@ -74,7 +74,7 @@ L<http://dev.catalyst.perl.org/repos/Catalyst/trunk/examples/Tutorial/>.
 
 =head2 L<Chapter 1: Intro|Catalyst::Manual::Tutorial::01_Intro>
 
-Note: Click on the heading in the previous line to jump to the actual 
+Note: Click on the heading in the previous line to jump to the actual
 chapter. Below is a "table of contents" for this chapter.
 
 =over 4
@@ -100,7 +100,7 @@ WHERE TO GET WORKING CODE
 
 =head2 L<Chapter 2: Catalyst Basics|Catalyst::Manual::Tutorial::02_CatalystBasics>
 
-Note: Click on the heading in the previous line to jump to the actual 
+Note: Click on the heading in the previous line to jump to the actual
 chapter. Below is a "table of contents" for this chapter.
 
 =over 4
@@ -134,7 +134,7 @@ CREATE A SIMPLE CONTROLLER AND AN ACTION
 
 =head2 L<Chapter 3: More Catalyst Basics|Catalyst::Manual::Tutorial::03_MoreCatalystBasics>
 
-Note: Click on the heading in the previous line to jump to the actual 
+Note: Click on the heading in the previous line to jump to the actual
 chapter. Below is a "table of contents" for this chapter.
 
 =over 4
@@ -273,7 +273,7 @@ Return To A Manually-Specified Template
 
 =head2 L<Chapter 4: Basic CRUD|Catalyst::Manual::Tutorial::04_BasicCRUD>
 
-Note: Click on the heading in the previous line to jump to the actual 
+Note: Click on the heading in the previous line to jump to the actual
 chapter. Below is a "table of contents" for this chapter.
 
 =over 4
@@ -411,7 +411,7 @@ Adding Methods to Result Classes
 
 =head2 L<Chapter 5: Authentication|Catalyst::Manual::Tutorial::05_Authentication>
 
-Note: Click on the heading in the previous line to jump to the actual 
+Note: Click on the heading in the previous line to jump to the actual
 chapter. Below is a "table of contents" for this chapter.
 
 =over 4
@@ -509,7 +509,7 @@ Switch To Flash-To-Stash
 
 =head2 L<Chapter 6: Authorization|Catalyst::Manual::Tutorial::06_Authorization>
 
-Note: Click on the heading in the previous line to jump to the actual 
+Note: Click on the heading in the previous line to jump to the actual
 chapter. Below is a "table of contents" for this chapter.
 
 =over 4
@@ -551,7 +551,7 @@ ENABLE MODEL-BASED AUTHORIZATION
 
 =head2 L<Chapter 7: Debugging|Catalyst::Manual::Tutorial::07_Debugging>
 
-Note: Click on the heading in the previous line to jump to the actual 
+Note: Click on the heading in the previous line to jump to the actual
 chapter. Below is a "table of contents" for this chapter.
 
 =over 4
@@ -577,7 +577,7 @@ TT DEBUGGING
 
 =head2 L<Chapter 8: Testing|Catalyst::Manual::Tutorial::08_Testing>
 
-Note: Click on the heading in the previous line to jump to the actual 
+Note: Click on the heading in the previous line to jump to the actual
 chapter. Below is a "table of contents" for this chapter.
 
 =over 4
@@ -603,7 +603,7 @@ SUPPORTING BOTH PRODUCTION AND TEST DATABASES
 
 =head2 L<Chapter 9: Advanced CRUD|Catalyst::Manual::Tutorial::09_AdvancedCRUD>
 
-Note: Click on the heading in the previous line to jump to the actual 
+Note: Click on the heading in the previous line to jump to the actual
 chapter. Below is a "table of contents" for this chapter.
 
 =over 4
@@ -617,7 +617,7 @@ ADVANCED CRUD OPTIONS
 
 =head2 L<Chapter 10: Appendices|Catalyst::Manual::Tutorial::10_Appendices>
 
-Note: Click on the heading in the previous line to jump to the actual 
+Note: Click on the heading in the previous line to jump to the actual
 chapter. Below is a "table of contents" for this chapter.
 
 =over 4
@@ -663,8 +663,8 @@ APPENDIX 3: IMPROVED HASHING SCRIPT
 
 =head1 THANKS
 
-This tutorial would not have been possible without the input of many 
-different people in the Catalyst community.  In particular, the 
+This tutorial would not have been possible without the input of many
+different people in the Catalyst community.  In particular, the
 primary author would like to thank:
 
 =over 4
@@ -690,7 +690,7 @@ key Catalyst modules.
 
 Other Catalyst documentation folks like Kieren Diment, Gavin Henry,
 and Jess Robinson (including their work on the original Catalyst
-tutorial).  
+tutorial).
 
 =item *
 
@@ -707,18 +707,18 @@ PostgreSQL content in the Appendix.
 
 =item *
 
-People who have emailed me with corrections and suggestions on the 
-tutorial. As of the most recent release, this include: Florian Ragwitz, 
-Mauro Andreolini, Jim Howard, Giovanni Gigante, William Moreno, Bryan 
-Roach, Ashley Berlin, David Kamholz, Kevin Old, Henning Sprang, Jeremy 
-Jones, David Kurtz, Ingo Wichmann, Shlomi Fish, Murray Walker, Adam 
-Witney and xenoterracide (Caleb Cushing). Thanks to Devin Austin for 
-coming up with an initial version of a non-TTSite wrapper page. Also, a 
-huge thank you to Kiffin Gish for all the hard work on the "database 
-depluralization" effort and Rafael Kitover for the work on updating the 
-tutorial to include foreign key support for SQLite. I'm sure I am 
-missing some names here... apologies for that (please let me know if you 
-name should be here). 
+People who have emailed me with corrections and suggestions on the
+tutorial. As of the most recent release, this include: Florian Ragwitz,
+Mauro Andreolini, Jim Howard, Giovanni Gigante, William Moreno, Bryan
+Roach, Ashley Berlin, David Kamholz, Kevin Old, Henning Sprang, Jeremy
+Jones, David Kurtz, Ingo Wichmann, Shlomi Fish, Murray Walker, Adam
+Witney and xenoterracide (Caleb Cushing). Thanks to Devin Austin for
+coming up with an initial version of a non-TTSite wrapper page. Also, a
+huge thank you to Kiffin Gish for all the hard work on the "database
+depluralization" effort and Rafael Kitover for the work on updating the
+tutorial to include foreign key support for SQLite. I'm sure I am
+missing some names here... apologies for that (please let me know if you
+name should be here).
 
 =back
 
index bb2a56e..42e53e4 100644 (file)
@@ -115,7 +115,7 @@ Subjects covered by the tutorial include:
 
 =over 4
 
-=item * 
+=item *
 
 A simple application that lists and adds books.
 
@@ -125,7 +125,7 @@ The use of L<DBIx::Class> (DBIC) for the model (including
 some of the more advanced techniques you will probably want to use in
 your applications).
 
-=item * 
+=item *
 
 How to write CRUD (Create, Read, Update, and Delete) operations in
 Catalyst.
@@ -134,25 +134,25 @@ Catalyst.
 
 Authentication ("auth").
 
-=item * 
+=item *
 
 Role-based authorization ("authz").
 
-=item * 
+=item *
 
 Attempts to provide an example showing current (5.9) Catalyst
 practices.
 
-=item * 
+=item *
 
 The use of Template Toolkit (TT).
 
-=item * 
+=item *
 
 Useful techniques for troubleshooting and debugging Catalyst
 applications.
 
-=item * 
+=item *
 
 The use of SQLite as a database (with code also provided for MySQL and
 PostgreSQL).  (Note: Because we make use of the DBIx::Class Object
@@ -160,7 +160,7 @@ Relational Mapping [ORM] layer, out our application will be database
 agnostic and can easily be used by any of the databases supported by
 DBIx::Class.)
 
-=item * 
+=item *
 
 The use of L<HTML::FormFu> or L<HTML::FormHandler>
 for automated form processing and validation.
@@ -203,7 +203,7 @@ current directory), but we will keep it short and just use "C<$>".
 
 =over 4
 
-=item 1 
+=item 1
 
 Download a Tutorial Virtual Machine image from
 L<http://cattut.shadowcat.co.uk/>
@@ -481,11 +481,11 @@ v5.80020 might show up as 5.8002):
 
 =over 4
 
-=item * 
+=item *
 
 Debian 6 (Squeeze)
 
-=item * 
+=item *
 
 Catalyst v5.90002
 
@@ -493,7 +493,7 @@ Catalyst v5.90002
 
 Catalyst::Devel v1.34
 
-=item * 
+=item *
 
 DBIx::Class v0.08195
 
@@ -510,7 +510,7 @@ Template Toolkit v2.22
 
 HTML::FormFu -- v0.09004
 
-=item * 
+=item *
 
 B<NOTE:> You can check the versions you have installed with the
 following command (note the slash before the space):
@@ -529,7 +529,7 @@ or:
 
     perl -MCatalyst::Devel -e 'print "$Catalyst::Devel::VERSION\n";'
 
-=item * 
+=item *
 
 This tutorial will show URLs in the format of C<http://localhost:3000>,
 but if you are running your web browser from outside the Tutorial
index 2319bea..c4524ec 100644 (file)
@@ -146,7 +146,7 @@ directories and files it creates:
     Changes               # Record of application changes
     lib                   # Lib directory for your app's Perl modules
         Hello             # Application main code directory
-            Controller    # Directory for Controller modules 
+            Controller    # Directory for Controller modules
             Model         # Directory for Models
             View          # Directory for Views
         Hello.pm          # Base application module
@@ -164,9 +164,9 @@ directories and files it creates:
         hello_server.pl   # The normal development server
         hello_test.pl     # Test your app from the command line
     t                     # Directory for tests
-        01app.t           # Test scaffold       
-        02pod.t           
-        03podcoverage.t 
+        01app.t           # Test scaffold
+        02pod.t
+        03podcoverage.t
 
 
 Catalyst will "auto-discover" modules in the Controller, Model, and View
@@ -202,7 +202,7 @@ C<Ctrl-C> to breakout of the dev server) if you prefer.
     .----------------------------------------------------------------------------.
     | Catalyst::Plugin::ConfigLoader  0.30                                       |
     '----------------------------------------------------------------------------'
-    
+
     [debug] Loaded dispatcher "Catalyst::Dispatcher"
     [debug] Loaded engine "Catalyst::Engine"
     [debug] Found home "/home/catalyst/Hello"
@@ -213,7 +213,7 @@ C<Ctrl-C> to breakout of the dev server) if you prefer.
     +-----------------------------------------------------------------+----------+
     | Hello::Controller::Root                                         | instance |
     '-----------------------------------------------------------------+----------'
-    
+
     [debug] Loaded Private actions:
     .----------------------+--------------------------------------+--------------.
     | Private              | Class                                | Method       |
@@ -222,7 +222,7 @@ C<Ctrl-C> to breakout of the dev server) if you prefer.
     | /end                 | Hello::Controller::Root              | end          |
     | /index               | Hello::Controller::Root              | index        |
     '----------------------+--------------------------------------+--------------'
-    
+
     [debug] Loaded Path actions:
     .-------------------------------------+--------------------------------------.
     | Path                                | Private                              |
@@ -230,7 +230,7 @@ C<Ctrl-C> to breakout of the dev server) if you prefer.
     | /                                   | /index                               |
     | /                                   | /default                             |
     '-------------------------------------+--------------------------------------'
-    
+
     [info] Hello powered by Catalyst 5.90002
     HTTP::Server::PSGI: Accepting connections at http://0:3000/
 
@@ -271,7 +271,7 @@ browser.
 
     sub index :Path :Args(0) {
         my ( $self, $c ) = @_;
-    
+
         # Hello World
         $c->response->body( $c->welcome_message );
     }
@@ -318,7 +318,7 @@ C<lib/Hello/Controller/Root.pm> file:
 
     sub hello :Global {
         my ( $self, $c ) = @_;
-    
+
         $c->response->body("Hello, World!");
     }
 
@@ -330,7 +330,7 @@ get output similar to the following:
 
     Saw changes to the following files:
      - /home/catalyst/Hello/lib/Hello/Controller/Root.pm (modify)
-    
+
     Attempting to restart the server
     ...
     [debug] Loaded Private actions:
@@ -420,7 +420,7 @@ following:
 
     sub hello :Global {
         my ( $self, $c ) = @_;
-    
+
         $c->stash(template => 'hello.tt');
     }
 
@@ -454,12 +454,12 @@ Although this style is still relatively common, the approach we
 used previous is becoming more common because it allows you to
 set multiple stash variables in one line.  For example:
 
-    $c->stash(template => 'hello.tt', foo => 'bar', 
+    $c->stash(template => 'hello.tt', foo => 'bar',
               another_thing => 1);
 
 You can also set multiple stash values with a hashref:
 
-    $c->stash({template => 'hello.tt', foo => 'bar', 
+    $c->stash({template => 'hello.tt', foo => 'bar',
               another_thing => 1});
 
 Any of these formats work, but the C<$c-E<gt>stash(name =E<gt> value);>
@@ -481,7 +481,7 @@ In C<lib/Hello/Controller/Site.pm>, add the following method:
 
     sub test :Local {
         my ( $self, $c ) = @_;
-    
+
         $c->stash(username => 'John',
                   template => 'site/test.tt');
     }
index 39b818a..9bf0ce3 100644 (file)
@@ -223,7 +223,7 @@ Then replace it with:
         -Debug
         ConfigLoader
         Static::Simple
-    
+
         StackTrace
     /;
 
@@ -311,23 +311,23 @@ each of the three parts of MVC: C<Model>, C<View> and C<Controller>)
 and add the following method to the controller:
 
     =head2 list
-    
+
     Fetch all book objects and pass to books/list.tt2 in stash to be displayed
-    
+
     =cut
-    
+
     sub list :Local {
         # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
         # 'Context' that's used to 'glue together' the various components
         # that make up the application
         my ($self, $c) = @_;
-    
+
         # Retrieve all of the book records as book model objects and store in the
         # stash where they can be accessed by the TT template
         # $c->stash(books => [$c->model('DB::Book')->all]);
         # But, for now, use this code until we create the model later
         $c->stash(books => '');
-    
+
         # Set the TT template to use.  You will almost always want to do this
         # in your action methods (action methods respond to user input in
         # your controllers).
@@ -549,14 +549,14 @@ First create a directory for book-related TT templates:
 Then create C<root/src/books/list.tt2> in your editor and enter:
 
     [% # This is a TT comment. -%]
-    
+
     [%- # Provide a title -%]
     [% META title = 'Book List' -%]
-    
+
     [% # Note That the '-' at the beginning or end of TT code  -%]
     [% # "chomps" the whitespace/newline at that end of the    -%]
     [% # output (use View Source in browser to see the effect) -%]
-    
+
     [% # Some basic HTML with a loop to display books -%]
     <table>
     <tr><th>Title</th><th>Rating</th><th>Author(s)</th></tr>
@@ -886,21 +886,21 @@ left disabled earlier so that your version matches the following
 and delete the next 2 lines):
 
     =head2 list
-    
+
     Fetch all book objects and pass to books/list.tt2 in stash to be displayed
-    
+
     =cut
-    
+
     sub list :Local {
         # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
         # 'Context' that's used to 'glue together' the various components
         # that make up the application
         my ($self, $c) = @_;
-    
+
         # Retrieve all of the book records as book model objects and store
         # in the stash where they can be accessed by the TT template
         $c->stash(books => [$c->model('DB::Book')->all]);
-    
+
         # Set the TT template to use.  You will almost always want to do this
         # in your action methods (action methods respond to user input in
         # your controllers).
@@ -959,7 +959,7 @@ display something like:
     | Catalyst::Plugin::ConfigLoader  0.30                                       |
     | Catalyst::Plugin::StackTrace  0.11                                         |
     '----------------------------------------------------------------------------'
-    
+
     [debug] Loaded dispatcher "Catalyst::Dispatcher"
     [debug] Loaded engine "Catalyst::Engine"
     [debug] Found home "/home/catalyst/MyApp"
@@ -976,7 +976,7 @@ display something like:
     | MyApp::Model::DB::BookAuthor                                    | class    |
     | MyApp::View::HTML                                               | instance |
     '-----------------------------------------------------------------+----------'
-    
+
     [debug] Loaded Private actions:
     .----------------------+--------------------------------------+--------------.
     | Private              | Class                                | Method       |
@@ -987,7 +987,7 @@ display something like:
     | /books/index         | MyApp::Controller::Books             | index        |
     | /books/list          | MyApp::Controller::Books             | list         |
     '----------------------+--------------------------------------+--------------'
-    
+
     [debug] Loaded Path actions:
     .-------------------------------------+--------------------------------------.
     | Path                                | Private                              |
@@ -997,7 +997,7 @@ display something like:
     | /books                              | /books/index                         |
     | /books/list                         | /books/list                          |
     '-------------------------------------+--------------------------------------'
-    
+
     [info] MyApp powered by Catalyst 5.80020
     HTTP::Server::PSGI: Accepting connections at http://0:3000
 
@@ -1091,7 +1091,7 @@ the tutorial, open C<root/src/wrapper.tt2> and input the following:
     <title>[% template.title or "My Catalyst App!" %]</title>
     <link rel="stylesheet" href="[% c.uri_for('/static/css/main.css') %]" />
     </head>
-    
+
     <body>
     <div id="outer">
     <div id="header">
@@ -1100,7 +1100,7 @@ the tutorial, open C<root/src/wrapper.tt2> and input the following:
         [%# Insert the page title -%]
         <h1>[% template.title or site.title %]</h1>
     </div>
-    
+
     <div id="bodyblock">
     <div id="menu">
         Navigation:
@@ -1110,7 +1110,7 @@ the tutorial, open C<root/src/wrapper.tt2> and input the following:
                 %]" title="Catalyst Welcome Page">Welcome</a></li>
         </ul>
     </div><!-- end menu -->
-    
+
     <div id="content">
         [%# Status and error messages %]
         <span class="message">[% status_msg %]</span>
@@ -1119,10 +1119,10 @@ the tutorial, open C<root/src/wrapper.tt2> and input the following:
         [% content %]
     </div><!-- end content -->
     </div><!-- end bodyblock -->
-    
+
     <div id="footer">Copyright (c) your name goes here</div>
     </div><!-- end outer -->
-    
+
     </body>
     </html>
 
@@ -1237,15 +1237,15 @@ keys. For example, take a look at C<lib/MyApp/Schema/Result/Book.pm> and
 notice the following code:
 
     =head1 RELATIONS
-    
+
     =head2 book_authors
-    
+
     Type: has_many
-    
+
     Related object: L<MyApp::Schema::Result::BookAuthor>
-    
+
     =cut
-    
+
     __PACKAGE__->has_many(
       "book_authors",
       "MyApp::Schema::Result::BookAuthor",
@@ -1306,15 +1306,15 @@ there is a C<belongs_to> relationship defined that acts as the "mirror
 image" to the C<has_many> relationship we just looked at above:
 
     =head1 RELATIONS
-    
+
     =head2 book
-    
+
     Type: belongs_to
-    
+
     Related object: L<MyApp::Schema::Result::Book>
-    
+
     =cut
-    
+
     __PACKAGE__->belongs_to(
       "book",
       "MyApp::Schema::Result::Book",
@@ -1442,15 +1442,15 @@ debug output (one for each book as the authors are being retrieved by
 DBIx::Class):
 
     SELECT me.id, me.title, me.rating FROM book me:
-    SELECT author.id, author.first_name, author.last_name FROM book_author me  
+    SELECT author.id, author.first_name, author.last_name FROM book_author me
     JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '1'
-    SELECT author.id, author.first_name, author.last_name FROM book_author me  
+    SELECT author.id, author.first_name, author.last_name FROM book_author me
     JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '2'
-    SELECT author.id, author.first_name, author.last_name FROM book_author me  
+    SELECT author.id, author.first_name, author.last_name FROM book_author me
     JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '3'
-    SELECT author.id, author.first_name, author.last_name FROM book_author me  
+    SELECT author.id, author.first_name, author.last_name FROM book_author me
     JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '4'
-    SELECT author.id, author.first_name, author.last_name FROM book_author me  
+    SELECT author.id, author.first_name, author.last_name FROM book_author me
     JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '5'
 
 Also note in C<root/src/books/list.tt2> that we are using "| html", a
@@ -1564,7 +1564,7 @@ this URL:
 
 You should get a page with the following message at the top:
 
-    Caught exception in MyApp::Controller::Root->end "Forced debug - 
+    Caught exception in MyApp::Controller::Root->end "Forced debug -
     Scrubbed output at /usr/share/perl5/Catalyst/Action/RenderView.pm line 46."
 
 Along with a summary of your application's state at the end of the
@@ -1594,21 +1594,21 @@ this line to match the following (only the
 C<$c-E<gt>stash-E<gt>{template}> line has changed):
 
     =head2 list
-    
+
     Fetch all book objects and pass to books/list.tt2 in stash to be displayed
-    
+
     =cut
-    
+
     sub list :Local {
         # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
         # 'Context' that's used to 'glue together' the various components
         # that make up the application
         my ($self, $c) = @_;
-    
+
         # Retrieve all of the book records as book model objects and store in the
         # stash where they can be accessed by the TT template
         $c->stash(books => [$c->model('DB::Book')->all]);
-    
+
         # Set the TT template to use.  You will almost always want to do this
         # in your action methods (actions methods respond to user input in
         # your controllers).
index f84c3d7..0df6ab2 100644 (file)
@@ -93,35 +93,35 @@ submission in the sections that follow).
 Edit C<lib/MyApp/Controller/Books.pm> and enter the following method:
 
     =head2 url_create
-    
+
     Create a book with the supplied title, rating, and author
-    
+
     =cut
-    
+
     sub url_create :Local {
         # In addition to self & context, get the title, rating, &
         # author_id args from the URL.  Note that Catalyst automatically
         # puts extra information after the "/<controller_name>/<action_name/"
         # into @_.  The args are separated  by the '/' char on the URL.
         my ($self, $c, $title, $rating, $author_id) = @_;
-    
+
         # Call create() on the book model object. Pass the table
         # columns/field values we want to set as hash values
         my $book = $c->model('DB::Book')->create({
                 title  => $title,
                 rating => $rating
             });
-    
+
         # Add a record to the join table for this book, mapping to
         # appropriate author
         $book->add_to_book_authors({author_id => $author_id});
         # Note: Above is a shortcut for this:
         # $book->create_related('book_authors', {author_id => $author_id});
-    
+
         # Assign the Book object to the stash for display and set template
         $c->stash(book     => $book,
                   template => 'books/create_done.tt2');
-    
+
         # Disable caching for this page
         $c->response->header('Cache-Control' => 'no-cache');
     }
@@ -152,7 +152,7 @@ Edit C<root/src/books/create_done.tt2> and then enter:
     [% # Not a good idea for production use, though. :-)  'Indent=1' is      -%]
     [% # optional, but prevents "massive indenting" of deeply nested objects -%]
     [% USE Dumper(Indent=1) -%]
-    
+
     [% # Set the page title.  META can 'go back' and set values in templates -%]
     [% # that have been processed 'before' this template (here it's updating -%]
     [% # the title in the root/src/wrapper.tt2 wrapper template).  Note that -%]
@@ -160,20 +160,20 @@ Edit C<root/src/books/create_done.tt2> and then enter:
     [% # interpolation -- if you need dynamic/interpolated content in your   -%]
     [% # title, set "$c->stash(title => $something)" in the controller).     -%]
     [% META title = 'Book Created' %]
-    
+
     [% # Output information about the record that was added.  First title.   -%]
     <p>Added book '[% book.title %]'
-    
+
     [% # Then, output the last name of the first author -%]
     by '[% book.authors.first.last_name %]'
-    
+
     [% # Then, output the rating for the book that was added -%]
     with a rating of [% book.rating %].</p>
-    
+
     [% # Provide a link back to the list page.  'c.uri_for' builds -%]
     [% # a full URI; e.g., 'http://localhost:3000/books/list'      -%]
     <p><a href="[% c.uri_for('/books/list') %]">Return to list</a></p>
-    
+
     [% # Try out the TT Dumper (for development only!) -%]
     <pre>
     Dump of the 'book' variable:
@@ -220,8 +220,8 @@ are now six books shown (if necessary, Shift+Reload or Ctrl+Reload your
 browser at the C</books/list> page).  You should now see the six DBIC
 debug messages similar to the following (where N=1-6):
 
-    SELECT author.id, author.first_name, author.last_name 
-        FROM book_author me  JOIN author author 
+    SELECT author.id, author.first_name, author.last_name
+        FROM book_author me  JOIN author author
         ON author.id = me.author_id WHERE ( me.book_id = ? ): 'N'
 
 
@@ -237,11 +237,11 @@ to match the following:
     sub url_create :Chained('/') :PathPart('books/url_create') :Args(3) {
         # In addition to self & context, get the title, rating, &
         # author_id args from the URL.  Note that Catalyst automatically
-        # puts the first 3 arguments worth of extra information after the 
+        # puts the first 3 arguments worth of extra information after the
         # "/<controller_name>/<action_name/" into @_ because we specified
         # "Args(3)".  The args are separated  by the '/' char on the URL.
         my ($self, $c, $title, $rating, $author_id) = @_;
-    
+
         ...
 
 This converts the method to take advantage of the Chained
@@ -368,7 +368,7 @@ the following:
     | /books                              | /books/index                         |
     | /books/list                         | /books/list                          |
     '-------------------------------------+--------------------------------------'
-    
+
     [debug] Loaded Chained actions:
     .-------------------------------------+--------------------------------------.
     | Path Spec                           | Private                              |
@@ -400,17 +400,17 @@ C<lib/MyApp/Controller/Books.pm> in your editor and add the following
 method:
 
     =head2 base
-    
+
     Can place common logic to start chained dispatch here
-    
+
     =cut
-    
+
     sub base :Chained('/') :PathPart('books') :CaptureArgs(0) {
         my ($self, $c) = @_;
-    
+
         # Store the ResultSet in stash so it's available for other methods
         $c->stash(resultset => $c->model('DB::Book'));
-    
+
         # Print a message to the debug log
         $c->log->debug('*** INSIDE BASE METHOD ***');
     }
@@ -484,14 +484,14 @@ for better options for handling web-based forms).
 Edit C<lib/MyApp/Controller/Books.pm> and add the following method:
 
     =head2 form_create
-    
+
     Display form to collect information for book to create
-    
+
     =cut
-    
+
     sub form_create :Chained('base') :PathPart('form_create') :Args(0) {
         my ($self, $c) = @_;
-    
+
         # Set the TT template to use
         $c->stash(template => 'books/form_create.tt2');
     }
@@ -504,7 +504,7 @@ This action simply invokes a view containing a form to create a book.
 Open C<root/src/books/form_create.tt2> in your editor and enter:
 
     [% META title = 'Manual Form Book Create' -%]
-    
+
     <form method="post" action="[% c.uri_for('form_create_do') %]">
     <table>
       <tr><td>Title:</td><td><input type="text" name="title"></td></tr>
@@ -524,19 +524,19 @@ Edit C<lib/MyApp/Controller/Books.pm> and add the following method to
 save the form information to the database:
 
     =head2 form_create_do
-    
+
     Take information from form and add to database
-    
+
     =cut
-    
+
     sub form_create_do :Chained('base') :PathPart('form_create_do') :Args(0) {
         my ($self, $c) = @_;
-    
+
         # Retrieve the values from the form
         my $title     = $c->request->params->{title}     || 'N/A';
         my $rating    = $c->request->params->{rating}    || 'N/A';
         my $author_id = $c->request->params->{author_id} || '1';
-    
+
         # Create the book
         my $book = $c->model('DB::Book')->create({
                 title   => $title,
@@ -546,7 +546,7 @@ save the form information to the database:
         $book->add_to_book_authors({author_id => $author_id});
         # Note: Above is a shortcut for this:
         # $book->create_related('book_authors', {author_id => $author_id});
-    
+
         # Store new model object in stash and set template
         $c->stash(book     => $book,
                   template => 'books/create_done.tt2');
@@ -596,14 +596,14 @@ Edit C<root/src/books/list.tt2> and update it to match the following
 header, and 2) the five lines for the Delete link near the bottom):
 
     [% # This is a TT comment. -%]
-    
+
     [%- # Provide a title -%]
     [% META title = 'Book List' -%]
-    
+
     [% # Note That the '-' at the beginning or end of TT code  -%]
     [% # "chomps" the whitespace/newline at that end of the    -%]
     [% # output (use View Source in browser to see the effect) -%]
-    
+
     [% # Some basic HTML with a loop to display books -%]
     <table>
     <tr><th>Title</th><th>Rating</th><th>Author(s)</th><th>Links</th></tr>
@@ -693,24 +693,24 @@ To add the C<object> method, edit C<lib/MyApp/Controller/Books.pm> and
 add the following code:
 
     =head2 object
-    
+
     Fetch the specified book object based on the book ID and store
     it in the stash
-    
+
     =cut
-    
+
     sub object :Chained('base') :PathPart('id') :CaptureArgs(1) {
         # $id = primary key of book to delete
         my ($self, $c, $id) = @_;
-    
+
         # Find the book object and store it in the stash
         $c->stash(object => $c->stash->{resultset}->find($id));
-    
+
         # Make sure the lookup was successful.  You would probably
         # want to do something like this in a real app:
         #   $c->detach('/error_404') if !$c->stash->{object};
         die "Book $id not found!" if !$c->stash->{object};
-    
+
         # Print a message to the debug log
         $c->log->debug("*** INSIDE OBJECT METHOD for obj id=$id ***");
     }
@@ -725,21 +725,21 @@ Open C<lib/MyApp/Controller/Books.pm> in your editor and add the
 following method:
 
     =head2 delete
-    
+
     Delete a book
-    
+
     =cut
-    
+
     sub delete :Chained('object') :PathPart('delete') :Args(0) {
         my ($self, $c) = @_;
-    
+
         # Use the book object saved by 'object' and delete it along
         # with related 'book_author' entries
         $c->stash->{object}->delete;
-    
+
         # Set a status message to be displayed at the top of the view
         $c->stash->{status_msg} = "Book deleted.";
-    
+
         # Forward to the list action/method in this controller
         $c->forward('list');
     }
@@ -818,21 +818,21 @@ C<lib/MyApp/Controller/Books.pm> and edit the existing C<sub delete>
 method to match:
 
     =head2 delete
-    
+
     Delete a book
-    
+
     =cut
-    
+
     sub delete :Chained('object') :PathPart('delete') :Args(0) {
         my ($self, $c) = @_;
-    
+
         # Use the book object saved by 'object' and delete it along
         # with related 'book_author' entries
         $c->stash->{object}->delete;
-    
+
         # Set a status message to be displayed at the top of the view
         $c->stash->{status_msg} = "Book deleted.";
-    
+
         # Redirect the user back to the list page.  Note the use
         # of $self->action_for as earlier in this section (BasicCRUD)
         $c->response->redirect($c->uri_for($self->action_for('list')));
@@ -863,18 +863,18 @@ C<lib/MyApp/Controller/Books.pm> and update the existing C<sub delete>
 method to match the following:
 
     =head2 delete
-    
+
     Delete a book
-    
+
     =cut
-    
+
     sub delete :Chained('object') :PathPart('delete') :Args(0) {
         my ($self, $c) = @_;
-    
+
         # Use the book object saved by 'object' and delete it along
         # with related 'book_author' entries
         $c->stash->{object}->delete;
-    
+
         # Redirect the user back to the list page with status msg as an arg
         $c->response->redirect($c->uri_for($self->action_for('list'),
             {status_msg => "Book deleted."}));
@@ -1036,7 +1036,7 @@ entered for it (see the last line in the listing below):
 Notice in the debug log that the SQL DBIC generated has changed to
 incorporate the datetime logic:
 
-    INSERT INTO book ( created, rating, title, updated ) VALUES ( ?, ?, ?, ? ): 
+    INSERT INTO book ( created, rating, title, updated ) VALUES ( ?, ?, ?, ? ):
     '2010-02-16 04:18:42', '5', 'TCPIP_Illustrated_Vol-2', '2010-02-16 04:18:42'
     INSERT INTO book_author ( author_id, book_id ) VALUES ( ?, ? ): '4', '10'
 
@@ -1060,47 +1060,47 @@ a directory where DBIx::Class will look for our ResultSet Class:
 Then open C<lib/MyApp/Schema/ResultSet/Book.pm> and enter the following:
 
     package MyApp::Schema::ResultSet::Book;
-    
+
     use strict;
     use warnings;
     use base 'DBIx::Class::ResultSet';
-    
+
     =head2 created_after
-    
+
     A predefined search for recently added books
-    
+
     =cut
-    
+
     sub created_after {
         my ($self, $datetime) = @_;
-    
+
         my $date_str = $self->result_source->schema->storage
                               ->datetime_parser->format_datetime($datetime);
-    
+
         return $self->search({
             created => { '>' => $date_str }
         });
     }
-    
+
     1;
 
 Then add the following method to the C<lib/MyApp/Controller/Books.pm>:
 
     =head2 list_recent
-    
+
     List recently created books
-    
+
     =cut
-    
+
     sub list_recent :Chained('base') :PathPart('list_recent') :Args(1) {
         my ($self, $c, $mins) = @_;
-    
+
         # Retrieve all of the book records as book model objects and store in the
         # stash where they can be accessed by the TT template, but only
         # retrieve books created within the last $min number of minutes
         $c->stash(books => [$c->model('DB::Book')
                                 ->created_after(DateTime->now->subtract(minutes => $mins))]);
-    
+
         # Set the TT template to use.  You will almost always want to do this
         # in your action methods (action methods respond to user input in
         # your controllers).
@@ -1136,14 +1136,14 @@ C<Books> controller that lists books that are both recent I<and> have
 the following method:
 
     =head2 list_recent_tcp
-    
+
     List recently created books
-    
+
     =cut
-    
+
     sub list_recent_tcp :Chained('base') :PathPart('list_recent_tcp') :Args(1) {
         my ($self, $c, $mins) = @_;
-    
+
         # Retrieve all of the book records as book model objects and store in the
         # stash where they can be accessed by the TT template, but only
         # retrieve books created within the last $min number of minutes
@@ -1153,7 +1153,7 @@ the following method:
                     ->created_after(DateTime->now->subtract(minutes => $mins))
                     ->search({title => {'like', '%TCP%'}})
             ]);
-    
+
         # Set the TT template to use.  You will almost always want to do this
         # in your action methods (action methods respond to user input in
         # your controllers).
@@ -1175,7 +1175,7 @@ you added books to your database):
 Take a look at the DBIC_TRACE output in the development server log for
 the first URL and you should see something similar to the following:
 
-    SELECT me.id, me.title, me.rating, me.created, me.updated FROM book me 
+    SELECT me.id, me.title, me.rating, me.created, me.updated FROM book me
     WHERE ( ( title LIKE ? AND created > ? ) ): '%TCP%', '2010-02-16 02:49:32'
 
 However, let's not pollute our controller code with this raw "TCP" query
@@ -1184,14 +1184,14 @@ ResultSet Class.  To do this, open C<lib/MyApp/Schema/ResultSet/Book.pm>
 and add the following method:
 
     =head2 title_like
-    
+
     A predefined search for books with a 'LIKE' search in the string
-    
+
     =cut
-    
+
     sub title_like {
         my ($self, $title_str) = @_;
-    
+
         return $self->search({
             title => { 'like' => "%$title_str%" }
         });
@@ -1204,14 +1204,14 @@ replaced the C<-E<gt>search> line with the C<-E<gt>title_like> line
 shown here -- the rest of the method should be the same):
 
     =head2 list_recent_tcp
-    
+
     List recently created books
-    
+
     =cut
-    
+
     sub list_recent_tcp :Chained('base') :PathPart('list_recent_tcp') :Args(1) {
         my ($self, $c, $mins) = @_;
-    
+
         # Retrieve all of the book records as book model objects and store in the
         # stash where they can be accessed by the TT template, but only
         # retrieve books created within the last $min number of minutes
@@ -1221,7 +1221,7 @@ shown here -- the rest of the method should be the same):
                     ->created_after(DateTime->now->subtract(minutes => $mins))
                     ->title_like('TCP')
             ]);
-    
+
         # Set the TT template to use.  You will almost always want to do this
         # in your action methods (action methods respond to user input in
         # your controllers).
@@ -1251,7 +1251,7 @@ always, it must be above the closing "C<1;>"):
     #
     sub full_name {
         my ($self) = @_;
-    
+
         return $self->first_name . ' ' . $self->last_name;
     }
 
@@ -1320,14 +1320,14 @@ return the number of authors for a book.  Open
 C<lib/MyApp/Schema/Result/Book.pm> and add the following method:
 
     =head2 author_count
-    
+
     Return the number of authors for the current book
-    
+
     =cut
-    
+
     sub author_count {
         my ($self) = @_;
-    
+
         # Use the 'many_to_many' relationship to fetch all of the authors for the current
         # and the 'count' method in DBIx::Class::ResultSet to get a SQL COUNT
         return $self->authors->count;
@@ -1337,21 +1337,21 @@ Next, let's add a method to return a list of authors for a book to the
 same C<lib/MyApp/Schema/Result/Book.pm> file:
 
     =head2 author_list
-    
+
     Return a comma-separated list of authors for the current book
-    
+
     =cut
-    
+
     sub author_list {
         my ($self) = @_;
-    
-        # Loop through all authors for the current book, calling all the 'full_name' 
+
+        # Loop through all authors for the current book, calling all the 'full_name'
         # Result Class method for each
         my @names;
         foreach my $author ($self->authors) {
             push(@names, $author->full_name);
         }
-    
+
         return join(', ', @names);
     }
 
index 21ce7e0..adf66fc 100644 (file)
@@ -225,11 +225,11 @@ C<StackTrace> is new):
         -Debug
         ConfigLoader
         Static::Simple
-    
+
         StackTrace
-    
+
         Authentication
-    
+
         Session
         Session::Store::File
         Session::State::Cookie
@@ -349,18 +349,18 @@ Then open C<lib/MyApp/Controller/Login.pm>, and update the definition of
 C<sub index> to match:
 
     =head2 index
-    
+
     Login logic
-    
+
     =cut
-    
+
     sub index :Path :Args(0) {
         my ($self, $c) = @_;
-    
+
         # Get the username and password from form
         my $username = $c->request->params->{username};
         my $password = $c->request->params->{password};
-    
+
         # If the username and password values were found in form
         if ($username && $password) {
             # Attempt to log the user in
@@ -379,7 +379,7 @@ C<sub index> to match:
             $c->stash(error_msg => "Empty username or password.")
                 unless ($c->user_exists);
         }
-    
+
         # If either of above don't work out, send to the login page
         $c->stash(template => 'login.tt2');
     }
@@ -411,17 +411,17 @@ Next, update the corresponding method in
 C<lib/MyApp/Controller/Logout.pm> to match:
 
     =head2 index
-    
+
     Logout logic
-    
+
     =cut
-    
+
     sub index :Path :Args(0) {
         my ($self, $c) = @_;
-    
+
         # Clear the user's state
         $c->logout;
-    
+
         # Send the user to the starting point
         $c->response->redirect($c->uri_for('/'));
     }
@@ -432,7 +432,7 @@ C<lib/MyApp/Controller/Logout.pm> to match:
 Create a login form by opening C<root/src/login.tt2> and inserting:
 
     [% META title = 'Login' %]
-    
+
     <!-- Login form -->
     <form method="post" action="[% c.uri_for('/login') %]">
       <table>
@@ -463,17 +463,17 @@ Edit the existing C<lib/MyApp/Controller/Root.pm> class file and insert
 the following method:
 
     =head2 auto
-    
+
     Check if there is a user and, if not, forward to login page
-    
+
     =cut
-    
+
     # Note that 'auto' runs after 'begin' but before your actions and that
     # 'auto's "chain" (all from application path to most specific class are run)
     # See the 'Actions' section of 'Catalyst::Manual::Intro' for more info.
     sub auto :Private {
         my ($self, $c) = @_;
-    
+
         # Allow unauthenticated users to reach the login page.  This
         # allows unauthenticated users to reach any action in the Login
         # controller.  To lock it down to a single action, we could use:
@@ -483,7 +483,7 @@ the following method:
         if ($c->controller eq $c->controller('Login')) {
             return 1;
         }
-    
+
         # If a user doesn't exist, force login
         if (!$c->user_exists) {
             # Dump a log message to the development server debug output
@@ -493,7 +493,7 @@ the following method:
             # Return 0 to cancel 'post-auto' processing and prevent use of application
             return 0;
         }
-    
+
         # User found, so return 1 to continue with processing after this 'auto'
         return 1;
     }
@@ -671,16 +671,16 @@ file C<set_hashed_passwords.pl> in your editor and enter the following
 text:
 
     #!/usr/bin/perl
-    
+
     use strict;
     use warnings;
-    
+
     use MyApp::Schema;
-    
+
     my $schema = MyApp::Schema->connect('dbi:SQLite:myapp.db');
-    
+
     my @users = $schema->resultset('User')->all;
-    
+
     foreach my $user (@users) {
         $user->password('mypass');
         $user->update;
@@ -772,21 +772,21 @@ match the following (everything after the model search line of code has
 changed):
 
     =head2 delete
-    
+
     Delete a book
-    
+
     =cut
-    
+
     sub delete :Chained('object') :PathPart('delete') :Args(0) {
         my ($self, $c) = @_;
-    
+
         # Use the book object saved by 'object' and delete it along
         # with related 'book_authors' entries
         $c->stash->{object}->delete;
-    
+
         # Use 'flash' to save information across requests until it's read
         $c->flash->{status_msg} = "Book deleted";
-    
+
         # Redirect the user back to the list page
         $c->response->redirect($c->uri_for($self->action_for('list')));
     }
@@ -833,7 +833,7 @@ we used above.  Consult L<Catalyst::Plugin::Session> for additional
 information.
 
 
-=head2 Switch To Catalyst::Plugin::StatusMessages 
+=head2 Switch To Catalyst::Plugin::StatusMessages
 
 Although the query parameter technique we used in
 L<Chapter 4|Catalyst::Manual::Tutorial::04_BasicCRUD> and the C<flash>
@@ -863,15 +863,15 @@ C<StatusMessage> to the list of plugins:
         -Debug
         ConfigLoader
         Static::Simple
-    
+
         StackTrace
-    
+
         Authentication
-    
+
         Session
         Session::Store::File
         Session::State::Cookie
-    
+
         StatusMessage
     /;
 
@@ -880,14 +880,14 @@ action to match the following:
 
     sub delete :Chained('object') :PathPart('delete') :Args(0) {
         my ($self, $c) = @_;
-    
+
         # Saved the PK id for status_msg below
         my $id = $c->stash->{object}->id;
-    
+
         # Use the book object saved by 'object' and delete it along
         # with related 'book_authors' entries
         $c->stash->{object}->delete;
-    
+
         # Redirect the user back to the list page
         $c->response->redirect($c->uri_for($self->action_for('list'),
             {mid => $c->set_status_msg("Deleted book $id")}));
@@ -909,13 +909,13 @@ match:
 
     sub base :Chained('/') :PathPart('books') :CaptureArgs(0) {
         my ($self, $c) = @_;
-    
+
         # Store the ResultSet in stash so it's available for other methods
         $c->stash(resultset => $c->model('DB::Book'));
-    
+
         # Print a message to the debug log
         $c->log->debug('*** INSIDE BASE METHOD ***');
-    
+
         # Load status messages
         $c->load_status_msgs;
     }
index 5ef7ac4..35f028c 100644 (file)
@@ -85,12 +85,12 @@ Edit C<lib/MyApp.pm> and add C<Authorization::Roles> to the list:
         -Debug
         ConfigLoader
         Static::Simple
-    
+
         StackTrace
-    
+
         Authentication
         Authorization::Roles
-    
+
         Session
         Session::Store::File
         Session::State::Cookie
@@ -111,12 +111,12 @@ lines to the bottom of the file:
 
     ...
     <p>Hello [% c.user.username %], you have the following roles:</p>
-    
+
     <ul>
       [% # Dump list of roles -%]
       [% FOR role = c.user.roles %]<li>[% role %]</li>[% END %]
     </ul>
-    
+
     <p>
     [% # Add some simple role-specific logic to template %]
     [% # Use $c->check_user_roles() to check authz -%]
@@ -124,7 +124,7 @@ lines to the bottom of the file:
       [% # Give normal users a link for 'logout' %]
       <a href="[% c.uri_for('/logout') %]">User Logout</a>
     [% END %]
-    
+
     [% # Can also use $c->user->check_roles() to check authz -%]
     [% IF c.check_user_roles('admin') %]
       [% # Give admin users a link for 'create' %]
@@ -149,18 +149,18 @@ admin-level users by editing C<lib/MyApp/Controller/Books.pm> and
 updating C<url_create> to match the following code:
 
     =head2 url_create
-    
+
     Create a book with the supplied title and rating,
     with manual authorization
-    
+
     =cut
-    
+
     sub url_create :Chained('base') :PathPart('url_create') :Args(3) {
         # In addition to self & context, get the title, rating & author_id args
         # from the URL.  Note that Catalyst automatically puts extra information
         # after the "/<controller_name>/<action_name/" into @_
         my ($self, $c, $title, $rating, $author_id) = @_;
-    
+
         # Check the user's roles
         if ($c->check_user_roles('admin')) {
             # Call create() on the book model object. Pass the table
@@ -169,13 +169,13 @@ updating C<url_create> to match the following code:
                     title   => $title,
                     rating  => $rating
                 });
-    
+
             # Add a record to the join table for this book, mapping to
             # appropriate author
             $book->add_to_book_authors({author_id => $author_id});
             # Note: Above is a shortcut for this:
             # $book->create_related('book_authors', {author_id => $author_id});
-    
+
             # Assign the Book object to the stash and set template
             $c->stash(book     => $book,
                       template => 'books/create_done.tt2');
@@ -243,14 +243,14 @@ C<lib/MyApp/Schema/Result/Book.pm> and add the following method (be sure
 to add it below the "C<DO NOT MODIFY ...>" line):
 
     =head2 delete_allowed_by
-    
+
     Can the specified user delete the current book?
-    
+
     =cut
-    
+
     sub delete_allowed_by {
         my ($self, $user) = @_;
-    
+
         # Only allow delete if user has 'admin' role
         return $user->has_role('admin');
     }
@@ -261,15 +261,15 @@ C<lib/MyApp/Schema/Result/User.pm> and add the following method below
 the "C<DO NOT MODIFY ...>" line:
 
     =head2 has_role
-    
+
     Check if a user has the specified role
-    
+
     =cut
-    
+
     use Perl6::Junction qw/any/;
     sub has_role {
         my ($self, $role) = @_;
-    
+
         # Does this user posses the required role?
         return any(map { $_->role } $self->roles) eq $role;
     }
@@ -291,25 +291,25 @@ C<lib/MyApp/Controller/Books.pm> and update the C<delete> method to
 match the following code:
 
     =head2 delete
-    
+
     Delete a book
-    
+
     =cut
-    
+
     sub delete :Chained('object') :PathPart('delete') :Args(0) {
         my ($self, $c) = @_;
-    
+
         # Check permissions
         $c->detach('/error_noperms')
             unless $c->stash->{object}->delete_allowed_by($c->user->get_object);
-    
+
         # Saved the PK id for status_msg below
         my $id = $c->stash->{object}->id;
-    
+
         # Use the book object saved by 'object' and delete it along
         # with related 'book_authors' entries
         $c->stash->{object}->delete;
-    
+
         # Redirect the user back to the list page
         $c->response->redirect($c->uri_for($self->action_for('list'),
             {mid => $c->set_status_msg("Deleted book $id")}));
@@ -321,14 +321,14 @@ for the '/error_noperms' action to work.  Open
 C<lib/MyApp/Controller/Root.pm> and add this method:
 
     =head2 error_noperms
-    
+
     Permissions error screen
-    
+
     =cut
-    
+
     sub error_noperms :Chained('/') :PathPart('error_noperms') :Args(0) {
         my ($self, $c) = @_;
-    
+
         $c->stash(template => 'error_noperms.tt2');
     }
 
index 9937274..bb9a558 100644 (file)
@@ -70,11 +70,11 @@ camps:
 
 =over 4
 
-=item * 
+=item *
 
 Fans of C<log> and C<print> statements embedded in the code.
 
-=item * 
+=item *
 
 Fans of interactive debuggers.
 
@@ -90,7 +90,7 @@ Folks in the former group can use Catalyst's C<$c-E<gt>log> facility.
 following code to a controller action method:
 
     $c->log->info("Starting the foreach loop here");
-    
+
     $c->log->debug("Value of \$id is: ".$id);
 
 Then the Catalyst development server will display your message along
@@ -141,13 +141,13 @@ you can obviously indent them if you prefer):
         # 'Context' that's used to 'glue together' the various components
         # that make up the application
         my ($self, $c) = @_;
-    
+
     $DB::single=1;
-    
+
         # Retrieve all of the book records as book model objects and store in the
         # stash where they can be accessed by the TT template
         $c->stash->{books} = [$c->model('DB::Book')->all];
-    
+
         # Set the TT template to use.  You will almost always want to do this
         # in your action methods.
         $c->stash->{template} = 'books/list.tt2';
@@ -170,16 +170,16 @@ simply prepend C<perl -d> to the front of C<script/myapp_server.pl>:
 
 This will start the interactive debugger and produce output similar to:
 
-    $ perl -d script/myapp_server.pl  
-    
+    $ perl -d script/myapp_server.pl
+
     Loading DB routines from perl5db.pl version 1.3
     Editor support available.
-    
+
     Enter h or `h h' for help, or `man perldebug' for more help.
-    
+
     main::(script/myapp_server.pl:16):      my $debug         = 0;
-    
-      DB<1> 
+
+      DB<1>
 
 Press the C<c> key and hit C<Enter> to continue executing the Catalyst
 development server under the debugger.  Although execution speed will be
@@ -193,7 +193,7 @@ development server will drop to the Perl debugger prompt:
 
     MyApp::Controller::Books::list(/home/catalyst/MyApp/script/../lib/MyApp/Controller/Books.pm:48):
     48:         $c->stash->{books} = [$c->model('DB::Book')->all];
-    
+
       DB<1>
 
 You now have the full Perl debugger at your disposal.  First use the
@@ -205,7 +205,7 @@ C<single-step> into methods/subroutines):
     SELECT me.id, me.title, me.rating, me.created, me.updated FROM book me:
     MyApp::Controller::Books::list(/home/catalyst/MyApp/script/../lib/MyApp/Controller/Books.pm:53):
     53:         $c->stash->{template} = 'books/list.tt2';
-    
+
       DB<1>
 
 This takes you to the next line of code where the template name is set.
@@ -226,7 +226,7 @@ Next, list the methods available on our C<Book> model:
     _calculate_score
     _collapse_cond
     <lines removed for brevity>
-    
+
       DB<2>
 
 We can also play with the model directly:
@@ -323,7 +323,7 @@ B<Note:> Matt has also suggested the following tips for Perl debugging:
 
 =over 4
 
-=item * 
+=item *
 
 Check the version of an installed module:
 
@@ -341,7 +341,7 @@ and if you are using bash aliases:
         or die qq(module \"\$m\" is not installed\\n); \
         print \$m->VERSION'"
 
-=item * 
+=item *
 
 Check if a modules contains a given method:
 
index 4ade0e5..bf759d8 100644 (file)
@@ -179,21 +179,21 @@ To create a sample test case, open the C<t/live_app01.t> file in your
 editor and enter the following:
 
     #!/usr/bin/env perl
-    
+
     use strict;
     use warnings;
     use Test::More;
-    
+
     # Need to specify the name of your app as arg on next line
     # Can also do:
     #   use Test::WWW::Mechanize::Catalyst "MyApp";
-    
+
     BEGIN { use_ok("Test::WWW::Mechanize::Catalyst" => "MyApp") }
-    
+
     # Create two 'user agents' to simulate two different users ('test01' & 'test02')
     my $ua1 = Test::WWW::Mechanize::Catalyst->new;
     my $ua2 = Test::WWW::Mechanize::Catalyst->new;
-    
+
     # Use a simplified for loop to do tests that are common to both users
     # Use get_ok() to make sure we can hit the base URL
     # Second arg = optional description of test (will be displayed for failed tests)
@@ -204,7 +204,7 @@ editor and enter the following:
     # Use content_contains() to match on text in the html body
     $_->content_contains("You need to log in to use this application",
         "Check we are NOT logged in") for $ua1, $ua2;
-    
+
     # Log in as each user
     # Specify username and password on the URL
     $ua1->get_ok("http://localhost/login?username=test01&password=mypass", "Login 'test01'");
@@ -214,19 +214,19 @@ editor and enter the following:
             username => 'test02',
             password => 'mypass',
         });
-    
+
     # Go back to the login page and it should show that we are already logged in
     $_->get_ok("http://localhost/login", "Return to '/login'") for $ua1, $ua2;
     $_->title_is("Login", "Check for login page") for $ua1, $ua2;
     $_->content_contains("Please Note: You are already logged in as ",
         "Check we ARE logged in" ) for $ua1, $ua2;
-    
+
     # 'Click' the 'Logout' link (see also 'text_regex' and 'url_regex' options)
     $_->follow_link_ok({n => 4}, "Logout via first link on page") for $ua1, $ua2;
     $_->title_is("Login", "Check for login title") for $ua1, $ua2;
     $_->content_contains("You need to log in to use this application",
         "Check we are NOT logged in") for $ua1, $ua2;
-    
+
     # Log back in
     $ua1->get_ok("http://localhost/login?username=test01&password=mypass",
         "Login 'test01'");
@@ -234,11 +234,11 @@ editor and enter the following:
         "Login 'test02'");
     # Should be at the Book List page... do some checks to confirm
     $_->title_is("Book List", "Check for book list title") for $ua1, $ua2;
-    
+
     $ua1->get_ok("http://localhost/books/list", "'test01' book list");
     $ua1->get_ok("http://localhost/login", "Login Page");
     $ua1->get_ok("http://localhost/books/list", "'test01' book list");
-    
+
     $_->content_contains("Book List", "Check for book list title") for $ua1, $ua2;
     # Make sure the appropriate logout buttons are displayed
     $_->content_contains("/logout\">User Logout</a>",
@@ -247,9 +247,9 @@ editor and enter the following:
         "'test01' should have a create link");
     $ua2->content_lacks("/books/form_create\">Admin Create</a>",
         "'test02' should NOT have a create link");
-    
+
     $ua1->get_ok("http://localhost/books/list", "View book list as 'test01'");
-    
+
     # User 'test01' should be able to create a book with the "formless create" URL
     $ua1->get_ok("http://localhost/books/url_create/TestTitle/2/4",
         "'test01' formless create");
@@ -260,13 +260,13 @@ editor and enter the following:
     # Try a regular expression to combine the previous 3 checks & account for whitespace
     $ua1->content_like(qr/Added book 'TestTitle'\s+by 'Stevens'\s+with a rating of 2./,
         "Regex check");
-    
+
     # Make sure the new book shows in the list
     $ua1->get_ok("http://localhost/books/list", "'test01' book list");
     $ua1->title_is("Book List", "Check logged in and at book list");
     $ua1->content_contains("Book List", "Book List page test");
     $ua1->content_contains("TestTitle", "Look for 'TestTitle'");
-    
+
     # Make sure the new book can be deleted
     # Get all the Delete links on the list page
     my @delLinks = $ua1->find_all_links(text => 'Delete');
@@ -275,11 +275,11 @@ editor and enter the following:
     # Check that delete worked
     $ua1->content_contains("Book List", "Book List page test");
     $ua1->content_like(qr/Deleted book \d+/, "Deleted book #");
-    
+
     # User 'test02' should not be able to add a book
     $ua2->get_ok("http://localhost/books/url_create/TestTitle2/2/5", "'test02' add");
     $ua2->content_contains("Unauthorized!", "Check 'test02' cannot add");
-    
+
     done_testing;
 
 The C<live_app.t> test cases uses copious comments to explain each step
@@ -363,7 +363,7 @@ C<__PACKAGE__-E<gt>config(...> declaration to resemble:
     my $dsn = $ENV{MYAPP_DSN} ||= 'dbi:SQLite:myapp.db';
     __PACKAGE__->config(
         schema_class => 'MyApp::Schema',
-    
+
         connect_info => {
             dsn => $dsn,
             user => '',
@@ -416,18 +416,18 @@ t/controller_Foo.t:
     use strict;
     use warnings;
     use Test::More;
-    
+
     BEGIN {
         $ENV{ MYAPP_CONFIG_LOCAL_SUFFIX } = 'testing';
     }
-    
+
     eval "use Test::WWW::Mechanize::Catalyst 'MyApp'";
     plan $@
         ? ( skip_all => 'Test::WWW::Mechanize::Catalyst required' )
         : ( tests => 2 );
-    
+
     ok( my $mech = Test::WWW::Mechanize::Catalyst->new, 'Created mech object' );
-    
+
     $mech->get_ok( 'http://localhost/foo' );
 
 
index f189bc8..4538d27 100644 (file)
@@ -2,7 +2,7 @@
 
 Catalyst::Manual::Tutorial::09_AdvancedCRUD::09_FormBuilder - Catalyst Tutorial - Chapter 9: Advanced CRUD - FormBuilder
 
-NOTE:  This chapter of the tutorial is in progress.  Feel free to 
+NOTE:  This chapter of the tutorial is in progress.  Feel free to
 volunteer to help out. :-)
 
 =head1 OVERVIEW
index 195e6f4..0dcc0af 100644 (file)
@@ -103,17 +103,17 @@ Open C<lib/MyApp/Controller/Books.pm> in your editor and add the
 following method:
 
     =head2 formfu_create
-    
+
     Use HTML::FormFu to create a new book
-    
+
     =cut
-    
+
     sub formfu_create :Chained('base') :PathPart('formfu_create') :Args(0) :FormConfig {
         my ($self, $c) = @_;
-    
+
         # Get the form that the :FormConfig attribute saved in the stash
         my $form = $c->stash->{form};
-    
+
         # Check if the form has been submitted (vs. displaying the initial
         # form) and if the data passed validation.  "submitted_and_valid"
         # is shorthand for "$form->submitted && !$form->has_errors"
@@ -139,7 +139,7 @@ following method:
             # Add the authors to it
             $select->options(\@authors);
         }
-    
+
         # Set the template
         $c->stash(template => 'books/formfu_create.tt2');
     }
@@ -168,14 +168,14 @@ following text:
           # This is an optional 'mouse over' title pop-up
           attributes:
             title: Enter a book title here
-    
+
         # Another text field for the numeric rating
         - type: Text
           name: rating
           label: Rating
           attributes:
             title: Enter a rating between 1 and 5 here
-    
+
         # Add a drop-down list for the author selection.  Note that we will
         # dynamically fill in all the authors from the controller but we
         # could manually set items in the drop-list by adding this YAML code:
@@ -185,7 +185,7 @@ following text:
         - type: Select
           name: authors
           label: Author
-    
+
         # The submit button
         - type: Submit
           name: submit
@@ -222,11 +222,11 @@ Open C<root/src/books/formfu_create.tt2> in your editor and enter the
 following:
 
     [% META title = 'Create/Update Book' %]
-    
+
     [%# Render the HTML::FormFu Form %]
     [% form %]
-    
-    <p><a href="[% c.uri_for(c.controller.action_for('list')) 
+
+    <p><a href="[% c.uri_for(c.controller.action_for('list'))
         %]">Return to book list</a></p>
 
 
@@ -314,7 +314,7 @@ to match:
               max: 40
               # Override the default of 'Invalid input'
               message: Length must be between 5 and 40 characters
-    
+
         # Another text field for the numeric rating
         - type: Text
           name: rating
@@ -338,7 +338,7 @@ to match:
               min: 1
               max: 5
               message: "Must be between 1 and 5."
-    
+
         # Add a select list for the author selection.  Note that we will
         # dynamically fill in all the authors from the controller but we
         # could manually set items in the select by adding this YAML code:
@@ -359,12 +359,12 @@ to match:
           constraints:
             # Make sure it's a number
             - Integer
-    
+
         # The submit button
         - type: Submit
           name: submit
           value: Submit
-    
+
     # Global filters and constraints.
     constraints:
         # The user cannot leave any fields blank
@@ -426,18 +426,18 @@ C<lib/MyApp/Controller/Books.pm> and add the following method to the
 bottom:
 
     =head2 formfu_edit
-    
+
     Use HTML::FormFu to update an existing book
-    
+
     =cut
-    
-    sub formfu_edit :Chained('object') :PathPart('formfu_edit') :Args(0) 
+
+    sub formfu_edit :Chained('object') :PathPart('formfu_edit') :Args(0)
             :FormConfig('books/formfu_create.yml') {
         my ($self, $c) = @_;
-    
+
         # Get the specified book already saved by the 'object' method
         my $book = $c->stash->{object};
-    
+
         # Make sure we were able to get a book
         unless ($book) {
             # Set an error message for the user & return to books list
@@ -445,10 +445,10 @@ bottom:
                 {mid => $c->set_error_msg("Invalid book -- Cannot edit")}));
             $c->detach;
         }
-    
+
         # Get the form that the :FormConfig attribute saved in the stash
         my $form = $c->stash->{form};
-    
+
         # Check if the form has been submitted (vs. displaying the initial
         # form) and if the data passed validation.  "submitted_and_valid"
         # is shorthand for "$form->submitted && !$form->has_errors"
@@ -475,7 +475,7 @@ bottom:
             # Populate the form with existing values from DB
             $form->model->default_values($book);
         }
-    
+
         # Set the template
         $c->stash(template => 'books/formfu_create.tt2');
     }
index 8db2e5f..60c554f 100644 (file)
@@ -62,9 +62,9 @@ forms, perform validation of form input, and save and restore data
 to or from the database. This was written using HTML::FormHandler version
 0.28001.
 
-See 
+See
 L<Catalyst::Manual::Tutorial::09_AdvancedCRUD>
-for additional form management options other than 
+for additional form management options other than
 L<HTML::FormHandler>.
 
 
@@ -74,9 +74,9 @@ L<HTML::FormHandler>.
 Use the following command to install L<HTML::FormHandler::Model::DBIC> directly
 from CPAN:
 
-    sudo cpan HTML::FormHandler::Model::DBIC 
+    sudo cpan HTML::FormHandler::Model::DBIC
 
-It will install L<HTML::FormHandler> as a prerequisite. 
+It will install L<HTML::FormHandler> as a prerequisite.
 
 Also, add:
 
@@ -86,11 +86,11 @@ to your C<Makefile.PL>.
 
 =head1 HTML::FormHandler FORM CREATION
 
-This section looks at how L<HTML::FormHandler> can be used to 
+This section looks at how L<HTML::FormHandler> can be used to
 add additional functionality to the manually created form from Chapter 4.
 
 
-=head2 Using FormHandler in your controllers 
+=head2 Using FormHandler in your controllers
 
 FormHandler doesn't have a Catalyst base controller, because interfacing
 to a form is only a couple of lines of code.
@@ -164,10 +164,10 @@ method later when we implement 'edit'.
 Open C<root/src/books/form.tt2> in your editor and enter the following:
 
     [% META title = 'Create/Update Book' %]
-    
+
     [%# Render the HTML::FormHandler Form %]
     [% form.render %]
-    
+
     <p><a href="[% c.uri_for(c.controller.action_for('list')) %]">Return to book list</a></p>
 
 
@@ -200,18 +200,18 @@ form.  Fill in the following values:
     Title  = "Internetworking with TCP/IP Vol. II"
     Rating = "4"
     Author = "Comer"
-    
+
 Click the Submit button, and you will be returned to the Book List page
 with a "Book created" status message displayed.
 
 Note that because the 'Author' column is a Select list, only the authors
 in the database can be entered. The 'ratings' field will only accept
-integers. 
+integers.
 
 
 =head2 Add Constraints
 
-Open C<lib/MyApp/Form/Book.pm> in your editor. 
+Open C<lib/MyApp/Form/Book.pm> in your editor.
 
 Restrict the title size and make it required:
 
@@ -234,20 +234,20 @@ can specify it explicitly; see L<HTML::FormHandler::Manual>.
 
 =head2 Try Out the Updated Form
 
-Press C<Ctrl-C> to kill the previous server instance (if it's still 
+Press C<Ctrl-C> to kill the previous server instance (if it's still
 running) and restart it:
 
     $ script/myapp_server.pl
 
-Make sure you are still logged in as C<test01> and try adding a book 
-with various errors: title less than 5 characters, non-numeric rating, a 
-rating of 0 or 6, etc.  Also try selecting one, two, and zero authors. 
+Make sure you are still logged in as C<test01> and try adding a book
+with various errors: title less than 5 characters, non-numeric rating, a
+rating of 0 or 6, etc.  Also try selecting one, two, and zero authors.
 
 =head2 Create the 'edit' method
 
 Edit C<lib/MyApp/Controller/Books.pm> and add the following method:
 
+
     =head2 edit
 
     Edit an existing book with  FormHandler
@@ -273,17 +273,17 @@ Update the C<root/src/books/list.tt2>, adding an 'edit' link below the
 
 =head2 Try Out the Edit/Update Feature
 
-Press C<Ctrl-C> to kill the previous server instance (if it's still 
+Press C<Ctrl-C> to kill the previous server instance (if it's still
 running) and restart it:
 
     $ script/myapp_server.pl
 
-Make sure you are still logged in as C<test01> and go to the 
-L<http://localhost:3000/books/list> URL in your browser.  Click the 
-"Edit" link next to "Internetworking with TCP/IP Vol. II", change the 
-rating to a 3, the "II" at end of the title to the number "2", add 
-Stevens as a co-author (control-click), and click Submit.  You will then 
-be returned to the book list with a "Book edited" message at the top in 
+Make sure you are still logged in as C<test01> and go to the
+L<http://localhost:3000/books/list> URL in your browser.  Click the
+"Edit" link next to "Internetworking with TCP/IP Vol. II", change the
+rating to a 3, the "II" at end of the title to the number "2", add
+Stevens as a co-author (control-click), and click Submit.  You will then
+be returned to the book list with a "Book edited" message at the top in
 green.  Experiment with other edits to various books.
 
 =head2 See additional documentation on FormHandler
@@ -296,7 +296,7 @@ L<HTML::FormHandler>
 
    mailing list: http://groups.google.com/group/formhandler
 
-   code: http://github.com/gshank/html-formhandler/tree/master 
+   code: http://github.com/gshank/html-formhandler/tree/master
 
 =head1 AUTHOR
 
index ac3bccf..8c4b513 100644 (file)
@@ -126,11 +126,11 @@ commands such as C<C-SPC> to set the mark at the cursor location and
 C<C-E<lt>> and C<C-E<gt>> to set the mark at the beginning and end of the
 file respectively.
 
-Also, Stefan Kangas sent in the following tip about an alternate 
-approach using the command C<indent-region> to redo the indentation 
-for the currently selected region (adhering to indent rules in the 
-current major mode). You can run the command by typing M-x 
-indent-region or pressing the default keybinding C-M-\ in cperl-mode. 
+Also, Stefan Kangas sent in the following tip about an alternate
+approach using the command C<indent-region> to redo the indentation
+for the currently selected region (adhering to indent rules in the
+current major mode). You can run the command by typing M-x
+indent-region or pressing the default keybinding C-M-\ in cperl-mode.
 Additional details can be found here:
 
 L<http://www.gnu.org/software/emacs/manual/html_node/emacs/Indentation-Commands.html>
@@ -158,9 +158,9 @@ field types/constraints.
 
 =head2 PostgreSQL
 
-Use the following steps to adapt the tutorial to PostgreSQL.  Thanks 
-to Caelum (Rafael Kitover) for assistance with the most recent 
-updates, and Louis Moore, Marcello Romani and Tom Lanyon for help with 
+Use the following steps to adapt the tutorial to PostgreSQL.  Thanks
+to Caelum (Rafael Kitover) for assistance with the most recent
+updates, and Louis Moore, Marcello Romani and Tom Lanyon for help with
 earlier versions.
 
 =over 4
@@ -180,8 +180,8 @@ items via this command:
 
     sudo aptitude install postgresql libdbd-pg-perl libdatetime-format-pg-perl
 
-To configure the permissions, you can open 
-C</etc/postgresql/8.3/main/pg_hba.conf> and change this line (near the 
+To configure the permissions, you can open
+C</etc/postgresql/8.3/main/pg_hba.conf> and change this line (near the
 bottom):
 
     # "local" is for Unix domain socket connections only
@@ -199,8 +199,8 @@ And then restart PostgreSQL:
 
 =item *
 
-Create the database and a user for the database (note that we are 
-using "E<lt>catalystE<gt>" to represent the hidden password of 
+Create the database and a user for the database (note that we are
+using "E<lt>catalystE<gt>" to represent the hidden password of
 "catalyst"):
 
     $ sudo -u postgres createuser -P catappuser
@@ -232,7 +232,7 @@ Open the C<myapp01_psql.sql> in your editor and enter:
     DROP TABLE IF EXISTS users CASCADE;
     DROP TABLE IF EXISTS roles CASCADE;
     DROP TABLE IF EXISTS user_roles CASCADE;
-    
+
     --
     -- Create a very simple database to hold book and author information
     --
@@ -244,20 +244,20 @@ Open the C<myapp01_psql.sql> in your editor and enter:
         -- created     TIMESTAMP NOT NULL DEFAULT now(),
         -- updated     TIMESTAMP
     );
-    
+
     CREATE TABLE authors (
         id          SERIAL PRIMARY KEY,
         first_name  TEXT,
         last_name   TEXT
     );
-    
+
     -- 'book_authors' is a many-to-many join table between books & authors
     CREATE TABLE book_authors (
         book_id     INTEGER REFERENCES books(id) ON DELETE CASCADE ON UPDATE CASCADE,
         author_id   INTEGER REFERENCES authors(id) ON DELETE CASCADE ON UPDATE CASCADE,
         PRIMARY KEY (book_id, author_id)
     );
-    
+
     ---
     --- Load some sample data
     ---
@@ -288,7 +288,7 @@ Open the C<myapp01_psql.sql> in your editor and enter:
 Load the data:
 
     $ psql -U catappuser -W catappdb -f myapp01_psql.sql
-    Password for user catappuser: 
+    Password for user catappuser:
     psql:myapp01_psql.sql:8: NOTICE:  CREATE TABLE will create implicit sequence "books_id_seq" for serial column "books.id"
     psql:myapp01_psql.sql:8: NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "books_pkey" for table "books"
     CREATE TABLE
@@ -309,24 +309,24 @@ Make sure the data loaded correctly:
     $ psql -U catappuser -W catappdb
     Password for user catappuser: <catalyst>
     Welcome to psql 8.3.7, the PostgreSQL interactive terminal.
-    
+
     Type:  \copyright for distribution terms
            \h for help with SQL commands
            \? for help with psql commands
            \g or terminate with semicolon to execute query
            \q to quit
-    
+
     catappdb=> \dt
                  List of relations
-     Schema |     Name     | Type  |   Owner    
+     Schema |     Name     | Type  |   Owner
     --------+--------------+-------+------------
      public | authors      | table | catappuser
      public | book_authors | table | catappuser
      public | books        | table | catappuser
     (3 rows)
-    
+
     catappdb=> select * from books;
-     id |               title                | rating 
+     id |               title                | rating
     ----+------------------------------------+--------
       1 | CCSP SNRS Exam Certification Guide |      5
       2 | TCP/IP Illustrated, Volume 1       |      5
@@ -334,8 +334,8 @@ Make sure the data loaded correctly:
       4 | Perl Cookbook                      |      5
       5 | Designing with Web Standards       |      5
     (5 rows)
-    
-    catappdb=> 
+
+    catappdb=>
 
 =back
 
@@ -344,13 +344,13 @@ Make sure the data loaded correctly:
 After the steps where you:
 
     edit lib/MyApp.pm
-    
+
     create lib/MyAppDB.pm
-    
+
     create lib/MyAppDB/Book.pm
-    
+
     create lib/MyAppDB/Author.pm
-    
+
     create lib/MyAppDB/BookAuthor.pm
 
 
@@ -401,7 +401,7 @@ Open C<myapp02_psql.sql> in your editor and enter:
     --
     -- Add users and roles tables, along with a many-to-many join table
     --
-    
+
     CREATE TABLE users (
         id            SERIAL PRIMARY KEY,
         username      TEXT,
@@ -411,24 +411,24 @@ Open C<myapp02_psql.sql> in your editor and enter:
         last_name     TEXT,
         active        INTEGER
     );
-    
+
     CREATE TABLE roles (
         id   SERIAL PRIMARY KEY,
         role TEXT
     );
-    
+
     CREATE TABLE user_roles (
         user_id INTEGER REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE,
         role_id INTEGER REFERENCES roles(id) ON DELETE CASCADE ON UPDATE CASCADE,
         PRIMARY KEY (user_id, role_id)
     );
-    
+
     --
     -- Load up some initial test data
     --
-    INSERT INTO users (username, password, email_address, first_name, last_name, active) 
+    INSERT INTO users (username, password, email_address, first_name, last_name, active)
         VALUES ('test01', 'mypass', 't01@na.com', 'Joe',  'Blow', 1);
-    INSERT INTO users (username, password, email_address, first_name, last_name, active) 
+    INSERT INTO users (username, password, email_address, first_name, last_name, active)
         VALUES ('test02', 'mypass', 't02@na.com', 'Jane', 'Doe',  1);
     INSERT INTO users (username, password, email_address, first_name, last_name, active)
         VALUES ('test03', 'mypass', 't03@na.com', 'No',   'Go',   0);
@@ -467,7 +467,7 @@ Confirm with:
 
     $ psql -U catappuser -W catappdb -c "select * from users"
     Password for user catappuser: <catalyst>
-     id | username | password | email_address | first_name | last_name | active 
+     id | username | password | email_address | first_name | last_name | active
     ----+----------+----------+---------------+------------+-----------+--------
       1 | test01   | mypass   | t01@na.com    | Joe        | Blow      |      1
       2 | test02   | mypass   | t02@na.com    | Jane       | Doe       |      1
@@ -481,22 +481,22 @@ Modify C<set_hashed_passwords.pl> to match the following (the only difference
 is the C<connect> line):
 
     #!/usr/bin/perl
-    
+
     use strict;
     use warnings;
-    
+
     use MyApp::Schema;
-    
+
     my $schema = MyApp::Schema->connect('dbi:Pg:dbname=catappdb', 'catappuser', 'catalyst');
-    
+
     my @users = $schema->resultset('Users')->all;
-    
+
     foreach my $user (@users) {
         $user->password('mypass');
         $user->update;
     }
 
-Run the C<set_hashed_passwords.pl> as per the "normal" flow of the 
+Run the C<set_hashed_passwords.pl> as per the "normal" flow of the
 tutorial:
 
     $ perl -Ilib set_hashed_passwords.pl
@@ -561,10 +561,10 @@ in you MySQL. You can simply figure out that your install supports it or not:
     # mysql -u root -p
     Enter password:
     Welcome to the MySQL monitor.  Commands end with ; or \g.
-    
-    Type 'help;' or '\h' for help. Type '\c' to clear the current input 
+
+    Type 'help;' or '\h' for help. Type '\c' to clear the current input
     statement.
-    
+
     mysql> SHOW VARIABLES LIKE 'have_innodb';
     +---------------+-------+
     | Variable_name | Value |
@@ -572,7 +572,7 @@ in you MySQL. You can simply figure out that your install supports it or not:
     | have_innodb   | YES   |
     +---------------+-------+
     1 row in set (0.01 sec)
-    
+
     mysql> exit
     Bye
 
@@ -586,18 +586,18 @@ Create the database and set the permissions:
     # mysql -u root -p
     Enter password:
     Welcome to the MySQL monitor.  Commands end with ; or \g.
-    
+
     Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
-    
+
     mysql> CREATE DATABASE `myapp`;
     Query OK, 1 row affected (0.01 sec)
-    
+
     mysql> GRANT ALL PRIVILEGES ON myapp.* TO 'tutorial'@'localhost' IDENTIFIED BY 'yourpassword';
     Query OK, 0 rows affected (0.00 sec)
-    
+
     mysql> FLUSH PRIVILEGES;
     Query OK, 0 rows affected (0.00 sec)
-    
+
     mysql> exit
     Bye
 
@@ -643,7 +643,7 @@ Open the C<myapp01_mysql.sql> in your editor and enter:
     (3, 'Internetworking with TCP/IP Vol.1', 4),
     (4, 'Perl Cookbook', 5),
     (5, 'Designing with Web Standards', 5);
-    
+
     INSERT INTO `book_authors` (`book_id`, `author_id`) VALUES
     (1, 1),
     (1, 2),
@@ -653,7 +653,7 @@ Open the C<myapp01_mysql.sql> in your editor and enter:
     (4, 6),
     (4, 7),
     (5, 8);
-    
+
     INSERT INTO `authors` (`id`, `first_name`, `last_name`) VALUES
     (1, 'Greg', 'Bastien'),
     (2, 'Sara', 'Nasseh'),
@@ -663,7 +663,7 @@ Open the C<myapp01_mysql.sql> in your editor and enter:
     (6, 'Tom', 'Christiansen'),
     (7, 'Nathan', 'Torkington'),
     (8, 'Jeffrey', 'Zeldman');
-    
+
     ALTER TABLE `book_authors`
     ADD CONSTRAINT `book_author_ibfk_2` FOREIGN KEY (`author_id`) REFERENCES `authors` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
     ADD CONSTRAINT `book_author_ibfk_1` FOREIGN KEY (`book_id`) REFERENCES `books` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
@@ -681,11 +681,11 @@ Make sure the data loaded correctly:
     $ mysql -u tutorial -p myapp
     Reading table information for completion of table and column names
     You can turn off this feature to get a quicker startup with -A
-    
+
     Welcome to the MySQL monitor.  Commands end with ; or \g.
-    
+
     Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
-    
+
     mysql> show tables;
     +-----------------+
     | Tables_in_myapp |
@@ -695,7 +695,7 @@ Make sure the data loaded correctly:
     | books           |
     +-----------------+
     3 rows in set (0.00 sec)
-    
+
     mysql> select * from books;
     +----+------------------------------------+--------+
     | id | title                              | rating |
@@ -707,7 +707,7 @@ Make sure the data loaded correctly:
     |  5 | Designing with Web Standards       |      5 |
     +----+------------------------------------+--------+
     5 rows in set (0.00 sec)
-    
+
     mysql>
 
 =back
@@ -777,18 +777,18 @@ Open C<myapp02_mysql.sql> in your editor and enter:
     INSERT INTO `roles` (`id`, `role`) VALUES
     (1, 'user'),
     (2, 'admin');
-    
+
     INSERT INTO `users` (`id`, `username`, `password`, `email_address`, `first_name`, `last_name`, `active`) VALUES
     (1, 'test01', 'mypass', 't01@na.com', 'Joe', 'Blow', 1),
     (2, 'test02', 'mypass', 't02@na.com', 'Jane', 'Doe', 1),
     (3, 'test03', 'mypass', 't03@na.com', 'No', 'Go', 0);
-    
+
     INSERT INTO `user_roles` (`user_id`, `role_id`) VALUES
     (1, 1),
     (2, 1),
     (3, 1),
     (1, 2);
-    
+
     ALTER TABLE `user_roles
     ADD CONSTRAINT `user_role_ibfk_2` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
     ADD CONSTRAINT `user_role_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;