actionview 6.0.0.beta3 → 6.0.0.rc1

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +40 -4
  3. data/README.rdoc +3 -1
  4. data/lib/action_view.rb +2 -1
  5. data/lib/action_view/base.rb +4 -4
  6. data/lib/action_view/cache_expiry.rb +49 -0
  7. data/lib/action_view/digestor.rb +0 -6
  8. data/lib/action_view/gem_version.rb +1 -1
  9. data/lib/action_view/helpers/form_helper.rb +2 -2
  10. data/lib/action_view/helpers/form_tag_helper.rb +1 -1
  11. data/lib/action_view/helpers/output_safety_helper.rb +1 -1
  12. data/lib/action_view/helpers/tags/base.rb +1 -1
  13. data/lib/action_view/helpers/translation_helper.rb +2 -2
  14. data/lib/action_view/helpers/url_helper.rb +1 -1
  15. data/lib/action_view/lookup_context.rb +11 -4
  16. data/lib/action_view/path_set.rb +5 -10
  17. data/lib/action_view/railtie.rb +1 -1
  18. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +20 -13
  19. data/lib/action_view/renderer/streaming_template_renderer.rb +1 -1
  20. data/lib/action_view/renderer/template_renderer.rb +9 -3
  21. data/lib/action_view/rendering.rb +3 -2
  22. data/lib/action_view/template.rb +43 -50
  23. data/lib/action_view/template/error.rb +21 -1
  24. data/lib/action_view/template/handlers.rb +3 -3
  25. data/lib/action_view/template/handlers/erb/erubi.rb +2 -2
  26. data/lib/action_view/template/raw_file.rb +28 -0
  27. data/lib/action_view/template/resolver.rb +73 -117
  28. data/lib/action_view/template/sources.rb +13 -0
  29. data/lib/action_view/template/sources/file.rb +17 -0
  30. data/lib/action_view/testing/resolvers.rb +9 -10
  31. data/lib/action_view/unbound_template.rb +32 -0
  32. data/lib/assets/compiled/rails-ujs.js +14 -8
  33. metadata +16 -12
  34. data/lib/action_view/file_template.rb +0 -33
@@ -34,7 +34,7 @@ module ActionView
34
34
  return unless logger
35
35
 
36
36
  message = +"\n#{exception.class} (#{exception.message}):\n"
37
- message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
37
+ message << exception.annotated_source_code.to_s if exception.respond_to?(:annotated_source_code)
38
38
  message << " " << exception.backtrace.join("\n ")
39
39
  logger.fatal("#{message}\n\n")
40
40
  end
@@ -26,7 +26,12 @@ module ActionView
26
26
  elsif options.key?(:html)
27
27
  Template::HTML.new(options[:html], formats.first)
28
28
  elsif options.key?(:file)
29
- @lookup_context.with_fallbacks.find_file(options[:file], nil, false, keys, @details)
29
+ if File.exist?(options[:file])
30
+ Template::RawFile.new(options[:file])
31
+ else
32
+ ActiveSupport::Deprecation.warn "render file: should be given the absolute path to a file"
33
+ @lookup_context.with_fallbacks.find_template(options[:file], nil, false, keys, @details)
34
+ end
30
35
  elsif options.key?(:inline)
31
36
  handler = Template.handler_for_extension(options[:type] || "erb")
32
37
  format = if handler.respond_to?(:default_format)
@@ -49,14 +54,14 @@ module ActionView
49
54
  # Renders the given template. A string representing the layout can be
50
55
  # supplied as well.
51
56
  def render_template(view, template, layout_name, locals)
52
- render_with_layout(view, layout_name, template, locals) do |layout|
57
+ render_with_layout(view, template, layout_name, locals) do |layout|
53
58
  instrument(:template, identifier: template.identifier, layout: layout.try(:virtual_path)) do
54
59
  template.render(view, locals) { |*name| view._layout_for(*name) }
55
60
  end
56
61
  end
57
62
  end
58
63
 
59
- def render_with_layout(view, path, template, locals)
64
+ def render_with_layout(view, template, path, locals)
60
65
  layout = path && find_layout(path, locals.keys, [formats.first])
