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 (57) hide show
  1. data/CONTRIBUTORS +33 -0
  2. data/README +7 -3
  3. data/Rakefile +3 -3
  4. data/lib/merb-core.rb +165 -94
  5. data/lib/merb-core/bootloader.rb +469 -100
  6. data/lib/merb-core/config.rb +79 -3
  7. data/lib/merb-core/constants.rb +24 -2
  8. data/lib/merb-core/controller/abstract_controller.rb +172 -67
  9. data/lib/merb-core/controller/exceptions.rb +50 -6
  10. data/lib/merb-core/controller/merb_controller.rb +215 -108
  11. data/lib/merb-core/controller/mime.rb +36 -12
  12. data/lib/merb-core/controller/mixins/authentication.rb +52 -7
  13. data/lib/merb-core/controller/mixins/conditional_get.rb +14 -0
  14. data/lib/merb-core/controller/mixins/controller.rb +90 -58
  15. data/lib/merb-core/controller/mixins/render.rb +34 -10
  16. data/lib/merb-core/controller/mixins/responder.rb +40 -16
  17. data/lib/merb-core/controller/template.rb +37 -16
  18. data/lib/merb-core/core_ext/hash.rb +9 -0
  19. data/lib/merb-core/core_ext/kernel.rb +92 -41
  20. data/lib/merb-core/dispatch/dispatcher.rb +29 -45
  21. data/lib/merb-core/dispatch/request.rb +186 -82
  22. data/lib/merb-core/dispatch/router.rb +141 -53
  23. data/lib/merb-core/dispatch/router/behavior.rb +296 -139
  24. data/lib/merb-core/dispatch/router/resources.rb +51 -19
  25. data/lib/merb-core/dispatch/router/route.rb +76 -23
  26. data/lib/merb-core/dispatch/session.rb +80 -36
  27. data/lib/merb-core/dispatch/session/container.rb +31 -15
  28. data/lib/merb-core/dispatch/session/cookie.rb +51 -22
  29. data/lib/merb-core/dispatch/session/memcached.rb +10 -6
  30. data/lib/merb-core/dispatch/session/memory.rb +17 -5
  31. data/lib/merb-core/dispatch/session/store_container.rb +21 -9
  32. data/lib/merb-core/dispatch/worker.rb +16 -2
  33. data/lib/merb-core/gem_ext/erubis.rb +4 -0
  34. data/lib/merb-core/plugins.rb +13 -0
  35. data/lib/merb-core/rack.rb +1 -0
  36. data/lib/merb-core/rack/adapter.rb +1 -0
  37. data/lib/merb-core/rack/adapter/abstract.rb +95 -17
  38. data/lib/merb-core/rack/adapter/irb.rb +50 -5
  39. data/lib/merb-core/rack/application.rb +27 -5
  40. data/lib/merb-core/rack/handler/mongrel.rb +6 -6
  41. data/lib/merb-core/rack/helpers.rb +33 -0
  42. data/lib/merb-core/rack/middleware/conditional_get.rb +1 -1
  43. data/lib/merb-core/rack/middleware/path_prefix.rb +3 -3
  44. data/lib/merb-core/rack/middleware/static.rb +11 -7
  45. data/lib/merb-core/server.rb +134 -69
  46. data/lib/merb-core/tasks/gem_management.rb +153 -80
  47. data/lib/merb-core/tasks/merb_rake_helper.rb +12 -4
  48. data/lib/merb-core/tasks/stats.rake +1 -1
  49. data/lib/merb-core/test/helpers/mock_request_helper.rb +29 -22
  50. data/lib/merb-core/test/helpers/request_helper.rb +1 -1
  51. data/lib/merb-core/test/helpers/route_helper.rb +50 -4
  52. data/lib/merb-core/test/matchers/request_matchers.rb +2 -36
  53. data/lib/merb-core/test/matchers/view_matchers.rb +32 -22
  54. data/lib/merb-core/test/run_specs.rb +6 -5
  55. data/lib/merb-core/test/test_ext/rspec.rb +6 -19
  56. data/lib/merb-core/version.rb +1 -1
  57. metadata +5 -4
@@ -6,21 +6,26 @@ module Merb
6
6
 
7
7
  class << self
8
8
 
9
+ # Returns the hash of default config values for Merb.
10
+ #
9
11
  # ==== Returns
