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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +51 -382
- data/lib/action_view/base.rb +25 -11
- data/lib/action_view/cache_expiry.rb +9 -3
- data/lib/action_view/dependency_tracker/erb_tracker.rb +36 -27
- data/lib/action_view/dependency_tracker/ruby_tracker.rb +43 -0
- data/lib/action_view/dependency_tracker/wildcard_resolver.rb +32 -0
- data/lib/action_view/dependency_tracker.rb +2 -1
- data/lib/action_view/digestor.rb +6 -2
- data/lib/action_view/gem_version.rb +2 -2
- data/lib/action_view/helpers/asset_tag_helper.rb +18 -6
- data/lib/action_view/helpers/atom_feed_helper.rb +0 -2
- data/lib/action_view/helpers/cache_helper.rb +14 -6
- data/lib/action_view/helpers/csrf_helper.rb +1 -1
- data/lib/action_view/helpers/date_helper.rb +3 -3
- data/lib/action_view/helpers/form_helper.rb +282 -273
- data/lib/action_view/helpers/form_options_helper.rb +23 -21
- data/lib/action_view/helpers/form_tag_helper.rb +104 -69
- data/lib/action_view/helpers/number_helper.rb +35 -329
- data/lib/action_view/helpers/output_safety_helper.rb +5 -6
- data/lib/action_view/helpers/rendering_helper.rb +160 -50
- data/lib/action_view/helpers/sanitize_helper.rb +31 -14
- data/lib/action_view/helpers/tag_helper.rb +196 -19
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +4 -3
- data/lib/action_view/helpers/tags/collection_helpers.rb +2 -1
- data/lib/action_view/helpers/text_helper.rb +125 -69
- data/lib/action_view/helpers/url_helper.rb +6 -80
- data/lib/action_view/layouts.rb +11 -13
- data/lib/action_view/log_subscriber.rb +8 -4
- data/lib/action_view/railtie.rb +0 -1
- data/lib/action_view/record_identifier.rb +1 -1
- data/lib/action_view/render_parser/prism_render_parser.rb +139 -0
- data/lib/action_view/{ripper_ast_parser.rb → render_parser/ripper_render_parser.rb} +162 -10
- data/lib/action_view/render_parser.rb +21 -169
- data/lib/action_view/renderer/abstract_renderer.rb +1 -1
- data/lib/action_view/renderer/partial_renderer.rb +2 -2
- data/lib/action_view/renderer/renderer.rb +32 -38
- data/lib/action_view/renderer/streaming_template_renderer.rb +0 -1
- data/lib/action_view/renderer/template_renderer.rb +3 -3
- data/lib/action_view/rendering.rb +6 -7
- data/lib/action_view/template/error.rb +11 -0
- data/lib/action_view/template/handlers/erb.rb +45 -37
- data/lib/action_view/template/renderable.rb +7 -1
- data/lib/action_view/template/resolver.rb +0 -3
- data/lib/action_view/template.rb +46 -12
- data/lib/action_view/test_case.rb +14 -16
- data/lib/action_view/unbound_template.rb +4 -4
- data/lib/action_view.rb +1 -1
- metadata +17 -19
- data/lib/action_view/dependency_tracker/ripper_tracker.rb +0 -59
- data/lib/assets/compiled/rails-ujs.js +0 -777
|
@@ -27,10 +27,10 @@ module ActionView
|
|
|
27
27
|
extend ActiveSupport::Concern
|
|
28
28
|
include ActionView::ViewPaths
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
attr_internal_reader :rendered_format
|
|
31
31
|
|
|
32
32
|
def initialize
|
|
33
|
-
@
|
|
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
|
-
@
|
|
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
|
|
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
|
|
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
|
|
@@ -27,6 +27,17 @@ module ActionView
|
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
class StrictLocalsError < ArgumentError # :nodoc:
|
|
31
|
+
def initialize(argument_error, template)
|
|
32
|
+
message = argument_error.message.
|
|
33
|
+
gsub("unknown keyword:", "unknown local:").
|
|
34
|
+
gsub("missing keyword:", "missing local:").
|
|
35
|
+
gsub("no keywords accepted", "no locals accepted").
|
|
36
|
+
concat(" for #{template.short_identifier}")
|
|
37
|
+
super(message)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
30
41
|
class MissingTemplate < ActionViewError # :nodoc:
|
|
31
42
|
attr_reader :path, :paths, :prefixes, :partial
|
|
32
43
|
|
|
@@ -42,7 +42,9 @@ module ActionView
|
|
|
42
42
|
# source location inside the template.
|
|
43
43
|
def translate_location(spot, backtrace_location, source)
|
|
44
44
|
# Tokenize the source line
|
|
45
|
-
|
|
45
|
+
source_lines = source.lines
|
|
46
|
+
return nil if source_lines.size < backtrace_location.lineno
|
|
47
|
+
tokens = ::ERB::Util.tokenize(source_lines[backtrace_location.lineno - 1])
|
|
46
48
|
new_first_column = find_offset(spot[:snippet], tokens, spot[:first_column])
|
|
47
49
|
lineno_delta = spot[:first_lineno] - backtrace_location.lineno
|
|
48
50
|
spot[:first_lineno] -= lineno_delta
|
|
@@ -51,7 +53,7 @@ module ActionView
|
|
|
51
53
|
column_delta = spot[:first_column] - new_first_column
|
|
52
54
|
spot[:first_column] -= column_delta
|
|
53
55
|
spot[:last_column] -= column_delta
|
|
54
|
-
spot[:script_lines] =
|
|
56
|
+
spot[:script_lines] = source_lines
|
|
55
57
|
|
|
56
58
|
spot
|
|
57
59
|
rescue NotImplementedError, LocationParsingError
|
|
@@ -105,51 +107,57 @@ module ActionView
|
|
|
105
107
|
raise WrongEncodingError.new(string, string.encoding)
|
|
106
108
|
end
|
|
107
109
|
|
|
110
|
+
# Find which token in the source template spans the byte range that
|
|
111
|
+
# contains the error_column, then return the offset compared to the
|
|
112
|
+
# original source template.
|
|
113
|
+
#
|
|
114
|
+
# Iterate consecutive pairs of CODE or TEXT tokens, requiring
|
|
115
|
+
# a match of the first token before matching either token.
|
|
116
|
+
#
|
|
117
|
+
# For example, if we want to find tokens A, B, C, we do the following:
|
|
118
|
+
# 1. Find a match for A: test error_column or advance scanner.
|
|
119
|
+
# 2. Find a match for B or A:
|
|
120
|
+
# a. If B: start over with next token set (B, C).
|
|
121
|
+
# b. If A: test error_column or advance scanner.
|
|
122
|
+
# c. Otherwise: Advance 1 byte
|
|
123
|
+
#
|
|
124
|
+
# Prioritize matching the next token over the current token once
|
|
125
|
+
# a match for the current token has been found. This is to prevent
|
|
126
|
+
# the current token from looping past the next token if they both
|
|
127
|
+
# match (i.e. if the current token is a single space character).
|
|
108
128
|
def find_offset(compiled, source_tokens, error_column)
|
|
109
129
|
compiled = StringScanner.new(compiled)
|
|
130
|
+
offset_source_tokens(source_tokens).each_cons(2) do |(name, str, offset), (_, next_str, _)|
|
|
131
|
+
matched_str = false
|
|
110
132
|
|
|
111
|
-
|
|
133
|
+
until compiled.eos?
|
|
134
|
+
if matched_str && next_str && compiled.match?(next_str)
|
|
135
|
+
break
|
|
136
|
+
elsif compiled.match?(str)
|
|
137
|
+
matched_str = true
|
|
112
138
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
when :TEXT
|
|
117
|
-
loop do
|
|
118
|
-
break if compiled.match?(str)
|
|
119
|
-
compiled.getch
|
|
120
|
-
end
|
|
121
|
-
raise LocationParsingError unless compiled.scan(str)
|
|
122
|
-
when :CODE
|
|
123
|
-
if compiled.pos > error_column
|
|
124
|
-
raise LocationParsingError, "We went too far"
|
|
125
|
-
end
|
|
139
|
+
if name == :CODE && compiled.pos <= error_column && compiled.pos + str.bytesize >= error_column
|
|
140
|
+
return error_column - compiled.pos + offset
|
|
141
|
+
end
|
|
126
142
|
|
|
127
|
-
|
|
128
|
-
offset = error_column - compiled.pos
|
|
129
|
-
return passed_tokens.map(&:last).join.bytesize + offset
|
|
143
|
+
compiled.pos += str.bytesize
|
|
130
144
|
else
|
|
131
|
-
|
|
132
|
-
raise LocationParsingError, "Couldn't find code snippet"
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
when :OPEN
|
|
136
|
-
next_tok = source_tokens.first.last
|
|
137
|
-
loop do
|
|
138
|
-
break if compiled.match?(next_tok)
|
|
139
|
-
compiled.getch
|
|
145
|
+
compiled.pos += 1
|
|
140
146
|
end
|
|
141
|
-
when :CLOSE
|
|
142
|
-
next_tok = source_tokens.first.last
|
|
143
|
-
loop do
|
|
144
|
-
break if compiled.match?(next_tok)
|
|
145
|
-
compiled.getch
|
|
146
|
-
end
|
|
147
|
-
else
|
|
148
|
-
raise LocationParsingError, "Not implemented: #{tok.first}"
|
|
149
147
|
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
raise LocationParsingError, "Couldn't find code snippet"
|
|
151
|
+
end
|
|
150
152
|
|
|
151
|
-
|
|
153
|
+
def offset_source_tokens(source_tokens)
|
|
154
|
+
source_offset = 0
|
|
155
|
+
with_offset = source_tokens.filter_map do |(name, str)|
|
|
156
|
+
result = [name, str, source_offset] if name == :CODE || name == :TEXT
|
|
157
|
+
source_offset += str.bytesize
|
|
158
|
+
result
|
|
152
159
|
end
|
|
160
|
+
with_offset << [:EOS, nil, source_offset]
|
|
153
161
|
end
|
|
154
162
|
end
|
|
155
163
|
end
|
|
@@ -14,10 +14,16 @@ module ActionView
|
|
|
14
14
|
|
|
15
15
|
def render(context, *args)
|
|
16
16
|
@renderable.render_in(context)
|
|
17
|
+
rescue NoMethodError
|
|
18
|
+
if !@renderable.respond_to?(:render_in)
|
|
19
|
+
raise ArgumentError, "'#{@renderable.inspect}' is not a renderable object. It must implement #render_in."
|
|
20
|
+
else
|
|
21
|
+
raise
|
|
22
|
+
end
|
|
17
23
|
end
|
|
18
24
|
|
|
19
25
|
def format
|
|
20
|
-
@renderable.format
|
|
26
|
+
@renderable.try(:format)
|
|
21
27
|
end
|
|
22
28
|
end
|
|
23
29
|
end
|
|
@@ -4,14 +4,11 @@ require "pathname"
|
|
|
4
4
|
require "active_support/core_ext/class"
|
|
5
5
|
require "active_support/core_ext/module/attribute_accessors"
|
|
6
6
|
require "action_view/template"
|
|
7
|
-
require "thread"
|
|
8
7
|
require "concurrent/map"
|
|
9
8
|
|
|
10
9
|
module ActionView
|
|
11
10
|
# = Action View Resolver
|
|
12
11
|
class Resolver
|
|
13
|
-
include ActiveSupport::Deprecation::DeprecatedConstantAccessor
|
|
14
|
-
|
|
15
12
|
class PathParser # :nodoc:
|
|
16
13
|
ParsedPath = Struct.new(:path, :details)
|
|
17
14
|
|
data/lib/action_view/template.rb
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "thread"
|
|
4
3
|
require "delegate"
|
|
5
4
|
|
|
6
5
|
module ActionView
|
|
@@ -148,6 +147,20 @@ module ActionView
|
|
|
148
147
|
# <p><%= alert %></p>
|
|
149
148
|
# <% end %>
|
|
150
149
|
#
|
|
150
|
+
# By default, templates will accept any <tt>locals</tt> as keyword arguments
|
|
151
|
+
# and make them available to <tt>local_assigns</tt>. To restrict what
|
|
152
|
+
# <tt>local_assigns</tt> a template will accept, add a <tt>locals:</tt> magic comment:
|
|
153
|
+
#
|
|
154
|
+
# <%# locals: (headline:, alerts: []) %>
|
|
155
|
+
#
|
|
156
|
+
# <h1><%= headline %></h1>
|
|
157
|
+
#
|
|
158
|
+
# <% alerts.each do |alert| %>
|
|
159
|
+
# <p><%= alert %></p>
|
|
160
|
+
# <% end %>
|
|
161
|
+
#
|
|
162
|
+
# Read more about strict locals in {Action View Overview}[https://guides.rubyonrails.org/action_view_overview.html#strict-locals]
|
|
163
|
+
# in the guides.
|
|
151
164
|
|
|
152
165
|
eager_autoload do
|
|
153
166
|
autoload :Error
|
|
@@ -216,11 +229,21 @@ module ActionView
|
|
|
216
229
|
end
|
|
217
230
|
|
|
218
231
|
def spot(location) # :nodoc:
|
|
219
|
-
ast = RubyVM::AbstractSyntaxTree.parse(compiled_source, keep_script_lines: true)
|
|
220
232
|
node_id = RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location(location)
|
|
221
|
-
|
|
233
|
+
found =
|
|
234
|
+
if RubyVM::InstructionSequence.compile("").to_a[4][:parser] == :prism
|
|
235
|
+
require "prism"
|
|
222
236
|
|
|
223
|
-
|
|
237
|
+
if Prism::VERSION >= "1.0.0"
|
|
238
|
+
result = Prism.parse(compiled_source).value
|
|
239
|
+
result.breadth_first_search { |node| node.node_id == node_id }
|
|
240
|
+
end
|
|
241
|
+
else
|
|
242
|
+
node = RubyVM::AbstractSyntaxTree.parse(compiled_source, keep_script_lines: true)
|
|
243
|
+
find_node_by_id(node, node_id)
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
ErrorHighlight.spot(found) if found
|
|
224
247
|
end
|
|
225
248
|
|
|
226
249
|
# Translate an error location returned by ErrorHighlight to the correct
|
|
@@ -258,7 +281,8 @@ module ActionView
|
|
|
258
281
|
view._run(method_name, self, locals, buffer, add_to_stack: add_to_stack, has_strict_locals: strict_locals?, &block)
|
|
259
282
|
nil
|
|
260
283
|
else
|
|
261
|
-
view._run(method_name, self, locals, OutputBuffer.new, add_to_stack: add_to_stack, has_strict_locals: strict_locals?, &block)
|
|
284
|
+
result = view._run(method_name, self, locals, OutputBuffer.new, add_to_stack: add_to_stack, has_strict_locals: strict_locals?, &block)
|
|
285
|
+
result.is_a?(OutputBuffer) ? result.to_s : result
|
|
262
286
|
end
|
|
263
287
|
end
|
|
264
288
|
rescue => e
|
|
@@ -332,7 +356,7 @@ module ActionView
|
|
|
332
356
|
|
|
333
357
|
# This method is responsible for marking a template as having strict locals
|
|
334
358
|
# which means the template can only accept the locals defined in a magic
|
|
335
|
-
# comment. For example, if your template
|
|
359
|
+
# comment. For example, if your template accepts the locals +title+ and
|
|
336
360
|
# +comment_count+, add the following to your template file:
|
|
337
361
|
#
|
|
338
362
|
# <%# locals: (title: "Default title", comment_count: 0) %>
|
|
@@ -423,9 +447,13 @@ module ActionView
|
|
|
423
447
|
|
|
424
448
|
method_arguments =
|
|
425
449
|
if set_strict_locals
|
|
426
|
-
|
|
450
|
+
if set_strict_locals.include?("&")
|
|
451
|
+
"local_assigns, output_buffer, #{set_strict_locals}"
|
|
452
|
+
else
|
|
453
|
+
"local_assigns, output_buffer, #{set_strict_locals}, &_"
|
|
454
|
+
end
|
|
427
455
|
else
|
|
428
|
-
"local_assigns, output_buffer"
|
|
456
|
+
"local_assigns, output_buffer, &_"
|
|
429
457
|
end
|
|
430
458
|
|
|
431
459
|
# Make sure that the resulting String to be eval'd is in the
|
|
@@ -481,15 +509,18 @@ module ActionView
|
|
|
481
509
|
|
|
482
510
|
return unless strict_locals?
|
|
483
511
|
|
|
484
|
-
parameters = mod.instance_method(method_name).parameters
|
|
512
|
+
parameters = mod.instance_method(method_name).parameters
|
|
513
|
+
parameters -= [[:req, :local_assigns], [:req, :output_buffer]]
|
|
514
|
+
|
|
485
515
|
# Check compiled method parameters to ensure that only kwargs
|
|
486
516
|
# were provided as strict locals, preventing `locals: (foo, *foo)` etc
|
|
487
517
|
# and allowing `locals: (foo:)`.
|
|
488
|
-
|
|
489
518
|
non_kwarg_parameters = parameters.select do |parameter|
|
|
490
519
|
![:keyreq, :key, :keyrest, :nokey].include?(parameter[0])
|
|
491
520
|
end
|
|
492
521
|
|
|
522
|
+
non_kwarg_parameters.pop if non_kwarg_parameters.last == %i(block _)
|
|
523
|
+
|
|
493
524
|
unless non_kwarg_parameters.empty?
|
|
494
525
|
mod.undef_method(method_name)
|
|
495
526
|
|
|
@@ -501,7 +532,7 @@ module ActionView
|
|
|
501
532
|
end
|
|
502
533
|
|
|
503
534
|
unless parameters.any? { |type, _| type == :keyrest }
|
|
504
|
-
parameters.map!(&:
|
|
535
|
+
parameters.map!(&:last)
|
|
505
536
|
parameters.sort!
|
|
506
537
|
@strict_local_keys = parameters.freeze
|
|
507
538
|
end
|
|
@@ -524,12 +555,15 @@ module ActionView
|
|
|
524
555
|
end
|
|
525
556
|
end
|
|
526
557
|
|
|
558
|
+
RUBY_RESERVED_KEYWORDS = ::ActiveSupport::Delegation::RUBY_RESERVED_KEYWORDS
|
|
559
|
+
private_constant :RUBY_RESERVED_KEYWORDS
|
|
560
|
+
|
|
527
561
|
def locals_code
|
|
528
562
|
return "" if strict_locals?
|
|
529
563
|
|
|
530
564
|
# Only locals with valid variable names get set directly. Others will
|
|
531
565
|
# still be available in local_assigns.
|
|
532
|
-
locals = @locals -
|
|
566
|
+
locals = @locals - RUBY_RESERVED_KEYWORDS
|
|
533
567
|
|
|
534
568
|
locals = locals.grep(/\A(?![A-Z0-9])(?:[[:alnum:]_]|[^\0-\177])+\z/)
|
|
535
569
|
|
|
@@ -60,7 +60,7 @@ module ActionView
|
|
|
60
60
|
include ActiveSupport::Testing::ConstantLookup
|
|
61
61
|
|
|
62
62
|
delegate :lookup_context, to: :controller
|
|
63
|
-
attr_accessor :controller, :request, :output_buffer
|
|
63
|
+
attr_accessor :controller, :request, :output_buffer, :rendered
|
|
64
64
|
|
|
65
65
|
module ClassMethods
|
|
66
66
|
def inherited(descendant) # :nodoc:
|
|
@@ -171,10 +171,9 @@ module ActionView
|
|
|
171
171
|
# Almost a duplicate from ActionController::Helpers
|
|
172
172
|
methods.flatten.each do |method|
|
|
173
173
|
_helpers_for_modification.module_eval <<~end_eval, __FILE__, __LINE__ + 1
|
|
174
|
-
def #{method}(
|
|
175
|
-
_test_case.send(:'#{method}',
|
|
176
|
-
end
|
|
177
|
-
ruby2_keywords(:'#{method}')
|
|
174
|
+
def #{method}(...) # def current_user(...)
|
|
175
|
+
_test_case.send(:'#{method}', ...) # _test_case.send(:'current_user', ...)
|
|
176
|
+
end # end
|
|
178
177
|
end_eval
|
|
179
178
|
end
|
|
180
179
|
end
|
|
@@ -198,11 +197,11 @@ module ActionView
|
|
|
198
197
|
end
|
|
199
198
|
|
|
200
199
|
included do
|
|
201
|
-
class_attribute :content_class, instance_accessor: false, default:
|
|
200
|
+
class_attribute :content_class, instance_accessor: false, default: RenderedViewContent
|
|
202
201
|
|
|
203
202
|
setup :setup_with_controller
|
|
204
203
|
|
|
205
|
-
register_parser :html, -> rendered { Rails::Dom::Testing.
|
|
204
|
+
register_parser :html, -> rendered { Rails::Dom::Testing.html_document_fragment.parse(rendered) }
|
|
206
205
|
register_parser :json, -> rendered { JSON.parse(rendered, object_class: ActiveSupport::HashWithIndifferentAccess) }
|
|
207
206
|
|
|
208
207
|
ActiveSupport.run_load_hooks(:action_view_test_case, self)
|
|
@@ -224,7 +223,7 @@ module ActionView
|
|
|
224
223
|
@request = @controller.request
|
|
225
224
|
@view_flow = ActionView::OutputFlow.new
|
|
226
225
|
@output_buffer = ActionView::OutputBuffer.new
|
|
227
|
-
@rendered = +""
|
|
226
|
+
@rendered = self.class.content_class.new(+"")
|
|
228
227
|
|
|
229
228
|
test_case_instance = self
|
|
230
229
|
controller_class.define_method(:_test_case) { test_case_instance }
|
|
@@ -244,6 +243,9 @@ module ActionView
|
|
|
244
243
|
@_rendered_views ||= RenderedViewsCollection.new
|
|
245
244
|
end
|
|
246
245
|
|
|
246
|
+
##
|
|
247
|
+
# :method: rendered
|
|
248
|
+
#
|
|
247
249
|
# Returns the content rendered by the last +render+ call.
|
|
248
250
|
#
|
|
249
251
|
# The returned object behaves like a string but also exposes a number of methods
|
|
@@ -291,15 +293,12 @@ module ActionView
|
|
|
291
293
|
#
|
|
292
294
|
# assert_pattern { rendered.json => { title: "Hello, world" } }
|
|
293
295
|
# end
|
|
294
|
-
def rendered
|
|
295
|
-
@_rendered ||= self.class.content_class.new(@rendered)
|
|
296
|
-
end
|
|
297
296
|
|
|
298
297
|
def _routes
|
|
299
298
|
@controller._routes if @controller.respond_to?(:_routes)
|
|
300
299
|
end
|
|
301
300
|
|
|
302
|
-
class
|
|
301
|
+
class RenderedViewContent < String # :nodoc:
|
|
303
302
|
end
|
|
304
303
|
|
|
305
304
|
# Need to experiment if this priority is the best one: rendered => output_buffer
|
|
@@ -416,7 +415,7 @@ module ActionView
|
|
|
416
415
|
end]
|
|
417
416
|
end
|
|
418
417
|
|
|
419
|
-
def method_missing(selector,
|
|
418
|
+
def method_missing(selector, ...)
|
|
420
419
|
begin
|
|
421
420
|
routes = @controller.respond_to?(:_routes) && @controller._routes
|
|
422
421
|
rescue
|
|
@@ -426,16 +425,15 @@ module ActionView
|
|
|
426
425
|
if routes &&
|
|
427
426
|
(routes.named_routes.route_defined?(selector) ||
|
|
428
427
|
routes.mounted_helpers.method_defined?(selector))
|
|
429
|
-
@controller.__send__(selector,
|
|
428
|
+
@controller.__send__(selector, ...)
|
|
430
429
|
else
|
|
431
430
|
super
|
|
432
431
|
end
|
|
433
432
|
end
|
|
434
|
-
ruby2_keywords(:method_missing)
|
|
435
433
|
|
|
436
434
|
def respond_to_missing?(name, include_private = false)
|
|
437
435
|
begin
|
|
438
|
-
routes =
|
|
436
|
+
routes = @controller.respond_to?(:_routes) && @controller._routes
|
|
439
437
|
rescue
|
|
440
438
|
# Don't call routes, if there is an error on _routes call
|
|
441
439
|
end
|
|
@@ -26,15 +26,15 @@ module ActionView
|
|
|
26
26
|
# while holding the lock.
|
|
27
27
|
template = (@templates[normalized_locals] ||= build_template(normalized_locals))
|
|
28
28
|
|
|
29
|
-
# This may have already been assigned, but we've already de-dup'd so
|
|
30
|
-
# reassignment is fine.
|
|
31
|
-
@templates[locals.dup] = template
|
|
32
|
-
|
|
33
29
|
if template.strict_locals?
|
|
34
30
|
# Under strict locals, we only need one template.
|
|
35
31
|
# This replaces the @templates Concurrent::Map with a hash which
|
|
36
32
|
# returns this template for every key.
|
|
37
33
|
@templates = Hash.new(template).freeze
|
|
34
|
+
else
|
|
35
|
+
# This may have already been assigned, but we've already de-dup'd so
|
|
36
|
+
# reassignment is fine.
|
|
37
|
+
@templates[locals.dup] = template
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
end
|
data/lib/action_view.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: actionview
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 8.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- David Heinemeier Hansson
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 2025-03-12 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: activesupport
|
|
@@ -16,14 +15,14 @@ dependencies:
|
|
|
16
15
|
requirements:
|
|
17
16
|
- - '='
|
|
18
17
|
- !ruby/object:Gem::Version
|
|
19
|
-
version:
|
|
18
|
+
version: 8.0.2
|
|
20
19
|
type: :runtime
|
|
21
20
|
prerelease: false
|
|
22
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
22
|
requirements:
|
|
24
23
|
- - '='
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
|
-
version:
|
|
25
|
+
version: 8.0.2
|
|
27
26
|
- !ruby/object:Gem::Dependency
|
|
28
27
|
name: builder
|
|
29
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -86,28 +85,28 @@ dependencies:
|
|
|
86
85
|
requirements:
|
|
87
86
|
- - '='
|
|
88
87
|
- !ruby/object:Gem::Version
|
|
89
|
-
version:
|
|
88
|
+
version: 8.0.2
|
|
90
89
|
type: :development
|
|
91
90
|
prerelease: false
|
|
92
91
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
92
|
requirements:
|
|
94
93
|
- - '='
|
|
95
94
|
- !ruby/object:Gem::Version
|
|
96
|
-
version:
|
|
95
|
+
version: 8.0.2
|
|
97
96
|
- !ruby/object:Gem::Dependency
|
|
98
97
|
name: activemodel
|
|
99
98
|
requirement: !ruby/object:Gem::Requirement
|
|
100
99
|
requirements:
|
|
101
100
|
- - '='
|
|
102
101
|
- !ruby/object:Gem::Version
|
|
103
|
-
version:
|
|
102
|
+
version: 8.0.2
|
|
104
103
|
type: :development
|
|
105
104
|
prerelease: false
|
|
106
105
|
version_requirements: !ruby/object:Gem::Requirement
|
|
107
106
|
requirements:
|
|
108
107
|
- - '='
|
|
109
108
|
- !ruby/object:Gem::Version
|
|
110
|
-
version:
|
|
109
|
+
version: 8.0.2
|
|
111
110
|
description: Simple, battle-tested conventions and helpers for building web pages.
|
|
112
111
|
email: david@loudthinking.com
|
|
113
112
|
executables: []
|
|
@@ -126,7 +125,8 @@ files:
|
|
|
126
125
|
- lib/action_view/context.rb
|
|
127
126
|
- lib/action_view/dependency_tracker.rb
|
|
128
127
|
- lib/action_view/dependency_tracker/erb_tracker.rb
|
|
129
|
-
- lib/action_view/dependency_tracker/
|
|
128
|
+
- lib/action_view/dependency_tracker/ruby_tracker.rb
|
|
129
|
+
- lib/action_view/dependency_tracker/wildcard_resolver.rb
|
|
130
130
|
- lib/action_view/deprecator.rb
|
|
131
131
|
- lib/action_view/digestor.rb
|
|
132
132
|
- lib/action_view/flows.rb
|
|
@@ -204,6 +204,8 @@ files:
|
|
|
204
204
|
- lib/action_view/railtie.rb
|
|
205
205
|
- lib/action_view/record_identifier.rb
|
|
206
206
|
- lib/action_view/render_parser.rb
|
|
207
|
+
- lib/action_view/render_parser/prism_render_parser.rb
|
|
208
|
+
- lib/action_view/render_parser/ripper_render_parser.rb
|
|
207
209
|
- lib/action_view/renderer/abstract_renderer.rb
|
|
208
210
|
- lib/action_view/renderer/collection_renderer.rb
|
|
209
211
|
- lib/action_view/renderer/object_renderer.rb
|
|
@@ -213,7 +215,6 @@ files:
|
|
|
213
215
|
- lib/action_view/renderer/streaming_template_renderer.rb
|
|
214
216
|
- lib/action_view/renderer/template_renderer.rb
|
|
215
217
|
- lib/action_view/rendering.rb
|
|
216
|
-
- lib/action_view/ripper_ast_parser.rb
|
|
217
218
|
- lib/action_view/routing_url_for.rb
|
|
218
219
|
- lib/action_view/tasks/cache_digests.rake
|
|
219
220
|
- lib/action_view/template.rb
|
|
@@ -240,18 +241,16 @@ files:
|
|
|
240
241
|
- lib/action_view/unbound_template.rb
|
|
241
242
|
- lib/action_view/version.rb
|
|
242
243
|
- lib/action_view/view_paths.rb
|
|
243
|
-
- lib/assets/compiled/rails-ujs.js
|
|
244
244
|
homepage: https://rubyonrails.org
|
|
245
245
|
licenses:
|
|
246
246
|
- MIT
|
|
247
247
|
metadata:
|
|
248
248
|
bug_tracker_uri: https://github.com/rails/rails/issues
|
|
249
|
-
changelog_uri: https://github.com/rails/rails/blob/
|
|
250
|
-
documentation_uri: https://api.rubyonrails.org/
|
|
249
|
+
changelog_uri: https://github.com/rails/rails/blob/v8.0.2/actionview/CHANGELOG.md
|
|
250
|
+
documentation_uri: https://api.rubyonrails.org/v8.0.2/
|
|
251
251
|
mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
|
|
252
|
-
source_code_uri: https://github.com/rails/rails/tree/
|
|
252
|
+
source_code_uri: https://github.com/rails/rails/tree/v8.0.2/actionview
|
|
253
253
|
rubygems_mfa_required: 'true'
|
|
254
|
-
post_install_message:
|
|
255
254
|
rdoc_options: []
|
|
256
255
|
require_paths:
|
|
257
256
|
- lib
|
|
@@ -259,7 +258,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
259
258
|
requirements:
|
|
260
259
|
- - ">="
|
|
261
260
|
- !ruby/object:Gem::Version
|
|
262
|
-
version: 2.
|
|
261
|
+
version: 3.2.0
|
|
263
262
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
264
263
|
requirements:
|
|
265
264
|
- - ">="
|
|
@@ -267,8 +266,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
267
266
|
version: '0'
|
|
268
267
|
requirements:
|
|
269
268
|
- none
|
|
270
|
-
rubygems_version: 3.
|
|
271
|
-
signing_key:
|
|
269
|
+
rubygems_version: 3.6.2
|
|
272
270
|
specification_version: 4
|
|
273
271
|
summary: Rendering framework putting the V in MVC (part of Rails).
|
|
274
272
|
test_files: []
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module ActionView
|
|
4
|
-
class DependencyTracker # :nodoc:
|
|
5
|
-
class RipperTracker # :nodoc:
|
|
6
|
-
EXPLICIT_DEPENDENCY = /# Template Dependency: (\S+)/
|
|
7
|
-
|
|
8
|
-
def self.call(name, template, view_paths = nil)
|
|
9
|
-
new(name, template, view_paths).dependencies
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def dependencies
|
|
13
|
-
render_dependencies + explicit_dependencies
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def self.supports_view_paths? # :nodoc:
|
|
17
|
-
true
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def initialize(name, template, view_paths = nil)
|
|
21
|
-
@name, @template, @view_paths = name, template, view_paths
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
private
|
|
25
|
-
attr_reader :template, :name, :view_paths
|
|
26
|
-
|
|
27
|
-
def render_dependencies
|
|
28
|
-
return [] unless template.source.include?("render")
|
|
29
|
-
|
|
30
|
-
compiled_source = template.handler.call(template, template.source)
|
|
31
|
-
|
|
32
|
-
RenderParser.new(@name, compiled_source).render_calls.filter_map do |render_call|
|
|
33
|
-
next if render_call.end_with?("/_")
|
|
34
|
-
render_call.gsub(%r|/_|, "/")
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def explicit_dependencies
|
|
39
|
-
dependencies = template.source.scan(EXPLICIT_DEPENDENCY).flatten.uniq
|
|
40
|
-
|
|
41
|
-
wildcards, explicits = dependencies.partition { |dependency| dependency.end_with?("/*") }
|
|
42
|
-
|
|
43
|
-
(explicits + resolve_directories(wildcards)).uniq
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def resolve_directories(wildcard_dependencies)
|
|
47
|
-
return [] unless view_paths
|
|
48
|
-
return [] if wildcard_dependencies.empty?
|
|
49
|
-
|
|
50
|
-
# Remove trailing "/*"
|
|
51
|
-
prefixes = wildcard_dependencies.map { |query| query[0..-3] }
|
|
52
|
-
|
|
53
|
-
view_paths.flat_map(&:all_template_paths).uniq.filter_map { |path|
|
|
54
|
-
path.to_s if prefixes.include?(path.prefix)
|
|
55
|
-
}.sort
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|