On Tue, Sep 18, 2007 at 03:14:14AM +0200, ry dahl wrote:
> Some cute things can be done by letting the controller have control of
> action routing.
>
> For example, in the standard controller we could use punctuation to
> declare that an action receives a POST:
> def update! # POST controller/update
> def update # GET controller/update
> def index # GET controller/index
I don't understand why this can't be done with "normal" routing, e.g.
(untested)
r.match(%r[/:controller(/::(/:id)?)?(\.:format)?], :method=>"post").
to(:action=>"[1]!")
This is just a variant on default_routes
> We can put custom route rules nearer to the actions they effect
> instead of in a separate file.
> add_route 'test/:blah', :index # assigns params[:blah] and routes
> to test action
> def test
> end
If the idea is to keep the route definition near to the controller, maybe it
would be simpler just to allow the router to be re-opened in each controller
source file (if it isn't already), e.g.
Merb::Router.prepare do |r|
r.match("/whatever/test/:blah").to(:test)
end
class Whatever < Application
def test
end
end
However, the benefit of putting all the routing logic in one place is it
makes it clear the order in which testing is made, to resolve ambiguities
between routes.
> In the end this will be a tighter, more readable, and more natural API
> than the current. Additionally this opportunity can be used to rid
> Merb of the increasingly complex @compiled_statement construction in
> route.rb and rely instead on a constructed data structure to match
> against. I suspect performance can be increased.
I agree that the current linear search, i.e. a big if / elsif tree, is far
from optimal. However I think it can be improved without moving the logic
out of centralised routing.
If I understand you correctly, you're saying that all matches will be
initially made against a fixed pattern /:controller/.*, and then the request
is dispatched to the controller which performs its own sub-matching as
required. By dispatching directly to a controller first, you avoid the
linear search, which is a potentially a factor of N improvement when you
have N controllers.
Well, you could get the same benefit in the centralised routing model, by
imposing an equivalent rule that all path regexps must start with /\w+.
Bundle all the path routing rules into bins, perform a match on /(\w+),
then perform a linear search under bins[$1]. That is, instead of having one
@@compiled_statement, have multiple @@compiled_statements indexed by the
first path component. (So it doesn't make the complexity any less, I'm
afraid!)
However I suspect this can be generalised. One way I'm thinking is to
combine all the path regexps into one mega path matching regexp, and let the
regexp engine take care of it. You would group together all routing rules
which have the same path regexp, and perform a linear search afterwards for
the non-path tests. e.g.
r.match("/admin/:action").to(www)
r.match("/:flurble/:action", :method=>"delete").to(xxx)
r.match("/:controller/:action", :method=>"post").to(yyy)
r.match("/:controller/:action").to(zzz)
The last three rules all match path /([^\/.,;?]+)/([^\/.,;?]+), and so you
would compile to something like
%r{ \A
(/admin/([^\/.,;?]+)) |
(/([^\/.,;?]+)/([^\/.,;?]+))
\z
}x
In the case of the first branch matching you'd dispatch to www, and in the
case of the second branch matching you'd run compiled (pseudocode)
if params[:method] == 'delete'
# set params[:flurble] = $1, params[:action] = $1
to(xxx)
elsif params[:method] == 'post'
# set params[:controller] = $1, params[:action] = $1
to(yyy)
else
# set params[:controller] = $1, params[:action] = $1
to(zzz)
end
However I'm not sure if there's a cheap way to identify which branch of a
regexp has matched. If you have to do
if $1
...
elsif $2
...
elsif $3
...
end
then much of the benefit has been lost. And you also need to be sure of how
ambiguous matching is resolved, e.g. in the above example /admin/foo matches
the first regexp branch in preference to the second.
Regards,
Brian.
_______________________________________________
Merb-devel mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/merb-devel