actionview 4.1.13 → 6.1.3.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionview might be problematic. Click here for more details.

Files changed (124) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +181 -359
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +12 -6
  5. data/lib/action_view/base.rb +115 -43
  6. data/lib/action_view/buffers.rb +22 -4
  7. data/lib/action_view/cache_expiry.rb +52 -0
  8. data/lib/action_view/context.rb +8 -12
  9. data/lib/action_view/dependency_tracker.rb +61 -21
  10. data/lib/action_view/digestor.rb +89 -84
  11. data/lib/action_view/flows.rb +12 -13
  12. data/lib/action_view/gem_version.rb +6 -4
  13. data/lib/action_view/helpers/active_model_helper.rb +16 -11
  14. data/lib/action_view/helpers/asset_tag_helper.rb +311 -105
  15. data/lib/action_view/helpers/asset_url_helper.rb +197 -80
  16. data/lib/action_view/helpers/atom_feed_helper.rb +20 -17
  17. data/lib/action_view/helpers/cache_helper.rb +109 -45
  18. data/lib/action_view/helpers/capture_helper.rb +20 -22
  19. data/lib/action_view/helpers/controller_helper.rb +15 -4
  20. data/lib/action_view/helpers/csp_helper.rb +26 -0
  21. data/lib/action_view/helpers/csrf_helper.rb +8 -6
  22. data/lib/action_view/helpers/date_helper.rb +245 -140
  23. data/lib/action_view/helpers/debug_helper.rb +14 -17
  24. data/lib/action_view/helpers/form_helper.rb +875 -148
  25. data/lib/action_view/helpers/form_options_helper.rb +128 -82
  26. data/lib/action_view/helpers/form_tag_helper.rb +253 -91
  27. data/lib/action_view/helpers/javascript_helper.rb +37 -15
  28. data/lib/action_view/helpers/number_helper.rb +100 -77
  29. data/lib/action_view/helpers/output_safety_helper.rb +42 -10
  30. data/lib/action_view/helpers/rendering_helper.rb +26 -15
  31. data/lib/action_view/helpers/sanitize_helper.rb +79 -164
  32. data/lib/action_view/helpers/tag_helper.rb +277 -64
  33. data/lib/action_view/helpers/tags/base.rb +143 -92
  34. data/lib/action_view/helpers/tags/check_box.rb +20 -19
  35. data/lib/action_view/helpers/tags/checkable.rb +4 -2
  36. data/lib/action_view/helpers/tags/collection_check_boxes.rb +12 -30
  37. data/lib/action_view/helpers/tags/collection_helpers.rb +69 -36
  38. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +6 -12
  39. data/lib/action_view/helpers/tags/collection_select.rb +4 -2
  40. data/lib/action_view/helpers/tags/color_field.rb +4 -3
  41. data/lib/action_view/helpers/tags/date_field.rb +3 -2
  42. data/lib/action_view/helpers/tags/date_select.rb +38 -37
  43. data/lib/action_view/helpers/tags/datetime_field.rb +14 -5
  44. data/lib/action_view/helpers/tags/datetime_local_field.rb +3 -2
  45. data/lib/action_view/helpers/tags/datetime_select.rb +2 -0
  46. data/lib/action_view/helpers/tags/email_field.rb +2 -0
  47. data/lib/action_view/helpers/tags/file_field.rb +2 -0
  48. data/lib/action_view/helpers/tags/grouped_collection_select.rb +4 -2
  49. data/lib/action_view/helpers/tags/hidden_field.rb +2 -0
  50. data/lib/action_view/helpers/tags/label.rb +41 -22
  51. data/lib/action_view/helpers/tags/month_field.rb +3 -2
  52. data/lib/action_view/helpers/tags/number_field.rb +2 -0
  53. data/lib/action_view/helpers/tags/password_field.rb +3 -1
  54. data/lib/action_view/helpers/tags/placeholderable.rb +24 -0
  55. data/lib/action_view/helpers/tags/radio_button.rb +7 -6
  56. data/lib/action_view/helpers/tags/range_field.rb +2 -0
  57. data/lib/action_view/helpers/tags/search_field.rb +3 -0
  58. data/lib/action_view/helpers/tags/select.rb +11 -10
  59. data/lib/action_view/helpers/tags/tel_field.rb +2 -0
  60. data/lib/action_view/helpers/tags/text_area.rb +7 -1
  61. data/lib/action_view/helpers/tags/text_field.rb +11 -7
  62. data/lib/action_view/helpers/tags/time_field.rb +3 -2
  63. data/lib/action_view/helpers/tags/time_select.rb +2 -0
  64. data/lib/action_view/helpers/tags/time_zone_select.rb +3 -1
  65. data/lib/action_view/helpers/tags/translator.rb +39 -0
  66. data/lib/action_view/helpers/tags/url_field.rb +2 -0
  67. data/lib/action_view/helpers/tags/week_field.rb +3 -2
  68. data/lib/action_view/helpers/tags.rb +4 -1
  69. data/lib/action_view/helpers/text_helper.rb +80 -45
  70. data/lib/action_view/helpers/translation_helper.rb +148 -67
  71. data/lib/action_view/helpers/url_helper.rb +289 -147
  72. data/lib/action_view/helpers.rb +5 -3
  73. data/lib/action_view/layouts.rb +68 -63
  74. data/lib/action_view/log_subscriber.rb +80 -13
  75. data/lib/action_view/lookup_context.rb +137 -92
  76. data/lib/action_view/model_naming.rb +4 -2
  77. data/lib/action_view/path_set.rb +30 -16
  78. data/lib/action_view/railtie.rb +62 -13
  79. data/lib/action_view/record_identifier.rb +53 -26
  80. data/lib/action_view/renderer/abstract_renderer.rb +152 -13
  81. data/lib/action_view/renderer/collection_renderer.rb +196 -0
  82. data/lib/action_view/renderer/object_renderer.rb +34 -0
  83. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +102 -0
  84. data/lib/action_view/renderer/partial_renderer.rb +61 -261
  85. data/lib/action_view/renderer/renderer.rb +67 -6
  86. data/lib/action_view/renderer/streaming_template_renderer.rb +58 -54
  87. data/lib/action_view/renderer/template_renderer.rb +83 -75
  88. data/lib/action_view/rendering.rb +73 -46
  89. data/lib/action_view/routing_url_for.rb +54 -17
  90. data/lib/action_view/tasks/cache_digests.rake +25 -0
  91. data/lib/action_view/template/error.rb +44 -29
  92. data/lib/action_view/template/handlers/builder.rb +12 -13
  93. data/lib/action_view/template/handlers/erb/erubi.rb +89 -0
  94. data/lib/action_view/template/handlers/erb.rb +23 -89
  95. data/lib/action_view/template/handlers/html.rb +11 -0
  96. data/lib/action_view/template/handlers/raw.rb +4 -4
  97. data/lib/action_view/template/handlers.rb +22 -9
  98. data/lib/action_view/template/html.rb +10 -11
  99. data/lib/action_view/template/inline.rb +22 -0
  100. data/lib/action_view/template/raw_file.rb +25 -0
  101. data/lib/action_view/template/renderable.rb +24 -0
  102. data/lib/action_view/template/resolver.rb +267 -181
  103. data/lib/action_view/template/sources/file.rb +17 -0
  104. data/lib/action_view/template/sources.rb +13 -0
  105. data/lib/action_view/template/text.rb +8 -10
  106. data/lib/action_view/template/types.rb +18 -18
  107. data/lib/action_view/template.rb +109 -99
  108. data/lib/action_view/test_case.rb +73 -53
  109. data/lib/action_view/testing/resolvers.rb +24 -33
  110. data/lib/action_view/unbound_template.rb +31 -0
  111. data/lib/action_view/version.rb +3 -1
  112. data/lib/action_view/view_paths.rb +74 -44
  113. data/lib/action_view.rb +14 -9
  114. data/lib/assets/compiled/rails-ujs.js +746 -0
  115. metadata +71 -26
  116. data/lib/action_view/helpers/record_tag_helper.rb +0 -108
  117. data/lib/action_view/tasks/dependencies.rake +0 -23
  118. data/lib/action_view/vendor/html-scanner/html/document.rb +0 -68
  119. data/lib/action_view/vendor/html-scanner/html/node.rb +0 -532
  120. data/lib/action_view/vendor/html-scanner/html/sanitizer.rb +0 -188
  121. data/lib/action_view/vendor/html-scanner/html/selector.rb +0 -830
  122. data/lib/action_view/vendor/html-scanner/html/tokenizer.rb +0 -107
  123. data/lib/action_view/vendor/html-scanner/html/version.rb +0 -11
  124. data/lib/action_view/vendor/html-scanner.rb +0 -20
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2004-2014 David Heinemeier Hansson
1
+ Copyright (c) 2004-2020 David Heinemeier Hansson
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.rdoc CHANGED
@@ -5,30 +5,36 @@ view helpers that assist when building HTML forms, Atom feeds and more.
5
5
  Template formats that Action View handles are ERB (embedded Ruby, typically
6
6
  used to inline short Ruby snippets inside HTML), and XML Builder.
