actionview 4.2.11.1 → 6.0.4

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 (114) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +201 -192
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +9 -8
  5. data/lib/action_view/base.rb +144 -37
  6. data/lib/action_view/buffers.rb +18 -1
  7. data/lib/action_view/cache_expiry.rb +53 -0
  8. data/lib/action_view/context.rb +8 -12
  9. data/lib/action_view/dependency_tracker.rb +54 -20
  10. data/lib/action_view/digestor.rb +88 -85
  11. data/lib/action_view/flows.rb +11 -12
  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 +241 -82
  15. data/lib/action_view/helpers/asset_url_helper.rb +171 -67
  16. data/lib/action_view/helpers/atom_feed_helper.rb +19 -17
  17. data/lib/action_view/helpers/cache_helper.rb +112 -42
  18. data/lib/action_view/helpers/capture_helper.rb +20 -13
  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 +230 -129
  23. data/lib/action_view/helpers/debug_helper.rb +7 -6
  24. data/lib/action_view/helpers/form_helper.rb +755 -129
  25. data/lib/action_view/helpers/form_options_helper.rb +130 -75
  26. data/lib/action_view/helpers/form_tag_helper.rb +116 -71
  27. data/lib/action_view/helpers/javascript_helper.rb +30 -14
  28. data/lib/action_view/helpers/number_helper.rb +84 -59
  29. data/lib/action_view/helpers/output_safety_helper.rb +36 -4
  30. data/lib/action_view/helpers/rendering_helper.rb +11 -8
  31. data/lib/action_view/helpers/sanitize_helper.rb +30 -31
  32. data/lib/action_view/helpers/tag_helper.rb +201 -75
  33. data/lib/action_view/helpers/tags/base.rb +138 -98
  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 -34
  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 +2 -1
  42. data/lib/action_view/helpers/tags/date_select.rb +37 -36
  43. data/lib/action_view/helpers/tags/datetime_field.rb +4 -3
  44. data/lib/action_view/helpers/tags/datetime_local_field.rb +2 -1
  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 +3 -2
  51. data/lib/action_view/helpers/tags/month_field.rb +2 -1
  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 +3 -1
  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 +14 -9
  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 +4 -2
  61. data/lib/action_view/helpers/tags/text_field.rb +8 -8
  62. data/lib/action_view/helpers/tags/time_field.rb +2 -1
  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 +15 -16
  66. data/lib/action_view/helpers/tags/url_field.rb +2 -0
  67. data/lib/action_view/helpers/tags/week_field.rb +2 -1
  68. data/lib/action_view/helpers/tags.rb +3 -1
  69. data/lib/action_view/helpers/text_helper.rb +56 -38
  70. data/lib/action_view/helpers/translation_helper.rb +91 -47
  71. data/lib/action_view/helpers/url_helper.rb +160 -105
  72. data/lib/action_view/helpers.rb +5 -3
  73. data/lib/action_view/layouts.rb +65 -61
  74. data/lib/action_view/log_subscriber.rb +61 -10
  75. data/lib/action_view/lookup_context.rb +147 -89
  76. data/lib/action_view/model_naming.rb +3 -1
  77. data/lib/action_view/path_set.rb +28 -23
  78. data/lib/action_view/railtie.rb +62 -6
  79. data/lib/action_view/record_identifier.rb +53 -26
  80. data/lib/action_view/renderer/abstract_renderer.rb +71 -13
  81. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +103 -0
  82. data/lib/action_view/renderer/partial_renderer.rb +239 -225
  83. data/lib/action_view/renderer/renderer.rb +22 -8
  84. data/lib/action_view/renderer/streaming_template_renderer.rb +54 -54
  85. data/lib/action_view/renderer/template_renderer.rb +79 -73
  86. data/lib/action_view/rendering.rb +68 -44
  87. data/lib/action_view/routing_url_for.rb +33 -22
  88. data/lib/action_view/tasks/cache_digests.rake +25 -0
  89. data/lib/action_view/template/error.rb +44 -29
  90. data/lib/action_view/template/handlers/builder.rb +12 -13
  91. data/lib/action_view/template/handlers/erb/erubi.rb +87 -0
  92. data/lib/action_view/template/handlers/erb.rb +24 -86
  93. data/lib/action_view/template/handlers/html.rb +11 -0
  94. data/lib/action_view/template/handlers/raw.rb +4 -4
  95. data/lib/action_view/template/handlers.rb +38 -8
  96. data/lib/action_view/template/html.rb +19 -10
  97. data/lib/action_view/template/inline.rb +22 -0
  98. data/lib/action_view/template/raw_file.rb +28 -0
  99. data/lib/action_view/template/resolver.rb +217 -193
  100. data/lib/action_view/template/sources/file.rb +17 -0
  101. data/lib/action_view/template/sources.rb +13 -0
  102. data/lib/action_view/template/text.rb +11 -10
  103. data/lib/action_view/template/types.rb +18 -18
  104. data/lib/action_view/template.rb +146 -90
  105. data/lib/action_view/test_case.rb +52 -32
  106. data/lib/action_view/testing/resolvers.rb +46 -34
  107. data/lib/action_view/unbound_template.rb +31 -0
  108. data/lib/action_view/version.rb +3 -1
  109. data/lib/action_view/view_paths.rb +48 -31
  110. data/lib/action_view.rb +11 -8
  111. data/lib/assets/compiled/rails-ujs.js +746 -0
  112. metadata +38 -29
  113. data/lib/action_view/helpers/record_tag_helper.rb +0 -108
  114. data/lib/action_view/tasks/dependencies.rake +0 -23
