actionview 7.1.5.2 → 8.1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +96 -436
  3. data/README.rdoc +1 -1
  4. data/lib/action_view/base.rb +29 -11
  5. data/lib/action_view/buffers.rb +1 -1
  6. data/lib/action_view/cache_expiry.rb +9 -3
  7. data/lib/action_view/dependency_tracker/erb_tracker.rb +37 -28
  8. data/lib/action_view/dependency_tracker/ruby_tracker.rb +43 -0
  9. data/lib/action_view/dependency_tracker/wildcard_resolver.rb +32 -0
  10. data/lib/action_view/dependency_tracker.rb +8 -2
  11. data/lib/action_view/digestor.rb +6 -2
  12. data/lib/action_view/gem_version.rb +3 -3
  13. data/lib/action_view/helpers/asset_tag_helper.rb +39 -8
  14. data/lib/action_view/helpers/atom_feed_helper.rb +1 -3
  15. data/lib/action_view/helpers/cache_helper.rb +10 -2
  16. data/lib/action_view/helpers/capture_helper.rb +2 -2
  17. data/lib/action_view/helpers/controller_helper.rb +6 -2
  18. data/lib/action_view/helpers/csrf_helper.rb +1 -1
  19. data/lib/action_view/helpers/date_helper.rb +28 -4
  20. data/lib/action_view/helpers/form_helper.rb +277 -272
  21. data/lib/action_view/helpers/form_options_helper.rb +39 -35
  22. data/lib/action_view/helpers/form_tag_helper.rb +115 -72
  23. data/lib/action_view/helpers/javascript_helper.rb +5 -1
  24. data/lib/action_view/helpers/number_helper.rb +14 -0
  25. data/lib/action_view/helpers/output_safety_helper.rb +5 -6
  26. data/lib/action_view/helpers/rendering_helper.rb +160 -50
  27. data/lib/action_view/helpers/sanitize_helper.rb +6 -0
  28. data/lib/action_view/helpers/tag_helper.rb +225 -48
  29. data/lib/action_view/helpers/tags/base.rb +11 -9
  30. data/lib/action_view/helpers/tags/check_box.rb +9 -3
  31. data/lib/action_view/helpers/tags/collection_check_boxes.rb +4 -3
  32. data/lib/action_view/helpers/tags/collection_helpers.rb +2 -1
  33. data/lib/action_view/helpers/tags/datetime_field.rb +1 -1
  34. data/lib/action_view/helpers/tags/file_field.rb +7 -2
  35. data/lib/action_view/helpers/tags/hidden_field.rb +1 -1
  36. data/lib/action_view/helpers/tags/label.rb +3 -10
  37. data/lib/action_view/helpers/tags/radio_button.rb +1 -1
  38. data/lib/action_view/helpers/tags/select.rb +6 -1
  39. data/lib/action_view/helpers/tags/select_renderer.rb +6 -4
  40. data/lib/action_view/helpers/tags/text_area.rb +1 -1
  41. data/lib/action_view/helpers/tags/text_field.rb +1 -1
  42. data/lib/action_view/helpers/text_helper.rb +11 -4
  43. data/lib/action_view/helpers/translation_helper.rb +6 -1
  44. data/lib/action_view/helpers/url_helper.rb +42 -90
  45. data/lib/action_view/layouts.rb +9 -11
  46. data/lib/action_view/locale/en.yml +3 -0
  47. data/lib/action_view/log_subscriber.rb +9 -8
  48. data/lib/action_view/railtie.rb +12 -2
  49. data/lib/action_view/record_identifier.rb +22 -1
  50. data/lib/action_view/render_parser/prism_render_parser.rb +139 -0
  51. data/lib/action_view/{ripper_ast_parser.rb → render_parser/ripper_render_parser.rb} +162 -10
  52. data/lib/action_view/render_parser.rb +21 -169
  53. data/lib/action_view/renderer/abstract_renderer.rb +1 -1
  54. data/lib/action_view/renderer/partial_renderer.rb +18 -2
  55. data/lib/action_view/renderer/renderer.rb +32 -38
  56. data/lib/action_view/renderer/streaming_template_renderer.rb +8 -2
  57. data/lib/action_view/renderer/template_renderer.rb +3 -3
  58. data/lib/action_view/rendering.rb +6 -7
  59. data/lib/action_view/structured_event_subscriber.rb +97 -0
  60. data/lib/action_view/template/error.rb +18 -3
  61. data/lib/action_view/template/handlers/erb/erubi.rb +1 -1
  62. data/lib/action_view/template/handlers/erb.rb +77 -44
  63. data/lib/action_view/template/raw_file.rb +4 -0
  64. data/lib/action_view/template/renderable.rb +7 -1
  65. data/lib/action_view/template/resolver.rb +0 -3
  66. data/lib/action_view/template.rb +39 -12
  67. data/lib/action_view/test_case.rb +57 -62
  68. data/lib/action_view.rb +4 -0
  69. metadata +17 -14
  70. data/lib/action_view/dependency_tracker/ripper_tracker.rb +0 -59
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "ripper"
4
-
5
3
  module ActionView