10
12
  # Hash:: The defaults for the config.
13
+ #
14
+ # @api private
11
15
  def defaults
12
16
  @defaults ||= {
13
17
  :host => "0.0.0.0",
14
18
  :port => "4000",
15
19
  :adapter => "runner",
16
20
  :reload_classes => true,
17
- :fork_for_class_load => !RUBY_PLATFORM.in?("windows", "java"),
21
+ :fork_for_class_load => !(RUBY_PLATFORM =~ /(:?mswin|mingw|java)/),
18
22
  :environment => "development",
19
23
  :merb_root => Dir.pwd,
20
24
  :use_mutex => true,
21
25
  :log_delimiter => " ~ ",
22
26
  :log_auto_flush => false,
23
27
  :log_level => :info,
28
+ :log_stream => STDOUT,
24
29
  :disabled_components => [],
25
30
  :deferred_actions => [],
26
31
  :verbose => false,
@@ -36,30 +41,47 @@ module Merb
36
41
  # ==== Examples
37
42
  # Merb::Config.use do |config|
38
43
  # config[:exception_details] = false
44
+ # config[:log_stream] = STDOUT
39
45
  # end
46
+ #
47
+ # ==== Returns
48
+ # nil
49
+ #
50
+ # @api public
40
51
  def use
41
52
  @configuration ||= {}
42
53
  yield @configuration
54
+ nil
43
55
  end
44
-
56
+
57
+ # Detects whether the provided key is in the config.
58
+ #
45
59
  # ==== Parameters
46
60
  # key<Object>:: The key to check.
47
61
  #
48
62
  # ==== Returns
49
63
  # Boolean:: True if the key exists in the config.
64
+ #
65
+ # @api public
50
66
  def key?(key)
51
67
  @configuration.key?(key)
52
68
  end
53
69
 
70
+ # Retrieve the value of a config entry.
71
+ #
54
72
  # ==== Parameters
55
73
  # key<Object>:: The key to retrieve the parameter for.
56
74
  #
57
75
  # ==== Returns
58
76
  # Object:: The value of the configuration parameter.
77
+ #
78
+ # @api public
59
79
  def [](key)
60
80
  (@configuration ||= setup)[key]
61
81
  end
62
82
 
83
+ # Set the value of a config entry.
84
+ #
63
85
  # ==== Parameters
64
86
  # key<Object>:: The key to set the parameter for.
65
87
  # val<Object>:: The value of the parameter.
@@ -67,12 +89,21 @@ module Merb
67
89
  (@configuration ||= setup)[key] = val
68
90
  end
69
91
 
92
+ # Remove the value of a config entry.
93
+ #
70
94
  # ==== Parameters
71
95
  # key<Object>:: The key of the parameter to delete.
96
+ #
97
+ # ==== Returns
98
+ # Object:: The value of the removed entry.
99
+ #
100
+ # @api public
72
101
  def delete(key)
73
102
  @configuration.delete(key)
74
103
  end
75
104
 
105
+ # Retrieve the value of a config entry, returning the provided default if the key is not present
106
+ #
76
107
  # ==== Parameters
77
108
  # key<Object>:: The key to retrieve the parameter for.
78
109
  # default<Object>::
@@ -84,14 +115,22 @@ module Merb
84
115
  @configuration.fetch(key, default)
85
116
  end
86
117
 
118
+ # Returns the configuration as a hash.
119
+ #
87
120
  # ==== Returns
88
121
  # Hash:: The config as a hash.
122
+ #
123
+ # @api public
89
124
  def to_hash
90
125
  @configuration
91
126
  end
92
127
 
128
+ # Returns the config as YAML.
129
+ #
93
130
  # ==== Returns
94
131
  # String:: The config as YAML.
132
+ #
133
+ # @api public
95
134
  def to_yaml
96
135
  require "yaml"
97
136
  @configuration.to_yaml
@@ -102,6 +141,11 @@ module Merb
102
141
  # ==== Parameters
103
142
  # settings<Hash>::
104
143
  # Configuration settings to use. These are merged with the defaults.
144
+ #
145
+ # ==== Returns
146
+ # The configuration as a hash.
147
+ #
148
+ # @api private
105
149
  def setup(settings = {})
106
150
  @configuration = defaults.merge(settings)
107
151
 
@@ -116,6 +160,11 @@ module Merb
116
160
  #
117
161
  # ==== Parameters
118
162
  # argv<String>:: The command line arguments. Defaults to +ARGV+.
163
+ #
164
+ # ==== Returns
165
+ # The configuration as a hash.
166
+ #
167
+ # @api private
119
168
  def parse_args(argv = ARGV)
120
169
  @configuration ||= {}
121
170
  # Our primary configuration hash for the length of this method
@@ -275,7 +324,7 @@ module Merb
275
324
 
276
325
  opts.on("-k", "--kill PORT", "Force kill one merb worker " \
277
326
  "by port number. This will cause the worker to" \
278
- "be respawned. If you want to kill ") do |port|
327
+ "be respawned.") do |port|
279
328
  options[:action] = :kill_9
