On Tue, Sep 18, 2007 at 01:17:41PM +0100, Brian Candler wrote:
> Here's an outline of how I think it could be done.
This was broken as I was using (?> ...), which permanently eats characters
and then won't allow the data to match a different branch. Fixed version
attached, with some other cleanups.
Incidentally, instead of writing
(?: () ...branch1... ) |
(?: () ...branch2... )
it would be simpler to write
( ...branch1... ) |
( ...branch2... )
since the outer brackets also capture the entire match, which gives a
suitable non-nil sentinel to mark the start of the branch.
However this way means I need a fast way to detect the first non-nil element
in the match array (rather than the first empty string element) and I
couldn't think of a way to do that faster than
i = (0...m.size).find { |x| m[x] }
Also, I decided to anchor the whole expression, which means the individual
branch regexps don't need to be anchored, but instead we could insist that
the branches need to have their own anchors (which I think is the current
behaviour)
Regards,
Brian.
class POCRouter
class Path
attr_reader :regexp, :num_captures, :blocks
def initialize(regexp, blocks=[])
@regexp = regexp
@num_captures = @regexp.source.scan(%r{\((?!\?)}).size # FIXME, e.g. \(
or [(]
@blocks = blocks
end
end
attr_reader :paths, :re, :capindex
def initialize
@paths = []
end
def match(regexp, &blk)
regexp = Regexp.new(regexp) unless regexp.is_a? Regexp
if path = @paths.find { |p| p.regexp == regexp }
path.blocks << blk
else
@paths << Path.new(regexp, [blk])
end
end
def compile
@re = %r{\A(?:
[EMAIL PROTECTED] { |p| "(?: () #{p.regexp})" }.join("|\n")}
)\z}x # extended RE is easier to read for debugging
@capindex = {}
i = 0
@paths.each do |p|
@capindex[i] = p
i += p.num_captures + 1
end
end
def inspect
(@re || @paths).inspect
end
def run(path, request={})
m = @re.match(path).captures
i = m.index("") || (return nil)
path = capindex[i]
path.blocks.each do |blk|
res = blk.call(request, m[i+1, path.num_captures])
return res if res
end
nil
end
end
r = POCRouter.new
r.match(%r{/admin/(\w+)}) { |req,m| p m; {:action=>"www"} }
r.match(%r{/(\w+)/(\w+)}) { |req,m| p m; {:action=>"xxx"} if
req[:method]=="delete" }
r.match(%r{/(\w+)/(\w+)}) { |req,m| {:action=>"yyy"} if req[:method]=="post" }
r.match(%r{/(\w+)/(\w+)}) { |req,m| {:action=>"zzz"} }
p r
r.compile
p r
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")
_______________________________________________
Merb-devel mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/merb-devel