Class: Raw::Dispatcher
- Inherits:
-
Object
- Object
- Raw::Dispatcher
- Defined in:
- lib/raw/dispatcher.rb,
lib/raw/dispatcher/mounter.rb
Overview
The Dispatcher manages a set of controllers. It selects the appropriate Controller and action to handle the given request.
This dispatcher intelligently handles RESTful uris according to the following scheme:
GET /links GET /links/index Link::Controller#index POST /links POST /links/create Link::Controller#create
GET /links;new GET /links/new Link::Controller#new GET /links/1 Link::Controller#view(1) GET /links/1;edit GET /links/edit/1 Link::Controller#edit(1) PUT /links/1 POST /links/update/1 Link::Controller#update DELETE /links/1 GET /links/delete/1 Link::Controller#delete(1) GET /links/index.xml Link::Controller#index # Atom GET /links/index.json Link::Controller#index # JSON
The default actions for the various methods are:
GET: index
POST: create
PUT: update
DELETE: delete
Defined Under Namespace
Classes: Mounter
Instance Attribute Summary collapse
-
#controllers ⇒ Object
The hash that maps mount paths to controllers.
-
#formats ⇒ Object
The representation formats this dispatcher understands.
-
#router ⇒ Object
The (optional) router.
Instance Method Summary collapse
-
#[](path = "/") ⇒ Object
Return the controller for the given mount path.
-
#[]=(path, controller) ⇒ Object
Mount a controller to the given mount path.
-
#dispatch(uri, method = :get) ⇒ Object
Dispatch a path given the request method.
-
#dispatch_request(request) ⇒ Object
(also: #dispatch_context)
Dispatch a request.
-
#initialize(controller_or_map = nil) ⇒ Dispatcher
constructor
Initialize the dispatcher.
-
#mount(map) ⇒ Object
Mounts a map of controllers.
- #root ⇒ Object
-
#root=(controller) ⇒ Object
An alternative mounting mechanism (CherryPy like).
Constructor Details
#initialize(controller_or_map = nil) ⇒ Dispatcher
Initialize the dispatcher.
49 50 51 52 53 54 55 56 57 58 |
# File 'lib/raw/dispatcher.rb', line 49 def initialize(controller_or_map = nil) @controllers = {} @formats = Nitro::STANDARD_FORMATS.dup if controller_or_map.is_a?(Class) mount("/" => controller_or_map) elsif controller_or_map.is_a?(Hash) mount(controller_or_map) end end |
Instance Attribute Details
#controllers ⇒ Object
The hash that maps mount paths to controllers.
41 42 43 |
# File 'lib/raw/dispatcher.rb', line 41 def controllers @controllers end |
#formats ⇒ Object
The representation formats this dispatcher understands.
45 46 47 |
# File 'lib/raw/dispatcher.rb', line 45 def formats @formats end |
#router ⇒ Object
The (optional) router.
37 38 39 |
# File 'lib/raw/dispatcher.rb', line 37 def router @router end |
Instance Method Details
#[](path = "/") ⇒ Object
Return the controller for the given mount path.
70 71 72 |
# File 'lib/raw/dispatcher.rb', line 70 def [](path = "/") @controllers[path] end |
#[]=(path, controller) ⇒ Object
Mount a controller to the given mount path.
76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/raw/dispatcher.rb', line 76 def []=(path, controller) controller = resolve_controller(controller) # Customize the class for mounting at the given path. controller.mount_at(path) if controller.respond_to? :mount_at # Call the mounted callback to allow for post mount # initialization. controller.mounted(path) if controller.respond_to? :mounted @controllers[path] = controller end |
#dispatch(uri, method = :get) ⇒ Object
Dispatch a path given the request method. This method handles fully resolved paths (containing an extension that denotes the expected content type).
This method automatically handles ‘nice’ (seo friendly, elegant) parameters, ie:
/links/view/1
instead of
/links/view?oid=1
Output
controller, action, query_string, nice_params, extension
– Lower level, useful for testing. ++
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/raw/dispatcher.rb', line 117 def dispatch(uri, method = :get) # Extract the query string. path, query = uri.split("?", 2) # Try to route the path. path = @router.route(path) if @router # The characters after the last '.' in the path form the # extension that itself represents the expected response # content type. ext = File.extname(path)[1..-1] || "html" # The resource representation format for this request. unless format = Context.current.format = @formats.by_extension[ext] raise ActionError.new("Cannot respond to '#{path}' using the '#{ext}' format representation.") end # Remove the extension from the path. path = path.gsub(/\.(.*)$/, '') # Try to extract the controller from the path (that may also # include 'nice' parameters). This algorithm tries to find # the bigest substring of the path that represents a mount # path for a controller. key = path.dup while (controller = @controllers[key]).nil? key = key[%r{^(/.+)/.+$}, 1] || '/' end # Try to extract the controller from the path. This # algorithm tries to find the bigest substring of the path # that represents an action of this controller. # # The algorithm respects action name conventions, ie # simple/sub/action maps to simple__sub__action. action = key = path.sub(%r{^#{key}}, '').gsub(%r{^/}, '').gsub(%r{/}, '__') while (!action.blank?) and !controller.action_or_template?(action, format) action = action[%r{^(.+)__.+$}, 1] end # Extract the 'nice' parameters. params = key.sub(%r{^#{action}}, '').gsub(/^__/, '').split('__') # Do we have an action? if action.blank? # Try to use a standard action for this http method. case method when :get action = "index" when :post action = "create" when :delete action = "delete" when :put action = "update" end unless controller.action_or_template?(action, format) raise ActionError.new("Cannot respond to '#{path}' using '#{controller}'") end end return controller, "#{action}___super", query, params, ext end |
#dispatch_request(request) ⇒ Object Also known as: dispatch_context
Dispatch a request. Calls the lower level dispatch method.
91 92 93 |
# File 'lib/raw/dispatcher.rb', line 91 def dispatch_request(request) dispatch(request.uri, request.method) end |
#mount(map) ⇒ Object
Mounts a map of controllers.
62 63 64 65 66 |
# File 'lib/raw/dispatcher.rb', line 62 def mount(map) for path, controller in map self[path] = controller end end |
#root ⇒ Object
52 53 54 55 56 |
# File 'lib/raw/dispatcher/mounter.rb', line 52 def root if controller = self["/"] Mounter.new(self, controller) end end |
#root=(controller) ⇒ Object
An alternative mounting mechanism (CherryPy like).
Example
dispatcher.root = RootController dispatcher.root.users = User::Controller dispatcher.root.users.comments = User::Comment::Controller
48 49 50 |
# File 'lib/raw/dispatcher/mounter.rb', line 48 def root=(controller) self["/"] = resolve_controller(controller) end |