wycats-merb-core 0.9.8

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 (98) hide show
  1. data/CHANGELOG +992 -0
  2. data/CONTRIBUTORS +94 -0
  3. data/LICENSE +20 -0
  4. data/PUBLIC_CHANGELOG +142 -0
  5. data/README +21 -0
  6. data/Rakefile +458 -0
  7. data/TODO +0 -0
  8. data/bin/merb +11 -0
  9. data/bin/merb-specs +5 -0
  10. data/lib/merb-core.rb +598 -0
  11. data/lib/merb-core/autoload.rb +31 -0
  12. data/lib/merb-core/bootloader.rb +717 -0
  13. data/lib/merb-core/config.rb +305 -0
  14. data/lib/merb-core/constants.rb +45 -0
  15. data/lib/merb-core/controller/abstract_controller.rb +568 -0
  16. data/lib/merb-core/controller/exceptions.rb +315 -0
  17. data/lib/merb-core/controller/merb_controller.rb +256 -0
  18. data/lib/merb-core/controller/mime.rb +107 -0
  19. data/lib/merb-core/controller/mixins/authentication.rb +123 -0
  20. data/lib/merb-core/controller/mixins/conditional_get.rb +83 -0
  21. data/lib/merb-core/controller/mixins/controller.rb +319 -0
  22. data/lib/merb-core/controller/mixins/render.rb +513 -0
  23. data/lib/merb-core/controller/mixins/responder.rb +469 -0
  24. data/lib/merb-core/controller/template.rb +254 -0
  25. data/lib/merb-core/core_ext.rb +9 -0
  26. data/lib/merb-core/core_ext/hash.rb +7 -0
  27. data/lib/merb-core/core_ext/kernel.rb +340 -0
  28. data/lib/merb-core/dispatch/cookies.rb +130 -0
  29. data/lib/merb-core/dispatch/default_exception/default_exception.rb +93 -0
  30. data/lib/merb-core/dispatch/default_exception/views/_css.html.erb +198 -0
  31. data/lib/merb-core/dispatch/default_exception/views/_javascript.html.erb +73 -0
  32. data/lib/merb-core/dispatch/default_exception/views/index.html.erb +94 -0
  33. data/lib/merb-core/dispatch/dispatcher.rb +176 -0
  34. data/lib/merb-core/dispatch/request.rb +729 -0
  35. data/lib/merb-core/dispatch/router.rb +151 -0
  36. data/lib/merb-core/dispatch/router/behavior.rb +566 -0
  37. data/lib/merb-core/dispatch/router/cached_proc.rb +52 -0
  38. data/lib/merb-core/dispatch/router/resources.rb +191 -0
  39. data/lib/merb-core/dispatch/router/route.rb +511 -0
  40. data/lib/merb-core/dispatch/session.rb +222 -0
  41. data/lib/merb-core/dispatch/session/container.rb +74 -0
  42. data/lib/merb-core/dispatch/session/cookie.rb +173 -0
  43. data/lib/merb-core/dispatch/session/memcached.rb +68 -0
  44. data/lib/merb-core/dispatch/session/memory.rb +99 -0
  45. data/lib/merb-core/dispatch/session/store_container.rb +150 -0
  46. data/lib/merb-core/dispatch/worker.rb +28 -0
  47. data/lib/merb-core/gem_ext/erubis.rb +77 -0
  48. data/lib/merb-core/logger.rb +203 -0
  49. data/lib/merb-core/plugins.rb +67 -0
  50. data/lib/merb-core/rack.rb +25 -0
  51. data/lib/merb-core/rack/adapter.rb +44 -0
  52. data/lib/merb-core/rack/adapter/ebb.rb +25 -0
  53. data/lib/merb-core/rack/adapter/evented_mongrel.rb +26 -0
  54. data/lib/merb-core/rack/adapter/fcgi.rb +17 -0
  55. data/lib/merb-core/rack/adapter/irb.rb +118 -0
  56. data/lib/merb-core/rack/adapter/mongrel.rb +26 -0
  57. data/lib/merb-core/rack/adapter/runner.rb +28 -0
  58. data/lib/merb-core/rack/adapter/swiftiplied_mongrel.rb +26 -0
  59. data/lib/merb-core/rack/adapter/thin.rb +39 -0
  60. data/lib/merb-core/rack/adapter/thin_turbo.rb +24 -0
  61. data/lib/merb-core/rack/adapter/webrick.rb +36 -0
  62. data/lib/merb-core/rack/application.rb +32 -0
  63. data/lib/merb-core/rack/handler/mongrel.rb +97 -0
  64. data/lib/merb-core/rack/middleware.rb +20 -0
  65. data/lib/merb-core/rack/middleware/conditional_get.rb +29 -0
  66. data/lib/merb-core/rack/middleware/content_length.rb +18 -0
  67. data/lib/merb-core/rack/middleware/csrf.rb +73 -0
  68. data/lib/merb-core/rack/middleware/path_prefix.rb +31 -0
  69. data/lib/merb-core/rack/middleware/profiler.rb +19 -0
  70. data/lib/merb-core/rack/middleware/static.rb +45 -0
  71. data/lib/merb-core/rack/middleware/tracer.rb +20 -0
  72. data/lib/merb-core/server.rb +284 -0
  73. data/lib/merb-core/tasks/audit.rake +68 -0
  74. data/lib/merb-core/tasks/gem_management.rb +229 -0
  75. data/lib/merb-core/tasks/merb.rb +1 -0
  76. data/lib/merb-core/tasks/merb_rake_helper.rb +80 -0
  77. data/lib/merb-core/tasks/stats.rake +71 -0
  78. data/lib/merb-core/test.rb +11 -0
  79. data/lib/merb-core/test/helpers.rb +9 -0
  80. data/lib/merb-core/test/helpers/controller_helper.rb +8 -0
  81. data/lib/merb-core/test/helpers/multipart_request_helper.rb +175 -0
  82. data/lib/merb-core/test/helpers/request_helper.rb +393 -0
  83. data/lib/merb-core/test/helpers/route_helper.rb +39 -0
  84. data/lib/merb-core/test/helpers/view_helper.rb +121 -0
  85. data/lib/merb-core/test/matchers.rb +9 -0
  86. data/lib/merb-core/test/matchers/controller_matchers.rb +351 -0
  87. data/lib/merb-core/test/matchers/route_matchers.rb +137 -0
  88. data/lib/merb-core/test/matchers/view_matchers.rb +375 -0
  89. data/lib/merb-core/test/run_specs.rb +49 -0
  90. data/lib/merb-core/test/tasks/spectasks.rb +68 -0
  91. data/lib/merb-core/test/test_ext/hpricot.rb +32 -0
  92. data/lib/merb-core/test/test_ext/object.rb +14 -0
  93. data/lib/merb-core/test/test_ext/string.rb +14 -0
  94. data/lib/merb-core/vendor/facets.rb +2 -0
  95. data/lib/merb-core/vendor/facets/dictionary.rb +433 -0
  96. data/lib/merb-core/vendor/facets/inflect.rb +342 -0
  97. data/lib/merb-core/version.rb +3 -0
  98. metadata +253 -0
