1
0
Fork 0
mirror of https://github.com/puma/puma.git synced 2022-11-09 13:48:40 -05:00
puma--puma/lib/puma/uri_classifier.rb
2011-09-22 19:24:43 -07:00

80 lines
2.4 KiB
Ruby

module Puma
class URIClassifier
class RegistrationError < RuntimeError
end
class UsageError < RuntimeError
end
attr_reader :handler_map
# Returns the URIs that have been registered with this classifier so far.
def uris
@handler_map.keys
end
def initialize
@handler_map = {}
@matcher = //
@root_handler = nil
end
# Register a handler object at a particular URI. The handler can be whatever
# you want, including an array. It's up to you what to do with it.
#
# Registering a handler is not necessarily threadsafe, so be careful if you go
# mucking around once the server is running.
def register(uri, handler)
raise RegistrationError, "#{uri.inspect} is already registered" if @handler_map[uri]
raise RegistrationError, "URI is empty" if !uri or uri.empty?
raise RegistrationError, "URI must begin with a \"#{Const::SLASH}\"" unless uri[0..0] == Const::SLASH
@handler_map[uri.dup] = handler
rebuild
end
# Unregister a particular URI and its handler.
def unregister(uri)
handler = @handler_map.delete(uri)
raise RegistrationError, "#{uri.inspect} was not registered" unless handler
rebuild
handler
end
# Resolve a request URI by finding the best partial match in the registered
# handler URIs.
def resolve(request_uri)
if @root_handler
# Optimization for the pathological case of only one handler on "/"; e.g. Rails
[Const::SLASH, request_uri, @root_handler]
elsif match = @matcher.match(request_uri)
uri = match.to_s
# A root mounted ("/") handler must resolve such that path info matches the original URI.
[uri, (uri == Const::SLASH ? request_uri : match.post_match), @handler_map[uri]]
else
[nil, nil, nil]
end
end
def rebuild
if @handler_map.size == 1 and @handler_map[Const::SLASH]
@root_handler = @handler_map.values.first
else
@root_handler = nil
routes = @handler_map.keys.sort.sort_by do |uri|
-uri.length
end
all_possibles = routes.map do |uri|
Regexp.new('^' + Regexp.escape(uri))
end.join('|')
@matcher = Regexp.new(all_possibles)
end
end
private :rebuild
end
end