actionview 5.0.7.2 → 5.1.0.beta1
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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +92 -384
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/action_view.rb +5 -5
- data/lib/action_view/base.rb +19 -19
- data/lib/action_view/buffers.rb +1 -1
- data/lib/action_view/context.rb +1 -1
- data/lib/action_view/dependency_tracker.rb +4 -5
- data/lib/action_view/digestor.rb +6 -7
- data/lib/action_view/flows.rb +5 -6
- data/lib/action_view/gem_version.rb +3 -3
- data/lib/action_view/helpers.rb +1 -1
- data/lib/action_view/helpers/active_model_helper.rb +8 -8
- data/lib/action_view/helpers/asset_tag_helper.rb +62 -36
- data/lib/action_view/helpers/asset_url_helper.rb +111 -49
- data/lib/action_view/helpers/atom_feed_helper.rb +12 -13
- data/lib/action_view/helpers/cache_helper.rb +34 -20
- data/lib/action_view/helpers/capture_helper.rb +2 -2
- data/lib/action_view/helpers/controller_helper.rb +3 -11
- data/lib/action_view/helpers/csrf_helper.rb +3 -3
- data/lib/action_view/helpers/date_helper.rb +109 -107
- data/lib/action_view/helpers/debug_helper.rb +2 -3
- data/lib/action_view/helpers/form_helper.rb +406 -31
- data/lib/action_view/helpers/form_options_helper.rb +12 -12
- data/lib/action_view/helpers/form_tag_helper.rb +19 -18
- data/lib/action_view/helpers/javascript_helper.rb +6 -6
- data/lib/action_view/helpers/number_helper.rb +48 -46
- data/lib/action_view/helpers/output_safety_helper.rb +8 -8
- data/lib/action_view/helpers/rendering_helper.rb +2 -2
- data/lib/action_view/helpers/sanitize_helper.rb +6 -8
- data/lib/action_view/helpers/tag_helper.rb +194 -77
- data/lib/action_view/helpers/tags/base.rb +121 -102
- data/lib/action_view/helpers/tags/check_box.rb +17 -17
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +8 -8
- data/lib/action_view/helpers/tags/collection_helpers.rb +60 -60
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +2 -2
- data/lib/action_view/helpers/tags/collection_select.rb +2 -2
- data/lib/action_view/helpers/tags/date_select.rb +36 -36
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +2 -2
- data/lib/action_view/helpers/tags/label.rb +4 -0
- data/lib/action_view/helpers/tags/password_field.rb +1 -1
- data/lib/action_view/helpers/tags/radio_button.rb +4 -4
- data/lib/action_view/helpers/tags/select.rb +9 -9
- data/lib/action_view/helpers/tags/text_area.rb +1 -1
- data/lib/action_view/helpers/tags/text_field.rb +5 -5
- data/lib/action_view/helpers/tags/translator.rb +14 -12
- data/lib/action_view/helpers/text_helper.rb +20 -19
- data/lib/action_view/helpers/translation_helper.rb +6 -6
- data/lib/action_view/helpers/url_helper.rb +42 -38
- data/lib/action_view/layouts.rb +51 -47
- data/lib/action_view/log_subscriber.rb +24 -9
- data/lib/action_view/lookup_context.rb +19 -25
- data/lib/action_view/path_set.rb +19 -19
- data/lib/action_view/railtie.rb +3 -3
- data/lib/action_view/record_identifier.rb +6 -6
- data/lib/action_view/renderer/abstract_renderer.rb +17 -17
- data/lib/action_view/renderer/partial_renderer.rb +188 -187
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +7 -1
- data/lib/action_view/renderer/streaming_template_renderer.rb +45 -47
- data/lib/action_view/renderer/template_renderer.rb +64 -66
- data/lib/action_view/rendering.rb +4 -5
- data/lib/action_view/routing_url_for.rb +9 -13
- data/lib/action_view/tasks/cache_digests.rake +7 -7
- data/lib/action_view/template.rb +26 -27
- data/lib/action_view/template/error.rb +5 -15
- data/lib/action_view/template/handlers.rb +4 -4
- data/lib/action_view/template/handlers/builder.rb +7 -7
- data/lib/action_view/template/handlers/erb.rb +9 -76
- data/lib/action_view/template/handlers/erb/deprecated_erubis.rb +9 -0
- data/lib/action_view/template/handlers/erb/erubi.rb +81 -0
- data/lib/action_view/template/handlers/erb/erubis.rb +81 -0
- data/lib/action_view/template/html.rb +2 -4
- data/lib/action_view/template/resolver.rb +107 -90
- data/lib/action_view/template/text.rb +5 -8
- data/lib/action_view/template/types.rb +1 -1
- data/lib/action_view/test_case.rb +20 -21
- data/lib/action_view/testing/resolvers.rb +29 -30
- data/lib/action_view/version.rb +1 -1
- data/lib/action_view/view_paths.rb +20 -8
- data/lib/assets/compiled/rails-ujs.js +648 -0
- metadata +19 -14
@@ -35,10 +35,10 @@ module ActionView
|
|
35
35
|
prefixes = Array(prefixes)
|
36
36
|
template_type = if partial
|
37
37
|
"partial"
|
38
|
-
elsif
|
39
|
-
|
38
|
+
elsif /layouts/i.match?(path)
|
39
|
+
"layout"
|
40
40
|
else
|
41
|
-
|
41
|
+
"template"
|
42
42
|
end
|
43
43
|
|
44
44
|
if partial && path.present?
|
@@ -62,23 +62,13 @@ module ActionView
|
|
62
62
|
# Override to prevent #cause resetting during re-raise.
|
63
63
|
attr_reader :cause
|
64
64
|
|
65
|
-
def initialize(template
|
66
|
-
if original_exception
|
67
|
-
ActiveSupport::Deprecation.warn("Passing #original_exception is deprecated and has no effect. " \
|
68
|
-
"Exceptions will automatically capture the original exception.", caller)
|
69
|
-
end
|
70
|
-
|
65
|
+
def initialize(template)
|
71
66
|
super($!.message)
|
72
67
|
set_backtrace($!.backtrace)
|
73
68
|
@cause = $!
|
74
69
|
@template, @sub_templates = template, nil
|
75
70
|
end
|
76
71
|
|
77
|
-
def original_exception
|
78
|
-
ActiveSupport::Deprecation.warn("#original_exception is deprecated. Use #cause instead.", caller)
|
79
|
-
cause
|
80
|
-
end
|
81
|
-
|
82
72
|
def file_name
|
83
73
|
@template.identifier
|
84
74
|
end
|
@@ -130,7 +120,7 @@ module ActionView
|
|
130
120
|
if line_number
|
131
121
|
"on line ##{line_number} of "
|
132
122
|
else
|
133
|
-
|
123
|
+
"in "
|
134
124
|
end + file_name
|
135
125
|
end
|
136
126
|
|
@@ -2,10 +2,10 @@ module ActionView #:nodoc:
|
|
2
2
|
# = Action View Template Handlers
|
3
3
|
class Template
|
4
4
|
module Handlers #:nodoc:
|
5
|
-
autoload :Raw,
|
6
|
-
autoload :ERB,
|
7
|
-
autoload :Html,
|
8
|
-
autoload :Builder,
|
5
|
+
autoload :Raw, "action_view/template/handlers/raw"
|
6
|
+
autoload :ERB, "action_view/template/handlers/erb"
|
7
|
+
autoload :Html, "action_view/template/handlers/html"
|
8
|
+
autoload :Builder, "action_view/template/handlers/builder"
|
9
9
|
|
10
10
|
def self.extended(base)
|
11
11
|
base.register_default_template_handler :raw, Raw.new
|
@@ -7,20 +7,20 @@ module ActionView
|
|
7
7
|
|
8
8
|
def call(template)
|
9
9
|
require_engine
|
10
|
-
"xml = ::Builder::XmlMarkup.new(:indent => 2);"
|
10
|
+
"xml = ::Builder::XmlMarkup.new(:indent => 2);" \
|
11
11
|
"self.output_buffer = xml.target!;" +
|
12
12
|
template.source +
|
13
13
|
";xml.target!;"
|
14
14
|
end
|
15
15
|
|
16
|
-
|
16
|
+
private
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
def require_engine # :doc:
|
19
|
+
@required ||= begin
|
20
|
+
require "builder"
|
21
|
+
true
|
22
|
+
end
|
22
23
|
end
|
23
|
-
end
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
@@ -1,87 +1,20 @@
|
|
1
|
-
require 'erubis'
|
2
|
-
|
3
1
|
module ActionView
|
4
2
|
class Template
|
5
3
|
module Handlers
|
6
|
-
|
7
|
-
def add_preamble(src)
|
8
|
-
@newline_pending = 0
|
9
|
-
src << "@output_buffer = output_buffer || ActionView::OutputBuffer.new;"
|
10
|
-
end
|
11
|
-
|
12
|
-
def add_text(src, text)
|
13
|
-
return if text.empty?
|
14
|
-
|
15
|
-
if text == "\n"
|
16
|
-
@newline_pending += 1
|
17
|
-
else
|
18
|
-
src << "@output_buffer.safe_append='"
|
19
|
-
src << "\n" * @newline_pending if @newline_pending > 0
|
20
|
-
src << escape_text(text)
|
21
|
-
src << "'.freeze;"
|
22
|
-
|
23
|
-
@newline_pending = 0
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
# Erubis toggles <%= and <%== behavior when escaping is enabled.
|
28
|
-
# We override to always treat <%== as escaped.
|
29
|
-
def add_expr(src, code, indicator)
|
30
|
-
case indicator
|
31
|
-
when '=='
|
32
|
-
add_expr_escaped(src, code)
|
33
|
-
else
|
34
|
-
super
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
BLOCK_EXPR = /\s*((\s+|\))do|\{)(\s*\|[^|]*\|)?\s*\Z/
|
39
|
-
|
40
|
-
def add_expr_literal(src, code)
|
41
|
-
flush_newline_if_pending(src)
|
42
|
-
if code =~ BLOCK_EXPR
|
43
|
-
src << '@output_buffer.append= ' << code
|
44
|
-
else
|
45
|
-
src << '@output_buffer.append=(' << code << ');'
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def add_expr_escaped(src, code)
|
50
|
-
flush_newline_if_pending(src)
|
51
|
-
if code =~ BLOCK_EXPR
|
52
|
-
src << "@output_buffer.safe_expr_append= " << code
|
53
|
-
else
|
54
|
-
src << "@output_buffer.safe_expr_append=(" << code << ");"
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def add_stmt(src, code)
|
59
|
-
flush_newline_if_pending(src)
|
60
|
-
super
|
61
|
-
end
|
62
|
-
|
63
|
-
def add_postamble(src)
|
64
|
-
flush_newline_if_pending(src)
|
65
|
-
src << '@output_buffer.to_s'
|
66
|
-
end
|
67
|
-
|
68
|
-
def flush_newline_if_pending(src)
|
69
|
-
if @newline_pending > 0
|
70
|
-
src << "@output_buffer.safe_append='#{"\n" * @newline_pending}'.freeze;"
|
71
|
-
@newline_pending = 0
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
4
|
+
autoload :Erubis, "action_view/template/handlers/erb/deprecated_erubis"
|
75
5
|
|
76
6
|
class ERB
|
7
|
+
autoload :Erubi, "action_view/template/handlers/erb/erubi"
|
8
|
+
autoload :Erubis, "action_view/template/handlers/erb/erubis"
|
9
|
+
|
77
10
|
# Specify trim mode for the ERB compiler. Defaults to '-'.
|
78
11
|
# See ERB documentation for suitable values.
|
79
12
|
class_attribute :erb_trim_mode
|
80
|
-
self.erb_trim_mode =
|
13
|
+
self.erb_trim_mode = "-"
|
81
14
|
|
82
15
|
# Default implementation used.
|
83
16
|
class_attribute :erb_implementation
|
84
|
-
self.erb_implementation =
|
17
|
+
self.erb_implementation = Erubi
|
85
18
|
|
86
19
|
# Do not escape templates of these mime types.
|
87
20
|
class_attribute :escape_whitelist
|
@@ -108,7 +41,7 @@ module ActionView
|
|
108
41
|
# expression
|
109
42
|
template_source = template.source.dup.force_encoding(Encoding::ASCII_8BIT)
|
110
43
|
|
111
|
-
erb = template_source.gsub(ENCODING_TAG,
|
44
|
+
erb = template_source.gsub(ENCODING_TAG, "")
|
112
45
|
encoding = $2
|
113
46
|
|
114
47
|
erb.force_encoding valid_encoding(template.source.dup, encoding)
|
@@ -118,8 +51,8 @@ module ActionView
|
|
118
51
|
|
119
52
|
self.class.erb_implementation.new(
|
120
53
|
erb,
|
121
|
-
:
|
122
|
-
:
|
54
|
+
escape: (self.class.escape_whitelist.include? template.type),
|
55
|
+
trim: (self.class.erb_trim_mode == "-")
|
123
56
|
).src
|
124
57
|
end
|
125
58
|
|
@@ -0,0 +1,9 @@
|
|
1
|
+
::ActiveSupport::Deprecation.warn("ActionView::Template::Handlers::Erubis is deprecated and will be removed from Rails 5.2. Switch to ActionView::Template::Handlers::ERB::Erubi instead.")
|
2
|
+
|
3
|
+
module ActionView
|
4
|
+
class Template
|
5
|
+
module Handlers
|
6
|
+
Erubis = ERB::Erubis
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require "erubi"
|
2
|
+
|
3
|
+
module ActionView
|
4
|
+
class Template
|
5
|
+
module Handlers
|
6
|
+
class ERB
|
7
|
+
class Erubi < ::Erubi::Engine
|
8
|
+
# :nodoc: all
|
9
|
+
def initialize(input, properties = {})
|
10
|
+
@newline_pending = 0
|
11
|
+
|
12
|
+
# Dup properties so that we don't modify argument
|
13
|
+
properties = Hash[properties]
|
14
|
+
properties[:preamble] = "@output_buffer = output_buffer || ActionView::OutputBuffer.new;"
|
15
|
+
properties[:postamble] = "@output_buffer.to_s"
|
16
|
+
properties[:bufvar] = "@output_buffer"
|
17
|
+
properties[:escapefunc] = ""
|
18
|
+
|
19
|
+
super
|
20
|
+
end
|
21
|
+
|
22
|
+
def evaluate(action_view_erb_handler_context)
|
23
|
+
pr = eval("proc { #{@src} }", binding, @filename || "(erubi)")
|
24
|
+
action_view_erb_handler_context.instance_eval(&pr)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
def add_text(text)
|
29
|
+
return if text.empty?
|
30
|
+
|
31
|
+
if text == "\n"
|
32
|
+
@newline_pending += 1
|
33
|
+
else
|
34
|
+
src << "@output_buffer.safe_append='"
|
35
|
+
src << "\n" * @newline_pending if @newline_pending > 0
|
36
|
+
src << text.gsub(/['\\]/, '\\\\\&')
|
37
|
+
src << "'.freeze;"
|
38
|
+
|
39
|
+
@newline_pending = 0
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
BLOCK_EXPR = /\s*((\s+|\))do|\{)(\s*\|[^|]*\|)?\s*\Z/
|
44
|
+
|
45
|
+
def add_expression(indicator, code)
|
46
|
+
flush_newline_if_pending(src)
|
47
|
+
|
48
|
+
if (indicator == "==") || @escape
|
49
|
+
src << "@output_buffer.safe_expr_append="
|
50
|
+
else
|
51
|
+
src << "@output_buffer.append="
|
52
|
+
end
|
53
|
+
|
54
|
+
if BLOCK_EXPR.match?(code)
|
55
|
+
src << " " << code
|
56
|
+
else
|
57
|
+
src << "(" << code << ");"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def add_code(code)
|
62
|
+
flush_newline_if_pending(src)
|
63
|
+
super
|
64
|
+
end
|
65
|
+
|
66
|
+
def add_postamble(_)
|
67
|
+
flush_newline_if_pending(src)
|
68
|
+
super
|
69
|
+
end
|
70
|
+
|
71
|
+
def flush_newline_if_pending(src)
|
72
|
+
if @newline_pending > 0
|
73
|
+
src << "@output_buffer.safe_append='#{"\n" * @newline_pending}'.freeze;"
|
74
|
+
@newline_pending = 0
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
gem "erubis"
|
2
|
+
require "erubis"
|
3
|
+
|
4
|
+
module ActionView
|
5
|
+
class Template
|
6
|
+
module Handlers
|
7
|
+
class ERB
|
8
|
+
class Erubis < ::Erubis::Eruby
|
9
|
+
# :nodoc: all
|
10
|
+
def add_preamble(src)
|
11
|
+
@newline_pending = 0
|
12
|
+
src << "@output_buffer = output_buffer || ActionView::OutputBuffer.new;"
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_text(src, text)
|
16
|
+
return if text.empty?
|
17
|
+
|
18
|
+
if text == "\n"
|
19
|
+
@newline_pending += 1
|
20
|
+
else
|
21
|
+
src << "@output_buffer.safe_append='"
|
22
|
+
src << "\n" * @newline_pending if @newline_pending > 0
|
23
|
+
src << escape_text(text)
|
24
|
+
src << "'.freeze;"
|
25
|
+
|
26
|
+
@newline_pending = 0
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Erubis toggles <%= and <%== behavior when escaping is enabled.
|
31
|
+
# We override to always treat <%== as escaped.
|
32
|
+
def add_expr(src, code, indicator)
|
33
|
+
case indicator
|
34
|
+
when "=="
|
35
|
+
add_expr_escaped(src, code)
|
36
|
+
else
|
37
|
+
super
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
BLOCK_EXPR = /\s*((\s+|\))do|\{)(\s*\|[^|]*\|)?\s*\Z/
|
42
|
+
|
43
|
+
def add_expr_literal(src, code)
|
44
|
+
flush_newline_if_pending(src)
|
45
|
+
if BLOCK_EXPR.match?(code)
|
46
|
+
src << "@output_buffer.append= " << code
|
47
|
+
else
|
48
|
+
src << "@output_buffer.append=(" << code << ");"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def add_expr_escaped(src, code)
|
53
|
+
flush_newline_if_pending(src)
|
54
|
+
if BLOCK_EXPR.match?(code)
|
55
|
+
src << "@output_buffer.safe_expr_append= " << code
|
56
|
+
else
|
57
|
+
src << "@output_buffer.safe_expr_append=(" << code << ");"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def add_stmt(src, code)
|
62
|
+
flush_newline_if_pending(src)
|
63
|
+
super
|
64
|
+
end
|
65
|
+
|
66
|
+
def add_postamble(src)
|
67
|
+
flush_newline_if_pending(src)
|
68
|
+
src << "@output_buffer.to_s"
|
69
|
+
end
|
70
|
+
|
71
|
+
def flush_newline_if_pending(src)
|
72
|
+
if @newline_pending > 0
|
73
|
+
src << "@output_buffer.safe_append='#{"\n" * @newline_pending}'.freeze;"
|
74
|
+
@newline_pending = 0
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -37,15 +37,15 @@ module ActionView
|
|
37
37
|
class Cache #:nodoc:
|
38
38
|
class SmallCache < Concurrent::Map
|
39
39
|
def initialize(options = {})
|
40
|
-
super(options.merge(:
|
40
|
+
super(options.merge(initial_capacity: 2))
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
44
|
# preallocate all the default blocks for performance/memory consumption reasons
|
45
|
-
PARTIAL_BLOCK = lambda {|cache, partial| cache[partial] = SmallCache.new}
|
46
|
-
PREFIX_BLOCK = lambda {|cache, prefix| cache[prefix] = SmallCache.new(&PARTIAL_BLOCK)}
|
47
|
-
NAME_BLOCK = lambda {|cache, name| cache[name] = SmallCache.new(&PREFIX_BLOCK)}
|
48
|
-
KEY_BLOCK = lambda {|cache, key| cache[key] = SmallCache.new(&NAME_BLOCK)}
|
45
|
+
PARTIAL_BLOCK = lambda { |cache, partial| cache[partial] = SmallCache.new }
|
46
|
+
PREFIX_BLOCK = lambda { |cache, prefix| cache[prefix] = SmallCache.new(&PARTIAL_BLOCK) }
|
47
|
+
NAME_BLOCK = lambda { |cache, name| cache[name] = SmallCache.new(&PREFIX_BLOCK) }
|
48
|
+
KEY_BLOCK = lambda { |cache, key| cache[key] = SmallCache.new(&NAME_BLOCK) }
|
49
49
|
|
50
50
|
# usually a majority of template look ups return nothing, use this canonical preallocated array to save memory
|
51
51
|
NO_TEMPLATES = [].freeze
|
@@ -88,24 +88,41 @@ module ActionView
|
|
88
88
|
@query_cache.clear
|
89
89
|
end
|
90
90
|
|
91
|
-
|
91
|
+
# Get the cache size. Do not call this
|
92
|
+
# method. This method is not guaranteed to be here ever.
|
93
|
+
def size # :nodoc:
|
94
|
+
size = 0
|
95
|
+
@data.each_value do |v1|
|
96
|
+
v1.each_value do |v2|
|
97
|
+
v2.each_value do |v3|
|
98
|
+
v3.each_value do |v4|
|
99
|
+
size += v4.size
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
92
104
|
|
93
|
-
|
94
|
-
templates.empty? ? NO_TEMPLATES : templates
|
105
|
+
size + @query_cache.size
|
95
106
|
end
|
96
107
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
return fresh_templates.blank? != cached_templates.blank?
|
108
|
+
private
|
109
|
+
|
110
|
+
def canonical_no_templates(templates)
|
111
|
+
templates.empty? ? NO_TEMPLATES : templates
|
102
112
|
end
|
103
113
|
|
104
|
-
|
114
|
+
def templates_have_changed?(cached_templates, fresh_templates)
|
115
|
+
# if either the old or new template list is empty, we don't need to (and can't)
|
116
|
+
# compare modification times, and instead just check whether the lists are different
|
117
|
+
if cached_templates.blank? || fresh_templates.blank?
|
118
|
+
return fresh_templates.blank? != cached_templates.blank?
|
119
|
+
end
|
105
120
|
|
106
|
-
|
107
|
-
|
108
|
-
|
121
|
+
cached_templates_max_updated_at = cached_templates.map(&:updated_at).max
|
122
|
+
|
123
|
+
# if a template has changed, it will be now be newer than all the cached templates
|
124
|
+
fresh_templates.any? { |t| t.updated_at > cached_templates_max_updated_at }
|
125
|
+
end
|
109
126
|
end
|
110
127
|
|
111
128
|
cattr_accessor :caching
|
@@ -124,13 +141,13 @@ module ActionView
|
|
124
141
|
end
|
125
142
|
|
126
143
|
# Normalizes the arguments and passes it on to find_templates.
|
127
|
-
def find_all(name, prefix=nil, partial=false, details={}, key=nil, locals=[])
|
144
|
+
def find_all(name, prefix = nil, partial = false, details = {}, key = nil, locals = [])
|
128
145
|
cached(key, [name, prefix, partial], details, locals) do
|
129
146
|
find_templates(name, prefix, partial, details)
|
130
147
|
end
|
131
148
|
end
|
132
149
|
|
133
|
-
def find_all_anywhere(name, prefix, partial=false, details={}, key=nil, locals=[])
|
150
|
+
def find_all_anywhere(name, prefix, partial = false, details = {}, key = nil, locals = [])
|
134
151
|
cached(key, [name, prefix, partial], details, locals) do
|
135
152
|
find_templates(name, prefix, partial, details, true)
|
136
153
|
end
|
@@ -160,7 +177,7 @@ module ActionView
|
|
160
177
|
# always check the cache before hitting the resolver. Otherwise,
|
161
178
|
# it always hits the resolver but if the key is present, check if the
|
162
179
|
# resolver is fresher before returning it.
|
163
|
-
def cached(key, path_info, details, locals)
|
180
|
+
def cached(key, path_info, details, locals)
|
164
181
|
name, prefix, partial = path_info
|
165
182
|
locals = locals.map(&:to_s).sort!
|
166
183
|
|
@@ -174,7 +191,7 @@ module ActionView
|
|
174
191
|
end
|
175
192
|
|
176
193
|
# Ensures all the resolver information is set in the template.
|
177
|
-
def decorate(templates, path_info, details, locals)
|
194
|
+
def decorate(templates, path_info, details, locals)
|
178
195
|
cached = nil
|
179
196
|
templates.each do |t|
|
180
197
|
t.locals = locals
|
@@ -187,103 +204,103 @@ module ActionView
|
|
187
204
|
|
188
205
|
# An abstract class that implements a Resolver with path semantics.
|
189
206
|
class PathResolver < Resolver #:nodoc:
|
190
|
-
EXTENSIONS = { :
|
207
|
+
EXTENSIONS = { locale: ".", formats: ".", variants: "+", handlers: "." }
|
191
208
|
DEFAULT_PATTERN = ":prefix/:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}"
|
192
209
|
|
193
|
-
def initialize(pattern=nil)
|
210
|
+
def initialize(pattern = nil)
|
194
211
|
@pattern = pattern || DEFAULT_PATTERN
|
195
212
|
super()
|
196
213
|
end
|
197
214
|
|
198
215
|
private
|
199
216
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
217
|
+
def find_templates(name, prefix, partial, details, outside_app_allowed = false)
|
218
|
+
path = Path.build(name, prefix, partial)
|
219
|
+
query(path, details, details[:formats], outside_app_allowed)
|
220
|
+
end
|
204
221
|
|
205
|
-
|
206
|
-
|
222
|
+
def query(path, details, formats, outside_app_allowed)
|
223
|
+
query = build_query(path, details)
|
207
224
|
|
208
|
-
|
209
|
-
|
225
|
+
template_paths = find_template_paths(query)
|
226
|
+
template_paths = reject_files_external_to_app(template_paths) unless outside_app_allowed
|
210
227
|
|
211
|
-
|
212
|
-
|
213
|
-
|
228
|
+
template_paths.map do |template|
|
229
|
+
handler, format, variant = extract_handler_and_format_and_variant(template)
|
230
|
+
contents = File.binread(template)
|
214
231
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
232
|
+
Template.new(contents, File.expand_path(template), handler,
|
233
|
+
virtual_path: path.virtual,
|
234
|
+
format: format,
|
235
|
+
variant: variant,
|
236
|
+
updated_at: mtime(template)
|
237
|
+
)
|
238
|
+
end
|
221
239
|
end
|
222
|
-
end
|
223
240
|
|
224
|
-
|
225
|
-
|
226
|
-
|
241
|
+
def reject_files_external_to_app(files)
|
242
|
+
files.reject { |filename| !inside_path?(@path, filename) }
|
243
|
+
end
|
227
244
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
245
|
+
def find_template_paths(query)
|
246
|
+
Dir[query].uniq.reject do |filename|
|
247
|
+
File.directory?(filename) ||
|
248
|
+
# deals with case-insensitive file systems.
|
249
|
+
!File.fnmatch(query, filename, File::FNM_EXTGLOB)
|
250
|
+
end
|
233
251
|
end
|
234
|
-
end
|
235
252
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
253
|
+
def inside_path?(path, filename)
|
254
|
+
filename = File.expand_path(filename)
|
255
|
+
path = File.join(path, "")
|
256
|
+
filename.start_with?(path)
|
257
|
+
end
|
241
258
|
|
242
|
-
|
243
|
-
|
244
|
-
|
259
|
+
# Helper for building query glob string based on resolver's pattern.
|
260
|
+
def build_query(path, details)
|
261
|
+
query = @pattern.dup
|
245
262
|
|
246
|
-
|
247
|
-
|
263
|
+
prefix = path.prefix.empty? ? "" : "#{escape_entry(path.prefix)}\\1"
|
264
|
+
query.gsub!(/:prefix(\/)?/, prefix)
|
248
265
|
|
249
|
-
|
250
|
-
|
266
|
+
partial = escape_entry(path.partial? ? "_#{path.name}" : path.name)
|
267
|
+
query.gsub!(/:action/, partial)
|
251
268
|
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
269
|
+
details.each do |ext, candidates|
|
270
|
+
if ext == :variants && candidates == :any
|
271
|
+
query.gsub!(/:#{ext}/, "*")
|
272
|
+
else
|
273
|
+
query.gsub!(/:#{ext}/, "{#{candidates.compact.uniq.join(',')}}")
|
274
|
+
end
|
257
275
|
end
|
258
|
-
end
|
259
276
|
|
260
|
-
|
261
|
-
|
277
|
+
File.expand_path(query, @path)
|
278
|
+
end
|
262
279
|
|
263
|
-
|
264
|
-
|
265
|
-
|
280
|
+
def escape_entry(entry)
|
281
|
+
entry.gsub(/[*?{}\[\]]/, '\\\\\\&'.freeze)
|
282
|
+
end
|
266
283
|
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
284
|
+
# Returns the file mtime from the filesystem.
|
285
|
+
def mtime(p)
|
286
|
+
File.mtime(p)
|
287
|
+
end
|
271
288
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
289
|
+
# Extract handler, formats and variant from path. If a format cannot be found neither
|
290
|
+
# from the path, or the handler, we should return the array of formats given
|
291
|
+
# to the resolver.
|
292
|
+
def extract_handler_and_format_and_variant(path)
|
293
|
+
pieces = File.basename(path).split(".".freeze)
|
294
|
+
pieces.shift
|
278
295
|
|
279
|
-
|
296
|
+
extension = pieces.pop
|
280
297
|
|
281
|
-
|
282
|
-
|
283
|
-
|
298
|
+
handler = Template.handler_for_extension(extension)
|
299
|
+
format, variant = pieces.last.split(EXTENSIONS[:variants], 2) if pieces.last
|
300
|
+
format &&= Template::Types[format]
|
284
301
|
|
285
|
-
|
286
|
-
|
302
|
+
[handler, format, variant]
|
303
|
+
end
|
287
304
|
end
|
288
305
|
|
289
306
|
# A resolver that loads files from the filesystem. It allows setting your own
|
@@ -325,7 +342,7 @@ module ActionView
|
|
325
342
|
# * <tt>:handlers</tt> - possible handlers (for example erb, haml, builder...)
|
326
343
|
#
|
327
344
|
class FileSystemResolver < PathResolver
|
328
|
-
def initialize(path, pattern=nil)
|
345
|
+
def initialize(path, pattern = nil)
|
329
346
|
raise ArgumentError, "path already is a Resolver class" if path.is_a?(Resolver)
|
330
347
|
super(pattern)
|
331
348
|
@path = File.expand_path(path)
|