1. A router is similar to a Rack middleware.

  2. The main difference is that it doesn’t wrap a single Rack endpoint, but keeps a list of endpoints, just like Rack::Cascade does.

  3. Depending on some criteria, usually the requested path, the router will then decide what endpoint to hand the request to.

  4. Most routers differ in the way they decide which endpoint to hand the request to.

  5. All routers meant for general usage do offer routing based on the path, but how complex their path matching might be varies.

  6. While Rack::URLMap only matches prefixes, most other routers allow simple wildcard matching.

  7. Both Rack::Mount, which is used by Rails, and Sinatra allow arbitrary matching logic.

  8. However, such flexibility comes at a price: Rack::Mount and Sinatra have a routing complexity of O(n), meaning that in the worst-case scenario an incoming request has to be matched against all the defined routes.

  9. Rack::Mount is known to produce fast routing, however its API is not meant to be used directly but rather by other libraries, like the Rails routes DSL.

[~/local/src/ruby/sinatra/rack/rack-mount]$ cat config.ru 
require 'sinatra/base'
require 'rack/mount'

class Foo < Sinatra::Base
  get('/foo') { 'foo' }
  get('/fou') { 'fou' }

class Bar < Sinatra::Base
  get('/bar') { 'bar' }
  get('/ba')  { 'ba' }

Routes = Rack::Mount::RouteSet.new do |set|
  set.add_route Foo, :path_info => %r{^/fo[ou]$}
  set.add_route Bar, :path_info => %r{^/bar?$}

run Routes

Casiano Rodriguez León 2015-01-07