61
66
  content = yield(layout)
62
67
 
@@ -84,6 +89,7 @@ module ActionView
84
89
  when String
85
90
  begin
86
91
  if layout.start_with?("/")
92
+ ActiveSupport::Deprecation.warn "Rendering layouts from an absolute path is deprecated."
87
93
  @lookup_context.with_fallbacks.find_template(layout, nil, false, [], details)
88
94
  else
89
95
  @lookup_context.find_template(layout, nil, false, [], details)
@@ -118,7 +118,8 @@ module ActionView
118
118
  renderer.render_to_object(context, options)
119
119
  end
120
120
 
121
- @rendered_format = Template::Types[rendered_template.format]
121
+ rendered_format = rendered_template.format || lookup_context.formats.first
122
+ @rendered_format = Template::Types[rendered_format]
122
123
 
123
124
  rendered_template.body
124
125
  end
@@ -126,7 +127,7 @@ module ActionView
126
127
  # Assign the rendered format to look up context.
127
128
  def _process_format(format)
128
129
  super
129
- lookup_context.formats = [format.to_sym]
130
+ lookup_context.formats = [format.to_sym] if format.to_sym
130
131
  end
131
132
 
132
133
  # Normalize args by converting render "foo" to render :action => "foo" and
@@ -113,51 +113,59 @@ module ActionView
113
113
 
114
114
  eager_autoload do
115
115
  autoload :Error
116
+ autoload :RawFile
116
117
  autoload :Handlers
117
118
  autoload :HTML
118
119
  autoload :Inline
120
+ autoload :Sources
119
121
  autoload :Text
120
122
  autoload :Types
121
123
  end
122
124
 
123
125
  extend Template::Handlers
124
126
 
125
- attr_accessor :locals, :variants, :virtual_path
127
+ attr_reader :identifier, :handler, :original_encoding, :updated_at
128
+ attr_reader :variable, :format, :variant, :locals, :virtual_path
126
129
 
127
- attr_reader :source, :identifier, :handler, :original_encoding, :updated_at
128
- attr_reader :variable, :format
129
-
130
- def initialize(source, identifier, handler, format: nil, **details)
131
- unless format
132
- ActiveSupport::Deprecation.warn "ActionView::Template#initialize requires a format parameter"
133
- format = :html
130
+ def initialize(source, identifier, handler, format: nil, variant: nil, locals: nil, virtual_path: nil, updated_at: nil)
131
+ unless locals
132
+ ActiveSupport::Deprecation.warn "ActionView::Template#initialize requires a locals parameter"
133
+ locals = []
134
134
  end
135
135
 
136
136
  @source = source
137
137
  @identifier = identifier
138
138
  @handler = handler
139
139
  @compiled = false
140
- @original_encoding = nil
141
- @locals = details[:locals] || []
142
- @virtual_path = details[:virtual_path]
140
+ @locals = locals
141
+ @virtual_path = virtual_path
143
142
 
144
143
  @variable = if @virtual_path
145
- base = @virtual_path[-1] == "/" ? "" : File.basename(@virtual_path)
144
+ base = @virtual_path[-1] == "/" ? "" : ::File.basename(@virtual_path)
146
145
  base =~ /\A_?(.*?)(?:\.\w+)*\z/
147
146
  $1.to_sym
148
147
  end
149
148
 
150
- @updated_at = details[:updated_at] || Time.now
149
+ if updated_at
150
+ ActiveSupport::Deprecation.warn "ActionView::Template#updated_at is deprecated"
151
+ @updated_at = updated_at
152
+ else
153
+ @updated_at = Time.now
154
+ end
151
155
  @format = format
152
- @variants = [details[:variant]]
156
+ @variant = variant
153
157
  @compile_mutex = Mutex.new
154
158
  end
155
159
 
156
- def formats=(_)
157
- end
158
- deprecate :formats=
159
-
160
+ deprecate :original_encoding
161
+ deprecate :updated_at
162
+ deprecate def virtual_path=(_); end
163
+ deprecate def locals=(_); end
164
+ deprecate def formats=(_); end
160
165
  deprecate def formats; Array(format); end
