Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

DirController; release

  • Loading branch information...
commit 1350da7dfb82776653b928bfcc656fb0ad7d616a 1 parent 063435f
Zbigniew Lukasiak authored
4 Changes
... ... @@ -1,5 +1,5 @@
1 1 Revision history for WebNano
2 2
3   -0.001
4   - Initial release.
  3 +0.001 17-10-2010
  4 + Initial release.
5 5
8 dist.ini
@@ -6,10 +6,14 @@ copyright_year = 2010
6 6 version = 0.001
7 7
8 8 [@Basic]
9   -[AutoPrereq]
10   -[Prereq]
  9 +[AutoPrereqs]
  10 +[Prereqs]
11 11 [TestRelease]
12 12
  13 +[MetaNoIndex]
  14 +directory = t/lib
  15 +directory = examples
  16 +directory = extensions
13 17 [InstallGuide]
14 18 [MetaJSON]
15 19 [MetaResources]
2  examples/DvdDatabase/lib/DvdDatabase/Controller.pm
@@ -3,7 +3,7 @@ use warnings;
3 3
4 4 package DvdDatabase::Controller;
5 5
6   -use base 'WebNano::Controller';
  6 +use base 'WebNano::DirController';
7 7
8 8 sub index_action {
9 9 my $self = shift;
4 examples/DvdDatabase/lib/DvdDatabase/Controller/DvdSimpleUrl.pm
@@ -47,7 +47,7 @@ sub create_action {
47 47 if( $req->method eq 'POST' && $form->process() ){
48 48 my $record = $form->item;
49 49 my $res = $req->new_response();
50   - $res->redirect( $self->self_url . 'record/' . $record->id . '/view' );
  50 + $res->redirect( $self->self_url . $record->id . '/view' );
51 51 return $res;
52 52 }
53 53 $form->field( 'submit' )->value( 'Create' );
@@ -82,7 +82,7 @@ sub edit {
82 82 );
83 83 if( $req->method eq 'POST' && $form->process() ){
84 84 my $res = $req->new_response();
85   - $res->redirect( $self->self_url . '/' . $record->id . '/view' );
  85 + $res->redirect( $self->self_url . $record->id . '/view' );
86 86 return $res;
87 87 }
88 88 $form->field( 'submit' )->value( 'Update' );
2  examples/DvdDatabase/t/separate_url.t
@@ -20,7 +20,7 @@ for my $controller( qw/Dvd Dvd1 Dvd2/ ){
20 20 my $res;
21 21 $res = $cb->(GET "/$controller");
22 22 like( $res->content, qr/Jurassic Park II/ );
23   - $res = $cb->(POST "/$controller/record/5/edit", [ name => 'Not Jurassic Park' ] );
  23 + $res = $cb->(POST "/$controller/record/5/edit", [ name => 'Not Jurassic Park', owner => 1 ] );
24 24 ok( $res->is_redirect, 'Redirect after POST' );
25 25 $res = $cb->(GET $res->header('Location'));
26 26 like( $res->content, qr/Not Jurassic Park/ );
3  examples/DvdDatabase/t/simple_url.t
@@ -20,7 +20,8 @@ for my $controller( qw/DvdSimpleUrl/ ){
20 20 my $res;
21 21 $res = $cb->(GET "/$controller");
22 22 like( $res->content, qr/Jurassic Park II/ );
23   - $res = $cb->(POST "/$controller/5/edit", [ name => 'Not Jurassic Park' ] );
  23 + $res = $cb->(POST "/$controller/5/edit", [ name => 'Not Jurassic Park', owner => 1 ] );
  24 + warn $res->content;
24 25 ok( $res->is_redirect, 'Redirect after POST' );
25 26 $res = $cb->(GET $res->header('Location'));
26 27 like( $res->content, qr/Not Jurassic Park/ );
6 examples/DvdDatabase/templates/DvdSimpleUrl/list.tt
@@ -16,9 +16,9 @@
16 16 <td>
17 17 [% record.creation_date %]
18 18 </td>
19   -<td><a href="[% self_url %]record/[% record.id %]/view">View</a></td>
20   -<td><a href="[% self_url %]record/[% record.id %]/edit">Edit</a></td>
21   -<td><a href="[% self_url %]record/[% record.id %]/delete">Delete</a></td>
  19 +<td><a href="[% self_url %][% record.id %]/view">View</a></td>
  20 +<td><a href="[% self_url %][% record.id %]/edit">Edit</a></td>
  21 +<td><a href="[% self_url %][% record.id %]/delete">Delete</a></td>
22 22 </tr>
23 23 [% END %]
24 24 </body>
2  examples/myapp/MyApp/Controller.pm
@@ -3,7 +3,7 @@ use warnings;
3 3
4 4 package MyApp::Controller;
5 5
6   -use base 'WebNano::Controller';
  6 +use base 'WebNano::DirController';
7 7
8 8
9 9 sub index_action {
2  extensions/WebNano-Controller-DSL/t/lib/MyApp/Controller.pm
@@ -2,7 +2,7 @@ package MyApp::Controller;
2 2
3 3 use Moose;
4 4 use MooseX::NonMoose;
5   -extends 'WebNano::Controller';
  5 +extends 'WebNano::DirController';
6 6
7 7 has 'url_map' => ( is => 'ro', default => sub { { 'mapped url' => 'mapped_url' } } );
8 8
2  extensions/WebNano-Controller-WithAttributes/t/lib/MyApp/Controller.pm
@@ -2,7 +2,7 @@ package MyApp::Controller;
2 2
3 3 use Moose;
4 4 use MooseX::NonMoose;
5   -extends 'WebNano::Controller';
  5 +extends 'WebNano::DirController';
6 6
7 7 has 'url_map' => ( is => 'ro', default => sub { { 'mapped url' => 'mapped_url' } } );
8 8
30 lib/WebNano.pm
@@ -3,13 +3,12 @@ use warnings;
3 3
4 4 package WebNano;
5 5
6   -use base 'WebNano::FindController';
  6 +use WebNano::FindController 'find_nested';
7 7
8 8 our $VERSION = '0.001';
9 9 use Plack::Response;
10 10 use Scalar::Util qw(blessed);
11 11 use Object::Tiny::RW 'renderer';
12   -use Try::Tiny;
13 12 use Encode;
14 13
15 14 sub psgi_callback {
@@ -25,7 +24,7 @@ sub controller_search_path { [ ref(shift) ] };
25 24 sub handle {
26 25 my( $self, $env ) = @_;
27 26 my $path = $env->{PATH_INFO};
28   - my $c_class = $self->find_nested( '', $self->controller_search_path );
  27 + my $c_class = find_nested( '', $self->controller_search_path );
29 28 $path =~ s{^/}{};
30 29 die 'Cannot find root controller' if !$c_class;
31 30 my $out = $c_class->handle(
@@ -107,6 +106,15 @@ calls as in the following examples:
107 106 '/page' -> 'MyApp::Controller->page_action()'
108 107 '/Some/Very/long/path' -> 'MyApp::Controller::Some::Very->long_action( 'path' )
109 108
  109 +The first type of dispatching is done by the plain L<WebNano::Controller> - to get actions
  110 +dispatched to controllers in subdirs you need to subclass L<WebNano::DirController>
  111 +(which is also a subclass of C<WebNano::Controller>).
  112 +So your root controllers should usually start with C<use base 'WebNano::DirController'>.
  113 +Other controllers also can subclass C<WebNano::DirController> - but if they do
  114 +their own dispatching to sub-controllers then they need to subclass plain C<WebNano::Controller>,
  115 +otherwise this automatic dispatching, sidestepping the custom-made code could become
  116 +a security risk.
  117 +
110 118 Additionally if the last part of the path is empty then C<index> is added to it - so C</> is
111 119 mapped to C<index_action> and C</SomeController/> is mapped to
112 120 C<MyApp::SomeController-E<gt>index_action>.
@@ -294,24 +302,18 @@ follow this rule.
294 302 =head1 DIAGNOSTICS
295 303
296 304 =for author to fill in:
297   - List every single error and warning message that the module can
298   - generate (even the ones that will "never happen"), with a full
299   - explanation of each problem, one or more likely causes, and any
300   - suggested remedies.
301 305
302 306 =over
303 307
304   -=item C<< Error message here, perhaps with %s placeholders >>
305   -
306   -[Description of error here]
  308 +=back
307 309
308   -=item C<< Another error message here >>
  310 +=head1 SEE ALSO
309 311
310   -[Description of error here]
  312 +L<WebNano::Renderer::TT> - Template Toolkit renderer with template inheritance
311 313
312   -[Et cetera, et cetera]
  314 +L<WebNano::Controller::CRUD> (experimental),
313 315
314   -=back
  316 +L<http://github.com/zby/Nblog> - example blog engine using WebNano
315 317
316 318 =head1 DEPENDENCIES
317 319
38 lib/WebNano/Controller.pm
@@ -2,12 +2,10 @@ use strict;
2 2 use warnings;
3 3
4 4 package WebNano::Controller;
5   -use base 'WebNano::FindController';
6 5
7 6 use Try::Tiny;
8 7 use URI::Escape 'uri_unescape';
9 8 use Plack::Request;
10   -use File::Spec::Functions qw/catfile catdir/;
11 9
12 10 use Object::Tiny::RW qw/ app env self_url url_map _req /;
13 11
@@ -26,29 +24,6 @@ sub render {
26 24 return $self->app->renderer->render( c => $self, @_ );
27 25 }
28 26
29   -sub _self_path{
30   - my $self = shift;
31   - my $path = ref $self;
32   - $path =~ s/.*::Controller(?=(::|$))//;
33   - $path =~ s{::}{/};
34   - return $path . '/';
35   -}
36   -
37   -sub _external_dispatch {
38   - my ( $self, $path ) = @_;
39   - my( $path_part, $new_path ) = ( $path =~ qr{^([^/]*)/?(.*)} );
40   - $path_part =~ s/::|'//g if defined( $path_part );
41   - return if !length( $path_part );
42   - my $controller_class = $self->find_nested( $self->_self_path . $path_part, $self->app->controller_search_path );
43   - return if !$controller_class;
44   - return $controller_class->handle(
45   - path => $new_path,
46   - self_url => $self->self_url . $path_part . '/',
47   - env => $self->env,
48   - app => $self->app,
49   - );
50   -}
51   -
52 27 sub local_dispatch {
53 28 my ( $self, $path, @args ) = @_;
54 29 my @parts = split /\//, $path;
@@ -73,15 +48,15 @@ sub handle {
73 48 my ( $class, %args ) = @_;
74 49 my $path = delete $args{path};
75 50 my $self = $class->new( %args );
76   - my $out = $self->local_dispatch( $path );
77   - return $out if defined $out;
78   - return $self->_external_dispatch( $path );
  51 + return $self->local_dispatch( $path );
79 52 };
80 53
81 54 1;
82 55
83 56 __END__
84 57
  58 +# ABSTRACT: WebNano Controller
  59 +
85 60 =head1 SYNOPSIS
86 61 With Moose:
87 62
@@ -112,17 +87,12 @@ to appropriate action method or to a next controller.
112 87 The action method should return a string containing the HTML page,
113 88 a Plack::Response object or a code ref.
114 89
115   -If there is no suitable method in the current class, child controller classes
116   -are tried out. If there is found one that matches the path part then it is
117   -instantiated with the current psgi env and it's handle method is called.
118   -
119 90 =head1 METHODS
120 91
121 92 =head2 handle
122 93
123 94 This is a class method - it receives the arguments, creates the controller
124   -object and then uses it's L<local_dispatch> method, if that fails it tries to
125   -find a suitable child controller class and forwards the request to it.
  95 +object and then uses it's L<local_dispatch> method.
126 96
127 97 Should return a Plack::Response object, a string containing the HTML page, a code ref
128 98 or undef (which is later interpreted as 404).
9 lib/WebNano/FindController.pm
@@ -2,11 +2,14 @@ use strict;
2 2 use warnings;
3 3
4 4 package WebNano::FindController;
  5 +
  6 +use Exporter 'import';
  7 +our @EXPORT_OK = qw(find_nested);
  8 +
5 9 use Try::Tiny;
6   -use Object::Tiny::RW;
7 10
8 11 sub find_nested {
9   - my( $self, $sub_path, $search_path ) = @_;
  12 + my( $sub_path, $search_path ) = @_;
10 13 return if $sub_path =~ /\./;
11 14 $sub_path =~ s{/}{::}g;
12 15 my @path = @$search_path;
@@ -30,5 +33,7 @@ sub find_nested {
30 33
31 34 __END__
32 35
  36 +# ABSTRACT: Tool for finding controller classes
  37 +
33 38 =head2 find_nested
34 39
2  t/10.main.t
@@ -25,6 +25,8 @@ test_psgi(
25 25 like( $res->content, qr/This is the safe_method page/ );
26 26 $res = $cb->(GET "NestedController/with_template");
27 27 like( $res->content, qr/This is a NestedController page rendered with a template/ );
  28 + $res = $cb->(GET "NestedController/self_url");
  29 + like( $res->content, qr{^/NestedController/$}, 'self_url' );
28 30
29 31 $res = $cb->(GET "NestedController2/some_method");
30 32 like( $res->content, qr/This is a method with _action postfix in MyApp::Controller::NestedController2/ );
3  t/lib/MyApp/Controller.pm
@@ -3,8 +3,7 @@ use warnings;
3 3
4 4 package MyApp::Controller;
5 5
6   -use base 'WebNano::Controller';
7   -
  6 +use base 'WebNano::DirController';
8 7
9 8 sub new {
10 9 my $class = shift;
2  t/lib/MyApp/Controller/Deep.pm
@@ -3,6 +3,6 @@ use warnings;
3 3
4 4 package MyApp::Controller::Deep;
5 5
6   -use base 'WebNano::Controller';
  6 +use base 'WebNano::DirController';
7 7
8 8 1;
2  t/lib/MyApp/Controller/NestedController.pm
@@ -17,5 +17,7 @@ sub some_method_action { 'This is a method with _action postfix' }
17 17
18 18 sub with_template_action { shift->render( template => 'some_template' ) }
19 19
  20 +sub self_url_action { shift->self_url }
  21 +
20 22 1;
21 23

0 comments on commit 1350da7

Please sign in to comment.
Something went wrong with that request. Please try again.