class Grape::Router
Attributes
compiled[R]
map[R]
Public Class Methods
new()
click to toggle source
# File lib/grape/router.rb, line 22 def initialize @neutral_map = [] @neutral_regexes = [] @map = Hash.new { |hash, key| hash[key] = [] } @optimized_map = Hash.new { |hash, key| hash[key] = // } end
normalize_path(path)
click to toggle source
# File lib/grape/router.rb, line 10 def self.normalize_path(path) path = +"/#{path}" path.squeeze!('/') path.sub!(%r{/+\Z}, '') path = '/' if path == '' path end
supported_methods()
click to toggle source
# File lib/grape/router.rb, line 18 def self.supported_methods @supported_methods ||= Grape::Http::Headers::SUPPORTED_METHODS + ['*'] end
Public Instance Methods
append(route)
click to toggle source
# File lib/grape/router.rb, line 45 def append(route) map[route.request_method] << route end
associate_routes(pattern, **options)
click to toggle source
# File lib/grape/router.rb, line 49 def associate_routes(pattern, **options) @neutral_regexes << Regexp.new("(?<_#{@neutral_map.length}>)#{pattern.to_regexp}") @neutral_map << Grape::Router::AttributeTranslator.new(**options, pattern: pattern, index: @neutral_map.length) end
call(env)
click to toggle source
# File lib/grape/router.rb, line 54 def call(env) with_optimization do response, route = identity(env) response || rotation(env, route) end end
compile!()
click to toggle source
# File lib/grape/router.rb, line 29 def compile! return if compiled @union = Regexp.union(@neutral_regexes) @neutral_regexes = nil self.class.supported_methods.each do |method| routes = map[method] @optimized_map[method] = routes.map.with_index do |route, index| route.index = index Regexp.new("(?<_#{index}>#{route.pattern.to_regexp})") end @optimized_map[method] = Regexp.union(@optimized_map[method]) end @compiled = true end
recognize_path(input)
click to toggle source
# File lib/grape/router.rb, line 61 def recognize_path(input) any = with_optimization { greedy_match?(input) } return if any == default_response any.endpoint end
Private Instance Methods
call_with_allow_headers(env, route)
click to toggle source
# File lib/grape/router.rb, line 158 def call_with_allow_headers(env, route) prepare_env_from_route(env, route) env[Grape::Env::GRAPE_ALLOWED_METHODS] = route.allow_header.join(', ').freeze route.endpoint.call(env) end
cascade?(response)
click to toggle source
# File lib/grape/router.rb, line 169 def cascade?(response) response && response[1][Grape::Http::Headers::X_CASCADE] == 'pass' end
default_response()
click to toggle source
# File lib/grape/router.rb, line 139 def default_response [404, { Grape::Http::Headers::X_CASCADE => 'pass' }, ['404 Not Found']] end
extract_input_and_method(env)
click to toggle source
# File lib/grape/router.rb, line 128 def extract_input_and_method(env) input = string_for(env[Grape::Http::Headers::PATH_INFO]) method = env[Grape::Http::Headers::REQUEST_METHOD] [input, method] end
greedy_match?(input)
click to toggle source
# File lib/grape/router.rb, line 151 def greedy_match?(input) return unless @union.match(input) last_match = Regexp.last_match @neutral_map.detect { |route| last_match["_#{route.index}"] } end
identity(env)
click to toggle source
# File lib/grape/router.rb, line 70 def identity(env) route = nil response = transaction(env) do |input, method| route = match?(input, method) process_route(route, env) if route end [response, route] end
make_routing_args(default_args, route, input)
click to toggle source
# File lib/grape/router.rb, line 123 def make_routing_args(default_args, route, input) args = default_args || { route_info: route } args.merge(route.params(input) || {}) end
match?(input, method)
click to toggle source
# File lib/grape/router.rb, line 143 def match?(input, method) current_regexp = @optimized_map[method] return unless current_regexp.match(input) last_match = Regexp.last_match @map[method].detect { |route| last_match["_#{route.index}"] } end
prepare_env_from_route(env, route)
click to toggle source
# File lib/grape/router.rb, line 164 def prepare_env_from_route(env, route) input, = *extract_input_and_method(env) env[Grape::Env::GRAPE_ROUTING_ARGS] = make_routing_args(env[Grape::Env::GRAPE_ROUTING_ARGS], route, input) end
process_route(route, env)
click to toggle source
# File lib/grape/router.rb, line 118 def process_route(route, env) prepare_env_from_route(env, route) route.exec(env) end
rotation(env, exact_route = nil)
click to toggle source
# File lib/grape/router.rb, line 79 def rotation(env, exact_route = nil) response = nil input, method = *extract_input_and_method(env) map[method].each do |route| next if exact_route == route next unless route.match?(input) response = process_route(route, env) break unless cascade?(response) end response end
string_for(input)
click to toggle source
# File lib/grape/router.rb, line 173 def string_for(input) self.class.normalize_path(input) end
transaction(env) { |input, method| ... }
click to toggle source
# File lib/grape/router.rb, line 92 def transaction(env) input, method = *extract_input_and_method(env) response = yield(input, method) return response if response && !(cascade = cascade?(response)) last_neighbor_route = greedy_match?(input) # If last_neighbor_route exists and request method is OPTIONS, # return response by using #call_with_allow_headers. return call_with_allow_headers(env, last_neighbor_route) if last_neighbor_route && method == Grape::Http::Headers::OPTIONS && !cascade route = match?(input, '*') return last_neighbor_route.endpoint.call(env) if last_neighbor_route && cascade && route if route response = process_route(route, env) return response if response && !(cascade = cascade?(response)) end return call_with_allow_headers(env, last_neighbor_route) if !cascade && last_neighbor_route nil end
with_optimization() { ||| default_response| ... }
click to toggle source
# File lib/grape/router.rb, line 134 def with_optimization compile! unless compiled yield || default_response end