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
@@ -4,6 +4,8 @@ module Merb::RenderMixin
4
4
 
5
5
  # ==== Parameters
6
6
  # base<Module>:: Module that is including RenderMixin (probably a controller)
7
+ #
8
+ # @private
7
9
  def self.included(base)
8
10
  base.extend(ClassMethods)
9
11
  base.class_eval do
@@ -17,6 +19,8 @@ module Merb::RenderMixin
17
19
  #
18
20
  # ==== Returns
19
21
  # Hash:: An options hash
22
+ #
23
+ # @api public
20
24
  def default_render_options
21
25
  self._default_render_options ||= {}
22
26
  end
@@ -25,6 +29,8 @@ module Merb::RenderMixin
25
29
  #
26
30
  # ==== Parameters
27
31
  # opts<Hash>:: An options hash
32
+ #
33
+ # @api public
28
34
  def render_options(opts)
29
35
  self._default_render_options = opts
30
36
  end
@@ -40,11 +46,18 @@ module Merb::RenderMixin
40
46
  #
41
47
  # ==== Returns
42
48
  # Hash:: The default render options.
49
+ #
50
+ # @api public
43
51
  def layout(layout)
44
52
  self.default_render_options.update(:layout => (layout || false))
45
53
  end
46
54
 
47
55
  # Enable the default layout logic - reset the layout option.
56
+ #
57
+ # ==== Returns
58
+ # ~to_s:: The layout that was previously set.
59
+ #
60
+ # @api public
48
61
  def default_layout
49
62
  self.default_render_options.delete(:layout)
50
63
  end
@@ -82,8 +95,8 @@ module Merb::RenderMixin
82
95
  # ==== Alternatives
83
96
  # If you pass a Hash as the first parameter, it will be moved to opts and
84
97
  # "thing" will be the current action
85
- #---
86
- # @public
98
+ #
99
+ # @api public
87
100
  def render(thing = nil, opts = {})
88
101
  # render :format => :xml means render nil, :format => :xml
89
102
  opts, thing = thing, nil if thing.is_a?(Hash)
@@ -188,6 +201,7 @@ module Merb::RenderMixin
188
201
  # The transformed object will not be used in a layout unless a :layout is
189
202
  # explicitly passed in the opts.
190
203
  #
204
+ # @api public
191
205
  def display(object, thing = nil, opts = {})
192
206
  template_opt = thing.is_a?(Hash) ? thing.delete(:template) : opts.delete(:template)
193
207
 
@@ -268,6 +282,8 @@ module Merb::RenderMixin
268
282
  #
269
283
  # In this case, "one" will be available in the partial through the local
270
284
  # variable named +number+.
285
+ #
286
+ # @api public
271
287
  def partial(template, opts={})
272
288
 
273
289
  # partial :foo becomes "#{controller_name}/_foo"
@@ -323,6 +339,8 @@ module Merb::RenderMixin
323
339
  #
324
340
  # ==== Returns
325
341
  # Hash:: The options hash that was passed in.
342
+ #
343
+ # @api private
326
344
  def _handle_options!(opts)
327
345
  self.status = opts.delete(:status).to_i if opts[:status]
328
346
  headers["Location"] = opts.delete(:location) if opts[:location]
@@ -346,6 +364,8 @@ module Merb::RenderMixin
346
364
  # If a layout was specified (either via layout in the class or by passing
347
365
  # one in to this method), and not found. No error will be raised if no
348
366
  # layout was specified, and the default layouts were not found.
367
+ #
368
+ # @api private
349
369
  def _get_layout(layout = nil)
350
370
  return false if layout == false
351
371
 
@@ -385,6 +405,8 @@ module Merb::RenderMixin
385
405
  # ==== Returns
386
406
  # Array[Symbol, String]::
387
407
  # A pair consisting of the template method and location.
408
+ #
409
+ # @api private
388
410
  def _template_for(context, content_type, controller=nil, template=nil, locals=[])
389
411
  template_method, template_location = nil, nil
390
412
 
@@ -419,6 +441,8 @@ module Merb::RenderMixin
419
441
  #
420
442
  # ==== Returns
