actionview 7.1.5 → 7.2.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +41 -451
- data/lib/action_view/base.rb +19 -1
- data/lib/action_view/cache_expiry.rb +9 -3
- data/lib/action_view/dependency_tracker/{ripper_tracker.rb → ruby_tracker.rb} +4 -3
- data/lib/action_view/dependency_tracker.rb +1 -1
- data/lib/action_view/gem_version.rb +3 -3
- data/lib/action_view/helpers/asset_tag_helper.rb +18 -6
- data/lib/action_view/helpers/csrf_helper.rb +1 -1
- data/lib/action_view/helpers/form_helper.rb +197 -192
- data/lib/action_view/helpers/form_tag_helper.rb +76 -43
- data/lib/action_view/helpers/output_safety_helper.rb +4 -4
- data/lib/action_view/helpers/tag_helper.rb +208 -18
- data/lib/action_view/helpers/url_helper.rb +6 -82
- data/lib/action_view/layouts.rb +2 -4
- data/lib/action_view/log_subscriber.rb +8 -4
- data/lib/action_view/railtie.rb +0 -1
- data/lib/action_view/render_parser/prism_render_parser.rb +127 -0
- data/lib/action_view/{ripper_ast_parser.rb → render_parser/ripper_render_parser.rb} +152 -9
- data/lib/action_view/render_parser.rb +21 -169
- data/lib/action_view/renderer/abstract_renderer.rb +1 -1
- data/lib/action_view/renderer/renderer.rb +32 -38
- data/lib/action_view/rendering.rb +4 -4
- data/lib/action_view/template/renderable.rb +7 -1
- data/lib/action_view/template/resolver.rb +0 -2
- data/lib/action_view/template.rb +18 -1
- data/lib/action_view/test_case.rb +7 -9
- data/lib/assets/compiled/rails-ujs.js +777 -0
- metadata +20 -18
@@ -18,7 +18,7 @@ module ActionView
|
|
18
18
|
info do
|
19
19
|
message = +" Rendered #{from_rails_root(event.payload[:identifier])}"
|
20
20
|
message << " within #{from_rails_root(event.payload[:layout])}" if event.payload[:layout]
|
21
|
-
message << " (Duration: #{event.duration.round(1)}ms |
|
21
|
+
message << " (Duration: #{event.duration.round(1)}ms | GC: #{event.gc_time.round(1)}ms)"
|
22
22
|
end
|
23
23
|
end
|
24
24
|
subscribe_log_level :render_template, :debug
|
@@ -27,7 +27,7 @@ module ActionView
|
|
27
27
|
debug do
|
28
28
|
message = +" Rendered #{from_rails_root(event.payload[:identifier])}"
|
29
29
|
message << " within #{from_rails_root(event.payload[:layout])}" if event.payload[:layout]
|
30
|
-
message << " (Duration: #{event.duration.round(1)}ms |
|
30
|
+
message << " (Duration: #{event.duration.round(1)}ms | GC: #{event.gc_time.round(1)}ms)"
|
31
31
|
message << " #{cache_message(event.payload)}" unless event.payload[:cache_hit].nil?
|
32
32
|
message
|
33
33
|
end
|
@@ -37,7 +37,7 @@ module ActionView
|
|
37
37
|
def render_layout(event)
|
38
38
|
info do
|
39
39
|
message = +" Rendered layout #{from_rails_root(event.payload[:identifier])}"
|
40
|
-
message << " (Duration: #{event.duration.round(1)}ms |
|
40
|
+
message << " (Duration: #{event.duration.round(1)}ms | GC: #{event.gc_time.round(1)}ms)"
|
41
41
|
end
|
42
42
|
end
|
43
43
|
subscribe_log_level :render_layout, :info
|
@@ -48,7 +48,7 @@ module ActionView
|
|
48
48
|
debug do
|
49
49
|
message = +" Rendered collection of #{from_rails_root(identifier)}"
|
50
50
|
message << " within #{from_rails_root(event.payload[:layout])}" if event.payload[:layout]
|
51
|
-
message << " #{render_count(event.payload)} (Duration: #{event.duration.round(1)}ms |
|
51
|
+
message << " #{render_count(event.payload)} (Duration: #{event.duration.round(1)}ms | GC: #{event.gc_time.round(1)}ms)"
|
52
52
|
message
|
53
53
|
end
|
54
54
|
end
|
@@ -96,6 +96,10 @@ module ActionView
|
|
96
96
|
|
97
97
|
def finish(name, id, payload)
|
98
98
|
end
|
99
|
+
|
100
|
+
def silenced?(_)
|
101
|
+
logger.nil? || !logger.debug?
|
102
|
+
end
|
99
103
|
end
|
100
104
|
|
101
105
|
def self.attach_to(*)
|
data/lib/action_view/railtie.rb
CHANGED
@@ -116,7 +116,6 @@ module ActionView
|
|
116
116
|
view_reloader = ActionView::CacheExpiry::ViewReloader.new(watcher: app.config.file_watcher)
|
117
117
|
|
118
118
|
app.reloaders << view_reloader
|
119
|
-
view_reloader.execute
|
120
119
|
app.reloader.to_run do
|
121
120
|
require_unload_lock!
|
122
121
|
view_reloader.execute
|
@@ -0,0 +1,127 @@
|
|
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
|
+
if node.is_a?(Prism::StringNode)
|
101
|
+
path = node.unescaped
|
102
|
+
path.include?("/") ? path : "#{directory}/#{path}"
|
103
|
+
else
|
104
|
+
dependency =
|
105
|
+
case node.type
|
106
|
+
when :class_variable_read_node
|
107
|
+
node.slice[2..]
|
108
|
+
when :instance_variable_read_node
|
109
|
+
node.slice[1..]
|
110
|
+
when :global_variable_read_node
|
111
|
+
node.slice[1..]
|
112
|
+
when :local_variable_read_node
|
113
|
+
node.slice
|
114
|
+
when :call_node
|
115
|
+
node.name.to_s
|
116
|
+
else
|
117
|
+
return
|
118
|
+
end
|
119
|
+
|
120
|
+
"#{dependency.pluralize}/#{dependency.singularize}"
|
121
|
+
end
|
122
|
+
|
123
|
+
[template, object_template]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -1,10 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "ripper"
|
4
|
-
|
5
3
|
module ActionView
|
6
|
-
|
7
|
-
|
4
|
+
module RenderParser
|
5
|
+
class RipperRenderParser < Base # :nodoc:
|
8
6
|
class Node < ::Array # :nodoc:
|
9
7
|
attr_reader :type
|
10
8
|
|
@@ -183,16 +181,161 @@ module ActionView
|
|
183
181
|
end
|
184
182
|
end
|
185
183
|
|
186
|
-
|
187
|
-
|
188
|
-
def parse_render_nodes(code)
|
189
|
-
parser = RenderCallExtractor.new(code)
|
184
|
+
def render_calls
|
185
|
+
parser = RenderCallExtractor.new(@code)
|
190
186
|
parser.parse
|
191
187
|
|
192
188
|
parser.render_calls.group_by(&:first).to_h do |method, nodes|
|
193
189
|
[ method.to_sym, nodes.collect { |v| v[1] } ]
|
194
|
-
end
|
190
|
+
end.map do |method, nodes|
|
191
|
+
nodes.map { |n| parse_render(n) }
|
192
|
+
end.flatten.compact
|
195
193
|
end
|
194
|
+
|
195
|
+
private
|
196
|
+
def resolve_path_directory(path)
|
197
|
+
if path.include?("/")
|
198
|
+
path
|
199
|
+
else
|
200
|
+
"#{directory}/#{path}"
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
# Convert
|
205
|
+
# render("foo", ...)
|
206
|
+
# into either
|
207
|
+
# render(template: "foo", ...)
|
208
|
+
# or
|
209
|
+
# render(partial: "foo", ...)
|
210
|
+
def normalize_args(string, options_hash)
|
211
|
+
if options_hash
|
212
|
+
{ partial: string, locals: options_hash }
|
213
|
+
else
|
214
|
+
{ partial: string }
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def parse_render(node)
|
219
|
+
node = node.argument_nodes
|
220
|
+
|
221
|
+
if (node.length == 1 || node.length == 2) && !node[0].hash?
|
222
|
+
if node.length == 1
|
223
|
+
options = normalize_args(node[0], nil)
|
224
|
+
elsif node.length == 2
|
225
|
+
options = normalize_args(node[0], node[1])
|
226
|
+
end
|
227
|
+
|
228
|
+
return nil unless options
|
229
|
+
|
230
|
+
parse_render_from_options(options)
|
231
|
+
elsif node.length == 1 && node[0].hash?
|
232
|
+
options = parse_hash_to_symbols(node[0])
|
233
|
+
|
234
|
+
return nil unless options
|
235
|
+
|
236
|
+
parse_render_from_options(options)
|
237
|
+
else
|
238
|
+
nil
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def parse_hash(node)
|
243
|
+
node.hash? && node.to_hash
|
244
|
+
end
|
245
|
+
|
246
|
+
def parse_hash_to_symbols(node)
|
247
|
+
hash = parse_hash(node)
|
248
|
+
|
249
|
+
return unless hash
|
250
|
+
|
251
|
+
hash.transform_keys do |key_node|
|
252
|
+
key = parse_sym(key_node)
|
253
|
+
|
254
|
+
return unless key
|
255
|
+
|
256
|
+
key
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def parse_render_from_options(options_hash)
|
261
|
+
renders = []
|
262
|
+
keys = options_hash.keys
|
263
|
+
|
264
|
+
if (keys & RENDER_TYPE_KEYS).size < 1
|
265
|
+
# Must have at least one of render keys
|
266
|
+
return nil
|
267
|
+
end
|
268
|
+
|
269
|
+
if (keys - ALL_KNOWN_KEYS).any?
|
270
|
+
# de-opt in case of unknown option
|
271
|
+
return nil
|
272
|
+
end
|
273
|
+
|
274
|
+
render_type = (keys & RENDER_TYPE_KEYS)[0]
|
275
|
+
|
276
|
+
node = options_hash[render_type]
|
277
|
+
|
278
|
+
if node.string?
|
279
|
+
template = resolve_path_directory(node.to_string)
|
280
|
+
else
|
281
|
+
if node.variable_reference?
|
282
|
+
dependency = node.variable_name.sub(/\A(?:\$|@{1,2})/, "")
|
283
|
+
elsif node.vcall?
|
284
|
+
dependency = node.variable_name
|
285
|
+
elsif node.call?
|
286
|
+
dependency = node.call_method_name
|
287
|
+
else
|
288
|
+
return
|
289
|
+
end
|
290
|
+
|
291
|
+
object_template = true
|
292
|
+
template = "#{dependency.pluralize}/#{dependency.singularize}"
|
293
|
+
end
|
294
|
+
|
295
|
+
return unless template
|
296
|
+
|
297
|
+
if spacer_template = render_template_with_spacer?(options_hash)
|
298
|
+
virtual_path = partial_to_virtual_path(:partial, spacer_template)
|
299
|
+
renders << virtual_path
|
300
|
+
end
|
301
|
+
|
302
|
+
if options_hash.key?(:object) || options_hash.key?(:collection) || object_template
|
303
|
+
return nil if options_hash.key?(:object) && options_hash.key?(:collection)
|
304
|
+
return nil unless options_hash.key?(:partial)
|
305
|
+
end
|
306
|
+
|
307
|
+
virtual_path = partial_to_virtual_path(render_type, template)
|
308
|
+
renders << virtual_path
|
309
|
+
|
310
|
+
# Support for rendering multiple templates (i.e. a partial with a layout)
|
311
|
+
if layout_template = render_template_with_layout?(render_type, options_hash)
|
312
|
+
virtual_path = partial_to_virtual_path(:layout, layout_template)
|
313
|
+
|
314
|
+
renders << virtual_path
|
315
|
+
end
|
316
|
+
|
317
|
+
renders
|
318
|
+
end
|
319
|
+
|
320
|
+
def parse_str(node)
|
321
|
+
node.string? && node.to_string
|
322
|
+
end
|
323
|
+
|
324
|
+
def parse_sym(node)
|
325
|
+
node.symbol? && node.to_symbol
|
326
|
+
end
|
327
|
+
|
328
|
+
def render_template_with_layout?(render_type, options_hash)
|
329
|
+
if render_type != :layout && options_hash.key?(:layout)
|
330
|
+
parse_str(options_hash[:layout])
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
def render_template_with_spacer?(options_hash)
|
335
|
+
if options_hash.key?(:spacer_template)
|
336
|
+
parse_str(options_hash[:spacer_template])
|
337
|
+
end
|
338
|
+
end
|
196
339
|
end
|
197
340
|
end
|
198
341
|
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
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
22
|
-
def
|
23
|
-
|
24
|
-
|
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
|
165
|
-
|
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
|
-
|
185
|
-
|
186
|
-
|
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
|
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
|
@@ -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
|
-
|
63
|
-
|
64
|
-
|
56
|
+
private
|
57
|
+
def render_template_to_object(context, options)
|
58
|
+
TemplateRenderer.new(@lookup_context).render(context, options)
|
59
|
+
end
|
65
60
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
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
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
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
|
-
|
82
|
-
|
83
|
-
|
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
|
-
|
95
|
-
|
96
|
-
|
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]
|