actionview 5.2.8.1 → 6.0.0.beta2

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.

Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +121 -152
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/action_view/base.rb +107 -10
  6. data/lib/action_view/buffers.rb +15 -0
  7. data/lib/action_view/context.rb +5 -9
  8. data/lib/action_view/digestor.rb +8 -11
  9. data/lib/action_view/file_template.rb +33 -0
  10. data/lib/action_view/gem_version.rb +4 -4
  11. data/lib/action_view/helpers/asset_tag_helper.rb +7 -30
  12. data/lib/action_view/helpers/asset_url_helper.rb +4 -3
  13. data/lib/action_view/helpers/cache_helper.rb +18 -10
  14. data/lib/action_view/helpers/capture_helper.rb +4 -0
  15. data/lib/action_view/helpers/csp_helper.rb +4 -2
  16. data/lib/action_view/helpers/csrf_helper.rb +1 -1
  17. data/lib/action_view/helpers/date_helper.rb +69 -25
  18. data/lib/action_view/helpers/form_helper.rb +240 -8
  19. data/lib/action_view/helpers/form_options_helper.rb +23 -15
  20. data/lib/action_view/helpers/form_tag_helper.rb +9 -9
  21. data/lib/action_view/helpers/javascript_helper.rb +10 -11
  22. data/lib/action_view/helpers/number_helper.rb +5 -0
  23. data/lib/action_view/helpers/rendering_helper.rb +6 -4
  24. data/lib/action_view/helpers/sanitize_helper.rb +3 -3
  25. data/lib/action_view/helpers/tag_helper.rb +13 -43
  26. data/lib/action_view/helpers/tags/base.rb +9 -5
  27. data/lib/action_view/helpers/tags/color_field.rb +1 -1
  28. data/lib/action_view/helpers/tags/translator.rb +1 -6
  29. data/lib/action_view/helpers/text_helper.rb +3 -3
  30. data/lib/action_view/helpers/translation_helper.rb +12 -19
  31. data/lib/action_view/helpers/url_helper.rb +14 -14
  32. data/lib/action_view/helpers.rb +0 -2
  33. data/lib/action_view/layouts.rb +5 -5
  34. data/lib/action_view/log_subscriber.rb +6 -6
  35. data/lib/action_view/lookup_context.rb +63 -28
  36. data/lib/action_view/railtie.rb +23 -0
  37. data/lib/action_view/record_identifier.rb +2 -2
  38. data/lib/action_view/renderer/abstract_renderer.rb +56 -3
  39. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +49 -10
  40. data/lib/action_view/renderer/partial_renderer.rb +66 -52
  41. data/lib/action_view/renderer/renderer.rb +16 -4
  42. data/lib/action_view/renderer/streaming_template_renderer.rb +4 -4
  43. data/lib/action_view/renderer/template_renderer.rb +18 -18
  44. data/lib/action_view/rendering.rb +49 -30
  45. data/lib/action_view/routing_url_for.rb +12 -11
  46. data/lib/action_view/template/handlers/builder.rb +2 -2
  47. data/lib/action_view/template/handlers/erb/erubi.rb +7 -3
  48. data/lib/action_view/template/handlers/erb.rb +17 -7
  49. data/lib/action_view/template/handlers/html.rb +1 -1
  50. data/lib/action_view/template/handlers/raw.rb +2 -2
  51. data/lib/action_view/template/handlers.rb +27 -1
  52. data/lib/action_view/template/html.rb +14 -5
  53. data/lib/action_view/template/inline.rb +22 -0
  54. data/lib/action_view/template/resolver.rb +70 -23
  55. data/lib/action_view/template/text.rb +5 -3
  56. data/lib/action_view/template.rb +75 -36
  57. data/lib/action_view/test_case.rb +1 -1
  58. data/lib/action_view/testing/resolvers.rb +7 -5
  59. data/lib/action_view/view_paths.rb +25 -1
  60. data/lib/action_view.rb +2 -2
  61. data/lib/assets/compiled/rails-ujs.js +39 -22
  62. metadata +19 -18
  63. data/lib/action_view/helpers/record_tag_helper.rb +0 -23
@@ -26,6 +26,13 @@ module ActionView
26
26
  extend ActiveSupport::Concern
27
27
  include ActionView::ViewPaths
28
28
 
