class Grape::Router

def self.normalize_path(path)

def self.normalize_path(path)
  path = +"/#{path}"
  path.squeeze!('/')
  path.sub!(%r{/+\Z}, '')
  path = '/' if path == ''
  path
end

def append(route)

def append(route)
  map[route.request_method] << route
end

def associate_routes(pattern, options)

def associate_routes(pattern, options)
  Grape::Router::GreedyRoute.new(pattern, options).then do |greedy_route|
    @neutral_regexes << greedy_route.to_regexp(@neutral_map.length)
    @neutral_map << greedy_route
  end
end

def call(env)

def call(env)
  with_optimization do
    response, route = identity(env)
    response || rotation(env, route)
  end
end

def call_with_allow_headers(env, route)

def call_with_allow_headers(env, route)
  prepare_env_from_route(env, route)
  env[Grape::Env::GRAPE_ALLOWED_METHODS] = route.options[:allow_header]
  route.options[:endpoint].call(env)
end

def cascade?(response)

def cascade?(response)
  response && response[1][Grape::Http::Headers::X_CASCADE] == 'pass'
end

def compile!

def compile!
  return if compiled
  @union = Regexp.union(@neutral_regexes)
  @neutral_regexes = nil
  (Grape::Http::Headers::SUPPORTED_METHODS + ['*']).each do |method|
    next unless map.key?(method)
    routes = map[method]
    optimized_map = routes.map.with_index { |route, index| route.to_regexp(index) }
    @optimized_map[method] = Regexp.union(optimized_map)
  end
  @compiled = true
end

def default_response

def default_response
  headers = Grape::Util::Header.new.merge(Grape::Http::Headers::X_CASCADE => 'pass')
  [404, headers, ['404 Not Found']]
end

def extract_input_and_method(env)

def extract_input_and_method(env)
  input = string_for(env[Rack::PATH_INFO])
  method = env[Rack::REQUEST_METHOD]
  [input, method]
end

def greedy_match?(input)

def greedy_match?(input)
  @union.match(input) { |m| @neutral_map.detect { |route| m[route.regexp_capture_index] } }
end

def identity(env)

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

def initialize

def initialize
  @neutral_map = []
  @neutral_regexes = []
  @map = Hash.new { |hash, key| hash[key] = [] }
  @optimized_map = Hash.new { |hash, key| hash[key] = // }
end

def make_routing_args(default_args, route, input)

def make_routing_args(default_args, route, input)
  args = default_args || { route_info: route }
  args.merge(route.params(input))
end

def match?(input, method)

def match?(input, method)
  @optimized_map[method].match(input) { |m| @map[method].detect { |route| m[route.regexp_capture_index] } }
end

def prepare_env_from_route(env, route)

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

def process_route(route, env)

def process_route(route, env)
  prepare_env_from_route(env, route)
  route.exec(env)
end

def recognize_path(input)

def recognize_path(input)
  any = with_optimization { greedy_match?(input) }
  return if any == default_response
  any.endpoint
end

def rotation(env, exact_route = nil)

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

def string_for(input)

def string_for(input)
  self.class.normalize_path(input)
end

def transaction(env)

def transaction(env)
  input, method = *extract_input_and_method(env)
  # using a Proc is important since `return` will exit the enclosing function
  cascade_or_return_response = proc do |response|
    if response
      cascade?(response).tap do |cascade|
        return response unless cascade
        # we need to close the body if possible before dismissing
        response[2].close if response[2].respond_to?(:close)
      end
    end
  end
  last_response_cascade = cascade_or_return_response.call(yield(input, method))
  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 == Rack::OPTIONS && !last_response_cascade
  route = match?(input, '*')
  return last_neighbor_route.options[:endpoint].call(env) if last_neighbor_route && last_response_cascade && route
  last_response_cascade = cascade_or_return_response.call(process_route(route, env)) if route
  return call_with_allow_headers(env, last_neighbor_route) if !last_response_cascade && last_neighbor_route
  nil
end

def with_optimization

def with_optimization
  compile! unless compiled
  yield || default_response
end