actionview 4.2.11.1 → 5.2.7

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 (108) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +108 -240
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -6
  5. data/lib/action_view/base.rb +38 -28
  6. data/lib/action_view/buffers.rb +3 -1
  7. data/lib/action_view/context.rb +3 -3
  8. data/lib/action_view/dependency_tracker.rb +54 -20
  9. data/lib/action_view/digestor.rb +94 -83
  10. data/lib/action_view/flows.rb +11 -11
  11. data/lib/action_view/gem_version.rb +5 -3
  12. data/lib/action_view/helpers/active_model_helper.rb +17 -11
  13. data/lib/action_view/helpers/asset_tag_helper.rb +244 -62
  14. data/lib/action_view/helpers/asset_url_helper.rb +170 -67
  15. data/lib/action_view/helpers/atom_feed_helper.rb +19 -17
  16. data/lib/action_view/helpers/cache_helper.rb +105 -42
  17. data/lib/action_view/helpers/capture_helper.rb +16 -13
  18. data/lib/action_view/helpers/controller_helper.rb +15 -4
  19. data/lib/action_view/helpers/csp_helper.rb +24 -0
  20. data/lib/action_view/helpers/csrf_helper.rb +7 -5
  21. data/lib/action_view/helpers/date_helper.rb +170 -112
  22. data/lib/action_view/helpers/debug_helper.rb +7 -6
  23. data/lib/action_view/helpers/form_helper.rb +521 -127
  24. data/lib/action_view/helpers/form_options_helper.rb +109 -63
  25. data/lib/action_view/helpers/form_tag_helper.rb +110 -67
  26. data/lib/action_view/helpers/javascript_helper.rb +27 -12
  27. data/lib/action_view/helpers/number_helper.rb +77 -58
  28. data/lib/action_view/helpers/output_safety_helper.rb +36 -4
  29. data/lib/action_view/helpers/record_tag_helper.rb +14 -99
  30. data/lib/action_view/helpers/rendering_helper.rb +6 -5
  31. data/lib/action_view/helpers/sanitize_helper.rb +20 -15
  32. data/lib/action_view/helpers/tag_helper.rb +198 -73
  33. data/lib/action_view/helpers/tags/base.rb +134 -97
  34. data/lib/action_view/helpers/tags/check_box.rb +20 -18
  35. data/lib/action_view/helpers/tags/checkable.rb +4 -2
  36. data/lib/action_view/helpers/tags/collection_check_boxes.rb +12 -33
  37. data/lib/action_view/helpers/tags/collection_helpers.rb +70 -36
  38. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +6 -11
  39. data/lib/action_view/helpers/tags/collection_select.rb +4 -2
  40. data/lib/action_view/helpers/tags/color_field.rb +3 -1
  41. data/lib/action_view/helpers/tags/date_field.rb +2 -0
  42. data/lib/action_view/helpers/tags/date_select.rb +38 -36
  43. data/lib/action_view/helpers/tags/datetime_field.rb +4 -2
  44. data/lib/action_view/helpers/tags/datetime_local_field.rb +2 -0
  45. data/lib/action_view/helpers/tags/datetime_select.rb +2 -0
  46. data/lib/action_view/helpers/tags/email_field.rb +2 -0
  47. data/lib/action_view/helpers/tags/file_field.rb +2 -0
  48. data/lib/action_view/helpers/tags/grouped_collection_select.rb +4 -2
  49. data/lib/action_view/helpers/tags/hidden_field.rb +2 -0
  50. data/lib/action_view/helpers/tags/label.rb +3 -1
  51. data/lib/action_view/helpers/tags/month_field.rb +2 -0
  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 -5
  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 -9
  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 -7
  62. data/lib/action_view/helpers/tags/time_field.rb +2 -0
  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 +17 -13
  66. data/lib/action_view/helpers/tags/url_field.rb +2 -0
  67. data/lib/action_view/helpers/tags/week_field.rb +2 -0
  68. data/lib/action_view/helpers/tags.rb +3 -1
  69. data/lib/action_view/helpers/text_helper.rb +55 -36
  70. data/lib/action_view/helpers/translation_helper.rb +74 -32
  71. data/lib/action_view/helpers/url_helper.rb +159 -104
  72. data/lib/action_view/helpers.rb +5 -1
  73. data/lib/action_view/layouts.rb +65 -58
  74. data/lib/action_view/log_subscriber.rb +60 -8
  75. data/lib/action_view/lookup_context.rb +80 -65
  76. data/lib/action_view/model_naming.rb +3 -1
  77. data/lib/action_view/path_set.rb +30 -19
  78. data/lib/action_view/railtie.rb +39 -6
  79. data/lib/action_view/record_identifier.rb +53 -25
  80. data/lib/action_view/renderer/abstract_renderer.rb +21 -15
  81. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +57 -0
  82. data/lib/action_view/renderer/partial_renderer.rb +218 -214
  83. data/lib/action_view/renderer/renderer.rb +8 -6
  84. data/lib/action_view/renderer/streaming_template_renderer.rb +50 -48
  85. data/lib/action_view/renderer/template_renderer.rb +67 -66
  86. data/lib/action_view/rendering.rb +19 -14
  87. data/lib/action_view/routing_url_for.rb +27 -17
  88. data/lib/action_view/tasks/cache_digests.rake +25 -0
  89. data/lib/action_view/template/error.rb +16 -16
  90. data/lib/action_view/template/handlers/builder.rb +10 -11
  91. data/lib/action_view/template/handlers/erb/erubi.rb +83 -0
  92. data/lib/action_view/template/handlers/erb.rb +9 -80
  93. data/lib/action_view/template/handlers/html.rb +11 -0
  94. data/lib/action_view/template/handlers/raw.rb +3 -3
  95. data/lib/action_view/template/handlers.rb +11 -7
  96. data/lib/action_view/template/html.rb +5 -5
  97. data/lib/action_view/template/resolver.rb +140 -115
  98. data/lib/action_view/template/text.rb +8 -9
  99. data/lib/action_view/template/types.rb +18 -18
  100. data/lib/action_view/template.rb +56 -31
  101. data/lib/action_view/test_case.rb +50 -29
  102. data/lib/action_view/testing/resolvers.rb +31 -31
  103. data/lib/action_view/version.rb +3 -1
  104. data/lib/action_view/view_paths.rb +28 -34
  105. data/lib/action_view.rb +8 -7
  106. data/lib/assets/compiled/rails-ujs.js +720 -0
  107. metadata +25 -24
  108. data/lib/action_view/tasks/dependencies.rake +0 -23