@@ -1,23 +1,17 @@
1
- require 'set'
2
- require 'active_support/core_ext/module/attribute_accessors'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module/attribute_accessors"
3
4
 
4
5
  module ActionView
5
- class Template
6
+ class Template #:nodoc:
6
7
  class Types
7
8
  class Type
8
- cattr_accessor :types
9
- self.types = Set.new
10
-
11
- def self.register(*t)
12
- types.merge(t.map { |type| type.to_s })
13
- end
14
-
15
- register :html, :text, :js, :css, :xml, :json
9
+ SET = Struct.new(:symbols).new([ :html, :text, :js, :css, :xml, :json ])
16
10
 
17
11
  def self.[](type)
18
- return type if type.is_a?(self)
19
-
20
- if type.is_a?(Symbol) || types.member?(type.to_s)
12
+ if type.is_a?(self)
13
+ type
14
+ else
21
15
  new(type)
22
16
  end
23
17
  end
@@ -28,16 +22,18 @@ module ActionView
28
22
  @symbol = symbol.to_sym
29
23
  end
30
24
 
31
- delegate :to_s, :to_sym, :to => :symbol
25
+ def to_s
26
+ @symbol.to_s
27
+ end
32
28
  alias to_str to_s
33
29
 
34
30
  def ref
35
- to_sym || to_s
31
+ @symbol
36
32
  end
33
+ alias to_sym ref
37
34
 
38
35
  def ==(type)
39
- return false if type.blank?
40
- symbol.to_sym == type.to_sym
36
+ @symbol == type.to_sym unless type.blank?
41
37
  end
42
38
  end
43
39
 
@@ -52,6 +48,10 @@ module ActionView
52
48
  def self.[](type)
53
49
  type_klass[type]
54
50
  end
51
+
52
+ def self.symbols
53
+ type_klass::SET.symbols
54
+ end
55
55
  end
56
56
  end
57
57
  end
@@ -1,12 +1,24 @@
1
- require 'active_support/core_ext/object/try'
2
- require 'active_support/core_ext/kernel/singleton_class'
3
- require 'thread'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/object/try"
4
+ require "active_support/core_ext/kernel/singleton_class"
5
+ require "active_support/deprecation"
6
+ require "thread"
7
+ require "delegate"
4
8
 
5
9
  module ActionView
6
10
  # = Action View Template
7
11
  class Template
8
12
  extend ActiveSupport::Autoload
9
13
 
14
+ def self.finalize_compiled_template_methods
15
+ ActiveSupport::Deprecation.warn "ActionView::Template.finalize_compiled_template_methods is deprecated and has no effect"
16
+ end
17
+
18
+ def self.finalize_compiled_template_methods=(_)
19
+ ActiveSupport::Deprecation.warn "ActionView::Template.finalize_compiled_template_methods= is deprecated and has no effect"
20
+ end
21
+
10
22
  # === Encodings in ActionView::Template
11
23
  #
12
24
  # ActionView::Template is one of a few sources of potential
@@ -65,8 +77,7 @@ module ActionView
65
77
  # If you want to provide an alternate mechanism for
