[Catalyst] catalyst++
Garrett Goebel
ggoebel at goebel.ws
Mon Oct 2 07:39:47 CEST 2006
On Sep 30, 2006, at 8:19 AM, Matt S Trout wrote:
> Garrett Goebel wrote:
>> On Sep 29, 2006, at 11:22 AM, John Napiorkowski wrote:
>>
>>> I'm not sure what you mean by 'multi-attribute
>>> dispatch routing'. I have someone here working on
>>> integrating Class::Workflow as a controller so you can
>>> dispatch based on workflow states and not just on
>>> actions. Is that something that interests you?
>>
>> I'm talking about the difference between single and multiple
>> dispatch. Catalyst's action attributes whether they're local, path,
>> regex, chained, etc. all are specific to the request uri. The
>> dispatcher tries each dispatch type until if finds one that matches
>> the path.
>>
>> I've modified the dispatcher so I can dispatch an action if it
>> matches request method and uri path. Dispatching based on workflow
>> states would be a nice addition. I've looked at Class::Workflow, but
>> never got past just looking at it. Yes, it does interest me.
>>
>> However, what I've done is a hack to meet my needs. It'd be nice if
>> there were a generic catalyst dispatcher which handled multiple
>> dispatch.
>
> There already is. It's called Catalyst::Dispatcher.
>
> We had a long thread about this where you kept saying "but it can't
> do X" and
> I followed up saying "yes it can, you do it like this".
Yes, you answered the questions I raised. However I believe I'm
raising a new one.
> I can't think of any point you raised that wasn't addressed as
> being viable
> against the standard dispatcher; if there are still things you
> believe can't
> be achieved please post *specific* examples rather than just
> complaining in
> general that it won't do what you want :)
Ignorance can always be cured. Let's hope I'm not being an idiot ;)
Per your request, let's see if I can be more specific...
package Catalyst::Dispatcher;
...
sub prepare_action {
...
foreach my $type ( @{ $self->dispatch_types } ) {
last DESCEND if $type->match( $c, $path );
}
...
}
and
package MyApp::Controller::Foo;
...
sub bar : Method(GET) Path('') Args(2) { ... }
This is a simplification, but for a given request, the catalyst
dispatcher attempts to match the request's uri path by iterating
through the dispatch types Index, Path, Regex, and Default invoking
the match class method, which in turn invokes the $action->match
method for each action instance for that $path until we find the
first match. IMHO this is effectively single-dispatch, in that
actions are dispatched based on the first invocation of dispatch_type
to match.
So if Catalyst::Dispatcher supports multiple dispatch, how do you
make an action dispatch based on more than one attribute of the
subroutine definition for a given action? I.e. path _and_ request
method? The recommendations I've gotten, if I've understood them
correctly, have not been to modify the behavior of
Catalyst::Dispatcher or Catalyst::DispatchType::* as one might expect
to affect dispatching behavior, but to rather to subclass
Catalyst::Action and the Catalyst::Controller. And while that might
work for my hack to dispatch based on request method, path, and args,
it won't scale well. I'd rather make one dispatch type class for each
dispatch type, than an Action class for each possible combination of
all the dispatch types.
Next, take for example, dispatching an action declared with
attributes for both Regex _and_ a custom dispatch types. The side
effects of calling the dispatch_type->match method will only occur
for the first dispatch type which matches. If my action matches on
the custom dispatch type first, $c->request->captures won't get set
by Catalyst::DispatchType::Regex. I.e., you don't get the side
effects of invoking dispatch_type->method for all of the dispatch
types indicated by the action's attributes.
Speaking without the experience with and intimate knowledge of the
code which you have, I would expect that the attribute handling code
in Catalyst::Base would work in conjunction with Catalyst::Dispatcher
to determine dispatch types in use. And that
Catalyst::Dispatcher::prepare_action would iterate through this list
of used dispatch types, not the complete list of all dispatch types
supported.
I would also expect that Catalyst::Dispatcher::prepare_action would
instead look something like:
package Catalyst::Dispatcher;
...
sub prepare_action {
...
OUTER: foreach my $type ( @{ $self->dispatch_types } ) {
push @done, $type;
if ($type->match( $c, $path )) {
@todo = diff($c->action->dispatch_types, \@done);
INNER: foreach my $other_type (@todo) {
next OUTER unless $other_type->match($c, $path);
}
last DESCEND;
}
}
...
}
Not only do I believe this would scale better, but this would allow
me to put the dispatch type match logic in my Catalyst::DispatchType
classes and out of my Action classes where IMHO it doesn't belong.
That said, I haven't wrapped my head around the Chained dispatch type
sufficiently well enough to see if Args processing in
Catalyst::Action::match could be moved to a
Catalyst::DispatchType::Args class.
cheers,
Garrett
More information about the Catalyst
mailing list