@@ -1,10 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "pathname"
2
4
  require "active_support/core_ext/class"
3
5
  require "active_support/core_ext/module/attribute_accessors"
4
- require 'active_support/core_ext/string/filters'
5
6
  require "action_view/template"
6
7
  require "thread"
7
- require "thread_safe"
8
+ require "concurrent/map"
8
9
 
9
10
  module ActionView
10
11
  # = Action View Resolver
@@ -15,7 +16,7 @@ module ActionView
15
16
  alias_method :partial?, :partial
16
17
 
17
18
  def self.build(name, prefix, partial)
18
- virtual = ""
19
+ virtual = "".dup
19
20
  virtual << "#{prefix}/" unless prefix.empty?
20
21
  virtual << (partial ? "_#{name}" : name)
21
22
  new name, prefix, partial, virtual
@@ -36,23 +37,28 @@ module ActionView
36
37
 
37
38
  # Threadsafe template cache
38
39
  class Cache #:nodoc:
39
- class SmallCache < ThreadSafe::Cache
40
+ class SmallCache < Concurrent::Map
40
41
  def initialize(options = {})
41
- super(options.merge(:initial_capacity => 2))
42
+ super(options.merge(initial_capacity: 2))
42
43
  end
43
44
  end
44
45
 
45
46
  # preallocate all the default blocks for performance/memory consumption reasons
46
- PARTIAL_BLOCK = lambda {|cache, partial| cache[partial] = SmallCache.new}
47
- PREFIX_BLOCK = lambda {|cache, prefix| cache[prefix] = SmallCache.new(&PARTIAL_BLOCK)}
48
- NAME_BLOCK = lambda {|cache, name| cache[name] = SmallCache.new(&PREFIX_BLOCK)}
49
- KEY_BLOCK = lambda {|cache, key| cache[key] = SmallCache.new(&NAME_BLOCK)}
47
+ PARTIAL_BLOCK = lambda { |cache, partial| cache[partial] = SmallCache.new }
48
+ PREFIX_BLOCK = lambda { |cache, prefix| cache[prefix] = SmallCache.new(&PARTIAL_BLOCK) }
49
+ NAME_BLOCK = lambda { |cache, name| cache[name] = SmallCache.new(&PREFIX_BLOCK) }
50
+ KEY_BLOCK = lambda { |cache, key| cache[key] = SmallCache.new(&NAME_BLOCK) }
50
51
 