280
329
  port = "main" if port == "all"
281
330
  options[:port] = port
@@ -348,9 +397,16 @@ module Merb
348
397
  # Merb::Config.configure do
349
398
  # environment "development"
350
399
  # log_level "debug"
400
+ # log_file Merb.root / "log" / "special.log"
351
401
  # end
402
+ #
403
+ # ==== Returns
404
+ # nil
405
+ #
406
+ # @api public
352
407
  def configure(&block)
353
408
  ConfigBlock.new(self, &block) if block_given?
409
+ nil
354
410
  end
355
411
 
356
412
  # Allows retrieval of single key config values via Merb.config.<key>
@@ -359,6 +415,11 @@ module Merb
359
415
  # ==== Parameters
360
416
  # method<~to_s>:: Method name as hash key value.
361
417
  # *args:: Value to set the configuration parameter to.
418
+ #
419
+ # ==== Returns
420
+ # The value of the entry fetched or assigned to.
421
+ #
422
+ # @api public
362
423
  def method_missing(method, *args)
363
424
  if method.to_s[-1,1] == '='
364
425
  @configuration[method.to_s.tr('=','').to_sym] = *args
@@ -371,11 +432,26 @@ module Merb
371
432
 
372
433
  class ConfigBlock
373
434
 
435
+ # Evaluates the provided block, where any call to a method causes
436
+ # #[]= to be called on klass with the method name as the key and the arguments
437
+ # as the value.
438
+ #
439
+ # ==== Parameters
440
+ # klass<Object~[]=>:: The object on which to assign values.
441
+ # &block:: The block which specifies the config values to set.
442
+ #
443
+ # ==== Returns
444
+ # nil
445
+ #
446
+ # @api private
374
447
  def initialize(klass, &block)
375
448
  @klass = klass
376
449
  instance_eval(&block)
377
450
  end
378
451
 
452
+ # Assign args as the value of the entry keyed by method.
453
+ #
454
+ # @api private
379
455
  def method_missing(method, *args)
380
456
  @klass[method] = *args
381
457
  end
@@ -1,6 +1,19 @@
1
1
  # Most of this list is simply constants frozen for efficiency
2
+ # and lowered memory consumption. Every time Ruby VM comes
3
+ # across a string or a number or a regexp literal,
4
+ # new object is created.
5
+ #
6
+ # This means if you refer to the same string 6 times per request
7
+ # and your application takes 100 requests per second, there are
8
+ # 600 objects for weak MRI garbage collector to work on.
9
+ #
10
+ # GC cycles take up to 80% (!) time of request processing in
11
+ # some cases. Eventually Rubinius and maybe MRI 2.0 gonna
12
+ # improve this situation but at the moment, all commonly used
13
+ # strings, regexp and numbers used as constants so no extra
14
+ # objects created and VM just operate pointers.
2
15
  module Merb
3
- module Const
16
+ module Const
4
17
 
