wycats-merb-core 0.9.8 → 0.9.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. data/CHANGELOG +136 -2
  2. data/CONTRIBUTORS +6 -0
  3. data/PUBLIC_CHANGELOG +15 -0
  4. data/Rakefile +12 -14
  5. data/lib/merb-core.rb +82 -43
  6. data/lib/merb-core/bootloader.rb +268 -60
  7. data/lib/merb-core/config.rb +119 -34
  8. data/lib/merb-core/controller/abstract_controller.rb +58 -18
  9. data/lib/merb-core/controller/exceptions.rb +2 -15
  10. data/lib/merb-core/controller/merb_controller.rb +28 -1
  11. data/lib/merb-core/controller/mime.rb +4 -0
  12. data/lib/merb-core/controller/mixins/controller.rb +14 -17
  13. data/lib/merb-core/controller/mixins/render.rb +23 -28
  14. data/lib/merb-core/controller/mixins/responder.rb +0 -1
  15. data/lib/merb-core/controller/template.rb +44 -20
  16. data/lib/merb-core/core_ext/kernel.rb +8 -3
  17. data/lib/merb-core/dispatch/default_exception/default_exception.rb +1 -1
  18. data/lib/merb-core/dispatch/default_exception/views/_css.html.erb +3 -1
  19. data/lib/merb-core/dispatch/default_exception/views/_javascript.html.erb +71 -67
  20. data/lib/merb-core/dispatch/default_exception/views/index.html.erb +6 -2
  21. data/lib/merb-core/dispatch/dispatcher.rb +5 -9
  22. data/lib/merb-core/dispatch/request.rb +46 -57
  23. data/lib/merb-core/dispatch/router.rb +83 -6
  24. data/lib/merb-core/dispatch/router/behavior.rb +87 -27
  25. data/lib/merb-core/dispatch/router/resources.rb +281 -167
  26. data/lib/merb-core/dispatch/router/route.rb +141 -27
  27. data/lib/merb-core/logger.rb +213 -202
  28. data/lib/merb-core/rack.rb +3 -1
  29. data/lib/merb-core/rack/adapter.rb +7 -4
  30. data/lib/merb-core/rack/adapter/ebb.rb +12 -13
  31. data/lib/merb-core/rack/adapter/evented_mongrel.rb +2 -15
  32. data/lib/merb-core/rack/adapter/irb.rb +3 -2
  33. data/lib/merb-core/rack/adapter/mongrel.rb +22 -15
  34. data/lib/merb-core/rack/adapter/swiftiplied_mongrel.rb +4 -16
  35. data/lib/merb-core/rack/adapter/thin.rb +21 -22
  36. data/lib/merb-core/rack/adapter/thin_turbo.rb +4 -11
  37. data/lib/merb-core/rack/adapter/webrick.rb +54 -18
  38. data/lib/merb-core/rack/handler/mongrel.rb +12 -13
  39. data/lib/merb-core/rack/middleware/csrf.rb +1 -1
  40. data/lib/merb-core/server.rb +135 -98
  41. data/lib/merb-core/tasks/gem_management.rb +50 -12
  42. data/lib/merb-core/tasks/merb.rb +1 -0
  43. data/lib/merb-core/tasks/merb_rake_helper.rb +9 -38
  44. data/lib/merb-core/tasks/stats.rake +2 -2
  45. data/lib/merb-core/test.rb +9 -3
  46. data/lib/merb-core/test/helpers.rb +1 -0
  47. data/lib/merb-core/test/helpers/multipart_request_helper.rb +3 -2
  48. data/lib/merb-core/test/helpers/request_helper.rb +40 -372
  49. data/lib/merb-core/test/helpers/route_helper.rb +15 -7
  50. data/lib/merb-core/test/matchers.rb +1 -0
  51. data/lib/merb-core/test/matchers/controller_matchers.rb +4 -247
  52. data/lib/merb-core/test/matchers/view_matchers.rb +22 -4
  53. data/lib/merb-core/test/run_specs.rb +117 -25
  54. data/lib/merb-core/version.rb +1 -1
  55. metadata +1 -1
  56. data/lib/merb-core/vendor/facets.rb +0 -2
  57. data/lib/merb-core/vendor/facets/dictionary.rb +0 -433
  58. data/lib/merb-core/vendor/facets/inflect.rb +0 -342
@@ -1,6 +1,9 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+
1
4
  <html>
2
5
  <head>