7
7
 
8
+ You can read more about Action View in the {Action View Overview}[https://edgeguides.rubyonrails.org/action_view_overview.html] guide.
9
+
8
10
  == Download and installation
9
11
 
10
12
  The latest version of Action View can be installed with RubyGems:
11
13
 
12
- % [sudo] gem install actionview
14
+ $ gem install actionview
13
15
 
14
- Source code can be downloaded as part of the Rails project on GitHub
16
+ Source code can be downloaded as part of the Rails project on GitHub:
15
17
 
16
- * https://github.com/rails/rails/tree/4-1-stable/actionview
18
+ * https://github.com/rails/rails/tree/main/actionview
17
19
 
18
20
 
19
21
  == License
20
22
 
21
23
  Action View is released under the MIT license:
22
24
 
23
- * http://www.opensource.org/licenses/MIT
25
+ * https://opensource.org/licenses/MIT
24
26
 
25
27
 
26
28
  == Support
27
29
 
28
30
  API documentation is at
29
31
 
30
- * http://api.rubyonrails.org
32
+ * https://api.rubyonrails.org
31
33
 
32
- Bug reports and feature requests can be filed with the rest for the Ruby on Rails project here:
34
+ Bug reports for the Ruby on Rails project can be filed here:
33
35
 
34
36
  * https://github.com/rails/rails/issues
37
+
38
+ Feature requests should be discussed on the rails-core mailing list here:
39
+
40
+ * https://discuss.rubyonrails.org/c/rubyonrails-core
@@ -1,21 +1,25 @@
1
- require 'active_support/core_ext/module/attr_internal'
2
- require 'active_support/core_ext/module/attribute_accessors'
3
- require 'active_support/ordered_options'
4
- require 'action_view/log_subscriber'
5
- require 'action_view/helpers'
6
- require 'action_view/context'
7
- require 'action_view/template'
8
- require 'action_view/lookup_context'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module/attr_internal"
4
+ require "active_support/core_ext/module/attribute_accessors"
5
+ require "active_support/ordered_options"
6
+ require "action_view/log_subscriber"
7
+ require "action_view/helpers"
8
+ require "action_view/context"
9
+ require "action_view/template"
10
+ require "action_view/lookup_context"
9
11
 
10
12
  module ActionView #:nodoc:
11
13
  # = Action View Base
12
14
  #
13
- # Action View templates can be written in several ways. If the template file has a <tt>.erb</tt> extension then it uses a mixture of ERB
14
- # (included in Ruby) and HTML. If the template file has a <tt>.builder</tt> extension then Jim Weirich's Builder::XmlMarkup library is used.
15
+ # Action View templates can be written in several ways.
16
+ # If the template file has a <tt>.erb</tt> extension, then it uses the erubi[https://rubygems.org/gems/erubi]
17
+ # template system which can embed Ruby into an HTML document.
18
+ # If the template file has a <tt>.builder</tt> extension, then Jim Weirich's Builder::XmlMarkup library is used.
15
19
  #
16
20
  # == ERB
17
21
  #
18
- # You trigger ERB by using embeddings such as <% %>, <% -%>, and <%= %>. The <%= %> tag set is used when you want output. Consider the
22
+ # You trigger ERB by using embeddings such as <tt><% %></tt>, <tt><% -%></tt>, and <tt><%= %></tt>. The <tt><%= %></tt> tag set is used when you want output. Consider the
19
23
  # following loop for names:
20
24
  #
21
25
  # <b>Names of all the people</b>
@@ -23,7 +27,7 @@ module ActionView #:nodoc:
23
27
  # Name: <%= person.name %><br/>
24
28
  # <% end %>
25
29
  #
26
- # The loop is setup in regular embedding tags <% %> and the name is written using the output embedding tag <%= %>. Note that this
30
+ # The loop is set up in regular embedding tags <tt><% %></tt>, and the name is written using the output embedding tag <tt><%= %></tt>. Note that this
27
31
  # is not just a usage suggestion. Regular output functions like print or puts won't work with ERB templates. So this would be wrong:
28
32
  #
29
33
  # <%# WRONG %>
@@ -31,7 +35,9 @@ module ActionView #:nodoc:
31
35
  #
32
36
  # If you absolutely must write from within a function use +concat+.
33
37
  #
34
- # <%- and -%> suppress leading and trailing whitespace, including the trailing newline, and can be used interchangeably with <% and %>.
38
+ # When on a line that only contains whitespaces except for the tag, <tt><% %></tt> suppresses leading and trailing whitespace,
39
+ # including the trailing newline. <tt><% %></tt> and <tt><%- -%></tt> are the same.
40
+ # Note however that <tt><%= %></tt> and <tt><%= -%></tt> are different: only the latter removes trailing whitespaces.
35
41
  #
36
42
  # === Using sub templates
37
43
  #
@@ -66,14 +72,13 @@ module ActionView #:nodoc:
66
72
  # Headline: <%= headline %>
67
73
  # First name: <%= person.first_name %>
68
74
  #
69
- # If you need to find out whether a certain local variable has been assigned a value in a particular render call,
70
- # you need to use the following pattern:
75
+ # The local variables passed to sub templates can be accessed as a hash using the <tt>local_assigns</tt> hash. This lets you access the
76
+ # variables as:
71
77
  #
72
- # <% if local_assigns.has_key? :headline %>
73
- # Headline: <%= headline %>
74
- # <% end %>
78
+ # Headline: <%= local_assigns[:headline] %>
75
79
  #
76
- # Testing using <tt>defined? headline</tt> will not work. This is an implementation restriction.
80
+ # This is useful in cases where you aren't sure if the local variable has been assigned. Alternatively, you could also use
81
+ # <tt>defined? headline</tt> to first check if the variable has been assigned before using it.
77
82
  #
78
83
  # === Template caching
79
84
  #
@@ -107,7 +112,7 @@ module ActionView #:nodoc:
107
112
  # <p>A product of Danish Design during the Winter of '79...</p>
108
113
  # </div>
109
114
  #
110
- # A full-length RSS example actually used on Basecamp:
115
+ # Here is a full-length RSS example actually used on Basecamp:
111
116
  #
112
117
  # xml.rss("version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/") do
113
118
  # xml.channel do
@@ -131,37 +136,40 @@ module ActionView #:nodoc:
131
136
  # end
132
137
  # end
133
138
  #
134
- # More builder documentation can be found at http://builder.rubyforge.org.
139
+ # For more information on Builder please consult the {source
140
+ # code}[https://github.com/jimweirich/builder].
135
141
  class Base
136
142
  include Helpers, ::ERB::Util, Context
137
143
 
138
144
  # Specify the proc used to decorate input tags that refer to attributes with errors.
139
- cattr_accessor :field_error_proc
140
- @@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"field_with_errors\">#{html_tag}</div>".html_safe }
145
+ cattr_accessor :field_error_proc, default: Proc.new { |html_tag, instance| "<div class=\"field_with_errors\">#{html_tag}</div>".html_safe }
141
146
 