421
443
  # String:: The method, if it exists. Otherwise return nil.
444
+ #
445
+ # @api private
422
446
  def _template_method_for(template_location, locals)
423
447
  meth = Merb::Template.template_for(template_location, [], locals)
424
448
  meth && self.respond_to?(meth) ? meth : nil
@@ -431,8 +455,8 @@ module Merb::RenderMixin
431
455
  #
432
456
  # ==== Parameters
433
457
  # obj<Object>:: The key in the thrown_content hash. Defaults to :for_layout.
434
- #---
435
- # @public
458
+ #
459
+ # @api public
436
460
  def catch_content(obj = :for_layout)
437
461
  @_caught_content[obj] || ''
438
462
  end
@@ -441,8 +465,8 @@ module Merb::RenderMixin
441
465
  #
442
466
  # ==== Parameters
443
467
  # obj<Object>:: The key in the thrown_content hash. Defaults to :for_layout.
444
- #---
445
- # @public
468
+ #
469
+ # @api public
446
470
  def thrown_content?(obj = :for_layout)
447
471
  @_caught_content.key?(obj)
448
472
  end
@@ -463,8 +487,8 @@ module Merb::RenderMixin
463
487
  # ==== Example
464
488
  # throw_content(:foo, "Foo")
465
489
  # catch_content(:foo) #=> "Foo"
466
- #---
467
- # @public
490
+ #
491
+ # @api public
468
492
  def throw_content(obj, string = nil, &block)
469
493
  unless string || block_given?
470
494
  raise ArgumentError, "You must pass a block or a string into throw_content"
@@ -499,8 +523,8 @@ module Merb::RenderMixin
499
523
  #
500
524
  # ==== Parameters
501
525
  # obj<Object>:: The key in the thrown_content hash. Defaults to :for_layout.
502
- #---
503
- # @public
526
+ #
527
+ # @api public
504
528
  def clear_content(obj = :for_layout)
505
529
  @_caught_content.delete(obj) unless @_caught_content[obj].nil?
506
530
  end
@@ -104,6 +104,8 @@ module Merb
104
104
 
105
105
  # ==== Parameters
106
106
  # base<Module>:: The module that ResponderMixin was mixed into
107
+ #
108
+ # @api private
107
109
  def self.included(base)
108
110
  base.extend(ClassMethods)
109
111
  base.class_eval do
@@ -130,8 +132,8 @@ module Merb
130
132
  #
131
133
  # ==== Examples
132
134
  # provides :html, :xml
133
- #---
134
- # @public
135
+ #
136
+ # @api public
135
137
  def provides(*formats)
136
138
  self.class_provided_formats |= formats
137
139
  end
@@ -145,8 +147,7 @@ module Merb
145
147
  # ==== Returns
146
148
  # Array[Symbol]:: List of formats passed in.
147
149
  #
148
- #---
149
- # @public
150
+ # @api public
150
151
  def only_provides(*formats)
151
152
  clear_provides
152
153
  provides(*formats)
@@ -162,8 +163,7 @@ module Merb
162
163
  # Array[Symbol]::
163
164
  # List of formats that remain after removing the ones not to provide.
164
165
  #
165
- #---
166
- # @public
166
+ # @api public
167
167
  def does_not_provide(*formats)
168
168
  self.class_provided_formats -= formats
169
169
  end
@@ -172,6 +172,8 @@ module Merb
172
172
  #
173
173
  # ==== Returns
174
174
  # Array:: An empty Array.
175
+ #
176
+ # @api public
175
177
  def clear_provides
176
178
  self.class_provided_formats.clear
177
179
  end
@@ -180,6 +182,8 @@ module Merb
180
182
  #
181
183
  # ==== Returns
182
184
  # Array[Symbol]:: [:html].
185
+ #
186
+ # @api public
183
187
  def reset_provides
184
188
  only_provides(:html)
185
189
  end
@@ -190,6 +194,8 @@ module Merb
190
194
  # The current list of formats provided for this instance of the
191
195
  # controller. It starts with what has been set in the controller (or
192
196
  # :html by default) but can be modifed on a per-action basis.