6
- class RenderParser
7
- module RipperASTParser # :nodoc:
4
+ module RenderParser
5
+ class RipperRenderParser < Base # :nodoc:
8
6
  class Node < ::Array # :nodoc:
9
7
  attr_reader :type
10
8
 
@@ -68,7 +66,16 @@ module ActionView
68
66
 
69
67
  def to_string
70
68
  raise unless string?
71
- self[0][0][0]
69
+
70
+ # s(:string_literal, s(:string_content, map))
71
+ self[0].map do |node|
72
+ case node.type
73
+ when :@tstring_content
74
+ node[0]
75
+ when :string_embexpr
76
+ "*"
77
+ end
78
+ end.join("")
72
79
  end
73
80
 
74
81
  def hash?
@@ -183,16 +190,161 @@ module ActionView
183
190
  end
184
191
  end
185
192
 
186
- extend self
187
-
188
- def parse_render_nodes(code)
189
- parser = RenderCallExtractor.new(code)
193
+ def render_calls
194
+ parser = RenderCallExtractor.new(@code)
190
195
  parser.parse
191
196
 
192
197
  parser.render_calls.group_by(&:first).to_h do |method, nodes|
193
198
  [ method.to_sym, nodes.collect { |v| v[1] } ]
194
- end
199
+ end.map do |method, nodes|
200
+ nodes.map { |n| parse_render(n) }
201
+ end.flatten.compact
195
202
  end
