actionview 8.0.3 → 8.1.0.rc1

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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +72 -67
  3. data/lib/action_view/base.rb +5 -2
  4. data/lib/action_view/buffers.rb +1 -1
  5. data/lib/action_view/dependency_tracker/erb_tracker.rb +1 -1
  6. data/lib/action_view/dependency_tracker.rb +6 -1
  7. data/lib/action_view/gem_version.rb +3 -3
  8. data/lib/action_view/helpers/asset_tag_helper.rb +23 -4
  9. data/lib/action_view/helpers/capture_helper.rb +2 -2
  10. data/lib/action_view/helpers/controller_helper.rb +6 -2
  11. data/lib/action_view/helpers/date_helper.rb +17 -0
  12. data/lib/action_view/helpers/form_helper.rb +2 -3
  13. data/lib/action_view/helpers/form_options_helper.rb +10 -12
  14. data/lib/action_view/helpers/form_tag_helper.rb +17 -10
  15. data/lib/action_view/helpers/javascript_helper.rb +5 -1
  16. data/lib/action_view/helpers/number_helper.rb +14 -0
  17. data/lib/action_view/helpers/tag_helper.rb +31 -34
  18. data/lib/action_view/helpers/tags/base.rb +2 -0
  19. data/lib/action_view/helpers/tags/check_box.rb +7 -1
  20. data/lib/action_view/helpers/tags/datetime_field.rb +1 -1
  21. data/lib/action_view/helpers/tags/file_field.rb +3 -1
  22. data/lib/action_view/helpers/tags/hidden_field.rb +1 -1
  23. data/lib/action_view/helpers/tags/select.rb +6 -1
  24. data/lib/action_view/helpers/tags/select_renderer.rb +5 -3
  25. data/lib/action_view/helpers/translation_helper.rb +6 -1
  26. data/lib/action_view/helpers/url_helper.rb +37 -9
  27. data/lib/action_view/locale/en.yml +3 -0
  28. data/lib/action_view/log_subscriber.rb +1 -4
  29. data/lib/action_view/railtie.rb +11 -0
  30. data/lib/action_view/record_identifier.rb +21 -0
  31. data/lib/action_view/renderer/partial_renderer.rb +16 -0
  32. data/lib/action_view/structured_event_subscriber.rb +97 -0
  33. data/lib/action_view/template/error.rb +7 -3
  34. data/lib/action_view/template/handlers/erb.rb +37 -12
  35. data/lib/action_view/test_case.rb +50 -52
  36. data/lib/action_view.rb +3 -0
  37. metadata +11 -10
@@ -40,17 +40,19 @@ module ActionView
40
40
 
41
41
  # Translate an error location returned by ErrorHighlight to the correct
42
42
  # source location inside the template.
43
- def translate_location(spot, backtrace_location, source)
44
- # Tokenize the source line
43
+ def translate_location(spot, _backtrace_location, source)
44
+ compiled = spot[:script_lines]
45
+ highlight = compiled[spot[:first_lineno] - 1]&.byteslice((spot[:first_column] - 1)...spot[:last_column])
46
+ return nil if highlight.blank?
47
+
45
48
  source_lines = source.lines
46
- return nil if source_lines.size < backtrace_location.lineno
47
- tokens = ::ERB::Util.tokenize(source_lines[backtrace_location.lineno - 1])
48
- new_first_column = find_offset(spot[:snippet], tokens, spot[:first_column])
49
- lineno_delta = spot[:first_lineno] - backtrace_location.lineno
49
+ lineno_delta = find_lineno_offset(compiled, source_lines, highlight, spot[:first_lineno])
50
+
51
+ tokens = ::ERB::Util.tokenize(source_lines[spot[:first_lineno] - lineno_delta - 1])
52
+ column_delta = find_offset(spot[:snippet], tokens, spot[:first_column])
53
+
50
54
  spot[:first_lineno] -= lineno_delta
51
55
  spot[:last_lineno] -= lineno_delta
52
-
53
- column_delta = spot[:first_column] - new_first_column
54
56
  spot[:first_column] -= column_delta
55
57
  spot[:last_column] -= column_delta
56
58
  spot[:script_lines] = source_lines
@@ -84,7 +86,7 @@ module ActionView
84
86
  }
85
87
 
86
88
  if ActionView::Base.annotate_rendered_view_with_filenames && template.format == :html
87
- options[:preamble] = "@output_buffer.safe_append='<!-- BEGIN #{template.short_identifier} -->';"
89
+ options[:preamble] = "@output_buffer.safe_append='<!-- BEGIN #{template.short_identifier}\n-->';"
88
90
  options[:postamble] = "@output_buffer.safe_append='<!-- END #{template.short_identifier} -->';@output_buffer"
89
91
  end
90
92
 
@@ -107,6 +109,28 @@ module ActionView
107
109
  raise WrongEncodingError.new(string, string.encoding)
108
110
  end
109
111
 