3
- <meta http-equiv="Content-type" content="text/html; charset=utf-8">
6
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
4
7
  <title><%= humanize_exception(@exceptions.first) %></title>
5
8
  <%= partial :css %>
6
9
  </head>
@@ -51,7 +54,7 @@
51
54
  </h1>
52
55
  <%= error_codes(exception) %>
53
56
  <p class="options">
54
- <label class="all">All<input type="checkbox" autocomplete="off"></label>
57
+ <label class="all">All<input type="checkbox" autocomplete="off" /></label>
55
58
  <span class="all">
56
59
  <label class="app">App<input type="checkbox" checked="checked" autocomplete="off"/></label>
57
60
  <label class="framework">Framework<input type="checkbox" autocomplete="off"/></label>
@@ -84,6 +87,7 @@
84
87
  <% end %>
85
88
  </table>
86
89
  <% end %>
90
+ </div>
87
91
  <div class="footer">
88
92
  lots of love, from <a href="http://www.merbivore.com">merb</a>
89
93
  </div>
@@ -83,18 +83,14 @@ module Merb
83
83
  # ==== Returns
84
84
  # Merb::Controller::
85
85
  # Merb::Controller set with redirect headers and a 301/302 status
86
- def redirect(url = nil, opts = {})
87
- controller = Merb::Controller.new(self)
88
-
89
- unless url
90
- status, url = redirect_status, redirect_url
91
- end
92
-
86
+ def redirect
87
+ status, url = redirect_status, redirect_url
88
+ controller = Merb::Controller.new(self, status)
89
+
93
90
  Merb.logger.info("Dispatcher redirecting to: #{url} (#{status})")
94
91
  Merb.logger.flush
95
92
 
96
- controller.redirect(url, opts)
97
- controller.status = status if status
93
+ controller.headers['Location'] = url
98
94
  controller.body = "<html><body>You are being <a href=\"#{url}\">redirected</a>.</body></html>"
99
95
  controller
100
96
  end
@@ -97,6 +97,48 @@ module Merb
97
97
  @route, @route_params = Merb::Router.route_for(self)
98
98
  params.merge! @route_params
99
99
  end
100
+
101
+ # Processes the return value of a deferred router block
102
+ # and returns the current route params for the current
103
+ # request evaluation
104
+ # ---
105
+ # @private
106
+ def _process_block_return(retval)
107
+ # If the return value is an array, then it is a redirect
108
+ # so we must set the request as a redirect and extract
109
+ # the redirect params and return it as a hash so that the
110
+ # dispatcher can handle it
111
+ if retval.is_a?(Array)
112
+ redirects!
113
+ return { :url => retval[0], :status => retval[1] }
114
+ end
115
+ retval
116
+ end
117
+
118
+ # Sets the request as a redirect. This method is only really
119
+ # used in the router to tell the request object how to handle
120
+ # the route params. This will also set the request as matched.
121
+ # ---
122
+ # @private
123
+ def redirects!
124
+ @matched = true
125
+ @redirects = true
126
+ end
127
+
128
+ # Sets the request as matched. This will abort evaluating any
129
+ # further deferred procs.
130
+ # ---
131
+ # @private
132
+ def matched!
133
+ @matched = true
134
+ end
135
+
136
+ # Checks whether or not the request has been matched to a route.
137
+ # ---
138
+ # @private
139
+ def matched?
140
+ @matched
141
+ end
100
142
 
101
143
  # Redirect status of route matched this request.
102
144
  #
@@ -104,7 +146,7 @@ module Merb
104
146
  # Integer::
105
147
  # The URL to redirect to if the route redirects
106
148
  def redirect_status
107
- route.redirect_status
149
+ @route_params[:status] if redirects?
108
150
  end
109
151
 
110
152
  # Returns redirect url of route matched this request.
@@ -112,7 +154,7 @@ module Merb
112
154
  # ==== Returns
113
155
  # <String>:: redirect url of route matched this request
114
156
  def redirect_url
115
- route.redirect_url
157
+ @route_params[:url] if redirects?
116
158
  end
117
159
 
118
160
  # Returns true if matched route does immediate redirection.
@@ -120,7 +162,7 @@ module Merb
120
162
  # ==== Returns
121
163
  # <Boolean>:: if matched route does immediate redirection.
122
164
  def redirects?
123
- route.redirects?
165
+ @redirects
124
166
  end
125
167
 
126
168
  private
