actionview 7.0.8.1 → 7.2.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 (96) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +60 -425
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/app/assets/javascripts/rails-ujs.esm.js +686 -0
  6. data/app/assets/javascripts/rails-ujs.js +630 -0
  7. data/lib/action_view/base.rb +52 -14
  8. data/lib/action_view/buffers.rb +106 -8
  9. data/lib/action_view/cache_expiry.rb +44 -41
  10. data/lib/action_view/context.rb +1 -1
  11. data/lib/action_view/dependency_tracker/{ripper_tracker.rb → ruby_tracker.rb} +4 -3
  12. data/lib/action_view/dependency_tracker.rb +1 -1
  13. data/lib/action_view/deprecator.rb +7 -0
  14. data/lib/action_view/digestor.rb +1 -1
  15. data/lib/action_view/gem_version.rb +3 -3
  16. data/lib/action_view/helpers/active_model_helper.rb +1 -1
  17. data/lib/action_view/helpers/asset_tag_helper.rb +151 -55
  18. data/lib/action_view/helpers/asset_url_helper.rb +6 -5
  19. data/lib/action_view/helpers/atom_feed_helper.rb +5 -5
  20. data/lib/action_view/helpers/cache_helper.rb +7 -13
  21. data/lib/action_view/helpers/capture_helper.rb +30 -10
  22. data/lib/action_view/helpers/content_exfiltration_prevention_helper.rb +70 -0
  23. data/lib/action_view/helpers/controller_helper.rb +6 -0
  24. data/lib/action_view/helpers/csp_helper.rb +2 -2
  25. data/lib/action_view/helpers/csrf_helper.rb +3 -3
  26. data/lib/action_view/helpers/date_helper.rb +17 -19
  27. data/lib/action_view/helpers/debug_helper.rb +3 -3
  28. data/lib/action_view/helpers/form_helper.rb +248 -214
  29. data/lib/action_view/helpers/form_options_helper.rb +2 -1
  30. data/lib/action_view/helpers/form_tag_helper.rb +125 -58
  31. data/lib/action_view/helpers/javascript_helper.rb +1 -0
  32. data/lib/action_view/helpers/number_helper.rb +37 -330
  33. data/lib/action_view/helpers/output_safety_helper.rb +6 -6
  34. data/lib/action_view/helpers/rendering_helper.rb +1 -1
  35. data/lib/action_view/helpers/sanitize_helper.rb +51 -21
  36. data/lib/action_view/helpers/tag_helper.rb +210 -42
  37. data/lib/action_view/helpers/tags/base.rb +11 -52
  38. data/lib/action_view/helpers/tags/collection_check_boxes.rb +1 -0
  39. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +1 -0
  40. data/lib/action_view/helpers/tags/collection_select.rb +3 -0
  41. data/lib/action_view/helpers/tags/date_field.rb +1 -1
  42. data/lib/action_view/helpers/tags/date_select.rb +2 -0
  43. data/lib/action_view/helpers/tags/datetime_field.rb +14 -6
  44. data/lib/action_view/helpers/tags/datetime_local_field.rb +11 -2
  45. data/lib/action_view/helpers/tags/grouped_collection_select.rb +3 -0
  46. data/lib/action_view/helpers/tags/month_field.rb +1 -1
  47. data/lib/action_view/helpers/tags/select.rb +3 -0
  48. data/lib/action_view/helpers/tags/select_renderer.rb +56 -0
  49. data/lib/action_view/helpers/tags/time_field.rb +1 -1
  50. data/lib/action_view/helpers/tags/time_zone_select.rb +3 -0
  51. data/lib/action_view/helpers/tags/week_field.rb +1 -1
  52. data/lib/action_view/helpers/tags/weekday_select.rb +3 -0
  53. data/lib/action_view/helpers/tags.rb +2 -0
  54. data/lib/action_view/helpers/text_helper.rb +157 -85
  55. data/lib/action_view/helpers/translation_helper.rb +3 -3
  56. data/lib/action_view/helpers/url_helper.rb +35 -80
  57. data/lib/action_view/helpers.rb +2 -0
  58. data/lib/action_view/layouts.rb +8 -8
  59. data/lib/action_view/log_subscriber.rb +57 -36
  60. data/lib/action_view/lookup_context.rb +29 -13
  61. data/lib/action_view/path_registry.rb +57 -0
  62. data/lib/action_view/path_set.rb +13 -14
  63. data/lib/action_view/railtie.rb +25 -3
  64. data/lib/action_view/record_identifier.rb +15 -8
  65. data/lib/action_view/render_parser/prism_render_parser.rb +127 -0
  66. data/lib/action_view/render_parser/ripper_render_parser.rb +341 -0
  67. data/lib/action_view/render_parser.rb +21 -169
  68. data/lib/action_view/renderer/abstract_renderer.rb +2 -2
  69. data/lib/action_view/renderer/collection_renderer.rb +10 -2
  70. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +2 -1
  71. data/lib/action_view/renderer/partial_renderer.rb +2 -1
  72. data/lib/action_view/renderer/renderer.rb +34 -38
  73. data/lib/action_view/renderer/streaming_template_renderer.rb +3 -2
  74. data/lib/action_view/renderer/template_renderer.rb +3 -2
  75. data/lib/action_view/rendering.rb +26 -8
  76. data/lib/action_view/template/error.rb +14 -1
  77. data/lib/action_view/template/handlers/builder.rb +4 -4
  78. data/lib/action_view/template/handlers/erb/erubi.rb +23 -27
  79. data/lib/action_view/template/handlers/erb.rb +73 -1
  80. data/lib/action_view/template/handlers.rb +1 -1
  81. data/lib/action_view/template/html.rb +1 -1
  82. data/lib/action_view/template/raw_file.rb +1 -1
  83. data/lib/action_view/template/renderable.rb +8 -2
  84. data/lib/action_view/template/resolver.rb +9 -3
  85. data/lib/action_view/template/text.rb +1 -1
  86. data/lib/action_view/template/types.rb +25 -34
  87. data/lib/action_view/template.rb +278 -55
  88. data/lib/action_view/template_path.rb +2 -0
  89. data/lib/action_view/test_case.rb +181 -28
  90. data/lib/action_view/unbound_template.rb +17 -7
  91. data/lib/action_view/version.rb +1 -1
  92. data/lib/action_view/view_paths.rb +15 -24
  93. data/lib/action_view.rb +4 -1
  94. metadata +31 -31
  95. data/lib/action_view/ripper_ast_parser.rb +0 -198
  96. data/lib/assets/compiled/rails-ujs.js +0 -777
