actionview 4.2.11.1 → 6.1.5

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 (117) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +232 -186
  3. data/MIT-LICENSE +1 -2
  4. data/README.rdoc +9 -8
  5. data/lib/action_view/base.rb +115 -39
  6. data/lib/action_view/buffers.rb +18 -1
  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 -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 +282 -83
  15. data/lib/action_view/helpers/asset_url_helper.rb +175 -69
  16. data/lib/action_view/helpers/atom_feed_helper.rb +20 -17
  17. data/lib/action_view/helpers/cache_helper.rb +107 -43
  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 +232 -130
  23. data/lib/action_view/helpers/debug_helper.rb +7 -6
  24. data/lib/action_view/helpers/form_helper.rb +808 -146
  25. data/lib/action_view/helpers/form_options_helper.rb +124 -78
  26. data/lib/action_view/helpers/form_tag_helper.rb +120 -74
  27. data/lib/action_view/helpers/javascript_helper.rb +33 -17
  28. data/lib/action_view/helpers/number_helper.rb +87 -62
  29. data/lib/action_view/helpers/output_safety_helper.rb +36 -4
  30. data/lib/action_view/helpers/rendering_helper.rb +21 -10
  31. data/lib/action_view/helpers/sanitize_helper.rb +30 -31
  32. data/lib/action_view/helpers/tag_helper.rb +269 -68
  33. data/lib/action_view/helpers/tags/base.rb +141 -97
  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 +3 -2
  42. data/lib/action_view/helpers/tags/date_select.rb +38 -37
  43. data/lib/action_view/helpers/tags/datetime_field.rb +4 -3
  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 +6 -0
  50. data/lib/action_view/helpers/tags/label.rb +7 -2
  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 +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 +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 +15 -16
  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 +3 -1
  69. data/lib/action_view/helpers/text_helper.rb +56 -38
  70. data/lib/action_view/helpers/translation_helper.rb +150 -68
  71. data/lib/action_view/helpers/url_helper.rb +284 -117
  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 +77 -10
  75. data/lib/action_view/lookup_context.rb +134 -91
  76. data/lib/action_view/model_naming.rb +3 -1
  77. data/lib/action_view/path_set.rb +26 -24
  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 +151 -14
  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 +55 -303
  85. data/lib/action_view/renderer/renderer.rb +66 -9
  86. data/lib/action_view/renderer/streaming_template_renderer.rb +58 -54
  87. data/lib/action_view/renderer/template_renderer.rb +82 -73
  88. data/lib/action_view/rendering.rb +71 -45
  89. data/lib/action_view/routing_url_for.rb +34 -23
  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 +12 -8
  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 +263 -197
  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 +108 -92
  108. data/lib/action_view/test_case.rb +66 -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 +73 -58
  113. data/lib/action_view.rb +14 -8
  114. data/lib/assets/compiled/rails-ujs.js +746 -0
  115. metadata +42 -29
  116. data/lib/action_view/helpers/record_tag_helper.rb +0 -108
  117. 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,6 +1,7 @@
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 "thread"
4
+ require "delegate"
4
5
 
5
6
  module ActionView
6
7
  # = Action View Template
@@ -65,8 +66,7 @@ module ActionView
65
66
  # If you want to provide an alternate mechanism for
66
67
  # specifying encodings (like ERB does via <%# encoding: ... %>),
67
68
  # you may indicate that you will handle encodings yourself
68
- # by implementing <tt>self.handles_encoding?</tt>
69
- # on your handler.
69
+ # by implementing <tt>handles_encoding?</tt> on your handler.
70
70
  #
71
71
  # If you do, Rails will not try to encode the String
72
72
  # into the default_internal, passing you the unaltered
@@ -87,48 +87,57 @@ module ActionView
87
87
  # expected_encoding
88
88
  # )
89
89
 