66
78
  # specifying encodings (like ERB does via <%# encoding: ... %>),
67
79
  # you may indicate that you will handle encodings yourself
68
- # by implementing <tt>self.handles_encoding?</tt>
69
- # on your handler.
80
+ # by implementing <tt>handles_encoding?</tt> on your handler.
70
81
  #
71
82
  # If you do, Rails will not try to encode the String
72
83
  # into the default_internal, passing you the unaltered
@@ -87,48 +98,77 @@ module ActionView
87
98
  # expected_encoding
88
99
  # )
89
100
 
101
+ ##
102
+ # :method: local_assigns
103
+ #
104
+ # Returns a hash with the defined local variables.
105
+ #
106
+ # Given this sub template rendering:
107
+ #
108
+ # <%= render "shared/header", { headline: "Welcome", person: person } %>
109
+ #
110
+ # You can use +local_assigns+ in the sub templates to access the local variables:
111
+ #
112
+ # local_assigns[:headline] # => "Welcome"
113
+
90
114
  eager_autoload do
91
115
  autoload :Error
116
+ autoload :RawFile
92
117
  autoload :Handlers
93
118
  autoload :HTML
119
+ autoload :Inline
120
+ autoload :Sources
94
121
  autoload :Text
95
122
  autoload :Types
96
123
  end
97
124
 
98
125
  extend Template::Handlers
99
126
 
100
- attr_accessor :locals, :formats, :variants, :virtual_path
127
+ attr_reader :identifier, :handler, :original_encoding, :updated_at
128
+ attr_reader :variable, :format, :variant, :locals, :virtual_path
101
129
 
102
- attr_reader :source, :identifier, :handler, :original_encoding, :updated_at
103
-
104
- # This finalizer is needed (and exactly with a proc inside another proc)
105
- # otherwise templates leak in development.
106
- Finalizer = proc do |method_name, mod|
107
- proc do
108
- mod.module_eval do
109
- remove_possible_method method_name
110
- end
130
+ def initialize(source, identifier, handler, format: nil, variant: nil, locals: nil, virtual_path: nil, updated_at: nil)
131
+ unless locals
132
+ ActiveSupport::Deprecation.warn "ActionView::Template#initialize requires a locals parameter"
133
+ locals = []
111
134
  end
112
- end
113
-
114
- def initialize(source, identifier, handler, details)
115
- format = details[:format] || (handler.default_format if handler.respond_to?(:default_format))
116
135
 
117
136
  @source = source
118
137
  @identifier = identifier
119
138
  @handler = handler
120
139
  @compiled = false
121
- @original_encoding = nil
122
- @locals = details[:locals] || []
123
- @virtual_path = details[:virtual_path]
124
- @updated_at = details[:updated_at] || Time.now
125
- @formats = Array(format).map { |f| f.respond_to?(:ref) ? f.ref : f }
126
- @variants = [details[:variant]]
140
+ @locals = locals
141
+ @virtual_path = virtual_path
142
+
143
+ @variable = if @virtual_path
144
+ base = @virtual_path[-1] == "/" ? "" : ::File.basename(@virtual_path)
145
+ base =~ /\A_?(.*?)(?:\.\w+)*\z/
146
+ $1.to_sym
147
+ end
148
+
149
+ if updated_at
150
+ ActiveSupport::Deprecation.warn "ActionView::Template#updated_at is deprecated"
151
+ @updated_at = updated_at
152
+ else
153
+ @updated_at = Time.now
154
+ end
155
+ @format = format
156
+ @variant = variant
127
157
  @compile_mutex = Mutex.new
128
158
  end
129
159
 
130
- # Returns if the underlying handler supports streaming. If so,
131
- # a streaming buffer *may* be passed when it start rendering.
160
+ deprecate :original_encoding
161
+ deprecate :updated_at
162
+ deprecate def virtual_path=(_); end
163
+ deprecate def locals=(_); end
164
+ deprecate def formats=(_); end
165
+ deprecate def formats; Array(format); end
166
+ deprecate def variants=(_); end
167
+ deprecate def variants; [variant]; end
168
+ deprecate def refresh(_); self; end
169
+
170
+ # Returns whether the underlying handler supports streaming. If so,
171
+ # a streaming buffer *may* be passed when it starts rendering.
132
172
  def supports_streaming?
133
173
  handler.respond_to?(:supports_streaming?) && handler.supports_streaming?
134
174
  end