@@ -269,59 +311,6 @@ module Merb
269
311
  return @env[Merb::Const::REMOTE_ADDR]
270
312
  end
271
313
 
272
- # ==== Parameters
273
- # name<~to_sym, Hash>:: The name of the URL to generate.
274
- # rparams<Hash>:: Parameters for the route generation.
275
- #
276
- # ==== Returns
277
- # String:: The generated URL.
278
- #
279
- # ==== Alternatives
280
- # If a hash is used as the first argument, a default route will be
281
- # generated based on it and rparams.
282
- # ====
283
- # TODO: Update this documentation
284
- def generate_url(name, *args)
285
- unless Symbol === name
286
- args.unshift(name)
287
- name = :default
288
- end
289
-
290
- unless route = Merb::Router.named_routes[name]
291
- raise Merb::Router::GenerationError, "Named route not found: #{name}"
292
- end
293
-
294
- route.generate(args, params)
295
- end
296
-
297
-
298
- # ==== Parameters
299
- # name<~to_sym, Hash>:: The name of the URL to generate.
300
- # rparams<Hash>:: Parameters for the route generation.
301
- #
302
- # ==== Returns
303
- # String:: The generated url with protocol + hostname + URL.
304
- #
305
- # ==== Options
306
- #
307
- # :protocol and :host options are special: use them to explicitly
308
- # specify protocol and host of resulting url. If you omit them,
309
- # protocol and host of request are used.
310
- #
311
- # ==== Alternatives
312
- # If a hash is used as the first argument, a default route will be
313
- # generated based on it and rparams.
314
- def generate_absolute_url(name, rparams={})
315
- if rparams.is_a?(Hash)
316
- tprotocol = rparams.delete(:protocol)
317
- thost = rparams.delete(:host)
318
- end
319
-
320
- (tprotocol || protocol) + "://" +
321
- (thost || host) +
322
- generate_url(name, rparams)
323
- end
324
-
325
314
  # ==== Returns
326
315
  # String::
327
316
  # The protocol, i.e. either "https" or "http" depending on the
@@ -345,7 +334,7 @@ module Merb
345
334
  # ==== Returns
346
335
  # String:: The full URI, including protocol and host
347
336
  def full_uri
348
- protocol + host + uri
337
+ protocol + "://" + host + uri
349
338
  end
350
339
 
351
340
  # ==== Returns
@@ -21,10 +21,11 @@ module Merb
21
21
  #
22
22
  # Compilation is synchronized by mutex.
23
23
  class Router
24
- @routes = []
25
- @named_routes = {}
26
- @compiler_mutex = Mutex.new
27
- @root_behavior = Behavior.new.defaults(:action => "index")
24
+ @routes = []
25
+ @named_routes = {}
26
+ @resource_routes = {}
27
+ @compiler_mutex = Mutex.new
28
+ @root_behavior = Behavior.new.defaults(:action => "index")
28
29
 
29
30
  # Raised when route lookup fails.
30
31
  class RouteNotFound < StandardError; end;
@@ -35,7 +36,7 @@ module Merb
35
36
 
36
37
  class << self
37
38
  # @private
38
- attr_accessor :routes, :named_routes, :root_behavior
39
+ attr_accessor :routes, :named_routes, :resource_routes, :root_behavior
39
40
 
40
41
  # Creates a route building context and evaluates the block in it. A
41
42
  # copy of +root_behavior+ (and instance of Behavior) is copied as
@@ -55,7 +56,7 @@ module Merb
55
56
  # Returns self to allow chaining of methods.
56
57
  def prepare(first = [], last = [], &block)
57
58
  @routes = []
58
- root_behavior.with_proxy(&block)
59
+ root_behavior._with_proxy(&block)
59
60
  @routes = first + @routes + last
60
61
  compile
61
62
  self
@@ -111,6 +112,82 @@ module Merb
111
112
  end
112
113
 
113
114
  alias_method :match, :match_before_compilation
