actionview 5.2.7.1 → 6.1.4.6

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 (92) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +250 -112
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -3
  5. data/lib/action_view/base.rb +81 -15
  6. data/lib/action_view/buffers.rb +15 -0
  7. data/lib/action_view/cache_expiry.rb +52 -0
  8. data/lib/action_view/context.rb +5 -9
  9. data/lib/action_view/dependency_tracker.rb +10 -4
  10. data/lib/action_view/digestor.rb +15 -22
  11. data/lib/action_view/flows.rb +0 -1
  12. data/lib/action_view/gem_version.rb +4 -4
  13. data/lib/action_view/helpers/active_model_helper.rb +0 -1
  14. data/lib/action_view/helpers/asset_tag_helper.rb +64 -47
  15. data/lib/action_view/helpers/asset_url_helper.rb +9 -6
  16. data/lib/action_view/helpers/atom_feed_helper.rb +2 -1
  17. data/lib/action_view/helpers/cache_helper.rb +23 -22
  18. data/lib/action_view/helpers/capture_helper.rb +4 -0
  19. data/lib/action_view/helpers/csp_helper.rb +4 -2
  20. data/lib/action_view/helpers/csrf_helper.rb +1 -1
  21. data/lib/action_view/helpers/date_helper.rb +73 -30
  22. data/lib/action_view/helpers/form_helper.rb +305 -37
  23. data/lib/action_view/helpers/form_options_helper.rb +23 -23
  24. data/lib/action_view/helpers/form_tag_helper.rb +19 -16
  25. data/lib/action_view/helpers/javascript_helper.rb +12 -11
  26. data/lib/action_view/helpers/number_helper.rb +14 -8
  27. data/lib/action_view/helpers/output_safety_helper.rb +1 -1
  28. data/lib/action_view/helpers/rendering_helper.rb +17 -7
  29. data/lib/action_view/helpers/sanitize_helper.rb +12 -18
  30. data/lib/action_view/helpers/tag_helper.rb +100 -55
  31. data/lib/action_view/helpers/tags/base.rb +18 -11
  32. data/lib/action_view/helpers/tags/check_box.rb +0 -1
  33. data/lib/action_view/helpers/tags/collection_check_boxes.rb +0 -1
  34. data/lib/action_view/helpers/tags/collection_helpers.rb +0 -1
  35. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +0 -1
  36. data/lib/action_view/helpers/tags/color_field.rb +1 -2
  37. data/lib/action_view/helpers/tags/date_field.rb +1 -2
  38. data/lib/action_view/helpers/tags/date_select.rb +2 -3
  39. data/lib/action_view/helpers/tags/datetime_field.rb +0 -1
  40. data/lib/action_view/helpers/tags/datetime_local_field.rb +1 -2
  41. data/lib/action_view/helpers/tags/label.rb +4 -1
  42. data/lib/action_view/helpers/tags/month_field.rb +1 -2
  43. data/lib/action_view/helpers/tags/radio_button.rb +0 -1
  44. data/lib/action_view/helpers/tags/select.rb +1 -2
  45. data/lib/action_view/helpers/tags/text_field.rb +0 -1
  46. data/lib/action_view/helpers/tags/time_field.rb +1 -2
  47. data/lib/action_view/helpers/tags/translator.rb +1 -6
  48. data/lib/action_view/helpers/tags/week_field.rb +1 -2
  49. data/lib/action_view/helpers/text_helper.rb +4 -5
  50. data/lib/action_view/helpers/translation_helper.rb +94 -54
  51. data/lib/action_view/helpers/url_helper.rb +136 -28
  52. data/lib/action_view/helpers.rb +0 -2
  53. data/lib/action_view/layouts.rb +8 -10
  54. data/lib/action_view/log_subscriber.rb +30 -15
  55. data/lib/action_view/lookup_context.rb +63 -35
  56. data/lib/action_view/path_set.rb +3 -12
  57. data/lib/action_view/railtie.rb +42 -26
  58. data/lib/action_view/record_identifier.rb +2 -3
  59. data/lib/action_view/renderer/abstract_renderer.rb +142 -11
  60. data/lib/action_view/renderer/collection_renderer.rb +196 -0
  61. data/lib/action_view/renderer/object_renderer.rb +34 -0
  62. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +61 -16
  63. data/lib/action_view/renderer/partial_renderer.rb +21 -273
  64. data/lib/action_view/renderer/renderer.rb +59 -4
  65. data/lib/action_view/renderer/streaming_template_renderer.rb +10 -8
  66. data/lib/action_view/renderer/template_renderer.rb +35 -27
  67. data/lib/action_view/rendering.rb +54 -33
  68. data/lib/action_view/routing_url_for.rb +13 -12
  69. data/lib/action_view/template/error.rb +30 -15
  70. data/lib/action_view/template/handlers/builder.rb +2 -2
  71. data/lib/action_view/template/handlers/erb/erubi.rb +15 -9
  72. data/lib/action_view/template/handlers/erb.rb +16 -11
  73. data/lib/action_view/template/handlers/html.rb +1 -1
  74. data/lib/action_view/template/handlers/raw.rb +2 -2
  75. data/lib/action_view/template/handlers.rb +1 -1
  76. data/lib/action_view/template/html.rb +5 -6
  77. data/lib/action_view/template/inline.rb +22 -0
  78. data/lib/action_view/template/raw_file.rb +25 -0
  79. data/lib/action_view/template/renderable.rb +24 -0
  80. data/lib/action_view/template/resolver.rb +191 -150
  81. data/lib/action_view/template/sources/file.rb +17 -0
  82. data/lib/action_view/template/sources.rb +13 -0
  83. data/lib/action_view/template/text.rb +2 -3
  84. data/lib/action_view/template.rb +66 -75
  85. data/lib/action_view/test_case.rb +21 -29
  86. data/lib/action_view/testing/resolvers.rb +18 -27
  87. data/lib/action_view/unbound_template.rb +31 -0
  88. data/lib/action_view/view_paths.rb +59 -38
  89. data/lib/action_view.rb +7 -2
  90. data/lib/assets/compiled/rails-ujs.js +32 -6
  91. metadata +29 -18
  92. data/lib/action_view/helpers/record_tag_helper.rb +0 -23
