actionview 7.1.2 → 8.0.2

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +51 -382
  3. data/lib/action_view/base.rb +25 -11
  4. data/lib/action_view/cache_expiry.rb +9 -3
  5. data/lib/action_view/dependency_tracker/erb_tracker.rb +36 -27
  6. data/lib/action_view/dependency_tracker/ruby_tracker.rb +43 -0
  7. data/lib/action_view/dependency_tracker/wildcard_resolver.rb +32 -0
  8. data/lib/action_view/dependency_tracker.rb +2 -1
  9. data/lib/action_view/digestor.rb +6 -2
  10. data/lib/action_view/gem_version.rb +2 -2
  11. data/lib/action_view/helpers/asset_tag_helper.rb +18 -6
  12. data/lib/action_view/helpers/atom_feed_helper.rb +0 -2
  13. data/lib/action_view/helpers/cache_helper.rb +14 -6
  14. data/lib/action_view/helpers/csrf_helper.rb +1 -1
  15. data/lib/action_view/helpers/date_helper.rb +3 -3
  16. data/lib/action_view/helpers/form_helper.rb +282 -273
  17. data/lib/action_view/helpers/form_options_helper.rb +23 -21
  18. data/lib/action_view/helpers/form_tag_helper.rb +104 -69
  19. data/lib/action_view/helpers/number_helper.rb +35 -329
  20. data/lib/action_view/helpers/output_safety_helper.rb +5 -6
  21. data/lib/action_view/helpers/rendering_helper.rb +160 -50
  22. data/lib/action_view/helpers/sanitize_helper.rb +31 -14
  23. data/lib/action_view/helpers/tag_helper.rb +196 -19
  24. data/lib/action_view/helpers/tags/collection_check_boxes.rb +4 -3
  25. data/lib/action_view/helpers/tags/collection_helpers.rb +2 -1
  26. data/lib/action_view/helpers/text_helper.rb +125 -69
  27. data/lib/action_view/helpers/url_helper.rb +6 -80
  28. data/lib/action_view/layouts.rb +11 -13
  29. data/lib/action_view/log_subscriber.rb +8 -4
  30. data/lib/action_view/railtie.rb +0 -1
  31. data/lib/action_view/record_identifier.rb +1 -1
  32. data/lib/action_view/render_parser/prism_render_parser.rb +139 -0
  33. data/lib/action_view/{ripper_ast_parser.rb → render_parser/ripper_render_parser.rb} +162 -10
  34. data/lib/action_view/render_parser.rb +21 -169
  35. data/lib/action_view/renderer/abstract_renderer.rb +1 -1
  36. data/lib/action_view/renderer/partial_renderer.rb +2 -2
  37. data/lib/action_view/renderer/renderer.rb +32 -38
  38. data/lib/action_view/renderer/streaming_template_renderer.rb +0 -1
  39. data/lib/action_view/renderer/template_renderer.rb +3 -3
  40. data/lib/action_view/rendering.rb +6 -7
  41. data/lib/action_view/template/error.rb +11 -0
  42. data/lib/action_view/template/handlers/erb.rb +45 -37
  43. data/lib/action_view/template/renderable.rb +7 -1
  44. data/lib/action_view/template/resolver.rb +0 -3
  45. data/lib/action_view/template.rb +46 -12
  46. data/lib/action_view/test_case.rb +14 -16
  47. data/lib/action_view/unbound_template.rb +4 -4
  48. data/lib/action_view.rb +1 -1
  49. metadata +17 -19
  50. data/lib/action_view/dependency_tracker/ripper_tracker.rb +0 -59
  51. data/lib/assets/compiled/rails-ujs.js +0 -777
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionView
4
+ module RenderParser
5
+ class PrismRenderParser < Base # :nodoc:
6
+ def render_calls
7
+ queue = [Prism.parse(@code).value]
8
+ templates = []
9
+
10
+ while (node = queue.shift)
11
+ queue.concat(node.compact_child_nodes)
12
+ next unless node.is_a?(Prism::CallNode)
13
+
14
+ options = render_call_options(node)
15
+ next unless options
16
+
17
+ render_type = (options.keys & RENDER_TYPE_KEYS)[0]
18
+ template, object_template = render_call_template(options[render_type])
19
+ next unless template
20
+
21
+ if options.key?(:object) || options.key?(:collection) || object_template
22
+ next if options.key?(:object) && options.key?(:collection)
23
+ next unless options.key?(:partial)
24
+ end
25
+
26
+ if options[:spacer_template].is_a?(Prism::StringNode)
27
+ templates << partial_to_virtual_path(:partial, options[:spacer_template].unescaped)
28
+ end
29
+
30
+ templates << partial_to_virtual_path(render_type, template)
31
+
32
+ if render_type != :layout && options[:layout].is_a?(Prism::StringNode)
33
+ templates << partial_to_virtual_path(:layout, options[:layout].unescaped)
34
+ end
35
+ end
36
+
37
+ templates
38
+ end
39
+
40
+ private
41
+ # Accept a call node and return a hash of options for the render call.
42
+ # If it doesn't match the expected format, return nil.
43
+ def render_call_options(node)
44
+ # We are only looking for calls to render or render_to_string.
45
+ name = node.name.to_sym
46
+ return if name != :render && name != :render_to_string
47
+
48
+ # We are only looking for calls with arguments.
49
+ arguments = node.arguments
50
+ return unless arguments
51
+
52
+ arguments = arguments.arguments
53
+ length = arguments.length
54
+
55
+ # Get rid of any parentheses to get directly to the contents.
56
+ arguments.map! do |argument|
57
+ current = argument
58
+
59
+ while current.is_a?(Prism::ParenthesesNode) &&
60
+ current.body.is_a?(Prism::StatementsNode) &&
61
+ current.body.body.length == 1
62
+ current = current.body.body.first
63
+ end
64
+
65
+ current
66
+ end
67
+
68
+ # We are only looking for arguments that are either a string with an
69
+ # array of locals or a keyword hash with symbol keys.
70
+ options =
71
+ if (length == 1 || length == 2) && !arguments[0].is_a?(Prism::KeywordHashNode)
72
+ { partial: arguments[0], locals: arguments[1] }
73
+ elsif length == 1 &&
74
+ arguments[0].is_a?(Prism::KeywordHashNode) &&
75
+ arguments[0].elements.all? do |element|
76
+ element.is_a?(Prism::AssocNode) && element.key.is_a?(Prism::SymbolNode)
77
+ end
78
+ arguments[0].elements.to_h do |element|
79
+ [element.key.unescaped.to_sym, element.value]
80
+ end
81
+ end
82
+
83
+ return unless options
84
+
85
+ # Here we validate that the options have the keys we expect.
86
+ keys = options.keys
87
+ return if !keys.intersect?(RENDER_TYPE_KEYS)
88
+ return if (keys - ALL_KNOWN_KEYS).any?
89
+
90
+ # Finally, we can return a valid set of options.
91
+ options
92
+ end
93
+
94
+ # Accept the node that is being passed in the position of the template
95
+ # and return the template name and whether or not it is an object
96
+ # template.
97
+ def render_call_template(node)
98
+ object_template = false
99
+ template =
100
+ case node.type
101
+ when :string_node
102
+ path = node.unescaped
103
+ path.include?("/") ? path : "#{directory}/#{path}"
104
+ when :interpolated_string_node
105
+ node.parts.map do |node|
106
+ case node.type
107
+ when :string_node
108
+ node.unescaped
109
+ when :embedded_statements_node
110
+ "*"
111
+ else
112
+ return
113
+ end
114
+ end.join("")
115
+ else
116
+ dependency =
117
+ case node.type
118
+ when :class_variable_read_node
119
+ node.slice[2..]
120
+ when :instance_variable_read_node
121
+ node.slice[1..]
122
+ when :global_variable_read_node
123
+ node.slice[1..]
124
+ when :local_variable_read_node
125
+ node.slice
126
+ when :call_node
127
+ node.name.to_s
128
+ else
129
+ return
130
+ end
131
+
132
+ "#{dependency.pluralize}/#{dependency.singularize}"
133
+ end
134
+
135
+ [template, object_template]
136
+ end
137
+ end
138
+ end
139
+ end
@@ -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
@@ -94,7 +94,7 @@ module ActionView
94
94
  # # <%= render partial: "accounts/account", locals: { account: @account} %>
95
95
  # <%= render partial: @account %>
96
96
  #
97
- # # @posts is an array of Post instances, so every post record returns 'posts/post' on +to_partial_path+,
97
+ # # @posts is an array of Post instances, so every post record returns 'posts/post' on #to_partial_path,
98
98
  # # that's why we can replace:
99
99
  # # <%= render partial: "posts/post", collection: @posts %>
100
100
  # <%= render partial: @posts %>
@@ -114,7 +114,7 @@ module ActionView
114
114
  # # <%= render partial: "accounts/account", locals: { account: @account} %>
115
115
  # <%= render @account %>
116
116
  #
117
- # # @posts is an array of Post instances, so every post record returns 'posts/post' on +to_partial_path+,
117
+ # # @posts is an array of Post instances, so every post record returns 'posts/post' on #to_partial_path,
118
118
  # # that's why we can replace:
119
119
  # # <%= render partial: "posts/post", collection: @posts %>
120
120
  # <%= 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
@@ -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