203
+
204
+ private
205
+ def resolve_path_directory(path)
206
+ if path.include?("/")
207
+ path
208
+ else
209
+ "#{directory}/#{path}"
210
+ end
211
+ end
212
+
213
+ # Convert
214
+ # render("foo", ...)
215
+ # into either
216
+ # render(template: "foo", ...)
217
+ # or
218
+ # render(partial: "foo", ...)
219
+ def normalize_args(string, options_hash)
220
+ if options_hash
221
+ { partial: string, locals: options_hash }
222
+ else
223
+ { partial: string }
224
+ end
225
+ end
226
+
227
+ def parse_render(node)
228
+ node = node.argument_nodes
229
+
230
+ if (node.length == 1 || node.length == 2) && !node[0].hash?
231
+ if node.length == 1
232
+ options = normalize_args(node[0], nil)
233
+ elsif node.length == 2
234
+ options = normalize_args(node[0], node[1])
235
+ end
236
+
237
+ return nil unless options
238
+
239
+ parse_render_from_options(options)
240
+ elsif node.length == 1 && node[0].hash?
241
+ options = parse_hash_to_symbols(node[0])
242
+
243
+ return nil unless options
244
+
245
+ parse_render_from_options(options)
246
+ else
247
+ nil
248
+ end
249
+ end
250
+
251
+ def parse_hash(node)
252
+ node.hash? && node.to_hash
253
+ end
254
+
255
+ def parse_hash_to_symbols(node)
256
+ hash = parse_hash(node)
257
+
258
+ return unless hash
259
+
260
+ hash.transform_keys do |key_node|
261
+ key = parse_sym(key_node)
262
+
263
+ return unless key
264
+
265
+ key
266
+ end
267
+ end
268
+
269
+ def parse_render_from_options(options_hash)
270
+ renders = []
271
+ keys = options_hash.keys
272
+
273
+ if (keys & RENDER_TYPE_KEYS).size < 1
274
+ # Must have at least one of render keys
275
+ return nil
276
+ end
277
+
278
+ if (keys - ALL_KNOWN_KEYS).any?
279
+ # de-opt in case of unknown option
280
+ return nil
281
+ end
282
+
283
+ render_type = (keys & RENDER_TYPE_KEYS)[0]
284
+
285
+ node = options_hash[render_type]
286
+
287
+ if node.string?
288
+ template = resolve_path_directory(node.to_string)
289
+ else
290
+ if node.variable_reference?
291
+ dependency = node.variable_name.sub(/\A(?:\$|@{1,2})/, "")
292
+ elsif node.vcall?
293
+ dependency = node.variable_name
294
+ elsif node.call?
295
+ dependency = node.call_method_name
296
+ else
297
+ return
298
+ end
299
+
300
+ object_template = true
301
+ template = "#{dependency.pluralize}/#{dependency.singularize}"
302
+ end
303
+
304
+ return unless template
305
+
306
+ if spacer_template = render_template_with_spacer?(options_hash)
307
+ virtual_path = partial_to_virtual_path(:partial, spacer_template)
308
+ renders << virtual_path
309
+ end
310
+
311
+ if options_hash.key?(:object) || options_hash.key?(:collection) || object_template
312
+ return nil if options_hash.key?(:object) && options_hash.key?(:collection)
313
+ return nil unless options_hash.key?(:partial)
314
+ end
315
+
316
+ virtual_path = partial_to_virtual_path(render_type, template)
317
+ renders << virtual_path
318
+
319
+ # Support for rendering multiple templates (i.e. a partial with a layout)
320
+ if layout_template = render_template_with_layout?(render_type, options_hash)
321
+ virtual_path = partial_to_virtual_path(:layout, layout_template)
322
+
323
+ renders << virtual_path
324
+ end
325
+
326
+ renders
327
+ end
328
+
329
+ def parse_str(node)
330
+ node.string? && node.to_string
331
+ end
332
+
333
+ def parse_sym(node)
334
+ node.symbol? && node.to_symbol
335
+ end
336
+
337
+ def render_template_with_layout?(render_type, options_hash)
338
+ if render_type != :layout && options_hash.key?(:layout)
339
+ parse_str(options_hash[:layout])
340
+ end
341
+ end
342
+
343
+ def render_template_with_spacer?(options_hash)
344
+ if options_hash.key?(:spacer_template)
345
+ parse_str(options_hash[:spacer_template])
346
+ end
347
+ end
196
348
  end
197
349
  end
198
350
  end
@@ -1,176 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "action_view/ripper_ast_parser"
4
-
5
3
  module ActionView
6
- class RenderParser # :nodoc:
7
- def initialize(name, code)
8
- @name = name
9
- @code = code
10
- @parser = RipperASTParser
11
- end
12
-
13
- def render_calls
14
- render_nodes = @parser.parse_render_nodes(@code)
15
-
16
- render_nodes.map do |method, nodes|
17
- nodes.map { |n| send(:parse_render, n) }
18
- end.flatten.compact
19
- end
4
+ module RenderParser # :nodoc:
5
+ ALL_KNOWN_KEYS = [:partial, :template, :layout, :formats, :locals, :object, :collection, :as, :status, :content_type, :location, :spacer_template]
6
+ RENDER_TYPE_KEYS = [:partial, :template, :layout]
20
7
 