@@ -1,8 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/object/try"
4
- require "active_support/core_ext/kernel/singleton_class"
5
3
  require "thread"
4
+ require "delegate"
6
5
 
7
6
  module ActionView
8
7
  # = Action View Template
@@ -103,41 +102,37 @@ module ActionView
103
102
 
104
103
  eager_autoload do
105
104
  autoload :Error
105
+ autoload :RawFile
106
+ autoload :Renderable
106
107
  autoload :Handlers
107
108
  autoload :HTML
109
+ autoload :Inline
110
+ autoload :Sources
108
111
  autoload :Text
109
112
  autoload :Types
110
113
  end
111
114
 
112
115
  extend Template::Handlers
113
116
 
114
- attr_accessor :locals, :formats, :variants, :virtual_path
115
-
116
- attr_reader :source, :identifier, :handler, :original_encoding, :updated_at
117
-
118
- # This finalizer is needed (and exactly with a proc inside another proc)
119
- # otherwise templates leak in development.
120
- Finalizer = proc do |method_name, mod| # :nodoc:
121
- proc do
122
- mod.module_eval do
123
- remove_possible_method method_name
124
- end
125
- end
126
- end
127
-
128
- def initialize(source, identifier, handler, details)
129
- format = details[:format] || (handler.default_format if handler.respond_to?(:default_format))
117
+ attr_reader :identifier, :handler
118
+ attr_reader :variable, :format, :variant, :locals, :virtual_path
130
119
 
120
+ def initialize(source, identifier, handler, locals:, format: nil, variant: nil, virtual_path: nil)
131
121
  @source = source
132
122
  @identifier = identifier
133
123
  @handler = handler
134
124
  @compiled = false