@@ -139,40 +179,29 @@ module ActionView
139
179
  # This method is instrumented as "!render_template.action_view". Notice that
140
180
  # we use a bang in this instrumentation because you don't want to
141
181
  # consume this in production. This is only slow if it's being listened to.
142
- def render(view, locals, buffer=nil, &block)
143
- instrument("!render_template") do
182
+ def render(view, locals, buffer = ActionView::OutputBuffer.new, &block)
183
+ instrument_render_template do
144
184
  compile!(view)
145
- view.send(method_name, locals, buffer, &block)
185
+ view._run(method_name, self, locals, buffer, &block)
146
186
  end
147
187
  rescue => e
148
188
  handle_render_error(view, e)
149
189
  end
150
190
 
151
191
  def type
152
- @type ||= Types[@formats.first] if @formats.first
192
+ @type ||= Types[format]
153
193
  end
154
194
 
155
- # Receives a view object and return a template similar to self by using @virtual_path.
156
- #
157
- # This method is useful if you have a template object but it does not contain its source
158
- # anymore since it was already compiled. In such cases, all you need to do is to call
159
- # refresh passing in the view object.
160
- #
161
- # Notice this method raises an error if the template to be refreshed does not have a
162
- # virtual path set (true just for inline templates).
163
- def refresh(view)
164
- raise "A template needs to have a virtual path in order to be refreshed" unless @virtual_path
165
- lookup = view.lookup_context
166
- pieces = @virtual_path.split("/")
167
- name = pieces.pop
168
- partial = !!name.sub!(/^_/, "")
169
- lookup.disable_cache do
170
- lookup.find_template(name, [ pieces.join('/') ], partial, @locals)
171
- end
195
+ def short_identifier
196
+ @short_identifier ||= defined?(Rails.root) ? identifier.sub("#{Rails.root}/", "") : identifier
172
197
  end
173
198
 
174
199
  def inspect
175
- @inspect ||= defined?(Rails.root) ? identifier.sub("#{Rails.root}/", '') : identifier
200
+ "#<#{self.class.name} #{short_identifier} locals=#{@locals.inspect}>"
201
+ end
202
+
203
+ def source
204
+ @source.to_s
176
205
  end
177
206
 
178
207
  # This method is responsible for properly setting the encoding of the
@@ -186,12 +215,14 @@ module ActionView
186
215
  # before passing the source on to the template engine, leaving a
187
216
  # blank line in its stead.
188
217
  def encode!
189
- return unless source.encoding == Encoding::BINARY
218
+ source = self.source
219
+
220
+ return source unless source.encoding == Encoding::BINARY
190
221
 
191
222
  # Look for # encoding: *. If we find one, we'll encode the
192
223
  # String in that encoding, otherwise, we'll use the
193
224
  # default external encoding.