90
+ ##
91
+ # :method: local_assigns
92
+ #
93
+ # Returns a hash with the defined local variables.
94
+ #
95
+ # Given this sub template rendering:
96
+ #
97
+ # <%= render "shared/header", { headline: "Welcome", person: person } %>
98
+ #
99
+ # You can use +local_assigns+ in the sub templates to access the local variables:
100
+ #
101
+ # local_assigns[:headline] # => "Welcome"
102
+
90
103
  eager_autoload do
91
104
  autoload :Error
105
+ autoload :RawFile
106
+ autoload :Renderable
92
107
  autoload :Handlers
93
108
  autoload :HTML
109
+ autoload :Inline
110
+ autoload :Sources
94
111
  autoload :Text
95
112
  autoload :Types
96
113
  end
97
114
 
98
115
  extend Template::Handlers
99
116
 
100
- attr_accessor :locals, :formats, :variants, :virtual_path
101
-
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
111
- end
112
- end
113
-
114
- def initialize(source, identifier, handler, details)
115
- 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
116
119
 
120
+ def initialize(source, identifier, handler, locals:, format: nil, variant: nil, virtual_path: nil)
117
121
  @source = source
118
122
  @identifier = identifier
119
123
  @handler = handler
120
124
  @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]]
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
127
136
  @compile_mutex = Mutex.new
128
137
  end
129
138
 
130
- # Returns if the underlying handler supports streaming. If so,
131
- # a streaming buffer *may* be passed when it start rendering.
139
+ # Returns whether the underlying handler supports streaming. If so,
140
+ # a streaming buffer *may* be passed when it starts rendering.
132
141
  def supports_streaming?
133
142
  handler.respond_to?(:supports_streaming?) && handler.supports_streaming?
134
143
  end
@@ -139,40 +148,29 @@ module ActionView
139
148
  # This method is instrumented as "!render_template.action_view". Notice that
140
149
  # we use a bang in this instrumentation because you don't want to
141
150
  # 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
151
+ def render(view, locals, buffer = ActionView::OutputBuffer.new, add_to_stack: true, &block)
152
+ instrument_render_template do
144
153
  compile!(view)
145
- view.send(method_name, locals, buffer, &block)
154
+ view._run(method_name, self, locals, buffer, add_to_stack: add_to_stack, &block)
146
155
  end
147
156
  rescue => e
148
157
  handle_render_error(view, e)
149
158
  end
150
159
 
151
160
  def type
152
- @type ||= Types[@formats.first] if @formats.first
161
+ @type ||= Types[format]
153
162
  end
154
163
 
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
164
+ def short_identifier
165
+ @short_identifier ||= defined?(Rails.root) ? identifier.delete_prefix("#{Rails.root}/") : identifier
172
166
  end
173
167
 
174
168
  def inspect
175
- @inspect ||= defined?(Rails.root) ? identifier.sub("#{Rails.root}/", '') : identifier
169
+ "#<#{self.class.name} #{short_identifier} locals=#{@locals.inspect}>"
170
+ end
171
+
172
+ def source
173
+ @source.to_s
176
174
  end
177
175
 
178
176
  # This method is responsible for properly setting the encoding of the
@@ -186,12 +184,14 @@ module ActionView
186
184
  # before passing the source on to the template engine, leaving a
187
185
  # blank line in its stead.
188
186
  def encode!
189
- return unless source.encoding == Encoding::BINARY
187
+ source = self.source
188
+
189
+ return source unless source.encoding == Encoding::BINARY
190
190
 
191
191
  # Look for # encoding: *. If we find one, we'll encode the
192
192
  # String in that encoding, otherwise, we'll use the
193
193
  # default external encoding.