@@ -0,0 +1,315 @@
1
+ class Exception
2
+ def action_name() self.class.action_name end
3
+
4
+ def same?(other)
5
+ self.class == other.class &&
6
+ self.message == other.message &&
7
+ self.backtrace == other.backtrace
8
+ end
9
+
10
+ def self.action_name
11
+ if self == Exception
12
+ return nil unless Object.const_defined?(:Exceptions) &&
13
+ Exceptions.method_defined?(:exception)
14
+ end
15
+ name = self.to_s.split('::').last.snake_case
16
+ Object.const_defined?(:Exceptions) &&
17
+ Exceptions.method_defined?(name) ? name : superclass.action_name
18
+ end
19
+
20
+ def self.status
21
+ 500
22
+ end
23
+ end
24
+
25
+ module Merb
26
+ # ControllerExceptions are a way of simplifying controller code by placing
27
+ # exception logic back into the MVC pattern.
28
+ #
29
+ # When a ControllerException is raised within your application merb will
30
+ # attempt to re-route the request to your Exceptions controller to render
31
+ # the error in a friendly manor.
32
+ #
33
+ # For example you might have an action in your app that raises NotFound
34
+ # if a resource was not available
35
+ #
36
+
37
+ # def show
38
+ # product = Product.find(params[:id])
39
+ # raise NotFound if product.nil?
40
+ # [...]
41
+ # end
42
+ #
43
+ # This would halt execution of your action and re-route it over to your
44
+ # Exceptions controller which might look something like:
45
+ #
46
+ # class Exceptions < Application
47
+
48
+ # def not_found
49
+ # render :layout => :none
50
+ # end
51
+ # end
52
+ #
53
+ # As usual, the not_found action will look for a template in
54
+ # app/views/exceptions/not_found.html.erb
55
+ #
56
+ # Note: All standard ControllerExceptions have an HTTP status code associated
57
+ # with them which is sent to the browser when the action is rendered.
58
+ #
59
+ # Note: If you do not specifiy how to handle raised ControllerExceptions
60
+ # or an unhandlable exception occurs within your customised exception action
61
+ # then they will be rendered using the built-in error template.
62
+ # In development mode this "built in" template will show stack-traces for
63
+ # any of the ServerError family of exceptions (you can force the stack-trace
64
+ # to display in production mode using the :exception_details config option in
65
+ # merb.yml)
66
+ #
67
+ #
68
+ # ==== Internal Exceptions
69
+ #
70
+ # Any other rogue errors (not ControllerExceptions) that occur during the
71
+ # execution of your app will be converted into the ControllerException
72
+ # InternalServerError. And like all other exceptions, the ControllerExceptions
73
+ # can be caught on your Exceptions controller.
74
+ #
75
+ # InternalServerErrors return status 500, a common use for customizing this
76
+ # action might be to send emails to the development team, warning that their
77
+ # application has exploded. Mock example:
78
+ #
79
+
80
+ # def internal_server_error
81
+ # MySpecialMailer.deliver(
82
+ # "team@cowboys.com",
83
+ # "Exception occured at #{Time.now}",
84
+ # params[:exception])
85
+ # render 'Something is wrong, but the team is on it!'
86
+ # end
87
+ #
88
+ # Note: The special param[:exception] is available in all Exception actions
89
+ # and contains the ControllerException that was raised (this is handy if
90
+ # you want to display the associated message or display more detailed info)
91
+ #
92
+ #
93
+ # ==== Extending ControllerExceptions
94
+ #
95
+ # To extend the use of the ControllerExceptions one may extend any of the
96
+ # HTTPError classes.
97
+ #
98
+ # As an example we can create an exception called AdminAccessRequired.
99
+ #
100
+ # class AdminAccessRequired < Merb::ControllerExceptions::Unauthorized; end
101
+ #
102
+ # Add the required action to our Exceptions controller
103
+ #
104
+ # class Exceptions < Application
105
+
106
+ # def admin_access_required
107
+ # render
108
+ # end
109
+ # end
110
+ #
111
+ # In app/views/exceptions/admin_access_required.rhtml
112
+ #
113
+ # <h1>You're not an administrator!</h1>
114
+ # <p>You tried to access <%= @tried_to_access %> but that URL is
115
+ # restricted to administrators.</p>
116
+ #
117
+ module ControllerExceptions
118
+
119
+ # Mapping of status code names to their numeric value.
120
+ STATUS_CODES = {}
121
+
122
+ class Base < StandardError #:doc:
123
+
124
+ # === Returns
125
+ # Integer:: The status-code of the error.
126
+ def status; self.class.status; end
127
+ alias :to_i :status
128
+
129
+ class << self
130
+
131
+ # Get the actual status-code for an Exception class.
132
+ #
133
+ # As usual, this can come from a constant upwards in
134
+ # the inheritance chain.
135
+ #
136
+ # ==== Returns
137
+ # Fixnum:: The status code of this exception.
138
+ def status
139
+ const_get(:STATUS) rescue 0
140
+ end
141
+ alias :to_i :status
142
+
143
+ # Set the actual status-code for an Exception class.
144
+ #
145
+ # If possible, set the STATUS constant, and update
146
+ # any previously registered (inherited) status-code.
147
+ #
148
+ # ==== Parameters
149
+ # num<~to_i>:: The status code
150
+ def status=(num)
151
+ unless self.status?
152
+ register_status_code(self, num)
153
+ self.const_set(:STATUS, num.to_i)
154
+ end
155
+ end
156
+
157
+ # See if a status-code has been defined (on self explicitly).
158
+ #
159
+ # ==== Returns
160
+ # Boolean:: Whether the a status code has been set
161
+ def status?
162
+ self.const_defined?(:STATUS)
163
+ end
164
+
165
+ # Registers any subclasses with status codes for easy lookup by
166
+ # set_status in Merb::Controller.
167
+ #
168
+ # Inheritance ensures this method gets inherited by any subclasses, so
169
+ # it goes all the way down the chain of inheritance.
170
+ #
171
+ # ==== Parameters
172
+ #
173
+ # subclass<Merb::ControllerExceptions::Base>::
174
+ # The Exception class that is inheriting from Merb::ControllerExceptions::Base
175
+ def inherited(subclass)
176
+ # don't set the constant yet - any class methods will be called after self.inherited
177
+ # unless self.status = ... is set explicitly, the status code will be inherited
178
+ register_status_code(subclass, self.status) if self.status?
179
+ end
180
+
181
+ private
182
+
183
+ # Register the status-code for an Exception class.
184
+ #
185
+ # ==== Parameters
186
+ # num<~to_i>:: The status code
187
+ def register_status_code(klass, code)
188
+ name = self.to_s.split('::').last.snake_case
189
+ STATUS_CODES[name.to_sym] = code.to_i
190
+ end
191
+
192
+ end
193
+ end
194
+
195
+ class Informational < Merb::ControllerExceptions::Base; end
196
+
197
+ class Continue < Merb::ControllerExceptions::Informational; self.status = 100; end
198
+
199
+ class SwitchingProtocols < Merb::ControllerExceptions::Informational; self.status = 101; end
200
+
201
+ class Successful < Merb::ControllerExceptions::Base; end
202
+
203
+ class OK < Merb::ControllerExceptions::Successful; self.status = 200; end
204
+
205
+ class Created < Merb::ControllerExceptions::Successful; self.status = 201; end
206
+
207
+ class Accepted < Merb::ControllerExceptions::Successful; self.status = 202; end
208
+
209
+ class NonAuthoritativeInformation < Merb::ControllerExceptions::Successful; self.status = 203; end
210
+
211
+ class NoContent < Merb::ControllerExceptions::Successful; self.status = 204; end
212
+
213
+ class ResetContent < Merb::ControllerExceptions::Successful; self.status = 205; end
214
+
215
+ class PartialContent < Merb::ControllerExceptions::Successful; self.status = 206; end
216
+
217
+ class Redirection < Merb::ControllerExceptions::Base; end
218
+
219
+ class MultipleChoices < Merb::ControllerExceptions::Redirection; self.status = 300; end
220
+
221
+ class MovedPermanently < Merb::ControllerExceptions::Redirection; self.status = 301; end
222
+
223
+ class MovedTemporarily < Merb::ControllerExceptions::Redirection; self.status = 302; end
224
+
225
+ class SeeOther < Merb::ControllerExceptions::Redirection; self.status = 303; end
226
+
227
+ class NotModified < Merb::ControllerExceptions::Redirection; self.status = 304; end
228
+
229
+ class UseProxy < Merb::ControllerExceptions::Redirection; self.status = 305; end
230
+
231
+ class TemporaryRedirect < Merb::ControllerExceptions::Redirection; self.status = 307; end
232
+
233
+ class ClientError < Merb::ControllerExceptions::Base; end
234
+
235
+ class BadRequest < Merb::ControllerExceptions::ClientError; self.status = 400; end
236
+
237
+ class MultiPartParseError < Merb::ControllerExceptions::BadRequest; end
238
+
239
+ class Unauthorized < Merb::ControllerExceptions::ClientError; self.status = 401; end
240
+
241
+ class PaymentRequired < Merb::ControllerExceptions::ClientError; self.status = 402; end
242
+
243
+ class Forbidden < Merb::ControllerExceptions::ClientError; self.status = 403; end
244
+
245
+ class NotFound < Merb::ControllerExceptions::ClientError; self.status = 404; end
246
+
247
+ class ActionNotFound < Merb::ControllerExceptions::NotFound; end
248
+
249
+ class TemplateNotFound < Merb::ControllerExceptions::NotFound; end
250
+
251
+ class LayoutNotFound < Merb::ControllerExceptions::NotFound; end
252
+
253
+ class MethodNotAllowed < Merb::ControllerExceptions::ClientError; self.status = 405; end
254
+
255
+ class NotAcceptable < Merb::ControllerExceptions::ClientError; self.status = 406; end
256
+
257
+ class ProxyAuthenticationRequired < Merb::ControllerExceptions::ClientError; self.status = 407; end
258
+
259
+ class RequestTimeout < Merb::ControllerExceptions::ClientError; self.status = 408; end
260
+
261
+ class Conflict < Merb::ControllerExceptions::ClientError; self.status = 409; end
262
+
263
+ class Gone < Merb::ControllerExceptions::ClientError; self.status = 410; end
264
+
265
+ class LengthRequired < Merb::ControllerExceptions::ClientError; self.status = 411; end
266
+
267
+ class PreconditionFailed < Merb::ControllerExceptions::ClientError; self.status = 412; end
268
+
269
+ class RequestEntityTooLarge < Merb::ControllerExceptions::ClientError; self.status = 413; end
270
+
271
+ class RequestURITooLarge < Merb::ControllerExceptions::ClientError; self.status = 414; end
272
+
273
+ class UnsupportedMediaType < Merb::ControllerExceptions::ClientError; self.status = 415; end
274
+
275
+ class RequestRangeNotSatisfiable < Merb::ControllerExceptions::ClientError; self.status = 416; end
276
+
277
+ class ExpectationFailed < Merb::ControllerExceptions::ClientError; self.status = 417; end
278
+
279
+ class ServerError < Merb::ControllerExceptions::Base; end
280
+
281
+ class NotImplemented < Merb::ControllerExceptions::ServerError; self.status = 501; end
282
+
283
+ class BadGateway < Merb::ControllerExceptions::ServerError; self.status = 502; end
284
+
285
+ class ServiceUnavailable < Merb::ControllerExceptions::ServerError; self.status = 503; end
286
+
287
+ class GatewayTimeout < Merb::ControllerExceptions::ServerError; self.status = 504; end
288
+
289
+ class HTTPVersionNotSupported < Merb::ControllerExceptions::ServerError; self.status = 505; end
290
+
291
+ class InternalServerError < Merb::ControllerExceptions::ServerError #:doc:
292
+ self.status = 500;
293
+ def initialize(exception = nil)
294
+ @exception = exception
295
+ end
296
+
297
+ def backtrace
298
+ @exception ? @exception.backtrace : backtrace
299
+ end
300
+
301
+ def message
302
+ @exception ? @exception.message : message
303
+ end
304
+ end
305
+ end
306
+
307
+ # Required to show exceptions in the log file
308
+ #
309
+ # e<Exception>:: The exception that a message is being generated for
310
+ def self.exception(e)
311
+ "#{ e.message } - (#{ e.class })\n" <<
312
+ "#{(e.backtrace or []).join("\n")}"
313
+ end
314
+
315
+ end
@@ -0,0 +1,256 @@
1
+ class Merb::Controller < Merb::AbstractController
2
+
3
+ class_inheritable_accessor :_hidden_actions, :_shown_actions
4
+
5
+ self._hidden_actions ||= []
6
+ self._shown_actions ||= []
7
+
8
+ cattr_accessor :_subclasses
9
+ self._subclasses = Set.new
10
+
11
+ def self.subclasses_list() _subclasses end
12
+
13
+ include Merb::ResponderMixin
14
+ include Merb::ControllerMixin
15
+ include Merb::AuthenticationMixin
16
+ include Merb::ConditionalGetMixin
17
+
18
+ class << self
19
+
20
+ # ==== Parameters
21
+ # klass<Merb::Controller>::
22
+ # The Merb::Controller inheriting from the base class.
23
+ def inherited(klass)
24
+ _subclasses << klass.to_s
25
+ super
26
+ klass._template_root = Merb.dir_for(:view) unless self._template_root
27
+ end
28
+
29
+ # Hide each of the given methods from being callable as actions.
30
+ #
31
+ # ==== Parameters
32
+ # *names<~to-s>:: Actions that should be added to the list.
33
+ #
34
+ # ==== Returns
35
+ # Array[String]::
36
+ # An array of actions that should not be possible to dispatch to.
37
+ #
38
+ #---
39
+ # @public
40
+ def hide_action(*names)
41
+ self._hidden_actions = self._hidden_actions | names.map { |n| n.to_s }
42
+ end
43
+
44
+ # Makes each of the given methods being callable as actions. You can use
45
+ # this to make methods included from modules callable as actions.
46
+ #
47
+ # ==== Parameters
48
+ # *names<~to-s>:: Actions that should be added to the list.
49
+ #
50
+ # ==== Returns
51
+ # Array[String]::
52
+ # An array of actions that should be dispatched to even if they would not
53
+ # otherwise be.
54
+ #
55
+ # ==== Example
56
+ # module Foo
57
+ # def self.included(base)
58
+ # base.show_action(:foo)
59
+ # end
60
+ #
61
+ # def foo
62
+ # # some actiony stuff
63
+ # end
64
+ #
65
+ # def foo_helper
66
+ # # this should not be an action
67
+ # end
68
+ # end
69
+ #
70
+ #---
71
+ # @public
72
+ def show_action(*names)
73
+ self._shown_actions = self._shown_actions | names.map {|n| n.to_s}
74
+ end
75
+
76
+ # The list of actions that are callable, after taking defaults,
77
+ # _hidden_actions and _shown_actions into consideration. It is calculated
78
+ # once, the first time an action is dispatched for this controller.
79
+ #
80
+ # ==== Returns
81
+ # SimpleSet[String]:: A set of actions that should be callable.
82
+ def callable_actions
83
+ @callable_actions ||= Extlib::SimpleSet.new(_callable_methods)
84
+ end
85
+
86
+ # This is a stub method so plugins can implement param filtering if they want.
87
+ #
88
+ # ==== Parameters
89
+ # params<Hash{Symbol => String}>:: A list of params
90
+ #
91
+ # ==== Returns
92
+ # Hash{Symbol => String}:: A new list of params, filtered as desired
93
+ #---
94
+ # @semipublic
95
+ def _filter_params(params)
96
+ params
97
+ end
98
+
99
+ private
100
+
101
+ # All methods that are callable as actions.
102
+ #
103
+ # ==== Returns
104
+ # Array:: A list of method names that are also actions
105
+ def _callable_methods
106
+ callables = []
107
+ klass = self
108
+ begin
109
+ callables << (klass.public_instance_methods(false) + klass._shown_actions) - klass._hidden_actions
110
+ klass = klass.superclass
111
+ end until klass == Merb::AbstractController || klass == Object
112
+ callables.flatten.reject{|action| action =~ /^_.*/}
113
+ end
114
+
115
+ end # class << self
116
+
117
+ # The location to look for a template for a particular controller, context,
118
+ # and mime-type. This is overridden from AbstractController, which defines a
119
+ # version of this that does not involve mime-types.
120
+ #
121
+ # ==== Parameters
122
+ # context<~to_s>:: The name of the action or template basename that will be rendered.
123
+ # type<~to_s>::
124
+ # The mime-type of the template that will be rendered. Defaults to nil.
125
+ # controller<~to_s>::
126
+ # The name of the controller that will be rendered. Defaults to
127
+ # controller_name.
128
+ #
129
+ # ==== Notes
130
+ # By default, this renders ":controller/:action.:type". To change this,
131
+ # override it in your application class or in individual controllers.
132
+ #
133
+ #---
134
+ # @public
135
+ def _template_location(context, type, controller)
136
+ _conditionally_append_extension(controller ? "#{controller}/#{context}" : "#{context}", type)
137
+ end
138
+
139
+ # The location to look for a template and mime-type. This is overridden
140
+ # from AbstractController, which defines a version of this that does not
141
+ # involve mime-types.
142
+ #
143
+ # ==== Parameters
144
+ # template<String>::
145
+ # The absolute path to a template - without mime and template extension.
146
+ # The mime-type extension is optional - it will be appended from the
147
+ # current content type if it hasn't been added already.
148
+ # type<~to_s>::
149
+ # The mime-type of the template that will be rendered. Defaults to nil.
150
+ #
151
+ # @public
152
+ def _absolute_template_location(template, type)
153
+ _conditionally_append_extension(template, type)
154
+ end
155
+
156
+ # Build a new controller.
157
+ #
158
+ # Sets the variables that came in through the dispatch as available to
159
+ # the controller.
160
+ #
161
+ # ==== Parameters
162
+ # request<Merb::Request>:: The Merb::Request that came in from Rack.
163
+ # status<Integer>:: An integer code for the status. Defaults to 200.
164
+ # headers<Hash{header => value}>::
165
+ # A hash of headers to start the controller with. These headers can be
166
+ # overridden later by the #headers method.
167
+ #---
168
+ # @semipublic
169
+ def initialize(request, status=200, headers={'Content-Type' => 'text/html; charset=utf-8'})
170
+ super()
171
+ @request, @_status, @headers = request, status, headers
172
+ end
173
+
174
+ # Dispatch the action.
175
+ #
176
+ # ==== Parameters
177
+ # action<~to_s>:: An action to dispatch to. Defaults to :index.
178
+ #
179
+ # ==== Returns
180
+ # String:: The string sent to the logger for time spent.
181
+ #
182
+ # ==== Raises
183
+ # ActionNotFound:: The requested action was not found in class.
184
+ #---
185
+ # @semipublic
186
+ def _dispatch(action=:index)
187
+ Merb.logger.info("Params: #{self.class._filter_params(request.params).inspect}")
188
+ start = Time.now
189
+ if self.class.callable_actions.include?(action.to_s)
190
+ super(action)
191
+ else
192
+ raise ActionNotFound, "Action '#{action}' was not found in #{self.class}"
193
+ end
194
+ @_benchmarks[:action_time] = Time.now - start
195
+ self
196
+ end
197
+
198
+ attr_reader :request, :headers
199
+
200
+ def status
201
+ @_status
202
+ end
203
+
204
+ # Set the response status code.
205
+ #
206
+ # ==== Parameters
207
+ # s<Fixnum, Symbol>:: A status-code or named http-status
208
+ def status=(s)
209
+ if s.is_a?(Symbol) && STATUS_CODES.key?(s)
210
+ @_status = STATUS_CODES[s]
211
+ elsif s.is_a?(Fixnum)
212
+ @_status = s
213
+ else
214
+ raise ArgumentError, "Status should be of type Fixnum or Symbol, was #{s.class}"
215
+ end
216
+ end
217
+
218
+ # ==== Returns
219
+ # Hash:: The parameters from the request object
220
+ def params() request.params end
221
+
222
+ # The results of the controller's render, to be returned to Rack.
223
+ #
224
+ # ==== Returns
225
+ # Array[Integer, Hash, String]::
226
+ # The controller's status code, headers, and body
227
+ def rack_response
228
+ [status, headers, body]
229
+ end
230
+
231
+ # Sets a controller to be "abstract"
232
+ # This controller will not be able to be routed to
233
+ # and is used for super classing only
234
+ def self.abstract!
235
+ @_abstract = true
236
+ end
237
+
238
+ # Asks a controller if it is abstract
239
+ #
240
+ # === Returns
241
+ # Boolean
242
+ # true if the controller has been set as abstract
243
+ def self.abstract?
244
+ !!@_abstract
245
+ end
246
+
247
+ # Hide any methods that may have been exposed as actions before.
248
+ hide_action(*_callable_methods)
249
+
250
+ private
251
+
252
+ # If not already added, add the proper mime extension to the template path.
253
+ def _conditionally_append_extension(template, type)
254
+ type && !template.match(/\.#{type.to_s.escape_regexp}$/) ? "#{template}.#{type}" : template
255
+ end
256
+ end