29
+ attr_reader :rendered_format
30
+
31
+ def initialize
32
+ @rendered_format = nil
33
+ super
34
+ end
35
+
29
36
  # Overwrite process to setup I18n proxy.
30
37
  def process(*) #:nodoc:
31
38
  old_config, I18n.config = I18n.config, I18nProxy.new(I18n.config, lookup_context)
@@ -35,47 +42,59 @@ module ActionView
35
42
  end
36
43
 
37
44
  module ClassMethods
38
- def view_context_class
39
- @view_context_class ||= begin
40
- supports_path = supports_path?
41
- routes = respond_to?(:_routes) && _routes
42
- helpers = respond_to?(:_helpers) && _helpers
43
-
44
- Class.new(ActionView::Base) do
45
- if routes
46
- include routes.url_helpers(supports_path)
47
- include routes.mounted_helpers
48
- end
49
-
50
- if helpers
51
- include helpers
52
- end
45
+ def _routes
46
+ end
47
+
48
+ def _helpers
49
+ end
50
+
51
+ def build_view_context_class(klass, supports_path, routes, helpers)
52
+ Class.new(klass) do
53
+ if routes
54
+ include routes.url_helpers(supports_path)
55
+ include routes.mounted_helpers
56
+ end
57
+
58
+ if helpers
59
+ include helpers
53
60
  end
54
61
  end
55
62
  end
56
- end
57
63
 
58
- attr_internal_writer :view_context_class
64
+ def view_context_class
65
+ klass = ActionView::LookupContext::DetailsKey.view_context_class(ActionView::Base)
66
+
67
+ @view_context_class ||= build_view_context_class(klass, supports_path?, _routes, _helpers)
68
+
69
+ if klass.changed?(@view_context_class)
70
+ @view_context_class = build_view_context_class(klass, supports_path?, _routes, _helpers)
71
+ end
72
+
73
+ @view_context_class
74
+ end
75
+ end
59
76
 
60
77
  def view_context_class
61
- @_view_context_class ||= self.class.view_context_class
78
+ self.class.view_context_class
62
79
  end
63
80
 
64
81
  # An instance of a view class. The default view class is ActionView::Base.
65
82
  #
66
83
  # The view class must have the following methods:
67
- # View.new[lookup_context, assigns, controller]
68
- # Create a new ActionView instance for a controller and we can also pass the arguments.
69
- # View#render(option)
70
- # Returns String with the rendered template
84
+ #
85
+ # * <tt>View.new(lookup_context, assigns, controller)</tt> Create a new
86
+ # ActionView instance for a controller and we can also pass the arguments.
87
+ #
88
+ # * <tt>View#render(option)</tt> — Returns String with the rendered template.
71
89
  #
72
90
  # Override this method in a module to change the default behavior.
73
91
  def view_context
74
- view_context_class.new(view_renderer, view_assigns, self)
92
+ view_context_class.new(lookup_context, view_assigns, self)
75
93
  end
76
94
 
77
95
  # Returns an object that is able to render templates.
78
96
  def view_renderer # :nodoc:
97
+ # Lifespan: Per controller
79
98
  @_view_renderer ||= ActionView::Renderer.new(lookup_context)
80
99
  end
81
100
 
@@ -84,10 +103,6 @@ module ActionView
84
103
  _render_template(options)
85
104
  end
86
105
 
87
- def rendered_format
88
- Template::Types[lookup_context.rendered_format]
89
- end
90
-
91
106
  private
92
107
 
93
108
  # Find and render a template based on the options given.
@@ -97,17 +112,21 @@ module ActionView
97
112
  context = view_context
98
113
 
99
114
  context.assign assigns if assigns
100
- lookup_context.rendered_format = nil if options[:formats]
101
115
  lookup_context.variants = variant if variant
102
116
 
103
- view_renderer.render(context, options)
117
+ rendered_template = context.in_rendering_context(options) do |renderer|
118
+ renderer.render_to_object(context, options)
119
+ end
120
+
121
+ @rendered_format = Template::Types[rendered_template.format]
122
+
123
+ rendered_template.body
104
124
  end
105
125
 
106
126
  # Assign the rendered format to look up context.
107
127
  def _process_format(format)
108
128
  super
109
129
  lookup_context.formats = [format.to_sym]
110
- lookup_context.rendered_format = lookup_context.formats.first
111
130
  end
112
131
 
