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.



289
290
291
292
# File 'lib/gin/router.rb', line 289

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.



299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
# File 'lib/gin/router.rb', line 299

def add ctrl, base_path=nil, &block
  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.



328
329
330
331
332
333
# File 'lib/gin/router.rb', line 328

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)


320
321
322
# File 'lib/gin/router.rb', line 320

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. Missing routes will raise a RouterError. 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"


351
352
353
354
355
# File 'lib/gin/router.rb', line 351

def path_to *args
  params = args.pop.dup if Hash === args.last
  route = route_to(*args)
  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.



390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
# File 'lib/gin/router.rb', line 390

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

  path.scan(%r{/([^/]+|$)}) do |matches|
    key = matches[0]
    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

#route_to(*args) ⇒ Object

Get the route object to the given Controller and action combo or route name. MissingParamError. Returns a Gin::Router::Route instance. Raises a RouterError if no route can be found.

route_to FooController, :show
route_to :show_foo


366
367
368
369
370
371
372
373
374
375
376
377
378
# File 'lib/gin/router.rb', line 366

def route_to *args
  key = Class === args[0] ? args.slice!(0..1) : args.shift
  route = @routes_lookup[key]

  unless route
    name = Array === key && Gin::Mountable === key[0] ?
            key[0].display_name(key[1]) : name.inspect

    raise Gin::RouterError, "No route for #{name}"
  end

  route
end