On Tue, Sep 18, 2007 at 12:01:07PM +0100, Brian Candler wrote:
> 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.
...
> However I'm not sure if there's a cheap way to identify which branch of a
> regexp has matched.
Here's an outline of how I think it could be done.
--- 8< ---------------------------------------------------------------------
# Part one: show how it works manually
RE = %r{\A(?:
(?> ()/admin/(\w+)) |
(?> ()/(\w+)/(\w+))
)\z}x
puts RE.inspect
ACTIONS = {
1 => proc { |m| puts "www: #{m.inspect}" },
3 => proc { |m| puts "xxx/yyy/zzz: #{m.inspect}" },
}
def test(patt)
m = RE.match(patt).to_a
puts m.inspect
i = m.index("")
ACTIONS[i].call(m[i+1..-1])
end
test("/admin/wibble")
test("/bibble/boing")
puts "----"
# Part two: proof of concept of automatic regexp construction
class POC
attr_reader :regexps, :re, :actions
def initialize
@regexps = [] # [[regexp,[action,action]], [regexp,[action,action], ...]
end
def match(regexp, action)
regexp = Regexp.new(regexp) unless regexp.is_a? Regexp
if entry = @regexps.find { |e| e[0] == regexp }
entry[1] << action
else
@regexps << [regexp, [action]]
end
end
def compile
@re = %r{\A(?:[EMAIL PROTECTED] { |r| "(?>()#{r[0]})" }.join("|")})\z}
@actions = {}
i = 1
@regexps.each do |r,a|
@actions[i] = a
i += 1 + r.source.scan(%r{\((?!\?)}).size # ergh, count number of
captures
end
end
def run(patt, request={})
m = @re.match(patt).to_a
i = m.index("")
@actions[i].each { |a| res = a.call(request, m[i+1..-1]); return res if res
}
nil
end
end
r = POC.new
r.match(%r{/admin/(\w+)}, proc { |req,path| {:action=>"www"} })
r.match(%r{/(\w+)/(\w+)}, proc { |req,path| {:action=>"xxx"} if
req[:method]=="delete" })
r.match(%r{/(\w+)/(\w+)}, proc { |req,path| {:action=>"yyy"} if
req[:method]=="post" })
r.match(%r{/(\w+)/(\w+)}, proc { |req,path| {:action=>"zzz"} })
p r.regexps
r.compile
p r.re
p r.actions
p r.run("/admin/wibble", :method=>"get")
p r.run("/bibble/boing", :method=>"delete")
p r.run("/bibble/boing", :method=>"post")
p r.run("/bibble/boing", :method=>"get")
--- 8< ---------------------------------------------------------------------
Seem feasible?
Other things to do:
- create procs automatically for the simple 'non-deferred' routing, which is
easy since procs are first-class objects. No eval required :-)
- map m[0], m[1], m[2]... into the named params fields like :controller,
:action etc if the original regexp had :foo placeholders
Regards,
Brian.
_______________________________________________
Merb-devel mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/merb-devel