113
132
  # Normalize args by converting render "foo" to render :action => "foo" and
@@ -84,25 +84,24 @@ module ActionView
84
84
  super(only_path: _generate_paths_by_default)
85
85
  when Hash
86
86
  options = options.symbolize_keys
87
- unless options.key?(:only_path)
88
- options[:only_path] = only_path?(options[:host])
89
- end
87
+ ensure_only_path_option(options)
90
88
 
91
89
  super(options)
92
90
  when ActionController::Parameters
93
- unless options.key?(:only_path)
94
- options[:only_path] = only_path?(options[:host])
95
- end
91
+ ensure_only_path_option(options)
96
92
 
97
93
  super(options)
98
94
  when :back
99
95
  _back_url
100
96
  when Array
101
97
  components = options.dup
102
- if _generate_paths_by_default
103
- polymorphic_path(components, components.extract_options!)
98
+ options = components.extract_options!
99
+ ensure_only_path_option(options)
100
+
101
+ if options[:only_path]
102
+ polymorphic_path(components, options)
104
103
  else
105
- polymorphic_url(components, components.extract_options!)
104
+ polymorphic_url(components, options)
106
105
  end
107
106
  else
108
107
  method = _generate_paths_by_default ? :path : :url
@@ -138,8 +137,10 @@ module ActionView
138
137
  true
139
138
  end
140
139
 
141
- def only_path?(host)
142
- _generate_paths_by_default unless host
140
+ def ensure_only_path_option(options)
141
+ unless options.key?(:only_path)
142
+ options[:only_path] = _generate_paths_by_default unless options[:host]
143
+ end
143
144
  end
144
145
  end
145
146
  end
@@ -5,11 +5,11 @@ module ActionView
5
5
  class Builder
6
6
  class_attribute :default_format, default: :xml
7
7
 
8
- def call(template)
8
+ def call(template, source)
9
9
  require_engine
10
10
  "xml = ::Builder::XmlMarkup.new(:indent => 2);" \
11
11
  "self.output_buffer = xml.target!;" +
12
- template.source +
12
+ source +
13
13
  ";xml.target!;"
14
14
  end
15
15
 
@@ -13,7 +13,7 @@ module ActionView
13
13
 
14
14
  # Dup properties so that we don't modify argument
15
15
  properties = Hash[properties]
16
- properties[:preamble] = "@output_buffer = output_buffer || ActionView::OutputBuffer.new;"
16
+ properties[:preamble] = ""
17
17
  properties[:postamble] = "@output_buffer.to_s"
18
18
  properties[:bufvar] = "@output_buffer"
19
19
  properties[:escapefunc] = ""
@@ -22,8 +22,12 @@ module ActionView
22
22
  end
23
23
 
24
24
  def evaluate(action_view_erb_handler_context)
25
- pr = eval("proc { #{@src} }", binding, @filename || "(erubi)")
26
- action_view_erb_handler_context.instance_eval(&pr)
25
+ src = @src
26
+ view = Class.new(ActionView::Base) {
27
+ include action_view_erb_handler_context._routes.url_helpers
28
+ class_eval("define_method(:_template) { |local_assigns, output_buffer| #{src} }", @filename || "(erubi)", 0)
29
+ }.empty
30
+ view.run(:_template, nil, {}, ActionView::OutputBuffer.new)
27
31
  end
28
32
 
29
33
  private
@@ -14,12 +14,22 @@ module ActionView
14
14
  class_attribute :erb_implementation, default: Erubi
15
15
 
16
16
  # Do not escape templates of these mime types.
17
- class_attribute :escape_whitelist, default: ["text/plain"]
17
+ class_attribute :escape_ignore_list, default: ["text/plain"]
18
+
19
+ [self, singleton_class].each do |base|
20
+ base.alias_method :escape_whitelist, :escape_ignore_list
21
+ base.alias_method :escape_whitelist=, :escape_ignore_list=
22
+
23
+ base.deprecate(
24
+ escape_whitelist: "use #escape_ignore_list instead",
25
+ :escape_whitelist= => "use #escape_ignore_list= instead"
26
+ )
27
+ end
18
28
 
19
29
  ENCODING_TAG = Regexp.new("\\A(<%#{ENCODING_FLAG}-?%>)[ \\t]*")
20
30
 
21
- def self.call(template)
22
- new.call(template)
31
+ def self.call(template, source)
32
+ new.call(template, source)
23
33
  end