@@ -10,7 +10,7 @@ require "action_view/template"
10
10
  require "action_view/lookup_context"
11
11
 
12
12
  module ActionView # :nodoc:
13
- # = Action View Base
13
+ # = Action View \Base
14
14
  #
15
15
  # Action View templates can be written in several ways.
16
16
  # If the template file has a <tt>.erb</tt> extension, then it uses the erubi[https://rubygems.org/gems/erubi]
@@ -44,9 +44,9 @@ module ActionView # :nodoc:
44
44
  # Using sub templates allows you to sidestep tedious replication and extract common display structures in shared templates. The
45
45
  # classic example is the use of a header and footer (even though the Action Pack-way would be to use Layouts):
46
46
  #
47
- # <%= render "shared/header" %>
47
+ # <%= render "application/header" %>
48
48
  # Something really specific and terrific
49
- # <%= render "shared/footer" %>
49
+ # <%= render "application/footer" %>
50
50
  #
51
51
  # As you see, we use the output embeddings for the render methods. The render call itself will just return a string holding the
52
52
  # result of the rendering. The output embedding writes it to the current template.
@@ -55,7 +55,7 @@ module ActionView # :nodoc:
55
55
  # variables defined using the regular embedding tags. Like this:
56
56
  #
57
57
  # <% @page_title = "A Wonderful Hello" %>
58
- # <%= render "shared/header" %>
58
+ # <%= render "application/header" %>
59
59
  #