115
+
116
+ # Generates a URL from the params
117
+ #
118
+ # ==== Parameters
119
+ # name<Symbol>::
120
+ # The name of the route to generate
121
+ #
122
+ # anonymous_params<Object>::
123
+ # An array of anonymous parameters to generate the route
124
+ # with. These parameters are assigned to the route parameters
125
+ # in the order that they are passed.
126
+ #
127
+ # params<Hash>::
128
+ # Named parameters to generate the route with.
129
+ #
130
+ # defaults<Hash>::
131
+ # A hash of default parameters to generate the route with.
132
+ # This is usually the request parameters. If there are any
133
+ # required params that are missing to generate the route,
134
+ # they are pulled from this hash.
135
+ # ==== Returns
136
+ # String:: The generated URL
137
+ # ---
138
+ # @private
139
+ def url(name, *args)
140
+ unless name.is_a?(Symbol)
141
+ args.unshift(name)
142
+ name = :default
143
+ end
144
+
145
+ unless route = Merb::Router.named_routes[name]
146
+ raise Merb::Router::GenerationError, "Named route not found: #{name}"
147
+ end
148
+
149
+ defaults = args.pop
150
+
151
+ route.generate(args, defaults)
152
+ end
153
+
154
+ # Generates a URL from the resource(s)
155
+ #
156
+ # ==== Parameters
157
+ # resources<Symbol,Object>::
158
+ # The identifiers for the resource route to generate. These
159
+ # can either be symbols or objects. Symbols denote resource
160
+ # collection routes and objects denote the members.
161
+ #
162
+ # params<Hash>::
163
+ # Any extra parameters needed to generate the route.
164
+ # ==== Returns
165
+ # String:: The generated URL
166
+ # ---
167
+ # @private
168
+ def resource(*args)
169
+ defaults = args.pop
170
+ options = extract_options_from_args!(args) || {}
171
+ key = []
172
+ params = []
173
+
174
+ args.each do |arg|
175
+ if arg.is_a?(Symbol) || arg.is_a?(String)
176
+ key << arg.to_s
177
+ else
178
+ key << arg.class.to_s
179
+ params << arg
180
+ end
181
+ end
182
+
183
+ params << options
184
+
185
+ unless route = Merb::Router.resource_routes[key]
186
+ raise Merb::Router::GenerationError, "Resource route not found: #{args.inspect}"
187
+ end
188
+
189
+ route.generate(params, defaults)
190
+ end
114
191
 
115
192
  private
116
193
 
@@ -28,12 +28,19 @@ module Merb
28
28
  @behaviors.pop
29
29
  end
30
30
 
31
+ def respond_to?(*args)
32
+ super || @behaviors.last.respond_to?(*args)
33
+ end
34
+
31
35
  # Rake does some stuff with methods in the global namespace, so if I don't
32
36
  # explicitly define the Behavior methods to proxy here (specifically namespace)
33
37
  # Rake's methods take precedence.
38
+ # ---
39
+ # Removing the following:
40
+ # name full_name fixatable redirect
34
41
  %w(
35
42
  match to with register default defaults options option namespace identify
36
- default_routes defer_to name full_name fixatable redirect capture
43
+ default_routes defer defer_to capture resources resource
37
44
  ).each do |method|
38
45
  class_eval %{
39
46
  def #{method}(*args, &block)
@@ -42,8 +49,21 @@ module Merb
42
49
  }
43
50
  end
44
51
 
45
- def respond_to?(*args)
46
- super || @behaviors.last.respond_to?(*args)
52
+ # --- These methods are to be used in defer_to blocks
53
+
54
+ # Generates a URL from the passed arguments. This method is for use
55
+ # inside of defer_to
56
+ def url(name, *args)
57
+ args << {}
58
+ Merb::Router.url(name, *args)
59
+ end
60
+
61
+ def redirect(url, opts = {})
62
+ [url, opts[:permanent] ? 301 : 302]
63
+ end
64
+
65
+ def route(params)
66
+ params
47
67
  end
48
68
 
49
69
  private
@@ -78,18 +98,21 @@ module Merb
78
98
  # The initial route default parameters. See #defaults.
79
99
  # options<Hash>::
80
100
  # The initial route options. See #options.
101
+ # blocks<Array>::
102
+ # The stack of deferred routing blocks for the route
81
103
  #
82
104
  # ==== Returns
83
105
  # Behavior:: The initialized Behavior object
84
106
  #---
85
107
  # @private
86
- def initialize(proxy = nil, conditions = {}, params = {}, defaults = {}, identifiers = {}, options = {}) #:nodoc:
108
+ def initialize(proxy = nil, conditions = {}, params = {}, defaults = {}, identifiers = {}, options = {}, blocks = []) #:nodoc:
87
109
  @proxy = proxy
88
110
  @conditions = conditions
89
111
  @params = params
90
112
  @defaults = defaults
91
113
  @identifiers = identifiers