21
- private
22
- def directory
23
- File.dirname(@name)
24
- end
25
-
26
- def resolve_path_directory(path)
27
- if path.include?("/")
28
- path
29
- else
30
- "#{directory}/#{path}"
31
- end
32
- end
33
-
34
- # Convert
35
- # render("foo", ...)
36
- # into either
37
- # render(template: "foo", ...)
38
- # or
39
- # render(partial: "foo", ...)
40
- def normalize_args(string, options_hash)
41
- if options_hash
42
- { partial: string, locals: options_hash }
43
- else
44
- { partial: string }
45
- end
46
- end
47
-
48
- def parse_render(node)
49
- node = node.argument_nodes
50
-
51
- if (node.length == 1 || node.length == 2) && !node[0].hash?
52
- if node.length == 1
53
- options = normalize_args(node[0], nil)
54
- elsif node.length == 2
55
- options = normalize_args(node[0], node[1])
56
- end
57
-
58
- return nil unless options
59
-
60
- parse_render_from_options(options)
61
- elsif node.length == 1 && node[0].hash?
62
- options = parse_hash_to_symbols(node[0])
63
-
64
- return nil unless options
65
-
66
- parse_render_from_options(options)
67
- else
68
- nil
69
- end
70
- end
71
-
72
- def parse_hash(node)
73
- node.hash? && node.to_hash
74
- end
75
-
76
- def parse_hash_to_symbols(node)
77
- hash = parse_hash(node)
78
-
79
- return unless hash
80
-
81
- hash.transform_keys do |key_node|
82
- key = parse_sym(key_node)
83
-
84
- return unless key
85
-
86
- key
87
- end
88
- end
89
-
90
- ALL_KNOWN_KEYS = [:partial, :template, :layout, :formats, :locals, :object, :collection, :as, :status, :content_type, :location, :spacer_template]
91
-
92
- RENDER_TYPE_KEYS =
93
- [:partial, :template, :layout]
94
-
95
- def parse_render_from_options(options_hash)
96
- renders = []
97
- keys = options_hash.keys
98
-
99
- if (keys & RENDER_TYPE_KEYS).size < 1
100
- # Must have at least one of render keys
101
- return nil
102
- end
103
-
104
- if (keys - ALL_KNOWN_KEYS).any?
105
- # de-opt in case of unknown option
106
- return nil
107
- end
108
-
109
- render_type = (keys & RENDER_TYPE_KEYS)[0]
110
-
111
- node = options_hash[render_type]
112
-
113
- if node.string?
114
- template = resolve_path_directory(node.to_string)
115
- else
116
- if node.variable_reference?
117
- dependency = node.variable_name.sub(/\A(?:\$|@{1,2})/, "")
118
- elsif node.vcall?
119
- dependency = node.variable_name
120
- elsif node.call?
121
- dependency = node.call_method_name
122
- else
123
- return
124
- end
125
-
126
- object_template = true
127
- template = "#{dependency.pluralize}/#{dependency.singularize}"
128
- end
129
-
130
- return unless template
131
-
132
- if spacer_template = render_template_with_spacer?(options_hash)
133
- virtual_path = partial_to_virtual_path(:partial, spacer_template)
134
- renders << virtual_path
135
- end
136
-
137
- if options_hash.key?(:object) || options_hash.key?(:collection) || object_template
138
- return nil if options_hash.key?(:object) && options_hash.key?(:collection)
139
- return nil unless options_hash.key?(:partial)
140
- end
141
-
142
- virtual_path = partial_to_virtual_path(render_type, template)
143
- renders << virtual_path
144
-
145
- # Support for rendering multiple templates (i.e. a partial with a layout)
146
- if layout_template = render_template_with_layout?(render_type, options_hash)
147
- virtual_path = partial_to_virtual_path(:layout, layout_template)
148
-
149
- renders << virtual_path
150
- end
151
-
152
- renders
153
- end
154
-
155
- def parse_str(node)
156
- node.string? && node.to_string
157
- end
158
-
159
- def parse_sym(node)
160
- node.symbol? && node.to_symbol
8
+ class Base # :nodoc:
9
+ def initialize(name, code)
10
+ @name = name
11
+ @code = code
161
12
  end
