actionview 4.2.11.3 → 5.0.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 +136 -255
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -3
- data/lib/action_view.rb +1 -1
- data/lib/action_view/base.rb +14 -2
- data/lib/action_view/dependency_tracker.rb +46 -15
- data/lib/action_view/digestor.rb +13 -9
- data/lib/action_view/flows.rb +1 -1
- data/lib/action_view/gem_version.rb +4 -4
- data/lib/action_view/helpers/asset_tag_helper.rb +15 -5
- data/lib/action_view/helpers/asset_url_helper.rb +51 -12
- data/lib/action_view/helpers/atom_feed_helper.rb +5 -4
- data/lib/action_view/helpers/cache_helper.rb +75 -20
- data/lib/action_view/helpers/capture_helper.rb +3 -2
- data/lib/action_view/helpers/controller_helper.rb +1 -0
- data/lib/action_view/helpers/date_helper.rb +39 -10
- data/lib/action_view/helpers/debug_helper.rb +1 -1
- data/lib/action_view/helpers/form_helper.rb +81 -35
- data/lib/action_view/helpers/form_options_helper.rb +74 -35
- data/lib/action_view/helpers/form_tag_helper.rb +46 -19
- data/lib/action_view/helpers/javascript_helper.rb +4 -4
- data/lib/action_view/helpers/number_helper.rb +10 -12
- data/lib/action_view/helpers/record_tag_helper.rb +12 -99
- data/lib/action_view/helpers/rendering_helper.rb +2 -2
- data/lib/action_view/helpers/sanitize_helper.rb +1 -2
- data/lib/action_view/helpers/tag_helper.rb +20 -13
- data/lib/action_view/helpers/tags/base.rb +33 -28
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +2 -30
- data/lib/action_view/helpers/tags/collection_helpers.rb +28 -0
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +1 -9
- data/lib/action_view/helpers/tags/file_field.rb +15 -0
- data/lib/action_view/helpers/tags/label.rb +1 -1
- data/lib/action_view/helpers/tags/placeholderable.rb +1 -1
- data/lib/action_view/helpers/tags/search_field.rb +12 -9
- data/lib/action_view/helpers/tags/text_field.rb +0 -1
- data/lib/action_view/helpers/tags/translator.rb +1 -1
- data/lib/action_view/helpers/text_helper.rb +25 -9
- data/lib/action_view/helpers/translation_helper.rb +56 -26
- data/lib/action_view/helpers/url_helper.rb +40 -65
- data/lib/action_view/layouts.rb +11 -10
- data/lib/action_view/lookup_context.rb +14 -40
- data/lib/action_view/model_naming.rb +1 -1
- data/lib/action_view/path_set.rb +15 -18
- data/lib/action_view/railtie.rb +20 -3
- data/lib/action_view/record_identifier.rb +44 -19
- data/lib/action_view/renderer/abstract_renderer.rb +1 -1
- data/lib/action_view/renderer/partial_renderer.rb +27 -26
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +70 -0
- data/lib/action_view/renderer/renderer.rb +2 -6
- data/lib/action_view/renderer/streaming_template_renderer.rb +1 -1
- data/lib/action_view/renderer/template_renderer.rb +12 -11
- data/lib/action_view/rendering.rb +8 -5
- data/lib/action_view/routing_url_for.rb +18 -6
- data/lib/action_view/template.rb +50 -13
- data/lib/action_view/template/error.rb +14 -7
- data/lib/action_view/template/handlers.rb +3 -3
- data/lib/action_view/template/handlers/erb.rb +25 -0
- data/lib/action_view/template/handlers/raw.rb +1 -1
- data/lib/action_view/template/resolver.rb +36 -58
- data/lib/action_view/template/types.rb +1 -1
- data/lib/action_view/test_case.rb +13 -8
- data/lib/action_view/testing/resolvers.rb +3 -4
- data/lib/action_view/view_paths.rb +6 -22
- metadata +17 -14
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'active_support/core_ext/object/try'
|
2
|
+
|
3
|
+
module ActionView
|
4
|
+
module CollectionCaching # :nodoc:
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
# Fallback cache store if Action View is used without Rails.
|
9
|
+
# Otherwise overridden in Railtie to use Rails.cache.
|
10
|
+
mattr_accessor(:collection_cache) { ActiveSupport::Cache::MemoryStore.new }
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
def cache_collection_render
|
15
|
+
return yield unless cache_collection?
|
16
|
+
|
17
|
+
keyed_collection = collection_by_cache_keys
|
18
|
+
partial_cache = collection_cache.read_multi(*keyed_collection.keys)
|
19
|
+
|
20
|
+
@collection = keyed_collection.reject { |key, _| partial_cache.key?(key) }.values
|
21
|
+
rendered_partials = @collection.any? ? yield.dup : []
|
22
|
+
|
23
|
+
fetch_or_cache_partial(partial_cache, order_by: keyed_collection.each_key) do
|
24
|
+
rendered_partials.shift
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def cache_collection?
|
29
|
+
@options.fetch(:cache, automatic_cache_eligible?)
|
30
|
+
end
|
31
|
+
|
32
|
+
def automatic_cache_eligible?
|
33
|
+
single_template_render? && !callable_cache_key? &&
|
34
|
+
@template.eligible_for_collection_caching?(as: @options[:as])
|
35
|
+
end
|
36
|
+
|
37
|
+
def single_template_render?
|
38
|
+
@template # Template is only set when a collection renders one template.
|
39
|
+
end
|
40
|
+
|
41
|
+
def callable_cache_key?
|
42
|
+
@options[:cache].respond_to?(:call)
|
43
|
+
end
|
44
|
+
|
45
|
+
def collection_by_cache_keys
|
46
|
+
seed = callable_cache_key? ? @options[:cache] : ->(i) { i }
|
47
|
+
|
48
|
+
@collection.each_with_object({}) do |item, hash|
|
49
|
+
hash[expanded_cache_key(seed.call(item))] = item
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def expanded_cache_key(key)
|
54
|
+
key = @view.fragment_cache_key(@view.cache_fragment_name(key, virtual_path: @template.virtual_path))
|
55
|
+
key.frozen? ? key.dup : key # #read_multi & #write may require mutability, Dalli 2.6.0.
|
56
|
+
end
|
57
|
+
|
58
|
+
def fetch_or_cache_partial(cached_partials, order_by:)
|
59
|
+
cache_options = @options[:cache_options] || @locals[:cache_options] || {}
|
60
|
+
|
61
|
+
order_by.map do |key|
|
62
|
+
cached_partials.fetch(key) do
|
63
|
+
yield.tap do |rendered_partial|
|
64
|
+
collection_cache.write(key, rendered_partial, cache_options)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -15,12 +15,8 @@ module ActionView
|
|
15
15
|
@lookup_context = lookup_context
|
16
16
|
end
|
17
17
|
|
18
|
-
# Main render entry point shared by
|
18
|
+
# Main render entry point shared by Action View and Action Controller.
|
19
19
|
def render(context, options)
|
20
|
-
if options.respond_to?(:permitted?) && !options.permitted?
|
21
|
-
raise ArgumentError, "render parameters are not permitted"
|
22
|
-
end
|
23
|
-
|
24
20
|
if options.key?(:partial)
|
25
21
|
render_partial(context, options)
|
26
22
|
else
|
@@ -41,7 +37,7 @@ module ActionView
|
|
41
37
|
end
|
42
38
|
end
|
43
39
|
|
44
|
-
# Direct
|
40
|
+
# Direct access to template rendering.
|
45
41
|
def render_template(context, options) #:nodoc:
|
46
42
|
TemplateRenderer.new(@lookup_context).render(context, options)
|
47
43
|
end
|
@@ -47,7 +47,7 @@ module ActionView
|
|
47
47
|
return [super] unless layout_name && template.supports_streaming?
|
48
48
|
|
49
49
|
locals ||= {}
|
50
|
-
layout = layout_name && find_layout(layout_name, locals.keys)
|
50
|
+
layout = layout_name && find_layout(layout_name, locals.keys, [formats.first])
|
51
51
|
|
52
52
|
Body.new do |buffer|
|
53
53
|
delayed_render(buffer, template, layout, @view, locals)
|
@@ -29,7 +29,7 @@ module ActionView
|
|
29
29
|
elsif options.key?(:html)
|
30
30
|
Template::HTML.new(options[:html], formats.first)
|
31
31
|
elsif options.key?(:file)
|
32
|
-
with_fallbacks {
|
32
|
+
with_fallbacks { find_template(options[:file], nil, false, keys, @details) }
|
33
33
|
elsif options.key?(:inline)
|
34
34
|
handler = Template.handler_for_extension(options[:type] || "erb")
|
35
35
|
Template.new(options[:inline], "inline template", handler, :locals => keys)
|
@@ -40,7 +40,7 @@ module ActionView
|
|
40
40
|
find_template(options[:template], options[:prefixes], false, keys, @details)
|
41
41
|
end
|
42
42
|
else
|
43
|
-
raise ArgumentError, "You invoked render but did not give any of :partial, :template, :inline, :file, :plain, :text or :body option."
|
43
|
+
raise ArgumentError, "You invoked render but did not give any of :partial, :template, :inline, :file, :plain, :html, :text or :body option."
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
@@ -57,7 +57,7 @@ module ActionView
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def render_with_layout(path, locals) #:nodoc:
|
60
|
-
layout = path && find_layout(path, locals.keys)
|
60
|
+
layout = path && find_layout(path, locals.keys, [formats.first])
|
61
61
|
content = yield(layout)
|
62
62
|
|
63
63
|
if layout
|
@@ -72,27 +72,28 @@ module ActionView
|
|
72
72
|
# This is the method which actually finds the layout using details in the lookup
|
73
73
|
# context object. If no layout is found, it checks if at least a layout with
|
74
74
|
# the given name exists across all details before raising the error.
|
75
|
-
def find_layout(layout, keys)
|
76
|
-
|
75
|
+
def find_layout(layout, keys, formats)
|
76
|
+
resolve_layout(layout, keys, formats)
|
77
77
|
end
|
78
78
|
|
79
|
-
def resolve_layout(layout, keys)
|
79
|
+
def resolve_layout(layout, keys, formats)
|
80
|
+
details = @details.dup
|
81
|
+
details[:formats] = formats
|
82
|
+
|
80
83
|
case layout
|
81
84
|
when String
|
82
85
|
begin
|
83
86
|
if layout =~ /^\//
|
84
|
-
with_fallbacks { find_template(layout, nil, false, keys,
|
87
|
+
with_fallbacks { find_template(layout, nil, false, keys, details) }
|
85
88
|
else
|
86
|
-
find_template(layout, nil, false, keys,
|
89
|
+
find_template(layout, nil, false, keys, details)
|
87
90
|
end
|
88
91
|
rescue ActionView::MissingTemplate
|
89
92
|
all_details = @details.merge(:formats => @lookup_context.default_formats)
|
90
93
|
raise unless template_exists?(layout, nil, false, keys, all_details)
|
91
94
|
end
|
92
95
|
when Proc
|
93
|
-
resolve_layout(layout.call, keys)
|
94
|
-
when FalseClass
|
95
|
-
nil
|
96
|
+
resolve_layout(layout.call(formats), keys, formats)
|
96
97
|
else
|
97
98
|
layout
|
98
99
|
end
|
@@ -59,7 +59,7 @@ module ActionView
|
|
59
59
|
@_view_context_class ||= self.class.view_context_class
|
60
60
|
end
|
61
61
|
|
62
|
-
# An instance of a view class. The default view class is ActionView::Base
|
62
|
+
# An instance of a view class. The default view class is ActionView::Base.
|
63
63
|
#
|
64
64
|
# The view class must have the following methods:
|
65
65
|
# View.new[lookup_context, assigns, controller]
|
@@ -92,16 +92,19 @@ module ActionView
|
|
92
92
|
# Find and render a template based on the options given.
|
93
93
|
# :api: private
|
94
94
|
def _render_template(options) #:nodoc:
|
95
|
-
variant = options
|
95
|
+
variant = options.delete(:variant)
|
96
|
+
assigns = options.delete(:assigns)
|
97
|
+
context = view_context
|
96
98
|
|
99
|
+
context.assign assigns if assigns
|
97
100
|
lookup_context.rendered_format = nil if options[:formats]
|
98
101
|
lookup_context.variants = variant if variant
|
99
102
|
|
100
|
-
view_renderer.render(
|
103
|
+
view_renderer.render(context, options)
|
101
104
|
end
|
102
105
|
|
103
|
-
# Assign the rendered format to
|
104
|
-
def _process_format(format
|
106
|
+
# Assign the rendered format to look up context.
|
107
|
+
def _process_format(format) #:nodoc:
|
105
108
|
super
|
106
109
|
lookup_context.formats = [format.to_sym]
|
107
110
|
lookup_context.rendered_format = lookup_context.formats.first
|
@@ -32,7 +32,7 @@ module ActionView
|
|
32
32
|
#
|
33
33
|
# ==== Examples
|
34
34
|
# <%= url_for(action: 'index') %>
|
35
|
-
# # => /
|
35
|
+
# # => /blogs/
|
36
36
|
#
|
37
37
|
# <%= url_for(action: 'find', controller: 'books') %>
|
38
38
|
# # => /books/find
|
@@ -84,11 +84,13 @@ module ActionView
|
|
84
84
|
when Hash
|
85
85
|
options = options.symbolize_keys
|
86
86
|
unless options.key?(:only_path)
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
87
|
+
options[:only_path] = only_path?(options[:host])
|
88
|
+
end
|
89
|
+
|
90
|
+
super(options)
|
91
|
+
when ActionController::Parameters
|
92
|
+
unless options.key?(:only_path)
|
93
|
+
options[:only_path] = only_path?(options[:host])
|
92
94
|
end
|
93
95
|
|
94
96
|
super(options)
|
@@ -131,5 +133,15 @@ module ActionView
|
|
131
133
|
controller.optimize_routes_generation? : super
|
132
134
|
end
|
133
135
|
protected :optimize_routes_generation?
|
136
|
+
|
137
|
+
private
|
138
|
+
|
139
|
+
def _generate_paths_by_default
|
140
|
+
true
|
141
|
+
end
|
142
|
+
|
143
|
+
def only_path?(host)
|
144
|
+
_generate_paths_by_default unless host
|
145
|
+
end
|
134
146
|
end
|
135
147
|
end
|
data/lib/action_view/template.rb
CHANGED
@@ -87,6 +87,19 @@ module ActionView
|
|
87
87
|
# expected_encoding
|
88
88
|
# )
|
89
89
|
|
90
|
+
##
|
91
|
+
# :method: local_assigns
|
92
|
+
#
|
93
|
+
# Returns a hash with the defined local variables.
|
94
|
+
#
|
95
|
+
# Given this sub template rendering:
|
96
|
+
#
|
97
|
+
# <%= render "shared/header", { headline: "Welcome", person: person } %>
|
98
|
+
#
|
99
|
+
# You can use +local_assigns+ in the sub templates to access the local variables:
|
100
|
+
#
|
101
|
+
# local_assigns[:headline] # => "Welcome"
|
102
|
+
|
90
103
|
eager_autoload do
|
91
104
|
autoload :Error
|
92
105
|
autoload :Handlers
|
@@ -103,7 +116,7 @@ module ActionView
|
|
103
116
|
|
104
117
|
# This finalizer is needed (and exactly with a proc inside another proc)
|
105
118
|
# otherwise templates leak in development.
|
106
|
-
Finalizer = proc do |method_name, mod|
|
119
|
+
Finalizer = proc do |method_name, mod| # :nodoc:
|
107
120
|
proc do
|
108
121
|
mod.module_eval do
|
109
122
|
remove_possible_method method_name
|
@@ -117,6 +130,7 @@ module ActionView
|
|
117
130
|
@source = source
|
118
131
|
@identifier = identifier
|
119
132
|
@handler = handler
|
133
|
+
@cache_name = extract_resource_cache_name
|
120
134
|
@compiled = false
|
121
135
|
@original_encoding = nil
|
122
136
|
@locals = details[:locals] || []
|
@@ -127,7 +141,7 @@ module ActionView
|
|
127
141
|
@compile_mutex = Mutex.new
|
128
142
|
end
|
129
143
|
|
130
|
-
# Returns
|
144
|
+
# Returns whether the underlying handler supports streaming. If so,
|
131
145
|
# a streaming buffer *may* be passed when it start rendering.
|
132
146
|
def supports_streaming?
|
133
147
|
handler.respond_to?(:supports_streaming?) && handler.supports_streaming?
|
@@ -140,7 +154,7 @@ module ActionView
|
|
140
154
|
# we use a bang in this instrumentation because you don't want to
|
141
155
|
# consume this in production. This is only slow if it's being listened to.
|
142
156
|
def render(view, locals, buffer=nil, &block)
|
143
|
-
instrument("!render_template") do
|
157
|
+
instrument("!render_template".freeze) do
|
144
158
|
compile!(view)
|
145
159
|
view.send(method_name, locals, buffer, &block)
|
146
160
|
end
|
@@ -152,6 +166,10 @@ module ActionView
|
|
152
166
|
@type ||= Types[@formats.first] if @formats.first
|
153
167
|
end
|
154
168
|
|
169
|
+
def eligible_for_collection_caching?(as: nil)
|
170
|
+
@cache_name == (as || inferred_cache_name).to_s
|
171
|
+
end
|
172
|
+
|
155
173
|
# Receives a view object and return a template similar to self by using @virtual_path.
|
156
174
|
#
|
157
175
|
# This method is useful if you have a template object but it does not contain its source
|
@@ -172,7 +190,7 @@ module ActionView
|
|
172
190
|
end
|
173
191
|
|
174
192
|
def inspect
|
175
|
-
@inspect ||= defined?(Rails.root) ? identifier.sub("#{Rails.root}/", '') : identifier
|
193
|
+
@inspect ||= defined?(Rails.root) ? identifier.sub("#{Rails.root}/", ''.freeze) : identifier
|
176
194
|
end
|
177
195
|
|
178
196
|
# This method is responsible for properly setting the encoding of the
|
@@ -307,34 +325,53 @@ module ActionView
|
|
307
325
|
template = refresh(view)
|
308
326
|
template.encode!
|
309
327
|
end
|
310
|
-
raise Template::Error.new(template
|
328
|
+
raise Template::Error.new(template)
|
311
329
|
end
|
312
330
|
end
|
313
331
|
|
314
332
|
def locals_code #:nodoc:
|
315
|
-
# Only locals with valid variable names get set directly. Others will
|
316
|
-
# still be available in local_assigns.
|
317
|
-
locals = @locals.to_set - Module::DELEGATION_RESERVED_METHOD_NAMES
|
318
|
-
locals = locals.grep(/\A(?![A-Z0-9])(?:[[:alnum:]_]|[^\0-\177])+\z/)
|
319
333
|
# Double assign to suppress the dreaded 'assigned but unused variable' warning
|
320
|
-
locals.each_with_object('') { |key, code| code << "#{key} = #{key} = local_assigns[:#{key}];" }
|
334
|
+
@locals.each_with_object('') { |key, code| code << "#{key} = #{key} = local_assigns[:#{key}];" }
|
321
335
|
end
|
322
336
|
|
323
337
|
def method_name #:nodoc:
|
324
338
|
@method_name ||= begin
|
325
339
|
m = "_#{identifier_method_name}__#{@identifier.hash}_#{__id__}"
|
326
|
-
m.tr!('-', '_')
|
340
|
+
m.tr!('-'.freeze, '_'.freeze)
|
327
341
|
m
|
328
342
|
end
|
329
343
|
end
|
330
344
|
|
331
345
|
def identifier_method_name #:nodoc:
|
332
|
-
inspect.tr('^a-z_', '_')
|
346
|
+
inspect.tr('^a-z_'.freeze, '_'.freeze)
|
333
347
|
end
|
334
348
|
|
335
349
|
def instrument(action, &block)
|
336
350
|
payload = { virtual_path: @virtual_path, identifier: @identifier }
|
337
|
-
|
351
|
+
case action
|
352
|
+
when "!render_template".freeze
|
353
|
+
ActiveSupport::Notifications.instrument("!render_template.action_view".freeze, payload, &block)
|
354
|
+
else
|
355
|
+
ActiveSupport::Notifications.instrument("#{action}.action_view".freeze, payload, &block)
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
EXPLICIT_COLLECTION = /# Template Collection: (?<resource_name>\w+)/
|
360
|
+
|
361
|
+
def extract_resource_cache_name
|
362
|
+
if match = @source.match(EXPLICIT_COLLECTION) || resource_cache_call_match
|
363
|
+
match[:resource_name]
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
def resource_cache_call_match
|
368
|
+
if @handler.respond_to?(:resource_cache_call_pattern)
|
369
|
+
@source.match(@handler.resource_cache_call_pattern)
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
def inferred_cache_name
|
374
|
+
@inferred_cache_name ||= @virtual_path.split('/'.freeze).last.sub('_'.freeze, ''.freeze)
|
338
375
|
end
|
339
376
|
end
|
340
377
|
end
|
@@ -59,13 +59,20 @@ module ActionView
|
|
59
59
|
class Error < ActionViewError #:nodoc:
|
60
60
|
SOURCE_CODE_RADIUS = 3
|
61
61
|
|
62
|
-
|
62
|
+
def initialize(template, original_exception = nil)
|
63
|
+
if original_exception
|
64
|
+
ActiveSupport::Deprecation.warn("Passing #original_exception is deprecated and has no effect. " \
|
65
|
+
"Exceptions will automatically capture the original exception.", caller)
|
66
|
+
end
|
67
|
+
|
68
|
+
super($!.message)
|
69
|
+
set_backtrace($!.backtrace)
|
70
|
+
@template, @sub_templates = template, nil
|
71
|
+
end
|
63
72
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
@sub_templates = nil
|
68
|
-
set_backtrace(original_exception.backtrace)
|
73
|
+
def original_exception
|
74
|
+
ActiveSupport::Deprecation.warn("#original_exception is deprecated. Use #cause instead.", caller)
|
75
|
+
cause
|
69
76
|
end
|
70
77
|
|
71
78
|
def file_name
|
@@ -75,7 +82,7 @@ module ActionView
|
|
75
82
|
def sub_template_message
|
76
83
|
if @sub_templates
|
77
84
|
"Trace of template inclusion: " +
|
78
|
-
@sub_templates.collect
|
85
|
+
@sub_templates.collect(&:inspect).join(", ")
|
79
86
|
else
|
80
87
|
""
|
81
88
|
end
|
@@ -7,9 +7,9 @@ module ActionView #:nodoc:
|
|
7
7
|
autoload :Raw, 'action_view/template/handlers/raw'
|
8
8
|
|
9
9
|
def self.extended(base)
|
10
|
-
base.register_default_template_handler :
|
10
|
+
base.register_default_template_handler :raw, Raw.new
|
11
|
+
base.register_template_handler :erb, ERB.new
|
11
12
|
base.register_template_handler :builder, Builder.new
|
12
|
-
base.register_template_handler :raw, Raw.new
|
13
13
|
base.register_template_handler :ruby, :source.to_proc
|
14
14
|
end
|
15
15
|
|
@@ -42,7 +42,7 @@ module ActionView #:nodoc:
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def template_handler_extensions
|
45
|
-
@@template_handlers.keys.map
|
45
|
+
@@template_handlers.keys.map(&:to_s).sort
|
46
46
|
end
|
47
47
|
|
48
48
|
def registered_template_handler(extension)
|
@@ -123,6 +123,31 @@ module ActionView
|
|
123
123
|
).src
|
124
124
|
end
|
125
125
|
|
126
|
+
# Returns Regexp to extract a cached resource's name from a cache call at the
|
127
|
+
# first line of a template.
|
128
|
+
# The extracted cache name is captured as :resource_name.
|
129
|
+
#
|
130
|
+
# <% cache notification do %> # => notification
|
131
|
+
#
|
132
|
+
# The pattern should support templates with a beginning comment:
|
133
|
+
#
|
134
|
+
# <%# Still extractable even though there's a comment %>
|
135
|
+
# <% cache notification do %> # => notification
|
136
|
+
#
|
137
|
+
# But fail to extract a name if a resource association is cached.
|
138
|
+
#
|
139
|
+
# <% cache notification.event do %> # => nil
|
140
|
+
def resource_cache_call_pattern
|
141
|
+
/\A
|
142
|
+
(?:<%\#.*%>)* # optional initial comment
|
143
|
+
\s* # followed by optional spaces or newlines
|
144
|
+
<%\s*cache[\(\s] # followed by an ERB call to cache
|
145
|
+
\s* # followed by optional spaces or newlines
|
146
|
+
(?<resource_name>\w+) # capture the cache call argument as :resource_name
|
147
|
+
[\s\)] # followed by a space or close paren
|
148
|
+
/xm
|
149
|
+
end
|
150
|
+
|
126
151
|
private
|
127
152
|
|
128
153
|
def valid_encoding(string, encoding)
|