135
- @original_encoding = nil
136
- @locals = details[:locals] || []
137
- @virtual_path = details[:virtual_path]
138
- @updated_at = details[:updated_at] || Time.now
139
- @formats = Array(format).map { |f| f.respond_to?(:ref) ? f.ref : f }
140
- @variants = [details[:variant]]
125
+ @locals = locals
126
+ @virtual_path = virtual_path
127
+
128
+ @variable = if @virtual_path
129
+ base = @virtual_path.end_with?("/") ? "" : ::File.basename(@virtual_path)
130
+ base =~ /\A_?(.*?)(?:\.\w+)*\z/
131
+ $1.to_sym
132
+ end
133
+
134
+ @format = format
135
+ @variant = variant
141
136
  @compile_mutex = Mutex.new
142
137
  end
143
138
 
@@ -153,40 +148,29 @@ module ActionView
153
148
  # This method is instrumented as "!render_template.action_view". Notice that
154
149
  # we use a bang in this instrumentation because you don't want to
155
150
  # consume this in production. This is only slow if it's being listened to.
156
- def render(view, locals, buffer = nil, &block)
151
+ def render(view, locals, buffer = ActionView::OutputBuffer.new, add_to_stack: true, &block)
157
152
  instrument_render_template do
158
153
  compile!(view)
159
- view.send(method_name, locals, buffer, &block)
154
+ view._run(method_name, self, locals, buffer, add_to_stack: add_to_stack, &block)
160
155
  end
161
156
  rescue => e
162
157
  handle_render_error(view, e)
163
158
  end
164
159
 
165
160
  def type
166
- @type ||= Types[@formats.first] if @formats.first
161
+ @type ||= Types[format]
167
162
  end
168
163
 
169
- # Receives a view object and return a template similar to self by using @virtual_path.
170
- #
171
- # This method is useful if you have a template object but it does not contain its source
172
- # anymore since it was already compiled. In such cases, all you need to do is to call
173
- # refresh passing in the view object.
174
- #
175
- # Notice this method raises an error if the template to be refreshed does not have a
176
- # virtual path set (true just for inline templates).
177
- def refresh(view)
178
- raise "A template needs to have a virtual path in order to be refreshed" unless @virtual_path
179
- lookup = view.lookup_context
180
- pieces = @virtual_path.split("/")
181
- name = pieces.pop
182
- partial = !!name.sub!(/^_/, "")
183
- lookup.disable_cache do
184
- lookup.find_template(name, [ pieces.join("/") ], partial, @locals)
185
- end
164
+ def short_identifier
165
+ @short_identifier ||= defined?(Rails.root) ? identifier.delete_prefix("#{Rails.root}/") : identifier
186
166
  end
187
167
 
188
168
  def inspect
189
- @inspect ||= defined?(Rails.root) ? identifier.sub("#{Rails.root}/", "".freeze) : identifier
169
+ "#<#{self.class.name} #{short_identifier} locals=#{@locals.inspect}>"
170
+ end
171
+
172
+ def source
173
+ @source.to_s
190
174
  end
191
175
 
192
176
  # This method is responsible for properly setting the encoding of the
@@ -200,7 +184,9 @@ module ActionView
200
184
  # before passing the source on to the template engine, leaving a
201
185
  # blank line in its stead.
202
186
  def encode!
203
- return unless source.encoding == Encoding::BINARY
187
+ source = self.source
188
+
189
+ return source unless source.encoding == Encoding::BINARY
204
190
 
205
191
  # Look for # encoding: *. If we find one, we'll encode the
206
192
  # String in that encoding, otherwise, we'll use the
@@ -233,8 +219,20 @@ module ActionView
233
219
  end
234
220
  end
235
221
 
236
- private
237
222
 