162
13
 
163
14
  private
164
- def render_template_with_layout?(render_type, options_hash)
165
- if render_type != :layout && options_hash.key?(:layout)
166
- parse_str(options_hash[:layout])
167
- end
168
- end
169
-
170
- def render_template_with_spacer?(options_hash)
171
- if options_hash.key?(:spacer_template)
172
- parse_str(options_hash[:spacer_template])
173
- end
15
+ def directory
16
+ File.dirname(@name)
174
17
  end
175
18
 
176
19
  def partial_to_virtual_path(render_type, partial_path)
@@ -180,9 +23,18 @@ module ActionView
180
23
  partial_path
181
24
  end
182
25
  end
26
+ end
183
27
 
184
- def layout_to_virtual_path(layout_path)
185
- "layouts/#{layout_path}"
186
- end
28
+ # Check if prism is available. If it is, use it. Otherwise, use ripper.
29
+ begin
30
+ require "prism"
31
+ rescue LoadError
32
+ require "ripper"
33
+ require_relative "render_parser/ripper_render_parser"
34
+ Default = RipperRenderParser
35
+ else
36
+ require_relative "render_parser/prism_render_parser"
37
+ Default = PrismRenderParser
38
+ end
187
39
  end
188
40
  end
@@ -79,7 +79,7 @@ module ActionView
79
79
  path = if object.respond_to?(:to_partial_path)
80
80
  object.to_partial_path
81
81
  else
82
- raise ArgumentError.new("'#{object.inspect}' is not an ActiveModel-compatible object. It must implement :to_partial_path.")
82
+ raise ArgumentError.new("'#{object.inspect}' is not an ActiveModel-compatible object. It must implement #to_partial_path.")
83
83
  end
84
84
 
85
85
  if view.prefix_partial_path_with_controller_namespace
@@ -48,6 +48,22 @@ module ActionView
48
48
  #
49
49
  # <%= render partial: "account", locals: { user: @buyer } %>
50
50
  #
51
+ # == \Rendering variants of a partial
52
+ #
53
+ # The <tt>:variants</tt> option can be used to render a different template variant of a partial. For instance:
54
+ #
55
+ # <%= render partial: "account", variants: :mobile %>
56
+ #
57
+ # This will render <tt>_account.html+mobile.erb</tt>. This option also accepts multiple variants
58
+ # like so:
59
+ #
60
+ # <%= render partial: "account", variants: [:desktop, :mobile] %>
61
+ #
62
+ # This will look for the following templates and render the first one that exists:
63
+ # * <tt>_account.html+desktop.erb</tt>
64
+ # * <tt>_account.html+mobile.erb</tt>
65
+ # * <tt>_account.html.erb</tt>
66
+ #
51
67
  # == \Rendering a collection of partials
52
68
  #
53
69
  # The example of partial use describes a familiar pattern where a template needs to iterate over an array and
@@ -94,7 +110,7 @@ module ActionView
94
110
  # # <%= render partial: "accounts/account", locals: { account: @account} %>
95
111
  # <%= render partial: @account %>
96
112
  #
97
- # # @posts is an array of Post instances, so every post record returns 'posts/post' on +to_partial_path+,
113
+ # # @posts is an array of Post instances, so every post record returns 'posts/post' on #to_partial_path,
98
114
  # # that's why we can replace:
99
115
  # # <%= render partial: "posts/post", collection: @posts %>