5
18
  DEFAULT_SEND_FILE_OPTIONS = {
6
19
  :type => 'application/octet-stream'.freeze,
@@ -27,7 +40,6 @@ module Merb
27
40
  ETAG = 'ETag'.freeze
28
41
  LAST_MODIFIED = "Last-Modified".freeze
29
42
  SLASH = "/".freeze
30
- REQUEST_METHOD = "REQUEST_METHOD".freeze
31
43
  GET = "GET".freeze
32
44
  POST = "POST".freeze
33
45
  HEAD = "HEAD".freeze
@@ -35,11 +47,21 @@ module Merb
35
47
  HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR".freeze
36
48
  HTTP_IF_MODIFIED_SINCE = "HTTP_IF_MODIFIED_SINCE".freeze
37
49
  HTTP_IF_NONE_MATCH = "HTTP_IF_NONE_MATCH".freeze
50
+ HTTP_CONTENT_TYPE = "HTTP_CONTENT_TYPE".freeze
51
+ HTTP_CONTENT_LENGTH = "HTTP_CONTENT_LENGTH".freeze
38
52
  UPLOAD_ID = "upload_id".freeze
39
53
  PATH_INFO = "PATH_INFO".freeze
40
54
  SCRIPT_NAME = "SCRIPT_NAME".freeze
41
55
  REQUEST_URI = "REQUEST_URI".freeze
42
56
  REQUEST_PATH = "REQUEST_PATH".freeze
57
+ REQUEST_METHOD = "REQUEST_METHOD".freeze
43
58
  REMOTE_ADDR = "REMOTE_ADDR".freeze
59
+ BREAK_TAG = "<br/>".freeze
60
+ EMPTY_STRING = "".freeze
61
+ NEWLINE = "\n".freeze
62
+ DOUBLE_NEWLINE = "\n\n".freeze
63
+ LOCATION = "Location".freeze
64
+ TEXT_SLASH_HTML = "text/html".freeze
65
+
44
66
  end
45
67
  end
@@ -103,7 +103,7 @@ class Merb::AbstractController
103
103
  cattr_accessor :_abstract_subclasses
104
104
 
105
105
  #---
106
- # @semipublic
106
+ # @api semipublic
107
107
  attr_accessor :body
108
108
  attr_accessor :action_name
109
109
  attr_accessor :_benchmarks, :_thrown_content
@@ -124,12 +124,13 @@ class Merb::AbstractController
124
124
 
125
125
  # ==== Returns
126
126
  # String:: The controller name in path form, e.g. "admin/items".
127
- #---
128
- # @public
127
+ # @api public
129
128
  def self.controller_name() @controller_name ||= self.name.to_const_path end
130
129
 
131
130
  # ==== Returns
132
131
  # String:: The controller name in path form, e.g. "admin/items".
132
+ #
133
+ # @api public
133
134
  def controller_name() self.class.controller_name end
134
135
 
135
136
  # This is called after the controller is instantiated to figure out where to
@@ -138,9 +139,9 @@ class Merb::AbstractController
138
139
  #
139
140
  # ==== Parameters
140
141
  # context<~to_s>:: The controller context (the action or template name).
141
- # type<~to_s>:: The content type. Defaults to nil.
142
+ # type<~to_s>:: The content type. Could be nil.
142
143
  # controller<~to_s>::
143
- # The name of the controller. Defaults to controller_name.
144
+ # The name of the controller. Defaults to being called with the controller_name. Set t
144
145
  #
145
146
  #
146
147
  # ==== Returns
@@ -160,29 +161,41 @@ class Merb::AbstractController
160
161
  #
161
162
  # This would look for templates at controller.action.mime.type instead
162
163
  # of controller/action.mime.type
163
- #---
164
- # @public
164
+ #
165
+ # @api public
166
+ # @overridable
165
167
  def _template_location(context, type, controller)
166
168
  controller ? "#{controller}/#{context}" : context
167
169
  end
168
170
 
169
- # The location to look for a template - stub method for particular behaviour.
171
+ # The location to look for a template - override this method for particular behaviour.
170
172
  #
171
173
  # ==== Parameters
172
174
  # template<String>:: The absolute path to a template - without template extension.
173
175
  # type<~to_s>::
174
- # The mime-type of the template that will be rendered. Defaults to nil.
176
+ # The mime-type of the template that will be rendered. Defaults to being called with nil.
175
177
  #
176
- # @public
178
+ # @api public
179
+ # @overridable
177
180
  def _absolute_template_location(template, type)
178
181
  template
179
182
  end
180
183
 
184
+ # Resets the template roots to the template root passed in.
185
+ #
186
+ # ==== Parameters
187
+ # root<~to_s>::
188
+ # The new path to set the template root to.
189
+ #
190
+ # @api public
181
191
  def self._template_root=(root)
182
192
  @_template_root = root
183
193
  _reset_template_roots
184
194
  end
185
195
 
196
+ # Reset the template root based on the @_template_root ivar.
197
+ #
198
+ # @api private
186
199
  def self._reset_template_roots
187
200
  self.template_roots = [[self._template_root, :_template_location]]
188
201
  end
@@ -191,6 +204,8 @@ class Merb::AbstractController
191
204
  # roots<Array[Array]>::
192
205
  # Template roots as pairs of template root path and template location
193
206
  # method.
207
+ #
208
+ # @api unknown
194
209
  def self._template_roots
195
210
  self.template_roots || _reset_template_roots
196
211
  end
@@ -199,45 +214,62 @@ class Merb::AbstractController
199
214
  # roots<Array[Array]>::
200
215
  # Template roots as pairs of template root path and template location
201
216
  # method.
217
+ #
218
+ # @api unknown
202
219
  def self._template_roots=(roots)
203
220
  self.template_roots = roots
204
221
  end
205
222
 
223
+ # Returns the list of classes that have specifically subclassed AbstractController.
224
+ # Does not include all decendents.
225
+ #
206
226
  # ==== Returns
207
227
  # Set:: The subclasses.
228
+ #
229
+ # @api private
208
230
  def self.subclasses_list() _abstract_subclasses end
209
231
 
210
- class << self
211
- # ==== Parameters
212
- # klass<Merb::AbstractController>::
213
- # The controller that is being inherited from Merb::AbstractController
214
- def inherited(klass)
215
- _abstract_subclasses << klass.to_s
216
- helper_module_name = klass.to_s =~ /^(#|Merb::)/ ? "#{klass}Helper" : "Merb::#{klass}Helper"
217
- Object.make_module helper_module_name
218
- klass.class_eval <<-HERE
219
- include Object.full_const_get("#{helper_module_name}") rescue nil
220
- HERE
221
- super
222
- end
223
- end
232
+ # ==== Parameters
233
+ # klass<Merb::AbstractController>::
234
+ # The controller that is being inherited from Merb::AbstractController
235
+ #
236
+ # @api private
237
+ def self.inherited(klass)
238
+ _abstract_subclasses << klass.to_s
239
+ helper_module_name = klass.to_s =~ /^(#|Merb::)/ ? "#{klass}Helper" : "Merb::#{klass}Helper"
240
+ Object.make_module helper_module_name
241
+ klass.class_eval <<-HERE
242
+ include Object.full_const_get("#{helper_module_name}") rescue nil
243
+ HERE
244
+ super
245
+ end
224
246
 
247
+ # This will initialize the controller, it is designed to be overridden in subclasses (like MerbController)
225
248
  # ==== Parameters
226
- # *args:: The args are ignored.
249
+ # *args:: The args are ignored in this class, but we need this so that subclassed initializes can have parameters
250
+ #
251
+ # @overridable
227
252
  def initialize(*args)
228
253
  @_benchmarks = {}
229
254
  @_caught_content = {}
230
255
  end
231
256
 
232
- # This will dispatch the request, calling internal before/after dispatch_callbacks
257
+ # This will dispatch the request, calling internal before/after dispatch callbacks.
258
+ # If the return value of _call_filters is not :filter_chain_completed the action is not called, and the return from the filters is used instead.
233
259
  #
234
260
  # ==== Parameters
235
261
  # action<~to_s>::
236
262
  # The action to dispatch to. This will be #send'ed in _call_action.
237
263
  # Defaults to :to_s.
238
264
  #
265
+ # ==== Returns
266
+ # <~to_s>::
267
+ # Returns the string that was returned from the action.
268
+ #
239
269
  # ==== Raises
240
- # MerbControllerError:: Invalid body content caught.
270
+ # ArgumentError:: Invalid result caught from before filters.
271
+ #
272
+ # @api plugin
241
273
  def _dispatch(action)
242
274
  self._before_dispatch_callbacks.each { |cb| cb.call(self) }
243
275
  self.action_name = action
@@ -252,7 +284,8 @@ class Merb::AbstractController
252
284
  @body = case caught
253
285
  when :filter_chain_completed then _call_action(action_name)
254
286
  when String then caught
255
- when nil then _filters_halted
287
+ # return *something* if you throw halt with nothing
288
+ when nil then "<html><body><h1>Filter Chain Halted!</h1></body></html>"
256
289
  when Symbol then __send__(caught)
257
290
  when Proc then self.instance_eval(&caught)
258
291
  else
@@ -267,14 +300,19 @@ class Merb::AbstractController
267
300
  @body
268
301
  end
269
302
 
270
- # This method exists to provide an overridable hook for ActionArgs
303
+ # This method exists to provide an overridable hook for ActionArgs. It uses #send to call the action method.
271
304
  #
272
305
  # ==== Parameters
273
306
  # action<~to_s>:: the action method to dispatch to
307
+ #
308
+ # @api plugin
309
+ # @overridable
274
310
  def _call_action(action)
275
311
  send(action)
276
312
  end
277
313
 
314
+ # Calls a filter chain.
315
+ #
278
316
  # ==== Parameters
279
317
  # filter_set<Array[Filter]>::
280
318
  # A set of filters in the form [[:filter, rule], [:filter, rule]]
@@ -290,6 +328,8 @@ class Merb::AbstractController
290
328
  # Procs::
291
329
  # Execute the +Proc+, in the context of the controller (self will be the
292
330
  # controller)
331
+ #
332
+ # @api private
293
333
  def _call_filters(filter_set)
294
334
  (filter_set || []).each do |filter, rule|
295
335
  if _call_filter_for_action?(rule, action_name) && _filter_condition_met?(rule)
@@ -308,6 +348,8 @@ class Merb::AbstractController
308
348
  return :filter_chain_completed
309
349
  end
310
350
 
351
+ # Determine whether the filter should be called for the current action using :only and :exclude.
352
+ #
311
353
  # ==== Parameters
312
354
  # rule<Hash>:: Rules for the filter (see below).
313
355
  # action_name<~to_s>:: The name of the action to be called.
@@ -322,6 +364,8 @@ class Merb::AbstractController
322
364
  #
323
365
  # ==== Returns
324
366
  # Boolean:: True if the action should be called.
367
+ #
368
+ # @api private
325
369
  def _call_filter_for_action?(rule, action_name)
326
370
  # Both:
327
371
  # * no :only or the current action is in the :only list
@@ -330,6 +374,8 @@ class Merb::AbstractController
330
374
  (!rule.key?(:exclude) || !rule[:exclude].include?(action_name))
331
375
  end
332
376
 
377
+ # Determines whether the filter should be run based on the conditions passed (:if and :unless)
378
+ #
333
379
  # ==== Parameters
334
380
  # rule<Hash>:: Rules for the filter (see below).
335
381
  #
@@ -340,6 +386,8 @@ class Merb::AbstractController
340
386
  #
341
387
  # ==== Returns
342
388
  # Boolean:: True if the conditions are met.
389
+ #
390
+ # @api private
343
391
  def _filter_condition_met?(rule)
344
392
  # Both:
345
393
  # * no :if or the if condition evaluates to true
@@ -348,6 +396,8 @@ class Merb::AbstractController
348
396
  (!rule.key?(:unless) || ! _evaluate_condition(rule[:unless]))
349
397
  end
350
398
 
399
+ # Evaluates a filter condition (:if or :unless)
400
+ #
351
401
  # ==== Parameters
352
402
  # condition<Symbol, Proc>:: The condition to evaluate.
353
403
  #
@@ -360,6 +410,8 @@ class Merb::AbstractController
360
410
  # ==== Alternatives
361
411
  # If condition is a symbol, it will be send'ed. If it is a Proc it will be
362
412
  # called directly with self as an argument.
413
+ #
414
+ # @api private
363
415
  def _evaluate_condition(condition)
364
416
  case condition
365
417
  when Symbol : self.send(condition)
@@ -370,6 +422,7 @@ class Merb::AbstractController
370
422
  end
371
423
  end
372
424
 
425
+ # Adds a filter to the after filter chain
373
426
  # ==== Parameters
374
427
  # filter<Symbol, Proc>:: The filter to add. Defaults to nil.
375
428
  # opts<Hash>::
@@ -377,11 +430,15 @@ class Merb::AbstractController
377
430
  # &block:: A block to use as a filter if filter is nil.
378
431
  #
379
432
  # ==== Notes
380
- # If the filter already exists, its options will be replaced with opts.
433
+ # If the filter already exists, its options will be replaced with opts.;
434
+ #
435
+ # @api public
381
436
  def self.after(filter = nil, opts = {}, &block)
382
437
  add_filter(self._after_filters, filter || block, opts)
383
438
  end
384
439
 
440
+ # Adds a filter to the before filter chain.
441
+ #
385
442
  # ==== Parameters
386
443
  # filter<Symbol, Proc>:: The filter to add. Defaults to nil.
387
444
  # opts<Hash>::
@@ -390,44 +447,90 @@ class Merb::AbstractController
390
447
  #
391
448
  # ==== Notes
392
449
  # If the filter already exists, its options will be replaced with opts.
450
+ #
451
+ # @api public
393
452
  def self.before(filter = nil, opts = {}, &block)
394
453
  add_filter(self._before_filters, filter || block, opts)
395
454
  end
396
455
 
397
- # Skip an after filter that has been previously defined (perhaps in a
398
- # superclass)
456
+ # Removes a filter from the after filter chain. This removes the
457
+ # filter from the filter chain for the whole controller and does not
458
+ # take any options.
399
459
  #
400
460
  # ==== Parameters
401
- # filter<Symbol>:: A filter name to skip.
461
+ # filter<Symbol, String>:: A filter name to skip.
462
+ #
463
+ # @api public
402
464
  def self.skip_after(filter)
403
465
  skip_filter(self._after_filters, filter)
404
466
  end
405
467
 
406
- # Skip a before filter that has been previously defined (perhaps in a
407
- # superclass).
468
+ # Removes a filter from the before filter chain. This removes the
469
+ # filter from the filter chain for the whole controller and does not
470
+ # take any options.
408
471
  #
409
472
  # ==== Parameters
410
- # filter<Symbol>:: A filter name to skip.
473
+ # filter<Symbol, String>:: A filter name to skip.
474
+ #
475
+ # @api public
411
476
  def self.skip_before(filter)
412
477
  skip_filter(self._before_filters , filter)
413
478
  end
414
-
415
- #---
416
- # Defaults that can be overridden by plugins, other mixins, or subclasses
417
- def _filters_halted() "<html><body><h1>Filter Chain Halted!</h1></body></html>" end
418
-
419
- # ==== Parameters
420
- # name<~to_sym, Hash>:: The name of the URL to generate.
421
- # rparams<Hash>:: Parameters for the route generation.
479
+
480
+ # There are three possible ways to use this method. First, if you have a named route,
481
+ # you can specify the route as the first parameter as a symbol and any paramters in a
482
+ # hash. Second, you can generate the default route by just passing the params hash,
483
+ # just passing the params hash. Finally, you can use the anonymous parameters. This
484
+ # allows you to specify the parameters to a named route in the order they appear in the
485
+ # router.
486
+ #
487
+ # ==== Parameters(Named Route)
488
+ # name<Symbol>::
489
+ # The name of the route.
490
+ # args<Hash>::
491
+ # Parameters for the route generation.
492
+ #
493
+ # ==== Parameters(Default Route)
494
+ # args<Hash>::
495
+ # Parameters for the route generation. This route will use the default route.
496
+ #
497
+ # ==== Parameters(Anonymous Parameters)
498
+ # name<Symbol>::
499
+ # The name of the route.
500
+ # args<Array>::
501
+ # An array of anonymous parameters to generate the route
502
+ # with. These parameters are assigned to the route parameters
503
+ # in the order that they are passed.
422
504
  #
423
505
  # ==== Returns
424
506
  # String:: The generated URL.
425
507
  #
426
- # ==== Alternatives
427
- # If a hash is used as the first argument, a default route will be
428
- # generated based on it and rparams.
429
- # ====
430
- # TODO: Update this documentation
508
+ # ==== Examples
509
+ # Named Route
510
+ #
511
+ # Merb::Router.prepare do
512
+ # match("/articles/:title").to(:controller => :articles, :action => :show).name("articles")
513
+ # end
514
+ #
515
+ # url(:articles, :title => "new_article")
516
+ #
517
+ # Default Route
518
+ #
519
+ # Merb::Router.prepare do
520
+ # default_routes
521
+ # end
522
+ #
523
+ # url(:controller => "articles", :action => "new")
524
+ #
525
+ # Anonymous Paramters
526
+ #
527
+ # Merb::Router.prepare do
528
+ # match("/articles/:year/:month/:title").to(:controller => :articles, :action => :show).name("articles")
529
+ # end
530
+ #
531
+ # url(:articles, 2008, 10, "test_article")
532
+ #
533
+ # @api public
431
534
  def url(name, *args)
432
535
  args << {}
433
536
  Merb::Router.url(name, *args)
@@ -435,22 +538,12 @@ class Merb::AbstractController
435
538
 
436
539
  alias_method :relative_url, :url
437
540
 
438
- # ==== Parameters
439
- # name<~to_sym, Hash>:: The name of the URL to generate.
440
- # rparams<Hash>:: Parameters for the route generation.
441
- #
442
- # ==== Returns
443
- # String:: The generated url with protocol + hostname + URL.
444
- #
445
- # ==== Options
446
- #
447
- # :protocol and :host options are special: use them to explicitly
448
- # specify protocol and host of resulting url. If you omit them,
449
- # protocol and host of request are used.
541
+ # Returns the absolute url including the passed protocol and host.
542
+ #
543
+ # This uses the same arguments as the url method, with added requirements
544
+ # of protocol and host options.
450
545
  #
451
- # ==== Alternatives
452
- # If a hash is used as the first argument, a default route will be
453
- # generated based on it and rparams.
546
+ # @api public
454
547
  def absolute_url(name, *args)
455
548
  # FIXME: arrgh, why request.protocol returns http://?
456
549
  # :// is not part of protocol name
@@ -494,8 +587,9 @@ class Merb::AbstractController
494
587
  # resource(:users, :new) # => /users/new
495
588
  # resource(:@user, :edit) # => /users/10/edit
496
589
  #
590
+ # @api public
497
591
  def resource(*args)
498
- args << params
592
+ args << {}
499
593
  Merb::Router.resource(*args)
500
594
  end
501
595
 
@@ -507,6 +601,8 @@ class Merb::AbstractController
507
601
  #
508
602
  # ==== Returns
509
603
  # String:: The output of a template block or the return value of a non-template block converted to a string.
604
+ #
605
+ # @api public
510
606
  def capture(*args, &block)
511
607
  ret = nil
512
608
 
@@ -523,13 +619,16 @@ class Merb::AbstractController
523
619
  # ==== Parameters
524
620
  # str<String>:: The string to concatenate to the buffer.
525
621
  # binding<Binding>:: The binding to use for the buffer.
622
+ #
623
+ # @api public
526
624
  def concat(str, binding)
527
625
  send("concat_#{@_engine}", str, binding)
528
626
  end
529
627
 
530
628
  private
629
+ # adds a filter to the specified filter chain
531
630
  # ==== Parameters
532
- # filters<Array[Filter]>:: The filter list that this should be added to.
631
+ # filters<Array[Filter]>:: The filter chain that this should be added to.
533
632
  # filter<Filter>:: A filter that should be added.
534
633
  # opts<Hash>::
535
634
  # Filter options (see class documentation under <tt>Filter Options</tt>).
@@ -538,6 +637,8 @@ class Merb::AbstractController
538
637
  # ArgumentError::
539
638
  # Both :only and :exclude, or :if and :unless given, if filter is not a
540
639
  # Symbol, String or Proc, or if an unknown option is passed.
640
+ #
641
+ # @api private
541
642
  def self.add_filter(filters, filter, opts={})
542
643
  raise(ArgumentError,
543
644
  "You can specify either :only or :exclude but
@@ -576,11 +677,13 @@ class Merb::AbstractController
576
677
  # inheritence hierarchies.
577
678
  #
578
679
  # ==== Parameters
579
- # filters<Array[Filter]>:: The filter list that this should be removed from.
680
+ # filters<Array[Filter]>:: The filter chain that this should be removed from.
580
681
  # filter<Filter>:: A filter that should be removed.
581
682
  #
582
683
  # ==== Raises
583
684
  # ArgumentError:: filter not Symbol or String.
685
+ #
686
+ # @api private
584
687
  def self.skip_filter(filters, filter)
585
688
  raise(ArgumentError, 'You can only skip filters that have a String or Symbol name.') unless
586
689
  [Symbol, String].include? filter.class
@@ -600,6 +703,8 @@ class Merb::AbstractController
600
703
  #
601
704
  # ==== Examples
602
705
  # normalize_filters!(:only => :new) #=> {:only => [:new]}
706
+ #
707
+ # @api public
603
708
  def self.normalize_filters!(opts={})
604
709
  opts[:only] = Array(opts[:only]).map {|x| x.to_s} if opts[:only]
605
710
  opts[:exclude] = Array(opts[:exclude]).map {|x| x.to_s} if opts[:exclude]