194
- if source.sub!(/\A#{ENCODING_FLAG}/, '')
194
+ if source.sub!(/\A#{ENCODING_FLAG}/, "")
195
195
  encoding = magic_encoding = $1
196
196
  else
197
197
  encoding = Encoding.default_external
@@ -219,11 +219,23 @@ module ActionView
219
219
  end
220
220
  end
221
221
 
222
- protected
223
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
224
236
  # Compile a template. This method ensures a template is compiled
225
237
  # just once and removes the source after it is compiled.
226
- def compile!(view) #:nodoc:
238
+ def compile!(view)
227
239
  return if @compiled
228
240
 
229
241
  # Templates can be used concurrently in threaded environments
@@ -235,19 +247,12 @@ module ActionView
235
247
  # re-compilation
236
248
  return if @compiled
237
249
 
238
- if view.is_a?(ActionView::CompiledTemplates)
239
- mod = ActionView::CompiledTemplates
240
- else
241
- mod = view.singleton_class
242
- end
250
+ mod = view.compiled_method_container
243
251
 
244
252
  instrument("!compile_template") do
245
253
  compile(mod)
246
254
  end
247
255
 
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
256
  @compiled = true
252
257
  end
253
258
  end
@@ -264,18 +269,16 @@ module ActionView
264
269
  # encode the source into <tt>Encoding.default_internal</tt>.
265
270
  # In general, this means that templates will be UTF-8 inside of Rails,
266
271
  # regardless of the original source encoding.
267
- def compile(mod) #:nodoc:
268
- encode!
269
- method_name = self.method_name
270
- code = @handler.call(self)
272
+ def compile(mod)
273
+ source = encode!
274
+ code = @handler.call(self, source)
271
275
 
272
276
  # Make sure that the resulting String to be eval'd is in the
273
277
  # encoding of the code
274
- source = <<-end_src
278
+ original_source = source
279
+ source = +<<-end_src
275
280
  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
281
+ @virtual_path = #{@virtual_path.inspect};#{locals_code};#{code}
279
282
  end
280
283
  end_src
281
284
 
@@ -290,47 +293,60 @@ module ActionView
290
293
  # handler is valid in the default_internal. This is for handlers
291
294
  # that handle encoding but screw up
292
295
  unless source.valid_encoding?
293
- raise WrongEncodingError.new(@source, Encoding.default_internal)
296
+ raise WrongEncodingError.new(source, Encoding.default_internal)
294
297
  end
295
298
 
296
- mod.module_eval(source, identifier, 0)
297
- 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
298
307
  end
299
308
 
300
- def handle_render_error(view, e) #:nodoc:
309
+ def handle_render_error(view, e)
301
310
  if e.is_a?(Template::Error)
302
311
  e.sub_template_of(self)
303
312
  raise e
304
313
  else
305
- template = self
306
- unless template.source
307
- template = refresh(view)
308
- template.encode!
309
- end
310
- raise Template::Error.new(template, e)
314
+ raise Template::Error.new(self)
311
315
  end
312
316
  end
313
317
 
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}];" }
318
+ def locals_code
319
+ # Only locals with valid variable names get set directly. Others will
320
+ # still be available in local_assigns.
321
+ locals = @locals - Module::RUBY_RESERVED_KEYWORDS
322
+ locals = locals.grep(/\A@?(?![A-Z0-9])(?:[[:alnum:]_]|[^\0-\177])+\z/)
323
+
324
+ # Assign for the same variable is to suppress unused variable warning
325
+ locals.each_with_object(+"") { |key, code| code << "#{key} = local_assigns[:#{key}]; #{key} = #{key};" }
317
326
  end
318
327
 
319
- def method_name #:nodoc:
328
+ def method_name
320
329
  @method_name ||= begin
321
- m = "_#{identifier_method_name}__#{@identifier.hash}_#{__id__}"
322
- m.tr!('-', '_')
330
+ m = +"_#{identifier_method_name}__#{@identifier.hash}_#{__id__}"
331
+ m.tr!("-", "_")
323
332
  m
324
333
  end
325
334
  end
326
335
 
327
- def identifier_method_name #:nodoc:
328
- inspect.tr('^a-z_', '_')
336
+ def identifier_method_name
337
+ short_identifier.tr("^a-z_", "_")
338
+ end
339
+
340
+ def instrument(action, &block) # :doc:
341
+ ActiveSupport::Notifications.instrument("#{action}.action_view", instrument_payload, &block)
342
+ end
343
+
344
+ def instrument_render_template(&block)
345
+ ActiveSupport::Notifications.instrument("!render_template.action_view", instrument_payload, &block)
329
346
  end
