actionview 7.0.8.7 → 7.2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +59 -454
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/app/assets/javascripts/rails-ujs.esm.js +686 -0
  6. data/app/assets/javascripts/rails-ujs.js +630 -0
  7. data/lib/action_view/base.rb +52 -14
  8. data/lib/action_view/buffers.rb +106 -8
  9. data/lib/action_view/cache_expiry.rb +44 -41
  10. data/lib/action_view/context.rb +1 -1
  11. data/lib/action_view/dependency_tracker/{ripper_tracker.rb → ruby_tracker.rb} +4 -3
  12. data/lib/action_view/dependency_tracker.rb +1 -1
  13. data/lib/action_view/deprecator.rb +7 -0
  14. data/lib/action_view/digestor.rb +1 -1
  15. data/lib/action_view/gem_version.rb +4 -4
  16. data/lib/action_view/helpers/active_model_helper.rb +1 -1
  17. data/lib/action_view/helpers/asset_tag_helper.rb +151 -55
  18. data/lib/action_view/helpers/asset_url_helper.rb +6 -5
  19. data/lib/action_view/helpers/atom_feed_helper.rb +5 -5
  20. data/lib/action_view/helpers/cache_helper.rb +7 -13
  21. data/lib/action_view/helpers/capture_helper.rb +30 -10
  22. data/lib/action_view/helpers/content_exfiltration_prevention_helper.rb +70 -0
  23. data/lib/action_view/helpers/controller_helper.rb +6 -0
  24. data/lib/action_view/helpers/csp_helper.rb +2 -2
  25. data/lib/action_view/helpers/csrf_helper.rb +3 -3
  26. data/lib/action_view/helpers/date_helper.rb +17 -19
  27. data/lib/action_view/helpers/debug_helper.rb +3 -3
  28. data/lib/action_view/helpers/form_helper.rb +248 -214
  29. data/lib/action_view/helpers/form_options_helper.rb +2 -1
  30. data/lib/action_view/helpers/form_tag_helper.rb +125 -58
  31. data/lib/action_view/helpers/javascript_helper.rb +1 -0
  32. data/lib/action_view/helpers/number_helper.rb +37 -330
  33. data/lib/action_view/helpers/output_safety_helper.rb +6 -6
  34. data/lib/action_view/helpers/rendering_helper.rb +1 -1
  35. data/lib/action_view/helpers/sanitize_helper.rb +51 -21
  36. data/lib/action_view/helpers/tag_helper.rb +210 -42
  37. data/lib/action_view/helpers/tags/base.rb +11 -52
  38. data/lib/action_view/helpers/tags/collection_check_boxes.rb +1 -0
  39. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +1 -0
  40. data/lib/action_view/helpers/tags/collection_select.rb +3 -0
  41. data/lib/action_view/helpers/tags/date_field.rb +1 -1
  42. data/lib/action_view/helpers/tags/date_select.rb +2 -0
  43. data/lib/action_view/helpers/tags/datetime_field.rb +14 -6
  44. data/lib/action_view/helpers/tags/datetime_local_field.rb +11 -2
  45. data/lib/action_view/helpers/tags/grouped_collection_select.rb +3 -0
  46. data/lib/action_view/helpers/tags/month_field.rb +1 -1
  47. data/lib/action_view/helpers/tags/select.rb +3 -0
  48. data/lib/action_view/helpers/tags/select_renderer.rb +56 -0
  49. data/lib/action_view/helpers/tags/time_field.rb +1 -1
  50. data/lib/action_view/helpers/tags/time_zone_select.rb +3 -0
  51. data/lib/action_view/helpers/tags/week_field.rb +1 -1
  52. data/lib/action_view/helpers/tags/weekday_select.rb +3 -0
  53. data/lib/action_view/helpers/tags.rb +2 -0
  54. data/lib/action_view/helpers/text_helper.rb +157 -85
  55. data/lib/action_view/helpers/translation_helper.rb +3 -3
  56. data/lib/action_view/helpers/url_helper.rb +35 -80
  57. data/lib/action_view/helpers.rb +2 -0
  58. data/lib/action_view/layouts.rb +8 -8
  59. data/lib/action_view/log_subscriber.rb +57 -36
  60. data/lib/action_view/lookup_context.rb +29 -13
  61. data/lib/action_view/path_registry.rb +57 -0
  62. data/lib/action_view/path_set.rb +13 -14
  63. data/lib/action_view/railtie.rb +25 -3
  64. data/lib/action_view/record_identifier.rb +15 -8
  65. data/lib/action_view/render_parser/prism_render_parser.rb +127 -0
  66. data/lib/action_view/{ripper_ast_parser.rb → render_parser/ripper_render_parser.rb} +156 -13
  67. data/lib/action_view/render_parser.rb +21 -169
  68. data/lib/action_view/renderer/abstract_renderer.rb +2 -2
  69. data/lib/action_view/renderer/collection_renderer.rb +10 -2
  70. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +2 -1
  71. data/lib/action_view/renderer/partial_renderer.rb +2 -1
  72. data/lib/action_view/renderer/renderer.rb +34 -38
  73. data/lib/action_view/renderer/streaming_template_renderer.rb +3 -2
  74. data/lib/action_view/renderer/template_renderer.rb +3 -2
  75. data/lib/action_view/rendering.rb +26 -8
  76. data/lib/action_view/template/error.rb +14 -1
  77. data/lib/action_view/template/handlers/builder.rb +4 -4
  78. data/lib/action_view/template/handlers/erb/erubi.rb +23 -27
  79. data/lib/action_view/template/handlers/erb.rb +73 -1
  80. data/lib/action_view/template/handlers.rb +1 -1
  81. data/lib/action_view/template/html.rb +1 -1
  82. data/lib/action_view/template/raw_file.rb +1 -1
  83. data/lib/action_view/template/renderable.rb +8 -2
  84. data/lib/action_view/template/resolver.rb +9 -3
  85. data/lib/action_view/template/text.rb +1 -1
  86. data/lib/action_view/template/types.rb +25 -34
  87. data/lib/action_view/template.rb +278 -55
  88. data/lib/action_view/template_path.rb +2 -0
  89. data/lib/action_view/test_case.rb +181 -28
  90. data/lib/action_view/unbound_template.rb +17 -7
  91. data/lib/action_view/version.rb +1 -1
  92. data/lib/action_view/view_paths.rb +15 -24
  93. data/lib/action_view.rb +4 -1
  94. metadata +26 -26
  95. data/lib/assets/compiled/rails-ujs.js +0 -777
