actionview 6.1.3.1 → 7.0.0.alpha1
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 +98 -261
- data/MIT-LICENSE +1 -1
- data/lib/action_view/base.rb +3 -3
- 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 +1 -1
- data/lib/action_view/helpers/asset_tag_helper.rb +85 -30
- data/lib/action_view/helpers/asset_url_helper.rb +7 -7
- data/lib/action_view/helpers/atom_feed_helper.rb +3 -4
- data/lib/action_view/helpers/cache_helper.rb +51 -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 +5 -5
- data/lib/action_view/helpers/debug_helper.rb +3 -1
- data/lib/action_view/helpers/form_helper.rb +72 -12
- data/lib/action_view/helpers/form_options_helper.rb +65 -33
- data/lib/action_view/helpers/form_tag_helper.rb +73 -30
- 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 +17 -4
- data/lib/action_view/helpers/tags/base.rb +2 -14
- data/lib/action_view/helpers/tags/check_box.rb +1 -1
- data/lib/action_view/helpers/tags/collection_select.rb +1 -1
- data/lib/action_view/helpers/tags/time_field.rb +10 -1
- data/lib/action_view/helpers/tags/weekday_select.rb +27 -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 +4 -3
- data/lib/action_view/helpers/url_helper.rb +122 -80
- data/lib/action_view/helpers.rb +25 -25
- data/lib/action_view/lookup_context.rb +33 -52
- data/lib/action_view/model_naming.rb +1 -1
- data/lib/action_view/path_set.rb +16 -22
- data/lib/action_view/railtie.rb +15 -2
- 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 +10 -1
- 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
- data/lib/assets/compiled/rails-ujs.js +2 -2
- metadata +22 -15
@@ -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
|
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,7 +41,17 @@ 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
|
+
ActionView::Helpers::AssetTagHelper.image_loading = app.config.action_view.delete(:image_loading)
|
52
|
+
ActionView::Helpers::AssetTagHelper.image_decoding = app.config.action_view.delete(:image_decoding)
|
41
53
|
ActionView::Helpers::AssetTagHelper.preload_links_header = app.config.action_view.delete(:preload_links_header)
|
54
|
+
ActionView::Helpers::AssetTagHelper.apply_stylesheet_media_default = app.config.action_view.delete(:apply_stylesheet_media_default)
|
42
55
|
end
|
43
56
|
|
44
57
|
config.after_initialize do |app|
|
@@ -46,7 +59,7 @@ module ActionView
|
|
46
59
|
app.config.action_view.each do |k, v|
|
47
60
|
if k == :raise_on_missing_translations
|
48
61
|
ActiveSupport::Deprecation.warn \
|
49
|
-
"action_view.raise_on_missing_translations is deprecated and will be removed in Rails
|
62
|
+
"action_view.raise_on_missing_translations is deprecated and will be removed in Rails 7.0. " \
|
50
63
|
"Set i18n.raise_on_missing_translations instead. " \
|
51
64
|
"Note that this new setting also affects how missing translations are handled in controllers."
|
52
65
|
end
|
@@ -85,7 +98,7 @@ module ActionView
|
|
85
98
|
end
|
86
99
|
|
87
100
|
unless enable_caching
|
88
|
-
app.executor.
|
101
|
+
app.executor.register_hook ActionView::CacheExpiry::Executor.new(watcher: app.config.file_watcher)
|
89
102
|
end
|
90
103
|
end
|
91
104
|
|
@@ -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
|