330
347
 
331
- def instrument(action, &block)
332
- payload = { virtual_path: @virtual_path, identifier: @identifier }
333
- ActiveSupport::Notifications.instrument("#{action}.action_view", payload, &block)
348
+ def instrument_payload
349
+ { virtual_path: @virtual_path, identifier: @identifier }
334
350
  end
335
351
  end
336
352
  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
@@ -14,21 +16,22 @@ module ActionView
14
16
  attr_accessor :request, :response, :params
15
17
 
16
18
  class << self
17
- attr_writer :controller_path
19
+ # Overrides AbstractController::Base#controller_path
20
+ attr_accessor :controller_path
18
21
  end
19
22
 
20
23
  def controller_path=(path)
21
- self.class.controller_path=(path)
24
+ self.class.controller_path = path
22
25
  end
23
26
 
24
27
  def initialize
25
28
  super
26
29
  self.class.controller_path = ""
27
- @request = ActionController::TestRequest.new
28
- @response = ActionController::TestResponse.new
30
+ @request = ActionController::TestRequest.create(self.class)
31
+ @response = ActionDispatch::TestResponse.new
29
32
 
30
- @request.env.delete('PATH_INFO')
31
- @params = {}
33
+ @request.env.delete("PATH_INFO")
34
+ @params = ActionController::Parameters.new
32
35
  end
33
36
  end
34
37
 
@@ -49,7 +52,7 @@ module ActionView
49
52
 
50
53
  include ActiveSupport::Testing::ConstantLookup
51
54
 
52
- delegate :lookup_context, :to => :controller
55
+ delegate :lookup_context, to: :controller
53
56
  attr_accessor :controller, :output_buffer, :rendered
54
57
 
55
58
  module ClassMethods
@@ -71,10 +74,11 @@ module ActionView
71
74
  def helper_method(*methods)
72
75
  # Almost a duplicate from ActionController::Helpers
73
76
  methods.flatten.each do |method|
74
- _helpers.module_eval <<-end_eval
77
+ _helpers_for_modification.module_eval <<-end_eval, __FILE__, __LINE__ + 1
75
78
  def #{method}(*args, &block) # def current_user(*args, &block)
76
- _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)
77
80
  end # end
81
+ ruby2_keywords(:'#{method}') if respond_to?(:ruby2_keywords, true)
78
82
  end_eval
79
83
  end
80
84
  end
@@ -91,24 +95,24 @@ module ActionView
91
95
  end
92
96
 
93
97
  private
94
-
95
98
  def include_helper_modules!
96
99
  helper(helper_class) if helper_class
97
100
  include _helpers
98
101
  end
99
-
100
102
  end
101
103
 
102
104
  def setup_with_controller
103
- @controller = ActionView::TestCase::TestController.new
105
+ controller_class = Class.new(ActionView::TestCase::TestController)
106
+ @controller = controller_class.new
104
107
  @request = @controller.request
108
+ @view_flow = ActionView::OutputFlow.new
105
109
  # empty string ensures buffer has UTF-8 encoding as
106
110
  # new without arguments returns ASCII-8BIT encoded buffer like String#new
107
- @output_buffer = ActiveSupport::SafeBuffer.new ''
108
- @rendered = ''
111
+ @output_buffer = ActiveSupport::SafeBuffer.new ""
112
+ @rendered = +""
109
113
 
110
- make_test_case_available_to_view!
111
- say_no_to_protect_against_forgery!
114
+ test_case_instance = self
115
+ controller_class.define_method(:_test_case) { test_case_instance }
112
116
  end
113
117
 
114
118
  def config
@@ -125,6 +129,10 @@ module ActionView
125
129
  @_rendered_views ||= RenderedViewsCollection.new