166
+ deprecate def variants=(_); end
167
+ deprecate def variants; [variant]; end
168
+ deprecate def refresh(_); self; end
161
169
 
162
170
  # Returns whether the underlying handler supports streaming. If so,
163
171
  # a streaming buffer *may* be passed when it starts rendering.
@@ -174,7 +182,7 @@ module ActionView
174
182
  def render(view, locals, buffer = ActionView::OutputBuffer.new, &block)
175
183
  instrument_render_template do
176
184
  compile!(view)
177
- view.run(method_name, self, locals, buffer, &block)
185
+ view._run(method_name, self, locals, buffer, &block)
178
186
  end
179
187
  rescue => e
180
188
  handle_render_error(view, e)
@@ -184,25 +192,6 @@ module ActionView
184
192
  @type ||= Types[format]
185
193
  end
186
194
 
187
- # Receives a view object and return a template similar to self by using @virtual_path.
188
- #
189
- # This method is useful if you have a template object but it does not contain its source
190
- # anymore since it was already compiled. In such cases, all you need to do is to call
191
- # refresh passing in the view object.
192
- #
193
- # Notice this method raises an error if the template to be refreshed does not have a
194
- # virtual path set (true just for inline templates).
195
- def refresh(view)
196
- raise "A template needs to have a virtual path in order to be refreshed" unless @virtual_path
197
- lookup = view.lookup_context
198
- pieces = @virtual_path.split("/")
199
- name = pieces.pop
200
- partial = !!name.sub!(/^_/, "")
201
- lookup.disable_cache do
202
- lookup.find_template(name, [ pieces.join("/") ], partial, @locals)
203
- end
204
- end
205
-
206
195
  def short_identifier
207
196
  @short_identifier ||= defined?(Rails.root) ? identifier.sub("#{Rails.root}/", "") : identifier
208
197
  end
@@ -211,6 +200,10 @@ module ActionView
211
200
  "#<#{self.class.name} #{short_identifier} locals=#{@locals.inspect}>"
212
201
  end
213
202
 
203
+ def source
204
+ @source.to_s
205
+ end
206
+
214
207
  # This method is responsible for properly setting the encoding of the
215
208
  # source. Until this point, we assume that the source is BINARY data.
216
209
  # If no additional information is supplied, we assume the encoding is
@@ -262,11 +255,11 @@ module ActionView
262
255
  # to ensure that references to the template object can be marshalled as well. This means forgoing
263
256
  # the marshalling of the compiler mutex and instantiating that again on unmarshalling.
264
257
  def marshal_dump # :nodoc:
265
- [ @source, @identifier, @handler, @compiled, @original_encoding, @locals, @virtual_path, @updated_at, @format, @variants ]
258
+ [ @source, @identifier, @handler, @compiled, @locals, @virtual_path, @updated_at, @format, @variant ]
266
259
  end
267
260
 
268
261
  def marshal_load(array) # :nodoc:
269
- @source, @identifier, @handler, @compiled, @original_encoding, @locals, @virtual_path, @updated_at, @format, @variants = *array
262
+ @source, @identifier, @handler, @compiled, @locals, @virtual_path, @updated_at, @format, @variant = *array
270
263
  @compile_mutex = Mutex.new
271
264
  end
272
265
 
@@ -292,9 +285,6 @@ module ActionView
292
285
  compile(mod)
293
286
  end
294
287
 
295
- # Just discard the source if we have a virtual path. This
296
- # means we can get the template back.
297
- @source = nil if @virtual_path
298
288
  @compiled = true
299
289
  end
300
290
  end
@@ -326,6 +316,7 @@ module ActionView
326
316
 
327
317
  # Make sure that the resulting String to be eval'd is in the
328
318
  # encoding of the code
319
+ original_source = source
329
320
  source = +<<-end_src
330
321
  def #{method_name}(local_assigns, output_buffer)
331
322
  @virtual_path = #{@virtual_path.inspect};#{locals_code};#{code}
