class Angus::Router

Constants

PathPattern
RE_TRAILING_SLASH
Route
SUPPORTED_HTTP_METHODS
VERSION

Public Instance Methods

on(m, path, &block) click to toggle source

It registers block to be yielded at a given HTTP method and path.

@param [Symbol] m HTTP method (see SUPPORTED_HTTP_METHODS) @param [String] path Url path @param [Proc] block The block that will be yielded when an incoming request matches the route

# File lib/angus/router.rb, line 60
def on(m, path, &block)
  path = path.gsub(RE_TRAILING_SLASH, '')

  unless SUPPORTED_HTTP_METHODS.include?(m)
    raise ArgumentError.new("Unsupported HTTP method #{m}")
  end

  route = Route.new(m.to_s.upcase, block, compile(path))

  if route.params?
    dynamic_routes << route
  else
    static_routes << route
  end
end
route(env) click to toggle source

Calls the corresponding previously registered block.

When calling, the rack environment and the extracted path params are passed to the route block.

@param [Hash] env A Rack environment. (see rack.rubyforge.org/doc/SPEC.html)

@return The result of the block call

# File lib/angus/router.rb, line 84
def route(env)
  request = Rack::Request.new(env)

  path_info = request.path_info.gsub(RE_TRAILING_SLASH, '').squeeze('/')
  matched_route = match_route(env['REQUEST_METHOD'], path_info)

  match, route_block, path_param_names = matched_route

  unless match
    raise NotImplementedError, "No route found #{request.path_info}"
  end

  path_params = extract_params(match, path_param_names)
  whole_params = request.params.clone.merge!(path_params)
  whole_params = symbolize(whole_params)

  route_block.call(env, whole_params)
end

Private Instance Methods

compile(pattern) click to toggle source

Returns a path pattern base on the given pattern.

@example compile('/users/:id')

=> PathPattern.new(/^\/users\/([^\/?#]+)$/, ['id']])

@param [String] Url path

@return [PathPattern]

# File lib/angus/router.rb, line 131
def compile(pattern)
  keys = []

  pattern = pattern.to_str.squeeze('/')
  pattern.gsub!(/[^\?\%\\\/\:\*\w]/) { |c| encoded(c) }
  pattern.gsub!(/(:\w+)/) do |match|
    keys << $1[1..-1]
    "([^/?#]+)"
  end

  PathPattern.new(/^#{pattern}$/, keys)
end
dynamic_routes() click to toggle source
# File lib/angus/router.rb, line 115
def dynamic_routes
  @dynamic_routes ||= []
end
encoded(char) click to toggle source

Escapes a char for uri regex matching.

@param [String] char

@return [String]

# File lib/angus/router.rb, line 149
def encoded(char)
  enc = URI.escape(char)
  enc = "(?:#{Regexp.escape enc}|#{URI.escape char, /./})" if enc == char
  enc = "(?:#{enc}|#{encoded('+')})" if char == " "
  enc
end
extract_params(match, keys) click to toggle source

Extracts matched values from the given match.

Assoaciates each match to the corresponding key.

@param [MatchData] match @param [Array] keys

@return [Hash] A hash containing extracted key / values

# File lib/angus/router.rb, line 183
def extract_params(match, keys)
  hash = {}

  captures = match.captures

  keys.each_with_index do |k, i|
    hash[k] = captures[i]
  end

  hash
end
match_route(method, path) click to toggle source

Returns regexp, block and path param names according to the route that matches the given method and path.

@param [String] method HTTP method @param [String] path Url path

@return [regexp, route_block, path_param_names]

# File lib/angus/router.rb, line 163
def match_route(method, path)
  [static_routes, dynamic_routes].each do |routes|
    routes.each do |route|
      if method == route.method && match = route.match(path)
        return [match, route.proc, route.param_names]
      end
    end
  end

  nil
end
static_routes() click to toggle source
# File lib/angus/router.rb, line 119
def static_routes
  @static_routes ||= []
end
symbolize(hash) click to toggle source

Returns a shallow copy with keys as symbols of hash.

@param [Hash] hash

@return [Hash]

# File lib/angus/router.rb, line 109
def symbolize(hash)
  Hash[
    hash.map { |k, v| [k.to_sym, v] }
  ]
end