class Shaf::Router

Attributes

controllers[R]

Public Class Methods

default_controller() click to toggle source

This controller will be used when no other can handle the request (E.g. returning 404 Not Found)

# File lib/shaf/router.rb, line 38
def default_controller
  @default_controller ||= nil
end
mount(controller, default: false) click to toggle source
# File lib/shaf/router.rb, line 25
def mount(controller, default: false)
  @default_controller = controller if default
  @controllers ||= []
  @controllers << controller
end
new(app) click to toggle source
# File lib/shaf/router.rb, line 60
def initialize(app)
  @app = app
end
routes() click to toggle source
# File lib/shaf/router.rb, line 31
def routes
  init_routes unless defined? @routes
  @routes
end

Private Class Methods

init_routes() click to toggle source
# File lib/shaf/router.rb, line 46
def init_routes
  @routes = Hash.new do |hash, key|
    hash[key] = Hash.new { |h, k| h[k] = Set.new }
  end
  controllers.each { |controller| init_routes_for(controller) }
end
init_routes_for(controller) click to toggle source
# File lib/shaf/router.rb, line 53
def init_routes_for(controller)
  controller.routes.each do |method, controller_routes|
    routes[method][controller] += controller_routes.map(&:first)
  end
end

Public Instance Methods

call(env) click to toggle source
# File lib/shaf/router.rb, line 64
def call(env)
  http_method, path = http_details(env)

  result = nil

  controllers_for(http_method, path) do |controller|
    result = controller.call(env)
    break unless cascade? result
  end

  result
end

Private Instance Methods

add_cache(controller, http_method, path) click to toggle source
# File lib/shaf/router.rb, line 149
def add_cache(controller, http_method, path)
  return unless controller

  key = cache_key(http_method, path)
  cache[key] << controller
end
cache() click to toggle source
# File lib/shaf/router.rb, line 145
def cache
  @cache ||= Hash.new { |hash, key| hash[key] = Set.new }
end
cache_key(http_method, path) click to toggle source
# File lib/shaf/router.rb, line 161
def cache_key(http_method, path)
  path[1..-1].split('/').inject("#{http_method}_") do |key, segment|
    segment = ':id' if segment =~ /\A\d+\z/
    "#{key}/#{segment}"
  end
end
cascade?(result) click to toggle source
# File lib/shaf/router.rb, line 141
def cascade?(result)
  result.dig(1, 'X-Cascade') == 'pass'
end
controllers_for(http_method, path) { |ctrlr| ... } click to toggle source
# File lib/shaf/router.rb, line 83
def controllers_for(http_method, path)
  find_cached(http_method, path).each { |ctrlr| yield ctrlr }

  if controller = find(http_method, path)
    yield controller
  end

  find_all(http_method, path).each do |ctrlr|
    yield ctrlr unless ctrlr == controller
  end

  supported_methods = supported_methods_for(path)
  if !supported_methods.empty? && !supported_methods.include?(http_method)
    yield MethodNotAllowedResponder.new(supported_methods)
  end

  yield default_controller
end
default_controller() click to toggle source
# File lib/shaf/router.rb, line 102
def default_controller
  self.class.default_controller || @app || raise('No default controller')
end
find(http_method, path) click to toggle source
# File lib/shaf/router.rb, line 110
def find(http_method, path)
  routes[http_method].each do |controller, patterns|
    next unless patterns.any? { |pattern| pattern.match(path) }
    add_cache(controller, http_method, path)
    return controller
  end

  nil
end
find_all(http_method, path) click to toggle source
# File lib/shaf/router.rb, line 120
def find_all(http_method, path)
  Set.new.tap do |controllers|
    routes[http_method].each do |ctrlr, patterns|
      next unless patterns.any? { |pattern| pattern.match(path) }
      add_cache(ctrlr, http_method, path)
      controllers << ctrlr
    end
  end
end
find_cached(http_method, path) click to toggle source
# File lib/shaf/router.rb, line 156
def find_cached(http_method, path)
  key = cache_key(http_method, path)
  cache[key]
end
http_details(env) click to toggle source
# File lib/shaf/router.rb, line 79
def http_details(env)
  [env['REQUEST_METHOD'], env['PATH_INFO']]
end
routes() click to toggle source
# File lib/shaf/router.rb, line 106
def routes
  self.class.routes
end
supported_methods_for(path) click to toggle source
# File lib/shaf/router.rb, line 130
def supported_methods_for(path)
  methods = Set.new
  routes.each do |http_method, controllers|
    controllers.each do |_, patterns|
      next unless patterns.any? { |pattern| pattern.match(path) }
      methods << http_method
    end
  end
  methods.to_a
end