197
+ #
198
+ # @api private
193
199
  def _provided_formats
194
200
  @_provided_formats ||= class_provided_formats.dup
195
201
  end
@@ -209,8 +215,7 @@ module Merb
209
215
  # ==== Returns
210
216
  # Array[Symbol]:: List of formats passed in.
211
217
  #
212
- #---
213
- # @public
218
+ # @api public
214
219
  def provides(*formats)
215
220
  if @_content_type
216
221
  raise ContentTypeAlreadySet, "Cannot modify provided_formats because content_type has already been set"
@@ -229,8 +234,7 @@ module Merb
229
234
  # ==== Returns
230
235
  # Array[Symbol]:: List of formats passed in.
231
236
  #
232
- #---
233
- # @public
237
+ # @api public
234
238
  def only_provides(*formats)
235
239
  @_provided_formats = []
236
240
  provides(*formats)
@@ -248,8 +252,7 @@ module Merb
248
252
  # Array[Symbol]::
249
253
  # List of formats that remain after removing the ones not to provide.
250
254
  #
251
- #---
252
- # @public
255
+ # @api public
253
256
  def does_not_provide(*formats)
254
257
  @_provided_formats -= formats.flatten
255
258
  end
@@ -260,6 +263,8 @@ module Merb
260
263
  # 3. If it's */*, use the first provided format
261
264
  # 4. Look for one that is provided, in order of request
262
265
  # 5. Raise 406 if none found
266
+ #
267
+ # @api private
263
268
  def _perform_content_negotiation
264
269
  if (fmt = params[:format]) && !fmt.empty?
265
270
  accepts = [fmt.to_sym]
@@ -307,8 +312,7 @@ module Merb
307
312
  # ==== Returns
308
313
  # Symbol:: The content-type that will be used for this controller.
309
314
  #
310
- #---
311
- # @public
315
+ # @api public
312
316
  def content_type(fmt = nil)
313
317
  self.content_type = (fmt || _perform_content_negotiation) unless @_content_type
314
318
  @_content_type
@@ -327,8 +331,7 @@ module Merb
327
331
  # ==== Returns
328
332
  # Symbol:: The content-type that was passed in.
329
333
  #
330
- #---
331
- # @semipublic
334
+ # @api plugin
332
335
  def content_type=(type)
333
336
  unless Merb.available_mime_types.has_key?(type)
334
337
  raise Merb::ControllerExceptions::NotAcceptable.new("Unknown content_type for response: #{type}")
@@ -359,6 +362,8 @@ module Merb
359
362
  #
360
363
  # ==== Returns
361
364
  # Array[AcceptType]:: The accepted types.
365
+ #
366
+ # @private
362
367
  def self.parse(accept_header)
363
368
  headers = accept_header.split(/,/)
364
369
  idx, list = 0, []
@@ -378,6 +383,8 @@ module Merb
378
383
  # index<Fixnum>::
379
384
  # The index used for sorting accept types. A lower value indicates higher
380
385
  # priority.
386
+ #
387
+ # @api private
381
388
  def initialize(entry,index)
382
389
  @index = index
383
390
 
@@ -399,6 +406,8 @@ module Merb
399
406
  # Fixnum::
400
407
  # -1, 0 or 1, depending on whether entry has a lower, equal or higher
401
408
  # priority than the accept type being compared.
409
+ #
410
+ # @api private
402
411
  def <=>(entry)
403
412
  if entry.quality == quality
404
413
  @index <=> entry.index
@@ -415,20 +424,28 @@ module Merb
415
424
  # Boolean::
416
425
  # True if the accept types are equal, i.e. if the synonyms for this
417
426
  # accept type includes the entry media range.
427
+ #
428
+ # @api private
418
429
  def eql?(entry)
419
430
  synonyms.include?(entry.media_range)
420
431
  end
421
432
 
422
433
  # An alias for eql?.
434
+ #
435
+ # @api private
423
436
  def ==(entry); eql?(entry); end
424
437
 
425
438
  # ==== Returns
426
439
  # Fixnum:: A hash based on the super range.
440
+ #
441
+ # @api private
427
442
  def hash; super_range.hash; end