223
+ # Exceptions are marshalled when using the parallel test runner with DRb, so we need
224
+ # to ensure that references to the template object can be marshalled as well. This means forgoing
225
+ # the marshalling of the compiler mutex and instantiating that again on unmarshalling.
226
+ def marshal_dump # :nodoc:
227
+ [ @source, @identifier, @handler, @compiled, @locals, @virtual_path, @format, @variant ]
228
+ end
229
+
230
+ def marshal_load(array) # :nodoc:
231
+ @source, @identifier, @handler, @compiled, @locals, @virtual_path, @format, @variant = *array
232
+ @compile_mutex = Mutex.new
233
+ end
234
+
235
+ private
238
236
  # Compile a template. This method ensures a template is compiled
239
237
  # just once and removes the source after it is compiled.
240
238
  def compile!(view)
@@ -249,19 +247,12 @@ module ActionView
249
247
  # re-compilation
250
248
  return if @compiled
251
249
 
252
- if view.is_a?(ActionView::CompiledTemplates)
253
- mod = ActionView::CompiledTemplates
254
- else
255
- mod = view.singleton_class
256
- end
250
+ mod = view.compiled_method_container
257
251
 
258
252
  instrument("!compile_template") do
259
253
  compile(mod)
260
254
  end
261
255
 
262
- # Just discard the source if we have a virtual path. This
263
- # means we can get the template back.
264
- @source = nil if @virtual_path
265
256
  @compiled = true
266
257
  end
267
258
  end
@@ -279,16 +270,15 @@ module ActionView
279
270
  # In general, this means that templates will be UTF-8 inside of Rails,
280
271
  # regardless of the original source encoding.
281
272
  def compile(mod)
282
- encode!
283
- code = @handler.call(self)
273
+ source = encode!
274
+ code = @handler.call(self, source)
284
275
 
285
276
  # Make sure that the resulting String to be eval'd is in the
286
277
  # encoding of the code
287
- source = <<-end_src.dup
278
+ original_source = source
279
+ source = +<<-end_src
288
280
  def #{method_name}(local_assigns, output_buffer)
289
- _old_virtual_path, @virtual_path = @virtual_path, #{@virtual_path.inspect};_old_output_buffer = @output_buffer;#{locals_code};#{code}
290
- ensure
291
- @virtual_path, @output_buffer = _old_virtual_path, _old_output_buffer
281
+ @virtual_path = #{@virtual_path.inspect};#{locals_code};#{code}
292
282
  end
293
283
  end_src
294
284
 
@@ -303,11 +293,17 @@ module ActionView
303
293
  # handler is valid in the default_internal. This is for handlers
304
294
  # that handle encoding but screw up
305
295
  unless source.valid_encoding?
306
- raise WrongEncodingError.new(@source, Encoding.default_internal)
296
+ raise WrongEncodingError.new(source, Encoding.default_internal)
307
297
  end
308
298
 
309
- mod.module_eval(source, identifier, 0)
310
- ObjectSpace.define_finalizer(self, Finalizer[method_name, mod])
299
+ begin
300
+ mod.module_eval(source, identifier, 0)
301
+ rescue SyntaxError
302
+ # Account for when code in the template is not syntactically valid; e.g. if we're using
303
+ # ERB and the user writes <%= foo( %>, attempting to call a helper `foo` and interpolate
304
+ # the result into the template, but missing an end parenthesis.
305
+ raise SyntaxErrorInTemplate.new(self, original_source)
306
+ end
311
307
  end
312
308
 
313
309
  def handle_render_error(view, e)
@@ -315,12 +311,7 @@ module ActionView
315
311
  e.sub_template_of(self)
316
312
  raise e
317
313
  else
318
- template = self
319
- unless template.source
320
- template = refresh(view)
321
- template.encode!
322
- end
323
- raise Template::Error.new(template)
314
+ raise Template::Error.new(self)
324
315
  end
325
316
  end
326
317
 
@@ -331,19 +322,19 @@ module ActionView
331
322
  locals = locals.grep(/\A@?(?![A-Z0-9])(?:[[:alnum:]_]|[^\0-\177])+\z/)
332
323
 
333
324
  # Assign for the same variable is to suppress unused variable warning
