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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +121 -152
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/action_view/base.rb +107 -10
- data/lib/action_view/buffers.rb +15 -0
- data/lib/action_view/context.rb +5 -9
- data/lib/action_view/digestor.rb +8 -11
- data/lib/action_view/file_template.rb +33 -0
- data/lib/action_view/gem_version.rb +4 -4
- data/lib/action_view/helpers/asset_tag_helper.rb +7 -30
- data/lib/action_view/helpers/asset_url_helper.rb +4 -3
- data/lib/action_view/helpers/cache_helper.rb +18 -10
- data/lib/action_view/helpers/capture_helper.rb +4 -0
- data/lib/action_view/helpers/csp_helper.rb +4 -2
- data/lib/action_view/helpers/csrf_helper.rb +1 -1
- data/lib/action_view/helpers/date_helper.rb +69 -25
- data/lib/action_view/helpers/form_helper.rb +240 -8
- data/lib/action_view/helpers/form_options_helper.rb +23 -15
- data/lib/action_view/helpers/form_tag_helper.rb +9 -9
- data/lib/action_view/helpers/javascript_helper.rb +10 -11
- data/lib/action_view/helpers/number_helper.rb +5 -0
- data/lib/action_view/helpers/rendering_helper.rb +6 -4
- data/lib/action_view/helpers/sanitize_helper.rb +3 -3
- data/lib/action_view/helpers/tag_helper.rb +13 -43
- data/lib/action_view/helpers/tags/base.rb +9 -5
- data/lib/action_view/helpers/tags/color_field.rb +1 -1
- data/lib/action_view/helpers/tags/translator.rb +1 -6
- data/lib/action_view/helpers/text_helper.rb +3 -3
- data/lib/action_view/helpers/translation_helper.rb +12 -19
- data/lib/action_view/helpers/url_helper.rb +14 -14
- data/lib/action_view/helpers.rb +0 -2
- data/lib/action_view/layouts.rb +5 -5
- data/lib/action_view/log_subscriber.rb +6 -6
- data/lib/action_view/lookup_context.rb +63 -28
- data/lib/action_view/railtie.rb +23 -0
- data/lib/action_view/record_identifier.rb +2 -2
- data/lib/action_view/renderer/abstract_renderer.rb +56 -3
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +49 -10
- data/lib/action_view/renderer/partial_renderer.rb +66 -52
- data/lib/action_view/renderer/renderer.rb +16 -4
- data/lib/action_view/renderer/streaming_template_renderer.rb +4 -4
- data/lib/action_view/renderer/template_renderer.rb +18 -18
- data/lib/action_view/rendering.rb +49 -30
- data/lib/action_view/routing_url_for.rb +12 -11
- data/lib/action_view/template/handlers/builder.rb +2 -2
- data/lib/action_view/template/handlers/erb/erubi.rb +7 -3
- data/lib/action_view/template/handlers/erb.rb +17 -7
- data/lib/action_view/template/handlers/html.rb +1 -1
- data/lib/action_view/template/handlers/raw.rb +2 -2
- data/lib/action_view/template/handlers.rb +27 -1
- data/lib/action_view/template/html.rb +14 -5
- data/lib/action_view/template/inline.rb +22 -0
- data/lib/action_view/template/resolver.rb +70 -23
- data/lib/action_view/template/text.rb +5 -3
- data/lib/action_view/template.rb +75 -36
- data/lib/action_view/test_case.rb +1 -1
- data/lib/action_view/testing/resolvers.rb +7 -5
- data/lib/action_view/view_paths.rb +25 -1
- data/lib/action_view.rb +2 -2
- data/lib/assets/compiled/rails-ujs.js +39 -22
- metadata +19 -18
- 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
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
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
|
-
|
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
|
-
|
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
|
-
#
|
68
|
-
#
|
69
|
-
#
|
70
|
-
#
|
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(
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
103
|
-
|
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,
|
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
|
142
|
-
|
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
|
-
|
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] = "
|
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
|
-
|
26
|
-
|
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 :
|
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 =
|
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(
|
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.
|
60
|
+
escape: (self.class.escape_ignore_list.include? template.type),
|
51
61
|
trim: (self.class.erb_trim_mode == "-")
|
52
62
|
).src
|
53
63
|
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,
|
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
|
-
|
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 =
|
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
|
30
|
-
|
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 = ""
|
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
|
-
|
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
|
-
|
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(/[*?{}\[\]]/, '\\\\\\&'
|
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("."
|
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
|
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
|
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
|
-
|
366
|
-
query = escape_entry(File.join(@path, path))
|
375
|
+
private
|
367
376
|
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
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
|
408
|
+
end
|
375
409
|
|
376
|
-
|
377
|
-
|
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
|
29
|
-
|
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
|