@@ -51,6 +51,10 @@ module ActionView
51
51
  def length
52
52
  @collection.respond_to?(:length) ? @collection.length : size
53
53
  end
54
+
55
+ def preload!
56
+ # no-op
57
+ end
54
58
  end
55
59
 
56
60
  class SameCollectionIterator < CollectionIterator # :nodoc:
@@ -84,9 +88,13 @@ module ActionView
84
88
 
85
89
  def each_with_info
86
90
  return super unless block_given?
87
- @relation.preload_associations(@collection)
91
+ preload!
88
92
  super
89
93
  end
94
+
95
+ def preload!
96
+ @relation.preload_associations(@collection)
97
+ end
90
98
  end
91
99
 
92
100
  class MixedCollectionIterator < CollectionIterator # :nodoc:
@@ -186,7 +194,7 @@ module ActionView
186
194
 
187
195
  _template = (cache[path] ||= (template || find_template(path, @locals.keys + [as, counter, iteration])))
188
196
 
189
- content = _template.render(view, locals)
197
+ content = _template.render(view, locals, implicit_locals: [counter, iteration])
190
198
  content = layout.render(view, locals) { content } if layout
191
199
  partial_iteration.iterate!
192
200
  build_rendered_template(content, _template)
@@ -59,6 +59,7 @@ module ActionView
59
59
  seed = callable_cache_key? ? @options[:cached] : ->(i) { i }
60
60
 
61
61
  digest_path = view.digest_path_from_template(template)
62
+ collection.preload! if callable_cache_key?
62
63
 
63
64
  collection.each_with_object([{}, []]) do |item, (hash, ordered_keys)|
64
65
  key = expanded_cache_key(seed.call(item), view, template, digest_path)
