actionview 4.2.11.1 → 7.0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of actionview might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +229 -215
- data/MIT-LICENSE +1 -1
- data/README.rdoc +9 -8
- data/lib/action_view/base.rb +116 -43
- data/lib/action_view/buffers.rb +20 -3
- data/lib/action_view/cache_expiry.rb +66 -0
- data/lib/action_view/context.rb +8 -12
- data/lib/action_view/dependency_tracker/erb_tracker.rb +154 -0
- data/lib/action_view/dependency_tracker/ripper_tracker.rb +59 -0
- data/lib/action_view/dependency_tracker.rb +21 -122
- data/lib/action_view/digestor.rb +92 -85
- data/lib/action_view/flows.rb +15 -16
- data/lib/action_view/gem_version.rb +6 -4
- data/lib/action_view/helpers/active_model_helper.rb +17 -12
- data/lib/action_view/helpers/asset_tag_helper.rb +356 -101
- data/lib/action_view/helpers/asset_url_helper.rb +180 -74
- data/lib/action_view/helpers/atom_feed_helper.rb +21 -19
- data/lib/action_view/helpers/cache_helper.rb +156 -43
- data/lib/action_view/helpers/capture_helper.rb +21 -14
- data/lib/action_view/helpers/controller_helper.rb +16 -5
- 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 +288 -132
- data/lib/action_view/helpers/debug_helper.rb +9 -6
- data/lib/action_view/helpers/form_helper.rb +956 -173
- data/lib/action_view/helpers/form_options_helper.rb +178 -97
- data/lib/action_view/helpers/form_tag_helper.rb +220 -101
- data/lib/action_view/helpers/javascript_helper.rb +33 -19
- data/lib/action_view/helpers/number_helper.rb +88 -63
- data/lib/action_view/helpers/output_safety_helper.rb +38 -6
- data/lib/action_view/helpers/rendering_helper.rb +21 -10
- data/lib/action_view/helpers/sanitize_helper.rb +31 -32
- data/lib/action_view/helpers/tag_helper.rb +332 -71
- data/lib/action_view/helpers/tags/base.rb +123 -99
- data/lib/action_view/helpers/tags/check_box.rb +21 -20
- 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 +5 -3
- 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 +18 -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 +12 -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/weekday_select.rb +28 -0
- data/lib/action_view/helpers/tags.rb +5 -2
- data/lib/action_view/helpers/text_helper.rb +80 -51
- data/lib/action_view/helpers/translation_helper.rb +120 -69
- data/lib/action_view/helpers/url_helper.rb +398 -171
- data/lib/action_view/helpers.rb +29 -27
- data/lib/action_view/layouts.rb +68 -63
- data/lib/action_view/log_subscriber.rb +77 -10
- data/lib/action_view/lookup_context.rb +137 -113
- data/lib/action_view/model_naming.rb +4 -2
- data/lib/action_view/path_set.rb +28 -32
- data/lib/action_view/railtie.rb +74 -13
- data/lib/action_view/record_identifier.rb +53 -26
- data/lib/action_view/render_parser.rb +188 -0
- data/lib/action_view/renderer/abstract_renderer.rb +152 -15
- 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 +51 -333
- data/lib/action_view/renderer/renderer.rb +68 -11
- data/lib/action_view/renderer/streaming_template_renderer.rb +60 -56
- data/lib/action_view/renderer/template_renderer.rb +87 -74
- data/lib/action_view/rendering.rb +73 -47
- data/lib/action_view/ripper_ast_parser.rb +198 -0
- data/lib/action_view/routing_url_for.rb +35 -24
- data/lib/action_view/tasks/cache_digests.rake +25 -0
- data/lib/action_view/template/error.rb +151 -41
- 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 +29 -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 +14 -10
- data/lib/action_view/template/html.rb +12 -13
- 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 +139 -300
- 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 +10 -12
- data/lib/action_view/template/types.rb +28 -26
- data/lib/action_view/template.rb +123 -91
- data/lib/action_view/template_details.rb +66 -0
- data/lib/action_view/template_path.rb +64 -0
- data/lib/action_view/test_case.rb +70 -53
- data/lib/action_view/testing/resolvers.rb +25 -35
- data/lib/action_view/unbound_template.rb +57 -0
- data/lib/action_view/version.rb +3 -1
- data/lib/action_view/view_paths.rb +73 -58
- data/lib/action_view.rb +16 -11
- data/lib/assets/compiled/rails-ujs.js +746 -0
- metadata +52 -32
- data/lib/action_view/helpers/record_tag_helper.rb +0 -108
- data/lib/action_view/tasks/dependencies.rake +0 -23
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,60 @@ 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 :
|
117
|
+
singleton_class.attr_accessor :frozen_string_literal
|
118
|
+
@frozen_string_literal = false
|
101
119
|
|
102
|
-
attr_reader :
|
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))
|
120
|
+
attr_reader :identifier, :handler
|
121
|
+
attr_reader :variable, :format, :variant, :locals, :virtual_path
|
116
122
|
|
123
|
+
def initialize(source, identifier, handler, locals:, format: nil, variant: nil, virtual_path: nil)
|
117
124
|
@source = source
|
118
125
|
@identifier = identifier
|
119
126
|
@handler = handler
|
120
127
|
@compiled = false
|
121
|
-
@
|
122
|
-
@
|
123
|
-
|
124
|
-
@
|
125
|
-
|
126
|
-
|
128
|
+
@locals = locals
|
129
|
+
@virtual_path = virtual_path
|
130
|
+
|
131
|
+
@variable = if @virtual_path
|
132
|
+
base = @virtual_path.end_with?("/") ? "" : ::File.basename(@virtual_path)
|
133
|
+
base =~ /\A_?(.*?)(?:\.\w+)*\z/
|
134
|
+
$1.to_sym
|
135
|
+
end
|
136
|
+
|
137
|
+
@format = format
|
138
|
+
@variant = variant
|
127
139
|
@compile_mutex = Mutex.new
|
128
140
|
end
|
129
141
|
|
130
|
-
# Returns
|
131
|
-
# a streaming buffer *may* be passed when it
|
142
|
+
# Returns whether the underlying handler supports streaming. If so,
|
143
|
+
# a streaming buffer *may* be passed when it starts rendering.
|
132
144
|
def supports_streaming?
|
133
145
|
handler.respond_to?(:supports_streaming?) && handler.supports_streaming?
|
134
146
|
end
|
@@ -139,40 +151,29 @@ module ActionView
|
|
139
151
|
# This method is instrumented as "!render_template.action_view". Notice that
|
140
152
|
# we use a bang in this instrumentation because you don't want to
|
141
153
|
# consume this in production. This is only slow if it's being listened to.
|
142
|
-
def render(view, locals, buffer=
|
143
|
-
|
154
|
+
def render(view, locals, buffer = ActionView::OutputBuffer.new, add_to_stack: true, &block)
|
155
|
+
instrument_render_template do
|
144
156
|
compile!(view)
|
145
|
-
view.
|
157
|
+
view._run(method_name, self, locals, buffer, add_to_stack: add_to_stack, &block)
|
146
158
|
end
|
147
159
|
rescue => e
|
148
160
|
handle_render_error(view, e)
|
149
161
|
end
|
150
162
|
|
151
163
|
def type
|
152
|
-
@type ||= Types[
|
164
|
+
@type ||= Types[format]
|
153
165
|
end
|
154
166
|
|
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
|
167
|
+
def short_identifier
|
168
|
+
@short_identifier ||= defined?(Rails.root) ? identifier.delete_prefix("#{Rails.root}/") : identifier
|
172
169
|
end
|
173
170
|
|
174
171
|
def inspect
|
175
|
-
|
172
|
+
"#<#{self.class.name} #{short_identifier} locals=#{@locals.inspect}>"
|
173
|
+
end
|
174
|
+
|
175
|
+
def source
|
176
|
+
@source.to_s
|
176
177
|
end
|
177
178
|
|
178
179
|
# This method is responsible for properly setting the encoding of the
|
@@ -186,12 +187,14 @@ module ActionView
|
|
186
187
|
# before passing the source on to the template engine, leaving a
|
187
188
|
# blank line in its stead.
|
188
189
|
def encode!
|
189
|
-
|
190
|
+
source = self.source
|
191
|
+
|
192
|
+
return source unless source.encoding == Encoding::BINARY
|
190
193
|
|
191
194
|
# Look for # encoding: *. If we find one, we'll encode the
|
192
195
|
# String in that encoding, otherwise, we'll use the
|
193
196
|
# default external encoding.
|
194
|
-
if source.sub!(/\A#{ENCODING_FLAG}/,
|
197
|
+
if source.sub!(/\A#{ENCODING_FLAG}/, "")
|
195
198
|
encoding = magic_encoding = $1
|
196
199
|
else
|
197
200
|
encoding = Encoding.default_external
|
@@ -219,11 +222,23 @@ module ActionView
|
|
219
222
|
end
|
220
223
|
end
|
221
224
|
|
222
|
-
protected
|
223
225
|
|
226
|
+
# Exceptions are marshalled when using the parallel test runner with DRb, so we need
|
227
|
+
# to ensure that references to the template object can be marshalled as well. This means forgoing
|
228
|
+
# the marshalling of the compiler mutex and instantiating that again on unmarshalling.
|
229
|
+
def marshal_dump # :nodoc:
|
230
|
+
[ @source, @identifier, @handler, @compiled, @locals, @virtual_path, @format, @variant ]
|
231
|
+
end
|
232
|
+
|
233
|
+
def marshal_load(array) # :nodoc:
|
234
|
+
@source, @identifier, @handler, @compiled, @locals, @virtual_path, @format, @variant = *array
|
235
|
+
@compile_mutex = Mutex.new
|
236
|
+
end
|
237
|
+
|
238
|
+
private
|
224
239
|
# Compile a template. This method ensures a template is compiled
|
225
240
|
# just once and removes the source after it is compiled.
|
226
|
-
def compile!(view)
|
241
|
+
def compile!(view)
|
227
242
|
return if @compiled
|
228
243
|
|
229
244
|
# Templates can be used concurrently in threaded environments
|
@@ -235,19 +250,12 @@ module ActionView
|
|
235
250
|
# re-compilation
|
236
251
|
return if @compiled
|
237
252
|
|
238
|
-
|
239
|
-
mod = ActionView::CompiledTemplates
|
240
|
-
else
|
241
|
-
mod = view.singleton_class
|
242
|
-
end
|
253
|
+
mod = view.compiled_method_container
|
243
254
|
|
244
255
|
instrument("!compile_template") do
|
245
256
|
compile(mod)
|
246
257
|
end
|
247
258
|
|
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
259
|
@compiled = true
|
252
260
|
end
|
253
261
|
end
|
@@ -264,18 +272,16 @@ module ActionView
|
|
264
272
|
# encode the source into <tt>Encoding.default_internal</tt>.
|
265
273
|
# In general, this means that templates will be UTF-8 inside of Rails,
|
266
274
|
# regardless of the original source encoding.
|
267
|
-
def compile(mod)
|
268
|
-
encode!
|
269
|
-
|
270
|
-
code = @handler.call(self)
|
275
|
+
def compile(mod)
|
276
|
+
source = encode!
|
277
|
+
code = @handler.call(self, source)
|
271
278
|
|
272
279
|
# Make sure that the resulting String to be eval'd is in the
|
273
280
|
# encoding of the code
|
274
|
-
|
281
|
+
original_source = source
|
282
|
+
source = +<<-end_src
|
275
283
|
def #{method_name}(local_assigns, output_buffer)
|
276
|
-
|
277
|
-
ensure
|
278
|
-
@virtual_path, @output_buffer = _old_virtual_path, _old_output_buffer
|
284
|
+
@virtual_path = #{@virtual_path.inspect};#{locals_code};#{code}
|
279
285
|
end
|
280
286
|
end_src
|
281
287
|
|
@@ -290,47 +296,73 @@ module ActionView
|
|
290
296
|
# handler is valid in the default_internal. This is for handlers
|
291
297
|
# that handle encoding but screw up
|
292
298
|
unless source.valid_encoding?
|
293
|
-
raise WrongEncodingError.new(
|
299
|
+
raise WrongEncodingError.new(source, Encoding.default_internal)
|
294
300
|
end
|
295
301
|
|
296
|
-
|
297
|
-
|
302
|
+
begin
|
303
|
+
if Template.frozen_string_literal
|
304
|
+
mod.module_eval("# frozen_string_literal: true\n#{source}", identifier, -1)
|
305
|
+
else
|
306
|
+
mod.module_eval(source, identifier, 0)
|
307
|
+
end
|
308
|
+
rescue SyntaxError
|
309
|
+
# Account for when code in the template is not syntactically valid; e.g. if we're using
|
310
|
+
# ERB and the user writes <%= foo( %>, attempting to call a helper `foo` and interpolate
|
311
|
+
# the result into the template, but missing an end parenthesis.
|
312
|
+
raise SyntaxErrorInTemplate.new(self, original_source)
|
313
|
+
end
|
298
314
|
end
|
299
315
|
|
300
|
-
def handle_render_error(view, e)
|
316
|
+
def handle_render_error(view, e)
|
301
317
|
if e.is_a?(Template::Error)
|
302
318
|
e.sub_template_of(self)
|
303
319
|
raise e
|
304
320
|
else
|
305
|
-
|
306
|
-
unless template.source
|
307
|
-
template = refresh(view)
|
308
|
-
template.encode!
|
309
|
-
end
|
310
|
-
raise Template::Error.new(template, e)
|
321
|
+
raise Template::Error.new(self)
|
311
322
|
end
|
312
323
|
end
|
313
324
|
|
314
|
-
def locals_code
|
315
|
-
#
|
316
|
-
|
325
|
+
def locals_code
|
326
|
+
# Only locals with valid variable names get set directly. Others will
|
327
|
+
# still be available in local_assigns.
|
328
|
+
locals = @locals - Module::RUBY_RESERVED_KEYWORDS
|
329
|
+
deprecated_locals = locals.grep(/\A@+/)
|
330
|
+
if deprecated_locals.any?
|
331
|
+
ActiveSupport::Deprecation.warn(<<~MSG)
|
332
|
+
Passing instance variables to `render` is deprecated.
|
333
|
+
In Rails 7.1, #{deprecated_locals.to_sentence} will be ignored.
|
334
|
+
MSG
|
335
|
+
locals = locals.grep(/\A@?(?![A-Z0-9])(?:[[:alnum:]_]|[^\0-\177])+\z/)
|
336
|
+
else
|
337
|
+
locals = locals.grep(/\A(?![A-Z0-9])(?:[[:alnum:]_]|[^\0-\177])+\z/)
|
338
|
+
end
|
339
|
+
|
340
|
+
# Assign for the same variable is to suppress unused variable warning
|
341
|
+
locals.each_with_object(+"") { |key, code| code << "#{key} = local_assigns[:#{key}]; #{key} = #{key};" }
|
317
342
|
end
|
318
343
|
|
319
|
-
def method_name
|
344
|
+
def method_name
|
320
345
|
@method_name ||= begin
|
321
|
-
m = "_#{identifier_method_name}__#{@identifier.hash}_#{__id__}"
|
322
|
-
m.tr!(
|
346
|
+
m = +"_#{identifier_method_name}__#{@identifier.hash}_#{__id__}"
|
347
|
+
m.tr!("-", "_")
|
323
348
|
m
|
324
349
|
end
|
325
350
|
end
|
326
351
|
|
327
|
-
def identifier_method_name
|
328
|
-
|
352
|
+
def identifier_method_name
|
353
|
+
short_identifier.tr("^a-z_", "_")
|
354
|
+
end
|
355
|
+
|
356
|
+
def instrument(action, &block) # :doc:
|
357
|
+
ActiveSupport::Notifications.instrument("#{action}.action_view", instrument_payload, &block)
|
358
|
+
end
|
359
|
+
|
360
|
+
def instrument_render_template(&block)
|
361
|
+
ActiveSupport::Notifications.instrument("!render_template.action_view", instrument_payload, &block)
|
329
362
|
end
|
330
363
|
|
331
|
-
def
|
332
|
-
|
333
|
-
ActiveSupport::Notifications.instrument("#{action}.action_view", payload, &block)
|
364
|
+
def instrument_payload
|
365
|
+
{ virtual_path: @virtual_path, identifier: @identifier }
|
334
366
|
end
|
335
367
|
end
|
336
368
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionView
|
4
|
+
class TemplateDetails # :nodoc:
|
5
|
+
class Requested
|
6
|
+
attr_reader :locale, :handlers, :formats, :variants
|
7
|
+
attr_reader :locale_idx, :handlers_idx, :formats_idx, :variants_idx
|
8
|
+
|
9
|
+
ANY_HASH = Hash.new(1).merge(nil => 0).freeze
|
10
|
+
|
11
|
+
def initialize(locale:, handlers:, formats:, variants:)
|
12
|
+
@locale = locale
|
13
|
+
@handlers = handlers
|
14
|
+
@formats = formats
|
15
|
+
@variants = variants
|
16
|
+
|
17
|
+
@locale_idx = build_idx_hash(locale)
|
18
|
+
@handlers_idx = build_idx_hash(handlers)
|
19
|
+
@formats_idx = build_idx_hash(formats)
|
20
|
+
if variants == :any
|
21
|
+
@variants_idx = ANY_HASH
|
22
|
+
else
|
23
|
+
@variants_idx = build_idx_hash(variants)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
def build_idx_hash(arr)
|
29
|
+
[*arr, nil].each_with_index.to_h.freeze
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
attr_reader :locale, :handler, :format, :variant
|
34
|
+
|
35
|
+
def initialize(locale, handler, format, variant)
|
36
|
+
@locale = locale
|
37
|
+
@handler = handler
|
38
|
+
@format = format
|
39
|
+
@variant = variant
|
40
|
+
end
|
41
|
+
|
42
|
+
def matches?(requested)
|
43
|
+
requested.formats_idx[@format] &&
|
44
|
+
requested.locale_idx[@locale] &&
|
45
|
+
requested.variants_idx[@variant] &&
|
46
|
+
requested.handlers_idx[@handler]
|
47
|
+
end
|
48
|
+
|
49
|
+
def sort_key_for(requested)
|
50
|
+
[
|
51
|
+
requested.formats_idx[@format],
|
52
|
+
requested.locale_idx[@locale],
|
53
|
+
requested.variants_idx[@variant],
|
54
|
+
requested.handlers_idx[@handler]
|
55
|
+
]
|
56
|
+
end
|
57
|
+
|
58
|
+
def handler_class
|
59
|
+
Template.handler_for_extension(handler)
|
60
|
+
end
|
61
|
+
|
62
|
+
def format_or_default
|
63
|
+
format || handler_class.try(:default_format)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionView
|
4
|
+
# Represents a template path within ActionView's lookup and rendering system,
|
5
|
+
# like "users/show"
|
6
|
+
#
|
7
|
+
# TemplatePath makes it convenient to convert between separate name, prefix,
|
8
|
+
# partial arguments and the virtual path.
|
9
|
+
class TemplatePath
|
10
|
+
attr_reader :name, :prefix, :partial, :virtual
|
11
|
+
alias_method :partial?, :partial
|
12
|
+
alias_method :virtual_path, :virtual
|
13
|
+
|
14
|
+
# Convert name, prefix, and partial into a virtual path string
|
15
|
+
def self.virtual(name, prefix, partial)
|
16
|
+
if prefix.empty?
|
17
|
+
"#{partial ? "_" : ""}#{name}"
|
18
|
+
elsif partial
|
19
|
+
"#{prefix}/_#{name}"
|
20
|
+
else
|
21
|
+
"#{prefix}/#{name}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Build a TemplatePath form a virtual path
|
26
|
+
def self.parse(virtual)
|
27
|
+
if nameidx = virtual.rindex("/")
|
28
|
+
prefix = virtual[0, nameidx]
|
29
|
+
name = virtual.from(nameidx + 1)
|
30
|
+
prefix = prefix[1..] if prefix.start_with?("/")
|
31
|
+
else
|
32
|
+
prefix = ""
|
33
|
+
name = virtual
|
34
|
+
end
|
35
|
+
partial = name.start_with?("_")
|
36
|
+
name = name[1..] if partial
|
37
|
+
new name, prefix, partial, virtual
|
38
|
+
end
|
39
|
+
|
40
|
+
# Convert name, prefix, and partial into a TemplatePath
|
41
|
+
def self.build(name, prefix, partial)
|
42
|
+
new name, prefix, partial, virtual(name, prefix, partial)
|
43
|
+
end
|
44
|
+
|
45
|
+
def initialize(name, prefix, partial, virtual)
|
46
|
+
@name = name
|
47
|
+
@prefix = prefix
|
48
|
+
@partial = partial
|
49
|
+
@virtual = virtual
|
50
|
+
end
|
51
|
+
|
52
|
+
alias :to_str :virtual
|
53
|
+
alias :to_s :virtual
|
54
|
+
|
55
|
+
def hash # :nodoc:
|
56
|
+
@virtual.hash
|
57
|
+
end
|
58
|
+
|
59
|
+
def eql?(other) # :nodoc:
|
60
|
+
@virtual == other.virtual
|
61
|
+
end
|
62
|
+
alias :== :eql? # :nodoc:
|
63
|
+
end
|
64
|
+
end
|