Simple (dumb?) request router for Strelka::App-based applications.
A Hash, keyed by Regexps, that contains the routing logic
Create a new router that will route requests according to the specified
routes
. Each route is a tuple of the form:
[ <http_verb>, # The HTTP verb as a Symbol (e.g., :GET, :POST, etc.) <path_array>, # An Array of the parts of the path, as Strings and Regexps. <route>, # A hash of routing data built by the Routing plugin ]
# File lib/strelka/router/default.rb, line 24
def initialize( routes=[], options={} )
@routes = Hash.new {|hash, path| hash[path] = {} }
routes.each {|r| self.add_route( *r ) }
super
end
Add a route for the specified verb
, path
, and
options
that will return action
when a request
matches them.
# File lib/strelka/router/default.rb, line 43
def add_route( verb, path, route )
re = Regexp.compile( '^' + path.join('/') )
# Add the route keyed by path regex and HTTP verb
self.routes[ re ][ verb ] = route
end
Build an HTTP Allowed header out of the allowed_verbs
and
throw a 405 response.
# File lib/strelka/router/default.rb, line 88
def not_allowed_response( allowed_verbs )
allowed_verbs << :HEAD if allowed_verbs.include?( :GET )
allowed_hdr = allowed_verbs.map {|verb| verb.to_s.upcase }.join( ', ' )
finish_with( HTTP::METHOD_NOT_ALLOWED, 'Method not allowed.', allow: allowed_hdr )
end
Determine the most-specific route for the specified request
and return the UnboundMethod object of the App that should handle it.
# File lib/strelka/router/default.rb, line 53
def route_request( request )
route = nil
path = request.app_path || ''
verb = request.verb
path.slice!( 0, 1 ) if path.start_with?( '/' ) # Strip the leading '/'
self.log.debug "Looking for routes for: %p %p" % [ verb, path ]
match = self.find_longest_match( self.routes.keys, path ) or return nil
self.log.debug " longest match result: %p" % [ match ]
routekey = match.regexp
# Pick the appropriate route based on the HTTP verb of the request. HEAD requests
# use the GET route. If there isn't a defined route for the request's verb
# send a 405 (Method Not Allowed) response
verb = :GET if verb == :HEAD
verbroutes = self.routes[ routekey ]
route = verbroutes[ verb ] or not_allowed_response( verbroutes.keys )
# Inject the parameters that are part of the route path (/foo/:id) into
# the parameters hash. They'll be the named match-groups in the matching
# Regex.
route_params = match.names.each_with_object({}) do |name, hash|
hash[ name ] = match[ name ]
end
# Add routing information to the request, and merge parameters if there are any
request.params.merge!( route_params ) unless route_params.empty?
# Return the routing data that should be used
return route
end
Find the longest match in patterns
for the given
path
and return the MatchData object for it. Returns
nil
if no match was found.
# File lib/strelka/router/default.rb, line 102
def find_longest_match( patterns, path )
return patterns.inject( nil ) do |longestmatch, pattern|
self.log.debug " trying pattern %p; longest match so far: %p" %
[ pattern, longestmatch ]
# If the pattern doesn't match, keep the longest match and move on to the next
match = pattern.match( path ) or next longestmatch
# If there was no previous match, or this match was longer, keep it
self.log.debug " matched: %p (size = %d)" % [ match[0], match[0].length ]
next match if longestmatch.nil? || match[0].length > longestmatch[0].length
# Otherwise just keep the previous match
self.log.debug " kept longer match %p (size = %d)" %
[ longestmatch[0], longestmatch[0].length ]
longestmatch
end
end