60
60
  # Now the header can pick up on the <tt>@page_title</tt> variable and use it for outputting a title tag:
61
61
  #
@@ -65,9 +65,9 @@ module ActionView # :nodoc:
65
65
  #
66
66
  # You can pass local variables to sub templates by using a hash with the variable names as keys and the objects as values:
67
67
  #
68
- # <%= render "shared/header", { headline: "Welcome", person: person } %>
68
+ # <%= render "application/header", { headline: "Welcome", person: person } %>
69
69
  #
70
- # These can now be accessed in <tt>shared/header</tt> with:
70
+ # These can now be accessed in <tt>application/header</tt> with:
71
71
  #
72
72
  # Headline: <%= headline %>
73
73
  # First name: <%= person.first_name %>
@@ -80,10 +80,27 @@ module ActionView # :nodoc:
80
80
  # This is useful in cases where you aren't sure if the local variable has been assigned. Alternatively, you could also use
81
81
  # <tt>defined? headline</tt> to first check if the variable has been assigned before using it.
82
82
  #
83
+ # By default, templates will accept any <tt>locals</tt> as keyword arguments. To restrict what <tt>locals</tt> a template accepts, add a <tt>locals:</tt> magic comment:
84
+ #
85
+ # <%# locals: (headline:) %>
86
+ #
87
+ # Headline: <%= headline %>
88
+ #
89
+ # In cases where the local variables are optional, declare the keyword argument with a default value:
90
+ #
91
+ # <%# locals: (headline: nil) %>
92
+ #
93
+ # <% unless headline.nil? %>
94
+ # Headline: <%= headline %>
95
+ # <% end %>
96
+ #
97
+ # Read more about strict locals in {Action View Overview}[https://guides.rubyonrails.org/action_view_overview.html#strict-locals]
98
+ # in the guides.
99
+ #
83
100
  # === Template caching
84
101
  #
85
- # By default, Rails will compile each template to a method in order to render it. When you alter a template,
86
- # Rails will check the file's modification time and recompile it in development mode.
102
+ # By default, \Rails will compile each template to a method in order to render it. When you alter a template,
103
+ # \Rails will check the file's modification time and recompile it in development mode.
87
104
  #
88
105
  # == Builder
89
106
  #
@@ -136,8 +153,7 @@ module ActionView # :nodoc:
136
153
  # end
137
154
  # end
138
155
  #
139
- # For more information on Builder please consult the {source
140
- # code}[https://github.com/jimweirich/builder].
156
+ # For more information on Builder please consult the {source code}[https://github.com/rails/builder].
141
157
  class Base
142
158
  include Helpers, ::ERB::Util, Context
143
159
 
@@ -205,7 +221,8 @@ module ActionView # :nodoc:
205
221
  delegate :formats, :formats=, :locale, :locale=, :view_paths, :view_paths=, to: :lookup_context
206
222
 
207
223
  def assign(new_assigns) # :nodoc:
208
- @_assigns = new_assigns.each { |key, value| instance_variable_set("@#{key}", value) }
224
+ @_assigns = new_assigns
225
+ new_assigns.each { |key, value| instance_variable_set("@#{key}", value) }
209
226
  end
210
227
 
211
228
  # :stopdoc:
@@ -232,16 +249,37 @@ module ActionView # :nodoc:
232
249
  @view_renderer = ActionView::Renderer.new @lookup_context
233
250
  @current_template = nil
234
251
 
235
- assign(assigns)
236
252
  assign_controller(controller)
237
253
  _prepare_context
254
+
255
+ super()
256
+
257
+ # Assigns must be called last to minimize the number of shapes
258
+ assign(assigns)
238
259
  end
239
260
 
240
- def _run(method, template, locals, buffer, add_to_stack: true, &block)
261
+ def _run(method, template, locals, buffer, add_to_stack: true, has_strict_locals: false, &block)
241
262
  _old_output_buffer, _old_virtual_path, _old_template = @output_buffer, @virtual_path, @current_template
242
263
  @current_template = template if add_to_stack
