Class: Gin::Router

Inherits:
Object
  • Object
show all
Defined in:
lib/gin/router.rb

Overview

The Gin::Router class is the core of how Gin maps HTTP requests to a Controller and action (target), and vice-versa.

router = Gin::Router.new
router.add FooController do
  get :index, "/"
  get :show, "/:id"
end

router.path_to FooController, :show, id: 123
#=> "/foo/123"

router.path_to :show_foo, id: 123
#=> "/foo/123"

router.resources_for "get", "/foo/123"
#=> [FooController, :show, {:id => "123"}]

Defined Under Namespace

Classes: Mount, Node, PathArgumentError, Route

Instance Method Summary collapse

Constructor Details

#initializeRouter

Returns a new instance of Router.



235
236
237
238
# File 'lib/gin/router.rb', line 235

def initialize
  @routes_tree = Node.new
  @routes_lookup = {}
end

Instance Method Details

#add(ctrl, base_path = nil, &block) ⇒ Object

Add a Controller to the router with a base path. Used by Gin::App.mount.



245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/gin/router.rb', line 245

def add ctrl, base_path=nil, &block
  base_path ||= ctrl.controller_name

  mount = Mount.new(ctrl, base_path, &block)

  mount.each_route do |route|
    curr_node = @routes_tree

    route.match_keys.each do |part|
      curr_node.add_child part
      curr_node = curr_node[part]
    end

    curr_node.value = route
    @routes_lookup[route.name]   = route if route.name
    @routes_lookup[route.target] = route
  end
end

#each_route(&block) ⇒ Object

Yield every route, controller, action combinations the router knows about.



276
277
278
279
280
281
# File 'lib/gin/router.rb', line 276

def each_route &block
  @routes_lookup.each do |key,route|
    next unless Array === key
    block.call route, key[0], key[1]
  end
end

#has_route?(ctrl, action) ⇒ Boolean

Check if a Controller and action pair has a route.

Returns:

  • (Boolean)


268
269
270
# File 'lib/gin/router.rb', line 268

def has_route? ctrl, action
  !!@routes_lookup[[ctrl, action]]
end

#path_to(*args) ⇒ Object

Get the path to the given Controller and action combo or route name, provided with the needed params. Routes with missing path params will raise MissingParamError. Returns a String starting with “/”.

path_to FooController, :show, id: 123
#=> "/foo/123"

path_to :show_foo, id: 123
#=> "/foo/123"

path_to :show_foo, id: 123, more: true
#=> "/foo/123?more=true"

Raises:



298
299
300
301
302
303
304
305
306
# File 'lib/gin/router.rb', line 298

def path_to *args
  key = Class === args[0] ? args.slice!(0..1) : args.shift
  route = @routes_lookup[key]
  raise PathArgumentError, "No route for #{Array(key).join("#")}" unless route

  params = (args.pop || {}).dup

  route.to_path(params)
end

#resources_for(http_verb, path) ⇒ Object

Takes a path and returns an array with the controller class, action symbol, processed path params.

router.resources_for "get", "/foo/123"
#=> [FooController, :show, {:id => "123"}]

Returns nil if no match was found.



318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
# File 'lib/gin/router.rb', line 318

def resources_for http_verb, path
  param_vals = []
  curr_node  = @routes_tree[http_verb.to_s.downcase]
  return unless curr_node

  path.scan(%r{/([^/]+|$)}) do |(key)|
    next if key.empty?

    if curr_node[key]
      curr_node = curr_node[key]

    elsif curr_node["%s"]
      param_vals << CGI.unescape(key)
      curr_node = curr_node["%s"]

    elsif child_and_matches = curr_node.match(CGI.unescape(key))
      param_vals.concat child_and_matches[1]
      curr_node = child_and_matches[0]

    else
      return
    end
  end

  return unless curr_node.value
  route = curr_node.value

  path_params = param_vals.empty? ?
    {} : route.param_keys.inject({}){|h, name| h[name] = param_vals.shift; h}

  [*route.target, path_params]
end