actionview 5.2.3 → 6.0.1
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 +203 -67
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -2
- data/lib/action_view.rb +3 -2
- data/lib/action_view/base.rb +107 -10
- data/lib/action_view/buffers.rb +15 -0
- data/lib/action_view/cache_expiry.rb +54 -0
- data/lib/action_view/context.rb +5 -9
- data/lib/action_view/digestor.rb +12 -20
- data/lib/action_view/gem_version.rb +3 -3
- data/lib/action_view/helpers.rb +0 -2
- data/lib/action_view/helpers/asset_tag_helper.rb +7 -30
- data/lib/action_view/helpers/asset_url_helper.rb +4 -3
- data/lib/action_view/helpers/cache_helper.rb +18 -10
- data/lib/action_view/helpers/capture_helper.rb +4 -0
- data/lib/action_view/helpers/csp_helper.rb +4 -2
- data/lib/action_view/helpers/csrf_helper.rb +1 -1
- data/lib/action_view/helpers/date_helper.rb +69 -25
- data/lib/action_view/helpers/form_helper.rb +240 -8
- data/lib/action_view/helpers/form_options_helper.rb +27 -18
- data/lib/action_view/helpers/form_tag_helper.rb +14 -9
- data/lib/action_view/helpers/javascript_helper.rb +9 -8
- data/lib/action_view/helpers/number_helper.rb +5 -0
- data/lib/action_view/helpers/output_safety_helper.rb +1 -1
- data/lib/action_view/helpers/rendering_helper.rb +6 -4
- data/lib/action_view/helpers/sanitize_helper.rb +12 -18
- data/lib/action_view/helpers/tag_helper.rb +7 -6
- data/lib/action_view/helpers/tags/base.rb +9 -5
- data/lib/action_view/helpers/tags/color_field.rb +1 -1
- data/lib/action_view/helpers/tags/translator.rb +1 -6
- data/lib/action_view/helpers/text_helper.rb +3 -3
- data/lib/action_view/helpers/translation_helper.rb +16 -12
- data/lib/action_view/helpers/url_helper.rb +15 -15
- data/lib/action_view/layouts.rb +5 -5
- data/lib/action_view/log_subscriber.rb +6 -6
- data/lib/action_view/lookup_context.rb +73 -31
- data/lib/action_view/path_set.rb +5 -10
- data/lib/action_view/railtie.rb +24 -1
- data/lib/action_view/record_identifier.rb +2 -2
- data/lib/action_view/renderer/abstract_renderer.rb +56 -3
- data/lib/action_view/renderer/partial_renderer.rb +66 -55
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +62 -16
- data/lib/action_view/renderer/renderer.rb +16 -4
- data/lib/action_view/renderer/streaming_template_renderer.rb +5 -5
- data/lib/action_view/renderer/template_renderer.rb +24 -18
- data/lib/action_view/rendering.rb +51 -31
- data/lib/action_view/routing_url_for.rb +12 -11
- data/lib/action_view/template.rb +102 -70
- data/lib/action_view/template/error.rb +21 -1
- data/lib/action_view/template/handlers.rb +27 -1
- data/lib/action_view/template/handlers/builder.rb +2 -2
- data/lib/action_view/template/handlers/erb.rb +17 -7
- data/lib/action_view/template/handlers/erb/erubi.rb +7 -3
- data/lib/action_view/template/handlers/html.rb +1 -1
- data/lib/action_view/template/handlers/raw.rb +2 -2
- data/lib/action_view/template/html.rb +14 -5
- data/lib/action_view/template/inline.rb +22 -0
- data/lib/action_view/template/raw_file.rb +28 -0
- data/lib/action_view/template/resolver.rb +136 -133
- data/lib/action_view/template/sources.rb +13 -0
- data/lib/action_view/template/sources/file.rb +17 -0
- data/lib/action_view/template/text.rb +5 -3
- data/lib/action_view/test_case.rb +1 -1
- data/lib/action_view/testing/resolvers.rb +33 -20
- data/lib/action_view/unbound_template.rb +32 -0
- data/lib/action_view/view_paths.rb +25 -1
- data/lib/assets/compiled/rails-ujs.js +33 -7
- metadata +26 -18
- data/lib/action_view/helpers/record_tag_helper.rb +0 -23
@@ -19,10 +19,14 @@ module ActionView
|
|
19
19
|
|
20
20
|
# Main render entry point shared by Action View and Action Controller.
|
21
21
|
def render(context, options)
|
22
|
+
render_to_object(context, options).body
|
23
|
+
end
|
24
|
+
|
25
|
+
def render_to_object(context, options) # :nodoc:
|
22
26
|
if options.key?(:partial)
|
23
|
-
|
27
|
+
render_partial_to_object(context, options)
|
24
28
|
else
|
25
|
-
|
29
|
+
render_template_to_object(context, options)
|
26
30
|
end
|
27
31
|
end
|
28
32
|
|
@@ -41,16 +45,24 @@ module ActionView
|
|
41
45
|
|
42
46
|
# Direct access to template rendering.
|
43
47
|
def render_template(context, options) #:nodoc:
|
44
|
-
|
48
|
+
render_template_to_object(context, options).body
|
45
49
|
end
|
46
50
|
|
47
51
|
# Direct access to partial rendering.
|
48
52
|
def render_partial(context, options, &block) #:nodoc:
|
49
|
-
|
53
|
+
render_partial_to_object(context, options, &block).body
|
50
54
|
end
|
51
55
|
|
52
56
|
def cache_hits # :nodoc:
|
53
57
|
@cache_hits ||= {}
|
54
58
|
end
|
59
|
+
|
60
|
+
def render_template_to_object(context, options) #:nodoc:
|
61
|
+
TemplateRenderer.new(@lookup_context).render(context, options)
|
62
|
+
end
|
63
|
+
|
64
|
+
def render_partial_to_object(context, options, &block) #:nodoc:
|
65
|
+
PartialRenderer.new(@lookup_context).render(context, options, block)
|
66
|
+
end
|
55
67
|
end
|
56
68
|
end
|
@@ -33,8 +33,8 @@ module ActionView
|
|
33
33
|
logger = ActionView::Base.logger
|
34
34
|
return unless logger
|
35
35
|
|
36
|
-
message = "\n#{exception.class} (#{exception.message}):\n"
|
37
|
-
message << exception.
|
36
|
+
message = +"\n#{exception.class} (#{exception.message}):\n"
|
37
|
+
message << exception.annotated_source_code.to_s if exception.respond_to?(:annotated_source_code)
|
38
38
|
message << " " << exception.backtrace.join("\n ")
|
39
39
|
logger.fatal("#{message}\n\n")
|
40
40
|
end
|
@@ -43,14 +43,14 @@ module ActionView
|
|
43
43
|
# For streaming, instead of rendering a given a template, we return a Body
|
44
44
|
# object that responds to each. This object is initialized with a block
|
45
45
|
# that knows how to render the template.
|
46
|
-
def render_template(template, layout_name = nil, locals = {}) #:nodoc:
|
47
|
-
return [super] unless layout_name && template.supports_streaming?
|
46
|
+
def render_template(view, template, layout_name = nil, locals = {}) #:nodoc:
|
47
|
+
return [super.body] unless layout_name && template.supports_streaming?
|
48
48
|
|
49
49
|
locals ||= {}
|
50
50
|
layout = layout_name && find_layout(layout_name, locals.keys, [formats.first])
|
51
51
|
|
52
52
|
Body.new do |buffer|
|
53
|
-
delayed_render(buffer, template, layout,
|
53
|
+
delayed_render(buffer, template, layout, view, locals)
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
@@ -5,15 +5,12 @@ require "active_support/core_ext/object/try"
|
|
5
5
|
module ActionView
|
6
6
|
class TemplateRenderer < AbstractRenderer #:nodoc:
|
7
7
|
def render(context, options)
|
8
|
-
@view = context
|
9
8
|
@details = extract_details(options)
|
10
9
|
template = determine_template(options)
|
11
10
|
|
12
|
-
prepend_formats(template.
|
11
|
+
prepend_formats(template.format)
|
13
12
|
|
14
|
-
|
15
|
-
|
16
|
-
render_template(template, options[:layout], options[:locals])
|
13
|
+
render_template(context, template, options[:layout], options[:locals] || {})
|
17
14
|
end
|
18
15
|
|
19
16
|
private
|
@@ -29,15 +26,25 @@ module ActionView
|
|
29
26
|
elsif options.key?(:html)
|
30
27
|
Template::HTML.new(options[:html], formats.first)
|
31
28
|
elsif options.key?(:file)
|
32
|
-
|
29
|
+
if File.exist?(options[:file])
|
30
|
+
Template::RawFile.new(options[:file])
|
31
|
+
else
|
32
|
+
ActiveSupport::Deprecation.warn "render file: should be given the absolute path to a file"
|
33
|
+
@lookup_context.with_fallbacks.find_template(options[:file], nil, false, keys, @details)
|
34
|
+
end
|
33
35
|
elsif options.key?(:inline)
|
34
36
|
handler = Template.handler_for_extension(options[:type] || "erb")
|
35
|
-
|
37
|
+
format = if handler.respond_to?(:default_format)
|
38
|
+
handler.default_format
|
39
|
+
else
|
40
|
+
@lookup_context.formats.first
|
41
|
+
end
|
42
|
+
Template::Inline.new(options[:inline], "inline template", handler, locals: keys, format: format)
|
36
43
|
elsif options.key?(:template)
|
37
44
|
if options[:template].respond_to?(:render)
|
38
45
|
options[:template]
|
39
46
|
else
|
40
|
-
find_template(options[:template], options[:prefixes], false, keys, @details)
|
47
|
+
@lookup_context.find_template(options[:template], options[:prefixes], false, keys, @details)
|
41
48
|
end
|
42
49
|
else
|
43
50
|
raise ArgumentError, "You invoked render but did not give any of :partial, :template, :inline, :file, :plain, :html or :body option."
|
@@ -46,27 +53,25 @@ module ActionView
|
|
46
53
|
|
47
54
|
# Renders the given template. A string representing the layout can be
|
48
55
|
# supplied as well.
|
49
|
-
def render_template(template, layout_name
|
50
|
-
view,
|
51
|
-
|
52
|
-
render_with_layout(layout_name, locals) do |layout|
|
56
|
+
def render_template(view, template, layout_name, locals)
|
57
|
+
render_with_layout(view, template, layout_name, locals) do |layout|
|
53
58
|
instrument(:template, identifier: template.identifier, layout: layout.try(:virtual_path)) do
|
54
59
|
template.render(view, locals) { |*name| view._layout_for(*name) }
|
55
60
|
end
|
56
61
|
end
|
57
62
|
end
|
58
63
|
|
59
|
-
def render_with_layout(path, locals)
|
64
|
+
def render_with_layout(view, template, path, locals)
|
60
65
|
layout = path && find_layout(path, locals.keys, [formats.first])
|
61
66
|
content = yield(layout)
|
62
67
|
|
63
|
-
if layout
|
64
|
-
view = @view
|
68
|
+
body = if layout
|
65
69
|
view.view_flow.set(:layout, content)
|
66
70
|
layout.render(view, locals) { |*name| view._layout_for(*name) }
|
67
71
|
else
|
68
72
|
content
|
69
73
|
end
|
74
|
+
build_rendered_template(body, template, layout)
|
70
75
|
end
|
71
76
|
|
72
77
|
# This is the method which actually finds the layout using details in the lookup
|
@@ -84,16 +89,17 @@ module ActionView
|
|
84
89
|
when String
|
85
90
|
begin
|
86
91
|
if layout.start_with?("/")
|
87
|
-
|
92
|
+
ActiveSupport::Deprecation.warn "Rendering layouts from an absolute path is deprecated."
|
93
|
+
@lookup_context.with_fallbacks.find_template(layout, nil, false, [], details)
|
88
94
|
else
|
89
|
-
find_template(layout, nil, false, [], details)
|
95
|
+
@lookup_context.find_template(layout, nil, false, [], details)
|
90
96
|
end
|
91
97
|
rescue ActionView::MissingTemplate
|
92
98
|
all_details = @details.merge(formats: @lookup_context.default_formats)
|
93
99
|
raise unless template_exists?(layout, nil, false, [], all_details)
|
94
100
|
end
|
95
101
|
when Proc
|
96
|
-
resolve_layout(layout.call(formats), keys, formats)
|
102
|
+
resolve_layout(layout.call(@lookup_context, formats), keys, formats)
|
97
103
|
else
|
98
104
|
layout
|
99
105
|
end
|
@@ -26,6 +26,13 @@ module ActionView
|
|
26
26
|
extend ActiveSupport::Concern
|
27
27
|
include ActionView::ViewPaths
|
28
28
|
|
29
|
+
attr_reader :rendered_format
|
30
|
+
|
31
|
+
def initialize
|
32
|
+
@rendered_format = nil
|
33
|
+
super
|
34
|
+
end
|
35
|
+
|
29
36
|
# Overwrite process to setup I18n proxy.
|
30
37
|
def process(*) #:nodoc:
|
31
38
|
old_config, I18n.config = I18n.config, I18nProxy.new(I18n.config, lookup_context)
|
@@ -35,47 +42,59 @@ module ActionView
|
|
35
42
|
end
|
36
43
|
|
37
44
|
module ClassMethods
|
38
|
-
def
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
45
|
+
def _routes
|
46
|
+
end
|
47
|
+
|
48
|
+
def _helpers
|
49
|
+
end
|
50
|
+
|
51
|
+
def build_view_context_class(klass, supports_path, routes, helpers)
|
52
|
+
Class.new(klass) do
|
53
|
+
if routes
|
54
|
+
include routes.url_helpers(supports_path)
|
55
|
+
include routes.mounted_helpers
|
56
|
+
end
|
57
|
+
|
58
|
+
if helpers
|
59
|
+
include helpers
|
53
60
|
end
|
54
61
|
end
|
55
62
|
end
|
56
|
-
end
|
57
63
|
|
58
|
-
|
64
|
+
def view_context_class
|
65
|
+
klass = ActionView::LookupContext::DetailsKey.view_context_class(ActionView::Base)
|
66
|
+
|
67
|
+
@view_context_class ||= build_view_context_class(klass, supports_path?, _routes, _helpers)
|
68
|
+
|
69
|
+
if klass.changed?(@view_context_class)
|
70
|
+
@view_context_class = build_view_context_class(klass, supports_path?, _routes, _helpers)
|
71
|
+
end
|
72
|
+
|
73
|
+
@view_context_class
|
74
|
+
end
|
75
|
+
end
|
59
76
|
|
60
77
|
def view_context_class
|
61
|
-
|
78
|
+
self.class.view_context_class
|
62
79
|
end
|
63
80
|
|
64
81
|
# An instance of a view class. The default view class is ActionView::Base.
|
65
82
|
#
|
66
83
|
# The view class must have the following methods:
|
67
|
-
#
|
68
|
-
#
|
69
|
-
#
|
70
|
-
#
|
84
|
+
#
|
85
|
+
# * <tt>View.new(lookup_context, assigns, controller)</tt> — Create a new
|
86
|
+
# ActionView instance for a controller and we can also pass the arguments.
|
87
|
+
#
|
88
|
+
# * <tt>View#render(option)</tt> — Returns String with the rendered template.
|
71
89
|
#
|
72
90
|
# Override this method in a module to change the default behavior.
|
73
91
|
def view_context
|
74
|
-
view_context_class.new(
|
92
|
+
view_context_class.new(lookup_context, view_assigns, self)
|
75
93
|
end
|
76
94
|
|
77
95
|
# Returns an object that is able to render templates.
|
78
96
|
def view_renderer # :nodoc:
|
97
|
+
# Lifespan: Per controller
|
79
98
|
@_view_renderer ||= ActionView::Renderer.new(lookup_context)
|
80
99
|
end
|
81
100
|
|
@@ -84,10 +103,6 @@ module ActionView
|
|
84
103
|
_render_template(options)
|
85
104
|
end
|
86
105
|
|
87
|
-
def rendered_format
|
88
|
-
Template::Types[lookup_context.rendered_format]
|
89
|
-
end
|
90
|
-
|
91
106
|
private
|
92
107
|
|
93
108
|
# Find and render a template based on the options given.
|
@@ -97,17 +112,22 @@ module ActionView
|
|
97
112
|
context = view_context
|
98
113
|
|
99
114
|
context.assign assigns if assigns
|
100
|
-
lookup_context.rendered_format = nil if options[:formats]
|
101
115
|
lookup_context.variants = variant if variant
|
102
116
|
|
103
|
-
|
117
|
+
rendered_template = context.in_rendering_context(options) do |renderer|
|
118
|
+
renderer.render_to_object(context, options)
|
119
|
+
end
|
120
|
+
|
121
|
+
rendered_format = rendered_template.format || lookup_context.formats.first
|
122
|
+
@rendered_format = Template::Types[rendered_format]
|
123
|
+
|
124
|
+
rendered_template.body
|
104
125
|
end
|
105
126
|
|
106
127
|
# Assign the rendered format to look up context.
|
107
128
|
def _process_format(format)
|
108
129
|
super
|
109
|
-
lookup_context.formats = [format.to_sym]
|
110
|
-
lookup_context.rendered_format = lookup_context.formats.first
|
130
|
+
lookup_context.formats = [format.to_sym] if format.to_sym
|
111
131
|
end
|
112
132
|
|
113
133
|
# Normalize args by converting render "foo" to render :action => "foo" and
|
@@ -84,25 +84,24 @@ module ActionView
|
|
84
84
|
super(only_path: _generate_paths_by_default)
|
85
85
|
when Hash
|
86
86
|
options = options.symbolize_keys
|
87
|
-
|
88
|
-
options[:only_path] = only_path?(options[:host])
|
89
|
-
end
|
87
|
+
ensure_only_path_option(options)
|
90
88
|
|
91
89
|
super(options)
|
92
90
|
when ActionController::Parameters
|
93
|
-
|
94
|
-
options[:only_path] = only_path?(options[:host])
|
95
|
-
end
|
91
|
+
ensure_only_path_option(options)
|
96
92
|
|
97
93
|
super(options)
|
98
94
|
when :back
|
99
95
|
_back_url
|
100
96
|
when Array
|
101
97
|
components = options.dup
|
102
|
-
|
103
|
-
|
98
|
+
options = components.extract_options!
|
99
|
+
ensure_only_path_option(options)
|
100
|
+
|
101
|
+
if options[:only_path]
|
102
|
+
polymorphic_path(components, options)
|
104
103
|
else
|
105
|
-
polymorphic_url(components,
|
104
|
+
polymorphic_url(components, options)
|
106
105
|
end
|
107
106
|
else
|
108
107
|
method = _generate_paths_by_default ? :path : :url
|
@@ -138,8 +137,10 @@ module ActionView
|
|
138
137
|
true
|
139
138
|
end
|
140
139
|
|
141
|
-
def
|
142
|
-
|
140
|
+
def ensure_only_path_option(options)
|
141
|
+
unless options.key?(:only_path)
|
142
|
+
options[:only_path] = _generate_paths_by_default unless options[:host]
|
143
|
+
end
|
143
144
|
end
|
144
145
|
end
|
145
146
|
end
|
data/lib/action_view/template.rb
CHANGED
@@ -2,13 +2,23 @@
|
|
2
2
|
|
3
3
|
require "active_support/core_ext/object/try"
|
4
4
|
require "active_support/core_ext/kernel/singleton_class"
|
5
|
+
require "active_support/deprecation"
|
5
6
|
require "thread"
|
7
|
+
require "delegate"
|
6
8
|
|
7
9
|
module ActionView
|
8
10
|
# = Action View Template
|
9
11
|
class Template
|
10
12
|
extend ActiveSupport::Autoload
|
11
13
|
|
14
|
+
def self.finalize_compiled_template_methods
|
15
|
+
ActiveSupport::Deprecation.warn "ActionView::Template.finalize_compiled_template_methods is deprecated and has no effect"
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.finalize_compiled_template_methods=(_)
|
19
|
+
ActiveSupport::Deprecation.warn "ActionView::Template.finalize_compiled_template_methods= is deprecated and has no effect"
|
20
|
+
end
|
21
|
+
|
12
22
|
# === Encodings in ActionView::Template
|
13
23
|
#
|
14
24
|
# ActionView::Template is one of a few sources of potential
|
@@ -103,44 +113,60 @@ module ActionView
|
|
103
113
|
|
104
114
|
eager_autoload do
|
105
115
|
autoload :Error
|
116
|
+
autoload :RawFile
|
106
117
|
autoload :Handlers
|
107
118
|
autoload :HTML
|
119
|
+
autoload :Inline
|
120
|
+
autoload :Sources
|
108
121
|
autoload :Text
|
109
122
|
autoload :Types
|
110
123
|
end
|
111
124
|
|
112
125
|
extend Template::Handlers
|
113
126
|
|
114
|
-
|
127
|
+
attr_reader :identifier, :handler, :original_encoding, :updated_at
|
128
|
+
attr_reader :variable, :format, :variant, :locals, :virtual_path
|
115
129
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
Finalizer = proc do |method_name, mod| # :nodoc:
|
121
|
-
proc do
|
122
|
-
mod.module_eval do
|
123
|
-
remove_possible_method method_name
|
124
|
-
end
|
130
|
+
def initialize(source, identifier, handler, format: nil, variant: nil, locals: nil, virtual_path: nil, updated_at: nil)
|
131
|
+
unless locals
|
132
|
+
ActiveSupport::Deprecation.warn "ActionView::Template#initialize requires a locals parameter"
|
133
|
+
locals = []
|
125
134
|
end
|
126
|
-
end
|
127
|
-
|
128
|
-
def initialize(source, identifier, handler, details)
|
129
|
-
format = details[:format] || (handler.default_format if handler.respond_to?(:default_format))
|
130
135
|
|
131
136
|
@source = source
|
132
137
|
@identifier = identifier
|
133
138
|
@handler = handler
|
134
139
|
@compiled = false
|
135
|
-
@
|
136
|
-
@
|
137
|
-
|
138
|
-
@
|
139
|
-
|
140
|
-
|
140
|
+
@locals = locals
|
141
|
+
@virtual_path = virtual_path
|
142
|
+
|
143
|
+
@variable = if @virtual_path
|
144
|
+
base = @virtual_path[-1] == "/" ? "" : ::File.basename(@virtual_path)
|
145
|
+
base =~ /\A_?(.*?)(?:\.\w+)*\z/
|
146
|
+
$1.to_sym
|
147
|
+
end
|
148
|
+
|
149
|
+
if updated_at
|
150
|
+
ActiveSupport::Deprecation.warn "ActionView::Template#updated_at is deprecated"
|
151
|
+
@updated_at = updated_at
|
152
|
+
else
|
153
|
+
@updated_at = Time.now
|
154
|
+
end
|
155
|
+
@format = format
|
156
|
+
@variant = variant
|
141
157
|
@compile_mutex = Mutex.new
|
142
158
|
end
|
143
159
|
|
160
|
+
deprecate :original_encoding
|
161
|
+
deprecate :updated_at
|
162
|
+
deprecate def virtual_path=(_); end
|
163
|
+
deprecate def locals=(_); end
|
164
|
+
deprecate def formats=(_); end
|
165
|
+
deprecate def formats; Array(format); end
|
166
|
+
deprecate def variants=(_); end
|
167
|
+
deprecate def variants; [variant]; end
|
168
|
+
deprecate def refresh(_); self; end
|
169
|
+
|
144
170
|
# Returns whether the underlying handler supports streaming. If so,
|
145
171
|
# a streaming buffer *may* be passed when it starts rendering.
|
146
172
|
def supports_streaming?
|
@@ -153,40 +179,29 @@ module ActionView
|
|
153
179
|
# This method is instrumented as "!render_template.action_view". Notice that
|
154
180
|
# we use a bang in this instrumentation because you don't want to
|
155
181
|
# consume this in production. This is only slow if it's being listened to.
|
156
|
-
def render(view, locals, buffer =
|
182
|
+
def render(view, locals, buffer = ActionView::OutputBuffer.new, &block)
|
157
183
|
instrument_render_template do
|
158
184
|
compile!(view)
|
159
|
-
view.
|
185
|
+
view._run(method_name, self, locals, buffer, &block)
|
160
186
|
end
|
161
187
|
rescue => e
|
162
188
|
handle_render_error(view, e)
|
163
189
|
end
|
164
190
|
|
165
191
|
def type
|
166
|
-
@type ||= Types[
|
192
|
+
@type ||= Types[format]
|
167
193
|
end
|
168
194
|
|
169
|
-
|
170
|
-
|
171
|
-
# This method is useful if you have a template object but it does not contain its source
|
172
|
-
# anymore since it was already compiled. In such cases, all you need to do is to call
|
173
|
-
# refresh passing in the view object.
|
174
|
-
#
|
175
|
-
# Notice this method raises an error if the template to be refreshed does not have a
|
176
|
-
# virtual path set (true just for inline templates).
|
177
|
-
def refresh(view)
|
178
|
-
raise "A template needs to have a virtual path in order to be refreshed" unless @virtual_path
|
179
|
-
lookup = view.lookup_context
|
180
|
-
pieces = @virtual_path.split("/")
|
181
|
-
name = pieces.pop
|
182
|
-
partial = !!name.sub!(/^_/, "")
|
183
|
-
lookup.disable_cache do
|
184
|
-
lookup.find_template(name, [ pieces.join("/") ], partial, @locals)
|
185
|
-
end
|
195
|
+
def short_identifier
|
196
|
+
@short_identifier ||= defined?(Rails.root) ? identifier.sub("#{Rails.root}/", "") : identifier
|
186
197
|
end
|
187
198
|
|
188
199
|
def inspect
|
189
|
-
|
200
|
+
"#<#{self.class.name} #{short_identifier} locals=#{@locals.inspect}>"
|
201
|
+
end
|
202
|
+
|
203
|
+
def source
|
204
|
+
@source.to_s
|
190
205
|
end
|
191
206
|
|
192
207
|
# This method is responsible for properly setting the encoding of the
|
@@ -200,7 +215,9 @@ module ActionView
|
|
200
215
|
# before passing the source on to the template engine, leaving a
|
201
216
|
# blank line in its stead.
|
202
217
|
def encode!
|
203
|
-
|
218
|
+
source = self.source
|
219
|
+
|
220
|
+
return source unless source.encoding == Encoding::BINARY
|
204
221
|
|
205
222
|
# Look for # encoding: *. If we find one, we'll encode the
|
206
223
|
# String in that encoding, otherwise, we'll use the
|
@@ -233,6 +250,19 @@ module ActionView
|
|
233
250
|
end
|
234
251
|
end
|
235
252
|
|
253
|
+
|
254
|
+
# Exceptions are marshalled when using the parallel test runner with DRb, so we need
|
255
|
+
# to ensure that references to the template object can be marshalled as well. This means forgoing
|
256
|
+
# the marshalling of the compiler mutex and instantiating that again on unmarshalling.
|
257
|
+
def marshal_dump # :nodoc:
|
258
|
+
[ @source, @identifier, @handler, @compiled, @locals, @virtual_path, @updated_at, @format, @variant ]
|
259
|
+
end
|
260
|
+
|
261
|
+
def marshal_load(array) # :nodoc:
|
262
|
+
@source, @identifier, @handler, @compiled, @locals, @virtual_path, @updated_at, @format, @variant = *array
|
263
|
+
@compile_mutex = Mutex.new
|
264
|
+
end
|
265
|
+
|
236
266
|
private
|
237
267
|
|
238
268
|
# Compile a template. This method ensures a template is compiled
|
@@ -249,23 +279,25 @@ module ActionView
|
|
249
279
|
# re-compilation
|
250
280
|
return if @compiled
|
251
281
|
|
252
|
-
|
253
|
-
mod = ActionView::CompiledTemplates
|
254
|
-
else
|
255
|
-
mod = view.singleton_class
|
256
|
-
end
|
282
|
+
mod = view.compiled_method_container
|
257
283
|
|
258
284
|
instrument("!compile_template") do
|
259
285
|
compile(mod)
|
260
286
|
end
|
261
287
|
|
262
|
-
# Just discard the source if we have a virtual path. This
|
263
|
-
# means we can get the template back.
|
264
|
-
@source = nil if @virtual_path
|
265
288
|
@compiled = true
|
266
289
|
end
|
267
290
|
end
|
268
291
|
|
292
|
+
class LegacyTemplate < DelegateClass(Template) # :nodoc:
|
293
|
+
attr_reader :source
|
294
|
+
|
295
|
+
def initialize(template, source)
|
296
|
+
super(template)
|
297
|
+
@source = source
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
269
301
|
# Among other things, this method is responsible for properly setting
|
270
302
|
# the encoding of the compiled template.
|
271
303
|
#
|
@@ -279,16 +311,15 @@ module ActionView
|
|
279
311
|
# In general, this means that templates will be UTF-8 inside of Rails,
|
280
312
|
# regardless of the original source encoding.
|
281
313
|
def compile(mod)
|
282
|
-
encode!
|
283
|
-
code = @handler.call(self)
|
314
|
+
source = encode!
|
315
|
+
code = @handler.call(self, source)
|
284
316
|
|
285
317
|
# Make sure that the resulting String to be eval'd is in the
|
286
318
|
# encoding of the code
|
287
|
-
|
319
|
+
original_source = source
|
320
|
+
source = +<<-end_src
|
288
321
|
def #{method_name}(local_assigns, output_buffer)
|
289
|
-
|
290
|
-
ensure
|
291
|
-
@virtual_path, @output_buffer = _old_virtual_path, _old_output_buffer
|
322
|
+
@virtual_path = #{@virtual_path.inspect};#{locals_code};#{code}
|
292
323
|
end
|
293
324
|
end_src
|
294
325
|
|
@@ -303,11 +334,17 @@ module ActionView
|
|
303
334
|
# handler is valid in the default_internal. This is for handlers
|
304
335
|
# that handle encoding but screw up
|
305
336
|
unless source.valid_encoding?
|
306
|
-
raise WrongEncodingError.new(
|
337
|
+
raise WrongEncodingError.new(source, Encoding.default_internal)
|
307
338
|
end
|
308
339
|
|
309
|
-
|
310
|
-
|
340
|
+
begin
|
341
|
+
mod.module_eval(source, identifier, 0)
|
342
|
+
rescue SyntaxError
|
343
|
+
# Account for when code in the template is not syntactically valid; e.g. if we're using
|
344
|
+
# ERB and the user writes <%= foo( %>, attempting to call a helper `foo` and interpolate
|
345
|
+
# the result into the template, but missing an end parenthesis.
|
346
|
+
raise SyntaxErrorInTemplate.new(self, original_source)
|
347
|
+
end
|
311
348
|
end
|
312
349
|
|
313
350
|
def handle_render_error(view, e)
|
@@ -315,12 +352,7 @@ module ActionView
|
|
315
352
|
e.sub_template_of(self)
|
316
353
|
raise e
|
317
354
|
else
|
318
|
-
|
319
|
-
unless template.source
|
320
|
-
template = refresh(view)
|
321
|
-
template.encode!
|
322
|
-
end
|
323
|
-
raise Template::Error.new(template)
|
355
|
+
raise Template::Error.new(self)
|
324
356
|
end
|
325
357
|
end
|
326
358
|
|
@@ -331,19 +363,19 @@ module ActionView
|
|
331
363
|
locals = locals.grep(/\A@?(?![A-Z0-9])(?:[[:alnum:]_]|[^\0-\177])+\z/)
|
332
364
|
|
333
365
|
# Assign for the same variable is to suppress unused variable warning
|
334
|
-
locals.each_with_object(""
|
366
|
+
locals.each_with_object(+"") { |key, code| code << "#{key} = local_assigns[:#{key}]; #{key} = #{key};" }
|
335
367
|
end
|
336
368
|
|
337
369
|
def method_name
|
338
370
|
@method_name ||= begin
|
339
|
-
m = "_#{identifier_method_name}__#{@identifier.hash}_#{__id__}"
|
340
|
-
m.tr!("-"
|
371
|
+
m = +"_#{identifier_method_name}__#{@identifier.hash}_#{__id__}"
|
372
|
+
m.tr!("-", "_")
|
341
373
|
m
|
342
374
|
end
|
343
375
|
end
|
344
376
|
|
345
377
|
def identifier_method_name
|
346
|
-
|
378
|
+
short_identifier.tr("^a-z_", "_")
|
347
379
|
end
|
348
380
|
|
349
381
|
def instrument(action, &block) # :doc:
|
@@ -351,7 +383,7 @@ module ActionView
|
|
351
383
|
end
|
352
384
|
|
353
385
|
def instrument_render_template(&block)
|
354
|
-
ActiveSupport::Notifications.instrument("!render_template.action_view"
|
386
|
+
ActiveSupport::Notifications.instrument("!render_template.action_view", instrument_payload, &block)
|
355
387
|
end
|
356
388
|
|
357
389
|
def instrument_payload
|