actionview 6.1.4.1 → 7.0.0.rc2
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 +4 -4
- data/CHANGELOG.md +189 -248
- data/MIT-LICENSE +1 -1
- data/lib/action_view/base.rb +4 -7
- data/lib/action_view/buffers.rb +2 -2
- data/lib/action_view/cache_expiry.rb +46 -32
- data/lib/action_view/dependency_tracker/erb_tracker.rb +154 -0
- data/lib/action_view/dependency_tracker/ripper_tracker.rb +59 -0
- data/lib/action_view/dependency_tracker.rb +6 -147
- data/lib/action_view/digestor.rb +7 -4
- data/lib/action_view/flows.rb +4 -4
- data/lib/action_view/gem_version.rb +4 -4
- data/lib/action_view/helpers/active_model_helper.rb +2 -2
- data/lib/action_view/helpers/asset_tag_helper.rb +84 -29
- data/lib/action_view/helpers/asset_url_helper.rb +9 -9
- data/lib/action_view/helpers/atom_feed_helper.rb +3 -4
- data/lib/action_view/helpers/cache_helper.rb +52 -3
- data/lib/action_view/helpers/capture_helper.rb +2 -2
- data/lib/action_view/helpers/controller_helper.rb +2 -2
- data/lib/action_view/helpers/csp_helper.rb +1 -1
- data/lib/action_view/helpers/csrf_helper.rb +1 -1
- data/lib/action_view/helpers/date_helper.rb +62 -7
- data/lib/action_view/helpers/debug_helper.rb +3 -1
- data/lib/action_view/helpers/form_helper.rb +190 -75
- data/lib/action_view/helpers/form_options_helper.rb +68 -33
- data/lib/action_view/helpers/form_tag_helper.rb +126 -36
- data/lib/action_view/helpers/javascript_helper.rb +3 -5
- data/lib/action_view/helpers/number_helper.rb +3 -4
- data/lib/action_view/helpers/output_safety_helper.rb +2 -2
- data/lib/action_view/helpers/rendering_helper.rb +1 -1
- data/lib/action_view/helpers/sanitize_helper.rb +2 -2
- data/lib/action_view/helpers/tag_helper.rb +34 -6
- data/lib/action_view/helpers/tags/base.rb +4 -24
- data/lib/action_view/helpers/tags/check_box.rb +2 -2
- data/lib/action_view/helpers/tags/collection_select.rb +1 -1
- data/lib/action_view/helpers/tags/hidden_field.rb +4 -0
- data/lib/action_view/helpers/tags/time_field.rb +10 -1
- data/lib/action_view/helpers/tags/weekday_select.rb +28 -0
- data/lib/action_view/helpers/tags.rb +3 -2
- data/lib/action_view/helpers/text_helper.rb +24 -13
- data/lib/action_view/helpers/translation_helper.rb +10 -41
- data/lib/action_view/helpers/url_helper.rb +166 -91
- data/lib/action_view/helpers.rb +25 -25
- data/lib/action_view/lookup_context.rb +33 -52
- data/lib/action_view/model_naming.rb +2 -2
- data/lib/action_view/path_set.rb +16 -22
- data/lib/action_view/railtie.rb +19 -7
- data/lib/action_view/render_parser.rb +188 -0
- data/lib/action_view/renderer/abstract_renderer.rb +2 -2
- data/lib/action_view/renderer/partial_renderer.rb +0 -34
- data/lib/action_view/renderer/renderer.rb +4 -4
- data/lib/action_view/renderer/streaming_template_renderer.rb +3 -3
- data/lib/action_view/renderer/template_renderer.rb +6 -2
- data/lib/action_view/rendering.rb +2 -2
- data/lib/action_view/ripper_ast_parser.rb +198 -0
- data/lib/action_view/routing_url_for.rb +1 -1
- data/lib/action_view/template/error.rb +108 -13
- data/lib/action_view/template/handlers/erb.rb +6 -0
- data/lib/action_view/template/handlers.rb +3 -3
- data/lib/action_view/template/html.rb +3 -3
- data/lib/action_view/template/inline.rb +3 -3
- data/lib/action_view/template/raw_file.rb +3 -3
- data/lib/action_view/template/resolver.rb +84 -311
- data/lib/action_view/template/text.rb +3 -3
- data/lib/action_view/template/types.rb +14 -12
- data/lib/action_view/template.rb +18 -2
- data/lib/action_view/template_details.rb +66 -0
- data/lib/action_view/template_path.rb +64 -0
- data/lib/action_view/test_case.rb +6 -2
- data/lib/action_view/testing/resolvers.rb +11 -12
- data/lib/action_view/unbound_template.rb +33 -7
- data/lib/action_view.rb +3 -4
- metadata +22 -14
@@ -12,12 +12,11 @@ module ActionView
|
|
12
12
|
# <tt>LookupContext</tt> is also responsible for generating a key, given to
|
13
13
|
# view paths, used in the resolver cache lookup. Since this key is generated
|
14
14
|
# only once during the request, it speeds up all cache accesses.
|
15
|
-
class LookupContext
|
15
|
+
class LookupContext # :nodoc:
|
16
16
|
attr_accessor :prefixes, :rendered_format
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
mattr_accessor :registered_details, default: []
|
18
|
+
singleton_class.attr_accessor :registered_details
|
19
|
+
self.registered_details = []
|
21
20
|
|
22
21
|
def self.register_detail(name, &block)
|
23
22
|
registered_details << name
|
@@ -37,7 +36,7 @@ module ActionView
|
|
37
36
|
end
|
38
37
|
|
39
38
|
# Holds accessors for the registered details.
|
40
|
-
module Accessors
|
39
|
+
module Accessors # :nodoc:
|
41
40
|
DEFAULT_PROCS = {}
|
42
41
|
end
|
43
42
|
|
@@ -52,7 +51,7 @@ module ActionView
|
|
52
51
|
register_detail(:variants) { [] }
|
53
52
|
register_detail(:handlers) { Template::Handlers.extensions }
|
54
53
|
|
55
|
-
class DetailsKey
|
54
|
+
class DetailsKey # :nodoc:
|
56
55
|
alias :eql? :equal?
|
57
56
|
|
58
57
|
@details_keys = Concurrent::Map.new
|
@@ -68,14 +67,13 @@ module ActionView
|
|
68
67
|
details = details.dup
|
69
68
|
details[:formats] &= Template::Types.symbols
|
70
69
|
end
|
71
|
-
@details_keys[details] ||=
|
70
|
+
@details_keys[details] ||= TemplateDetails::Requested.new(**details)
|
72
71
|
end
|
73
72
|
|
74
73
|
def self.clear
|
75
74
|
ActionView::ViewPaths.all_view_paths.each do |path_set|
|
76
75
|
path_set.each(&:clear_cache)
|
77
76
|
end
|
78
|
-
ActionView::LookupContext.fallbacks.each(&:clear_cache)
|
79
77
|
@view_context_class = nil
|
80
78
|
@details_keys.clear
|
81
79
|
@digest_cache.clear
|
@@ -98,7 +96,7 @@ module ActionView
|
|
98
96
|
|
99
97
|
# Calculate the details key. Remove the handlers from calculation to improve performance
|
100
98
|
# since the user cannot modify it explicitly.
|
101
|
-
def details_key
|
99
|
+
def details_key # :nodoc:
|
102
100
|
@details_key ||= DetailsKey.details_cache_key(@details) if @cache
|
103
101
|
end
|
104
102
|
|
@@ -124,39 +122,32 @@ module ActionView
|
|
124
122
|
attr_reader :view_paths, :html_fallback_for_js
|
125
123
|
|
126
124
|
def find(name, prefixes = [], partial = false, keys = [], options = {})
|
127
|
-
|
125
|
+
name, prefixes = normalize_name(name, prefixes)
|
126
|
+
details, details_key = detail_args_for(options)
|
127
|
+
@view_paths.find(name, prefixes, partial, details, details_key, keys)
|
128
128
|
end
|
129
129
|
alias :find_template :find
|
130
130
|
|
131
131
|
def find_all(name, prefixes = [], partial = false, keys = [], options = {})
|
132
|
-
|
132
|
+
name, prefixes = normalize_name(name, prefixes)
|
133
|
+
details, details_key = detail_args_for(options)
|
134
|
+
@view_paths.find_all(name, prefixes, partial, details, details_key, keys)
|
133
135
|
end
|
134
136
|
|
135
137
|
def exists?(name, prefixes = [], partial = false, keys = [], **options)
|
136
|
-
|
138
|
+
name, prefixes = normalize_name(name, prefixes)
|
139
|
+
details, details_key = detail_args_for(options)
|
140
|
+
@view_paths.exists?(name, prefixes, partial, details, details_key, keys)
|
137
141
|
end
|
138
142
|
alias :template_exists? :exists?
|
139
143
|
|
140
144
|
def any?(name, prefixes = [], partial = false)
|
141
|
-
|
145
|
+
name, prefixes = normalize_name(name, prefixes)
|
146
|
+
details, details_key = detail_args_for_any
|
147
|
+
@view_paths.exists?(name, prefixes, partial, details, details_key, [])
|
142
148
|
end
|
143
149
|
alias :any_templates? :any?
|
144
150
|
|
145
|
-
# Adds fallbacks to the view paths. Useful in cases when you are rendering
|
146
|
-
# a :file.
|
147
|
-
def with_fallbacks
|
148
|
-
view_paths = build_view_paths((@view_paths.paths + self.class.fallbacks).uniq)
|
149
|
-
|
150
|
-
if block_given?
|
151
|
-
raise ArgumentError, <<~eowarn.squish
|
152
|
-
Calling `with_fallbacks` with a block is not supported. Call methods on
|
153
|
-
the lookup context returned by `with_fallbacks` instead.
|
154
|
-
eowarn
|
155
|
-
else
|
156
|
-
ActionView::LookupContext.new(view_paths, @details, @prefixes)
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
151
|
private
|
161
152
|
# Whenever setting view paths, makes a copy so that we can manipulate them in
|
162
153
|
# instance objects as we wish.
|
@@ -164,12 +155,6 @@ module ActionView
|
|
164
155
|
ActionView::PathSet.new(Array(paths))
|
165
156
|
end
|
166
157
|
|
167
|
-
def args_for_lookup(name, prefixes, partial, keys, details_options)
|
168
|
-
name, prefixes = normalize_name(name, prefixes)
|
169
|
-
details, details_key = detail_args_for(details_options)
|
170
|
-
[name, prefixes, partial || false, details, details_key, keys]
|
171
|
-
end
|
172
|
-
|
173
158
|
# Compute details hash and key according to user options (e.g. passed from #render).
|
174
159
|
def detail_args_for(options) # :doc:
|
175
160
|
return @details, details_key if options.empty? # most common path.
|
@@ -184,17 +169,11 @@ module ActionView
|
|
184
169
|
[user_details, details_key]
|
185
170
|
end
|
186
171
|
|
187
|
-
def args_for_any(name, prefixes, partial)
|
188
|
-
name, prefixes = normalize_name(name, prefixes)
|
189
|
-
details, details_key = detail_args_for_any
|
190
|
-
[name, prefixes, partial || false, details, details_key]
|
191
|
-
end
|
192
|
-
|
193
172
|
def detail_args_for_any
|
194
173
|
@detail_args_for_any ||= begin
|
195
174
|
details = {}
|
196
175
|
|
197
|
-
registered_details.each do |k|
|
176
|
+
LookupContext.registered_details.each do |k|
|
198
177
|
if k == :variants
|
199
178
|
details[k] = :any
|
200
179
|
else
|
@@ -210,19 +189,21 @@ module ActionView
|
|
210
189
|
end
|
211
190
|
end
|
212
191
|
|
213
|
-
#
|
214
|
-
# as well as incorrectly putting part of the path in the template
|
215
|
-
# name instead of the prefix.
|
192
|
+
# Fix when prefix is specified as part of the template name
|
216
193
|
def normalize_name(name, prefixes)
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
name = parts.pop
|
194
|
+
name = name.to_s
|
195
|
+
idx = name.rindex("/")
|
196
|
+
return name, prefixes.presence || [""] unless idx
|
221
197
|
|
222
|
-
|
198
|
+
path_prefix = name[0, idx]
|
199
|
+
path_prefix = path_prefix.from(1) if path_prefix.start_with?("/")
|
200
|
+
name = name.from(idx + 1)
|
223
201
|
|
224
|
-
|
225
|
-
|
202
|
+
if !prefixes || prefixes.empty?
|
203
|
+
prefixes = [path_prefix]
|
204
|
+
else
|
205
|
+
prefixes = prefixes.map { |p| "#{p}/#{path_prefix}" }
|
206
|
+
end
|
226
207
|
|
227
208
|
return name, prefixes
|
228
209
|
end
|
@@ -254,7 +235,7 @@ module ActionView
|
|
254
235
|
end
|
255
236
|
|
256
237
|
def initialize_details(target, details)
|
257
|
-
registered_details.each do |k|
|
238
|
+
LookupContext.registered_details.each do |k|
|
258
239
|
target[k] = details[k] || Accessors::DEFAULT_PROCS[k].call
|
259
240
|
end
|
260
241
|
target
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActionView
|
4
|
-
module ModelNaming
|
5
|
-
# Converts the given object to an
|
4
|
+
module ModelNaming # :nodoc:
|
5
|
+
# Converts the given object to an Active Model compliant one.
|
6
6
|
def convert_to_model(object)
|
7
7
|
object.respond_to?(:to_model) ? object.to_model : object
|
8
8
|
end
|
data/lib/action_view/path_set.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module ActionView
|
3
|
+
module ActionView # :nodoc:
|
4
4
|
# = Action View PathSet
|
5
5
|
#
|
6
6
|
# This class is used to store and access paths in Action View. A number of
|
@@ -8,7 +8,7 @@ module ActionView #:nodoc:
|
|
8
8
|
# set and also perform operations on other +PathSet+ objects.
|
9
9
|
#
|
10
10
|
# A +LookupContext+ will use a +PathSet+ to store the paths in its context.
|
11
|
-
class PathSet
|
11
|
+
class PathSet # :nodoc:
|
12
12
|
include Enumerable
|
13
13
|
|
14
14
|
attr_reader :paths
|
@@ -44,44 +44,38 @@ module ActionView #:nodoc:
|
|
44
44
|
METHOD
|
45
45
|
end
|
46
46
|
|
47
|
-
def find(
|
48
|
-
find_all(
|
47
|
+
def find(path, prefixes, partial, details, details_key, locals)
|
48
|
+
find_all(path, prefixes, partial, details, details_key, locals).first ||
|
49
|
+
raise(MissingTemplate.new(self, path, prefixes, partial, details, details_key, locals))
|
49
50
|
end
|
50
51
|
|
51
|
-
def find_all(path, prefixes
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
def exists?(path, prefixes, *args)
|
56
|
-
find_all(path, prefixes, *args).any?
|
57
|
-
end
|
58
|
-
|
59
|
-
def find_all_with_query(query) # :nodoc:
|
60
|
-
paths.each do |resolver|
|
61
|
-
templates = resolver.find_all_with_query(query)
|
52
|
+
def find_all(path, prefixes, partial, details, details_key, locals)
|
53
|
+
search_combinations(prefixes) do |resolver, prefix|
|
54
|
+
templates = resolver.find_all(path, prefix, partial, details, details_key, locals)
|
62
55
|
return templates unless templates.empty?
|
63
56
|
end
|
64
|
-
|
65
57
|
[]
|
66
58
|
end
|
67
59
|
|
60
|
+
def exists?(path, prefixes, partial, details, details_key, locals)
|
61
|
+
find_all(path, prefixes, partial, details, details_key, locals).any?
|
62
|
+
end
|
63
|
+
|
68
64
|
private
|
69
|
-
def
|
70
|
-
prefixes =
|
65
|
+
def search_combinations(prefixes)
|
66
|
+
prefixes = Array(prefixes)
|
71
67
|
prefixes.each do |prefix|
|
72
68
|
paths.each do |resolver|
|
73
|
-
|
74
|
-
return templates unless templates.empty?
|
69
|
+
yield resolver, prefix
|
75
70
|
end
|
76
71
|
end
|
77
|
-
[]
|
78
72
|
end
|
79
73
|
|
80
74
|
def typecast(paths)
|
81
75
|
paths.map do |path|
|
82
76
|
case path
|
83
77
|
when Pathname, String
|
84
|
-
|
78
|
+
FileSystemResolver.new path.to_s
|
85
79
|
else
|
86
80
|
path
|
87
81
|
end
|
data/lib/action_view/railtie.rb
CHANGED
@@ -10,6 +10,9 @@ module ActionView
|
|
10
10
|
config.action_view.embed_authenticity_token_in_remote_forms = nil
|
11
11
|
config.action_view.debug_missing_translation = true
|
12
12
|
config.action_view.default_enforce_utf8 = nil
|
13
|
+
config.action_view.image_loading = nil
|
14
|
+
config.action_view.image_decoding = nil
|
15
|
+
config.action_view.apply_stylesheet_media_default = true
|
13
16
|
|
14
17
|
config.eager_load_namespaces << ActionView
|
15
18
|
|
@@ -38,18 +41,27 @@ module ActionView
|
|
38
41
|
end
|
39
42
|
|
40
43
|
config.after_initialize do |app|
|
44
|
+
button_to_generates_button_tag = app.config.action_view.delete(:button_to_generates_button_tag)
|
45
|
+
unless button_to_generates_button_tag.nil?
|
46
|
+
ActionView::Helpers::UrlHelper.button_to_generates_button_tag = button_to_generates_button_tag
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
config.after_initialize do |app|
|
51
|
+
frozen_string_literal = app.config.action_view.delete(:frozen_string_literal)
|
52
|
+
ActionView::Template.frozen_string_literal = frozen_string_literal
|
53
|
+
end
|
54
|
+
|
55
|
+
config.after_initialize do |app|
|
56
|
+
ActionView::Helpers::AssetTagHelper.image_loading = app.config.action_view.delete(:image_loading)
|
57
|
+
ActionView::Helpers::AssetTagHelper.image_decoding = app.config.action_view.delete(:image_decoding)
|
41
58
|
ActionView::Helpers::AssetTagHelper.preload_links_header = app.config.action_view.delete(:preload_links_header)
|
59
|
+
ActionView::Helpers::AssetTagHelper.apply_stylesheet_media_default = app.config.action_view.delete(:apply_stylesheet_media_default)
|
42
60
|
end
|
43
61
|
|
44
62
|
config.after_initialize do |app|
|
45
63
|
ActiveSupport.on_load(:action_view) do
|
46
64
|
app.config.action_view.each do |k, v|
|
47
|
-
if k == :raise_on_missing_translations
|
48
|
-
ActiveSupport::Deprecation.warn \
|
49
|
-
"action_view.raise_on_missing_translations is deprecated and will be removed in Rails 6.2. " \
|
50
|
-
"Set i18n.raise_on_missing_translations instead. " \
|
51
|
-
"Note that this new setting also affects how missing translations are handled in controllers."
|
52
|
-
end
|
53
65
|
send "#{k}=", v
|
54
66
|
end
|
55
67
|
end
|
@@ -85,7 +97,7 @@ module ActionView
|
|
85
97
|
end
|
86
98
|
|
87
99
|
unless enable_caching
|
88
|
-
app.executor.
|
100
|
+
app.executor.register_hook ActionView::CacheExpiry::Executor.new(watcher: app.config.file_watcher)
|
89
101
|
end
|
90
102
|
end
|
91
103
|
|
@@ -0,0 +1,188 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "action_view/ripper_ast_parser"
|
4
|
+
|
5
|
+
module ActionView
|
6
|
+
class RenderParser # :nodoc:
|
7
|
+
def initialize(name, code)
|
8
|
+
@name = name
|
9
|
+
@code = code
|
10
|
+
@parser = RipperASTParser
|
11
|
+
end
|
12
|
+
|
13
|
+
def render_calls
|
14
|
+
render_nodes = @parser.parse_render_nodes(@code)
|
15
|
+
|
16
|
+
render_nodes.map do |method, nodes|
|
17
|
+
nodes.map { |n| send(:parse_render, n) }
|
18
|
+
end.flatten.compact
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def directory
|
23
|
+
File.dirname(@name)
|
24
|
+
end
|
25
|
+
|
26
|
+
def resolve_path_directory(path)
|
27
|
+
if path.include?("/")
|
28
|
+
path
|
29
|
+
else
|
30
|
+
"#{directory}/#{path}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Convert
|
35
|
+
# render("foo", ...)
|
36
|
+
# into either
|
37
|
+
# render(template: "foo", ...)
|
38
|
+
# or
|
39
|
+
# render(partial: "foo", ...)
|
40
|
+
def normalize_args(string, options_hash)
|
41
|
+
if options_hash
|
42
|
+
{ partial: string, locals: options_hash }
|
43
|
+
else
|
44
|
+
{ partial: string }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def parse_render(node)
|
49
|
+
node = node.argument_nodes
|
50
|
+
|
51
|
+
if (node.length == 1 || node.length == 2) && !node[0].hash?
|
52
|
+
if node.length == 1
|
53
|
+
options = normalize_args(node[0], nil)
|
54
|
+
elsif node.length == 2
|
55
|
+
options = normalize_args(node[0], node[1])
|
56
|
+
end
|
57
|
+
|
58
|
+
return nil unless options
|
59
|
+
|
60
|
+
parse_render_from_options(options)
|
61
|
+
elsif node.length == 1 && node[0].hash?
|
62
|
+
options = parse_hash_to_symbols(node[0])
|
63
|
+
|
64
|
+
return nil unless options
|
65
|
+
|
66
|
+
parse_render_from_options(options)
|
67
|
+
else
|
68
|
+
nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def parse_hash(node)
|
73
|
+
node.hash? && node.to_hash
|
74
|
+
end
|
75
|
+
|
76
|
+
def parse_hash_to_symbols(node)
|
77
|
+
hash = parse_hash(node)
|
78
|
+
|
79
|
+
return unless hash
|
80
|
+
|
81
|
+
hash.transform_keys do |key_node|
|
82
|
+
key = parse_sym(key_node)
|
83
|
+
|
84
|
+
return unless key
|
85
|
+
|
86
|
+
key
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
ALL_KNOWN_KEYS = [:partial, :template, :layout, :formats, :locals, :object, :collection, :as, :status, :content_type, :location, :spacer_template]
|
91
|
+
|
92
|
+
RENDER_TYPE_KEYS =
|
93
|
+
[:partial, :template, :layout]
|
94
|
+
|
95
|
+
def parse_render_from_options(options_hash)
|
96
|
+
renders = []
|
97
|
+
keys = options_hash.keys
|
98
|
+
|
99
|
+
if (keys & RENDER_TYPE_KEYS).size < 1
|
100
|
+
# Must have at least one of render keys
|
101
|
+
return nil
|
102
|
+
end
|
103
|
+
|
104
|
+
if (keys - ALL_KNOWN_KEYS).any?
|
105
|
+
# de-opt in case of unknown option
|
106
|
+
return nil
|
107
|
+
end
|
108
|
+
|
109
|
+
render_type = (keys & RENDER_TYPE_KEYS)[0]
|
110
|
+
|
111
|
+
node = options_hash[render_type]
|
112
|
+
|
113
|
+
if node.string?
|
114
|
+
template = resolve_path_directory(node.to_string)
|
115
|
+
else
|
116
|
+
if node.variable_reference?
|
117
|
+
dependency = node.variable_name.sub(/\A(?:\$|@{1,2})/, "")
|
118
|
+
elsif node.vcall?
|
119
|
+
dependency = node.variable_name
|
120
|
+
elsif node.call?
|
121
|
+
dependency = node.call_method_name
|
122
|
+
else
|
123
|
+
return
|
124
|
+
end
|
125
|
+
|
126
|
+
object_template = true
|
127
|
+
template = "#{dependency.pluralize}/#{dependency.singularize}"
|
128
|
+
end
|
129
|
+
|
130
|
+
return unless template
|
131
|
+
|
132
|
+
if spacer_template = render_template_with_spacer?(options_hash)
|
133
|
+
virtual_path = partial_to_virtual_path(:partial, spacer_template)
|
134
|
+
renders << virtual_path
|
135
|
+
end
|
136
|
+
|
137
|
+
if options_hash.key?(:object) || options_hash.key?(:collection) || object_template
|
138
|
+
return nil if options_hash.key?(:object) && options_hash.key?(:collection)
|
139
|
+
return nil unless options_hash.key?(:partial)
|
140
|
+
end
|
141
|
+
|
142
|
+
virtual_path = partial_to_virtual_path(render_type, template)
|
143
|
+
renders << virtual_path
|
144
|
+
|
145
|
+
# Support for rendering multiple templates (i.e. a partial with a layout)
|
146
|
+
if layout_template = render_template_with_layout?(render_type, options_hash)
|
147
|
+
virtual_path = partial_to_virtual_path(:layout, layout_template)
|
148
|
+
|
149
|
+
renders << virtual_path
|
150
|
+
end
|
151
|
+
|
152
|
+
renders
|
153
|
+
end
|
154
|
+
|
155
|
+
def parse_str(node)
|
156
|
+
node.string? && node.to_string
|
157
|
+
end
|
158
|
+
|
159
|
+
def parse_sym(node)
|
160
|
+
node.symbol? && node.to_symbol
|
161
|
+
end
|
162
|
+
|
163
|
+
private
|
164
|
+
def render_template_with_layout?(render_type, options_hash)
|
165
|
+
if render_type != :layout && options_hash.key?(:layout)
|
166
|
+
parse_str(options_hash[:layout])
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def render_template_with_spacer?(options_hash)
|
171
|
+
if options_hash.key?(:spacer_template)
|
172
|
+
parse_str(options_hash[:spacer_template])
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def partial_to_virtual_path(render_type, partial_path)
|
177
|
+
if render_type == :partial || render_type == :layout
|
178
|
+
partial_path.gsub(%r{(/|^)([^/]*)\z}, '\1_\2')
|
179
|
+
else
|
180
|
+
partial_path
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def layout_to_virtual_path(layout_path)
|
185
|
+
"layouts/#{layout_path}"
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
@@ -18,7 +18,7 @@ module ActionView
|
|
18
18
|
# renderer object of the correct type is created, and the +render+ method on
|
19
19
|
# that new object is called in turn. This abstracts the set up and rendering
|
20
20
|
# into a separate classes for partials and templates.
|
21
|
-
class AbstractRenderer
|
21
|
+
class AbstractRenderer # :nodoc:
|
22
22
|
delegate :template_exists?, :any_templates?, :formats, to: :@lookup_context
|
23
23
|
|
24
24
|
def initialize(lookup_context)
|
@@ -158,7 +158,7 @@ module ActionView
|
|
158
158
|
|
159
159
|
def extract_details(options) # :doc:
|
160
160
|
details = nil
|
161
|
-
|
161
|
+
LookupContext.registered_details.each do |key|
|
162
162
|
value = options[key]
|
163
163
|
|
164
164
|
if value
|
@@ -217,40 +217,6 @@ module ActionView
|
|
217
217
|
# </div>
|
218
218
|
#
|
219
219
|
# As you can see, the <tt>:locals</tt> hash is shared between both the partial and its layout.
|
220
|
-
#
|
221
|
-
# If you pass arguments to "yield" then this will be passed to the block. One way to use this is to pass
|
222
|
-
# an array to layout and treat it as an enumerable.
|
223
|
-
#
|
224
|
-
# <%# app/views/users/_user.html.erb %>
|
225
|
-
# <div class="user">
|
226
|
-
# Budget: $<%= user.budget %>
|
227
|
-
# <%= yield user %>
|
228
|
-
# </div>
|
229
|
-
#
|
230
|
-
# <%# app/views/users/index.html.erb %>
|
231
|
-
# <%= render layout: @users do |user| %>
|
232
|
-
# Title: <%= user.title %>
|
233
|
-
# <% end %>
|
234
|
-
#
|
235
|
-
# This will render the layout for each user and yield to the block, passing the user, each time.
|
236
|
-
#
|
237
|
-
# You can also yield multiple times in one layout and use block arguments to differentiate the sections.
|
238
|
-
#
|
239
|
-
# <%# app/views/users/_user.html.erb %>
|
240
|
-
# <div class="user">
|
241
|
-
# <%= yield user, :header %>
|
242
|
-
# Budget: $<%= user.budget %>
|
243
|
-
# <%= yield user, :footer %>
|
244
|
-
# </div>
|
245
|
-
#
|
246
|
-
# <%# app/views/users/index.html.erb %>
|
247
|
-
# <%= render layout: @users do |user, section| %>
|
248
|
-
# <%- case section when :header -%>
|
249
|
-
# Title: <%= user.title %>
|
250
|
-
# <%- when :footer -%>
|
251
|
-
# Deadline: <%= user.deadline %>
|
252
|
-
# <%- end -%>
|
253
|
-
# <% end %>
|
254
220
|
class PartialRenderer < AbstractRenderer
|
255
221
|
include CollectionCaching
|
256
222
|
|
@@ -44,12 +44,12 @@ module ActionView
|
|
44
44
|
end
|
45
45
|
|
46
46
|
# Direct access to template rendering.
|
47
|
-
def render_template(context, options)
|
47
|
+
def render_template(context, options) # :nodoc:
|
48
48
|
render_template_to_object(context, options).body
|
49
49
|
end
|
50
50
|
|
51
51
|
# Direct access to partial rendering.
|
52
|
-
def render_partial(context, options, &block)
|
52
|
+
def render_partial(context, options, &block) # :nodoc:
|
53
53
|
render_partial_to_object(context, options, &block).body
|
54
54
|
end
|
55
55
|
|
@@ -57,11 +57,11 @@ module ActionView
|
|
57
57
|
@cache_hits ||= {}
|
58
58
|
end
|
59
59
|
|
60
|
-
def render_template_to_object(context, options)
|
60
|
+
def render_template_to_object(context, options) # :nodoc:
|
61
61
|
TemplateRenderer.new(@lookup_context).render(context, options)
|
62
62
|
end
|
63
63
|
|
64
|
-
def render_partial_to_object(context, options, &block)
|
64
|
+
def render_partial_to_object(context, options, &block) # :nodoc:
|
65
65
|
partial = options[:partial]
|
66
66
|
if String === partial
|
67
67
|
collection = collection_from_options(options)
|
@@ -7,11 +7,11 @@ module ActionView
|
|
7
7
|
#
|
8
8
|
# * Support streaming from child templates, partials and so on.
|
9
9
|
# * Rack::Cache needs to support streaming bodies
|
10
|
-
class StreamingTemplateRenderer < TemplateRenderer
|
10
|
+
class StreamingTemplateRenderer < TemplateRenderer # :nodoc:
|
11
11
|
# A valid Rack::Body (i.e. it responds to each).
|
12
12
|
# It is initialized with a block that, when called, starts
|
13
13
|
# rendering the template.
|
14
|
-
class Body
|
14
|
+
class Body # :nodoc:
|
15
15
|
def initialize(&start)
|
16
16
|
@start = start
|
17
17
|
end
|
@@ -42,7 +42,7 @@ module ActionView
|
|
42
42
|
# For streaming, instead of rendering a given a template, we return a Body
|
43
43
|
# object that responds to each. This object is initialized with a block
|
44
44
|
# that knows how to render the template.
|
45
|
-
def render_template(view, template, layout_name = nil, locals = {})
|
45
|
+
def render_template(view, template, layout_name = nil, locals = {}) # :nodoc:
|
46
46
|
return [super.body] unless layout_name && template.supports_streaming?
|
47
47
|
|
48
48
|
locals ||= {}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActionView
|
4
|
-
class TemplateRenderer < AbstractRenderer
|
4
|
+
class TemplateRenderer < AbstractRenderer # :nodoc:
|
5
5
|
def render(context, options)
|
6
6
|
@details = extract_details(options)
|
7
7
|
template = determine_template(options)
|
@@ -26,7 +26,11 @@ module ActionView
|
|
26
26
|
if File.exist?(options[:file])
|
27
27
|
Template::RawFile.new(options[:file])
|
28
28
|
else
|
29
|
-
|
29
|
+
if Pathname.new(options[:file]).absolute?
|
30
|
+
raise ArgumentError, "File #{options[:file]} does not exist"
|
31
|
+
else
|
32
|
+
raise ArgumentError, "`render file:` should be given the absolute path to a file. '#{options[:file]}' was given instead"
|
33
|
+
end
|
30
34
|
end
|
31
35
|
elsif options.key?(:inline)
|
32
36
|
handler = Template.handler_for_extension(options[:type] || "erb")
|
@@ -5,7 +5,7 @@ require "action_view/view_paths"
|
|
5
5
|
module ActionView
|
6
6
|
# This is a class to fix I18n global state. Whenever you provide I18n.locale during a request,
|
7
7
|
# it will trigger the lookup_context and consequently expire the cache.
|
8
|
-
class I18nProxy < ::I18n::Config
|
8
|
+
class I18nProxy < ::I18n::Config # :nodoc:
|
9
9
|
attr_reader :original_config, :lookup_context
|
10
10
|
|
11
11
|
def initialize(original_config, lookup_context)
|
@@ -34,7 +34,7 @@ module ActionView
|
|
34
34
|
end
|
35
35
|
|
36
36
|
# Overwrite process to set up I18n proxy.
|
37
|
-
def process(*)
|
37
|
+
def process(*) # :nodoc:
|
38
38
|
old_config, I18n.config = I18n.config, I18nProxy.new(I18n.config, lookup_context)
|
39
39
|
super
|
40
40
|
ensure
|