[Catalyst] Unit Testing

Kieren Diment diment at gmail.com
Sun Apr 20 14:33:49 BST 2008


On 20 Apr 2008, at 21:26, Octavian Rasnita wrote:
> From: "Jonathan Rockway" <jon at jrock.us>
>> * On Sun, Apr 20 2008, Octavian Rasnita wrote:
>>
>>> Please tell us if we can find an example of putting the logic in the
>>> model than call those methods from the controller.
>>
>> http://www.jrock.us/fp2008/catalyst/start.html
>>
>> Using a DBIC-based model works the same way.
>
> Thank you Jonathan but I couldn't access any kind of helpful text  
> on that page. I've look in the source code what link I need to  
> access because it was hidden on the page. I accessed it, but I  
> couldn't find a text in the following page neither.
> Please tell me at least if it is a text what I need to search for,  
> or an image slide show (which unfortunately I can't see).
>

Yeah, there's an accessability issue there.  Anyway:

perl -e 'for $i (1 .. 48) { system "lynx -dump -nolist http:// 
www.jrock.us/fp2008/catalyst/slide$i.html"}' > jrock.txt

gives me:


    Catalyst Introducing Catalyst #1
Meta
      * I'm Jonathan Rockway
      * http://jrock.us/     * Exciting blog at http://blog.jrock.us/
      Code and slides at http://jrock.us/
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #2
    [1847190952.jpg]
Catalyst Book
      * Hands-on tutorial
      * Learn DBIx::Class, Template Toolkit, and Catalyst
      http://www.packtpub.com/catalyst-perl-web-application/book
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #3
What is Catalyst?
      * Web application environment
      * You write the code, Catalyst figures out how to run it
      * Development Server     * FastCGI     * mod_perl
      Niceties     * Debugging pages     * Plugins     * CPAN-able  
components
      MVC framework     * Separate concerns
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #4
    Hello
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #5
Demo the wiki
      * Get the code now: http://jrock.us/KitiWiki-0.01.tar.gz
      * Code on slides abridged for clarity; tarball has  
everything.     * Download now and follow along!
      Untar, perl Makefile.PL, make installdeps
    < < Previous | Index | Next >>                              ""
                                    Not Found
    The requested URL /fp2008/catalyst/slide6.html was not found on  
this   server.      
_________________________________________________________________

     Apache/2.2.8 (Debian) mod_perl/2.0.3 Perl/v5.8.8 Server at     
www.jrock.us Port 80
                                    Not Found
    The requested URL /fp2008/catalyst/slide7.html was not found on  
this   server.      
_________________________________________________________________

     Apache/2.2.8 (Debian) mod_perl/2.0.3 Perl/v5.8.8 Server at     
www.jrock.us Port 80
                                    Not Found
    The requested URL /fp2008/catalyst/slide8.html was not found on  
this   server.      
_________________________________________________________________

     Apache/2.2.8 (Debian) mod_perl/2.0.3 Perl/v5.8.8 Server at     
www.jrock.us Port 80
                                    Not Found
    The requested URL /fp2008/catalyst/slide9.html was not found on  
this   server.      
_________________________________________________________________

     Apache/2.2.8 (Debian) mod_perl/2.0.3 Perl/v5.8.8 Server at     
www.jrock.us Port 80
    Catalyst Introducing Catalyst #10
Getting started
      * catalyst.pl KitiWiki
      * create directories for our application
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #11
Writing the Wiki Class
      * In KitiWiki::Backend::Wiki (lib/KitiWiki/Backend/Wiki.pm)
package KitiWiki::Backend::Wiki;use Moose;
has 'storage_root' => (    is => 'ro', isa => Dir, ...);
sub page {    my ($self, $page) = @_;    my $pagedir = $self- 
 >storage_root->subdir($page);    $self->_validate_page_name($page)  
or      confess "attempt to load invalid page '$page'";    return  
KitiWiki::Backend::Wiki::Page->new( storage => $pagedir );}
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #12
Page Class
      * A bunch of functions, here's one:
sub new_revision {    my ($self, $author, $text) = @_;    my $date =  
time;    my $name = "$date-$author";
     my $encoded = Encode::encode('utf8', $text);
     write_file($self->storage->file($name)->stringify,  
$encoded)      or confess "Failed to write $name";
     $self->_unshift_revision($name);
     return KitiWiki::Backend::Wiki::Page::Revision->new 
(        storage  => $self->storage,        filename => $name,         
author   => $author,        date     => $date,    );}
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #13
More Page code
has 'revisions' => (    metaclass  => 'Collection::Array',     
is         => 'ro',    isa        => 'ArrayRef[Str]',    required    
=> 0,    default    => sub { shift->_versions },    lazy       =>  
1,    auto_deref => 1,    provides   => {        unshift =>  
'_unshift_revision',
     },);
sub _versions {    my $self = shift;    my $dir = $self->storage;     
opendir my $dh, $dir->stringify;    my @files = readdir $dh;     
closedir $dh;
     return [        sort { _revision_sorter($a, $b) }          map  
{ $_->basename }            grep { -f }              map { $dir->file 
($_) } @files    ];}
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #14
Revision Class
      * Moosey struct
has 'storage' => (    is       => 'ro',    isa      => Dir,     
required => 1,    coerce   => 1,);
has 'filename' => (    is       => 'ro',    isa      => 'Str',     
required => 1,);
has 'author' => (    is       => 'ro',    isa      => 'Str',     
required => 1,);
subtype DateTime  => as Class  => where { blessed $_ && $_->isa 
('DateTime') };
coerce DateTime  => as Num  => via { DateTime->from_epoch( epoch =>  
$_ ) };
has 'date' => (    is       => 'ro',    isa      => 'DateTime',     
coerce   => 1,    required => 1,);
has 'content' => (    is      => 'rw',    isa     => 'Str',     
default => sub { shift->_read_content },    lazy    => 1,);
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #15
More revision code
sub _read_content {    my ($self) = @_;    my $filename = $self->_file;
     my $data = read_file($self->_file->stringify);    return  
Encode::decode('utf8', $data);}
    < < Previous | Index | Next >>                              ""
                                    Not Found
    The requested URL /fp2008/catalyst/slide16.html was not found on  
this   server.      
_________________________________________________________________

     Apache/2.2.8 (Debian) mod_perl/2.0.3 Perl/v5.8.8 Server at     
www.jrock.us Port 80
    Catalyst Introducing Catalyst #17
More tests
      * t/wiki-validation.t
      * Tests the page name validation rules:
use KitiWiki::Backend::Wiki;use Test::TableDriven (    validate =>  
{        'foo'                     => 0,         
'FooBar'                  => 1,        'Foo..'                   =>  
0,        'Foo/../../../etc/passwd' => 0,         
''                        => 0,        'A'                       =>  
0,        'Ab'                      => 1,    },);
sub validate {    my $in = shift;    return KitiWiki::Backend::Wiki- 
 >_validate_page_name($in)      ? 1 : 0;}
runtests;
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #18
Catalyst
      * Request-handling code lives in Controllers
      * Controllers have actions:
package YourApp::Controller::Whatever;sub foo :Local { action goes  
here }     * Actions have URLs, here /whatever/foo.     * Root  
controller is /, not /root.
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #19
Setting up the Catalyst app
      * We want TT templates, so we need a View that can render them
    *$ perl script/kitiwiki_create.pl view TT TT     * Creates lib/ 
KitiWiki/View/TT.pm
      * tells Catalyst that $c->stash->{template} is a TT template  
to       render
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #20
Adding a template to the app
      * Templates go in root     * In root/hello.tt:
Hello, world!  This is [% template | html %]!
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #21
Using that from Catalyst
      * In KitiWiki::Controller::Root:
sub hello :Local {    my ($self, $c) = @_;    $c->stash->{template} =  
'hello.tt';}
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #22
Viewing the template
      * Start the server
$ perl script/kitiwiki_server.pl -d     * Browse to http://localhost: 
3000/hello.
Hello, world!  This is hello.tt!     * [% template %] replaced with  
$c->stash->{template}
      * Everything in stash becomes TT variables     * $c is just [%  
c %]
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #23
Adding wiki functionality
      * Clear out Root controller     * Add a default action (for  
when no URL matches)
sub default : Private {    my ($self, $c) = @_;    $c->res->status 
(404);    $c->stash->{template} = '404.tt';}     * Private means  
"internal to Catalyst"
    < < Previous | Index | Next >>                              ""
                                    Not Found
    The requested URL /fp2008/catalyst/slide24.html was not found on  
this   server.      
_________________________________________________________________

     Apache/2.2.8 (Debian) mod_perl/2.0.3 Perl/v5.8.8 Server at     
www.jrock.us Port 80
    Catalyst Introducing Catalyst #25
uri_for
      * $c->uri_for('/path') creates links
      * use this so you can move your app around
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #26
Adding a Wiki viewer
      * New controller Wiki so wiki pages are at /wiki/...     * New  
model for getting at the Wiki
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #27
KitiWiki::Model::Wiki
package KitiWiki::Model::Wiki;use strict;use warnings;
use base 'Catalyst::Model::Adaptor';
__PACKAGE__->config( class => 'KitiWiki::Backend::Wiki' );
1;
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #28
Model
      * Catalyst::Model glues app's data-related logic to  
Catalyst     * Biggest part of app
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #29
Why not use KitiWiki::Backend::Wiki directly?
      * Configure wiki directory from Catalyst     * kitiwiki.yml
---Model::Wiki:  args:    storage_root: "__path_to(wiki_pages)__"      
* path_to() keeps path sane
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #30
Controller::Wiki
package KitiWiki::Controller::Wiki;use strict;use warnings;use base  
'Catalyst::Controller';
sub wiki : Chained('/') PathPart('wiki') CaptureArgs(1) {    my  
($self, $c, $page_name) = @_;    $c->log->debug("Acting on wiki page  
$page_name");    $c->stash->{page_name} = $page_name;    $c->stash-> 
{page}      = $c->model('Wiki')->page($page_name);}
sub latest : Chained('wiki') PathPart Args(0) {    my ($self, $c) =  
@_;    $c->stash->{revision}  = $c->stash->{page}->latest;    $c- 
 >stash->{formatted} = $self->format_revision($c);    $c->stash-> 
{template}  = 'view_wiki.tt';}
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #31
Chained
      * provides url like /wiki/<page name>/latest     * easily add  
new actions:
sub foo :Chained('wiki') PathPart Args(0) {}     * now /wiki/<page  
name>/foo is a URL     * dispatch order, left-first
      * CaptureArgs (capture /.../)     * Args (endpoint, consume /...)
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #32
Templates for wiki viewing
      * view_wiki.tt
[% WRAPPER page.tt title = page_name %]<h1>[% page_name | html %]</h1> 
[% formatted | html_para %]<hr /><i>Last modified by [%  
revision.author %] on [% revision.date %]</i><a href='[% c.uri_for("/ 
wiki/$page_name/create") %]'>Edit</a>
[% END %]
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #33
Another chained action
      * view older revisions:
sub revision : Chained('wiki') PathPart Args(1) {    my ($self, $c,  
$revision) = @_;    $c->stash->{revision}        = $c->stash->{page}- 
 >get_revision($revision);    $c->stash->{revision_number} =  
$revision;    $c->stash->{formatted}       = $self->format_revision 
($c);    $c->stash->{template}        = 'view_wiki.tt';}     *  
template reused     * Args(1) captures revision number
      * /wiki/PageName/revision/42
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #34
Theme of controller
      * get data from model     * munge it to make the view happy      
* NOTHING ELSE
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #35
Writing wiki pages
      * don't want random users writing wiki pages     * need  
authentication
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #36
Authentication
      * needs session
    < < Previous | Index | Next >>                              ""
                                    Not Found
    The requested URL /fp2008/catalyst/slide37.html was not found on  
this   server.      
_________________________________________________________________

     Apache/2.2.8 (Debian) mod_perl/2.0.3 Perl/v5.8.8 Server at     
www.jrock.us Port 80
    Catalyst Introducing Catalyst #38
Sessions
      * $c->session->{anything}
      * lasts until session expiration
      $c->flash->{anything}     * lasts until end of next request      
* good for "Logged in as ..." and a redirect
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #39
Authentication
      * Plugin loaded above     * Very simple configuration in  
KitiWiki.pm
__PACKAGE__->config(authentication => {    default_realm =>  
'editors',    realms => {        editors => {            credential  
=> {                class => 'Password',                 
password_field => 'password',                password_type =>  
'clear'            },            store => {                class =>  
'Minimal',                users => {                    jon =>  
{ password =>  
"test" },                },            },        },    },});
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #40
Authentication
      * realms
      * store     * credentials
      $c->user
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #41
Now we can edit
      * Nope, need to login
    < < Previous | Index | Next >>                              ""
                                    Not Found
    The requested URL /fp2008/catalyst/slide42.html was not found on  
this   server.      
_________________________________________________________________

     Apache/2.2.8 (Debian) mod_perl/2.0.3 Perl/v5.8.8 Server at     
www.jrock.us Port 80
    Catalyst Introducing Catalyst #43
Authentication
      * login /login     * logout /logout
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #44
Editing, finally!
      * Using REST again. First start with base:
sub create : Chained('wiki') PathPart Args(0) ActionClass('REST') 
{    my ($self, $c) = @_;    unless($c->user_exists){        $c- 
 >session->{login_from} = $c->req->uri;        $c->flash->{message} =  
'You must log in to edit.';        $c->res->redirect($c->uri_for('/ 
login'));        $c->detach;    }}     * If no user, redirect them to  
login.     * Login remembers where they came from.
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #45
Editing: show form
sub create_GET {    my ($self, $c) = @_;    $c->stash->{template} =  
'wiki_edit_form.tt';    $c->stash->{existing_content} =       eval  
{ $c->stash->{page}->latest->content };}
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #46
Editing: process form submission
sub create_POST {    my ($self, $c) = @_;    $c->stash->{page}- 
 >new_revision(        $c->user->id,        $c->req->params-> 
{new_content},    );    my $name = $c->stash->{page_name};    $c- 
 >response->redirect(        $c->uri_for("/wiki/$name/latest")    );}
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #47
That's how Catalyst works
      * Flexible URI dispatching
      * Actions that are dispatched to get data from a model, then  
pass       that data to the View.
    < < Previous | Index | Next >>                              ""
    Catalyst Introducing Catalyst #48
Questions?
      * If there's time, let's add a "full history" page.
    < < Previous | Index | Next >>                              ""



More information about the Catalyst mailing list