actionview 5.2.7.1 → 6.1.4.6
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 +250 -112
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -3
- data/lib/action_view/base.rb +81 -15
- data/lib/action_view/buffers.rb +15 -0
- data/lib/action_view/cache_expiry.rb +52 -0
- data/lib/action_view/context.rb +5 -9
- data/lib/action_view/dependency_tracker.rb +10 -4
- data/lib/action_view/digestor.rb +15 -22
- data/lib/action_view/flows.rb +0 -1
- data/lib/action_view/gem_version.rb +4 -4
- data/lib/action_view/helpers/active_model_helper.rb +0 -1
- data/lib/action_view/helpers/asset_tag_helper.rb +64 -47
- data/lib/action_view/helpers/asset_url_helper.rb +9 -6
- data/lib/action_view/helpers/atom_feed_helper.rb +2 -1
- data/lib/action_view/helpers/cache_helper.rb +23 -22
- 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 +73 -30
- data/lib/action_view/helpers/form_helper.rb +305 -37
- data/lib/action_view/helpers/form_options_helper.rb +23 -23
- data/lib/action_view/helpers/form_tag_helper.rb +19 -16
- data/lib/action_view/helpers/javascript_helper.rb +12 -11
- data/lib/action_view/helpers/number_helper.rb +14 -8
- data/lib/action_view/helpers/output_safety_helper.rb +1 -1
- data/lib/action_view/helpers/rendering_helper.rb +17 -7
- data/lib/action_view/helpers/sanitize_helper.rb +12 -18
- data/lib/action_view/helpers/tag_helper.rb +100 -55
- data/lib/action_view/helpers/tags/base.rb +18 -11
- data/lib/action_view/helpers/tags/check_box.rb +0 -1
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +0 -1
- data/lib/action_view/helpers/tags/collection_helpers.rb +0 -1
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +0 -1
- data/lib/action_view/helpers/tags/color_field.rb +1 -2
- data/lib/action_view/helpers/tags/date_field.rb +1 -2
- data/lib/action_view/helpers/tags/date_select.rb +2 -3
- data/lib/action_view/helpers/tags/datetime_field.rb +0 -1
- data/lib/action_view/helpers/tags/datetime_local_field.rb +1 -2
- data/lib/action_view/helpers/tags/label.rb +4 -1
- data/lib/action_view/helpers/tags/month_field.rb +1 -2
- data/lib/action_view/helpers/tags/radio_button.rb +0 -1
- data/lib/action_view/helpers/tags/select.rb +1 -2
- data/lib/action_view/helpers/tags/text_field.rb +0 -1
- data/lib/action_view/helpers/tags/time_field.rb +1 -2
- data/lib/action_view/helpers/tags/translator.rb +1 -6
- data/lib/action_view/helpers/tags/week_field.rb +1 -2
- data/lib/action_view/helpers/text_helper.rb +4 -5
- data/lib/action_view/helpers/translation_helper.rb +94 -54
- data/lib/action_view/helpers/url_helper.rb +136 -28
- data/lib/action_view/helpers.rb +0 -2
- data/lib/action_view/layouts.rb +8 -10
- data/lib/action_view/log_subscriber.rb +30 -15
- data/lib/action_view/lookup_context.rb +63 -35
- data/lib/action_view/path_set.rb +3 -12
- data/lib/action_view/railtie.rb +42 -26
- data/lib/action_view/record_identifier.rb +2 -3
- data/lib/action_view/renderer/abstract_renderer.rb +142 -11
- data/lib/action_view/renderer/collection_renderer.rb +196 -0
- data/lib/action_view/renderer/object_renderer.rb +34 -0
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +61 -16
- data/lib/action_view/renderer/partial_renderer.rb +21 -273
- data/lib/action_view/renderer/renderer.rb +59 -4
- data/lib/action_view/renderer/streaming_template_renderer.rb +10 -8
- data/lib/action_view/renderer/template_renderer.rb +35 -27
- data/lib/action_view/rendering.rb +54 -33
- data/lib/action_view/routing_url_for.rb +13 -12
- data/lib/action_view/template/error.rb +30 -15
- data/lib/action_view/template/handlers/builder.rb +2 -2
- data/lib/action_view/template/handlers/erb/erubi.rb +15 -9
- data/lib/action_view/template/handlers/erb.rb +16 -11
- 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/handlers.rb +1 -1
- data/lib/action_view/template/html.rb +5 -6
- data/lib/action_view/template/inline.rb +22 -0
- data/lib/action_view/template/raw_file.rb +25 -0
- data/lib/action_view/template/renderable.rb +24 -0
- data/lib/action_view/template/resolver.rb +191 -150
- data/lib/action_view/template/sources/file.rb +17 -0
- data/lib/action_view/template/sources.rb +13 -0
- data/lib/action_view/template/text.rb +2 -3
- data/lib/action_view/template.rb +66 -75
- data/lib/action_view/test_case.rb +21 -29
- data/lib/action_view/testing/resolvers.rb +18 -27
- data/lib/action_view/unbound_template.rb +31 -0
- data/lib/action_view/view_paths.rb +59 -38
- data/lib/action_view.rb +7 -2
- data/lib/assets/compiled/rails-ujs.js +32 -6
- metadata +29 -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,67 @@ 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
|
+
partial = options[:partial]
|
66
|
+
if String === partial
|
67
|
+
collection = collection_from_options(options)
|
68
|
+
|
69
|
+
if collection
|
70
|
+
# Collection + Partial
|
71
|
+
renderer = CollectionRenderer.new(@lookup_context, options)
|
72
|
+
renderer.render_collection_with_partial(collection, partial, context, block)
|
73
|
+
else
|
74
|
+
if options.key?(:object)
|
75
|
+
# Object + Partial
|
76
|
+
renderer = ObjectRenderer.new(@lookup_context, options)
|
77
|
+
renderer.render_object_with_partial(options[:object], partial, context, block)
|
78
|
+
else
|
79
|
+
# Partial
|
80
|
+
renderer = PartialRenderer.new(@lookup_context, options)
|
81
|
+
renderer.render(partial, context, block)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
else
|
85
|
+
collection = collection_from_object(partial) || collection_from_options(options)
|
86
|
+
|
87
|
+
if collection
|
88
|
+
# Collection + Derived Partial
|
89
|
+
renderer = CollectionRenderer.new(@lookup_context, options)
|
90
|
+
renderer.render_collection_derive_partial(collection, context, block)
|
91
|
+
else
|
92
|
+
# Object + Derived Partial
|
93
|
+
renderer = ObjectRenderer.new(@lookup_context, options)
|
94
|
+
renderer.render_object_derive_partial(partial, context, block)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
def collection_from_options(options)
|
101
|
+
if options.key?(:collection)
|
102
|
+
collection = options[:collection]
|
103
|
+
collection || []
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def collection_from_object(object)
|
108
|
+
object if object.respond_to?(:to_ary)
|
109
|
+
end
|
55
110
|
end
|
56
111
|
end
|
@@ -27,14 +27,13 @@ module ActionView
|
|
27
27
|
end
|
28
28
|
|
29
29
|
private
|
30
|
-
|
31
30
|
# This is the same logging logic as in ShowExceptions middleware.
|
32
31
|
def log_error(exception)
|
33
32
|
logger = ActionView::Base.logger
|
34
33
|
return unless logger
|
35
34
|
|
36
|
-
message = "\n#{exception.class} (#{exception.message}):\n"
|
37
|
-
message << exception.
|
35
|
+
message = +"\n#{exception.class} (#{exception.message}):\n"
|
36
|
+
message << exception.annotated_source_code.to_s if exception.respond_to?(:annotated_source_code)
|
38
37
|
message << " " << exception.backtrace.join("\n ")
|
39
38
|
logger.fatal("#{message}\n\n")
|
40
39
|
end
|
@@ -43,19 +42,18 @@ module ActionView
|
|
43
42
|
# For streaming, instead of rendering a given a template, we return a Body
|
44
43
|
# object that responds to each. This object is initialized with a block
|
45
44
|
# 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?
|
45
|
+
def render_template(view, template, layout_name = nil, locals = {}) #:nodoc:
|
46
|
+
return [super.body] unless layout_name && template.supports_streaming?
|
48
47
|
|
49
48
|
locals ||= {}
|
50
49
|
layout = layout_name && find_layout(layout_name, locals.keys, [formats.first])
|
51
50
|
|
52
51
|
Body.new do |buffer|
|
53
|
-
delayed_render(buffer, template, layout,
|
52
|
+
delayed_render(buffer, template, layout, view, locals)
|
54
53
|
end
|
55
54
|
end
|
56
55
|
|
57
56
|
private
|
58
|
-
|
59
57
|
def delayed_render(buffer, template, layout, view, locals)
|
60
58
|
# Wrap the given buffer in the StreamingBuffer and pass it to the
|
61
59
|
# underlying template handler. Now, every time something is concatenated
|
@@ -64,7 +62,11 @@ module ActionView
|
|
64
62
|
output = ActionView::StreamingBuffer.new(buffer)
|
65
63
|
yielder = lambda { |*name| view._layout_for(*name) }
|
66
64
|
|
67
|
-
instrument(
|
65
|
+
ActiveSupport::Notifications.instrument(
|
66
|
+
"render_template.action_view",
|
67
|
+
identifier: template.identifier,
|
68
|
+
layout: layout && layout.virtual_path
|
69
|
+
) do
|
68
70
|
outer_config = I18n.config
|
69
71
|
fiber = Fiber.new do
|
70
72
|
I18n.config = outer_config
|
@@ -1,23 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/core_ext/object/try"
|
4
|
-
|
5
3
|
module ActionView
|
6
4
|
class TemplateRenderer < AbstractRenderer #:nodoc:
|
7
5
|
def render(context, options)
|
8
|
-
@view = context
|
9
6
|
@details = extract_details(options)
|
10
7
|
template = determine_template(options)
|
11
8
|
|
12
|
-
prepend_formats(template.
|
13
|
-
|
14
|
-
@lookup_context.rendered_format ||= (template.formats.first || formats.first)
|
9
|
+
prepend_formats(template.format)
|
15
10
|
|
16
|
-
render_template(template, options[:layout], options[:locals])
|
11
|
+
render_template(context, template, options[:layout], options[:locals] || {})
|
17
12
|
end
|
18
13
|
|
19
14
|
private
|
20
|
-
|
21
15
|
# Determine the template to be rendered using the given options.
|
22
16
|
def determine_template(options)
|
23
17
|
keys = options.has_key?(:locals) ? options[:locals].keys : []
|
@@ -29,15 +23,26 @@ module ActionView
|
|
29
23
|
elsif options.key?(:html)
|
30
24
|
Template::HTML.new(options[:html], formats.first)
|
31
25
|
elsif options.key?(:file)
|
32
|
-
|
26
|
+
if File.exist?(options[:file])
|
27
|
+
Template::RawFile.new(options[:file])
|
28
|
+
else
|
29
|
+
raise ArgumentError, "`render file:` should be given the absolute path to a file. '#{options[:file]}' was given instead"
|
30
|
+
end
|
33
31
|
elsif options.key?(:inline)
|
34
32
|
handler = Template.handler_for_extension(options[:type] || "erb")
|
35
|
-
|
33
|
+
format = if handler.respond_to?(:default_format)
|
34
|
+
handler.default_format
|
35
|
+
else
|
36
|
+
@lookup_context.formats.first
|
37
|
+
end
|
38
|
+
Template::Inline.new(options[:inline], "inline template", handler, locals: keys, format: format)
|
39
|
+
elsif options.key?(:renderable)
|
40
|
+
Template::Renderable.new(options[:renderable])
|
36
41
|
elsif options.key?(:template)
|
37
42
|
if options[:template].respond_to?(:render)
|
38
43
|
options[:template]
|
39
44
|
else
|
40
|
-
find_template(options[:template], options[:prefixes], false, keys, @details)
|
45
|
+
@lookup_context.find_template(options[:template], options[:prefixes], false, keys, @details)
|
41
46
|
end
|
42
47
|
else
|
43
48
|
raise ArgumentError, "You invoked render but did not give any of :partial, :template, :inline, :file, :plain, :html or :body option."
|
@@ -46,27 +51,30 @@ module ActionView
|
|
46
51
|
|
47
52
|
# Renders the given template. A string representing the layout can be
|
48
53
|
# supplied as well.
|
49
|
-
def render_template(template, layout_name
|
50
|
-
view,
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
+
def render_template(view, template, layout_name, locals)
|
55
|
+
render_with_layout(view, template, layout_name, locals) do |layout|
|
56
|
+
ActiveSupport::Notifications.instrument(
|
57
|
+
"render_template.action_view",
|
58
|
+
identifier: template.identifier,
|
59
|
+
layout: layout && layout.virtual_path
|
60
|
+
) do
|
54
61
|
template.render(view, locals) { |*name| view._layout_for(*name) }
|
55
62
|
end
|
56
63
|
end
|
57
64
|
end
|
58
65
|
|
59
|
-
def render_with_layout(path, locals)
|
66
|
+
def render_with_layout(view, template, path, locals)
|
60
67
|
layout = path && find_layout(path, locals.keys, [formats.first])
|
61
|
-
content = yield(layout)
|
62
68
|
|
63
|
-
if layout
|
64
|
-
|
65
|
-
|
66
|
-
|
69
|
+
body = if layout
|
70
|
+
ActiveSupport::Notifications.instrument("render_layout.action_view", identifier: layout.identifier) do
|
71
|
+
view.view_flow.set(:layout, yield(layout))
|
72
|
+
layout.render(view, locals) { |*name| view._layout_for(*name) }
|
73
|
+
end
|
67
74
|
else
|
68
|
-
|
75
|
+
yield
|
69
76
|
end
|
77
|
+
build_rendered_template(body, template)
|
70
78
|
end
|
71
79
|
|
72
80
|
# This is the method which actually finds the layout using details in the lookup
|
@@ -84,16 +92,16 @@ module ActionView
|
|
84
92
|
when String
|
85
93
|
begin
|
86
94
|
if layout.start_with?("/")
|
87
|
-
|
95
|
+
raise ArgumentError, "Rendering layouts from an absolute path is not supported."
|
88
96
|
else
|
89
|
-
find_template(layout, nil, false, [], details)
|
97
|
+
@lookup_context.find_template(layout, nil, false, [], details)
|
90
98
|
end
|
91
99
|
rescue ActionView::MissingTemplate
|
92
100
|
all_details = @details.merge(formats: @lookup_context.default_formats)
|
93
|
-
raise unless template_exists?(layout, nil, false, [], all_details)
|
101
|
+
raise unless template_exists?(layout, nil, false, [], **all_details)
|
94
102
|
end
|
95
103
|
when Proc
|
96
|
-
resolve_layout(layout.call(formats), keys, formats)
|
104
|
+
resolve_layout(layout.call(@lookup_context, formats), keys, formats)
|
97
105
|
else
|
98
106
|
layout
|
99
107
|
end
|
@@ -26,7 +26,14 @@ module ActionView
|
|
26
26
|
extend ActiveSupport::Concern
|
27
27
|
include ActionView::ViewPaths
|
28
28
|
|
29
|
-
|
29
|
+
attr_reader :rendered_format
|
30
|
+
|
31
|
+
def initialize
|
32
|
+
@rendered_format = nil
|
33
|
+
super
|
34
|
+
end
|
35
|
+
|
36
|
+
# Overwrite process to set up I18n proxy.
|
30
37
|
def process(*) #:nodoc:
|
31
38
|
old_config, I18n.config = I18n.config, I18nProxy.new(I18n.config, lookup_context)
|
32
39
|
super
|
@@ -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,12 +103,7 @@ 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
|
-
|
93
107
|
# Find and render a template based on the options given.
|
94
108
|
def _render_template(options)
|
95
109
|
variant = options.delete(:variant)
|
@@ -97,17 +111,22 @@ module ActionView
|
|
97
111
|
context = view_context
|
98
112
|
|
99
113
|
context.assign assigns if assigns
|
100
|
-
lookup_context.rendered_format = nil if options[:formats]
|
101
114
|
lookup_context.variants = variant if variant
|
102
115
|
|
103
|
-
|
116
|
+
rendered_template = context.in_rendering_context(options) do |renderer|
|
117
|
+
renderer.render_to_object(context, options)
|
118
|
+
end
|
119
|
+
|
120
|
+
rendered_format = rendered_template.format || lookup_context.formats.first
|
121
|
+
@rendered_format = Template::Types[rendered_format]
|
122
|
+
|
123
|
+
rendered_template.body
|
104
124
|
end
|
105
125
|
|
106
126
|
# Assign the rendered format to look up context.
|
107
127
|
def _process_format(format)
|
108
128
|
super
|
109
|
-
lookup_context.formats = [format.to_sym]
|
110
|
-
lookup_context.rendered_format = lookup_context.formats.first
|
129
|
+
lookup_context.formats = [format.to_sym] if format.to_sym
|
111
130
|
end
|
112
131
|
|
113
132
|
# Normalize args by converting render "foo" to render :action => "foo" and
|
@@ -125,6 +144,8 @@ module ActionView
|
|
125
144
|
else
|
126
145
|
if action.respond_to?(:permitted?) && action.permitted?
|
127
146
|
options = action
|
147
|
+
elsif action.respond_to?(:render_in)
|
148
|
+
options[:renderable] = action
|
128
149
|
else
|
129
150
|
options[:partial] = action
|
130
151
|
end
|
@@ -84,29 +84,28 @@ 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
|
109
|
-
builder = ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.
|
108
|
+
builder = ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.public_send(method)
|
110
109
|
|
111
110
|
case options
|
112
111
|
when Symbol
|
@@ -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
|
@@ -81,19 +81,19 @@ module ActionView
|
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
|
-
def source_extract(indentation = 0
|
85
|
-
return unless num = line_number
|
84
|
+
def source_extract(indentation = 0)
|
85
|
+
return [] unless num = line_number
|
86
86
|
num = num.to_i
|
87
87
|
|
88
|
-
source_code = @template.
|
88
|
+
source_code = @template.encode!.split("\n")
|
89
89
|
|
90
90
|
start_on_line = [ num - SOURCE_CODE_RADIUS - 1, 0 ].max
|
91
91
|
end_on_line = [ num + SOURCE_CODE_RADIUS - 1, source_code.length].min
|
92
92
|
|
93
93
|
indent = end_on_line.to_s.size + indentation
|
94
|
-
return unless source_code = source_code[start_on_line..end_on_line]
|
94
|
+
return [] unless source_code = source_code[start_on_line..end_on_line]
|
95
95
|
|
96
|
-
formatted_code_for(source_code, start_on_line, indent
|
96
|
+
formatted_code_for(source_code, start_on_line, indent)
|
97
97
|
end
|
98
98
|
|
99
99
|
def sub_template_of(template_path)
|
@@ -109,12 +109,11 @@ module ActionView
|
|
109
109
|
end
|
110
110
|
end
|
111
111
|
|
112
|
-
def
|
112
|
+
def annotated_source_code
|
113
113
|
source_extract(4)
|
114
114
|
end
|
115
115
|
|
116
116
|
private
|
117
|
-
|
118
117
|
def source_location
|
119
118
|
if line_number
|
120
119
|
"on line ##{line_number} of "
|
@@ -123,19 +122,35 @@ module ActionView
|
|
123
122
|
end + file_name
|
124
123
|
end
|
125
124
|
|
126
|
-
def formatted_code_for(source_code, line_counter, indent
|
127
|
-
|
128
|
-
source_code.
|
125
|
+
def formatted_code_for(source_code, line_counter, indent)
|
126
|
+
indent_template = "%#{indent}s: %s"
|
127
|
+
source_code.map do |line|
|
129
128
|
line_counter += 1
|
130
|
-
|
131
|
-
result.update(line_counter.to_s => "%#{indent}s %s\n" % ["", line])
|
132
|
-
else
|
133
|
-
result << "%#{indent}s: %s" % [line_counter, line]
|
134
|
-
end
|
129
|
+
indent_template % [line_counter, line]
|
135
130
|
end
|
136
131
|
end
|
137
132
|
end
|
138
133
|
end
|
139
134
|
|
140
135
|
TemplateError = Template::Error
|
136
|
+
|
137
|
+
class SyntaxErrorInTemplate < TemplateError #:nodoc
|
138
|
+
def initialize(template, offending_code_string)
|
139
|
+
@offending_code_string = offending_code_string
|
140
|
+
super(template)
|
141
|
+
end
|
142
|
+
|
143
|
+
def message
|
144
|
+
<<~MESSAGE
|
145
|
+
Encountered a syntax error while rendering template: check #{@offending_code_string}
|
146
|
+
MESSAGE
|
147
|
+
end
|
148
|
+
|
149
|
+
def annotated_source_code
|
150
|
+
@offending_code_string.split("\n").map.with_index(1) { |line, index|
|
151
|
+
indentation = " " * 4
|
152
|
+
"#{index}:#{indentation}#{line}"
|
153
|
+
}
|
154
|
+
end
|
155
|
+
end
|
141
156
|
end
|
@@ -5,11 +5,11 @@ module ActionView
|
|
5
5
|
class Builder
|
6
6
|
class_attribute :default_format, default: :xml
|
7
7
|
|
8
|
-
def call(template)
|
8
|
+
def call(template, source)
|
9
9
|
require_engine
|
10
10
|
"xml = ::Builder::XmlMarkup.new(:indent => 2);" \
|
11
11
|
"self.output_buffer = xml.target!;" +
|
12
|
-
|
12
|
+
source +
|
13
13
|
";xml.target!;"
|
14
14
|
end
|
15
15
|
|
@@ -13,17 +13,23 @@ module ActionView
|
|
13
13
|
|
14
14
|
# Dup properties so that we don't modify argument
|
15
15
|
properties = Hash[properties]
|
16
|
-
|
17
|
-
properties[:
|
18
|
-
properties[:
|
16
|
+
|
17
|
+
properties[:bufvar] ||= "@output_buffer"
|
18
|
+
properties[:preamble] ||= ""
|
19
|
+
properties[:postamble] ||= "#{properties[:bufvar]}.to_s"
|
20
|
+
|
19
21
|
properties[:escapefunc] = ""
|
20
22
|
|
21
23
|
super
|
22
24
|
end
|
23
25
|
|
24
26
|
def evaluate(action_view_erb_handler_context)
|
25
|
-
|
26
|
-
|
27
|
+
src = @src
|
28
|
+
view = Class.new(ActionView::Base) {
|
29
|
+
include action_view_erb_handler_context._routes.url_helpers
|
30
|
+
class_eval("define_method(:_template) { |local_assigns, output_buffer| #{src} }", defined?(@filename) ? @filename : "(erubi)", 0)
|
31
|
+
}.empty
|
32
|
+
view._run(:_template, nil, {}, ActionView::OutputBuffer.new)
|
27
33
|
end
|
28
34
|
|
29
35
|
private
|
@@ -33,7 +39,7 @@ module ActionView
|
|
33
39
|
if text == "\n"
|
34
40
|
@newline_pending += 1
|
35
41
|
else
|
36
|
-
src << "
|
42
|
+
src << bufvar << ".safe_append='"
|
37
43
|
src << "\n" * @newline_pending if @newline_pending > 0
|
38
44
|
src << text.gsub(/['\\]/, '\\\\\&')
|
39
45
|
src << "'.freeze;"
|
@@ -48,9 +54,9 @@ module ActionView
|
|
48
54
|
flush_newline_if_pending(src)
|
49
55
|
|
50
56
|
if (indicator == "==") || @escape
|
51
|
-
src << "
|
57
|
+
src << bufvar << ".safe_expr_append="
|
52
58
|
else
|
53
|
-
src << "
|
59
|
+
src << bufvar << ".append="
|
54
60
|
end
|
55
61
|
|
56
62
|
if BLOCK_EXPR.match?(code)
|
@@ -72,7 +78,7 @@ module ActionView
|
|
72
78
|
|
73
79
|
def flush_newline_if_pending(src)
|
74
80
|
if @newline_pending > 0
|
75
|
-
src << "
|
81
|
+
src << bufvar << ".safe_append='#{"\n" * @newline_pending}'.freeze;"
|
76
82
|
@newline_pending = 0
|
77
83
|
end
|
78
84
|
end
|
@@ -14,12 +14,12 @@ module ActionView
|
|
14
14
|
class_attribute :erb_implementation, default: Erubi
|
15
15
|
|
16
16
|
# Do not escape templates of these mime types.
|
17
|
-
class_attribute :
|
17
|
+
class_attribute :escape_ignore_list, default: ["text/plain"]
|
18
18
|
|
19
19
|
ENCODING_TAG = Regexp.new("\\A(<%#{ENCODING_FLAG}-?%>)[ \\t]*")
|
20
20
|
|
21
|
-
def self.call(template)
|
22
|
-
new.call(template)
|
21
|
+
def self.call(template, source)
|
22
|
+
new.call(template, source)
|
23
23
|
end
|
24
24
|
|
25
25
|
def supports_streaming?
|
@@ -30,30 +30,35 @@ module ActionView
|
|
30
30
|
true
|
31
31
|
end
|
32
32
|
|
33
|
-
def call(template)
|
33
|
+
def call(template, source)
|
34
34
|
# First, convert to BINARY, so in case the encoding is
|
35
35
|
# wrong, we can still find an encoding tag
|
36
36
|
# (<%# encoding %>) inside the String using a regular
|
37
37
|
# expression
|
38
|
-
template_source =
|
38
|
+
template_source = source.b
|
39
39
|
|
40
40
|
erb = template_source.gsub(ENCODING_TAG, "")
|
41
41
|
encoding = $2
|
42
42
|
|
43
|
-
erb.force_encoding valid_encoding(
|
43
|
+
erb.force_encoding valid_encoding(source.dup, encoding)
|
44
44
|
|
45
45
|
# Always make sure we return a String in the default_internal
|
46
46
|
erb.encode!
|
47
47
|
|
48
|
-
|
49
|
-
|
50
|
-
escape: (self.class.escape_whitelist.include? template.type),
|
48
|
+
options = {
|
49
|
+
escape: (self.class.escape_ignore_list.include? template.type),
|
51
50
|
trim: (self.class.erb_trim_mode == "-")
|
52
|
-
|
51
|
+
}
|
52
|
+
|
53
|
+
if ActionView::Base.annotate_rendered_view_with_filenames && template.format == :html
|
54
|
+
options[:preamble] = "@output_buffer.safe_append='<!-- BEGIN #{template.short_identifier} -->';"
|
55
|
+
options[:postamble] = "@output_buffer.safe_append='<!-- END #{template.short_identifier} -->';@output_buffer.to_s"
|
56
|
+
end
|
57
|
+
|
58
|
+
self.class.erb_implementation.new(erb, options).src
|
53
59
|
end
|
54
60
|
|
55
61
|
private
|
56
|
-
|
57
62
|
def valid_encoding(string, encoding)
|
58
63
|
# If a magic encoding comment was found, tag the
|
59
64
|
# String with this encoding. This is for a case
|