@@ -346,7 +337,14 @@ module ActionView
346
337
  raise WrongEncodingError.new(source, Encoding.default_internal)
347
338
  end
348
339
 
349
- mod.module_eval(source, identifier, 0)
340
+ begin
341
+ mod.module_eval(source, identifier, 0)
342
+ rescue SyntaxError
343
+ # Account for when code in the template is not syntactically valid; e.g. if we're using
344
+ # ERB and the user writes <%= foo( %>, attempting to call a helper `foo` and interpolate
345
+ # the result into the template, but missing an end parenthesis.
346
+ raise SyntaxErrorInTemplate.new(self, original_source)
347
+ end
350
348
  end
351
349
 
352
350
  def handle_render_error(view, e)
@@ -354,12 +352,7 @@ module ActionView
354
352
  e.sub_template_of(self)
355
353
  raise e
356
354
  else
357
- template = self
358
- unless template.source
359
- template = refresh(view)
360
- template.encode!
361
- end
362
- raise Template::Error.new(template)
355
+ raise Template::Error.new(self)
363
356
  end
364
357
  end
365
358
 
@@ -109,7 +109,7 @@ module ActionView
109
109
  end
110
110
  end
111
111
 
112
- def annoted_source_code
112
+ def annotated_source_code
113
113
  source_extract(4)
114
114
  end
115
115
 
@@ -138,4 +138,24 @@ module ActionView
138
138
  end
139
139
 
140
140
  TemplateError = Template::Error
141
+
142
+ class SyntaxErrorInTemplate < TemplateError #:nodoc
143
+ def initialize(template, offending_code_string)
144
+ @offending_code_string = offending_code_string
145
+ super(template)
146
+ end
147
+
148
+ def message
149
+ <<~MESSAGE
150
+ Encountered a syntax error while rendering template: check #{@offending_code_string}
151
+ MESSAGE
152
+ end
153
+
154
+ def annotated_source_code
155
+ @offending_code_string.split("\n").map.with_index(1) { |line, index|
156
+ indentation = " " * 4
157
+ "#{index}:#{indentation}#{line}"
158
+ }
159
+ end
160
+ end
141
161
  end
@@ -45,12 +45,12 @@ module ActionView #:nodoc:
45
45
 
46
46
  unless params.find_all { |type, _| type == :req || type == :opt }.length >= 2
47
47
  ActiveSupport::Deprecation.warn <<~eowarn
48
- Single arity template handlers are deprecated. Template handlers must
48
+ Single arity template handlers are deprecated. Template handlers must
49
49
  now accept two parameters, the view object and the source for the view object.
50
50
  Change:
51
- >> #{handler.class}#call(#{params.map(&:last).join(", ")})
51
+ >> #{handler}.call(#{params.map(&:last).join(", ")})
52
52
  To:
53
- >> #{handler.class}#call(#{params.map(&:last).join(", ")}, source)
53
+ >> #{handler}.call(#{params.map(&:last).join(", ")}, source)
54
54
  eowarn
55
55
  handler = LegacyHandlerWrapper.new(handler)
56
56
  end
@@ -25,9 +25,9 @@ module ActionView
25
25
  src = @src
26
26
  view = Class.new(ActionView::Base) {
27
27
  include action_view_erb_handler_context._routes.url_helpers
28
- class_eval("define_method(:_template) { |local_assigns, output_buffer| #{src} }", @filename || "(erubi)", 0)
28
+ class_eval("define_method(:_template) { |local_assigns, output_buffer| #{src} }", defined?(@filename) ? @filename : "(erubi)", 0)
29
29
  }.empty
30
- view.run(:_template, nil, {}, ActionView::OutputBuffer.new)
30
+ view._run(:_template, nil, {}, ActionView::OutputBuffer.new)
31
31
  end
32
32
 