428
443
 
429
444
  # ==== Returns
430
445
  # Array[String]::
431
446
  # All Accept header values, such as "text/html", that match this type.
447
+ #
448
+ # @api private
432
449
  def synonyms
433
450
  return @syns if @syns
434
451
  if _mime = mime
@@ -438,6 +455,7 @@ module Merb
438
455
  end
439
456
  end
440
457
 
458
+ # @api private
441
459
  def mime
442
460
  @mime ||= Merb.available_mime_types[Merb::ResponderMixin::MIMES[@media_range]]
443
461
  end
@@ -446,12 +464,16 @@ module Merb
446
464
  # String::
447
465
  # The primary media range for this accept type, i.e. either the first
448
466
  # synonym or, if none exist, the media range.
467
+ #
468
+ # @api private
449
469
  def super_range
450
470
  synonyms.first || @media_range
451
471
  end
452
472
 
453
473
  # ==== Returns
454
474
  # Symbol: The type as a symbol, e.g. :html.
475
+ #
476
+ # @api private
455
477
  def to_sym
456
478
  Merb.available_mime_types.select{|k,v|
457
479
  v[:accepts] == synonyms || v[:accepts][0] == synonyms[0]}.flatten.first
@@ -459,6 +481,8 @@ module Merb
459
481
 
460
482
  # ==== Returns
461
483
  # String:: The accept type as a string, i.e. the media range.
484
+ #
485
+ # @api private
462
486
  def to_s
463
487
  @media_range
464
488
  end
@@ -21,10 +21,12 @@ module Merb::Template
21
21
  # ==== Returns
22
22
  # String:: The template name.
23
23
  #
24
- #---
24
+ #
25
25
  # We might want to replace this with something that varies the
26
26
  # character replaced based on the non-alphanumeric character
27
27
  # to avoid edge-case collisions.
28
+ #
29
+ # @api private
28
30
  def template_name(path)
29
31
  path = File.expand_path(path)
30
32
  path.gsub(/[^\.a-zA-Z0-9]/, "__").gsub(/\./, "_")
@@ -45,8 +47,9 @@ module Merb::Template
45
47
  #
46
48
  # ==== Returns
47
49
  # IO#path:: An IO object that responds to path (File or VirtualFile).
48
- #---
49
- # @semipublic
50
+ #
51
+ # @api plugin
52
+ # @overridable
50
53
  def load_template_io(path)
51
54
  File.open(path, "r")
52
55
  end
@@ -60,8 +63,8 @@ module Merb::Template
60
63
  #
61
64
  # ==== Returns
62
65
  # <String>:: name of the method that inlines the template.
63
- #---
64
- # @semipublic
66
+ #
67
+ # @api private
65
68
  def template_for(path, template_stack = [], locals=[])
66
69
  path = File.expand_path(path)
67
70
 
@@ -81,20 +84,22 @@ module Merb::Template
81
84
  #
82
85
  # ==== Returns
83
86
  # Boolean:: Whether or not the template for the provided path needs to be recompiled
84
- #---
87
+ #
88
+ # @api private
85
89
  def needs_compilation?(path, locals)
86
90
  return true if Merb::Config[:reload_templates] || !METHOD_LIST[path]
87
91
 
88
92
  current_locals = SUPPORTED_LOCALS_LIST[path]
89
- locals.any?{|local| !current_locals.include?(local)}
93
+ current_locals != locals &&
94
+ !(locals - current_locals).empty?
90
95
  end
91
96
 
92
97
  # Get all known template extensions
93
98
  #
94
99
  # ==== Returns
95
100
  # Array:: Extension strings.
96
- #---
97
- # @semipublic
101
+ #
102
+ # @api plugin
98
103
  def template_extensions
99
104
  EXTENSIONS.keys
100
105
  end
@@ -112,11 +117,14 @@ module Merb::Template
112
117
  # The module to put the compiled method into. Defaults to
113
118
  # Merb::InlineTemplates
114
119
  #
120
+ # ==== Returns
121
+ # Symbol:: The name of the method that the template was compiled into.
122
+ #
115
123
  # ==== Notes