334
- locals.each_with_object("".dup) { |key, code| code << "#{key} = local_assigns[:#{key}]; #{key} = #{key};" }
325
+ locals.each_with_object(+"") { |key, code| code << "#{key} = local_assigns[:#{key}]; #{key} = #{key};" }
335
326
  end
336
327
 
337
328
  def method_name
338
329
  @method_name ||= begin
339
- m = "_#{identifier_method_name}__#{@identifier.hash}_#{__id__}".dup
340
- m.tr!("-".freeze, "_".freeze)
330
+ m = +"_#{identifier_method_name}__#{@identifier.hash}_#{__id__}"
331
+ m.tr!("-", "_")
341
332
  m
342
333
  end
343
334
  end
344
335
 
345
336
  def identifier_method_name
346
- inspect.tr("^a-z_".freeze, "_".freeze)
337
+ short_identifier.tr("^a-z_", "_")
347
338
  end
348
339
 
349
340
  def instrument(action, &block) # :doc:
@@ -351,7 +342,7 @@ module ActionView
351
342
  end
352
343
 
353
344
  def instrument_render_template(&block)
354
- ActiveSupport::Notifications.instrument("!render_template.action_view".freeze, instrument_payload, &block)
345
+ ActiveSupport::Notifications.instrument("!render_template.action_view", instrument_payload, &block)
355
346
  end
356
347
 
357
348
  def instrument_payload
@@ -16,11 +16,12 @@ module ActionView
16
16
  attr_accessor :request, :response, :params
17
17
 
18
18
  class << self
19
- attr_writer :controller_path
19
+ # Overrides AbstractController::Base#controller_path
20
+ attr_accessor :controller_path
20
21
  end
21
22
 
22
23
  def controller_path=(path)
23
- self.class.controller_path = (path)
24
+ self.class.controller_path = path
24
25
  end
25
26
 
26
27
  def initialize
@@ -73,10 +74,11 @@ module ActionView
73
74
  def helper_method(*methods)
74
75
  # Almost a duplicate from ActionController::Helpers
75
76
  methods.flatten.each do |method|
76
- _helpers.module_eval <<-end_eval, __FILE__, __LINE__ + 1
77
+ _helpers_for_modification.module_eval <<-end_eval, __FILE__, __LINE__ + 1
77
78
  def #{method}(*args, &block) # def current_user(*args, &block)
