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.
- data/CHANGELOG +992 -0
- data/CONTRIBUTORS +94 -0
- data/LICENSE +20 -0
- data/PUBLIC_CHANGELOG +142 -0
- data/README +21 -0
- data/Rakefile +458 -0
- data/TODO +0 -0
- data/bin/merb +11 -0
- data/bin/merb-specs +5 -0
- data/lib/merb-core.rb +598 -0
- data/lib/merb-core/autoload.rb +31 -0
- data/lib/merb-core/bootloader.rb +717 -0
- data/lib/merb-core/config.rb +305 -0
- data/lib/merb-core/constants.rb +45 -0
- data/lib/merb-core/controller/abstract_controller.rb +568 -0
- data/lib/merb-core/controller/exceptions.rb +315 -0
- data/lib/merb-core/controller/merb_controller.rb +256 -0
- data/lib/merb-core/controller/mime.rb +107 -0
- data/lib/merb-core/controller/mixins/authentication.rb +123 -0
- data/lib/merb-core/controller/mixins/conditional_get.rb +83 -0
- data/lib/merb-core/controller/mixins/controller.rb +319 -0
- data/lib/merb-core/controller/mixins/render.rb +513 -0
- data/lib/merb-core/controller/mixins/responder.rb +469 -0
- data/lib/merb-core/controller/template.rb +254 -0
- data/lib/merb-core/core_ext.rb +9 -0
- data/lib/merb-core/core_ext/hash.rb +7 -0
- data/lib/merb-core/core_ext/kernel.rb +340 -0
- data/lib/merb-core/dispatch/cookies.rb +130 -0
- data/lib/merb-core/dispatch/default_exception/default_exception.rb +93 -0
- data/lib/merb-core/dispatch/default_exception/views/_css.html.erb +198 -0
- data/lib/merb-core/dispatch/default_exception/views/_javascript.html.erb +73 -0
- data/lib/merb-core/dispatch/default_exception/views/index.html.erb +94 -0
- data/lib/merb-core/dispatch/dispatcher.rb +176 -0
- data/lib/merb-core/dispatch/request.rb +729 -0
- data/lib/merb-core/dispatch/router.rb +151 -0
- data/lib/merb-core/dispatch/router/behavior.rb +566 -0
- data/lib/merb-core/dispatch/router/cached_proc.rb +52 -0
- data/lib/merb-core/dispatch/router/resources.rb +191 -0
- data/lib/merb-core/dispatch/router/route.rb +511 -0
- data/lib/merb-core/dispatch/session.rb +222 -0
- data/lib/merb-core/dispatch/session/container.rb +74 -0
- data/lib/merb-core/dispatch/session/cookie.rb +173 -0
- data/lib/merb-core/dispatch/session/memcached.rb +68 -0
- data/lib/merb-core/dispatch/session/memory.rb +99 -0
- data/lib/merb-core/dispatch/session/store_container.rb +150 -0
- data/lib/merb-core/dispatch/worker.rb +28 -0
- data/lib/merb-core/gem_ext/erubis.rb +77 -0
- data/lib/merb-core/logger.rb +203 -0
- data/lib/merb-core/plugins.rb +67 -0
- data/lib/merb-core/rack.rb +25 -0
- data/lib/merb-core/rack/adapter.rb +44 -0
- data/lib/merb-core/rack/adapter/ebb.rb +25 -0
- data/lib/merb-core/rack/adapter/evented_mongrel.rb +26 -0
- data/lib/merb-core/rack/adapter/fcgi.rb +17 -0
- data/lib/merb-core/rack/adapter/irb.rb +118 -0
- data/lib/merb-core/rack/adapter/mongrel.rb +26 -0
- data/lib/merb-core/rack/adapter/runner.rb +28 -0
- data/lib/merb-core/rack/adapter/swiftiplied_mongrel.rb +26 -0
- data/lib/merb-core/rack/adapter/thin.rb +39 -0
- data/lib/merb-core/rack/adapter/thin_turbo.rb +24 -0
- data/lib/merb-core/rack/adapter/webrick.rb +36 -0
- data/lib/merb-core/rack/application.rb +32 -0
- data/lib/merb-core/rack/handler/mongrel.rb +97 -0
- data/lib/merb-core/rack/middleware.rb +20 -0
- data/lib/merb-core/rack/middleware/conditional_get.rb +29 -0
- data/lib/merb-core/rack/middleware/content_length.rb +18 -0
- data/lib/merb-core/rack/middleware/csrf.rb +73 -0
- data/lib/merb-core/rack/middleware/path_prefix.rb +31 -0
- data/lib/merb-core/rack/middleware/profiler.rb +19 -0
- data/lib/merb-core/rack/middleware/static.rb +45 -0
- data/lib/merb-core/rack/middleware/tracer.rb +20 -0
- data/lib/merb-core/server.rb +284 -0
- data/lib/merb-core/tasks/audit.rake +68 -0
- data/lib/merb-core/tasks/gem_management.rb +229 -0
- data/lib/merb-core/tasks/merb.rb +1 -0
- data/lib/merb-core/tasks/merb_rake_helper.rb +80 -0
- data/lib/merb-core/tasks/stats.rake +71 -0
- data/lib/merb-core/test.rb +11 -0
- data/lib/merb-core/test/helpers.rb +9 -0
- data/lib/merb-core/test/helpers/controller_helper.rb +8 -0
- data/lib/merb-core/test/helpers/multipart_request_helper.rb +175 -0
- data/lib/merb-core/test/helpers/request_helper.rb +393 -0
- data/lib/merb-core/test/helpers/route_helper.rb +39 -0
- data/lib/merb-core/test/helpers/view_helper.rb +121 -0
- data/lib/merb-core/test/matchers.rb +9 -0
- data/lib/merb-core/test/matchers/controller_matchers.rb +351 -0
- data/lib/merb-core/test/matchers/route_matchers.rb +137 -0
- data/lib/merb-core/test/matchers/view_matchers.rb +375 -0
- data/lib/merb-core/test/run_specs.rb +49 -0
- data/lib/merb-core/test/tasks/spectasks.rb +68 -0
- data/lib/merb-core/test/test_ext/hpricot.rb +32 -0
- data/lib/merb-core/test/test_ext/object.rb +14 -0
- data/lib/merb-core/test/test_ext/string.rb +14 -0
- data/lib/merb-core/vendor/facets.rb +2 -0
- data/lib/merb-core/vendor/facets/dictionary.rb +433 -0
- data/lib/merb-core/vendor/facets/inflect.rb +342 -0
- data/lib/merb-core/version.rb +3 -0
- 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
|