class Padrino::Router

This class is an extended version of Rack::URLMap.

Padrino::Router like Rack::URLMap dispatches in such a way that the longest paths are tried first, since they are most specific.

Features:

@example

routes = Padrino::Router.new do
  map(:path => "/", :to => PadrinoWeb, :host => "padrino.local")
  map(:path => "/", :to => Admin, :host => "admin.padrino.local")
end
run routes

routes = Padrino::Router.new do
  map(:path => "/", :to => PadrinoWeb, :host => /*.padrino.local/)
end
run routes

@api semipublic

Public Class Methods

new(*mapping, &block) click to toggle source
# File lib/padrino-core/router.rb, line 29
def initialize(*mapping, &block)
  @mapping = []
  mapping.each { |m| map(m) }
  instance_eval(&block) if block
end

Public Instance Methods

call(env) click to toggle source

The call handler setup to route a request given the mappings specified.

# File lib/padrino-core/router.rb, line 68
def call(env)
  began_at = Time.now
  path_info = env["PATH_INFO"].to_s
  script_name = env['SCRIPT_NAME']
  http_host = env['HTTP_HOST']
  last_result = nil

  @mapping.each do |host, path, match, app|
    next unless host.nil? || http_host =~ host
    next unless path_info =~ match && rest = $1
    next unless rest.empty? || rest[0] == ?/

    rest = "/" if rest.empty?

    env['SCRIPT_NAME'] = script_name + path
    env['PATH_INFO'] = rest
    last_result = app.call(env)

    cascade_setting = app.respond_to?(:cascade) ? app.cascade : true
    cascade_statuses = cascade_setting.respond_to?(:include?) ? cascade_setting : Mounter::DEFAULT_CASCADE
    break unless cascade_setting && cascade_statuses.include?(last_result[0])
  end
  last_result || begin
    env['SCRIPT_NAME'] = script_name
    env['PATH_INFO'] = path_info
    Padrino::Logger::Rack.new(nil,'/').send(:log, env, 404, {}, began_at) if logger.debug?
    [404, {"Content-Type" => "text/plain", "X-Cascade" => "pass"}, ["Not Found: #{path_info}"]]
  end
end
map(options={}) click to toggle source

Map a route path and host to a specified application.

@param [Hash] options

The options to map.

@option options [Sinatra::Application] :to

The class of the application to mount.

@option options [String] :path (“/”)

The path to map the specified application.

@option options [String] :host

The host to map the specified application.

@example

map(:path => "/", :to => PadrinoWeb, :host => "padrino.local")

@return [Array] The sorted route mappings. @api semipublic

# File lib/padrino-core/router.rb, line 52
def map(options={})
  path = options[:path] || "/"
  host = options[:host]
  app  = options[:to]

  raise ArgumentError, "paths need to start with /" if path[0] != ?/
  raise ArgumentError, "app is required" if app.nil?

  path  = path.chomp('/')
  match = Regexp.new("^#{Regexp.quote(path).gsub('/', '/+')}(.*)", nil, 'n')
  host  = Regexp.new("^#{Regexp.quote(host)}$", true, 'n') unless host.nil? || host.is_a?(Regexp)

  @mapping << [host, path, match, app]
end