51
52
  # usually a majority of template look ups return nothing, use this canonical preallocated array to save memory
52
53
  NO_TEMPLATES = [].freeze
53
54
 
54
55
  def initialize
55
56
  @data = SmallCache.new(&KEY_BLOCK)
57
+ @query_cache = SmallCache.new
58
+ end
59
+
60
+ def inspect
61
+ "#<#{self.class.name}:0x#{(object_id << 1).to_s(16)} keys=#{@data.size} queries=#{@query_cache.size}>"
56
62
  end
57
63
 
58
64
  # Cache the templates returned by the block
@@ -71,32 +77,57 @@ module ActionView
71
77
  end
72
78
  end
73
79
 
80
+ def cache_query(query) # :nodoc:
81
+ if Resolver.caching?
82
+ @query_cache[query] ||= canonical_no_templates(yield)
83
+ else
84
+ yield
85
+ end
86
+ end
87
+
74
88
  def clear
75
89
  @data.clear
90
+ @query_cache.clear
76
91
  end
77
92
 
78
- private
93
+ # Get the cache size. Do not call this
94
+ # method. This method is not guaranteed to be here ever.
95
+ def size # :nodoc:
96
+ size = 0
97
+ @data.each_value do |v1|
98
+ v1.each_value do |v2|
99
+ v2.each_value do |v3|
100
+ v3.each_value do |v4|
101
+ size += v4.size
102
+ end
103
+ end
104
+ end
105
+ end
79
106
 
80
- def canonical_no_templates(templates)
81
- templates.empty? ? NO_TEMPLATES : templates
107
+ size + @query_cache.size
82
108
  end
83
109
 
84
- def templates_have_changed?(cached_templates, fresh_templates)
85
- # if either the old or new template list is empty, we don't need to (and can't)
86
- # compare modification times, and instead just check whether the lists are different
87
- if cached_templates.blank? || fresh_templates.blank?
88
- return fresh_templates.blank? != cached_templates.blank?
110
+ private
111
+
112
+ def canonical_no_templates(templates)
113
+ templates.empty? ? NO_TEMPLATES : templates
89
114
  end
90
115
 
91
- cached_templates_max_updated_at = cached_templates.map(&:updated_at).max
116
+ def templates_have_changed?(cached_templates, fresh_templates)
117
+ # if either the old or new template list is empty, we don't need to (and can't)
118
+ # compare modification times, and instead just check whether the lists are different
119
+ if cached_templates.blank? || fresh_templates.blank?
120
+ return fresh_templates.blank? != cached_templates.blank?
121
+ end
92
122
 
93
- # if a template has changed, it will be now be newer than all the cached templates
94
- fresh_templates.any? { |t| t.updated_at > cached_templates_max_updated_at }
95
- end
123
+ cached_templates_max_updated_at = cached_templates.map(&:updated_at).max
124
+
125
+ # if a template has changed, it will be now be newer than all the cached templates
126
+ fresh_templates.any? { |t| t.updated_at > cached_templates_max_updated_at }
127
+ end
96
128
  end
97
129
 
98
- cattr_accessor :caching
99
- self.caching = true
130
+ cattr_accessor :caching, default: true
100
131
 
101
132
  class << self
102
133
  alias :caching? :caching
@@ -111,18 +142,22 @@ module ActionView
111
142
  end
112
143
 
113
144
  # Normalizes the arguments and passes it on to find_templates.
114
- def find_all(name, prefix=nil, partial=false, details={}, key=nil, locals=[])
145
+ def find_all(name, prefix = nil, partial = false, details = {}, key = nil, locals = [])
115
146
  cached(key, [name, prefix, partial], details, locals) do
116
- find_templates(name, prefix, partial, details, false)
147
+ find_templates(name, prefix, partial, details)
117
148
  end
118
149
  end
119
150
 
120
- def find_all_anywhere(name, prefix, partial=false, details={}, key=nil, locals=[])
151
+ def find_all_anywhere(name, prefix, partial = false, details = {}, key = nil, locals = [])
121
152
  cached(key, [name, prefix, partial], details, locals) do
122
153
  find_templates(name, prefix, partial, details, true)
123
154
  end
124
155
  end
125
156
 