@@ -100,7 +101,7 @@ module ActionView
100
101
  # We want to cache buffers as raw strings. This both improve performance and
101
102
  # avoid creating forward compatibility issues with the internal representation
102
103
  # of these two types.
103
- if body.is_a?(ActiveSupport::SafeBuffer)
104
+ if body.is_a?(ActionView::OutputBuffer) || body.is_a?(ActiveSupport::SafeBuffer)
104
105
  body = body.to_str
105
106
  end
106
107
 
@@ -246,7 +246,8 @@ module ActionView
246
246
  ActiveSupport::Notifications.instrument(
247
247
  "render_partial.action_view",
248
248
  identifier: template.identifier,
249
- layout: layout && layout.virtual_path
249
+ layout: layout && layout.virtual_path,
250
+ locals: locals
250
251
  ) do |payload|
251
252
  content = template.render(view, locals, add_to_stack: !block) do |*name|
252
253
  view._layout_for(*name, &block)
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionView
4
+ # = Action View \Renderer
5
+ #
4
6
  # This is the main entry point for rendering. It basically delegates
5
7
  # to other objects like TemplateRenderer and PartialRenderer which
6
8
  # actually renders the template.
@@ -43,12 +45,6 @@ module ActionView
43
45
  end
44
46
  end
45
47
 
46
- # Direct access to template rendering.
47
- def render_template(context, options) # :nodoc:
48
- render_template_to_object(context, options).body
49
- end
50
-
51
- # Direct access to partial rendering.
52
48
  def render_partial(context, options, &block) # :nodoc:
53
49
  render_partial_to_object(context, options, &block).body
54
50
  end
@@ -57,46 +53,46 @@ module ActionView
57
53
  @cache_hits ||= {}
58
54
  end
59
55
 
60
- def render_template_to_object(context, options) # :nodoc:
61
- TemplateRenderer.new(@lookup_context).render(context, options)
62
- end
56
+ private
57
+ def render_template_to_object(context, options)
58
+ TemplateRenderer.new(@lookup_context).render(context, options)
59
+ end
63
60
 
64
- def render_partial_to_object(context, options, &block) # :nodoc:
65
- partial = options[:partial]
66
- if String === partial
67
- collection = collection_from_options(options)
61
+ def render_partial_to_object(context, options, &block)
62
+ partial = options[:partial]
63
+ if String === partial
64
+ collection = collection_from_options(options)
68
65
 
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)
66
+ if collection
67
+ # Collection + Partial
68
+ renderer = CollectionRenderer.new(@lookup_context, options)
69
+ renderer.render_collection_with_partial(collection, partial, context, block)
78
70
  else
79
- # Partial
80
- renderer = PartialRenderer.new(@lookup_context, options)
81
- renderer.render(partial, context, block)
71
+ if options.key?(:object)
72
+ # Object + Partial
73
+ renderer = ObjectRenderer.new(@lookup_context, options)
74
+ renderer.render_object_with_partial(options[:object], partial, context, block)
75
+ else
76
+ # Partial
77
+ renderer = PartialRenderer.new(@lookup_context, options)
78
+ renderer.render(partial, context, block)
79
+ end
82
80
  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
81
  else
92
- # Object + Derived Partial
93
- renderer = ObjectRenderer.new(@lookup_context, options)
94
- renderer.render_object_derive_partial(partial, context, block)
82
+ collection = collection_from_object(partial) || collection_from_options(options)
83
+
84
+ if collection
85
+ # Collection + Derived Partial
86
+ renderer = CollectionRenderer.new(@lookup_context, options)
87
+ renderer.render_collection_derive_partial(collection, context, block)
88
+ else
89
+ # Object + Derived Partial
90
+ renderer = ObjectRenderer.new(@lookup_context, options)
91
+ renderer.render_object_derive_partial(partial, context, block)
92
+ end
95
93
  end
96
94
  end
97
- end
98
95
 
99
- private
100
96
  def collection_from_options(options)
101
97
  if options.key?(:collection)
102
98
  collection = options[:collection]
@@ -46,7 +46,7 @@ module ActionView
46
46
  return [super.body] unless layout_name && template.supports_streaming?
47
47
 
48
48
  locals ||= {}