112
+ # Return the offset between the error lineno and the source lineno.
113
+ # Searches in reverse from the backtrace lineno so we have a better
114
+ # chance of finding the correct line
115
+ #
116
+ # The compiled template is likely to be longer than the source.
117
+ # Use the difference between the compiled and source sizes to
118
+ # determine the earliest line that could contain the highlight.
119
+ def find_lineno_offset(compiled, source_lines, highlight, error_lineno)
120
+ first_index = error_lineno - 1 - compiled.size + source_lines.size
121
+ first_index = 0 if first_index < 0
122
+
123
+ last_index = error_lineno - 1
124
+ last_index = source_lines.size - 1 if last_index >= source_lines.size
125
+
126
+ last_index.downto(first_index) do |line_index|
127
+ next unless source_lines[line_index].include?(highlight)
128
+ return error_lineno - 1 - line_index
129
+ end
130
+
131
+ raise LocationParsingError, "Couldn't find code snippet"
132
+ end
133
+
110
134
  # Find which token in the source template spans the byte range that
111
135
  # contains the error_column, then return the offset compared to the
112
136
  # original source template.
@@ -137,7 +161,7 @@ module ActionView
137
161
  matched_str = true
138
162
 
139
163
  if name == :CODE && compiled.pos <= error_column && compiled.pos + str.bytesize >= error_column
140
- return error_column - compiled.pos + offset
164
+ return compiled.pos - offset
141
165
  end
142
166
 
143
167
  compiled.pos += str.bytesize
@@ -152,8 +176,9 @@ module ActionView
152
176
 
153
177
  def offset_source_tokens(source_tokens)
154
178
  source_offset = 0
155
- with_offset = source_tokens.filter_map do |(name, str)|
156
- result = [name, str, source_offset] if name == :CODE || name == :TEXT
179
+ with_offset = source_tokens.filter_map do |name, str|
180
+ result = [:CODE, str, source_offset] if name == :CODE || name == :PLAIN
181
+ result = [:TEXT, str, source_offset] if name == :TEXT
157
182
  source_offset += str.bytesize
158
183
  result
159
184
  end
@@ -60,7 +60,56 @@ module ActionView
60
60
  include ActiveSupport::Testing::ConstantLookup
61
61
 
62
62
  delegate :lookup_context, to: :controller
63
- attr_accessor :controller, :request, :output_buffer, :rendered
63
+ attr_accessor :controller, :request, :output_buffer
64
+
65
+ # Returns the content rendered by the last +render+ call.
66
+ #
67
+ # The returned object behaves like a string but also exposes a number of methods
68
+ # that allows you to parse the content string in formats registered using
69
+ # <tt>.register_parser</tt>.
70
+ #
71
+ # By default includes the following parsers:
72
+ #
73
+ # +.html+
74
+ #
75
+ # Parse the <tt>rendered</tt> content String into HTML. By default, this means
76
+ # a <tt>Nokogiri::XML::Node</tt>.
77
+ #
78
+ # test "renders HTML" do
79
+ # article = Article.create!(title: "Hello, world")
80
+ #
81
+ # render partial: "articles/article", locals: { article: article }
82
+ #
83
+ # assert_pattern { rendered.html.at("main h1") => { content: "Hello, world" } }
84
+ # end
85
+ #
86
+ # To parse the rendered content into a <tt>Capybara::Simple::Node</tt>,
87
+ # re-register an <tt>:html</tt> parser with a call to
88
+ # <tt>Capybara.string</tt>:
89
+ #
90
+ # register_parser :html, -> rendered { Capybara.string(rendered) }
91
+ #
92
+ # test "renders HTML" do
93
+ # article = Article.create!(title: "Hello, world")
94
+ #
95
+ # render partial: article
96
+ #
97
+ # rendered.html.assert_css "h1", text: "Hello, world"
98
+ # end
99
+ #
100
+ # +.json+
101
+ #
102
+ # Parse the <tt>rendered</tt> content String into JSON. By default, this means
103
+ # a <tt>ActiveSupport::HashWithIndifferentAccess</tt>.
104
+ #
105
+ # test "renders JSON" do
106
+ # article = Article.create!(title: "Hello, world")
107
+ #
108
+ # render formats: :json, partial: "articles/article", locals: { article: article }
109
+ #
110
+ # assert_pattern { rendered.json => { title: "Hello, world" } }
111
+ # end
112
+ attr_accessor :rendered
64
113
 
65
114
  module ClassMethods
66
115
  def inherited(descendant) # :nodoc:
@@ -243,57 +292,6 @@ module ActionView
243
292
  @_rendered_views ||= RenderedViewsCollection.new
244
293
  end
245
294
 