33
33
  private
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionView #:nodoc:
4
+ # = Action View RawFile Template
5
+ class Template #:nodoc:
6
+ class RawFile #:nodoc:
7
+ attr_accessor :type, :format
8
+
9
+ def initialize(filename)
10
+ @filename = filename.to_s
11
+ extname = ::File.extname(filename).delete(".")
12
+ @type = Template::Types[extname] || Template::Types[:text]
13
+ @format = @type.symbol
14
+ end
15
+
16
+ def identifier
17
+ @filename
18
+ end
19
+
20
+ def render(*args)
21
+ ::File.read(@filename)
22
+ end
23
+
24
+ def formats; Array(format); end
25
+ deprecate :formats
26
+ end
27
+ end
28
+ end
@@ -63,26 +63,11 @@ module ActionView
63
63
 
64
64
  # Cache the templates returned by the block
65
65
  def cache(key, name, prefix, partial, locals)
66
- if Resolver.caching?
67
- @data[key][name][prefix][partial][locals] ||= canonical_no_templates(yield)
68
- else
69
- fresh_templates = yield
70
- cached_templates = @data[key][name][prefix][partial][locals]
71
-
72
- if templates_have_changed?(cached_templates, fresh_templates)
73
- @data[key][name][prefix][partial][locals] = canonical_no_templates(fresh_templates)
74
- else
75
- cached_templates || NO_TEMPLATES
76
- end
77
- end
66
+ @data[key][name][prefix][partial][locals] ||= canonical_no_templates(yield)
78
67
  end
79
68
 
80
69
  def cache_query(query) # :nodoc:
81
- if Resolver.caching?
82
- @query_cache[query] ||= canonical_no_templates(yield)
83
- else
84
- yield
85
- end
70
+ @query_cache[query] ||= canonical_no_templates(yield)
86
71
  end
87
72
 
88
73
  def clear
@@ -112,19 +97,6 @@ module ActionView
112
97
  def canonical_no_templates(templates)
113
98
  templates.empty? ? NO_TEMPLATES : templates
114
99
  end
115
-
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
122
-
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
128
100
  end
129
101
 
130
102
  cattr_accessor :caching, default: true
@@ -143,35 +115,33 @@ module ActionView
143
115
 
144
116
  # Normalizes the arguments and passes it on to find_templates.
145
117
  def find_all(name, prefix = nil, partial = false, details = {}, key = nil, locals = [])
146
- cached(key, [name, prefix, partial], details, locals) do
147
- find_templates(name, prefix, partial, details)
148
- end
149
- end
118
+ locals = locals.map(&:to_s).sort!.freeze
150
119
 
151
- def find_all_anywhere(name, prefix, partial = false, details = {}, key = nil, locals = [])
152
120
  cached(key, [name, prefix, partial], details, locals) do
153
- find_templates(name, prefix, partial, details, true)
121
+ _find_all(name, prefix, partial, details, key, locals)
154
122
  end
155
123
  end
156
124
 
125
+ alias :find_all_anywhere :find_all
126
+ deprecate :find_all_anywhere
127
+
157
128
  def find_all_with_query(query) # :nodoc:
158
129
  @cache.cache_query(query) { find_template_paths(File.join(@path, query)) }
159
130
  end
160
131
 
161
132
  private
162
133
 
134
+ def _find_all(name, prefix, partial, details, key, locals)
135
+ find_templates(name, prefix, partial, details, locals)
136
+ end
137
+
163
138
  delegate :caching?, to: :class
164
139
 
165
140
  # This is what child classes implement. No defaults are needed
166
141
  # because Resolver guarantees that the arguments are present and
167
142
  # normalized.
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"
170
- end
171
-
172
- # Helpers that builds a path. Useful for building virtual paths.
173
- def build_path(name, prefix, partial)
174
- Path.build(name, prefix, partial)
143
+ def find_templates(name, prefix, partial, details, locals = [])
144
+ raise NotImplementedError, "Subclasses must implement a find_templates(name, prefix, partial, details, locals = []) method"
175
145
  end
176
146
 
177
147
  # Handles templates caching. If a key is given and caching is on
@@ -180,24 +150,13 @@ module ActionView
180
150
  # resolver is fresher before returning it.
181
151
  def cached(key, path_info, details, locals)
182
152
  name, prefix, partial = path_info