157
+ def find_all_with_query(query) # :nodoc:
158
+ @cache.cache_query(query) { find_template_paths(File.join(@path, query)) }
159
+ end
160
+
126
161
  private
127
162
 
128
163
  delegate :caching?, to: :class
@@ -130,8 +165,8 @@ module ActionView
130
165
  # This is what child classes implement. No defaults are needed
131
166
  # because Resolver guarantees that the arguments are present and
132
167
  # normalized.
133
- def find_templates(name, prefix, partial, details, outside_app_allowed)
134
- raise NotImplementedError, "Subclasses must implement a find_templates(name, prefix, partial, details, outside_app_allowed) method"
168
+ def find_templates(name, prefix, partial, details, outside_app_allowed = false)
169
+ raise NotImplementedError, "Subclasses must implement a find_templates(name, prefix, partial, details, outside_app_allowed = false) method"
135
170
  end
136
171
 
137
172
  # Helpers that builds a path. Useful for building virtual paths.
@@ -143,9 +178,9 @@ module ActionView
143
178
  # always check the cache before hitting the resolver. Otherwise,
144
179
  # it always hits the resolver but if the key is present, check if the
145
180
  # resolver is fresher before returning it.
146
- def cached(key, path_info, details, locals) #:nodoc:
181
+ def cached(key, path_info, details, locals)
147
182
  name, prefix, partial = path_info
148
- locals = locals.map { |x| x.to_s }.sort!
183
+ locals = locals.map(&:to_s).sort!
149
184
 
150
185
  if key
151
186
  @cache.cache(key, name, prefix, partial, locals) do
@@ -157,7 +192,7 @@ module ActionView
157
192
  end
158
193
 
159
194
  # Ensures all the resolver information is set in the template.
160
- def decorate(templates, path_info, details, locals) #:nodoc:
195
+ def decorate(templates, path_info, details, locals)
161
196
  cached = nil
162
197
  templates.each do |t|
163
198
  t.locals = locals
@@ -170,117 +205,103 @@ module ActionView
170
205
 
171
206
  # An abstract class that implements a Resolver with path semantics.
172
207
  class PathResolver < Resolver #:nodoc:
173
- EXTENSIONS = { :locale => ".", :formats => ".", :variants => "+", :handlers => "." }
208
+ EXTENSIONS = { locale: ".", formats: ".", variants: "+", handlers: "." }
174
209
  DEFAULT_PATTERN = ":prefix/:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}"
175
210
 
176
- def initialize(pattern=nil)
211
+ def initialize(pattern = nil)
177
212
  @pattern = pattern || DEFAULT_PATTERN
178
213
  super()
179
214
  end
180
215
 
181
216
  private
182
217
 
183
- def find_templates(name, prefix, partial, details, outside_app_allowed = false)
184
- path = Path.build(name, prefix, partial)
185
- query(path, details, details[:formats], outside_app_allowed)
186
- end
218
+ def find_templates(name, prefix, partial, details, outside_app_allowed = false)
219
+ path = Path.build(name, prefix, partial)
220
+ query(path, details, details[:formats], outside_app_allowed)
221
+ end
187
222
 
188
- def query(path, details, formats, outside_app_allowed)
189
- query = build_query(path, details)
223
+ def query(path, details, formats, outside_app_allowed)
224
+ query = build_query(path, details)
190
225
 
191
- template_paths = find_template_paths query
192
- template_paths = reject_files_external_to_app(template_paths) unless outside_app_allowed
226
+ template_paths = find_template_paths(query)
227
+ template_paths = reject_files_external_to_app(template_paths) unless outside_app_allowed
193
228
 
194
- template_paths.map { |template|
195
- handler, format, variant = extract_handler_and_format_and_variant(template, formats)
196
- contents = File.binread(template)
229
+ template_paths.map do |template|
230
+ handler, format, variant = extract_handler_and_format_and_variant(template)
231
+ contents = File.binread(template)
197
232
 
198
- Template.new(contents, File.expand_path(template), handler,
199
- :virtual_path => path.virtual,
200
- :format => format,
201
- :variant => variant,
202
- :updated_at => mtime(template)
203
- )
204
- }
205
- end
233
+ Template.new(contents, File.expand_path(template), handler,
234
+ virtual_path: path.virtual,
235
+ format: format,
236
+ variant: variant,
237
+ updated_at: mtime(template)
238
+ )
239
+ end
240
+ end
206
241
 
