merb-core 0.9.8 → 0.9.9

Sign up to get free protection for your applications and to get access to all the features.
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 << "; "