183
- locals = locals.map(&:to_s).sort!
184
153
 
185
154
  if key
186
155
  @cache.cache(key, name, prefix, partial, locals) do
187
- decorate(yield, path_info, details, locals)
156
+ yield
188
157
  end
189
158
  else
190
- decorate(yield, path_info, details, locals)
191
- end
192
- end
193
-
194
- # Ensures all the resolver information is set in the template.
195
- def decorate(templates, path_info, details, locals)
196
- cached = nil
197
- templates.each do |t|
198
- t.locals = locals
199
- t.variants = details[:variants] || [] if t.variants.empty?
200
- t.virtual_path ||= (cached ||= build_path(*path_info))
159
+ yield
201
160
  end
202
161
  end
203
162
  end
@@ -208,33 +167,60 @@ module ActionView
208
167
  DEFAULT_PATTERN = ":prefix/:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}"
209
168
 
210
169
  def initialize(pattern = nil)
211
- @pattern = pattern || DEFAULT_PATTERN
170
+ if pattern
171
+ ActiveSupport::Deprecation.warn "Specifying a custom path for #{self.class} is deprecated. Implement a custom Resolver subclass instead."
172
+ @pattern = pattern
173
+ else
174
+ @pattern = DEFAULT_PATTERN
175
+ end
176
+ @unbound_templates = Concurrent::Map.new
177
+ super()
178
+ end
179
+
180
+ def clear_cache
181
+ @unbound_templates.clear
212
182
  super()
213
183
  end
214
184
 
215
185
  private
216
186
 
217
- def find_templates(name, prefix, partial, details, outside_app_allowed = false)
187
+ def _find_all(name, prefix, partial, details, key, locals)
218
188
  path = Path.build(name, prefix, partial)
219
- query(path, details, details[:formats], outside_app_allowed)
189
+ query(path, details, details[:formats], locals, cache: !!key)
220
190
  end
221
191
 
222
- def query(path, details, formats, outside_app_allowed)
192
+ def query(path, details, formats, locals, cache:)
223
193
  template_paths = find_template_paths_from_details(path, details)
224
- template_paths = reject_files_external_to_app(template_paths) unless outside_app_allowed
194
+ template_paths = reject_files_external_to_app(template_paths)
225
195
 
226
196
  template_paths.map do |template|
227
- handler, format, variant = extract_handler_and_format_and_variant(template, formats.first)
228
-
229
- FileTemplate.new(File.expand_path(template), handler,
230
- virtual_path: path.virtual,
231
- format: format,
232
- variant: variant,
233
- updated_at: mtime(template)
234
- )
197
+ unbound_template =
198
+ if cache
199
+ @unbound_templates.compute_if_absent([template, path.virtual]) do
200
+ build_unbound_template(template, path.virtual)
201
+ end
202
+ else
203
+ build_unbound_template(template, path.virtual)
204
+ end
205
+
206
+ unbound_template.bind_locals(locals)
235
207
  end
236
208
  end
237
209
 
210
+ def build_unbound_template(template, virtual_path)
211
+ handler, format, variant = extract_handler_and_format_and_variant(template)
212
+ source = Template::Sources::File.new(template)
213
+
214
+ UnboundTemplate.new(
215
+ source,
216
+ template,
217
+ handler,
218
+ virtual_path: virtual_path,
219
+ format: format,
220
+ variant: variant,
221
+ )
222
+ end
223
+
238
224
  def reject_files_external_to_app(files)
239
225
  files.reject { |filename| !inside_path?(@path, filename) }
240
226
  end
@@ -283,15 +269,10 @@ module ActionView
283
269
  entry.gsub(/[*?{}\[\]]/, '\\\\\\&')
284
270
  end
285
271
 
286
- # Returns the file mtime from the filesystem.
287
- def mtime(p)
288
- File.mtime(p)
289
- end
290
-
291
272
  # Extract handler, formats and variant from path. If a format cannot be found neither
292
273
  # from the path, or the handler, we should return the array of formats given
293
274
  # to the resolver.