100
116
  # <%= render partial: @posts %>
@@ -114,7 +130,7 @@ module ActionView
114
130
  # # <%= render partial: "accounts/account", locals: { account: @account} %>
115
131
  # <%= render @account %>
116
132
  #
117
- # # @posts is an array of Post instances, so every post record returns 'posts/post' on +to_partial_path+,
133
+ # # @posts is an array of Post instances, so every post record returns 'posts/post' on #to_partial_path,
118
134
  # # that's why we can replace:
119
135
  # # <%= render partial: "posts/post", collection: @posts %>
120
136
  # <%= render @posts %>
@@ -45,12 +45,6 @@ module ActionView
45
45
  end
46
46
  end
47
47
 
48
- # Direct access to template rendering.
49
- def render_template(context, options) # :nodoc:
50
- render_template_to_object(context, options).body
51
- end
52
-
53
- # Direct access to partial rendering.
54
48
  def render_partial(context, options, &block) # :nodoc:
55
49
  render_partial_to_object(context, options, &block).body
56
50
  end
@@ -59,46 +53,46 @@ module ActionView
59
53
  @cache_hits ||= {}
60
54
  end
61
55
 
62
- def render_template_to_object(context, options) # :nodoc:
63
- TemplateRenderer.new(@lookup_context).render(context, options)
64
- end
56
+ private
57
+ def render_template_to_object(context, options)
58
+ TemplateRenderer.new(@lookup_context).render(context, options)
59
+ end
65
60
 
66
- def render_partial_to_object(context, options, &block) # :nodoc:
67
- partial = options[:partial]
68
- if String === partial
69
- collection = collection_from_options(options)
61
+ def render_partial_to_object(context, options, &block)
62
+ partial = options[:partial]
63
+ if String === partial
64
+ collection = collection_from_options(options)
70
65
 
71
- if collection
72
- # Collection + Partial
73
- renderer = CollectionRenderer.new(@lookup_context, options)
74
- renderer.render_collection_with_partial(collection, partial, context, block)
75
- else
76
- if options.key?(:object)
77
- # Object + Partial
78
- renderer = ObjectRenderer.new(@lookup_context, options)
79
- renderer.render_object_with_partial(options[:object], partial, context, block)
66
+ if collection
67
+ # Collection + Partial
68
+ renderer = CollectionRenderer.new(@lookup_context, options)
69
+ renderer.render_collection_with_partial(collection, partial, context, block)
80
70
  else
81
- # Partial
82
- renderer = PartialRenderer.new(@lookup_context, options)
83
- renderer.render(partial, context, block)
71
+ if options.key?(:object)
72
+ # Object + Partial
73
+ renderer = ObjectRenderer.new(@lookup_context, options)
74
+ renderer.render_object_with_partial(options[:object], partial, context, block)
75
+ else
76
+ # Partial
77
+ renderer = PartialRenderer.new(@lookup_context, options)
78
+ renderer.render(partial, context, block)
79
+ end
84
80
  end
85
- end
86
- else
87
- collection = collection_from_object(partial) || collection_from_options(options)
88
-
89
- if collection
90
- # Collection + Derived Partial
91
- renderer = CollectionRenderer.new(@lookup_context, options)
92
- renderer.render_collection_derive_partial(collection, context, block)
93
81
  else
94
- # Object + Derived Partial
95
- renderer = ObjectRenderer.new(@lookup_context, options)
96
- renderer.render_object_derive_partial(partial, context, block)
82
+ collection = collection_from_object(partial) || collection_from_options(options)
83
+
84
+ if collection
85
+ # Collection + Derived Partial
86
+ renderer = CollectionRenderer.new(@lookup_context, options)
87
+ renderer.render_collection_derive_partial(collection, context, block)
88
+ else
89
+ # Object + Derived Partial
90
+ renderer = ObjectRenderer.new(@lookup_context, options)
91
+ renderer.render_object_derive_partial(partial, context, block)
92
+ end
97
93
  end