49
- layout = layout_name && find_layout(layout_name, locals.keys, [formats.first])
49
+ layout = find_layout(layout_name, locals.keys, [formats.first])
50
50
 
51
51
  Body.new do |buffer|
52
52
  delayed_render(buffer, template, layout, view, locals)
@@ -65,7 +65,8 @@ module ActionView
65
65
  ActiveSupport::Notifications.instrument(
66
66
  "render_template.action_view",
67
67
  identifier: template.identifier,
68
- layout: layout && layout.virtual_path
68
+ layout: layout && layout.virtual_path,
69
+ locals: locals
69
70
  ) do
70
71
  outer_config = I18n.config
71
72
  fiber = Fiber.new do
@@ -49,7 +49,7 @@ module ActionView
49
49
  @lookup_context.find_template(options[:template], options[:prefixes], false, keys, @details)
50
50
  end
51
51
  else
52
- raise ArgumentError, "You invoked render but did not give any of :partial, :template, :inline, :file, :plain, :html or :body option."
52
+ raise ArgumentError, "You invoked render but did not give any of :body, :file, :html, :inline, :partial, :plain, :renderable, or :template option."
53
53
  end
54
54
  end
55
55
 
@@ -60,7 +60,8 @@ module ActionView
60
60
  ActiveSupport::Notifications.instrument(
61
61
  "render_template.action_view",
62
62
  identifier: template.identifier,
63
- layout: layout && layout.virtual_path
63
+ layout: layout && layout.virtual_path,
64
+ locals: locals
64
65
  ) do
65
66
  template.render(view, locals) { |*name| view._layout_for(*name) }
66
67
  end
@@ -10,7 +10,8 @@ module ActionView
10
10
 
11
11
  def initialize(original_config, lookup_context)
12
12
  original_config = original_config.original_config if original_config.respond_to?(:original_config)
13
- @original_config, @lookup_context = original_config, lookup_context
13
+ @original_config = original_config
14
+ @lookup_context = lookup_context
14
15
  end
15
16
 
16
17
  def locale
@@ -26,10 +27,10 @@ module ActionView
26
27
  extend ActiveSupport::Concern
27
28
  include ActionView::ViewPaths
28
29
 
29
- attr_reader :rendered_format
30
+ attr_internal_reader :rendered_format
30
31
 
31
32
  def initialize
32
- @rendered_format = nil
33
+ @_rendered_format = nil
33
34
  super
34
35
  end
35
36
 
@@ -48,7 +49,18 @@ module ActionView
48
49
  def _helpers
49
50
  end
50
51
 
52
+ def inherit_view_context_class?
53
+ superclass.respond_to?(:view_context_class) &&
54
+ supports_path? == superclass.supports_path? &&
55
+ _routes.equal?(superclass._routes) &&
56
+ _helpers.equal?(superclass._helpers)
57
+ end
58
+
51
59
  def build_view_context_class(klass, supports_path, routes, helpers)
60
+ if inherit_view_context_class?
61
+ return superclass.view_context_class
62
+ end
63
+
52
64
  Class.new(klass) do
53
65
  if routes
54
66
  include routes.url_helpers(supports_path)
@@ -61,8 +73,14 @@ module ActionView
61
73
  end
62
74
  end
63
75
 
76
+ def eager_load!
77
+ super
78
+ view_context_class
79
+ nil
80
+ end
81
+
64
82
  def view_context_class
65
- klass = ActionView::LookupContext::DetailsKey.view_context_class(ActionView::Base)
83
+ klass = ActionView::LookupContext::DetailsKey.view_context_class
66
84
 
67
85
  @view_context_class ||= build_view_context_class(klass, supports_path?, _routes, _helpers)
68
86
 
@@ -118,7 +136,7 @@ module ActionView
118
136
  end
119
137
 
120
138
  rendered_format = rendered_template.format || lookup_context.formats.first
121
- @rendered_format = Template::Types[rendered_format]
139
+ @_rendered_format = Template::Types[rendered_format]
122
140
 
123
141
  rendered_template.body
124
142
  end
@@ -129,8 +147,8 @@ module ActionView
129
147
  lookup_context.formats = [format.to_sym] if format.to_sym
130
148
  end
131
149
 