92
114
  @options = options
115
+ @blocks = blocks
93
116
 
94
117
  stringify_condition_values
95
118
  end
@@ -174,12 +197,15 @@ module Merb
174
197
  #---
175
198
  # @public
176
199
  def match(path = {}, conditions = {}, &block)
177
- path, conditions = path[:path], path if Hash === path
178
- conditions[:path] = merge_paths(path)
200
+ path, conditions = path[:path], path if path.is_a?(Hash)
179
201
 
180
202
  raise Error, "The route has already been committed. Further conditions cannot be specified" if @route
203
+
204
+
205
+ conditions.delete_if { |k, v| v.nil? }
206
+ conditions[:path] = merge_paths(path)
181
207
 
182
- behavior = Behavior.new(@proxy, @conditions.merge(conditions), @params, @defaults, @identifiers, @options)
208
+ behavior = Behavior.new(@proxy, @conditions.merge(conditions), @params, @defaults, @identifiers, @options, @blocks)
183
209
  with_behavior_context(behavior, &block)
184
210
  end
185
211
 
@@ -211,7 +237,7 @@ module Merb
211
237
  def to(params = {}, &block)
212
238
  raise Error, "The route has already been committed. Further params cannot be specified" if @route
213
239
 
214
- behavior = Behavior.new(@proxy, @conditions, @params.merge(params), @defaults, @identifiers, @options)
240
+ behavior = Behavior.new(@proxy, @conditions, @params.merge(params), @defaults, @identifiers, @options, @blocks)
215
241
 
216
242
  if block_given?
217
243
  with_behavior_context(behavior, &block)
@@ -256,7 +282,7 @@ module Merb
256
282
  # ---
257
283
  # @public
258
284
  def default(defaults = {}, &block)
259
- behavior = Behavior.new(@proxy, @conditions, @params, @defaults.merge(defaults), @identifiers, @options)
285
+ behavior = Behavior.new(@proxy, @conditions, @params, @defaults.merge(defaults), @identifiers, @options, @blocks)
260
286
  with_behavior_context(behavior, &block)
261
287
  end
262
288
 
@@ -291,7 +317,7 @@ module Merb
291
317
  options[key] = (options[key] || []) + [value.freeze] if value
292
318
  end
293
319
 
294
- behavior = Behavior.new(@proxy, @conditions, @params, @defaults, @identifiers, options)
320
+ behavior = Behavior.new(@proxy, @conditions, @params, @defaults, @identifiers, options, @blocks)
295
321
  with_behavior_context(behavior, &block)
296
322
  end
297
323
 
@@ -335,6 +361,7 @@ module Merb
335
361
  # option keys could be nil
336
362
  opts[:controller_prefix] = name unless opts.has_key?(:controller_prefix)
337
363
  opts[:name_prefix] = name unless opts.has_key?(:name_prefix)
364
+ opts[:resource_prefix] = opts[:name_prefix] unless opts.has_key?(:resource_prefix)
338
365
 
339
366
  behavior = self
340
367
  behavior = behavior.match("/#{path}") unless path.nil? || path.empty?
@@ -368,7 +395,7 @@ module Merb
368
395
  { Object => identifiers }
369
396
  end
370
397
 
371
- behavior = Behavior.new(@proxy, @conditions, @params, @defaults, identifiers.freeze, @options)
398
+ behavior = Behavior.new(@proxy, @conditions, @params, @defaults, identifiers.freeze, @options, @blocks)
372
399
  with_behavior_context(behavior, &block)
373
400
  end
374
401
 
@@ -418,14 +445,23 @@ module Merb
418
445
  # Route :: The default route.
419
446
  #
420
447
  # ==== Examples
421
- # r.defer_to do |request, params|
448
+ # defer_to do |request, params|
422
449
  # params.merge :controller => 'here',
423
450
  # :action => 'there' if request.xhr?
424
451
  # end
425
452
  #---
426
453
  # @public
427
- def defer_to(params = {}, &conditional_block)
428
- to_route(params, &conditional_block)
454
+ def defer_to(params = {}, &block)
455
+ defer(block).to(params)
456
+ end
457
+
458
+ # Takes a Proc as a parameter and applies it as a deferred proc for all the
459
+ # routes defined in the block. This is mostly interesting for plugin
460
+ # developers.
461
+ def defer(deferred_block, &block)
462
+ blocks = @blocks + [CachedProc.new(deferred_block)]
463
+ behavior = Behavior.new(@proxy, @conditions, @params, @defaults, @identifiers, @options, blocks)
464
+ with_behavior_context(behavior, &block)
429
465
  end