294
- def extract_handler_and_format_and_variant(path, query_format)
275
+ def extract_handler_and_format_and_variant(path)
295
276
  pieces = File.basename(path).split(".")
296
277
  pieces.shift
297
278
 
@@ -305,54 +286,19 @@ module ActionView
305
286
  if handler.respond_to?(:default_format) # default_format can return nil
306
287
  handler.default_format
307
288
  else
308
- query_format
289
+ nil
309
290
  end
310
291
  end
311
292
 
312
293
  # Template::Types[format] and handler.default_format can return nil
313
- [handler, format || query_format, variant]
294
+ [handler, format, variant]
314
295
  end
315
296
  end
316
297
 
317
- # A resolver that loads files from the filesystem. It allows setting your own
318
- # resolving pattern. Such pattern can be a glob string supported by some variables.
319
- #
320
- # ==== Examples
321
- #
322
- # Default pattern, loads views the same way as previous versions of rails, eg. when you're
323
- # looking for <tt>users/new</tt> it will produce query glob: <tt>users/new{.{en},}{.{html,js},}{.{erb,haml},}</tt>
324
- #
325
- # FileSystemResolver.new("/path/to/views", ":prefix/:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}")
326
- #
327
- # This one allows you to keep files with different formats in separate subdirectories,
328
- # eg. <tt>users/new.html</tt> will be loaded from <tt>users/html/new.erb</tt> or <tt>users/new.html.erb</tt>,
329
- # <tt>users/new.js</tt> from <tt>users/js/new.erb</tt> or <tt>users/new.js.erb</tt>, etc.
330
- #
331
- # FileSystemResolver.new("/path/to/views", ":prefix/{:formats/,}:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}")
332
- #
333
- # If you don't specify a pattern then the default will be used.
334
- #
335
- # In order to use any of the customized resolvers above in a Rails application, you just need
336
- # to configure ActionController::Base.view_paths in an initializer, for example:
337
- #
338
- # ActionController::Base.view_paths = FileSystemResolver.new(
339
- # Rails.root.join("app/views"),
340
- # ":prefix/:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}",
341
- # )
342
- #
343
- # ==== Pattern format and variables
344
- #
345
- # Pattern has to be a valid glob string, and it allows you to use the
346
- # following variables:
347
- #
348
- # * <tt>:prefix</tt> - usually the controller path
349
- # * <tt>:action</tt> - name of the action
350
- # * <tt>:locale</tt> - possible locale versions
351
- # * <tt>:formats</tt> - possible request formats (for example html, json, xml...)
352
- # * <tt>:variants</tt> - possible request variants (for example phone, tablet...)
353
- # * <tt>:handlers</tt> - possible handlers (for example erb, haml, builder...)
354
- #
298
+ # A resolver that loads files from the filesystem.
355
299
  class FileSystemResolver < PathResolver
300
+ attr_reader :path
301
+
356
302
  def initialize(path, pattern = nil)
357
303
  raise ArgumentError, "path already is a Resolver class" if path.is_a?(Resolver)
358
304
  super(pattern)
@@ -372,6 +318,10 @@ module ActionView
372
318
 
373
319
  # An Optimized resolver for Rails' most common case.
374
320
  class OptimizedFileSystemResolver < FileSystemResolver #:nodoc:
321
+ def initialize(path)
322
+ super(path)
323
+ end
324
+
375
325
  private
376
326
 
377
327
  def find_template_paths_from_details(path, details)
@@ -427,12 +377,18 @@ module ActionView
427
377
  # The same as FileSystemResolver but does not allow templates to store
428
378
  # a virtual path since it is invalid for such resolvers.
429
379
  class FallbackFileSystemResolver < FileSystemResolver #:nodoc:
380
+ private_class_method :new
381
+
430
382
  def self.instances
431
383
  [new(""), new("/")]
432
384
  end
433
385
 
434
- def decorate(*)
435
- super.each { |t| t.virtual_path = nil }
386
+ def build_unbound_template(template, _)
387
+ super(template, nil)
388
+ end
389
+
390
+ def reject_files_external_to_app(files)
391
+ files
436
392
  end
437
393
  end
438
394
  end