132
- # Normalize args by converting render "foo" to render :action => "foo" and
133
- # render "foo/bar" to render :template => "foo/bar".
150
+ # Normalize args by converting render "foo" to render action: "foo" and
151
+ # render "foo/bar" to render template: "foo/bar".
134
152
  def _normalize_args(action = nil, options = {})
135
153
  options = super(action, options)
136
154
  case action
@@ -161,7 +179,7 @@ module ActionView
161
179
  options[:partial] = action_name
162
180
  end
163
181
 
164
- if (options.keys & [:partial, :file, :template]).empty?
182
+ if !options.keys.intersect?([:partial, :file, :template])
165
183
  options[:prefixes] ||= _prefixes
166
184
  end
167
185
 
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/enumerable"
4
+ require "active_support/syntax_error_proxy"
4
5
 
5
6
  module ActionView
6
7
  # = Action View Errors
@@ -156,13 +157,25 @@ module ActionView
156
157
  # Override to prevent #cause resetting during re-raise.
157
158
  attr_reader :cause
158
159
 
160
+ attr_reader :template
161
+
159
162
  def initialize(template)
160
163
  super($!.message)
161
- set_backtrace($!.backtrace)
162
164
  @cause = $!
165
+ if @cause.is_a?(SyntaxError)
166
+ @cause = ActiveSupport::SyntaxErrorProxy.new(@cause)
167
+ end
163
168
  @template, @sub_templates = template, nil
164
169
  end
165
170
 
171
+ def backtrace
172
+ @cause.backtrace
173
+ end
174
+
175
+ def backtrace_locations
176
+ @cause.backtrace_locations
177
+ end
178
+
166
179
  def file_name
167
180
  @template.identifier
168
181
  end
@@ -7,10 +7,10 @@ module ActionView
7
7
 
8
8
  def call(template, source)
9
9
  require_engine
10
- "xml = ::Builder::XmlMarkup.new(:indent => 2);" \
11
- "self.output_buffer = xml.target!;" +
12
- source +
13
- ";xml.target!;"
10
+ # the double assignment is to silence "assigned but unused variable" warnings
11
+ "xml = xml = ::Builder::XmlMarkup.new(indent: 2, target: output_buffer.raw);" \
12
+ "#{source};" \
13
+ "output_buffer.to_s"
14
14
  end
15
15
 
16
16
  private
@@ -16,22 +16,16 @@ module ActionView
16
16
 
17
17
  properties[:bufvar] ||= "@output_buffer"
18
18
  properties[:preamble] ||= ""
19
- properties[:postamble] ||= "#{properties[:bufvar]}.to_s"
19
+ properties[:postamble] ||= "#{properties[:bufvar]}"
20
+
21
+ # Tell Eruby that whether template will be compiled with `frozen_string_literal: true`
22
+ properties[:freeze_template_literals] = !Template.frozen_string_literal
20
23
 
21
24
  properties[:escapefunc] = ""
22
25
 
23
26
  super
24
27
  end
25
28
 
26
- def evaluate(action_view_erb_handler_context)
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)
33
- end
34
-
35
29
  private
36
30
  def add_text(text)
37
31
  return if text.empty?
@@ -39,30 +33,32 @@ module ActionView
39
33
  if text == "\n"
40
34
  @newline_pending += 1
41
35
  else
