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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +232 -186
- data/MIT-LICENSE +1 -2
- data/README.rdoc +9 -8
- data/lib/action_view/base.rb +115 -39
- data/lib/action_view/buffers.rb +18 -1
- data/lib/action_view/cache_expiry.rb +52 -0
- data/lib/action_view/context.rb +8 -12
- data/lib/action_view/dependency_tracker.rb +61 -21
- data/lib/action_view/digestor.rb +89 -85
- data/lib/action_view/flows.rb +11 -12
- data/lib/action_view/gem_version.rb +6 -4
- data/lib/action_view/helpers/active_model_helper.rb +16 -11
- data/lib/action_view/helpers/asset_tag_helper.rb +282 -83
- data/lib/action_view/helpers/asset_url_helper.rb +175 -69
- data/lib/action_view/helpers/atom_feed_helper.rb +20 -17
- data/lib/action_view/helpers/cache_helper.rb +107 -43
- data/lib/action_view/helpers/capture_helper.rb +20 -13
- data/lib/action_view/helpers/controller_helper.rb +15 -4
- data/lib/action_view/helpers/csp_helper.rb +26 -0
- data/lib/action_view/helpers/csrf_helper.rb +8 -6
- data/lib/action_view/helpers/date_helper.rb +232 -130
- data/lib/action_view/helpers/debug_helper.rb +7 -6
- data/lib/action_view/helpers/form_helper.rb +808 -146
- data/lib/action_view/helpers/form_options_helper.rb +124 -78
- data/lib/action_view/helpers/form_tag_helper.rb +120 -74
- data/lib/action_view/helpers/javascript_helper.rb +33 -17
- data/lib/action_view/helpers/number_helper.rb +87 -62
- data/lib/action_view/helpers/output_safety_helper.rb +36 -4
- data/lib/action_view/helpers/rendering_helper.rb +21 -10
- data/lib/action_view/helpers/sanitize_helper.rb +30 -31
- data/lib/action_view/helpers/tag_helper.rb +269 -68
- data/lib/action_view/helpers/tags/base.rb +141 -97
- data/lib/action_view/helpers/tags/check_box.rb +20 -19
- data/lib/action_view/helpers/tags/checkable.rb +4 -2
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +12 -34
- data/lib/action_view/helpers/tags/collection_helpers.rb +69 -36
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +6 -12
- data/lib/action_view/helpers/tags/collection_select.rb +4 -2
- data/lib/action_view/helpers/tags/color_field.rb +4 -3
- data/lib/action_view/helpers/tags/date_field.rb +3 -2
- data/lib/action_view/helpers/tags/date_select.rb +38 -37
- data/lib/action_view/helpers/tags/datetime_field.rb +4 -3
- data/lib/action_view/helpers/tags/datetime_local_field.rb +3 -2
- data/lib/action_view/helpers/tags/datetime_select.rb +2 -0
- data/lib/action_view/helpers/tags/email_field.rb +2 -0
- data/lib/action_view/helpers/tags/file_field.rb +2 -0
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +4 -2
- data/lib/action_view/helpers/tags/hidden_field.rb +6 -0
- data/lib/action_view/helpers/tags/label.rb +7 -2
- data/lib/action_view/helpers/tags/month_field.rb +3 -2
- data/lib/action_view/helpers/tags/number_field.rb +2 -0
- data/lib/action_view/helpers/tags/password_field.rb +3 -1
- data/lib/action_view/helpers/tags/placeholderable.rb +3 -1
- data/lib/action_view/helpers/tags/radio_button.rb +7 -6
- data/lib/action_view/helpers/tags/range_field.rb +2 -0
- data/lib/action_view/helpers/tags/search_field.rb +14 -9
- data/lib/action_view/helpers/tags/select.rb +11 -10
- data/lib/action_view/helpers/tags/tel_field.rb +2 -0
- data/lib/action_view/helpers/tags/text_area.rb +4 -2
- data/lib/action_view/helpers/tags/text_field.rb +8 -8
- data/lib/action_view/helpers/tags/time_field.rb +3 -2
- data/lib/action_view/helpers/tags/time_select.rb +2 -0
- data/lib/action_view/helpers/tags/time_zone_select.rb +3 -1
- data/lib/action_view/helpers/tags/translator.rb +15 -16
- data/lib/action_view/helpers/tags/url_field.rb +2 -0
- data/lib/action_view/helpers/tags/week_field.rb +3 -2
- data/lib/action_view/helpers/tags.rb +3 -1
- data/lib/action_view/helpers/text_helper.rb +56 -38
- data/lib/action_view/helpers/translation_helper.rb +150 -68
- data/lib/action_view/helpers/url_helper.rb +284 -117
- data/lib/action_view/helpers.rb +5 -3
- data/lib/action_view/layouts.rb +68 -63
- data/lib/action_view/log_subscriber.rb +77 -10
- data/lib/action_view/lookup_context.rb +134 -91
- data/lib/action_view/model_naming.rb +3 -1
- data/lib/action_view/path_set.rb +26 -24
- data/lib/action_view/railtie.rb +62 -13
- data/lib/action_view/record_identifier.rb +53 -26
- data/lib/action_view/renderer/abstract_renderer.rb +151 -14
- data/lib/action_view/renderer/collection_renderer.rb +196 -0
- data/lib/action_view/renderer/object_renderer.rb +34 -0
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +102 -0
- data/lib/action_view/renderer/partial_renderer.rb +55 -303
- data/lib/action_view/renderer/renderer.rb +66 -9
- data/lib/action_view/renderer/streaming_template_renderer.rb +58 -54
- data/lib/action_view/renderer/template_renderer.rb +82 -73
- data/lib/action_view/rendering.rb +71 -45
- data/lib/action_view/routing_url_for.rb +34 -23
- data/lib/action_view/tasks/cache_digests.rake +25 -0
- data/lib/action_view/template/error.rb +44 -29
- data/lib/action_view/template/handlers/builder.rb +12 -13
- data/lib/action_view/template/handlers/erb/erubi.rb +89 -0
- data/lib/action_view/template/handlers/erb.rb +23 -89
- data/lib/action_view/template/handlers/html.rb +11 -0
- data/lib/action_view/template/handlers/raw.rb +4 -4
- data/lib/action_view/template/handlers.rb +12 -8
- data/lib/action_view/template/html.rb +10 -11
- data/lib/action_view/template/inline.rb +22 -0
- data/lib/action_view/template/raw_file.rb +25 -0
- data/lib/action_view/template/renderable.rb +24 -0
- data/lib/action_view/template/resolver.rb +263 -197
- data/lib/action_view/template/sources/file.rb +17 -0
- data/lib/action_view/template/sources.rb +13 -0
- data/lib/action_view/template/text.rb +8 -10
- data/lib/action_view/template/types.rb +18 -18
- data/lib/action_view/template.rb +108 -92
- data/lib/action_view/test_case.rb +66 -53
- data/lib/action_view/testing/resolvers.rb +24 -33
- data/lib/action_view/unbound_template.rb +31 -0
- data/lib/action_view/version.rb +3 -1
- data/lib/action_view/view_paths.rb +73 -58
- data/lib/action_view.rb +14 -8
- data/lib/assets/compiled/rails-ujs.js +746 -0
- metadata +42 -29
- data/lib/action_view/helpers/record_tag_helper.rb +0 -108
- data/lib/action_view/tasks/dependencies.rake +0 -23
@@ -1,23 +1,17 @@
|
|
1
|
-
|
2
|
-
|
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
|
-
|
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
|
-
|
19
|
-
|
20
|
-
|
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
|
-
|
25
|
+
def to_s
|
26
|
+
@symbol.to_s
|
27
|
+
end
|
32
28
|
alias to_str to_s
|
33
29
|
|
34
30
|
def ref
|
35
|
-
|
31
|
+
@symbol
|
36
32
|
end
|
33
|
+
alias to_sym ref
|
37
34
|
|
38
35
|
def ==(type)
|
39
|
-
|
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
|
data/lib/action_view/template.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
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>
|
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
|
-
|
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
|
-
@
|
122
|
-
@
|
123
|
-
|
124
|
-
@
|
125
|
-
|
126
|
-
|
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
|
131
|
-
# a streaming buffer *may* be passed when it
|
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=
|
143
|
-
|
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.
|
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[
|
161
|
+
@type ||= Types[format]
|
153
162
|
end
|
154
163
|
|
155
|
-
|
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
|
-
|
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
|
-
|
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)
|
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
|
-
|
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)
|
268
|
-
encode!
|
269
|
-
|
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
|
-
|
278
|
+
original_source = source
|
279
|
+
source = +<<-end_src
|
275
280
|
def #{method_name}(local_assigns, output_buffer)
|
276
|
-
|
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(
|
296
|
+
raise WrongEncodingError.new(source, Encoding.default_internal)
|
294
297
|
end
|
295
298
|
|
296
|
-
|
297
|
-
|
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)
|
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
|
-
|
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
|
315
|
-
#
|
316
|
-
|
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
|
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
|
328
|
-
|
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
|
332
|
-
|
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
|
-
|
2
|
-
require 'action_controller'
|
3
|
-
require 'action_controller/test_case'
|
4
|
-
require 'action_view'
|
1
|
+
# frozen_string_literal: true
|
5
2
|
|
6
|
-
require
|
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
|
-
|
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=
|
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.
|
28
|
-
@response =
|
30
|
+
@request = ActionController::TestRequest.create(self.class)
|
31
|
+
@response = ActionDispatch::TestResponse.new
|
29
32
|
|
30
|
-
@request.env.delete(
|
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, :
|
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
|
-
|
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(
|
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
|
-
|
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
|
-
|
111
|
-
|
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
|
-
|
164
|
+
ActiveSupport.run_load_hooks(:action_view_test_case, self)
|
157
165
|
|
158
|
-
|
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
|
-
|
175
|
-
|
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.
|
206
|
+
view.singleton_class.include(_helpers)
|
208
207
|
view.extend(Locals)
|
209
|
-
view.rendered_views =
|
210
|
-
view.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
|
-
|
268
|
-
|
269
|
-
|
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
|