Motivation
- I want to be able to handle http requests. I like the simplicity of Rack, but I want more control over the initial mapping. I like Sinatra, but I want to easily handle request methods other than GET, PUT, POST, DELETE, and HEAD. So, the Router class below maps regular expressions to handler functions.
Requirements/Environment
- Mac os x 10.5.8
- Ruby 1.8.6 (2008-08-11 patchlevel 287) [universal-darwin9.0]
- Rack gem version 1.1.0
Code
class Router def initialize(routes) @routes = routes end def default [ 404, {'Content-Type' => 'text/plain'}, 'file not found' ] end def call(env) @routes.each do |route| match = env['REQUEST_PATH'].match(route[:pattern]) if match return route[:controller].call( env, match ) end end default end end
Usage
# assumes router code is in router.rb require 'router' use Rack::CommonLogger use Rack::ShowExceptions use Rack::Lint use Rack::Static, :urls => ["/static"] run Router.new([ { :pattern => %r{^/page1$}, :controller => lambda do |env, match| [ 200, {'Content-Type' => 'text/html'}, 'page 1' ] end }, { :pattern => %r{^/}, :controller => lambda do |env, match| [ 200, {'Content-Type' => 'text/html'}, 'index!' ] end } ]);
Run it on the command line using Rack’s native Rackup ($ rackup config.ru
) or via Ryan Tomayko’s shotgun, which conveniently auto-reloads.
Reference
Update Mar 5, 2011
- because Ruby < 1.9 doesn't preserve ordering in hashes, I’ve updated the code to use an array of routes. It’s more verbose, but now the route matching correctly runs top to bottom.
- I also added a method for overriding the default response from the router
Update Mar 9, 2011
- I’m now maintaining this code in a Github gist:https://gist.github.com/861870
- Added instructions for running this code