joe-merb-core 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
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 +456 -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 +648 -0
  11. data/lib/merb-core/autoload.rb +31 -0
  12. data/lib/merb-core/bootloader.rb +889 -0
  13. data/lib/merb-core/config.rb +380 -0
  14. data/lib/merb-core/constants.rb +45 -0
  15. data/lib/merb-core/controller/abstract_controller.rb +620 -0
  16. data/lib/merb-core/controller/exceptions.rb +302 -0
  17. data/lib/merb-core/controller/merb_controller.rb +283 -0
  18. data/lib/merb-core/controller/mime.rb +111 -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 +316 -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 +345 -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 +200 -0
  31. data/lib/merb-core/dispatch/default_exception/views/_javascript.html.erb +77 -0
  32. data/lib/merb-core/dispatch/default_exception/views/index.html.erb +98 -0
  33. data/lib/merb-core/dispatch/dispatcher.rb +172 -0
  34. data/lib/merb-core/dispatch/request.rb +718 -0
  35. data/lib/merb-core/dispatch/router.rb +228 -0
  36. data/lib/merb-core/dispatch/router/behavior.rb +610 -0
  37. data/lib/merb-core/dispatch/router/cached_proc.rb +52 -0
  38. data/lib/merb-core/dispatch/router/resources.rb +220 -0
  39. data/lib/merb-core/dispatch/router/route.rb +560 -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 +215 -0
  49. data/lib/merb-core/plugins.rb +67 -0
  50. data/lib/merb-core/rack.rb +27 -0
  51. data/lib/merb-core/rack/adapter.rb +47 -0
  52. data/lib/merb-core/rack/adapter/ebb.rb +24 -0
  53. data/lib/merb-core/rack/adapter/evented_mongrel.rb +13 -0
  54. data/lib/merb-core/rack/adapter/fcgi.rb +17 -0
  55. data/lib/merb-core/rack/adapter/irb.rb +119 -0
  56. data/lib/merb-core/rack/adapter/mongrel.rb +33 -0
  57. data/lib/merb-core/rack/adapter/runner.rb +28 -0
  58. data/lib/merb-core/rack/adapter/swiftiplied_mongrel.rb +14 -0
  59. data/lib/merb-core/rack/adapter/thin.rb +40 -0
  60. data/lib/merb-core/rack/adapter/thin_turbo.rb +17 -0
  61. data/lib/merb-core/rack/adapter/webrick.rb +72 -0
  62. data/lib/merb-core/rack/application.rb +32 -0
  63. data/lib/merb-core/rack/handler/mongrel.rb +96 -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 +321 -0
  73. data/lib/merb-core/tasks/audit.rake +68 -0
  74. data/lib/merb-core/tasks/gem_management.rb +252 -0
  75. data/lib/merb-core/tasks/merb.rb +2 -0
  76. data/lib/merb-core/tasks/merb_rake_helper.rb +51 -0
  77. data/lib/merb-core/tasks/stats.rake +71 -0
  78. data/lib/merb-core/test.rb +17 -0
  79. data/lib/merb-core/test/helpers.rb +10 -0
  80. data/lib/merb-core/test/helpers/controller_helper.rb +8 -0
  81. data/lib/merb-core/test/helpers/multipart_request_helper.rb +176 -0
  82. data/lib/merb-core/test/helpers/request_helper.rb +61 -0
  83. data/lib/merb-core/test/helpers/route_helper.rb +47 -0
  84. data/lib/merb-core/test/helpers/view_helper.rb +121 -0
  85. data/lib/merb-core/test/matchers.rb +10 -0
  86. data/lib/merb-core/test/matchers/controller_matchers.rb +108 -0
  87. data/lib/merb-core/test/matchers/route_matchers.rb +137 -0
  88. data/lib/merb-core/test/matchers/view_matchers.rb +393 -0
  89. data/lib/merb-core/test/run_specs.rb +141 -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,302 @@
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 InternalServerError < Merb::ControllerExceptions::ServerError; self.status = 500; end
282
+
283
+ class NotImplemented < Merb::ControllerExceptions::ServerError; self.status = 501; end
284
+
285
+ class BadGateway < Merb::ControllerExceptions::ServerError; self.status = 502; end
286
+
287
+ class ServiceUnavailable < Merb::ControllerExceptions::ServerError; self.status = 503; end
288
+
289
+ class GatewayTimeout < Merb::ControllerExceptions::ServerError; self.status = 504; end
290
+
291
+ class HTTPVersionNotSupported < Merb::ControllerExceptions::ServerError; self.status = 505; end
292
+ end
293
+
294
+ # Required to show exceptions in the log file
295
+ #
296
+ # e<Exception>:: The exception that a message is being generated for
297
+ def self.exception(e)
298
+ "#{ e.message } - (#{ e.class })\n" <<
299
+ "#{(e.backtrace or []).join("\n")}"
300
+ end
301
+
302
+ end
@@ -0,0 +1,283 @@
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
+ # ==== Parameters
223
+ # name<~to_sym, Hash>:: The name of the URL to generate.
224
+ # rparams<Hash>:: Parameters for the route generation.
225
+ #
226
+ # ==== Returns
227
+ # String:: The generated URL.
228
+ #
229
+ # ==== Alternatives
230
+ # If a hash is used as the first argument, a default route will be
231
+ # generated based on it and rparams.
232
+ # ====
233
+ # TODO: Update this documentation
234
+ def url(name, *args)
235
+ args << params
236
+ Merb::Router.url(name, *args)
237
+ end
238
+
239
+ alias_method :relative_url, :url
240
+
241
+ def absolute_url(*args)
242
+ options = extract_options_from_args!(args) || {}
243
+ options[:protocol] ||= request.protocol
244
+ options[:host] ||= request.host
245
+ args << options
246
+ super(args.first, *args[1..-1])
247
+ end
248
+
249
+ # The results of the controller's render, to be returned to Rack.
250
+ #
251
+ # ==== Returns
252
+ # Array[Integer, Hash, String]::
253
+ # The controller's status code, headers, and body
254
+ def rack_response
255
+ [status, headers, Merb::Rack::StreamWrapper.new(body)]
256
+ end
257
+
258
+ # Sets a controller to be "abstract"
259
+ # This controller will not be able to be routed to
260
+ # and is used for super classing only
261
+ def self.abstract!
262
+ @_abstract = true
263
+ end
264
+
265
+ # Asks a controller if it is abstract
266
+ #
267
+ # === Returns
268
+ # Boolean
269
+ # true if the controller has been set as abstract
270
+ def self.abstract?
271
+ !!@_abstract
272
+ end
273
+
274
+ # Hide any methods that may have been exposed as actions before.
275
+ hide_action(*_callable_methods)
276
+
277
+ private
278
+
279
+ # If not already added, add the proper mime extension to the template path.
280
+ def _conditionally_append_extension(template, type)
281
+ type && !template.match(/\.#{type.to_s.escape_regexp}$/) ? "#{template}.#{type}" : template
282
+ end
283
+ end