Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
DirController; release
  • Loading branch information
Zbigniew Lukasiak committed Oct 17, 2010
1 parent 063435f commit 1350da7
Show file tree
Hide file tree
Showing 17 changed files with 53 additions and 68 deletions.
4 changes: 2 additions & 2 deletions Changes
@@ -1,5 +1,5 @@
Revision history for WebNano Revision history for WebNano


0.001 0.001 17-10-2010
Initial release. Initial release.


8 changes: 6 additions & 2 deletions dist.ini
Expand Up @@ -6,10 +6,14 @@ copyright_year = 2010
version = 0.001 version = 0.001


[@Basic] [@Basic]
[AutoPrereq] [AutoPrereqs]
[Prereq] [Prereqs]
[TestRelease] [TestRelease]


[MetaNoIndex]
directory = t/lib
directory = examples
directory = extensions
[InstallGuide] [InstallGuide]
[MetaJSON] [MetaJSON]
[MetaResources] [MetaResources]
Expand Down
2 changes: 1 addition & 1 deletion examples/DvdDatabase/lib/DvdDatabase/Controller.pm
Expand Up @@ -3,7 +3,7 @@ use warnings;


package DvdDatabase::Controller; package DvdDatabase::Controller;


use base 'WebNano::Controller'; use base 'WebNano::DirController';