207
- def reject_files_external_to_app(files)
208
- files.reject { |filename| !inside_path?(@path, filename) }
209
- end
242
+ def reject_files_external_to_app(files)
243
+ files.reject { |filename| !inside_path?(@path, filename) }
244
+ end
210
245
 
211
- if RUBY_VERSION >= '2.2.0'
212
246
  def find_template_paths(query)
213
- Dir[query].reject { |filename|
247
+ Dir[query].uniq.reject do |filename|
214
248
  File.directory?(filename) ||
215
249
  # deals with case-insensitive file systems.
216
250
  !File.fnmatch(query, filename, File::FNM_EXTGLOB)
217
- }
251
+ end
218
252
  end
219
- else
220
- def find_template_paths(query)
221
- # deals with case-insensitive file systems.
222
- sanitizer = Hash.new { |h,dir| h[dir] = Dir["#{dir}/*"] }
223
253
 
224
- Dir[query].reject { |filename|
225
- File.directory?(filename) ||
226
- !sanitizer[File.dirname(filename)].include?(filename)
227
- }
254
+ def inside_path?(path, filename)
255
+ filename = File.expand_path(filename)
256
+ path = File.join(path, "")
257
+ filename.start_with?(path)
228
258
  end
229
- end
230
259
 
231
- def inside_path?(path, filename)
232
- filename = File.expand_path(filename)
233
- path = File.join(path, '')
234
- filename.start_with?(path)
235
- end
260
+ # Helper for building query glob string based on resolver's pattern.
261
+ def build_query(path, details)
262
+ query = @pattern.dup
236
263
 
237
- # Helper for building query glob string based on resolver's pattern.
238
- def build_query(path, details)
239
- query = @pattern.dup
264
+ prefix = path.prefix.empty? ? "" : "#{escape_entry(path.prefix)}\\1"
265
+ query.gsub!(/:prefix(\/)?/, prefix)
240
266
 
241
- prefix = path.prefix.empty? ? "" : "#{escape_entry(path.prefix)}\\1"
242
- query.gsub!(/\:prefix(\/)?/, prefix)
267
+ partial = escape_entry(path.partial? ? "_#{path.name}" : path.name)
268
+ query.gsub!(/:action/, partial)
243
269
 