243
264
  @output_buffer = buffer
244
- public_send(method, locals, buffer, &block)
265
+
266
+ if has_strict_locals
267
+ begin
268
+ public_send(method, locals, buffer, **locals, &block)
269
+ rescue ArgumentError => argument_error
270
+ raise(
271
+ ArgumentError,
272
+ argument_error.
273
+ message.
274
+ gsub("unknown keyword:", "unknown local:").
275
+ gsub("missing keyword:", "missing local:").
276
+ gsub("no keywords accepted", "no locals accepted").
277
+ concat(" for #{@current_template.short_identifier}")
278
+ )
279
+ end
280
+ else
281
+ public_send(method, locals, buffer, &block)
282
+ end
245
283
  ensure
246
284
  @output_buffer, @virtual_path, @current_template = _old_output_buffer, _old_virtual_path, _old_template
247
285
  end
@@ -18,24 +18,91 @@ module ActionView
18
18
  # sbuf << 5
19
19
  # puts sbuf # => "hello\u0005"
20
20
  #
21
- class OutputBuffer < ActiveSupport::SafeBuffer # :nodoc:
22
- def initialize(*)
23
- super
24
- encode!
21
+ class OutputBuffer # :nodoc:
22
+ def initialize(buffer = "")
23
+ @raw_buffer = String.new(buffer)
24
+ @raw_buffer.encode!
25
+ end
26
+
27
+ delegate :length, :empty?, :blank?, :encoding, :encode!, :force_encoding, to: :@raw_buffer
28
+
29
+ def to_s
30
+ @raw_buffer.html_safe
31
+ end
32
+ alias_method :html_safe, :to_s
33
+
34
+ def to_str
35
+ @raw_buffer.dup
36
+ end
37
+
38
+ def html_safe?
39
+ true
25
40
  end
26
41
 
27
42
  def <<(value)
28
- return self if value.nil?
29
- super(value.to_s)
43
+ unless value.nil?
44
+ value = value.to_s
45
+ @raw_buffer << if value.html_safe?
46
+ value
47
+ else
48
+ CGI.escapeHTML(value)
49
+ end
50
+ end
51
+ self
30
52
  end
53
+ alias :concat :<<
31
54
  alias :append= :<<
32
55
 
56
+ def safe_concat(value)
57
+ @raw_buffer << value
58
+ self
59
+ end
60
+ alias :safe_append= :safe_concat
61
+
33
62
  def safe_expr_append=(val)
34
63
  return self if val.nil?
35
- safe_concat val.to_s
64
+ @raw_buffer << val.to_s
65
+ self
36
66
  end
37
67
 
38
- alias :safe_append= :safe_concat
68
+ def initialize_copy(other)
69
+ @raw_buffer = other.to_str
70
+ end
71
+
72
+ def capture(*args)
73
+ new_buffer = +""
74
+ old_buffer, @raw_buffer = @raw_buffer, new_buffer
75
+ yield(*args)
76
+ new_buffer.html_safe
77
+ ensure
78
+ @raw_buffer = old_buffer
79
+ end
80
+
81
+ def ==(other)
82
+ other.class == self.class && @raw_buffer == other.to_str
83
+ end
84
+
85
+ def raw
86
+ RawOutputBuffer.new(self)
87
+ end
88
+
89
+ attr_reader :raw_buffer
90
+ end
91
+
92
+ class RawOutputBuffer # :nodoc:
93
+ def initialize(buffer)
94
+ @buffer = buffer
95
+ end
96
+
97
+ def <<(value)
98
+ unless value.nil?
99
+ @buffer.raw_buffer << value.to_s
100
+ end
101
+ end
102
+
103
+ def raw
104
+ self
105
+ end
39
106
  end
40
107
 
41
108
  class StreamingBuffer # :nodoc:
@@ -56,6 +123,15 @@ module ActionView
56
123
  end
57
124
  alias :safe_append= :safe_concat
58
125
 