sub index_action { sub index_action {
my $self = shift; my $self = shift;
Expand Down
Expand Up @@ -47,7 +47,7 @@ sub create_action {
if( $req->method eq 'POST' && $form->process() ){ if( $req->method eq 'POST' && $form->process() ){
my $record = $form->item; my $record = $form->item;
my $res = $req->new_response(); my $res = $req->new_response();
$res->redirect( $self->self_url . 'record/' . $record->id . '/view' ); $res->redirect( $self->self_url . $record->id . '/view' );
return $res; return $res;
} }
$form->field( 'submit' )->value( 'Create' ); $form->field( 'submit' )->value( 'Create' );
Expand Down Expand Up @@ -82,7 +82,7 @@ sub edit {
); );
if( $req->method eq 'POST' && $form->process() ){ if( $req->method eq 'POST' && $form->process() ){
my $res = $req->new_response(); my $res = $req->new_response();
$res->redirect( $self->self_url . '/' . $record->id . '/view' ); $res->redirect( $self->self_url . $record->id . '/view' );
return $res; return $res;
} }
$form->field( 'submit' )->value( 'Update' ); $form->field( 'submit' )->value( 'Update' );
Expand Down
2 changes: 1 addition & 1 deletion examples/DvdDatabase/t/separate_url.t
Expand Up @@ -20,7 +20,7 @@ for my $controller( qw/Dvd Dvd1 Dvd2/ ){
my $res; my $res;
$res = $cb->(GET "/$controller"); $res = $cb->(GET "/$controller");
like( $res->content, qr/Jurassic Park II/ ); like( $res->content, qr/Jurassic Park II/ );
$res = $cb->(POST "/$controller/record/5/edit", [ name => 'Not Jurassic Park' ] ); $res = $cb->(POST "/$controller/record/5/edit", [ name => 'Not Jurassic Park', owner => 1 ] );
ok( $res->is_redirect, 'Redirect after POST' ); ok( $res->is_redirect, 'Redirect after POST' );
$res = $cb->(GET $res->header('Location')); $res = $cb->(GET $res->header('Location'));
like( $res->content, qr/Not Jurassic Park/ ); like( $res->content, qr/Not Jurassic Park/ );
Expand Down
3 changes: 2 additions & 1 deletion examples/DvdDatabase/t/simple_url.t
Expand Up @@ -20,7 +20,8 @@ for my $controller( qw/DvdSimpleUrl/ ){
my $res; my $res;
$res = $cb->(GET "/$controller"); $res = $cb->(GET "/$controller");
like( $res->content, qr/Jurassic Park II/ ); like( $res->content, qr/Jurassic Park II/ );
$res = $cb->(POST "/$controller/5/edit", [ name => 'Not Jurassic Park' ] ); $res = $cb->(POST "/$controller/5/edit", [ name => 'Not Jurassic Park', owner => 1 ] );
warn $res->content;
ok( $res->is_redirect, 'Redirect after POST' ); ok( $res->is_redirect, 'Redirect after POST' );
$res = $cb->(GET $res->header('Location')); $res = $cb->(GET $res->header('Location'));
like( $res->content, qr/Not Jurassic Park/ ); like( $res->content, qr/Not Jurassic Park/ );
Expand Down
6 changes: 3 additions & 3 deletions examples/DvdDatabase/templates/DvdSimpleUrl/list.tt
Expand Up @@ -16,9 +16,9 @@
<td> <td>
[% record.creation_date %] [% record.creation_date %]
</td> </td>
<td><a href="[% self_url %]record/[% record.id %]/view">View</a></td> <td><a href="[% self_url %][% record.id %]/view">View</a></td>
<td><a href="[% self_url %]record/[% record.id %]/edit">Edit</a></td> <td><a href="[% self_url %][% record.id %]/edit">Edit</a></td>
<td><a href="[% self_url %]record/[% record.id %]/delete">Delete</a></td> <td><a href="[% self_url %][% record.id %]/delete">Delete</a></td>
</tr> </tr>
[% END %] [% END %]
</body> </body>
Expand Down
2 changes: 1 addition & 1 deletion examples/myapp/MyApp/Controller.pm
Expand Up @@ -3,7 +3,7 @@ use warnings;


package MyApp::Controller; package MyApp::Controller;


use base 'WebNano::Controller'; use base 'WebNano::DirController';




sub index_action { sub index_action {
Expand Down
Expand Up @@ -2,7 +2,7 @@ package MyApp::Controller;


use Moose; use Moose;
use MooseX::NonMoose; use MooseX::NonMoose;
extends 'WebNano::Controller'; extends 'WebNano::DirController';


has 'url_map' => ( is => 'ro', default => sub { { 'mapped url' => 'mapped_url' } } ); has 'url_map' => ( is => 'ro', default => sub { { 'mapped url' => 'mapped_url' } } );


Expand Down
Expand Up @@ -2,7 +2,7 @@ package MyApp::Controller;


use Moose; use Moose;
use MooseX::NonMoose; use MooseX::NonMoose;
extends 'WebNano::Controller'; extends 'WebNano::DirController';


has 'url_map' => ( is => 'ro', default => sub { { 'mapped url' => 'mapped_url' } } ); has 'url_map' => ( is => 'ro', default => sub { { 'mapped url' => 'mapped_url' } } );


Expand Down
30 changes: 16 additions & 14 deletions lib/WebNano.pm
Expand Up @@ -3,13 +3,12 @@ use warnings;


package WebNano; package WebNano;


use base 'WebNano::FindController'; use WebNano::FindController 'find_nested';


our $VERSION = '0.001'; our $VERSION = '0.001';
use Plack::Response; use Plack::Response;
use Scalar::Util qw(blessed); use Scalar::Util qw(blessed);
use Object::Tiny::RW 'renderer'; use Object::Tiny::RW 'renderer';
use Try::Tiny;
use Encode; use Encode;


sub psgi_callback { sub psgi_callback {
Expand All @@ -25,7 +24,7 @@ sub controller_search_path { [ ref(shift) ] };
sub handle { sub handle {
my( $self, $env ) = @_; my( $self, $env ) = @_;
my $path = $env->{PATH_INFO}; my $path = $env->{PATH_INFO};
my $c_class = $self->find_nested( '', $self->controller_search_path ); my $c_class = find_nested( '', $self->controller_search_path );
$path =~ s{^/}{}; $path =~ s{^/}{};
die 'Cannot find root controller' if !$c_class; die 'Cannot find root controller' if !$c_class;
my $out = $c_class->handle( my $out = $c_class->handle(
Expand Down Expand Up @@ -107,6 +106,15 @@ calls as in the following examples:
'/page' -> 'MyApp::Controller->page_action()' '/page' -> 'MyApp::Controller->page_action()'
'/Some/Very/long/path' -> 'MyApp::Controller::Some::Very->long_action( 'path' ) '/Some/Very/long/path' -> 'MyApp::Controller::Some::Very->long_action( 'path' )
The first type of dispatching is done by the plain L<WebNano::Controller> - to get actions
dispatched to controllers in subdirs you need to subclass L<WebNano::DirController>
(which is also a subclass of C<WebNano::Controller>).
So your root controllers should usually start with C<use base 'WebNano::DirController'>.
Other controllers also can subclass C<WebNano::DirController> - but if they do
their own dispatching to sub-controllers then they need to subclass plain C<WebNano::Controller>,
otherwise this automatic dispatching, sidestepping the custom-made code could become
a security risk.
Additionally if the last part of the path is empty then C<index> is added to it - so C</> is Additionally if the last part of the path is empty then C<index> is added to it - so C</> is
mapped to C<index_action> and C</SomeController/> is mapped to mapped to C<index_action> and C</SomeController/> is mapped to
C<MyApp::SomeController-E<gt>index_action>. C<MyApp::SomeController-E<gt>index_action>.
Expand Down Expand Up @@ -294,24 +302,18 @@ follow this rule.
=head1 DIAGNOSTICS =head1 DIAGNOSTICS
=for author to fill in: =for author to fill in:
List every single error and warning message that the module can
generate (even the ones that will "never happen"), with a full
explanation of each problem, one or more likely causes, and any
suggested remedies.
=over =over
=item C<< Error message here, perhaps with %s placeholders >> =back
[Description of error here]
=item C<< Another error message here >> =head1 SEE ALSO
[Description of error here] L<WebNano::Renderer::TT> - Template Toolkit renderer with template inheritance
[Et cetera, et cetera] L<WebNano::Controller::CRUD> (experimental),
=back L<http://github.com/zby/Nblog> - example blog engine using WebNano
=head1 DEPENDENCIES =head1 DEPENDENCIES
Expand Down
38 changes: 4 additions & 34 deletions lib/WebNano/Controller.pm
Expand Up @@ -2,12 +2,10 @@ use strict;
use warnings; use warnings;


package WebNano::Controller; package WebNano::Controller;
use base 'WebNano::FindController';


use Try::Tiny; use Try::Tiny;
use URI::Escape 'uri_unescape'; use URI::Escape 'uri_unescape';
use Plack::Request; use Plack::Request;
use File::Spec::Functions qw/catfile catdir/;


use Object::Tiny::RW qw/ app env self_url url_map _req /; use Object::Tiny::RW qw/ app env self_url url_map _req /;


Expand All @@ -26,29 +24,6 @@ sub render {
return $self->app->renderer->render( c => $self, @_ ); return $self->app->renderer->render( c => $self, @_ );
} }


sub _self_path{
my $self = shift;
my $path = ref $self;
$path =~ s/.*::Controller(?=(::|$))//;
$path =~ s{::}{/};
return $path . '/';
}

sub _external_dispatch {
my ( $self, $path ) = @_;
my( $path_part, $new_path ) = ( $path =~ qr{^([^/]*)/?(.*)} );
$path_part =~ s/::|'//g if defined( $path_part );
return if !length( $path_part );
my $controller_class = $self->find_nested( $self->_self_path . $path_part, $self->app->controller_search_path );
return if !$controller_class;
return $controller_class->handle(
path => $new_path,
self_url => $self->self_url . $path_part . '/',
env => $self->env,
app => $self->app,
);
}

sub local_dispatch { sub local_dispatch {
my ( $self, $path, @args ) = @_; my ( $self, $path, @args ) = @_;
my @parts = split /\//, $path; my @parts = split /\//, $path;
Expand All @@ -73,15 +48,15 @@ sub handle {
my ( $class, %args ) = @_; my ( $class, %args ) = @_;
my $path = delete $args{path}; my $path = delete $args{path};
my $self = $class->new( %args ); my $self = $class->new( %args );
my $out = $self->local_dispatch( $path ); return $self->local_dispatch( $path );
return $out if defined $out;
return $self->_external_dispatch( $path );
}; };


1; 1;


__END__ __END__
# ABSTRACT: WebNano Controller
=head1 SYNOPSIS =head1 SYNOPSIS
With Moose: With Moose:
Expand Down Expand Up @@ -112,17 +87,12 @@ to appropriate action method or to a next controller.
The action method should return a string containing the HTML page, The action method should return a string containing the HTML page,
a Plack::Response object or a code ref. a Plack::Response object or a code ref.
If there is no suitable method in the current class, child controller classes
are tried out. If there is found one that matches the path part then it is
instantiated with the current psgi env and it's handle method is called.
=head1 METHODS =head1 METHODS
=head2 handle =head2 handle
This is a class method - it receives the arguments, creates the controller This is a class method - it receives the arguments, creates the controller
object and then uses it's L<local_dispatch> method, if that fails it tries to object and then uses it's L<local_dispatch> method.
find a suitable child controller class and forwards the request to it.
Should return a Plack::Response object, a string containing the HTML page, a code ref Should return a Plack::Response object, a string containing the HTML page, a code ref
or undef (which is later interpreted as 404). or undef (which is later interpreted as 404).
Expand Down
9 changes: 7 additions & 2 deletions lib/WebNano/FindController.pm
Expand Up @@ -2,11 +2,14 @@ use strict;
use warnings; use warnings;


package WebNano::FindController; package WebNano::FindController;

use Exporter 'import';
our @EXPORT_OK = qw(find_nested);

use Try::Tiny; use Try::Tiny;
use Object::Tiny::RW;


sub find_nested { sub find_nested {
my( $self, $sub_path, $search_path ) = @_; my( $sub_path, $search_path ) = @_;
return if $sub_path =~ /\./; return if $sub_path =~ /\./;
$sub_path =~ s{/}{::}g; $sub_path =~ s{/}{::}g;
my @path = @$search_path; my @path = @$search_path;
Expand All @@ -30,5 +33,7 @@ sub find_nested {


__END__ __END__
# ABSTRACT: Tool for finding controller classes
=head2 find_nested =head2 find_nested
2 changes: 2 additions & 0 deletions t/10.main.t
Expand Up @@ -25,6 +25,8 @@ test_psgi(
like( $res->content, qr/This is the safe_method page/ ); like( $res->content, qr/This is the safe_method page/ );
$res = $cb->(GET "NestedController/with_template"); $res = $cb->(GET "NestedController/with_template");
like( $res->content, qr/This is a NestedController page rendered with a template/ ); like( $res->content, qr/This is a NestedController page rendered with a template/ );
$res = $cb->(GET "NestedController/self_url");
like( $res->content, qr{^/NestedController/$}, 'self_url' );


$res = $cb->(GET "NestedController2/some_method"); $res = $cb->(GET "NestedController2/some_method");
like( $res->content, qr/This is a method with _action postfix in MyApp::Controller::NestedController2/ ); like( $res->content, qr/This is a method with _action postfix in MyApp::Controller::NestedController2/ );
Expand Down
3 changes: 1 addition & 2 deletions t/lib/MyApp/Controller.pm
Expand Up @@ -3,8 +3,7 @@ use warnings;


package MyApp::Controller; package MyApp::Controller;


use base 'WebNano::Controller'; use base 'WebNano::DirController';



sub new { sub new {
my $class = shift; my $class = shift;
Expand Down
2 changes: 1 addition & 1 deletion t/lib/MyApp/Controller/Deep.pm
Expand Up @@ -3,6 +3,6 @@ use warnings;


package MyApp::Controller::Deep; package MyApp::Controller::Deep;


use base 'WebNano::Controller'; use base 'WebNano::DirController';


1; 1;
2 changes: 2 additions & 0 deletions t/lib/MyApp/Controller/NestedController.pm
Expand Up @@ -17,5 +17,7 @@ sub some_method_action { 'This is a method with _action postfix' }


sub with_template_action { shift->render( template => 'some_template' ) } sub with_template_action { shift->render( template => 'some_template' ) }


sub self_url_action { shift->self_url }

1; 1;


0 comments on commit 1350da7

Please sign in to comment.