194
- if source.sub!(/\A#{ENCODING_FLAG}/, '')
225
+ if source.sub!(/\A#{ENCODING_FLAG}/, "")
195
226
  encoding = magic_encoding = $1
196
227
  else
197
228
  encoding = Encoding.default_external
@@ -219,11 +250,23 @@ module ActionView
219
250
  end
220
251
  end
221
252
 
222
- protected
223
253
 
254
+ # Exceptions are marshalled when using the parallel test runner with DRb, so we need
255
+ # to ensure that references to the template object can be marshalled as well. This means forgoing
256
+ # the marshalling of the compiler mutex and instantiating that again on unmarshalling.
257
+ def marshal_dump # :nodoc:
258
+ [ @source, @identifier, @handler, @compiled, @locals, @virtual_path, @updated_at, @format, @variant ]
259
+ end
260
+
261
+ def marshal_load(array) # :nodoc:
262
+ @source, @identifier, @handler, @compiled, @locals, @virtual_path, @updated_at, @format, @variant = *array
263
+ @compile_mutex = Mutex.new
264
+ end
265
+
266
+ private
224
267
  # Compile a template. This method ensures a template is compiled
225
268
  # just once and removes the source after it is compiled.
226
- def compile!(view) #:nodoc:
269
+ def compile!(view)
227
270
  return if @compiled
228
271
 
229
272
  # Templates can be used concurrently in threaded environments
@@ -235,23 +278,25 @@ module ActionView
235
278
  # re-compilation
236
279
  return if @compiled
237
280
 
238
- if view.is_a?(ActionView::CompiledTemplates)
239
- mod = ActionView::CompiledTemplates
240
- else
241
- mod = view.singleton_class
242
- end
281
+ mod = view.compiled_method_container
243
282
 
244
283
  instrument("!compile_template") do
245
284
  compile(mod)
246
285
  end
247
286
 
248
- # Just discard the source if we have a virtual path. This
249
- # means we can get the template back.
250
- @source = nil if @virtual_path
251
287
  @compiled = true
252
288
  end
253
289
  end
254
290
 
291
+ class LegacyTemplate < DelegateClass(Template) # :nodoc:
292
+ attr_reader :source
293
+
294
+ def initialize(template, source)
295
+ super(template)
296
+ @source = source
297
+ end
298
+ end
299
+
255
300
  # Among other things, this method is responsible for properly setting
256
301
  # the encoding of the compiled template.
257
302
  #
@@ -264,18 +309,16 @@ module ActionView
264
309
  # encode the source into <tt>Encoding.default_internal</tt>.
265
310
  # In general, this means that templates will be UTF-8 inside of Rails,
266
311
  # regardless of the original source encoding.
267
- def compile(mod) #:nodoc:
268
- encode!
269
- method_name = self.method_name
270
- code = @handler.call(self)
312
+ def compile(mod)
313
+ source = encode!
314
+ code = @handler.call(self, source)
271
315
 
272
316
  # Make sure that the resulting String to be eval'd is in the
273
317
  # encoding of the code
274
- source = <<-end_src
318
+ original_source = source
319
+ source = +<<-end_src
275
320
  def #{method_name}(local_assigns, output_buffer)
276
- _old_virtual_path, @virtual_path = @virtual_path, #{@virtual_path.inspect};_old_output_buffer = @output_buffer;#{locals_code};#{code}
277
- ensure
278
- @virtual_path, @output_buffer = _old_virtual_path, _old_output_buffer
321
+ @virtual_path = #{@virtual_path.inspect};#{locals_code};#{code}
279
322
  end
280
323
  end_src
281
324
 
@@ -290,47 +333,60 @@ module ActionView
290
333
  # handler is valid in the default_internal. This is for handlers
291
334
  # that handle encoding but screw up
292
335
  unless source.valid_encoding?
293
- raise WrongEncodingError.new(@source, Encoding.default_internal)
336
+ raise WrongEncodingError.new(source, Encoding.default_internal)
294
337
  end
295
338
 
296
- mod.module_eval(source, identifier, 0)
297
- ObjectSpace.define_finalizer(self, Finalizer[method_name, mod])
339
+ begin
340
+ mod.module_eval(source, identifier, 0)
341
+ rescue SyntaxError
342
+ # Account for when code in the template is not syntactically valid; e.g. if we're using
343
+ # ERB and the user writes <%= foo( %>, attempting to call a helper `foo` and interpolate
344
+ # the result into the template, but missing an end parenthesis.
345
+ raise SyntaxErrorInTemplate.new(self, original_source)
346
+ end
298
347
  end
299
348
 
300
- def handle_render_error(view, e) #:nodoc:
349
+ def handle_render_error(view, e)
301
350
  if e.is_a?(Template::Error)
302
351
  e.sub_template_of(self)
303
352
  raise e
304
353
  else
305
- template = self
306
- unless template.source
307
- template = refresh(view)
308
- template.encode!
309
- end
310
- raise Template::Error.new(template, e)
354
+ raise Template::Error.new(self)
311
355
  end
312
356
  end
313
357
 
314
- def locals_code #:nodoc:
315
- # Double assign to suppress the dreaded 'assigned but unused variable' warning
316
- @locals.each_with_object('') { |key, code| code << "#{key} = #{key} = local_assigns[:#{key}];" }
358
+ def locals_code
359
+ # Only locals with valid variable names get set directly. Others will
360
+ # still be available in local_assigns.
361
+ locals = @locals - Module::RUBY_RESERVED_KEYWORDS
362
+ locals = locals.grep(/\A@?(?![A-Z0-9])(?:[[:alnum:]_]|[^\0-\177])+\z/)
363
+
364
+ # Assign for the same variable is to suppress unused variable warning
365
+ locals.each_with_object(+"") { |key, code| code << "#{key} = local_assigns[:#{key}]; #{key} = #{key};" }
317
366
  end
318
367
 
319
- def method_name #:nodoc:
368
+ def method_name
320
369
  @method_name ||= begin
321
- m = "_#{identifier_method_name}__#{@identifier.hash}_#{__id__}"
322
- m.tr!('-', '_')
370
+ m = +"_#{identifier_method_name}__#{@identifier.hash}_#{__id__}"
371
+ m.tr!("-", "_")
323
372
  m
324
373
  end
325
374
  end
326
375
 
327
- def identifier_method_name #:nodoc:
328
- inspect.tr('^a-z_', '_')
376
+ def identifier_method_name
377
+ short_identifier.tr("^a-z_", "_")
378
+ end
379
+
380
+ def instrument(action, &block) # :doc:
381
+ ActiveSupport::Notifications.instrument("#{action}.action_view", instrument_payload, &block)
382
+ end
383
+
384
+ def instrument_render_template(&block)
385
+ ActiveSupport::Notifications.instrument("!render_template.action_view", instrument_payload, &block)
329
386
  end
330
387
 
331
- def instrument(action, &block)
332
- payload = { virtual_path: @virtual_path, identifier: @identifier }
333
- ActiveSupport::Notifications.instrument("#{action}.action_view", payload, &block)
388
+ def instrument_payload
389
+ { virtual_path: @virtual_path, identifier: @identifier }
334
390
  end
335
391
  end
336
392
  end
@@ -1,9 +1,11 @@
1
- require 'active_support/core_ext/module/remove_method'
2
- require 'action_controller'
3
- require 'action_controller/test_case'
4
- require 'action_view'
1
+ # frozen_string_literal: true
5
2
 
6
- require 'rails-dom-testing'
3
+ require "active_support/core_ext/module/redefine_method"
4
+ require "action_controller"
5
+ require "action_controller/test_case"
6
+ require "action_view"
7
+
8
+ require "rails-dom-testing"
7
9
 
8
10
  module ActionView
9
11
  # = Action View Test Case
@@ -18,17 +20,17 @@ module ActionView
18
20
  end
19
21
 
20
22
  def controller_path=(path)
21
- self.class.controller_path=(path)
23
+ self.class.controller_path = (path)
22
24
  end
23
25
 
24
26
  def initialize
25
27
  super
26
28
  self.class.controller_path = ""
27
- @request = ActionController::TestRequest.new
28
- @response = ActionController::TestResponse.new
29
+ @request = ActionController::TestRequest.create(self.class)
30
+ @response = ActionDispatch::TestResponse.new
29
31
 
30
- @request.env.delete('PATH_INFO')
31
- @params = {}
32
+ @request.env.delete("PATH_INFO")
33
+ @params = ActionController::Parameters.new
32
34
  end
33
35
  end
34
36
 
@@ -49,7 +51,7 @@ module ActionView
49
51
 
50
52
  include ActiveSupport::Testing::ConstantLookup
51
53
 
52
- delegate :lookup_context, :to => :controller
54
+ delegate :lookup_context, to: :controller
53
55
  attr_accessor :controller, :output_buffer, :rendered
54
56
 
55
57
  module ClassMethods
@@ -71,10 +73,11 @@ module ActionView
71
73
  def helper_method(*methods)
72
74
  # Almost a duplicate from ActionController::Helpers
73
75
  methods.flatten.each do |method|
74
- _helpers.module_eval <<-end_eval
76
+ _helpers.module_eval <<-end_eval, __FILE__, __LINE__ + 1
75
77
  def #{method}(*args, &block) # def current_user(*args, &block)
76
- _test_case.send(%(#{method}), *args, &block) # _test_case.send(%(current_user), *args, &block)
78
+ _test_case.send(:'#{method}', *args, &block) # _test_case.send(:'current_user', *args, &block)
77
79
  end # end
80
+ ruby2_keywords(:'#{method}') if respond_to?(:ruby2_keywords, true)
78
81
  end_eval
79
82
  end
80
83
  end
@@ -91,21 +94,20 @@ module ActionView
91
94
  end
92
95
 
93
96
  private
94
-
95
97
  def include_helper_modules!
96
98
  helper(helper_class) if helper_class
97
99
  include _helpers
98
100
  end
99
-
100
101
  end
101
102
 
102
103
  def setup_with_controller
103
104
  @controller = ActionView::TestCase::TestController.new
104
105
  @request = @controller.request
106
+ @view_flow = ActionView::OutputFlow.new
105
107
  # empty string ensures buffer has UTF-8 encoding as
106
108
  # new without arguments returns ASCII-8BIT encoded buffer like String#new
107
- @output_buffer = ActiveSupport::SafeBuffer.new ''
108
- @rendered = ''
109
+ @output_buffer = ActiveSupport::SafeBuffer.new ""
110
+ @rendered = +""
109
111
 
110
112
  make_test_case_available_to_view!
111
113
  say_no_to_protect_against_forgery!
@@ -125,6 +127,10 @@ module ActionView
125
127
  @_rendered_views ||= RenderedViewsCollection.new
126
128
  end
127
129
 
130
+ def _routes
131
+ @controller._routes if @controller.respond_to?(:_routes)
132
+ end
133
+
128
134
  # Need to experiment if this priority is the best one: rendered => output_buffer
129
135
  class RenderedViewsCollection
130
136
  def initialize
@@ -146,17 +152,17 @@ module ActionView
146
152
 
147
153
  def view_rendered?(view, expected_locals)
148
154
  locals_for(view).any? do |actual_locals|
149
- expected_locals.all? {|key, value| value == actual_locals[key] }
155
+ expected_locals.all? { |key, value| value == actual_locals[key] }
150
156
  end
151
157
  end
152
158
  end
153
159
 
154
160
  included do
155
161
  setup :setup_with_controller
162
+ ActiveSupport.run_load_hooks(:action_view_test_case, self)
156
163
  end
157
164
 
158
165
  private
159
-
160
166
  # Need to experiment if this priority is the best one: rendered => output_buffer
161
167
  def document_root_element
162
168
  Nokogiri::HTML::Document.parse(@rendered.blank? ? @output_buffer : @rendered).root
@@ -164,7 +170,7 @@ module ActionView
164
170
 
165
171
  def say_no_to_protect_against_forgery!
166
172
  _helpers.module_eval do
167
- remove_possible_method :protect_against_forgery?
173
+ silence_redefinition_of_method :protect_against_forgery?
168
174
  def protect_against_forgery?
169
175
  false
170
176
  end
@@ -204,10 +210,10 @@ module ActionView
204
210
  def view
205
211
  @view ||= begin
206
212
  view = @controller.view_context
207
- view.singleton_class.send :include, _helpers
213
+ view.singleton_class.include(_helpers)
208
214
  view.extend(Locals)
209
- view.rendered_views = self.rendered_views
210
- view.output_buffer = self.output_buffer
215
+ view.rendered_views = rendered_views
216
+ view.output_buffer = output_buffer
211
217
  view
212
218
  end
213
219
  end
@@ -240,9 +246,9 @@ module ActionView
240
246
  :@test_passed,
241
247
  :@view,
242
248
  :@view_context_class,
249
+ :@view_flow,
243
250
  :@_subscribers,
244
- :@html_document,
245
- :@html_scanner_document
251
+ :@html_document
246
252
  ]
247
253
 
248
254
  def _user_defined_ivars
@@ -259,19 +265,33 @@ module ActionView
259
265
  end]
260
266
  end
261
267
 
262
- def _routes
263
- @controller._routes if @controller.respond_to?(:_routes)
264
- end
265
-
266
268
  def method_missing(selector, *args)
267
- if @controller.respond_to?(:_routes) &&
268
- ( @controller._routes.named_routes.route_defined?(selector) ||
269
- @controller._routes.mounted_helpers.method_defined?(selector) )
269
+ begin
270
+ routes = @controller.respond_to?(:_routes) && @controller._routes
271
+ rescue
272
+ # Don't call routes, if there is an error on _routes call
273
+ end
274
+
275
+ if routes &&
276
+ (routes.named_routes.route_defined?(selector) ||
277
+ routes.mounted_helpers.method_defined?(selector))
270
278
  @controller.__send__(selector, *args)
271
279
  else
272
280
  super
273
281
  end
274
282
  end
283
+
284
+ def respond_to_missing?(name, include_private = false)
285
+ begin
286
+ routes = @controller.respond_to?(:_routes) && @controller._routes
287
+ rescue
288
+ # Don't call routes, if there is an error on _routes call
289
+ end
290
+
291
+ routes &&
292
+ (routes.named_routes.route_defined?(name) ||
293
+ routes.mounted_helpers.method_defined?(name))
294
+ end
275
295
  end
276
296
 
277
297
  include Behavior