116
124
  # Even though this method supports inlining into any module, the method
117
125
  # must be available to instances of AbstractController that will use it.
118
- #---
119
- # @public
126
+ #
127
+ # @api private
120
128
  def inline_template(io, locals=[], mod = Merb::InlineTemplates)
121
129
  full_file_path = File.expand_path(io.path)
122
130
  engine_neutral_path = full_file_path.gsub(/\.[^\.]*$/, "")
@@ -136,8 +144,8 @@ module Merb::Template
136
144
  #
137
145
  # ==== Returns
138
146
  # Class:: The engine.
139
- #---
140
- # @semipublic
147
+ #
148
+ # @api private
141
149
  def engine_for(path)
142
150
  path = File.expand_path(path)
143
151
  EXTENSIONS[path.match(/\.([^\.]*)$/)[1]]
@@ -155,10 +163,13 @@ module Merb::Template
155
163
  # ==== Raises
156
164
  # ArgumentError:: engine does not have a compile_template method.
157
165
  #
166
+ # ==== Returns
167
+ # nil
168
+ #
158
169
  # ==== Example
159
170
  # Merb::Template.register_extensions(Merb::Template::Erubis, ["erb"])
160
- #---
161
- # @public
171
+ #
172
+ # @api plugin
162
173
  def register_extensions(engine, extensions)
163
174
  raise ArgumentError, "The class you are registering does not have a compile_template method" unless
164
175
  engine.respond_to?(:compile_template)
@@ -177,6 +188,8 @@ module Merb::Template
177
188
  # name<String>:: The name of the method that will be created.
178
189
  # locals<Array[Symbol]>:: A list of locals to assign from the args passed into the compiled template.
179
190
  # mod<Module>:: The module that the compiled method will be placed into.
191
+ #
192
+ # @api private
180
193
  def self.compile_template(io, name, locals, mod)
181
194
  template = ::Erubis::BlockAwareEruby.new(io.read)
182
195
  _old_verbose, $VERBOSE = $VERBOSE, nil
@@ -206,6 +219,8 @@ module Merb::Template
206
219
  # <% @foo = capture do %>
207
220
  # <p>Some Foo content!</p>
208
221
  # <% end %>
222
+ #
223
+ # @private
209
224
  def capture_erb(*args, &block)
210
225
  _old_buf, @_erb_buf = @_erb_buf, ""
211
226
  block.call(*args)
@@ -214,7 +229,7 @@ module Merb::Template
214
229
  ret
215
230
  end
216
231
 
217
- # DOC
232
+ # @private
218
233
  def concat_erb(string, binding)
219
234
  @_erb_buf << string
220
235
  end
@@ -228,30 +243,36 @@ end
228
243
 
229
244
  module Erubis
230
245
  module BlockAwareEnhancer
246
+ # @api private
231
247
  def add_preamble(src)
232
248
  src << "_old_buf, @_erb_buf = @_erb_buf, ''; "
233
249
  src << "@_engine = 'erb'; "
234
250
  end
235
251
 
252
+ # @api private
236
253
  def add_postamble(src)
237
254
  src << "\n" unless src[-1] == ?\n
238
255
  src << "_ret = @_erb_buf; @_erb_buf = _old_buf; _ret.to_s;\n"
239
256
  end
240
257
 
258
+ # @api private
241
259
  def add_text(src, text)
242
260
  src << " @_erb_buf.concat('" << escape_text(text) << "'); "
243
261
  end
244
262
 
263
+ # @api private
245
264
  def add_expr_escaped(src, code)
246
265
  src << ' @_erb_buf.concat(' << escaped_expr(code) << ');'
247
266
  end
248
267
 
268
+ # @api private
249
269
  def add_stmt2(src, code, tailch)
250
270
  src << code
251
271
  src << " ).to_s; " if tailch == "="
252
272
  src << ';' unless code[-1] == ?\n
253
273
  end
254
274
 
275
+ # @api private
255
276
  def add_expr_literal(src, code)
256
277
  if code =~ /(do|\{)(\s*\|[^|]*\|)?\s*\Z/
257
278
  src << ' @_erb_buf.concat( ' << code << "; "