244
- partial = escape_entry(path.partial? ? "_#{path.name}" : path.name)
245
- query.gsub!(/\:action/, partial)
270
+ details.each do |ext, candidates|
271
+ if ext == :variants && candidates == :any
272
+ query.gsub!(/:#{ext}/, "*")
273
+ else
274
+ query.gsub!(/:#{ext}/, "{#{candidates.compact.uniq.join(',')}}")
275
+ end
276
+ end
246
277
 
247
- details.each do |ext, variants|
248
- query.gsub!(/\:#{ext}/, "{#{variants.compact.uniq.join(',')}}")
278
+ File.expand_path(query, @path)
249
279
  end
250
280
 
251
- File.expand_path(query, @path)
252
- end
281
+ def escape_entry(entry)
282
+ entry.gsub(/[*?{}\[\]]/, '\\\\\\&'.freeze)
283
+ end
253
284
 
254
- def escape_entry(entry)
255
- entry.gsub(/[*?{}\[\]]/, '\\\\\\&')
256
- end
285
+ # Returns the file mtime from the filesystem.
286
+ def mtime(p)
287
+ File.mtime(p)
288
+ end
257
289
 
258
- # Returns the file mtime from the filesystem.
259
- def mtime(p)
260
- File.mtime(p)
261
- end
290
+ # Extract handler, formats and variant from path. If a format cannot be found neither
291
+ # from the path, or the handler, we should return the array of formats given
292
+ # to the resolver.
293
+ def extract_handler_and_format_and_variant(path)
294
+ pieces = File.basename(path).split(".".freeze)
295
+ pieces.shift
262
296
 
263
- # Extract handler, formats and variant from path. If a format cannot be found neither
264
- # from the path, or the handler, we should return the array of formats given
265
- # to the resolver.
266
- def extract_handler_and_format_and_variant(path, default_formats)
267
- pieces = File.basename(path).split(".")
268
- pieces.shift
269
-
270
- extension = pieces.pop
271
- unless extension
272
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
273
- The file #{path} did not specify a template handler. The default is
274
- currently ERB, but will change to RAW in the future.
275
- MSG
276
- end
297
+ extension = pieces.pop
277
298
 
278
- handler = Template.handler_for_extension(extension)
279
- format, variant = pieces.last.split(EXTENSIONS[:variants], 2) if pieces.last
280
- format &&= Template::Types[format]
299
+ handler = Template.handler_for_extension(extension)
300
+ format, variant = pieces.last.split(EXTENSIONS[:variants], 2) if pieces.last
301
+ format &&= Template::Types[format]
281
302
 
282
- [handler, format, variant]
283
- end
303
+ [handler, format, variant]
304
+ end
284
305
  end
285
306
 
286
307
  # A resolver that loads files from the filesystem. It allows setting your own
@@ -289,13 +310,13 @@ module ActionView
289
310
  # ==== Examples
290
311
  #
291
312
  # Default pattern, loads views the same way as previous versions of rails, eg. when you're
292
- # looking for `users/new` it will produce query glob: `users/new{.{en},}{.{html,js},}{.{erb,haml},}`
313
+ # looking for <tt>users/new</tt> it will produce query glob: <tt>users/new{.{en},}{.{html,js},}{.{erb,haml},}</tt>
293
314
  #
294
315
  # FileSystemResolver.new("/path/to/views", ":prefix/:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}")
295
316
  #
296
317
  # This one allows you to keep files with different formats in separate subdirectories,
297
- # eg. `users/new.html` will be loaded from `users/html/new.erb` or `users/new.html.erb`,
298
- # `users/new.js` from `users/js/new.erb` or `users/new.js.erb`, etc.
318
+ # eg. <tt>users/new.html</tt> will be loaded from <tt>users/html/new.erb</tt> or <tt>users/new.html.erb</tt>,
319
+ # <tt>users/new.js</tt> from <tt>users/js/new.erb</tt> or <tt>users/new.js.erb</tt>, etc.
299
320
  #
300
321
  # FileSystemResolver.new("/path/to/views", ":prefix/{:formats/,}:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}")
301
322
  #
@@ -306,7 +327,7 @@ module ActionView
306
327
  #
307
328
  # ActionController::Base.view_paths = FileSystemResolver.new(
308
329
  # Rails.root.join("app/views"),
309
- # ":prefix{/:locale}/:action{.:formats,}{+:variants,}{.:handlers,}"
330
+ # ":prefix/:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}",
310
331
  # )
311
332
  #
312
333
  # ==== Pattern format and variables
@@ -322,7 +343,7 @@ module ActionView
322
343
  # * <tt>:handlers</tt> - possible handlers (for example erb, haml, builder...)
323
344
  #
324
345
  class FileSystemResolver < PathResolver
325
- def initialize(path, pattern=nil)
346
+ def initialize(path, pattern = nil)
326
347
  raise ArgumentError, "path already is a Resolver class" if path.is_a?(Resolver)
327
348
  super(pattern)
328
349
  @path = File.expand_path(path)
@@ -345,7 +366,11 @@ module ActionView
345
366
  query = escape_entry(File.join(@path, path))
346
367
 
347
368
  exts = EXTENSIONS.map do |ext, prefix|
348
- "{#{details[ext].compact.uniq.map { |e| "#{prefix}#{e}," }.join}}"
369
+ if ext == :variants && details[ext] == :any
370
+ "{#{prefix}*,}"
371
+ else
372
+ "{#{details[ext].compact.uniq.map { |e| "#{prefix}#{e}," }.join}}"
373
+ end
349
374
  end.join
350
375
 
351
376
  query + exts
@@ -1,22 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActionView #:nodoc:
2
4
  # = Action View Text Template
3
- class Template
5
+ class Template #:nodoc:
4
6
  class Text #:nodoc:
5
7
  attr_accessor :type
6
8
 
7
- def initialize(string, type = nil)
9
+ def initialize(string)
8
10
  @string = string.to_s
9
- @type = Types[type] || type if type
10
- @type ||= Types[:text]
11
+ @type = Types[:text]
11
12
  end
12
13
 
13
14
  def identifier
14
- 'text template'
15
+ "text template"
15
16
  end
16
17
 
17
- def inspect
18
- 'text template'
19
- end
18
+ alias_method :inspect, :identifier
20
19
 
21
20
  def to_str
22
21
  @string
@@ -27,7 +26,7 @@ module ActionView #:nodoc:
27
26
  end
28
27
 
29
28
  def formats
30
- [@type.respond_to?(:ref) ? @type.ref : @type.to_s]
29
+ [@type.ref]
31
30
  end
32
31
  end
33
32
  end
@@ -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