merb-core 0.9.3 → 0.9.4
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +1 -1
- data/README +3 -3
- data/Rakefile +144 -33
- data/bin/merb +0 -0
- data/bin/merb-specs +0 -0
- data/docs/bootloading.dox +1 -0
- data/docs/merb-core-call-stack-diagram.mmap +0 -0
- data/docs/merb-core-call-stack-diagram.pdf +0 -0
- data/docs/merb-core-call-stack-diagram.png +0 -0
- data/lib/merb-core.rb +159 -37
- data/lib/merb-core/autoload.rb +1 -0
- data/lib/merb-core/bootloader.rb +208 -92
- data/lib/merb-core/config.rb +20 -6
- data/lib/merb-core/controller/abstract_controller.rb +113 -61
- data/lib/merb-core/controller/exceptions.rb +28 -13
- data/lib/merb-core/controller/merb_controller.rb +73 -44
- data/lib/merb-core/controller/mime.rb +25 -7
- data/lib/merb-core/controller/mixins/authentication.rb +1 -1
- data/lib/merb-core/controller/mixins/controller.rb +44 -8
- data/lib/merb-core/controller/mixins/render.rb +191 -128
- data/lib/merb-core/controller/mixins/responder.rb +65 -63
- data/lib/merb-core/controller/template.rb +103 -54
- data/lib/merb-core/core_ext.rb +7 -12
- data/lib/merb-core/core_ext/kernel.rb +128 -136
- data/lib/merb-core/dispatch/cookies.rb +26 -4
- 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 +92 -0
- data/lib/merb-core/dispatch/dispatcher.rb +156 -224
- data/lib/merb-core/dispatch/request.rb +126 -25
- data/lib/merb-core/dispatch/router.rb +61 -6
- data/lib/merb-core/dispatch/router/behavior.rb +122 -41
- data/lib/merb-core/dispatch/router/route.rb +147 -22
- data/lib/merb-core/dispatch/session.rb +52 -2
- data/lib/merb-core/dispatch/session/cookie.rb +4 -2
- data/lib/merb-core/dispatch/session/memcached.rb +38 -27
- data/lib/merb-core/dispatch/session/memory.rb +18 -11
- data/lib/merb-core/dispatch/worker.rb +28 -0
- data/lib/merb-core/gem_ext/erubis.rb +58 -0
- data/lib/merb-core/logger.rb +3 -31
- data/lib/merb-core/plugins.rb +25 -3
- data/lib/merb-core/rack.rb +18 -12
- data/lib/merb-core/rack/adapter.rb +10 -8
- data/lib/merb-core/rack/adapter/ebb.rb +2 -2
- data/lib/merb-core/rack/adapter/irb.rb +31 -21
- data/lib/merb-core/rack/adapter/swiftiplied_mongrel.rb +26 -0
- data/lib/merb-core/rack/adapter/thin.rb +19 -9
- data/lib/merb-core/rack/adapter/thin_turbo.rb +24 -0
- data/lib/merb-core/rack/application.rb +9 -84
- data/lib/merb-core/rack/middleware.rb +26 -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/server.rb +27 -9
- data/lib/merb-core/tasks/audit.rake +68 -0
- data/lib/merb-core/tasks/merb.rb +1 -0
- data/lib/merb-core/tasks/merb_rake_helper.rb +12 -0
- data/lib/merb-core/tasks/stats.rake +71 -0
- data/lib/merb-core/test.rb +2 -1
- data/lib/merb-core/test/helpers/multipart_request_helper.rb +3 -3
- data/lib/merb-core/test/helpers/request_helper.rb +66 -24
- data/lib/merb-core/test/matchers/controller_matchers.rb +36 -4
- data/lib/merb-core/test/matchers/route_matchers.rb +12 -3
- data/lib/merb-core/test/matchers/view_matchers.rb +3 -3
- data/lib/merb-core/test/run_specs.rb +1 -0
- data/lib/merb-core/test/tasks/spectasks.rb +13 -5
- data/lib/merb-core/test/test_ext/string.rb +14 -0
- data/lib/merb-core/vendor/facets/dictionary.rb +3 -3
- data/lib/merb-core/vendor/facets/inflect.rb +82 -37
- data/lib/merb-core/version.rb +2 -2
- data/spec/private/config/config_spec.rb +39 -4
- data/spec/private/core_ext/kernel_spec.rb +3 -14
- data/spec/private/dispatch/bootloader_spec.rb +1 -1
- data/spec/private/dispatch/cookies_spec.rb +181 -69
- data/spec/private/dispatch/fixture/app/controllers/exceptions.rb +0 -2
- data/spec/private/dispatch/fixture/app/controllers/foo.rb +0 -2
- data/spec/private/dispatch/fixture/config/rack.rb +10 -0
- data/spec/private/dispatch/fixture/log/merb_test.log +7054 -1802
- data/spec/private/dispatch/route_params_spec.rb +2 -3
- data/spec/private/dispatch/session_mixin_spec.rb +47 -0
- data/spec/private/plugins/plugin_spec.rb +73 -59
- data/spec/private/router/behavior_spec.rb +60 -0
- data/spec/private/router/fixture/log/merb_test.log +1693 -0
- data/spec/private/router/route_spec.rb +414 -0
- data/spec/private/router/router_spec.rb +175 -0
- data/spec/private/vendor/facets/plural_spec.rb +564 -0
- data/spec/private/vendor/facets/singular_spec.rb +489 -0
- data/spec/public/abstract_controller/controllers/cousins.rb +41 -0
- data/spec/public/abstract_controller/controllers/helpers.rb +12 -2
- data/spec/public/abstract_controller/controllers/partial.rb +17 -2
- data/spec/public/abstract_controller/controllers/render.rb +16 -1
- data/spec/public/abstract_controller/controllers/views/helpers/capture_eq/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/helpers/capture_with_args/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/render_two_throw_contents/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/partial_with_collections_and_counter/_collection.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/partial_with_collections_and_counter/index.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/with_absolute_partial/_partial.erb +1 -0
- data/spec/public/abstract_controller/controllers/views/partial/with_absolute_partial/index.erb +1 -0
- data/spec/public/abstract_controller/filter_spec.rb +20 -1
- data/spec/public/abstract_controller/helper_spec.rb +10 -2
- data/spec/public/abstract_controller/partial_spec.rb +8 -0
- data/spec/public/abstract_controller/render_spec.rb +8 -0
- data/spec/public/abstract_controller/spec_helper.rb +7 -3
- data/spec/public/boot_loader/boot_loader_spec.rb +2 -2
- data/spec/public/controller/base_spec.rb +10 -2
- data/spec/public/controller/config/init.rb +6 -0
- data/spec/public/controller/controllers/authentication.rb +9 -11
- data/spec/public/controller/controllers/base.rb +2 -8
- data/spec/public/controller/controllers/cookies.rb +16 -0
- data/spec/public/controller/controllers/dispatcher.rb +35 -0
- data/spec/public/controller/controllers/display.rb +62 -14
- data/spec/public/controller/controllers/redirect.rb +36 -0
- data/spec/public/controller/controllers/responder.rb +37 -11
- data/spec/public/controller/controllers/views/layout/custom_arg.json.erb +1 -0
- data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/class_and_local_provides/index.html.erb +1 -0
- data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/class_and_local_provides/index.xml.erb +1 -0
- data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/display_with_template/no_layout.html.erb +1 -0
- data/spec/public/controller/cookies_spec.rb +23 -0
- data/spec/public/controller/dispatcher_spec.rb +411 -0
- data/spec/public/controller/display_spec.rb +43 -10
- data/spec/public/controller/redirect_spec.rb +33 -0
- data/spec/public/controller/responder_spec.rb +79 -11
- data/spec/public/controller/spec_helper.rb +3 -1
- data/spec/public/controller/url_spec.rb +10 -0
- data/spec/public/core/merb_core_spec.rb +11 -0
- data/spec/public/core_ext/fixtures/core_ext_dependency.rb +2 -0
- data/spec/public/core_ext/kernel_spec.rb +9 -0
- data/spec/public/core_ext/spec_helper.rb +1 -0
- data/spec/public/directory_structure/directory/log/merb_test.log +3729 -272
- data/spec/public/directory_structure/directory_spec.rb +3 -4
- data/spec/public/logger/logger_spec.rb +4 -4
- data/spec/public/reloading/directory/log/merb_test.log +288066 -15
- data/spec/public/reloading/reload_spec.rb +49 -27
- data/spec/public/request/multipart_spec.rb +26 -0
- data/spec/public/request/request_spec.rb +21 -2
- data/spec/public/router/fixation_spec.rb +27 -0
- data/spec/public/router/fixture/log/merb_test.log +30050 -0
- data/spec/public/router/nested_matches_spec.rb +97 -0
- data/spec/public/router/resource_spec.rb +1 -9
- data/spec/public/router/resources_spec.rb +0 -20
- data/spec/public/router/spec_helper.rb +27 -9
- data/spec/public/router/special_spec.rb +21 -8
- data/spec/public/template/template_spec.rb +17 -5
- data/spec/public/test/controller_matchers_spec.rb +10 -0
- data/spec/public/test/request_helper_spec.rb +29 -0
- data/spec/public/test/route_helper_spec.rb +18 -1
- data/spec/public/test/route_matchers_spec.rb +28 -1
- data/spec/public/test/view_matchers_spec.rb +3 -3
- data/spec/spec_helper.rb +56 -12
- metadata +89 -47
- data/lib/merb-core/core_ext/class.rb +0 -299
- data/lib/merb-core/core_ext/hash.rb +0 -426
- data/lib/merb-core/core_ext/mash.rb +0 -154
- data/lib/merb-core/core_ext/object.rb +0 -147
- data/lib/merb-core/core_ext/object_space.rb +0 -14
- data/lib/merb-core/core_ext/rubygems.rb +0 -28
- data/lib/merb-core/core_ext/set.rb +0 -46
- data/lib/merb-core/core_ext/string.rb +0 -89
- data/lib/merb-core/core_ext/time.rb +0 -13
- data/lib/merb-core/dispatch/exceptions.html.erb +0 -297
- data/spec/private/core_ext/class_spec.rb +0 -22
- data/spec/private/core_ext/hash_spec.rb +0 -522
- data/spec/private/core_ext/object_spec.rb +0 -121
- data/spec/private/core_ext/set_spec.rb +0 -26
- data/spec/private/core_ext/string_spec.rb +0 -167
- data/spec/private/core_ext/time_spec.rb +0 -16
- data/spec/private/dispatch/dispatch_spec.rb +0 -26
- data/spec/private/dispatch/fixture/log/development.log +0 -1
- data/spec/private/dispatch/fixture/log/merb.4000.pid +0 -1
- data/spec/private/dispatch/fixture/log/production.log +0 -1
- data/spec/private/dispatch/fixture/merb.4000.pid +0 -1
- data/spec/private/rack/application_spec.rb +0 -43
- data/spec/public/controller/log/merb.4000.pid +0 -1
- data/spec/public/directory_structure/directory/log/merb.4000.pid +0 -1
- data/spec/public/directory_structure/directory/merb.4000.pid +0 -1
- data/spec/public/reloading/directory/log/merb.4000.pid +0 -1
- data/spec/public/reloading/directory/merb.4000.pid +0 -1
@@ -1,7 +1,12 @@
|
|
1
1
|
class Merb::Controller < Merb::AbstractController
|
2
2
|
|
3
|
-
class_inheritable_accessor :_hidden_actions, :_shown_actions
|
4
|
-
|
3
|
+
class_inheritable_accessor :_hidden_actions, :_shown_actions,
|
4
|
+
:_session_id_key, :_session_secret_key, :_session_expiry, :_session_cookie_domain
|
5
|
+
|
6
|
+
self._hidden_actions ||= []
|
7
|
+
self._shown_actions ||= []
|
8
|
+
|
9
|
+
cattr_accessor :_subclasses
|
5
10
|
self._subclasses = Set.new
|
6
11
|
|
7
12
|
def self.subclasses_list() _subclasses end
|
@@ -9,13 +14,12 @@ class Merb::Controller < Merb::AbstractController
|
|
9
14
|
self._session_secret_key = nil
|
10
15
|
self._session_id_key = Merb::Config[:session_id_key] || '_session_id'
|
11
16
|
self._session_expiry = Merb::Config[:session_expiry] || Merb::Const::WEEK * 2
|
17
|
+
self._session_cookie_domain = Merb::Config[:session_cookie_domain]
|
12
18
|
|
13
19
|
include Merb::ResponderMixin
|
14
20
|
include Merb::ControllerMixin
|
15
21
|
include Merb::AuthenticationMixin
|
16
22
|
|
17
|
-
attr_accessor :route
|
18
|
-
|
19
23
|
class << self
|
20
24
|
|
21
25
|
# ==== Parameters
|
@@ -23,8 +27,8 @@ class Merb::Controller < Merb::AbstractController
|
|
23
27
|
# The Merb::Controller inheriting from the base class.
|
24
28
|
def inherited(klass)
|
25
29
|
_subclasses << klass.to_s
|
26
|
-
self._template_root = Merb.dir_for(:view) unless self._template_root
|
27
30
|
super
|
31
|
+
klass._template_root = Merb.dir_for(:view) unless self._template_root
|
28
32
|
end
|
29
33
|
|
30
34
|
# Hide each of the given methods from being callable as actions.
|
@@ -74,26 +78,6 @@ class Merb::Controller < Merb::AbstractController
|
|
74
78
|
self._shown_actions = self._shown_actions | names.map {|n| n.to_s}
|
75
79
|
end
|
76
80
|
|
77
|
-
# This list of actions that should not be callable.
|
78
|
-
#
|
79
|
-
# ==== Returns
|
80
|
-
# Array[String]:: An array of actions that should not be dispatchable.
|
81
|
-
def _hidden_actions
|
82
|
-
actions = read_inheritable_attribute(:_hidden_actions)
|
83
|
-
actions ? actions : write_inheritable_attribute(:_hidden_actions, [])
|
84
|
-
end
|
85
|
-
|
86
|
-
# This list of actions that should be callable.
|
87
|
-
#
|
88
|
-
# ==== Returns
|
89
|
-
# Array[String]::
|
90
|
-
# An array of actions that should be dispatched to even if they would not
|
91
|
-
# otherwise be.
|
92
|
-
def _shown_actions
|
93
|
-
actions = read_inheritable_attribute(:_shown_actions)
|
94
|
-
actions ? actions : write_inheritable_attribute(:_shown_actions, [])
|
95
|
-
end
|
96
|
-
|
97
81
|
# The list of actions that are callable, after taking defaults,
|
98
82
|
# _hidden_actions and _shown_actions into consideration. It is calculated
|
99
83
|
# once, the first time an action is dispatched for this controller.
|
@@ -101,16 +85,7 @@ class Merb::Controller < Merb::AbstractController
|
|
101
85
|
# ==== Returns
|
102
86
|
# SimpleSet[String]:: A set of actions that should be callable.
|
103
87
|
def callable_actions
|
104
|
-
|
105
|
-
callables = []
|
106
|
-
klass = self
|
107
|
-
begin
|
108
|
-
callables << (klass.public_instance_methods(false) + klass._shown_actions) - klass._hidden_actions
|
109
|
-
klass = klass.superclass
|
110
|
-
end until klass == Merb::AbstractController || klass == Object
|
111
|
-
@callable_actions = Merb::SimpleSet.new(callables.flatten)
|
112
|
-
end
|
113
|
-
@callable_actions
|
88
|
+
@callable_actions ||= Extlib::SimpleSet.new(_callable_methods)
|
114
89
|
end
|
115
90
|
|
116
91
|
# This is a stub method so plugins can implement param filtering if they want.
|
@@ -126,6 +101,22 @@ class Merb::Controller < Merb::AbstractController
|
|
126
101
|
params
|
127
102
|
end
|
128
103
|
|
104
|
+
private
|
105
|
+
|
106
|
+
# All methods that are callable as actions.
|
107
|
+
#
|
108
|
+
# ==== Returns
|
109
|
+
# Array:: A list of method names that are also actions
|
110
|
+
def _callable_methods
|
111
|
+
callables = []
|
112
|
+
klass = self
|
113
|
+
begin
|
114
|
+
callables << (klass.public_instance_methods(false) + klass._shown_actions) - klass._hidden_actions
|
115
|
+
klass = klass.superclass
|
116
|
+
end until klass == Merb::AbstractController || klass == Object
|
117
|
+
callables.flatten.reject{|action| action =~ /^_.*/}
|
118
|
+
end
|
119
|
+
|
129
120
|
end # class << self
|
130
121
|
|
131
122
|
# The location to look for a template for a particular controller, context,
|
@@ -147,7 +138,24 @@ class Merb::Controller < Merb::AbstractController
|
|
147
138
|
#---
|
148
139
|
# @public
|
149
140
|
def _template_location(context, type = nil, controller = controller_name)
|
150
|
-
controller ? "#{controller}/#{context}
|
141
|
+
_conditionally_append_extension(controller ? "#{controller}/#{context}" : "#{context}", type)
|
142
|
+
end
|
143
|
+
|
144
|
+
# The location to look for a template and mime-type. This is overridden
|
145
|
+
# from AbstractController, which defines a version of this that does not
|
146
|
+
# involve mime-types.
|
147
|
+
#
|
148
|
+
# ==== Parameters
|
149
|
+
# template<String>::
|
150
|
+
# The absolute path to a template - without mime and template extension.
|
151
|
+
# The mime-type extension is optional - it will be appended from the
|
152
|
+
# current content type if it hasn't been added already.
|
153
|
+
# type<~to_s>::
|
154
|
+
# The mime-type of the template that will be rendered. Defaults to nil.
|
155
|
+
#
|
156
|
+
# @public
|
157
|
+
def _absolute_template_location(template, type)
|
158
|
+
_conditionally_append_extension(template, type)
|
151
159
|
end
|
152
160
|
|
153
161
|
# Build a new controller.
|
@@ -168,7 +176,7 @@ class Merb::Controller < Merb::AbstractController
|
|
168
176
|
# @semipublic
|
169
177
|
def initialize(request, status=200, headers={'Content-Type' => 'text/html; charset=utf-8'})
|
170
178
|
super()
|
171
|
-
@request, @
|
179
|
+
@request, @_status, @headers = request, status, headers
|
172
180
|
end
|
173
181
|
|
174
182
|
# Dispatch the action.
|
@@ -184,6 +192,7 @@ class Merb::Controller < Merb::AbstractController
|
|
184
192
|
#---
|
185
193
|
# @semipublic
|
186
194
|
def _dispatch(action=:index)
|
195
|
+
Merb.logger.info("Params: #{self.class._filter_params(request.params).inspect}")
|
187
196
|
start = Time.now
|
188
197
|
if self.class.callable_actions.include?(action.to_s)
|
189
198
|
super(action)
|
@@ -191,10 +200,14 @@ class Merb::Controller < Merb::AbstractController
|
|
191
200
|
raise ActionNotFound, "Action '#{action}' was not found in #{self.class}"
|
192
201
|
end
|
193
202
|
@_benchmarks[:action_time] = Time.now - start
|
203
|
+
self
|
194
204
|
end
|
195
205
|
|
196
206
|
attr_reader :request, :headers
|
197
|
-
|
207
|
+
|
208
|
+
def status
|
209
|
+
@_status
|
210
|
+
end
|
198
211
|
|
199
212
|
# Set the response status code.
|
200
213
|
#
|
@@ -202,9 +215,9 @@ class Merb::Controller < Merb::AbstractController
|
|
202
215
|
# s<Fixnum, Symbol>:: A status-code or named http-status
|
203
216
|
def status=(s)
|
204
217
|
if s.is_a?(Symbol) && STATUS_CODES.key?(s)
|
205
|
-
@
|
218
|
+
@_status = STATUS_CODES[s]
|
206
219
|
elsif s.is_a?(Fixnum)
|
207
|
-
@
|
220
|
+
@_status = s
|
208
221
|
else
|
209
222
|
raise ArgumentError, "Status should be of type Fixnum or Symbol, was #{s.class}"
|
210
223
|
end
|
@@ -227,12 +240,28 @@ class Merb::Controller < Merb::AbstractController
|
|
227
240
|
# ==== Returns
|
228
241
|
# Hash:: The session that was extracted from the request object.
|
229
242
|
def session() request.session end
|
230
|
-
|
243
|
+
|
244
|
+
# The results of the controller's render, to be returned to Rack.
|
245
|
+
#
|
246
|
+
# ==== Returns
|
247
|
+
# Array[Integer, Hash, String]::
|
248
|
+
# The controller's status code, headers, and body
|
249
|
+
def rack_response
|
250
|
+
[status, headers, body]
|
251
|
+
end
|
252
|
+
|
253
|
+
# Hide any methods that may have been exposed as actions before.
|
254
|
+
hide_action(*_callable_methods)
|
255
|
+
|
231
256
|
private
|
232
257
|
|
233
|
-
#
|
234
|
-
|
258
|
+
# If not already added, add the proper mime extension to the template path.
|
259
|
+
def _conditionally_append_extension(template, type = nil)
|
260
|
+
type && !template.match(/\.#{type.to_s.escape_regexp}$/) ? "#{template}.#{type}" : template
|
261
|
+
end
|
262
|
+
|
263
|
+
# Create a default cookie jar, and pre-set a fixation cookie if fixation is enabled.
|
235
264
|
def _setup_cookies
|
236
265
|
::Merb::Cookies.new(request.cookies, @headers)
|
237
266
|
end
|
238
|
-
end
|
267
|
+
end
|
@@ -28,17 +28,35 @@ module Merb
|
|
28
28
|
# The associated method to call on objects to convert them to the
|
29
29
|
# appropriate mime-type. For instance, :json would use :to_json as its
|
30
30
|
# transform_method.
|
31
|
-
#
|
31
|
+
# mimes<Array[String]>::
|
32
32
|
# A list of possible values sent in the Accept header, such as text/html,
|
33
33
|
# that should be associated with this content-type.
|
34
34
|
# new_response_headers<Hash>::
|
35
|
-
# The response headers to set for the the mime type.
|
36
|
-
|
37
|
-
|
35
|
+
# The response headers to set for the the mime type. For example:
|
36
|
+
# 'Content-Type' => 'application/json; charset=utf-8'; As a shortcut for
|
37
|
+
# the common charset option, use :charset => 'utf-8', which will be
|
38
|
+
# correctly appended to the mimetype itself.
|
39
|
+
# &block:: a block which recieves the current controller when the format
|
40
|
+
# is set (in the controller's #content_type method)
|
41
|
+
def add_mime_type(key, transform_method, mimes, new_response_headers = {}, &block)
|
42
|
+
enforce!(key => Symbol, mimes => Array)
|
43
|
+
|
44
|
+
content_type = new_response_headers["Content-Type"] || mimes.first
|
45
|
+
|
46
|
+
if charset = new_response_headers.delete(:charset)
|
47
|
+
content_type += "; charset=#{charset}"
|
48
|
+
end
|
49
|
+
|
38
50
|
ResponderMixin::TYPES.update(key =>
|
39
|
-
{:
|
51
|
+
{:accepts => mimes,
|
40
52
|
:transform_method => transform_method,
|
41
|
-
:
|
53
|
+
:content_type => content_type,
|
54
|
+
:response_headers => new_response_headers,
|
55
|
+
:response_block => block })
|
56
|
+
|
57
|
+
mimes.each do |mime|
|
58
|
+
ResponderMixin::MIMES.update(mime => key)
|
59
|
+
end
|
42
60
|
|
43
61
|
Merb::RenderMixin.class_eval <<-EOS, __FILE__, __LINE__
|
44
62
|
def render_#{key}(thing = nil, opts = {})
|
@@ -81,7 +99,7 @@ module Merb
|
|
81
99
|
# ==== Returns
|
82
100
|
# Hash:: The mime type information.
|
83
101
|
def mime_by_request_header(header)
|
84
|
-
available_mime_types.find {|key,info| info[
|
102
|
+
available_mime_types.find {|key,info| info[:accepts].include?(header)}.first
|
85
103
|
end
|
86
104
|
|
87
105
|
end
|
@@ -1,6 +1,22 @@
|
|
1
1
|
module Merb
|
2
2
|
# Module that is mixed in to all implemented controllers.
|
3
3
|
module ControllerMixin
|
4
|
+
|
5
|
+
# Enqueu a block to run in a background thread outside of the request
|
6
|
+
# response dispatch
|
7
|
+
#
|
8
|
+
# ==== Parameters
|
9
|
+
# takes a block to run later
|
10
|
+
#
|
11
|
+
# ==== Example
|
12
|
+
# run_later do
|
13
|
+
# SomeBackgroundTask.run
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
def run_later(&blk)
|
17
|
+
Merb::Dispatcher.work_queue << blk
|
18
|
+
end
|
19
|
+
|
4
20
|
# Renders the block given as a parameter using chunked encoding.
|
5
21
|
#
|
6
22
|
# ==== Parameters
|
@@ -88,24 +104,43 @@ module Merb
|
|
88
104
|
blk.call
|
89
105
|
}
|
90
106
|
end
|
91
|
-
|
107
|
+
|
92
108
|
# ==== Parameters
|
93
109
|
# url<String>::
|
94
110
|
# URL to redirect to. It can be either a relative or fully-qualified URL.
|
111
|
+
# opts<Hash>:: An options hash (see below)
|
112
|
+
#
|
113
|
+
# ==== Options (opts)
|
114
|
+
# :message<Hash>::
|
115
|
+
# Messages to pass in url query string as value for "_message"
|
116
|
+
# :permanent<Boolean>::
|
117
|
+
# When true, return status 301 Moved Permanently
|
95
118
|
#
|
96
119
|
# ==== Returns
|
97
120
|
# String:: Explanation of redirect.
|
98
121
|
#
|
99
122
|
# ==== Examples
|
100
123
|
# redirect("/posts/34")
|
124
|
+
# redirect("/posts/34", :message => { :notice => 'Post updated successfully!' })
|
101
125
|
# redirect("http://www.merbivore.com/")
|
102
|
-
|
103
|
-
|
104
|
-
|
126
|
+
# redirect("http://www.merbivore.com/", :permanent => true)
|
127
|
+
def redirect(url, opts = {})
|
128
|
+
default_redirect_options = { :message => nil, :permanent => false }
|
129
|
+
opts = default_redirect_options.merge(opts)
|
130
|
+
if opts[:message]
|
131
|
+
notice = Merb::Request.escape([Marshal.dump(opts[:message])].pack("m"))
|
132
|
+
url = url =~ /\?/ ? "#{url}&_message=#{notice}" : "#{url}?_message=#{notice}"
|
133
|
+
end
|
134
|
+
self.status = opts[:permanent] ? 301 : 302
|
135
|
+
Merb.logger.info("Redirecting to: #{url} (#{self.status})")
|
105
136
|
headers['Location'] = url
|
106
137
|
"<html><body>You are being <a href=\"#{url}\">redirected</a>.</body></html>"
|
107
138
|
end
|
108
139
|
|
140
|
+
def message
|
141
|
+
@_message = defined?(@_message) ? @_message : request.message
|
142
|
+
end
|
143
|
+
|
109
144
|
# Sends a file over HTTP. When given a path to a file, it will set the
|
110
145
|
# right headers so that the static file is served directly.
|
111
146
|
#
|
@@ -131,7 +166,7 @@ module Merb
|
|
131
166
|
'Content-Disposition' => disposition,
|
132
167
|
'Content-Transfer-Encoding' => 'binary'
|
133
168
|
)
|
134
|
-
File.open(file)
|
169
|
+
File.open(file, 'rb')
|
135
170
|
end
|
136
171
|
|
137
172
|
# Send binary data over HTTP to the user as a file download. May set content type,
|
@@ -190,7 +225,8 @@ module Merb
|
|
190
225
|
'Content-Type' => opts[:type].strip, # fixes a problem with extra '\r' with some browsers
|
191
226
|
'Content-Disposition' => disposition,
|
192
227
|
'Content-Transfer-Encoding' => 'binary',
|
193
|
-
|
228
|
+
# Rack specification requires header values to respond to :each
|
229
|
+
'CONTENT-LENGTH' => opts[:content_length].to_s
|
194
230
|
)
|
195
231
|
Proc.new{|response|
|
196
232
|
response.send_status(opts[:content_length])
|
@@ -206,8 +242,8 @@ module Merb
|
|
206
242
|
# ==== Parameters
|
207
243
|
# file<String>:: Path to file to send to the client.
|
208
244
|
def nginx_send_file(file)
|
209
|
-
headers['X-Accel-Redirect'] =
|
210
|
-
return
|
245
|
+
headers['X-Accel-Redirect'] = file
|
246
|
+
return ' '
|
211
247
|
end
|
212
248
|
|
213
249
|
# Sets a cookie to be included in the response.
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Merb::RenderMixin
|
2
2
|
# So we can do raise TemplateNotFound
|
3
3
|
include Merb::ControllerExceptions
|
4
|
-
|
4
|
+
|
5
5
|
# ==== Parameters
|
6
6
|
# base<Module>:: Module that is including RenderMixin (probably a controller)
|
7
7
|
def self.included(base)
|
@@ -10,9 +10,9 @@ module Merb::RenderMixin
|
|
10
10
|
class_inheritable_accessor :_default_render_options
|
11
11
|
end
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
module ClassMethods
|
15
|
-
|
15
|
+
|
16
16
|
# Return the default render options.
|
17
17
|
#
|
18
18
|
# ==== Returns
|
@@ -20,7 +20,7 @@ module Merb::RenderMixin
|
|
20
20
|
def default_render_options
|
21
21
|
self._default_render_options ||= {}
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
# Set default render options at the class level.
|
25
25
|
#
|
26
26
|
# ==== Parameters
|
@@ -28,53 +28,57 @@ module Merb::RenderMixin
|
|
28
28
|
def render_options(opts)
|
29
29
|
self._default_render_options = opts
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
# Set the default layout to use or nil/false to disable layout rendering.
|
33
|
-
# This is a shortcut for render_options :layout => false.
|
33
|
+
# This is a shortcut for render_options :layout => false.
|
34
34
|
#
|
35
35
|
# ==== Parameters
|
36
|
-
# layout<~to_s>:: The layout that should be used for this class
|
37
|
-
#
|
36
|
+
# layout<~to_s>:: The layout that should be used for this class.
|
37
|
+
#
|
38
|
+
# ==== Notes
|
39
|
+
# You can override by passing :layout => true to render method.
|
40
|
+
#
|
38
41
|
# ==== Returns
|
39
42
|
# Hash:: The default render options.
|
40
43
|
def layout(layout)
|
41
44
|
self.default_render_options.update(:layout => (layout ? layout : false))
|
42
45
|
end
|
43
|
-
|
46
|
+
|
44
47
|
# Enable the default layout logic - reset the layout option.
|
45
48
|
def default_layout
|
46
49
|
self.default_render_options.delete(:layout)
|
47
50
|
end
|
48
|
-
|
51
|
+
|
49
52
|
end
|
50
|
-
|
53
|
+
|
51
54
|
# Render the specified item, with the specified options.
|
52
55
|
#
|
53
56
|
# ==== Parameters
|
54
|
-
# thing<String, Symbol, nil>::
|
57
|
+
# thing<String, Symbol, nil>::
|
55
58
|
# The thing to render. This will default to the current action
|
56
59
|
# opts<Hash>:: An options hash (see below)
|
57
60
|
#
|
58
61
|
# ==== Options (opts)
|
59
62
|
# :format<Symbol>:: A registered mime-type format
|
60
|
-
# :template<String>::
|
63
|
+
# :template<String>::
|
61
64
|
# The path to the template relative to the template root
|
62
|
-
# :status<~to_i>::
|
65
|
+
# :status<~to_i>::
|
63
66
|
# The status to send to the client. Typically, this would be an integer
|
64
67
|
# (200), or a Merb status code (Accepted)
|
65
|
-
# :layout<~to_s>::
|
68
|
+
# :layout<~to_s, FalseClass>::
|
66
69
|
# A layout to use instead of the default. This should be relative to the
|
67
70
|
# layout root. By default, the layout will be either the controller_name or
|
68
71
|
# application. If you want to use an alternative content-type than the one
|
69
72
|
# that the base template was rendered as, you will need to do :layout =>
|
70
|
-
# "foo.#{content_type}" (i.e. "foo.json")
|
73
|
+
# "foo.#{content_type}" (i.e. "foo.json"). If you want to render without
|
74
|
+
# layout, use :layout => false. This overrides layout set by +layout+ method.
|
71
75
|
#
|
72
76
|
# ==== Returns
|
73
77
|
# String:: The rendered template, including layout, if appropriate.
|
74
78
|
#
|
75
79
|
# ==== Raises
|
76
80
|
# TemplateNotFound:: There is no template for the specified location.
|
77
|
-
#
|
81
|
+
#
|
78
82
|
# ==== Alternatives
|
79
83
|
# If you pass a Hash as the first parameter, it will be moved to opts and
|
80
84
|
# "thing" will be the current action
|
@@ -83,59 +87,65 @@ module Merb::RenderMixin
|
|
83
87
|
def render(thing = nil, opts = {})
|
84
88
|
# render :format => :xml means render nil, :format => :xml
|
85
89
|
opts, thing = thing, nil if thing.is_a?(Hash)
|
86
|
-
|
90
|
+
|
87
91
|
# Merge with class level default render options
|
88
92
|
opts = self.class.default_render_options.merge(opts)
|
89
|
-
|
93
|
+
|
90
94
|
# If you don't specify a thing to render, assume they want to render the current action
|
91
95
|
thing ||= action_name.to_sym
|
92
96
|
|
93
97
|
# Content negotiation
|
94
|
-
opts[:format] ? (self.content_type = opts[:format]) : content_type
|
95
|
-
|
98
|
+
opts[:format] ? (self.content_type = opts[:format]) : content_type
|
99
|
+
|
96
100
|
# Handle options (:status)
|
97
|
-
_handle_options!(opts)
|
98
|
-
|
101
|
+
_handle_options!(opts)
|
102
|
+
|
99
103
|
# Do we have a template to try to render?
|
100
104
|
if thing.is_a?(Symbol) || opts[:template]
|
101
105
|
|
102
|
-
template_method, template_location =
|
103
|
-
|
106
|
+
template_method, template_location =
|
107
|
+
_template_for(thing, content_type, controller_name, opts[:template])
|
108
|
+
|
104
109
|
# Raise an error if there's no template
|
105
|
-
|
106
|
-
|
110
|
+
unless template_method && self.respond_to?(template_method)
|
111
|
+
template_files = Merb::Template.template_extensions.map { |ext| "#{template_location}.#{ext}" }
|
112
|
+
raise TemplateNotFound, "Oops! No template found. Merb was looking for #{template_files.join(', ')}" +
|
113
|
+
"for content type '#{content_type}'. You might have mispelled the template or file name. " +
|
114
|
+
"Registered template extensions: #{Merb::Template.template_extensions.join(', ')}. " +
|
115
|
+
"If you use Haml or some other template plugin, make sure you required Merb plugin dependency " +
|
116
|
+
"in your init file."
|
117
|
+
end
|
107
118
|
|
108
119
|
# Call the method in question and throw the content for later consumption by the layout
|
109
120
|
throw_content(:for_layout, self.send(template_method))
|
110
|
-
|
121
|
+
|
111
122
|
# Do we have a string to render?
|
112
123
|
elsif thing.is_a?(String)
|
113
|
-
|
124
|
+
|
114
125
|
# Throw it for later consumption by the layout
|
115
126
|
throw_content(:for_layout, thing)
|
116
127
|
end
|
117
|
-
|
128
|
+
|
118
129
|
# If we find a layout, use it. Otherwise, just render the content thrown for layout.
|
119
|
-
layout = opts[:layout]
|
120
|
-
layout ? send(layout) : catch_content(:for_layout)
|
130
|
+
(layout = _get_layout(opts[:layout])) ? send(layout) : catch_content(:for_layout)
|
121
131
|
end
|
122
|
-
|
132
|
+
|
123
133
|
# Renders an object using to registered transform method based on the
|
124
134
|
# negotiated content-type, if a template does not exist. For instance, if the
|
125
135
|
# content-type is :json, Merb will first look for current_action.json.*.
|
126
136
|
# Failing that, it will run object.to_json.
|
127
137
|
#
|
128
138
|
# ==== Parameter
|
129
|
-
# object<Object>::
|
139
|
+
# object<Object>::
|
130
140
|
# An object that responds_to? the transform method registered for the
|
131
141
|
# negotiated mime-type.
|
132
142
|
# thing<String, Symbol>::
|
133
143
|
# The thing to attempt to render via #render before calling the transform
|
134
144
|
# method on the object. Defaults to nil.
|
135
|
-
# opts<Hash>::
|
145
|
+
# opts<Hash>::
|
136
146
|
# An options hash that will be used for rendering
|
137
147
|
# (passed on to #render or serialization methods like #to_json or #to_xml)
|
138
|
-
#
|
148
|
+
#
|
139
149
|
# ==== Returns
|
140
150
|
# String::
|
141
151
|
# The rendered template or if no template is found, the transformed object.
|
@@ -144,10 +154,10 @@ module Merb::RenderMixin
|
|
144
154
|
# NotAcceptable::
|
145
155
|
# If there is no transform method for the specified mime-type or the object
|
146
156
|
# does not respond to the transform method.
|
147
|
-
#
|
157
|
+
#
|
148
158
|
# ==== Alternatives
|
149
159
|
# A string in the second parameter will be interpreted as a template:
|
150
|
-
# display @object, "path/to/foo"
|
160
|
+
# display @object, "path/to/foo"
|
151
161
|
# #=> display @object, nil, :template => "path/to/foo"
|
152
162
|
#
|
153
163
|
# A hash in the second parameters will be interpreted as opts:
|
@@ -157,18 +167,20 @@ module Merb::RenderMixin
|
|
157
167
|
# If you need to pass extra parameters to serialization method, for instance,
|
158
168
|
# to exclude some of attributes or serialize associations, just pass options
|
159
169
|
# for it.
|
160
|
-
# For instance,
|
170
|
+
# For instance,
|
161
171
|
#
|
162
|
-
# display
|
172
|
+
# display @locations, :except => [:locatable_type, :locatable_id], :include => [:locatable]
|
173
|
+
#
|
174
|
+
# serializes object with polymorphic association, not raw locatable_* attributes.
|
163
175
|
#
|
164
|
-
# serializes object with polymorphic association, not raw locatable_* attributes.
|
165
176
|
#
|
166
|
-
#
|
167
177
|
# ==== Options
|
168
178
|
#
|
169
179
|
# :template a template to use for rendering
|
170
180
|
# :layout a layout to use for rendering
|
171
|
-
|
181
|
+
# :status the status code to return (defaults to 200)
|
182
|
+
# :location the value of the Location header
|
183
|
+
#
|
172
184
|
# all other options options that will be pass to serialization method
|
173
185
|
# like #to_json or #to_xml
|
174
186
|
#
|
@@ -177,62 +189,50 @@ module Merb::RenderMixin
|
|
177
189
|
# explicitly passed in the opts.
|
178
190
|
#
|
179
191
|
def display(object, thing = nil, opts = {})
|
180
|
-
# display @object, "path/to/foo" means display @object, nil, :template => "path/to/foo"
|
181
|
-
# display @object, :template => "path/to/foo" means display @object, nil, :template => "path/to/foo"
|
182
192
|
template_opt = opts.delete(:template)
|
183
|
-
|
193
|
+
|
184
194
|
case thing
|
195
|
+
# display @object, "path/to/foo" means display @object, nil, :template => "path/to/foo"
|
185
196
|
when String
|
186
197
|
template_opt, thing = thing, nil
|
198
|
+
# display @object, :template => "path/to/foo" means display @object, nil, :template => "path/to/foo"
|
187
199
|
when Hash
|
188
200
|
opts, thing = thing, nil
|
189
201
|
end
|
190
|
-
|
202
|
+
|
191
203
|
# Try to render without the object
|
192
204
|
render(thing || action_name.to_sym, opts.merge(:template => template_opt))
|
193
|
-
|
205
|
+
|
194
206
|
# If the render fails (i.e. a template was not found)
|
195
|
-
rescue TemplateNotFound
|
207
|
+
rescue TemplateNotFound => e
|
196
208
|
# Merge with class level default render options
|
209
|
+
# @todo can we find a way to refactor this out so we don't have to do it everywhere?
|
197
210
|
opts = self.class.default_render_options.merge(opts)
|
198
|
-
|
211
|
+
|
199
212
|
# Figure out what to transform and raise NotAcceptable unless there's a transform method assigned
|
200
213
|
transform = Merb.mime_transform_method(content_type)
|
201
|
-
|
214
|
+
if !transform
|
215
|
+
raise NotAcceptable, "#{e.message} and there was no transform method registered for #{content_type.inspect}"
|
216
|
+
elsif !object.respond_to?(transform)
|
217
|
+
raise NotAcceptable, "#{e.message} and your object does not respond to ##{transform}"
|
218
|
+
end
|
202
219
|
|
203
|
-
# Only use a layout if one was specified
|
204
220
|
layout_opt = opts.delete(:layout)
|
221
|
+
_handle_options!(opts)
|
222
|
+
throw_content(:for_layout, opts.empty? ? object.send(transform) : object.send(transform, opts))
|
205
223
|
|
206
|
-
if layout_opt
|
207
|
-
|
208
|
-
# the TemplateNotFound error
|
209
|
-
template = _template_location(layout_opt, layout.index(".") ? content_type : nil, "layout")
|
210
|
-
layout = _template_for(_template_root / template) ||
|
211
|
-
(raise TemplateNotFound, "No layout found at #{_template_root / template}.*")
|
212
|
-
|
213
|
-
# If the layout was found, call it
|
214
|
-
send(layout)
|
215
|
-
|
216
|
-
# Otherwise, just render the transformed object
|
217
|
-
else
|
218
|
-
unless opts.empty?
|
219
|
-
# there are options for serialization method
|
220
|
-
throw_content(:for_layout, object.send(transform, opts))
|
221
|
-
else
|
222
|
-
throw_content(:for_layout, object.send(transform))
|
223
|
-
end
|
224
|
-
catch_content(:for_layout)
|
225
|
-
end
|
224
|
+
meth, _ = _template_for(layout_opt, layout_opt.to_s.index(".") ? nil : content_type, "layout") if layout_opt
|
225
|
+
meth ? send(meth) : catch_content(:for_layout)
|
226
226
|
end
|
227
227
|
|
228
228
|
# Render a partial template.
|
229
229
|
#
|
230
230
|
# ==== Parameters
|
231
231
|
# template<~to_s>::
|
232
|
-
# The path to the template, relative to the current controller or the
|
233
|
-
# template root. If the template contains a "/",
|
234
|
-
# relative to the template root; otherwise,
|
235
|
-
# relative to the current controller.
|
232
|
+
# The path to the template, relative to the current controller or the
|
233
|
+
# template root; absolute path will work too. If the template contains a "/",
|
234
|
+
# Merb will search for it relative to the template root; otherwise,
|
235
|
+
# Merb will search for it relative to the current controller.
|
236
236
|
# opts<Hash>:: A hash of options (see below)
|
237
237
|
#
|
238
238
|
# ==== Options (opts)
|
@@ -244,56 +244,95 @@ module Merb::RenderMixin
|
|
244
244
|
# A Hash object names and values that will be the local names and values
|
245
245
|
# inside the partial.
|
246
246
|
#
|
247
|
-
# ====
|
247
|
+
# ==== Examples
|
248
248
|
# partial :foo, :hello => @object
|
249
249
|
#
|
250
250
|
# The "_foo" partial will be called, relative to the current controller,
|
251
251
|
# with a local variable of +hello+ inside of it, assigned to @object.
|
252
|
+
#
|
253
|
+
# partial :bar, :with => ['one', 'two', 'three']
|
254
|
+
#
|
255
|
+
# The "_bar" partial will be called once for each element of the array
|
256
|
+
# specified by :with for a total of three iterations. Each element
|
257
|
+
# of the array will be available in the partial via a local variable named
|
258
|
+
# +bar+. Additionally, there will be two extra local variables:
|
259
|
+
# +collection_index+ and +collection_size+. +collection_index+ is the index
|
260
|
+
# of the object currently referenced by +bar+ in the collection passed to
|
261
|
+
# the partial. +collection_size+ is the total size of the collection.
|
262
|
+
#
|
263
|
+
# By default, the object specified by :with will be available through a
|
264
|
+
# local variable with the same name as the partial template. However,
|
265
|
+
# this can be changed using the :as option.
|
266
|
+
#
|
267
|
+
# partial :bar, :with => "one", :as => :number
|
268
|
+
#
|
269
|
+
# In this case, "one" will be available in the partial through the local
|
270
|
+
# variable named +number+.
|
271
|
+
#
|
272
|
+
# ==== Notes
|
273
|
+
# It is important to note that the object being passed to the partial
|
274
|
+
# as well as any extra local variables cannot use names of helper methods
|
275
|
+
# since any helper method of the same name will take precedence over the
|
276
|
+
# passed variable. Example:
|
277
|
+
#
|
278
|
+
# partial :bar, :with => "one", :as => :partial
|
279
|
+
#
|
280
|
+
# In this case, "one" will not be available in the partial because "partial"
|
281
|
+
# is already a helper method.
|
252
282
|
def partial(template, opts={})
|
253
283
|
|
254
284
|
# partial :foo becomes "#{controller_name}/_foo"
|
255
285
|
# partial "foo/bar" becomes "foo/_bar"
|
256
286
|
template = template.to_s
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
287
|
+
if template =~ %r{^/}
|
288
|
+
template_path = File.dirname(template) / "_#{File.basename(template)}"
|
289
|
+
else
|
290
|
+
kontroller = (m = template.match(/.*(?=\/)/)) ? m[0] : controller_name
|
291
|
+
template = "_#{File.basename(template)}"
|
292
|
+
end
|
293
|
+
template_method, template_location =
|
294
|
+
_template_for(template, opts.delete(:format) || content_type, kontroller, template_path)
|
261
295
|
|
262
296
|
(@_old_partial_locals ||= []).push @_merb_partial_locals
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
297
|
+
|
298
|
+
# This handles no :with as well
|
299
|
+
with = [opts.delete(:with)].flatten
|
300
|
+
as = opts.delete(:as) || template_location.match(%r[.*/_([^\.]*)])[1]
|
301
|
+
|
302
|
+
@_merb_partial_locals = opts.merge(:collection_index => -1, :collection_size => with.size)
|
303
|
+
|
304
|
+
# this handles an edge-case where the name of the partial is _foo.* and your opts
|
305
|
+
# have :foo as a key.
|
306
|
+
named_local = @_merb_partial_locals.key?(as.to_sym)
|
307
|
+
|
308
|
+
sent_template = with.map do |temp|
|
309
|
+
@_merb_partial_locals[as.to_sym] = temp unless named_local
|
274
310
|
if template_method && self.respond_to?(template_method)
|
275
|
-
|
311
|
+
@_merb_partial_locals[:collection_index] += 1
|
312
|
+
send(template_method)
|
276
313
|
else
|
277
314
|
raise TemplateNotFound, "Could not find template at #{template_location}.*"
|
278
315
|
end
|
279
|
-
end
|
316
|
+
end.join
|
317
|
+
|
280
318
|
@_merb_partial_locals = @_old_partial_locals.pop
|
281
319
|
sent_template
|
282
|
-
end
|
283
|
-
|
320
|
+
end
|
321
|
+
|
284
322
|
# Take the options hash and handle it as appropriate.
|
285
|
-
#
|
323
|
+
#
|
286
324
|
# ==== Parameters
|
287
325
|
# opts<Hash>:: The options hash that was passed into render.
|
288
|
-
#
|
326
|
+
#
|
289
327
|
# ==== Options
|
290
328
|
# :status<~to_i>::
|
291
329
|
# The status of the response will be set to opts[:status].to_i
|
292
|
-
#
|
330
|
+
#
|
293
331
|
# ==== Returns
|
294
332
|
# Hash:: The options hash that was passed in.
|
295
333
|
def _handle_options!(opts)
|
296
|
-
self.status = opts
|
334
|
+
self.status = opts.delete(:status).to_i if opts[:status]
|
335
|
+
headers["Location"] = opts.delete(:location) if opts[:location]
|
297
336
|
opts
|
298
337
|
end
|
299
338
|
|
@@ -305,22 +344,26 @@ module Merb::RenderMixin
|
|
305
344
|
#
|
306
345
|
# ==== Parameters
|
307
346
|
# layout<~to_s>:: A layout, relative to the layout root. Defaults to nil.
|
308
|
-
#
|
347
|
+
#
|
309
348
|
# ==== Returns
|
310
349
|
# String:: The method name that corresponds to the found layout.
|
311
|
-
#
|
350
|
+
#
|
312
351
|
# ==== Raises
|
313
352
|
# TemplateNotFound::
|
314
353
|
# If a layout was specified (either via layout in the class or by passing
|
315
354
|
# one in to this method), and not found. No error will be raised if no
|
316
355
|
# layout was specified, and the default layouts were not found.
|
317
356
|
def _get_layout(layout = nil)
|
357
|
+
return false if layout == false
|
358
|
+
|
318
359
|
layout = layout.instance_of?(Symbol) && self.respond_to?(layout, true) ? send(layout) : layout
|
319
360
|
layout = layout.to_s if layout
|
320
|
-
|
361
|
+
|
321
362
|
# If a layout was provided, throw an error if it's not found
|
322
|
-
if layout
|
323
|
-
template_method, template_location =
|
363
|
+
if layout
|
364
|
+
template_method, template_location =
|
365
|
+
_template_for(layout, layout.index(".") ? nil : content_type, "layout")
|
366
|
+
|
324
367
|
raise TemplateNotFound, "No layout found at #{template_location}" unless template_method
|
325
368
|
template_method
|
326
369
|
|
@@ -331,13 +374,13 @@ module Merb::RenderMixin
|
|
331
374
|
template
|
332
375
|
end
|
333
376
|
end
|
334
|
-
|
335
|
-
# Iterate over the template roots in reverse order, and return the template
|
377
|
+
|
378
|
+
# Iterate over the template roots in reverse order, and return the template
|
336
379
|
# and template location of the first match.
|
337
380
|
#
|
338
381
|
# ==== Parameters
|
339
|
-
# context<Object>:: The controller action or template basename.
|
340
|
-
# content_type<~to_s>:: The content type
|
382
|
+
# context<Object>:: The controller action or template (basename or absolute path).
|
383
|
+
# content_type<~to_s>:: The content type (like html or json).
|
341
384
|
# controller<~to_s>:: The name of the controller. Defaults to nil.
|
342
385
|
#
|
343
386
|
# ==== Options (opts)
|
@@ -348,25 +391,44 @@ module Merb::RenderMixin
|
|
348
391
|
# ==== Returns
|
349
392
|
# Array[Symbol, String]::
|
350
393
|
# A pair consisting of the template method and location.
|
351
|
-
def _template_for(context, content_type, controller=nil,
|
352
|
-
template_method = nil
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
394
|
+
def _template_for(context, content_type, controller=nil, template=nil)
|
395
|
+
template_method, template_location = nil, nil
|
396
|
+
|
397
|
+
# absolute path to a template (:template => "/foo/bar")
|
398
|
+
if template.is_a?(String) && template =~ %r{^/}
|
399
|
+
template_location = self._absolute_template_location(template, content_type)
|
400
|
+
return [_template_method_for(template_location), template_location]
|
401
|
+
end
|
402
|
+
|
403
|
+
self.class._template_roots.reverse_each do |root, template_meth|
|
404
|
+
# :template => "foo/bar.html" where root / "foo/bar.html.*" exists
|
405
|
+
if template
|
406
|
+
template_location = root / self.send(template_meth, template, content_type, nil)
|
407
|
+
# :layout => "foo" where root / "layouts" / "#{controller}.html.*" exists
|
408
|
+
else
|
409
|
+
template_location = root / self.send(template_meth, context, content_type, controller)
|
360
410
|
end
|
361
411
|
|
362
|
-
|
363
|
-
template_method = Merb::Template.template_for(template_location)
|
364
|
-
break if template_method && self.respond_to?(template_method)
|
412
|
+
break if template_method = _template_method_for(template_location.to_s)
|
365
413
|
end
|
366
414
|
|
367
|
-
|
415
|
+
# template_location is a Pathname
|
416
|
+
[template_method, template_location.to_s]
|
368
417
|
end
|
369
|
-
|
418
|
+
|
419
|
+
# Return the template method for a location, and check to make sure the current controller
|
420
|
+
# actually responds to the method.
|
421
|
+
#
|
422
|
+
# ==== Parameters
|
423
|
+
# template_location<String>:: The phyical path of the template
|
424
|
+
#
|
425
|
+
# ==== Returns
|
426
|
+
# String:: The method, if it exists. Otherwise return nil.
|
427
|
+
def _template_method_for(template_location)
|
428
|
+
meth = Merb::Template.template_for(template_location)
|
429
|
+
meth && self.respond_to?(meth) ? meth : nil
|
430
|
+
end
|
431
|
+
|
370
432
|
# Called in templates to get at content thrown in another template. The
|
371
433
|
# results of rendering a template are automatically thrown into :for_layout,
|
372
434
|
# so catch_content or catch_content(:for_layout) can be used inside layouts
|
@@ -377,9 +439,9 @@ module Merb::RenderMixin
|
|
377
439
|
#---
|
378
440
|
# @public
|
379
441
|
def catch_content(obj = :for_layout)
|
380
|
-
@_caught_content[obj]
|
442
|
+
@_caught_content[obj] * '' unless @_caught_content[obj].nil?
|
381
443
|
end
|
382
|
-
|
444
|
+
|
383
445
|
# Called in templates to test for the existence of previously thrown content.
|
384
446
|
#
|
385
447
|
# ==== Parameters
|
@@ -389,7 +451,7 @@ module Merb::RenderMixin
|
|
389
451
|
def thrown_content?(obj = :for_layout)
|
390
452
|
@_caught_content.key?(obj)
|
391
453
|
end
|
392
|
-
|
454
|
+
|
393
455
|
# Called in templates to store up content for later use. Takes a string
|
394
456
|
# and/or a block. First, the string is evaluated, and then the block is
|
395
457
|
# captured using the capture() helper provided by the template languages. The
|
@@ -412,7 +474,8 @@ module Merb::RenderMixin
|
|
412
474
|
unless string || block_given?
|
413
475
|
raise ArgumentError, "You must pass a block or a string into throw_content"
|
414
476
|
end
|
415
|
-
@_caught_content[obj] =
|
477
|
+
@_caught_content[obj] = [] if @_caught_content[obj].nil?
|
478
|
+
@_caught_content[obj] << string.to_s << (block_given? ? capture(&block) : "")
|
416
479
|
end
|
417
|
-
|
480
|
+
|
418
481
|
end
|