Class: Nitro::Dispatcher
- Inherits:
-
Object
- Object
- Nitro::Dispatcher
- Includes:
- Router
- Defined in:
- lib/nitro/dispatcher.rb
Overview
The Dispatcher manages a set of controllers. It maps a request uri to a [controller, action] pair.
Constant Summary collapse
- ROOT =
'/'
Instance Attribute Summary collapse
-
#controllers ⇒ Object
The controllers map.
-
#server ⇒ Object
The server.
Attributes included from Router
Instance Method Summary collapse
-
#add_controller(controllers) ⇒ Object
(also: #mount, #publish, #map=)
A published object is exposed through a REST interface.
-
#dispatch(path, context = nil) ⇒ Object
(also: #split_path)
Processes the path and dispatches to the corresponding controller/action pair.
-
#initialize(controllers = nil) ⇒ Dispatcher
constructor
Create a new Dispatcher.
-
#mixin_auto_helpers(klass) ⇒ Object
Call this method to automatically include helpers in the Controllers.
-
#update_routes ⇒ Object
Update the routes.
Methods included from Router
#<<, add_rule, #add_rule, #add_rules, #decode_route, #encode_route, #init_routes
Constructor Details
#initialize(controllers = nil) ⇒ Dispatcher
Create a new Dispatcher.
Input:
controllers
-
Either a hash of controller mappings or a single controller that gets mapped to :root.
37 38 39 40 41 42 43 44 45 |
# File 'lib/nitro/dispatcher.rb', line 37 def initialize(controllers = nil) if controllers and controllers.is_a?(Class) and controllers.ancestors.include?(Controller) controllers = { '/' => controllers } else controllers ||= { '/' => Controller } end mount(controllers) end |
Instance Attribute Details
#controllers ⇒ Object
The controllers map.
27 28 29 |
# File 'lib/nitro/dispatcher.rb', line 27 def controllers @controllers end |
#server ⇒ Object
The server.
23 24 25 |
# File 'lib/nitro/dispatcher.rb', line 23 def server @server end |
Instance Method Details
#add_controller(controllers) ⇒ Object Also known as: mount, publish, map=
A published object is exposed through a REST interface. Only the public non standard methods of the object are accessible. Published objects implement the Controller part of MVC.
Process the given hash and mount the defined classes (controllers).
Input:
controllers
-
A hash representing the mapping of mount points to controllers.
Examples
disp.mount(
'/' => MainController, # mounts /
'/users' => UsersController # mounts /users
)
disp.publish ‘/’ => MainController
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/nitro/dispatcher.rb', line 69 def add_controller(controllers) for path, klass in controllers unless (klass.ancestors.include?(Controller) or klass.ancestors.include?(Publishable)) klass.send :include, Publishable end # Automatically mixin controller helpers. mixin_auto_helpers(klass) # Customize the class for mounting at the given path. #-- # gmosx, TODO: path should include trailing '/' # gmosx, TODO: should actually create an instance, thus # allowing mounting the same controller to multiple # paths, plus simplifying the code. This instance will # be dup-ed for each request. #++ klass.mount_at(path) # Call the mounted callback to allow for post mount # initialization. klass.mounted(path) if klass.respond_to?(:mounted) end (@controllers ||= {}).update(controllers) update_routes() end |
#dispatch(path, context = nil) ⇒ Object Also known as: split_path
Processes the path and dispatches to the corresponding controller/action pair.
path
-
The path to dispatch.
- :context
-
The dispatching context.
The dispatching algorithm handles implicit nice urls. Subdirectories are also supported. Action containing ‘/’ separators look for templates in subdirectories. The ‘/’ char is converted to ‘__’ to find the actual action. The dispatcher also handles nested controllers.
Returns the dispatcher class and the action name. – FIXME: this is a critical method that should be optimized watch out for excessive String creation. TODO: add caching. ++
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 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
# File 'lib/nitro/dispatcher.rb', line 170 def dispatch(path, context = nil) # Try if the router can directly decode the path. klass, action, params = decode_route(path) if klass # This adds parameter values from the setup from the route to the normal # query strings. context.headers['QUERY_STRING'] ||= '' extra = params.map { |k, v| "#{k}=#{v}"}.join(';') if params if context.headers['QUERY_STRING'].empty? context.headers['QUERY_STRING'] = extra else context.headers['QUERY_STRING'] << ';' << extra end context.headers['ACTION_PARAMS'] = params.values # context.params.update(params) if params # gmosx, FIXME/OPTIMIZE: no annotation for mount point!! return klass, "#{action}_action", klass.mount_path end key, * = path.split('?', 2) key = key.split('/') parts = [] while (not key.empty?) and (klass = controller_class_for("#{key.join('/')}")).nil? parts.unshift(key.pop) end klass = controller_class_for(ROOT) unless klass idx = 0 found = false # gmosx, HACKFIX! parts.shift if parts.first == '' # Try to find the first valid action substring action = '' for part in parts action << part if klass.respond_to_action_or_template?(action) found = true break end action << '__' idx += 1 end # Check the index action. unless found action = :index if klass.respond_to_action? action a = klass.instance_method(action).arity found = true if a < 0 || a >= parts.size elsif klass.respond_to_template? action found = true if parts.size == 0 end idx = -1 if found end if found parts.slice!(0, idx + 1) =begin if $DBG # Some extra checking of the parameters. Only enabled # on debug mode, because it slows down dispatching. a = klass.instance_method(action).arity if a > 0 and a != parts.size raise ActionError, "Invalid parameters for action, expects #{a} parameters, received #{parts.size}" end end =end else #-- # FIXME: no raise to make testable. #++ raise ActionError, "No action for path '#{path}' on '#{klass}'" end # push any remaining parts of the url onto the query # string for use with request context.headers['ACTION_PARAMS'] = parts return klass, "#{action}_action" end |
#mixin_auto_helpers(klass) ⇒ Object
Call this method to automatically include helpers in the Controllers. For each Controller ‘XxxController’ the default helper ‘Helper’ and the auto helper ‘XxxControllerHelper’ (if it exists) are included.
109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/nitro/dispatcher.rb', line 109 def mixin_auto_helpers(klass) klass.helper(Nitro::DefaultHelper) return # FIXME: make the following work again! begin if helper = Module.by_name("#{klass}Helper") klass.helper(helper) end rescue NameError # The auto helper is not defined. end end |
#update_routes ⇒ Object
Update the routes. Typically called after a new Controller is mounted.
Example of routing through annotations
def view_user
"params: #{request[:id]} and #{request[:mode]}"
end ann :view_user, :route => [ /user_(d*)_(*?).html/, :id, :mode ]
133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/nitro/dispatcher.rb', line 133 def update_routes init_routes() @controllers.each do |base, c| base = '' if base == '/' for m in c.action_methods m = m.to_sym if route = c.ann(m).route and (!route.nil?) add_rule(:match => route.first, :controller => c, :action => m, :params => route.last) end end end end |