142
147
  # How to complete the streaming when an exception occurs.
143
148
  # This is our best guess: first try to close the attribute, then the tag.
144
- cattr_accessor :streaming_completion_on_exception
145
- @@streaming_completion_on_exception = %("><script>window.location = "/500.html"</script></html>)
149
+ cattr_accessor :streaming_completion_on_exception, default: %("><script>window.location = "/500.html"</script></html>)
146
150
 
147
151
  # Specify whether rendering within namespaced controllers should prefix
148
152
  # the partial paths for ActiveModel objects with the namespace.
149
153
  # (e.g., an Admin::PostsController would render @post using /admin/posts/_post.erb)
150
- cattr_accessor :prefix_partial_path_with_controller_namespace
151
- @@prefix_partial_path_with_controller_namespace = true
154
+ class_attribute :prefix_partial_path_with_controller_namespace, default: true
152
155
 
153
156
  # Specify default_formats that can be rendered.
154
157
  cattr_accessor :default_formats
155
158
 
156
159
  # Specify whether an error should be raised for missing translations
157
- cattr_accessor :raise_on_missing_translations
158
- @@raise_on_missing_translations = false
160
+ cattr_accessor :raise_on_missing_translations, default: false
161
+
162
+ # Specify whether submit_tag should automatically disable on click
163
+ cattr_accessor :automatically_disable_submit_tag, default: true
164
+
165
+ # Annotate rendered view with file names
166
+ cattr_accessor :annotate_rendered_view_with_filenames, default: false
159
167
 
160
168
  class_attribute :_routes
161
169
  class_attribute :logger
162
170
 
163
171
  class << self
164
- delegate :erb_trim_mode=, :to => 'ActionView::Template::Handlers::ERB'
172
+ delegate :erb_trim_mode=, to: "ActionView::Template::Handlers::ERB"
165
173
 
166
174
  def cache_template_loading
167
175
  ActionView::Resolver.caching?
@@ -174,36 +182,100 @@ module ActionView #:nodoc:
174
182
  def xss_safe? #:nodoc:
175
183
  true
176
184
  end
185
+
186
+ def with_empty_template_cache # :nodoc:
187
+ subclass = Class.new(self) {
188
+ # We can't implement these as self.class because subclasses will
189
+ # share the same template cache as superclasses, so "changed?" won't work
190
+ # correctly.
191
+ define_method(:compiled_method_container) { subclass }
192
+ define_singleton_method(:compiled_method_container) { subclass }
193
+
194
+ def inspect
195
+ "#<ActionView::Base:#{'%#016x' % (object_id << 1)}>"
196
+ end
197
+ }
198
+ end
199
+
200
+ def changed?(other) # :nodoc:
201
+ compiled_method_container != other.compiled_method_container
202
+ end
177
203
  end
178
204
 
179
- attr_accessor :view_renderer
205
+ attr_reader :view_renderer, :lookup_context
180
206
  attr_internal :config, :assigns
181
207
 
182
- delegate :lookup_context, :to => :view_renderer
183
- delegate :formats, :formats=, :locale, :locale=, :view_paths, :view_paths=, :to => :lookup_context
208
+ delegate :formats, :formats=, :locale, :locale=, :view_paths, :view_paths=, to: :lookup_context
184
209
 
185
210
  def assign(new_assigns) # :nodoc:
186
211
  @_assigns = new_assigns.each { |key, value| instance_variable_set("@#{key}", value) }
187
212
  end
188
213
 
189
- def initialize(context = nil, assigns = {}, controller = nil, formats = nil) #:nodoc:
214
+ # :stopdoc:
215
+
216
+ def self.empty
217
+ with_view_paths([])
218
+ end
219
+
220
+ def self.with_view_paths(view_paths, assigns = {}, controller = nil)
221
+ with_context ActionView::LookupContext.new(view_paths), assigns, controller
222
+ end
223
+
224
+ def self.with_context(context, assigns = {}, controller = nil)
225
+ new context, assigns, controller
226
+ end
227
+
228
+ # :startdoc:
229
+
230
+ def initialize(lookup_context, assigns, controller) #:nodoc:
190
231
  @_config = ActiveSupport::InheritableOptions.new
191
232
 
192
- if context.is_a?(ActionView::Renderer)
193
- @view_renderer = context
194
- else
195
- lookup_context = context.is_a?(ActionView::LookupContext) ?
196
- context : ActionView::LookupContext.new(context)
197
- lookup_context.formats = formats if formats
198
- lookup_context.prefixes = controller._prefixes if controller
199
- @view_renderer = ActionView::Renderer.new(lookup_context)
200
- end
233
+ @lookup_context = lookup_context
234
+
235
+ @view_renderer = ActionView::Renderer.new @lookup_context
236
+ @current_template = nil
201
237
 
202
238
  assign(assigns)
203
239
  assign_controller(controller)
204
240
  _prepare_context
205
241
  end
206
242
 
243
+ def _run(method, template, locals, buffer, add_to_stack: true, &block)
244
+ _old_output_buffer, _old_virtual_path, _old_template = @output_buffer, @virtual_path, @current_template
245
+ @current_template = template if add_to_stack
246
+ @output_buffer = buffer
247
+ public_send(method, locals, buffer, &block)
248
+ ensure
249
+ @output_buffer, @virtual_path, @current_template = _old_output_buffer, _old_virtual_path, _old_template
250
+ end
251
+
252
+ def compiled_method_container
253
+ raise NotImplementedError, <<~msg.squish
254
+ Subclasses of ActionView::Base must implement `compiled_method_container`
255
+ or use the class method `with_empty_template_cache` for constructing
256
+ an ActionView::Base subclass that has an empty cache.
257
+ msg
258
+ end
259
+
260
+ def in_rendering_context(options)
261
+ old_view_renderer = @view_renderer
262
+ old_lookup_context = @lookup_context
263
+
264
+ if !lookup_context.html_fallback_for_js && options[:formats]
265
+ formats = Array(options[:formats])
266
+ if formats == [:js]
267
+ formats << :html
268
+ end
269
+ @lookup_context = lookup_context.with_prepended_formats(formats)
270
+ @view_renderer = ActionView::Renderer.new @lookup_context
271
+ end
272
+
273
+ yield @view_renderer
274
+ ensure
275
+ @view_renderer = old_view_renderer
276
+ @lookup_context = old_lookup_context
277
+ end
278
+
207
279
  ActiveSupport.run_load_hooks(:action_view, self)
208
280
  end
209
281
  end
@@ -1,6 +1,23 @@
1
- require 'active_support/core_ext/string/output_safety'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/string/output_safety"
2
4
 
3
5
  module ActionView
6
+ # Used as a buffer for views
7
+ #
8
+ # The main difference between this and ActiveSupport::SafeBuffer
9
+ # is for the methods `<<` and `safe_expr_append=` the inputs are
10
+ # checked for nil before they are assigned and `to_s` is called on
11
+ # the input. For example:
12
+ #
13
+ # obuf = ActionView::OutputBuffer.new "hello"
14
+ # obuf << 5
15
+ # puts obuf # => "hello5"
16
+ #
17
+ # sbuf = ActiveSupport::SafeBuffer.new "hello"
18
+ # sbuf << 5
19
+ # puts sbuf # => "hello\u0005"
20
+ #
4
21
  class OutputBuffer < ActiveSupport::SafeBuffer #:nodoc:
5
22
  def initialize(*)
6
23
  super
@@ -13,10 +30,11 @@ module ActionView
13
30
  end
14
31
  alias :append= :<<
15
32
 
16
- def safe_concat(value)
17
- return self if value.nil?
18
- super(value.to_s)
33
+ def safe_expr_append=(val)
34
+ return self if val.nil?
35
+ safe_concat val.to_s
19
36
  end
37
+
20
38
  alias :safe_append= :safe_concat
21
39
  end
22
40
 
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionView
4
+ class CacheExpiry
5
+ class Executor
6
+ def initialize(watcher:)
7
+ @cache_expiry = CacheExpiry.new(watcher: watcher)
8
+ end
9
+
10
+ def before(target)
11
+ @cache_expiry.clear_cache_if_necessary
12
+ end
13
+ end
14
+
15
+ def initialize(watcher:)
16
+ @watched_dirs = nil
17
+ @watcher_class = watcher
18
+ @watcher = nil
19
+ @mutex = Mutex.new
20
+ end
21
+
22
+ def clear_cache_if_necessary
23
+ @mutex.synchronize do
24
+ watched_dirs = dirs_to_watch
25
+ return if watched_dirs.empty?
26
+
27
+ if watched_dirs != @watched_dirs
28
+ @watched_dirs = watched_dirs
29
+ @watcher = @watcher_class.new([], watched_dirs) do
30
+ clear_cache
31
+ end
32
+ @watcher.execute
33
+ else
34
+ @watcher.execute_if_updated
35
+ end
36
+ end
37
+ end
38
+
39
+ def clear_cache
40
+ ActionView::LookupContext::DetailsKey.clear
41
+ end
42
+
43
+ private
44
+ def dirs_to_watch
45
+ all_view_paths.grep(FileSystemResolver).map!(&:path).tap(&:uniq!).sort!
46
+ end
47
+
48
+ def all_view_paths
49
+ ActionView::ViewPaths.all_view_paths.flat_map(&:paths)
50
+ end
51
+ end
52
+ end
@@ -1,23 +1,20 @@
1
- module ActionView
2
- module CompiledTemplates #:nodoc:
3
- # holds compiled template code
4
- end
1
+ # frozen_string_literal: true
5
2
 
3
+ module ActionView
6
4
  # = Action View Context
7
5
  #
8
6
  # Action View contexts are supplied to Action Controller to render a template.
9
7
  # The default Action View context is ActionView::Base.
10
8
  #
11
- # In order to work with ActionController, a Context must just include this module.
12
- # The initialization of the variables used by the context (@output_buffer, @view_flow,
13
- # and @virtual_path) is responsibility of the object that includes this module
14
- # (although you can call _prepare_context defined below).
9
+ # In order to work with Action Controller, a Context must just include this
10
+ # module. The initialization of the variables used by the context
11
+ # (@output_buffer, @view_flow, and @virtual_path) is responsibility of the
12
+ # object that includes this module (although you can call _prepare_context
13
+ # defined below).
15
14
  module Context
16
- include CompiledTemplates
17
15
  attr_accessor :output_buffer, :view_flow
18
16
 
19
17
  # Prepares the context by setting the appropriate instance variables.
20
- # :api: plugin
21
18
  def _prepare_context
22
19
  @view_flow = OutputFlow.new
23
20
  @output_buffer = nil
@@ -27,8 +24,7 @@ module ActionView
27
24
  # Encapsulates the interaction with the view flow so it
28
25
  # returns the correct buffer on +yield+. This is usually
29
26
  # overwritten by helpers to add more behavior.
30
- # :api: plugin
31
- def _layout_for(name=nil)
27
+ def _layout_for(name = nil)
32
28
  name ||= :layout
33
29
  view_flow.get(name).html_safe
34
30
  end
@@ -1,22 +1,28 @@
1
- require 'thread_safe'
1
+ # frozen_string_literal: true
2
+
3
+ require "concurrent/map"
4
+ require "action_view/path_set"
2
5
 
3
6
  module ActionView
4
7
  class DependencyTracker # :nodoc:
5
- @trackers = ThreadSafe::Cache.new
8
+ @trackers = Concurrent::Map.new
6
9
 
7
- def self.find_dependencies(name, template)
10
+ def self.find_dependencies(name, template, view_paths = nil)
8
11
  tracker = @trackers[template.handler]
12
+ return [] unless tracker
9
13
 
10
- if tracker.present?
11
- tracker.call(name, template)
12
- else
13
- []
14
- end
14
+ tracker.call(name, template, view_paths)
15
15
  end
16
16
 
17
17
  def self.register_tracker(extension, tracker)
18
18
  handler = Template.handler_for_extension(extension)
19
- @trackers[handler] = tracker
19
+ if tracker.respond_to?(:supports_view_paths?)
20
+ @trackers[handler] = tracker
21
+ else
22
+ @trackers[handler] = lambda { |name, template, _|
23
+ tracker.call(name, template)
24
+ }
25
+ end
20
26
  end
21
27
 
22
28
  def self.remove_tracker(handler)
@@ -76,12 +82,22 @@ module ActionView
76
82
  (?:#{STRING}|#{VARIABLE_OR_METHOD_CHAIN}) # finally, the dependency name of interest
77
83
  /xm
78
84
 
79
- def self.call(name, template)
80
- new(name, template).dependencies
85
+ LAYOUT_DEPENDENCY = /\A
86
+ (?:\s*\(?\s*) # optional opening paren surrounded by spaces
87
+ (?:.*?#{LAYOUT_HASH_KEY}) # check if the line has layout key declaration
88
+ (?:#{STRING}|#{VARIABLE_OR_METHOD_CHAIN}) # finally, the dependency name of interest
89
+ /xm
90
+
91
+ def self.supports_view_paths? # :nodoc:
92
+ true
81
93
  end
82
94
 
83
- def initialize(name, template)
84
- @name, @template = name, template
95
+ def self.call(name, template, view_paths = nil)
96
+ new(name, template, view_paths).dependencies
97
+ end
98
+
99
+ def initialize(name, template, view_paths = nil)
100
+ @name, @template, @view_paths = name, template, view_paths
85
101
  end
86
102
 
87
103
  def dependencies
@@ -91,7 +107,6 @@ module ActionView
91
107
  attr_reader :name, :template
92
108
  private :name, :template
93
109
 
94
-
95
110
  private
96
111
  def source
97
112
  template.source
@@ -106,24 +121,35 @@ module ActionView
106
121
  render_calls = source.split(/\brender\b/).drop(1)
107
122
 
108
123
  render_calls.each do |arguments|
109
- arguments.scan(RENDER_ARGUMENTS) do
110
- add_dynamic_dependency(render_dependencies, Regexp.last_match[:dynamic])
111
- add_static_dependency(render_dependencies, Regexp.last_match[:static])
112
- end
124
+ add_dependencies(render_dependencies, arguments, LAYOUT_DEPENDENCY)
125
+ add_dependencies(render_dependencies, arguments, RENDER_ARGUMENTS)
113
126
  end
114
127
 
115
128
  render_dependencies.uniq
116
129
  end
117
130
 
131
+ def add_dependencies(render_dependencies, arguments, pattern)
132
+ arguments.scan(pattern) do
133
+ match = Regexp.last_match
134
+ add_dynamic_dependency(render_dependencies, match[:dynamic])
135
+ add_static_dependency(render_dependencies, match[:static], match[:quote])
136
+ end
137
+ end
138
+
118
139
  def add_dynamic_dependency(dependencies, dependency)
119
140
  if dependency
120
141
  dependencies << "#{dependency.pluralize}/#{dependency.singularize}"
121
142
  end
122
143
  end
123
144
 
124
- def add_static_dependency(dependencies, dependency)
145
+ def add_static_dependency(dependencies, dependency, quote_type)
146
+ if quote_type == '"'
147
+ # Ignore if there is interpolation
148
+ return if dependency.include?('#{')
149
+ end
150
+
125
151
  if dependency
126
- if dependency.include?('/')
152
+ if dependency.include?("/")
127
153
  dependencies << dependency
128
154
  else
129
155
  dependencies << "#{directory}/#{dependency}"
@@ -131,8 +157,22 @@ module ActionView
131
157
  end
132
158
  end
133
159
 
160
+ def resolve_directories(wildcard_dependencies)
161
+ return [] unless @view_paths
162
+
163
+ wildcard_dependencies.flat_map { |query, templates|
164
+ @view_paths.find_all_with_query(query).map do |template|
165
+ "#{File.dirname(query)}/#{File.basename(template).split('.').first}"
166
+ end
167
+ }.sort
168
+ end
169
+
134
170
  def explicit_dependencies
135
- source.scan(EXPLICIT_DEPENDENCY).flatten.uniq
171
+ dependencies = source.scan(EXPLICIT_DEPENDENCY).flatten.uniq
172
+
173
+ wildcards, explicits = dependencies.partition { |dependency| dependency.end_with?("*") }
174
+
175
+ (explicits + resolve_directories(wildcards)).uniq
136
176
  end
137
177
  end
138
178