126
+ def capture
127
+ buffer = +""
128
+ old_block, @block = @block, ->(value) { buffer << value }
129
+ yield
130
+ buffer.html_safe
131
+ ensure
132
+ @block = old_block
133
+ end
134
+
59
135
  def html_safe?
60
136
  true
61
137
  end
@@ -63,5 +139,27 @@ module ActionView
63
139
  def html_safe
64
140
  self
65
141
  end
142
+
143
+ def raw
144
+ RawStreamingBuffer.new(self)
145
+ end
146
+
147
+ attr_reader :block
148
+ end
149
+
150
+ class RawStreamingBuffer # :nodoc:
151
+ def initialize(buffer)
152
+ @buffer = buffer
153
+ end
154
+
155
+ def <<(value)
156
+ unless value.nil?
157
+ @buffer.block.call(value.to_s)
158
+ end
159
+ end
160
+
161
+ def raw
162
+ self
163
+ end
66
164
  end
67
165
  end
@@ -1,65 +1,68 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionView
4
- class CacheExpiry
5
- class Executor
6
- def initialize(watcher:)
7
- @execution_lock = Concurrent::ReentrantReadWriteLock.new
8
- @cache_expiry = ViewModificationWatcher.new(watcher: watcher) do
9
- clear_cache
10
- end
4
+ module CacheExpiry # :nodoc: all
5
+ class ViewReloader
6
+ def initialize(watcher:, &block)
7
+ @mutex = Mutex.new
8
+ @watcher_class = watcher
9
+ @watched_dirs = nil
10
+ @watcher = nil
11
+ @previous_change = false
12
+
13
+ ActionView::PathRegistry.file_system_resolver_hooks << method(:rebuild_watcher)
11
14
  end
12
15
 
13
- def run
14
- ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
15
- @cache_expiry.execute_if_updated
16
- @execution_lock.acquire_read_lock
17
- end
16
+ def updated?
17
+ build_watcher unless @watcher
18
+ @previous_change || @watcher.updated?
18
19
  end
19
20
 
20
- def complete(_)
21
- @execution_lock.release_read_lock
21
+ def execute
22
+ return unless @watcher
23
+
24
+ watcher = nil
25
+ @mutex.synchronize do
26
+ @previous_change = false
27
+ watcher = @watcher
28
+ end
29
+ watcher.execute
22
30
  end
23
31
 
24
32
  private
25
- def clear_cache
26
- @execution_lock.with_write_lock do
27
- ActionView::LookupContext::DetailsKey.clear
28
- end
33
+ def reload!
34
+ ActionView::LookupContext::DetailsKey.clear
29
35
  end
30
- end
31
36
 
32
- class ViewModificationWatcher
33
- def initialize(watcher:, &block)
34
- @watched_dirs = nil
35
- @watcher_class = watcher
36
- @watcher = nil
37
- @mutex = Mutex.new
38
- @block = block
39
- end
37
+ def build_watcher
38
+ @mutex.synchronize do
39
+ old_watcher = @watcher
40
40
 
41
- def execute_if_updated
42
- @mutex.synchronize do
43
- watched_dirs = dirs_to_watch
44
- return if watched_dirs.empty?
41
+ if @watched_dirs != dirs_to_watch
42
+ @watched_dirs = dirs_to_watch
43
+ new_watcher = @watcher_class.new([], @watched_dirs) do
44
+ reload!
45
+ end
46
+ @watcher = new_watcher
45
47
 
46
- if watched_dirs != @watched_dirs
47
- @watched_dirs = watched_dirs
48
- @watcher = @watcher_class.new([], watched_dirs, &@block)
49
- @watcher.execute
50
- else
51
- @watcher.execute_if_updated
48
+ # We must check the old watcher after initializing the new one to
49
+ # ensure we don't miss any events
50
+ @previous_change ||= old_watcher&.updated?
51
+ end
52
52
  end
53
53
  end
54
- end
55
54
 
56
- private
55
+ def rebuild_watcher
56
+ return unless @watcher
57
+ build_watcher
58
+ end
59
+
57
60
  def dirs_to_watch
58
- all_view_paths.grep(FileSystemResolver).map!(&:path).tap(&:uniq!).sort!
61
+ all_view_paths.uniq.sort
59
62
  end
60
63
 
61
64
  def all_view_paths
62
- ActionView::ViewPaths.all_view_paths.flat_map(&:paths)
65
+ ActionView::PathRegistry.all_file_system_resolvers.map(&:path)
63
66
  end
64
67
  end
65
68
  end
@@ -17,7 +17,7 @@ module ActionView
17
17
  # Prepares the context by setting the appropriate instance variables.
18
18
  def _prepare_context
19
19
  @view_flow = OutputFlow.new
20
- @output_buffer = nil
20
+ @output_buffer = ActionView::OutputBuffer.new
21
21
  @virtual_path = nil
22
22
  end
23
23
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  module ActionView
4
4
  class DependencyTracker # :nodoc:
5
- class RipperTracker # :nodoc:
5
+ class RubyTracker # :nodoc:
6
6
  EXPLICIT_DEPENDENCY = /# Template Dependency: (\S+)/
7
7
 
8
8
  def self.call(name, template, view_paths = nil)
@@ -17,8 +17,9 @@ module ActionView
17
17
  true
18
18
  end
19
19
 
20
- def initialize(name, template, view_paths = nil)
20
+ def initialize(name, template, view_paths = nil, parser_class: RenderParser::Default)
21
21
  @name, @template, @view_paths = name, template, view_paths
22
+ @parser_class = parser_class
22
23
  end
23
24
 
24
25
  private
@@ -29,7 +30,7 @@ module ActionView
29
30
 
30
31
  compiled_source = template.handler.call(template, template.source)
31
32
 
32
- RenderParser.new(@name, compiled_source).render_calls.filter_map do |render_call|
33
+ @parser_class.new(@name, compiled_source).render_calls.filter_map do |render_call|
33
34
  next if render_call.end_with?("/_")
34
35
  render_call.gsub(%r|/_|, "/")
35
36
  end
@@ -9,7 +9,7 @@ module ActionView
9
9
  extend ActiveSupport::Autoload
10
10
 
11
11
  autoload :ERBTracker
12
- autoload :RipperTracker
12
+ autoload :RubyTracker
13
13
 
14
14
  @trackers = Concurrent::Map.new
15
15
 
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionView
4
+ def self.deprecator # :nodoc:
5
+ @deprecator ||= ActiveSupport::Deprecation.new
6
+ end
7
+ end
@@ -11,7 +11,7 @@ module ActionView
11
11
  #
12
12
  # * <tt>name</tt> - Template name
13
13
  # * <tt>format</tt> - Template format
14
- # * <tt>finder</tt> - An instance of <tt>ActionView::LookupContext</tt>
14
+ # * +finder+ - An instance of ActionView::LookupContext
15
15
  # * <tt>dependencies</tt> - An array of dependent views
16
16
  def digest(name:, format: nil, finder:, dependencies: nil)
17
17
  if dependencies.nil? || dependencies.empty?
@@ -1,15 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionView
4
- # Returns the currently loaded version of Action View as a <tt>Gem::Version</tt>.
4
+ # Returns the currently loaded version of Action View as a +Gem::Version+.
5
5
  def self.gem_version
6
6
  Gem::Version.new VERSION::STRING
7
7
  end
8
8
 
9
9
  module VERSION
10
10
  MAJOR = 7
11
- MINOR = 0
12
- TINY = 8
11
+ MINOR = 2
12
+ TINY = 2
13
13
  PRE = "1"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
@@ -4,11 +4,11 @@ require "active_support/core_ext/module/attribute_accessors"
4
4
  require "active_support/core_ext/enumerable"
5
5
 
6
6
  module ActionView
7
- # = Active Model Helpers
8
7
  module Helpers # :nodoc:
9
8
  module ActiveModelHelper
10
9
  end
11
10
 
11
+ # = Active \Model Instance Tag \Helpers
12
12
  module ActiveModelInstanceTag
13
13
  def object
14
14
  @active_model_object ||= begin