78
- _test_case.send(%(#{method}), *args, &block) # _test_case.send(%(current_user), *args, &block)
79
+ _test_case.send(:'#{method}', *args, &block) # _test_case.send(:'current_user', *args, &block)
79
80
  end # end
81
+ ruby2_keywords(:'#{method}') if respond_to?(:ruby2_keywords, true)
80
82
  end_eval
81
83
  end
82
84
  end
@@ -93,7 +95,6 @@ module ActionView
93
95
  end
94
96
 
95
97
  private
96
-
97
98
  def include_helper_modules!
98
99
  helper(helper_class) if helper_class
99
100
  include _helpers
@@ -101,16 +102,17 @@ module ActionView
101
102
  end
102
103
 
103
104
  def setup_with_controller
104
- @controller = ActionView::TestCase::TestController.new
105
+ controller_class = Class.new(ActionView::TestCase::TestController)
106
+ @controller = controller_class.new
105
107
  @request = @controller.request
106
108
  @view_flow = ActionView::OutputFlow.new
107
109
  # empty string ensures buffer has UTF-8 encoding as
108
110
  # new without arguments returns ASCII-8BIT encoded buffer like String#new
109
111
  @output_buffer = ActiveSupport::SafeBuffer.new ""
110
- @rendered = "".dup
112
+ @rendered = +""
111
113
 
112
- make_test_case_available_to_view!
113
- say_no_to_protect_against_forgery!
114
+ test_case_instance = self
115
+ controller_class.define_method(:_test_case) { test_case_instance }
114
116
  end
115
117
 
116
118
  def config
@@ -160,34 +162,24 @@ module ActionView
160
162
  included do
161
163
  setup :setup_with_controller
162
164
  ActiveSupport.run_load_hooks(:action_view_test_case, self)
163
- end
164
-
165
- private
166
-
167
- # Need to experiment if this priority is the best one: rendered => output_buffer
168
- def document_root_element
169
- Nokogiri::HTML::Document.parse(@rendered.blank? ? @output_buffer : @rendered).root
170
- end
171
165
 
172
- def say_no_to_protect_against_forgery!
173
- _helpers.module_eval do
174
- silence_redefinition_of_method :protect_against_forgery?
166
+ helper do
175
167
  def protect_against_forgery?
176
168
  false
177
169
  end
178
- end
179
- end
180
170
 
181
- def make_test_case_available_to_view!
182
- test_case_instance = self
183
- _helpers.module_eval do
184
- unless private_method_defined?(:_test_case)
185
- define_method(:_test_case) { test_case_instance }
186
- private :_test_case
171
+ def _test_case
172
+ controller._test_case
187
173
  end
188
174
  end
189
175
  end
190
176
 
177
+ private
178
+ # Need to experiment if this priority is the best one: rendered => output_buffer
179
+ def document_root_element
180
+ Nokogiri::HTML::Document.parse(@rendered.blank? ? @output_buffer : @rendered).root
181
+ end
182
+
191
183
  module Locals
192
184
  attr_accessor :rendered_views
193
185
 
@@ -284,7 +276,7 @@ module ActionView
284
276
 
285
277
  def respond_to_missing?(name, include_private = false)
286
278
  begin
287
- routes = @controller.respond_to?(:_routes) && @controller._routes
279
+ routes = defined?(@controller) && @controller.respond_to?(:_routes) && @controller._routes
288
280
  rescue
289
281
  # Don't call routes, if there is an error on _routes call
290
282
  end
@@ -7,12 +7,15 @@ module ActionView #:nodoc:
7
7
  # file system. This is used internally by Rails' own test suite, and is
8
8
  # useful for testing extensions that have no way of knowing what the file
9
9
  # system will look like at runtime.
10
- class FixtureResolver < PathResolver
11
- attr_reader :hash
12
-
13
- def initialize(hash = {}, pattern = nil)
14
- super(pattern)
10
+ class FixtureResolver < OptimizedFileSystemResolver
11
+ def initialize(hash = {})
12
+ super("")
15
13
  @hash = hash
14
+ @path = ""
15
+ end
16
+
17
+ def data
18
+ @hash
16
19
  end
17
20
 
18
21
  def to_s
@@ -20,35 +23,23 @@ module ActionView #:nodoc:
20
23
  end
21
24
 
22
25
  private
23
-
24
- def query(path, exts, _, _)
25
- query = "".dup
26
- EXTENSIONS.each_key do |ext|
27
- query << "(" << exts[ext].map { |e| e && Regexp.escape(".#{e}") }.join("|") << "|)"
28
- end
29
- query = /^(#{Regexp.escape(path)})#{query}$/
30
-
31
- templates = []
32
- @hash.each do |_path, array|
33
- source, updated_at = array
34
- next unless query.match?(_path)
35
- handler, format, variant = extract_handler_and_format_and_variant(_path)
36
- templates << Template.new(source, _path, handler,
37
- virtual_path: path.virtual,
38
- format: format,
39
- variant: variant,
40
- updated_at: updated_at
41
- )
26
+ def find_candidate_template_paths(path)
27
+ @hash.keys.select do |fixture|
28
+ fixture.start_with?(path.virtual)
29
+ end.map do |fixture|
30
+ "/#{fixture}"
42
31
  end
32
+ end
43
33
 
44
- templates.sort_by { |t| -t.identifier.match(/^#{query}$/).captures.reject(&:blank?).size }
34
+ def source_for_template(template)
35
+ @hash[template[1..template.size]]
45
36
  end
46
37
  end
47
38
 
48
39
  class NullResolver < PathResolver
49
- def query(path, exts, _, _)
40
+ def query(path, exts, _, locals, cache:)
50
41
  handler, format, variant = extract_handler_and_format_and_variant(path)
51
- [ActionView::Template.new("Template generated by Null Resolver", path.virtual, handler, virtual_path: path.virtual, format: format, variant: variant)]
42
+ [ActionView::Template.new("Template generated by Null Resolver", path.virtual, handler, virtual_path: path.virtual, format: format, variant: variant, locals: locals)]
52
43
  end
53
44
  end
54
45
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "concurrent/map"
4
+
5
+ module ActionView
6
+ class UnboundTemplate
7
+ def initialize(source, identifier, handler, options)
8
+ @source = source
9
+ @identifier = identifier
10
+ @handler = handler
11
+ @options = options
12
+
13
+ @templates = Concurrent::Map.new(initial_capacity: 2)
14
+ end
15
+
16
+ def bind_locals(locals)
17
+ @templates[locals] ||= build_template(locals)
18
+ end
19
+
20
+ private
21
+ def build_template(locals)
22
+ options = @options.merge(locals: locals)
23
+ Template.new(
24
+ @source,
25
+ @identifier,
26
+ @handler,
27
+ **options
28
+ )
29
+ end
30
+ end
31
+ end
@@ -5,13 +5,21 @@ module ActionView
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- class_attribute :_view_paths, default: ActionView::PathSet.new.freeze
8
+ ViewPaths.set_view_paths(self, ActionView::PathSet.new.freeze)
9
9
  end
10
10
 
11
11
  delegate :template_exists?, :any_templates?, :view_paths, :formats, :formats=,
12
12
  :locale, :locale=, to: :lookup_context
13
13
 
14
14
  module ClassMethods
15
+ def _view_paths
16
+ ViewPaths.get_view_paths(self)
17
+ end
18
+
19
+ def _view_paths=(paths)
20
+ ViewPaths.set_view_paths(self, paths)
21
+ end
22
+
15
23
  def _prefixes # :nodoc:
16
24
  @_prefixes ||= begin
17
25
  return local_prefixes if superclass.abstract?
@@ -20,8 +28,41 @@ module ActionView
20
28
  end
21
29
  end
22
30
 
23
- private
31
+ # Append a path to the list of view paths for this controller.
32
+ #
33
+ # ==== Parameters
34
+ # * <tt>path</tt> - If a String is provided, it gets converted into
35
+ # the default view path. You may also provide a custom view path
36
+ # (see ActionView::PathSet for more information)
37
+ def append_view_path(path)
38
+ self._view_paths = view_paths + Array(path)
39
+ end
24
40
 
41
+ # Prepend a path to the list of view paths for this controller.
42
+ #
43
+ # ==== Parameters
44
+ # * <tt>path</tt> - If a String is provided, it gets converted into
45
+ # the default view path. You may also provide a custom view path
46
+ # (see ActionView::PathSet for more information)
47
+ def prepend_view_path(path)
48
+ self._view_paths = ActionView::PathSet.new(Array(path) + view_paths)
49
+ end
50
+
51
+ # A list of all of the default view paths for this controller.
52
+ def view_paths
53
+ _view_paths
54
+ end
55
+
56
+ # Set the view paths.
57
+ #
58
+ # ==== Parameters
59
+ # * <tt>paths</tt> - If a PathSet is provided, use that;
60
+ # otherwise, process the parameter into a PathSet.
61
+ def view_paths=(paths)
62
+ self._view_paths = ActionView::PathSet.new(Array(paths))
63
+ end
64
+
65
+ private
25
66
  # Override this method in your controller if you want to change paths prefixes for finding views.
26
67
  # Prefixes defined here will still be added to parents' <tt>._prefixes</tt>.
27
68
  def local_prefixes
@@ -29,6 +70,22 @@ module ActionView
29
70
  end
30
71
  end
31
72
 
73
+ # :stopdoc:
74
+ @all_view_paths = {}
75
+
76
+ def self.get_view_paths(klass)
77
+ @all_view_paths[klass] || get_view_paths(klass.superclass)
78
+ end
79
+
80
+ def self.set_view_paths(klass, paths)
81
+ @all_view_paths[klass] = paths
82
+ end
83
+
84
+ def self.all_view_paths
85
+ @all_view_paths.values.uniq
86
+ end
87
+ # :startdoc:
88
+
32
89
  # The prefixes used in render "foo" shortcuts.
33
90
  def _prefixes # :nodoc:
34
91
  self.class._prefixes
@@ -65,41 +122,5 @@ module ActionView
65
122
  def prepend_view_path(path)
66
123
  lookup_context.view_paths.unshift(*path)
67
124
  end
68
-
69
- module ClassMethods
70
- # Append a path to the list of view paths for this controller.
71
- #
72
- # ==== Parameters
73
- # * <tt>path</tt> - If a String is provided, it gets converted into
74
- # the default view path. You may also provide a custom view path
75
- # (see ActionView::PathSet for more information)
76
- def append_view_path(path)
77
- self._view_paths = view_paths + Array(path)
78
- end
79
-
80
- # Prepend a path to the list of view paths for this controller.
81
- #
82
- # ==== Parameters
83
- # * <tt>path</tt> - If a String is provided, it gets converted into
84
- # the default view path. You may also provide a custom view path
85
- # (see ActionView::PathSet for more information)
86
- def prepend_view_path(path)
87
- self._view_paths = ActionView::PathSet.new(Array(path) + view_paths)
88
- end
89
-
90
- # A list of all of the default view paths for this controller.
91
- def view_paths
92
- _view_paths
93
- end
94
-
95
- # Set the view paths.
96
- #
97
- # ==== Parameters
98
- # * <tt>paths</tt> - If a PathSet is provided, use that;
99
- # otherwise, process the parameter into a PathSet.
100
- def view_paths=(paths)
101
- self._view_paths = ActionView::PathSet.new(Array(paths))
102
- end
103
- end
104
125
  end
105
126
  end
data/lib/action_view.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #--
4
- # Copyright (c) 2004-2018 David Heinemeier Hansson
4
+ # Copyright (c) 2004-2020 David Heinemeier Hansson
5
5
  #
6
6
  # Permission is hereby granted, free of charge, to any person obtaining
7
7
  # a copy of this software and associated documentation files (the
@@ -35,7 +35,6 @@ module ActionView
35
35
  eager_autoload do
36
36
  autoload :Base
37
37
  autoload :Context
38
- autoload :CompiledTemplates, "action_view/context"
39
38
  autoload :Digestor
40
39
  autoload :Helpers
41
40
  autoload :LookupContext
@@ -45,12 +44,15 @@ module ActionView
45
44
  autoload :Rendering
46
45
  autoload :RoutingUrlFor
47
46
  autoload :Template
47
+ autoload :UnboundTemplate
48
48
  autoload :ViewPaths
49
49
 
50
50
  autoload_under "renderer" do
51
51
  autoload :Renderer
52
52
  autoload :AbstractRenderer
53
53
  autoload :PartialRenderer
54
+ autoload :CollectionRenderer
55
+ autoload :ObjectRenderer
54
56
  autoload :TemplateRenderer
55
57
  autoload :StreamingTemplateRenderer
56
58
  end
@@ -58,6 +60,7 @@ module ActionView
58
60
  autoload_at "action_view/template/resolver" do
59
61
  autoload :Resolver
60
62
  autoload :PathResolver
63
+ autoload :FileSystemResolver
61
64
  autoload :OptimizedFileSystemResolver
62
65
  autoload :FallbackFileSystemResolver
63
66
  end
@@ -77,10 +80,12 @@ module ActionView
77
80
  autoload :ActionViewError
78
81
  autoload :EncodingError
79
82
  autoload :TemplateError
83
+ autoload :SyntaxErrorInTemplate
80
84
  autoload :WrongEncodingError
81
85
  end
82
86
  end
83
87
 
88
+ autoload :CacheExpiry
84
89
  autoload :TestCase
85
90
 
86
91
  def self.eager_load!