246
- ##
247
- # :method: rendered
248
- #
249
- # Returns the content rendered by the last +render+ call.
250
- #
251
- # The returned object behaves like a string but also exposes a number of methods
252
- # that allows you to parse the content string in formats registered using
253
- # <tt>.register_parser</tt>.
254
- #
255
- # By default includes the following parsers:
256
- #
257
- # +.html+
258
- #
259
- # Parse the <tt>rendered</tt> content String into HTML. By default, this means
260
- # a <tt>Nokogiri::XML::Node</tt>.
261
- #
262
- # test "renders HTML" do
263
- # article = Article.create!(title: "Hello, world")
264
- #
265
- # render partial: "articles/article", locals: { article: article }
266
- #
267
- # assert_pattern { rendered.html.at("main h1") => { content: "Hello, world" } }
268
- # end
269
- #
270
- # To parse the rendered content into a <tt>Capybara::Simple::Node</tt>,
271
- # re-register an <tt>:html</tt> parser with a call to
272
- # <tt>Capybara.string</tt>:
273
- #
274
- # register_parser :html, -> rendered { Capybara.string(rendered) }
275
- #
276
- # test "renders HTML" do
277
- # article = Article.create!(title: "Hello, world")
278
- #
279
- # render partial: article
280
- #
281
- # rendered.html.assert_css "h1", text: "Hello, world"
282
- # end
283
- #
284
- # +.json+
285
- #
286
- # Parse the <tt>rendered</tt> content String into JSON. By default, this means
287
- # a <tt>ActiveSupport::HashWithIndifferentAccess</tt>.
288
- #
289
- # test "renders JSON" do
290
- # article = Article.create!(title: "Hello, world")
291
- #
292
- # render formats: :json, partial: "articles/article", locals: { article: article }
293
- #
294
- # assert_pattern { rendered.json => { title: "Hello, world" } }
295
- # end
296
-
297
295
  def _routes
298
296
  @controller._routes if @controller.respond_to?(:_routes)
299
297
  end
data/lib/action_view.rb CHANGED
@@ -91,6 +91,9 @@ module ActionView
91
91
  autoload :CacheExpiry
92
92
  autoload :TestCase
93
93
 
94
+ singleton_class.attr_accessor :render_tracker
95
+ self.render_tracker = :regex
96
+
94
97
  def self.eager_load!
95
98
  super
96
99
  ActionView::Helpers.eager_load!
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: actionview
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.0.3
4
+ version: 8.1.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - '='
17
17
  - !ruby/object:Gem::Version
18
- version: 8.0.3
18
+ version: 8.1.0.rc1
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - '='
24
24
  - !ruby/object:Gem::Version
25
- version: 8.0.3
25
+ version: 8.1.0.rc1
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: builder
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -85,28 +85,28 @@ dependencies:
85
85
  requirements:
86
86
  - - '='
87
87
  - !ruby/object:Gem::Version
88
- version: 8.0.3
88
+ version: 8.1.0.rc1
89
89
  type: :development
90
90
  prerelease: false
91
91
  version_requirements: !ruby/object:Gem::Requirement
92
92
  requirements:
93
93
  - - '='
94
94
  - !ruby/object:Gem::Version
95
- version: 8.0.3
95
+ version: 8.1.0.rc1
96
96
  - !ruby/object:Gem::Dependency
97
97
  name: activemodel
98
98
  requirement: !ruby/object:Gem::Requirement
99
99
  requirements:
100
100
  - - '='
101
101
  - !ruby/object:Gem::Version
102
- version: 8.0.3
102
+ version: 8.1.0.rc1
103
103
  type: :development
104
104
  prerelease: false
105
105
  version_requirements: !ruby/object:Gem::Requirement
106
106
  requirements:
107
107
  - - '='
108
108
  - !ruby/object:Gem::Version
109
- version: 8.0.3
109
+ version: 8.1.0.rc1
110
110
  description: Simple, battle-tested conventions and helpers for building web pages.
111
111
  email: david@loudthinking.com
112
112
  executables: []
@@ -216,6 +216,7 @@ files:
216
216
  - lib/action_view/renderer/template_renderer.rb
217
217
  - lib/action_view/rendering.rb
218
218
  - lib/action_view/routing_url_for.rb
219
+ - lib/action_view/structured_event_subscriber.rb
219
220
  - lib/action_view/tasks/cache_digests.rake
220
221
  - lib/action_view/template.rb
221
222
  - lib/action_view/template/error.rb
@@ -246,10 +247,10 @@ licenses:
246
247
  - MIT
247
248
  metadata:
248
249
  bug_tracker_uri: https://github.com/rails/rails/issues
249
- changelog_uri: https://github.com/rails/rails/blob/v8.0.3/actionview/CHANGELOG.md
250
- documentation_uri: https://api.rubyonrails.org/v8.0.3/
250
+ changelog_uri: https://github.com/rails/rails/blob/v8.1.0.rc1/actionview/CHANGELOG.md
251
+ documentation_uri: https://api.rubyonrails.org/v8.1.0.rc1/
251
252
  mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
252
- source_code_uri: https://github.com/rails/rails/tree/v8.0.3/actionview
253
+ source_code_uri: https://github.com/rails/rails/tree/v8.1.0.rc1/actionview
253
254
  rubygems_mfa_required: 'true'
254
255
  rdoc_options: []
255
256
  require_paths: