actionview 7.0.1 → 7.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +281 -202
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +3 -3
  5. data/app/assets/javascripts/rails-ujs.esm.js +693 -0
  6. data/app/assets/javascripts/rails-ujs.js +630 -0
  7. data/lib/action_view/base.rb +33 -12
  8. data/lib/action_view/buffers.rb +106 -8
  9. data/lib/action_view/cache_expiry.rb +40 -43
  10. data/lib/action_view/context.rb +1 -1
  11. data/lib/action_view/deprecator.rb +7 -0
  12. data/lib/action_view/digestor.rb +1 -1
  13. data/lib/action_view/gem_version.rb +2 -2
  14. data/lib/action_view/helpers/active_model_helper.rb +1 -1
  15. data/lib/action_view/helpers/asset_tag_helper.rb +133 -48
  16. data/lib/action_view/helpers/asset_url_helper.rb +13 -12
  17. data/lib/action_view/helpers/atom_feed_helper.rb +5 -5
  18. data/lib/action_view/helpers/cache_helper.rb +3 -9
  19. data/lib/action_view/helpers/capture_helper.rb +26 -12
  20. data/lib/action_view/helpers/content_exfiltration_prevention_helper.rb +70 -0
  21. data/lib/action_view/helpers/controller_helper.rb +6 -0
  22. data/lib/action_view/helpers/csp_helper.rb +2 -2
  23. data/lib/action_view/helpers/csrf_helper.rb +3 -3
  24. data/lib/action_view/helpers/date_helper.rb +76 -64
  25. data/lib/action_view/helpers/debug_helper.rb +3 -3
  26. data/lib/action_view/helpers/form_helper.rb +62 -31
  27. data/lib/action_view/helpers/form_options_helper.rb +6 -3
  28. data/lib/action_view/helpers/form_tag_helper.rb +88 -44
  29. data/lib/action_view/helpers/javascript_helper.rb +1 -0
  30. data/lib/action_view/helpers/number_helper.rb +15 -13
  31. data/lib/action_view/helpers/output_safety_helper.rb +4 -4
  32. data/lib/action_view/helpers/rendering_helper.rb +5 -6
  33. data/lib/action_view/helpers/sanitize_helper.rb +34 -15
  34. data/lib/action_view/helpers/tag_helper.rb +27 -16
  35. data/lib/action_view/helpers/tags/base.rb +11 -52
  36. data/lib/action_view/helpers/tags/collection_check_boxes.rb +1 -0
  37. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +1 -0
  38. data/lib/action_view/helpers/tags/collection_select.rb +3 -0
  39. data/lib/action_view/helpers/tags/date_field.rb +1 -1
  40. data/lib/action_view/helpers/tags/date_select.rb +2 -0
  41. data/lib/action_view/helpers/tags/datetime_field.rb +14 -6
  42. data/lib/action_view/helpers/tags/datetime_local_field.rb +11 -2
  43. data/lib/action_view/helpers/tags/grouped_collection_select.rb +3 -0
  44. data/lib/action_view/helpers/tags/month_field.rb +1 -1
  45. data/lib/action_view/helpers/tags/select.rb +4 -1
  46. data/lib/action_view/helpers/tags/select_renderer.rb +56 -0
  47. data/lib/action_view/helpers/tags/time_field.rb +1 -1
  48. data/lib/action_view/helpers/tags/time_zone_select.rb +3 -0
  49. data/lib/action_view/helpers/tags/week_field.rb +1 -1
  50. data/lib/action_view/helpers/tags/weekday_select.rb +3 -0
  51. data/lib/action_view/helpers/tags.rb +2 -0
  52. data/lib/action_view/helpers/text_helper.rb +33 -17
  53. data/lib/action_view/helpers/translation_helper.rb +6 -6
  54. data/lib/action_view/helpers/url_helper.rb +90 -65
  55. data/lib/action_view/helpers.rb +2 -0
  56. data/lib/action_view/layouts.rb +13 -8
  57. data/lib/action_view/log_subscriber.rb +49 -32
  58. data/lib/action_view/lookup_context.rb +29 -13
  59. data/lib/action_view/path_registry.rb +57 -0
  60. data/lib/action_view/path_set.rb +13 -14
  61. data/lib/action_view/railtie.rb +26 -3
  62. data/lib/action_view/record_identifier.rb +16 -9
  63. data/lib/action_view/renderer/abstract_renderer.rb +1 -1
  64. data/lib/action_view/renderer/collection_renderer.rb +9 -1
  65. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +21 -3
  66. data/lib/action_view/renderer/partial_renderer.rb +3 -2
  67. data/lib/action_view/renderer/renderer.rb +2 -0
  68. data/lib/action_view/renderer/streaming_template_renderer.rb +3 -2
  69. data/lib/action_view/renderer/template_renderer.rb +3 -2
  70. data/lib/action_view/rendering.rb +24 -6
  71. data/lib/action_view/ripper_ast_parser.rb +6 -6
  72. data/lib/action_view/routing_url_for.rb +7 -4
  73. data/lib/action_view/template/error.rb +14 -1
  74. data/lib/action_view/template/handlers/builder.rb +4 -4
  75. data/lib/action_view/template/handlers/erb/erubi.rb +23 -27
  76. data/lib/action_view/template/handlers/erb.rb +73 -1
  77. data/lib/action_view/template/handlers.rb +1 -1
  78. data/lib/action_view/template/html.rb +1 -1
  79. data/lib/action_view/template/raw_file.rb +1 -1
  80. data/lib/action_view/template/renderable.rb +1 -1
  81. data/lib/action_view/template/resolver.rb +15 -5
  82. data/lib/action_view/template/text.rb +1 -1
  83. data/lib/action_view/template/types.rb +25 -34
  84. data/lib/action_view/template.rb +227 -53
  85. data/lib/action_view/template_path.rb +2 -0
  86. data/lib/action_view/test_case.rb +174 -21
  87. data/lib/action_view/unbound_template.rb +15 -5
  88. data/lib/action_view/version.rb +1 -1
  89. data/lib/action_view/view_paths.rb +19 -28
  90. data/lib/action_view.rb +4 -1
  91. data/lib/assets/compiled/rails-ujs.js +36 -5
  92. metadata +27 -27
@@ -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 %>
@@ -82,8 +82,8 @@ module ActionView # :nodoc:
82
82
  #
83
83
  # === Template caching
84
84
  #
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.
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.
87
87
  #
88
88
  # == Builder
89
89
  #
@@ -205,7 +205,8 @@ module ActionView # :nodoc:
205
205
  delegate :formats, :formats=, :locale, :locale=, :view_paths, :view_paths=, to: :lookup_context
206
206
 
207
207
  def assign(new_assigns) # :nodoc:
208
- @_assigns = new_assigns.each { |key, value| instance_variable_set("@#{key}", value) }
208
+ @_assigns = new_assigns
209
+ new_assigns.each { |key, value| instance_variable_set("@#{key}", value) }
209
210
  end
210
211
 
211
212
  # :stopdoc:
@@ -232,16 +233,36 @@ module ActionView # :nodoc:
232
233
  @view_renderer = ActionView::Renderer.new @lookup_context
233
234
  @current_template = nil
234
235
 
235
- assign(assigns)
236
236
  assign_controller(controller)
237
237
  _prepare_context
238
+
239
+ super()
240
+
241
+ # Assigns must be called last to minimize the number of shapes
242
+ assign(assigns)
238
243
  end
239
244
 
240
- def _run(method, template, locals, buffer, add_to_stack: true, &block)
245
+ def _run(method, template, locals, buffer, add_to_stack: true, has_strict_locals: false, &block)
241
246
  _old_output_buffer, _old_virtual_path, _old_template = @output_buffer, @virtual_path, @current_template
242
247
  @current_template = template if add_to_stack
243
248
  @output_buffer = buffer
244
- public_send(method, locals, buffer, &block)
249
+
250
+ if has_strict_locals
251
+ begin
252
+ public_send(method, buffer, **locals, &block)
253
+ rescue ArgumentError => argument_error
254
+ raise(
255
+ ArgumentError,
256
+ argument_error.
257
+ message.
258
+ gsub("unknown keyword:", "unknown local:").
259
+ gsub("missing keyword:", "missing local:").
260
+ gsub("no keywords accepted", "no locals accepted")
261
+ )
262
+ end
263
+ else
264
+ public_send(method, locals, buffer, &block)
265
+ end
245
266
  ensure
246
267
  @output_buffer, @virtual_path, @current_template = _old_output_buffer, _old_virtual_path, _old_template
247
268
  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,62 @@
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
11
- 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
12
 
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
13
+ rebuild_watcher
14
+
15
+ ActionView::PathRegistry.file_system_resolver_hooks << method(:rebuild_watcher)
18
16
  end
19
17
 
20
- def complete(_)
21
- @execution_lock.release_read_lock
18
+ def updated?
19
+ @previous_change || @watcher.updated?
22
20
  end
23
21
 
24
- private
25
- def clear_cache
26
- @execution_lock.with_write_lock do
27
- ActionView::LookupContext::DetailsKey.clear
28
- end
22
+ def execute
23
+ watcher = nil
24
+ @mutex.synchronize do
25
+ @previous_change = false
26
+ watcher = @watcher
29
27
  end
30
- end
31
-
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
28
+ watcher.execute
39
29
  end
40
30
 
41
- def execute_if_updated
42
- @mutex.synchronize do
43
- watched_dirs = dirs_to_watch
44
- return if watched_dirs.empty?
31
+ private
32
+ def reload!
33
+ ActionView::LookupContext::DetailsKey.clear
34
+ end
45
35
 
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
36
+ def rebuild_watcher
37
+ @mutex.synchronize do
38
+ old_watcher = @watcher
39
+
40
+ if @watched_dirs != dirs_to_watch
41
+ @watched_dirs = dirs_to_watch
42
+ new_watcher = @watcher_class.new([], @watched_dirs) do
43
+ reload!
44
+ end
45
+ @watcher = new_watcher
46
+
47
+ # We must check the old watcher after initializing the new one to
48
+ # ensure we don't miss any events
49
+ @previous_change ||= old_watcher&.updated?
50
+ end
52
51
  end
53
52
  end
54
- end
55
53
 
56
- private
57
54
  def dirs_to_watch
58
- all_view_paths.grep(FileSystemResolver).map!(&:path).tap(&:uniq!).sort!
55
+ all_view_paths.uniq.sort
59
56
  end
60
57
 
61
58
  def all_view_paths
62
- ActionView::ViewPaths.all_view_paths.flat_map(&:paths)
59
+ ActionView::PathRegistry.all_file_system_resolvers.map(&:path)
63
60
  end
64
61
  end
65
62
  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
 
@@ -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,14 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionView
4
- # Returns the version of the currently loaded 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
11
+ MINOR = 1
12
12
  TINY = 1
13
13
  PRE = nil
14
14
 
@@ -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