24
34
 
25
35
  def supports_streaming?
@@ -30,24 +40,24 @@ module ActionView
30
40
  true
31
41
  end
32
42
 
33
- def call(template)
43
+ def call(template, source)
34
44
  # First, convert to BINARY, so in case the encoding is
35
45
  # wrong, we can still find an encoding tag
36
46
  # (<%# encoding %>) inside the String using a regular
37
47
  # expression
38
- template_source = template.source.dup.force_encoding(Encoding::ASCII_8BIT)
48
+ template_source = source.dup.force_encoding(Encoding::ASCII_8BIT)
39
49
 
40
50
  erb = template_source.gsub(ENCODING_TAG, "")
41
51
  encoding = $2
42
52
 
43
- erb.force_encoding valid_encoding(template.source.dup, encoding)
53
+ erb.force_encoding valid_encoding(source.dup, encoding)
44
54
 
45
55
  # Always make sure we return a String in the default_internal
46
56
  erb.encode!
47
57
 
48
58
  self.class.erb_implementation.new(
49
59
  erb,
50
- escape: (self.class.escape_whitelist.include? template.type),
60
+ escape: (self.class.escape_ignore_list.include? template.type),
51
61
  trim: (self.class.erb_trim_mode == "-")
52
62
  ).src
53
63
  end
@@ -3,7 +3,7 @@
3
3
  module ActionView
4
4
  module Template::Handlers
5
5
  class Html < Raw
6
- def call(template)
6
+ def call(template, source)
7
7
  "ActionView::OutputBuffer.new #{super}"
8
8
  end
9
9
  end
@@ -3,8 +3,8 @@
3
3
  module ActionView
4
4
  module Template::Handlers
5
5
  class Raw
6
- def call(template)
7
- "#{template.source.inspect}.html_safe;"
6
+ def call(template, source)
7
+ "#{source.inspect}.html_safe;"
8
8
  end
9
9
  end
10
10
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/deprecation"
4
+
3
5
  module ActionView #:nodoc:
4
6
  # = Action View Template Handlers
5
7
  class Template #:nodoc:
@@ -14,7 +16,7 @@ module ActionView #:nodoc:
14
16
  base.register_template_handler :erb, ERB.new
15
17
  base.register_template_handler :html, Html.new
16
18
  base.register_template_handler :builder, Builder.new
17
- base.register_template_handler :ruby, :source.to_proc
19
+ base.register_template_handler :ruby, lambda { |_, source| source }
18
20
  end
19
21
 
20
22
  @@template_handlers = {}
@@ -24,11 +26,35 @@ module ActionView #:nodoc:
24
26
  @@template_extensions ||= @@template_handlers.keys
25
27
  end
26
28
 
29
+ class LegacyHandlerWrapper < SimpleDelegator # :nodoc:
30
+ def call(view, source)
31
+ __getobj__.call(ActionView::Template::LegacyTemplate.new(view, source))
32
+ end
33
+ end
34
+
27
35
  # Register an object that knows how to handle template files with the given
28
36
  # extensions. This can be used to implement new template types.
29
37
  # The handler must respond to +:call+, which will be passed the template
30
38
  # and should return the rendered template as a String.
31
39
  def register_template_handler(*extensions, handler)
40
+ params = if handler.is_a?(Proc)
41
+ handler.parameters
42
+ else
43
+ handler.method(:call).parameters
44
+ end
45
+
46
+ unless params.find_all { |type, _| type == :req || type == :opt }.length >= 2
47
+ ActiveSupport::Deprecation.warn <<~eowarn
48
+ Single arity template handlers are deprecated. Template handlers must
49
+ now accept two parameters, the view object and the source for the view object.
50
+ Change:
51
+ >> #{handler.class}#call(#{params.map(&:last).join(", ")})
52
+ To:
53
+ >> #{handler.class}#call(#{params.map(&:last).join(", ")}, source)
54
+ eowarn
55
+ handler = LegacyHandlerWrapper.new(handler)
56
+ end
57
+
32
58
  raise(ArgumentError, "Extension is required") if extensions.empty?
33
59
  extensions.each do |extension|
34
60
  @@template_handlers[extension.to_sym] = handler
@@ -1,15 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/deprecation"
4
+
3
5
  module ActionView #:nodoc:
4
6
  # = Action View HTML Template
5
7
  class Template #:nodoc:
6
8
  class HTML #:nodoc:
7
- attr_accessor :type
9
+ attr_reader :type
8
10
 
9
11
  def initialize(string, type = nil)
12
+ unless type
13
+ ActiveSupport::Deprecation.warn "ActionView::Template::HTML#initialize requires a type parameter"
14
+ type = :html
15
+ end
16
+
10
17
  @string = string.to_s
11
- @type = Types[type] || type if type
12
- @type ||= Types[:html]
18
+ @type = type
13
19
  end
14
20
 
15
21
  def identifier
@@ -26,9 +32,12 @@ module ActionView #:nodoc:
26
32
  to_str
27
33
  end
28
34
 
29
- def formats
30
- [@type.respond_to?(:ref) ? @type.ref : @type.to_s]
35
+ def format
36
+ @type
31
37
  end
38
+
39
+ def formats; Array(format); end
40
+ deprecate :formats
32
41
  end
33
42
  end
34
43
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionView #:nodoc:
4
+ class Template #:nodoc:
5
+ class Inline < Template #:nodoc:
6
+ # This finalizer is needed (and exactly with a proc inside another proc)
7
+ # otherwise templates leak in development.
8
+ Finalizer = proc do |method_name, mod| # :nodoc:
9
+ proc do
10
+ mod.module_eval do
11
+ remove_possible_method method_name
12
+ end
13
+ end
14
+ end
15
+
16
+ def compile(mod)
17
+ super
18
+ ObjectSpace.define_finalizer(self, Finalizer[method_name, mod])
19
+ end
20
+ end
21
+ end
22
+ end
@@ -16,7 +16,7 @@ module ActionView
16
16
  alias_method :partial?, :partial
17
17
 
18
18
  def self.build(name, prefix, partial)
19
- virtual = "".dup
19
+ virtual = +""
20
20
  virtual << "#{prefix}/" unless prefix.empty?
21
21
  virtual << (partial ? "_#{name}" : name)
22
22
  new name, prefix, partial, virtual
@@ -196,7 +196,6 @@ module ActionView
196
196
  cached = nil
197
197
  templates.each do |t|
198
198
  t.locals = locals
199
- t.formats = details[:formats] || [:html] if t.formats.empty?
200
199
  t.variants = details[:variants] || [] if t.variants.empty?
201
200
  t.virtual_path ||= (cached ||= build_path(*path_info))
202
201
  end
@@ -221,16 +220,13 @@ module ActionView
221
220
  end
222
221
 
223
222
  def query(path, details, formats, outside_app_allowed)
224
- query = build_query(path, details)
225
-
226
- template_paths = find_template_paths(query)
223
+ template_paths = find_template_paths_from_details(path, details)
227
224
  template_paths = reject_files_external_to_app(template_paths) unless outside_app_allowed
228
225
 
229
226
  template_paths.map do |template|
230
- handler, format, variant = extract_handler_and_format_and_variant(template)
231
- contents = File.binread(template)
227
+ handler, format, variant = extract_handler_and_format_and_variant(template, formats.first)
232
228
 