126
130
  end
127
131
 
132
+ def _routes
133
+ @controller._routes if @controller.respond_to?(:_routes)
134
+ end
135
+
128
136
  # Need to experiment if this priority is the best one: rendered => output_buffer
129
137
  class RenderedViewsCollection
130
138
  def initialize
@@ -146,41 +154,32 @@ module ActionView
146
154
 
147
155
  def view_rendered?(view, expected_locals)
148
156
  locals_for(view).any? do |actual_locals|
149
- expected_locals.all? {|key, value| value == actual_locals[key] }
157
+ expected_locals.all? { |key, value| value == actual_locals[key] }
150
158
  end
151
159
  end
152
160
  end
153
161
 
154
162
  included do
155
163
  setup :setup_with_controller
156
- end
164
+ ActiveSupport.run_load_hooks(:action_view_test_case, self)
157
165
 
158
- private
159
-
160
- # Need to experiment if this priority is the best one: rendered => output_buffer
161
- def document_root_element
162
- Nokogiri::HTML::Document.parse(@rendered.blank? ? @output_buffer : @rendered).root
163
- end
164
-
165
- def say_no_to_protect_against_forgery!
166
- _helpers.module_eval do
167
- remove_possible_method :protect_against_forgery?
166
+ helper do
168
167
  def protect_against_forgery?
169
168
  false
170
169
  end
171
- end
172
- end
173
170
 
174
- def make_test_case_available_to_view!
175
- test_case_instance = self
176
- _helpers.module_eval do
177
- unless private_method_defined?(:_test_case)
178
- define_method(:_test_case) { test_case_instance }
179
- private :_test_case
171
+ def _test_case
172
+ controller._test_case
180
173
  end
181
174
  end
182
175
  end
183
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
+
184
183
  module Locals
185
184
  attr_accessor :rendered_views
186
185
 
@@ -204,10 +203,10 @@ module ActionView
204
203
  def view
205
204
  @view ||= begin
206
205
  view = @controller.view_context
207
- view.singleton_class.send :include, _helpers
206
+ view.singleton_class.include(_helpers)
208
207
  view.extend(Locals)
209
- view.rendered_views = self.rendered_views
210
- view.output_buffer = self.output_buffer
208
+ view.rendered_views = rendered_views
209
+ view.output_buffer = output_buffer
211
210
  view
212
211
  end
213
212
  end
@@ -240,9 +239,9 @@ module ActionView
240
239
  :@test_passed,
241
240
  :@view,
242
241
  :@view_context_class,
242
+ :@view_flow,
243
243
  :@_subscribers,
244
- :@html_document,
245
- :@html_scanner_document
244
+ :@html_document
246
245
  ]
247
246
 
248
247
  def _user_defined_ivars
@@ -259,19 +258,33 @@ module ActionView
259
258
  end]
260
259
  end
261
260
 
262
- def _routes
263
- @controller._routes if @controller.respond_to?(:_routes)
264
- end
265
-
266
261
  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) )
262
+ begin
263
+ routes = @controller.respond_to?(:_routes) && @controller._routes
264
+ rescue
265
+ # Don't call routes, if there is an error on _routes call
266
+ end
267
+
268
+ if routes &&
269
+ (routes.named_routes.route_defined?(selector) ||
270
+ routes.mounted_helpers.method_defined?(selector))
270
271
  @controller.__send__(selector, *args)
271
272
  else
272
273
  super
273
274
  end
274
275
  end
276
+
277
+ def respond_to_missing?(name, include_private = false)
278
+ begin
279
+ routes = defined?(@controller) && @controller.respond_to?(:_routes) && @controller._routes
280
+ rescue
281
+ # Don't call routes, if there is an error on _routes call
282
+ end
283
+
284
+ routes &&
285
+ (routes.named_routes.route_defined?(name) ||
286
+ routes.mounted_helpers.method_defined?(name))
287
+ end
275
288
  end
276
289
 
277
290
  include Behavior