430
466
 
431
467
  # Names this route in Router. Name must be a Symbol.
@@ -467,11 +503,22 @@ module Merb
467
503
  self
468
504
  end
469
505
 
470
- def redirect(url, permanent = true)
506
+ # Sets the current route as a redirect.
507
+ #
508
+ # ==== Parameters
509
+ # path<String::
510
+ # The path to redirect to
511
+ #
512
+ # options<Hash>::
513
+ # Options for the redirect
514
+ # The supported options are:
515
+ # * :permanent: Whether or not the redirect should be permanent.
516
+ # The default value is false.
517
+ def redirect(url, opts = {})
471
518
  raise Error, "The route has already been committed." if @route
472
519
 
473
- status = permanent ? 301 : 302
474
- @route = Route.new(@conditions, {:url => url.freeze, :status => status.freeze}, :redirects => true)
520
+ status = opts[:permanent] ? 301 : 302
521
+ @route = Route.new(@conditions, {:url => url.freeze, :status => status.freeze}, @blocks, :redirects => true)
475
522
  @route.register
476
523
  self
477
524
  end
@@ -487,7 +534,7 @@ module Merb
487
534
  name_prefix = [@options[:name_prefix]].flatten.compact.map { |p| "#{p}_"}
488
535
  current_names = Merb::Router.named_routes.keys
489
536
 
490
- behavior = Behavior.new(@proxy, @conditions, @params, @defaults, @identifiers, @options)
537
+ behavior = Behavior.new(@proxy, @conditions, @params, @defaults, @identifiers, @options, @blocks)
491
538
  with_behavior_context(behavior, &block)
492
539
 
493
540
  Merb::Router.named_routes.reject { |k,v| current_names.include?(k) }.each do |name, route|
@@ -501,21 +548,23 @@ module Merb
501
548
  # So that Router can have a default route
502
549
  # ---
503
550
  # @private
504
- def with_proxy(&block) #:nodoc:
551
+ def _with_proxy(&block) #:nodoc:
505
552
  proxy = Proxy.new
506
- proxy.push Behavior.new(proxy, @conditions, @params, @defaults, @identifiers, @options)
553
+ proxy.push Behavior.new(proxy, @conditions, @params, @defaults, @identifiers, @options, @blocks)
507
554
  proxy.instance_eval(&block)
508
555
  proxy
509
556
  end
510
557
 
511
558
  protected
559
+
560
+ def _route
561
+ @route
562
+ end
512
563
 
513
- def to_route(params = {}, &conditional_block) # :nodoc:
514
-
564
+ def to_route # :nodoc:
515
565
  raise Error, "The route has already been committed." if @route
516
566
 
517
- params = @params.merge(params)
518
- controller = params[:controller]
567
+ controller = @params[:controller]
519
568
 
520
569
  if prefixes = @options[:controller_prefix]
521
570
  controller ||= ":controller"
@@ -526,17 +575,28 @@ module Merb
526
575
  end
527
576
  end
528
577
 
529
- params.merge!(:controller => controller.to_s.gsub(%r{^/}, '')) if controller
578
+ @params.merge!(:controller => controller.to_s.gsub(%r{^/}, '')) if controller
530
579
 
531
580
  # Sorts the identifiers so that modules that are at the bottom of the
532
581
  # inheritance chain come first (more specific modules first). Object
533
582
  # should always be last.
534
583
  identifiers = @identifiers.sort { |(first,_),(sec,_)| first <=> sec || 1 }
535
584
 
536
- @route = Route.new(@conditions.dup, params, :defaults => @defaults.dup, :identifiers => identifiers, &conditional_block)
537
- @route.register
585
+ @route = Route.new(@conditions.dup,@params, @blocks, :defaults => @defaults.dup, :identifiers => identifiers)
586
+
587
+ if before = @options[:before] && @options[:before].last
588
+ @route.register_at(Router.routes.index(before))
589
+ else
590
+ @route.register
591
+ end
538
592
  self
539
593
  end
594
+
595
+ # Allows to insert the route at a certain spot in the list of routes
596
+ # instead of appending to the list.
597
+ def before(route, &block) #:nodoc:
598
+ options(:before => route, &block)
599
+ end
540
600
 
541
601
  private
542
602