42
- src << bufvar << ".safe_append='"
43
- src << "\n" * @newline_pending if @newline_pending > 0
44
- src << text.gsub(/['\\]/, '\\\\\&')
45
- src << "'.freeze;"
46
-
36
+ with_buffer do
37
+ src << ".safe_append='"
38
+ src << "\n" * @newline_pending if @newline_pending > 0
39
+ src << text.gsub(/['\\]/, '\\\\\&') << @text_end
40
+ end
47
41
  @newline_pending = 0
48
42
  end
49
43
  end
50
44
 
51
- BLOCK_EXPR = /\s*((\s+|\))do|\{)(\s*\|[^|]*\|)?\s*\Z/
45
+ BLOCK_EXPR = /((\s|\))do|\{)(\s*\|[^|]*\|)?\s*\Z/
52
46
 
53
47
  def add_expression(indicator, code)
54
48
  flush_newline_if_pending(src)
55
49
 
56
- if (indicator == "==") || @escape
57
- src << bufvar << ".safe_expr_append="
58
- else
59
- src << bufvar << ".append="
60
- end
61
-
62
- if BLOCK_EXPR.match?(code)
63
- src << " " << code
64
- else
65
- src << "(" << code << ");"
50
+ with_buffer do
51
+ if (indicator == "==") || @escape
52
+ src << ".safe_expr_append="
53
+ else
54
+ src << ".append="
55
+ end
56
+
57
+ if BLOCK_EXPR.match?(code)
58
+ src << " " << code
59
+ else
60
+ src << "(" << code << ")"
61
+ end
66
62
  end
67
63
  end
68
64
 
@@ -78,7 +74,7 @@ module ActionView
78
74
 
79
75
  def flush_newline_if_pending(src)
80
76
  if @newline_pending > 0
81
- src << bufvar << ".safe_append='#{"\n" * @newline_pending}'.freeze;"
77
+ with_buffer { src << ".safe_append='#{"\n" * @newline_pending}" << @text_end }
82
78
  @newline_pending = 0
83
79
  end
84
80
  end
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "strscan"
4
+ require "active_support/core_ext/erb/util"
5
+
3
6
  module ActionView
4
7
  class Template
5
8
  module Handlers
@@ -21,6 +24,8 @@ module ActionView
21
24
 
22
25
  ENCODING_TAG = Regexp.new("\\A(<%#{ENCODING_FLAG}-?%>)[ \\t]*")
23
26
 
27
+ LocationParsingError = Class.new(StandardError) # :nodoc:
28
+
24
29
  def self.call(template, source)
25
30
  new.call(template, source)
26
31
  end
@@ -33,6 +38,26 @@ module ActionView
33
38
  true
34
39
  end
35
40
 
41
+ # Translate an error location returned by ErrorHighlight to the correct
42
+ # source location inside the template.
43
+ def translate_location(spot, backtrace_location, source)
44
+ # Tokenize the source line
45
+ tokens = ::ERB::Util.tokenize(source.lines[backtrace_location.lineno - 1])
46
+ new_first_column = find_offset(spot[:snippet], tokens, spot[:first_column])
47
+ lineno_delta = spot[:first_lineno] - backtrace_location.lineno
48
+ spot[:first_lineno] -= lineno_delta
49
+ spot[:last_lineno] -= lineno_delta
50
+
51
+ column_delta = spot[:first_column] - new_first_column
52
+ spot[:first_column] -= column_delta
53
+ spot[:last_column] -= column_delta
54
+ spot[:script_lines] = source.lines
55
+
56
+ spot
57
+ rescue NotImplementedError, LocationParsingError
58
+ nil
59
+ end
60
+
36
61
  def call(template, source)
37
62
  # First, convert to BINARY, so in case the encoding is
38
63
  # wrong, we can still find an encoding tag
@@ -58,7 +83,7 @@ module ActionView
58
83
 
59
84
  if ActionView::Base.annotate_rendered_view_with_filenames && template.format == :html
60
85
  options[:preamble] = "@output_buffer.safe_append='<!-- BEGIN #{template.short_identifier} -->';"
61
- options[:postamble] = "@output_buffer.safe_append='<!-- END #{template.short_identifier} -->';@output_buffer.to_s"
86
+ options[:postamble] = "@output_buffer.safe_append='<!-- END #{template.short_identifier} -->';@output_buffer"
62
87
  end
63
88
 
64
89
  self.class.erb_implementation.new(erb, options).src
@@ -79,6 +104,53 @@ module ActionView
79
104
  # Otherwise, raise an exception
80
105
  raise WrongEncodingError.new(string, string.encoding)
81
106
  end
107
+
108
+ def find_offset(compiled, source_tokens, error_column)
109
+ compiled = StringScanner.new(compiled)
110
+
111
+ passed_tokens = []
112
+
113
+ while tok = source_tokens.shift
114
+ tok_name, str = *tok
115
+ case tok_name
116
+ when :TEXT
117
+ loop do
118
+ break if compiled.match?(str)
119
+ compiled.getch
120
+ end
121
+ raise LocationParsingError unless compiled.scan(str)
122
+ when :CODE
123
+ if compiled.pos > error_column
124
+ raise LocationParsingError, "We went too far"
125
+ end
126
+
127
+ if compiled.pos + str.bytesize >= error_column
128
+ offset = error_column - compiled.pos
129
+ return passed_tokens.map(&:last).join.bytesize + offset
130
+ else
131
+ unless compiled.scan(str)
132
+ raise LocationParsingError, "Couldn't find code snippet"
133
+ end
134
+ end
135
+ when :OPEN
136
+ next_tok = source_tokens.first.last
137
+ loop do
138
+ break if compiled.match?(next_tok)
139
+ compiled.getch
140
+ end
141
+ when :CLOSE
142
+ next_tok = source_tokens.first.last
143
+ loop do
144
+ break if compiled.match?(next_tok)
145
+ compiled.getch
146
+ end
147
+ else
148
+ raise LocationParsingError, "Not implemented: #{tok.first}"
149
+ end
150
+
151
+ passed_tokens << tok
152
+ end
153
+ end
82
154
  end
83
155
  end
84
156
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionView # :nodoc:
4
- # = Action View Template Handlers
5
4
  class Template # :nodoc:
5
+ # = Action View Template Handlers
6
6
  module Handlers # :nodoc:
7
7
  autoload :Raw, "action_view/template/handlers/raw"
8
8
  autoload :ERB, "action_view/template/handlers/erb"
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionView # :nodoc:
4
- # = Action View HTML Template
5
4
  class Template # :nodoc:
5
+ # = Action View HTML Template
6
6
  class HTML # :nodoc:
7
7
  attr_reader :type
8
8
 
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionView # :nodoc:
4
- # = Action View RawFile Template
5
4
  class Template # :nodoc:
5
+ # = Action View RawFile Template
6
6
  class RawFile # :nodoc:
7
7
  attr_accessor :type, :format
8
8
 
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionView
4
- # = Action View Renderable Template for objects that respond to #render_in
5
4
  class Template
5
+ # = Action View Renderable Template for objects that respond to #render_in
6
6
  class Renderable # :nodoc:
7
7
  def initialize(renderable)
8
8
  @renderable = renderable
@@ -14,10 +14,16 @@ module ActionView
14
14
 
15
15
  def render(context, *args)
16
16
  @renderable.render_in(context)
17
+ rescue NoMethodError
18
+ if !@renderable.respond_to?(:render_in)
19
+ raise ArgumentError, "'#{@renderable.inspect}' is not a renderable object. It must implement #render_in."
20
+ else
21
+ raise
22
+ end
17
23
  end
18
24
 
19
25
  def format
20
- @renderable.format
26
+ @renderable.try(:format)
21
27
  end
22
28
  end
23
29
  end
@@ -10,9 +10,6 @@ require "concurrent/map"
10
10
  module ActionView
11
11
  # = Action View Resolver
12
12
  class Resolver
13
- Path = ActionView::TemplatePath
14
- deprecate_constant :Path
15
-
16
13
  class PathParser # :nodoc:
17
14
  ParsedPath = Struct.new(:path, :details)
18
15
 
@@ -65,6 +62,11 @@ module ActionView
65
62
  _find_all(name, prefix, partial, details, key, locals)
66
63
  end
67
64
 
65
+ def built_templates # :nodoc:
66
+ # Used for error pages
67
+ []
68
+ end
69
+
68
70
  def all_template_paths # :nodoc:
69
71
  # Not implemented by default
70
72
  []
@@ -122,6 +124,10 @@ module ActionView
122
124
  end
123
125
  end
124
126
 
127
+ def built_templates # :nodoc:
128
+ @unbound_templates.values.flatten.flat_map(&:built_templates)
129
+ end
130
+
125
131
  private
126
132
  def _find_all(name, prefix, partial, details, key, locals)
127
133
  requested_details = key || TemplateDetails::Requested.new(**details)
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionView # :nodoc:
4
- # = Action View Text Template
5
4
  class Template # :nodoc:
5
+ # = Action View Text Template
6
6
  class Text # :nodoc:
7
7
  attr_accessor :type
8
8