From: Matt S Trout Date: Sat, 22 Oct 2005 04:23:10 +0000 (+0000) Subject: - Start of DispatchType refactor X-Git-Tag: 5.7099_04~1142 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Runtime.git;a=commitdiff_plain;h=b96f127f47d826a5bb8ebebc80f1b46ab3497e39 - Start of DispatchType refactor --- diff --git a/lib/Catalyst/Action.pm b/lib/Catalyst/Action.pm index 649ea78..807a6db 100644 --- a/lib/Catalyst/Action.pm +++ b/lib/Catalyst/Action.pm @@ -3,7 +3,7 @@ package Catalyst::Action; use strict; use base qw/Class::Accessor::Fast/; -__PACKAGE__->mk_accessors(qw/code namespace reverse prefix/); +__PACKAGE__->mk_accessors(qw/code namespace reverse prefix attributes/); use overload ( @@ -29,6 +29,8 @@ See L. =over 4 +=item attributes + =item code =item execute diff --git a/lib/Catalyst/DispatchType.pm b/lib/Catalyst/DispatchType.pm new file mode 100644 index 0000000..4adba13 --- /dev/null +++ b/lib/Catalyst/DispatchType.pm @@ -0,0 +1,14 @@ +package Catalyst::DispatchType; + +use strict; + +sub new { # Dumbass constructor + my ( $class, $attrs ) = @_; + return bless { %{ $attrs || {} } }, $class; +} + +sub prepare_action { die "Abstract method!"; } + +sub register_action { return; } + +1; diff --git a/lib/Catalyst/DispatchType/Default.pm b/lib/Catalyst/DispatchType/Default.pm new file mode 100644 index 0000000..4825647 --- /dev/null +++ b/lib/Catalyst/DispatchType/Default.pm @@ -0,0 +1,18 @@ +package Catalyst::DispatchType::Default; + +use strict; +use base qw/Catalyst::DispatchType/; + +sub prepare_action { + my ($self, $c, $path) = @_; + return if $path =~ m!/!; # Not at root yet, wait for it ... + my $result = @{$c->get_action('default', $c->req->path, 1) || []}[-1]; + if ($result) { + $c->action( $result->[0] ); + $c->namespace( $c->req->path ); + $c->req->action('default'); + $c->req->match(''); + } +} + +1; diff --git a/lib/Catalyst/DispatchType/Regex.pm b/lib/Catalyst/DispatchType/Regex.pm new file mode 100644 index 0000000..120ae93 --- /dev/null +++ b/lib/Catalyst/DispatchType/Regex.pm @@ -0,0 +1,46 @@ +package Catalyst::DispatchType::Regex; + +use strict; +use base qw/Catalyst::DispatchType/; + +sub prepare_action { + my ($self, $c, $path) = @_; + + if ( my $action = $self->{paths}->{$path} ) { + $c->req->action($path); + $c->req->match($path); + $c->action($action); + $c->namespace($action->prefix); + return 1; + } + + foreach my $compiled (@{$self->{compiled}||[]}) { + if ( my @snippets = ( $path =~ $compiled->{re} ) ) { + $c->req->action($compiled->{path}); + $c->req->match($path); + $c->req->snippets(\@snippets); + $c->action($compiled->{action}); + $c->namespace($compiled->{action}->prefix); + return 1; + } + } + + return 0; +} + +sub register_action { + my ( $self, $c, $action ) = @_; + my $attrs = $action->attributes; + my @register = map { @{$_ || []} } @{$attrs}{'Regex', 'Regexp'}; + foreach my $r (@register) { + $self->{paths}{$r} = $action; + push(@{$self->{compiled}}, + { + re => qr#$r#, + action => $action, + path => $r, + } ); + } +} + +1; diff --git a/lib/Catalyst/Dispatcher.pm b/lib/Catalyst/Dispatcher.pm index ea9a550..36493ec 100644 --- a/lib/Catalyst/Dispatcher.pm +++ b/lib/Catalyst/Dispatcher.pm @@ -6,6 +6,8 @@ use Catalyst::Exception; use Catalyst::Utils; use Catalyst::Action; use Catalyst::ActionContainer; +use Catalyst::DispatchType::Regex; +use Catalyst::DispatchType::Default; use Text::ASCIITable; use Tree::Simple; use Tree::Simple::Visitor::FindByPath; @@ -13,7 +15,7 @@ use Tree::Simple::Visitor::FindByPath; # Stringify to class use overload '""' => sub { return ref shift }, fallback => 1; -__PACKAGE__->mk_accessors(qw/actions tree/); +__PACKAGE__->mk_accessors(qw/actions tree dispatch_types/); =head1 NAME @@ -87,7 +89,7 @@ sub dispatch { # Execute the action or last default my $mkay = $autorun ? $c->state ? 1 : 0 : 1; - if ( ( my $action = $c->req->action ) && $mkay ) { + if ( $mkay ) { unless ($error) { $c->action->execute($c); $error++ if scalar @{ $c->error }; @@ -214,7 +216,7 @@ sub prepare_action { my @path = split /\//, $c->req->path; $c->req->args( \my @args ); - while (@path) { + DESCEND: while (@path) { $path = join '/', @path; if ( my $result = ${ $c->get_action($path) }[0] ) { @@ -240,19 +242,17 @@ sub prepare_action { $c->req->match($path); $c->action($result->[0]); $c->namespace($result->[0]->prefix); - last; + last DESCEND; } - unshift @args, pop @path; - } - unless ( $c->req->action ) { - my $result = @{$c->get_action('default', $c->req->path, 1) || []}[-1]; - if ($result) { - $c->action( $result->[0] ); - $c->namespace( $c->req->path ); - $c->req->action('default'); - $c->req->match(''); + unless ( $c->action ) { + foreach my $type (@{$self->dispatch_types}) { + last DESCEND if $type->prepare_action($c, $path); + #last DESCEND if $c->action; + } } + + unshift @args, pop @path; } $c->log->debug( 'Arguments are "' . join( '/', @args ) . '"' ) @@ -283,21 +283,21 @@ sub get_action { } elsif ( my $p = $self->actions->{plain}->{$action} ) { return [ [$p] ] } - elsif ( my $r = $self->actions->{regex}->{$action} ) { return [ [$r] ] } + #elsif ( my $r = $self->actions->{regex}->{$action} ) { return [ [$r] ] } - else { + #else { - for my $i ( 0 .. $#{ $self->actions->{compiled} } ) { - my $name = $self->actions->{compiled}->[$i]->[0]; - my $regex = $self->actions->{compiled}->[$i]->[1]; + # for my $i ( 0 .. $#{ $self->actions->{compiled} } ) { + # my $name = $self->actions->{compiled}->[$i]->[0]; + # my $regex = $self->actions->{compiled}->[$i]->[1]; - if ( my @snippets = ( $action =~ $regex ) ) { - return [ - [ $self->actions->{regex}->{$name}, $name, \@snippets ] ]; - } + # if ( my @snippets = ( $action =~ $regex ) ) { + # return [ + # [ $self->actions->{regex}->{$name}, $name, \@snippets ] ]; + # } - } - } + # } + #} return []; } @@ -353,6 +353,7 @@ sub set_action { Catalyst::Utils::class2prefix( $namespace, $c->config->{case_sensitive} ) || ''; my %flags; + my %attributes; for my $attr ( @{$attrs} ) { if ( $attr =~ /^(Local|Relative)$/ ) { $flags{local}++ } @@ -364,6 +365,12 @@ sub set_action { elsif ( $attr =~ /^(Regex|Regexp)\(\s*(.+)\s*\)$/i ) { push @{ $flags{regex} }, $2; } + if ( my ($key, $value) = ($attr =~ /^(.*?)(?:\(\s*(.+)\s*\))?$/) ) { + if ( defined $value ) { + ($value =~ s/^'(.*)'$/$1/) || ($value =~ s/^"(.*)"/$1/); + } + push(@{$attributes{$key}}, $value); + } } if ( $flags{private} && ( keys %flags > 1 ) ) { @@ -405,10 +412,11 @@ sub set_action { my $action = Catalyst::Action->new( { - code => $code, - reverse => $reverse, - namespace => $namespace, - prefix => $prefix, + code => $code, + reverse => $reverse, + namespace => $namespace, + prefix => $prefix, + attributes => \%attributes, } ); @@ -452,6 +460,10 @@ sub set_action { push @{ $self->actions->{compiled} }, [ $regex, qr#$regex# ]; $self->actions->{regex}->{$regex} = $action; } + + foreach my $type ( @{ $self->dispatch_types } ) { + $type->register_action($c, $action); + } } =item $self->setup_actions( $class, $component ) @@ -471,6 +483,10 @@ sub setup_actions { } ); + $self->dispatch_types([ + map { "Catalyst::DispatchType::$_"->new } + qw/Regex Default/ ]); + # We use a tree my $container = Catalyst::ActionContainer->new( { part => '/', actions => {} } );