class Racket::Router

Handles routing in Racket applications.

Constants

Route

A struct describing a route.

Attributes

routes[R]

Public Class Methods

new(options) click to toggle source
# File lib/racket/router.rb, line 59
def initialize(options)
  @options = OpenStruct.new(options)
  @router = HttpRouter.new
  @routes = {}
end
service(_options = {}) click to toggle source

Returns a service proc that can be used by the registry.

@param [Hash] _options (unused) @return [Proc]

# File lib/racket/router.rb, line 44
def self.service(_options = {})
  lambda do |reg|
    new(
      action_cache: reg.action_cache,
      dev_mode: reg.application_settings.mode == :dev,
      logger: reg.application_logger
    )
  end
end

Public Instance Methods

action_cache() click to toggle source

@return [Racket::Utils::Routing::ActionCache]

# File lib/racket/router.rb, line 55
def action_cache
  @options.action_cache
end
get_route(controller_class, action, params) click to toggle source

Returns a route to the specified controller/action/parameter combination.

@param [Class] controller_class @param [Symbol] action @param [Array] params @return [String]

# File lib/racket/router.rb, line 71
def get_route(controller_class, action, params)
  raise "Cannot find controller #{controller_class}" unless @routes.key?(controller_class)
  params.flatten!
  Route.new(@routes[controller_class], action, params).to_s
end
map(path, controller_class) click to toggle source

Maps a controller to the specified path.

@param [String] path @param [Class] controller_class @return [nil]

# File lib/racket/router.rb, line 82
def map(path, controller_class)
  map_controller(path.empty? ? '/' : path, controller_class)
  @router.add("#{path}(/*params)").to(controller_class)
  action_cache.add(controller_class)
end
render_error(status, error = nil) click to toggle source

@todo: Allow the user to set custom handlers for different errors

# File lib/racket/router.rb, line 89
def render_error(status, error = nil)
  if (error)
    # If running in dev mode, let Rack::ShowExceptions handle the error.
    raise error if @options.dev_mode
    # Not running in dev mode, let us handle the error ourselves.
    $stderr.write("#{error.class}: #{error.message}\n#{error.backtrace.map { |l| "\t#{l}" }.join("\n")}\n\n")
  end
  Response.generate_error_response(status)
end
route(env) click to toggle source

Routes a request and renders it.

@param [Hash] env Rack environment @return [Array] A Rack response triplet

# File lib/racket/router.rb, line 103
def route(env)
  catch :response do # Catches early exits from Controller.respond.
    # Ensure that that a controller will respond to the request. If not, send a 404.
    return render_error(404) unless (target_info = target_info(env))
    Racket::Utils::Routing::Dispatcher.new(env, target_info).dispatch
  end
rescue => err
  render_error(500, err)
end

Private Instance Methods

map_controller(base_path, controller_class) click to toggle source
# File lib/racket/router.rb, line 115
def map_controller(base_path, controller_class)
  @options.logger.inform_dev("Mapping #{controller_class} to #{base_path}.")
  @routes[controller_class] = base_path
end
target_info(env) click to toggle source

Returns information about the target of the request. If no valid target can be found, nil is returned.

@param [Hash] env @return [Array|nil]

# File lib/racket/router.rb, line 125
def target_info(env)
  matching_route = @router.recognize(env).first
  # Exit early if no controller is responsible for the route
  return nil unless matching_route
  # Some controller is claiming to be responsible for the route, find out which one.
  result = Racket::Utils::Routing::Dispatcher.extract_target(matching_route.first)
  # Exit early if action is not available on target
  return nil unless action_cache.present?(result.first, result.last)
  result
end