233
- Template.new(contents, File.expand_path(template), handler,
229
+ FileTemplate.new(File.expand_path(template), handler,
234
230
  virtual_path: path.virtual,
235
231
  format: format,
236
232
  variant: variant,
@@ -243,6 +239,11 @@ module ActionView
243
239
  files.reject { |filename| !inside_path?(@path, filename) }
244
240
  end
245
241
 
242
+ def find_template_paths_from_details(path, details)
243
+ query = build_query(path, details)
244
+ find_template_paths(query)
245
+ end
246
+
246
247
  def find_template_paths(query)
247
248
  Dir[query].uniq.reject do |filename|
248
249
  File.directory?(filename) ||
@@ -279,7 +280,7 @@ module ActionView
279
280
  end
280
281
 
281
282
  def escape_entry(entry)
282
- entry.gsub(/[*?{}\[\]]/, '\\\\\\&'.freeze)
283
+ entry.gsub(/[*?{}\[\]]/, '\\\\\\&')
283
284
  end
284
285
 
285
286
  # Returns the file mtime from the filesystem.
@@ -290,17 +291,26 @@ module ActionView
290
291
  # Extract handler, formats and variant from path. If a format cannot be found neither
291
292
  # from the path, or the handler, we should return the array of formats given
292
293
  # to the resolver.
293
- def extract_handler_and_format_and_variant(path)
294
- pieces = File.basename(path).split(".".freeze)
294
+ def extract_handler_and_format_and_variant(path, query_format)
295
+ pieces = File.basename(path).split(".")
295
296
  pieces.shift
296
297
 
297
298
  extension = pieces.pop
298
299
 
299
300
  handler = Template.handler_for_extension(extension)
300
301
  format, variant = pieces.last.split(EXTENSIONS[:variants], 2) if pieces.last
301
- format &&= Template::Types[format]
302
+ format = if format
303
+ Template::Types[format]&.ref
304
+ else
305
+ if handler.respond_to?(:default_format) # default_format can return nil
306
+ handler.default_format
307
+ else
308
+ query_format
309
+ end
310
+ end
302
311
 
303
- [handler, format, variant]
312
+ # Template::Types[format] and handler.default_format can return nil
313
+ [handler, format || query_format, variant]
304
314
  end
305
315
  end
306
316
 
@@ -362,19 +372,56 @@ module ActionView
362
372
 
363
373
  # An Optimized resolver for Rails' most common case.
364
374
  class OptimizedFileSystemResolver < FileSystemResolver #:nodoc:
365
- def build_query(path, details)
366
- query = escape_entry(File.join(@path, path))
375
+ private
367
376
 
368
- exts = EXTENSIONS.map do |ext, prefix|
369
- if ext == :variants && details[ext] == :any
370
- "{#{prefix}*,}"
371
- else
372
- "{#{details[ext].compact.uniq.map { |e| "#{prefix}#{e}," }.join}}"
377
+ def find_template_paths_from_details(path, details)
378
+ # Instead of checking for every possible path, as our other globs would
379
+ # do, scan the directory for files with the right prefix.
380
+ query = "#{escape_entry(File.join(@path, path))}*"
381
+
382
+ regex = build_regex(path, details)
383
+
384
+ Dir[query].uniq.reject do |filename|
385
+ # This regex match does double duty of finding only files which match
386
+ # details (instead of just matching the prefix) and also filtering for
387
+ # case-insensitive file systems.
388
+ !regex.match?(filename) ||
389
+ File.directory?(filename)
390
+ end.sort_by do |filename|
391
+ # Because we scanned the directory, instead of checking for files
392
+ # one-by-one, they will be returned in an arbitrary order.
393
+ # We can use the matches found by the regex and sort by their index in
394
+ # details.
395
+ match = filename.match(regex)
396
+ EXTENSIONS.keys.reverse.map do |ext|
397
+ if ext == :variants && details[ext] == :any
398
+ match[ext].nil? ? 0 : 1
399
+ elsif match[ext].nil?
400
+ # No match should be last
401
+ details[ext].length
402
+ else
403
+ found = match[ext].to_sym
404
+ details[ext].index(found)
405
+ end
406
+ end
373
407
  end
374
- end.join
408
+ end
375
409
 
376
- query + exts
377
- end
410
+ def build_regex(path, details)
411
+ query = escape_entry(File.join(@path, path))
412
+ exts = EXTENSIONS.map do |ext, prefix|
413
+ match =
414
+ if ext == :variants && details[ext] == :any
415
+ ".*?"
416
+ else
417
+ details[ext].compact.uniq.map { |e| Regexp.escape(e) }.join("|")
418
+ end
419
+ prefix = Regexp.escape(prefix)
420
+ "(#{prefix}(?<#{ext}>#{match}))?"
421
+ end.join
422
+
423
+ %r{\A#{query}#{exts}\z}
424
+ end
378
425
  end
379
426
 
380
427
  # The same as FileSystemResolver but does not allow templates to store
@@ -8,7 +8,6 @@ module ActionView #:nodoc:
8
8
 
9
9
  def initialize(string)
10
10
  @string = string.to_s
11
- @type = Types[:text]
12
11
  end
13
12
 
14
13
  def identifier
@@ -25,9 +24,12 @@ module ActionView #:nodoc:
25
24
  to_str
26
25
  end
27
26
 
28
- def formats
29
- [@type.ref]
27
+ def format
28
+ :text
30
29
  end
30
+
31
+ def formats; Array(format); end
32
+ deprecate :formats
31
33
  end
32
34
  end
33
35
  end