98
94
  end
99
- end
100
95
 
101
- private
102
96
  def collection_from_options(options)
103
97
  if options.key?(:collection)
104
98
  collection = options[:collection]
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "fiber"
4
3
 
5
4
  module ActionView
6
5
  # == TODO
@@ -26,6 +25,13 @@ module ActionView
26
25
  self
27
26
  end
28
27
 
28
+ # Returns the complete body as a string.
29
+ def body
30
+ buffer = String.new
31
+ each { |part| buffer << part }
32
+ buffer
33
+ end
34
+
29
35
  private
30
36
  # This is the same logging logic as in ShowExceptions middleware.
31
37
  def log_error(exception)
@@ -43,7 +49,7 @@ module ActionView
43
49
  # object that responds to each. This object is initialized with a block
44
50
  # that knows how to render the template.
45
51
  def render_template(view, template, layout_name = nil, locals = {}) # :nodoc:
46
- return [super.body] unless layout_name && template.supports_streaming?
52
+ return [super.body] unless template.supports_streaming?
47
53
 
48
54
  locals ||= {}
49
55
  layout = find_layout(layout_name, locals.keys, [formats.first])
@@ -99,14 +99,14 @@ module ActionView
99
99
  if layout.start_with?("/")
100
100
  raise ArgumentError, "Rendering layouts from an absolute path is not supported."
101
101
  else
102
- @lookup_context.find_template(layout, nil, false, [], details)
102
+ @lookup_context.find_template(layout, nil, false, keys, details)
103
103
  end
104
104
  rescue ActionView::MissingTemplate
105
105
  all_details = @details.merge(formats: @lookup_context.default_formats)
106
- raise unless template_exists?(layout, nil, false, [], **all_details)
106
+ raise unless template_exists?(layout, nil, false, keys, **all_details)
107
107
  end
108
108
  when Proc
109
- resolve_layout(layout.call(@lookup_context, formats), keys, formats)
109
+ resolve_layout(layout.call(@lookup_context, formats, keys), keys, formats)
110
110
  else
111
111
  layout
112
112
  end
@@ -27,10 +27,10 @@ module ActionView
27
27
  extend ActiveSupport::Concern
28
28
  include ActionView::ViewPaths
29
29
 
30
- attr_reader :rendered_format
30
+ attr_internal_reader :rendered_format
31
31
 
32
32
  def initialize
33
- @rendered_format = nil
33
+ @_rendered_format = nil
34
34
  super
35
35
  end
36
36
 
@@ -118,6 +118,7 @@ module ActionView
118
118
 
119
119
  def render_to_body(options = {})
120
120
  _process_options(options)
121
+ _process_render_template_options(options)
121
122
  _render_template(options)
122
123
  end
123
124
 
@@ -136,7 +137,7 @@ module ActionView
136
137
  end
137
138
 
138
139
  rendered_format = rendered_template.format || lookup_context.formats.first
139
- @rendered_format = Template::Types[rendered_format]
140
+ @_rendered_format = Template::Types[rendered_format]
140
141
 
141
142
  rendered_template.body
142
143
  end
@@ -173,18 +174,16 @@ module ActionView
173
174
  end
174
175
 
175
176
  # Normalize options.
176
- def _normalize_options(options)
177
- options = super(options)
177
+ def _process_render_template_options(options)
178
178
  if options[:partial] == true
179
179
  options[:partial] = action_name
180
180
  end
181
181
 
182
- if (options.keys & [:partial, :file, :template]).empty?
182
+ if !options.keys.intersect?([:partial, :file, :template])
183
183
  options[:prefixes] ||= _prefixes
184
184
  end
185
185
 
186
186
  options[:template] ||= (options[:action] || action_name).to_s
187
- options
188
187
  end
189
188
  end
190
189
  end