actionview 6.1.6.1 → 7.0.0.alpha1

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.

Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +89 -347
  3. data/MIT-LICENSE +2 -1
  4. data/lib/action_view/base.rb +3 -3
  5. data/lib/action_view/buffers.rb +2 -2
  6. data/lib/action_view/cache_expiry.rb +46 -32
  7. data/lib/action_view/dependency_tracker/erb_tracker.rb +154 -0
  8. data/lib/action_view/dependency_tracker/ripper_tracker.rb +59 -0
  9. data/lib/action_view/dependency_tracker.rb +6 -147
  10. data/lib/action_view/digestor.rb +7 -4
  11. data/lib/action_view/flows.rb +4 -4
  12. data/lib/action_view/gem_version.rb +4 -4
  13. data/lib/action_view/helpers/active_model_helper.rb +1 -1
  14. data/lib/action_view/helpers/asset_tag_helper.rb +84 -29
  15. data/lib/action_view/helpers/asset_url_helper.rb +7 -7
  16. data/lib/action_view/helpers/atom_feed_helper.rb +3 -4
  17. data/lib/action_view/helpers/cache_helper.rb +51 -3
  18. data/lib/action_view/helpers/capture_helper.rb +2 -2
  19. data/lib/action_view/helpers/controller_helper.rb +2 -2
  20. data/lib/action_view/helpers/csp_helper.rb +1 -1
  21. data/lib/action_view/helpers/csrf_helper.rb +1 -1
  22. data/lib/action_view/helpers/date_helper.rb +6 -7
  23. data/lib/action_view/helpers/debug_helper.rb +3 -1
  24. data/lib/action_view/helpers/form_helper.rb +72 -12
  25. data/lib/action_view/helpers/form_options_helper.rb +65 -33
  26. data/lib/action_view/helpers/form_tag_helper.rb +75 -32
  27. data/lib/action_view/helpers/javascript_helper.rb +3 -5
  28. data/lib/action_view/helpers/number_helper.rb +3 -4
  29. data/lib/action_view/helpers/output_safety_helper.rb +2 -2
  30. data/lib/action_view/helpers/rendering_helper.rb +1 -1
  31. data/lib/action_view/helpers/sanitize_helper.rb +2 -2
  32. data/lib/action_view/helpers/tag_helper.rb +25 -44
  33. data/lib/action_view/helpers/tags/base.rb +3 -15
  34. data/lib/action_view/helpers/tags/check_box.rb +2 -2
  35. data/lib/action_view/helpers/tags/collection_select.rb +1 -1
  36. data/lib/action_view/helpers/tags/hidden_field.rb +0 -4
  37. data/lib/action_view/helpers/tags/time_field.rb +10 -1
  38. data/lib/action_view/helpers/tags/weekday_select.rb +27 -0
  39. data/lib/action_view/helpers/tags.rb +3 -2
  40. data/lib/action_view/helpers/text_helper.rb +24 -13
  41. data/lib/action_view/helpers/translation_helper.rb +1 -2
  42. data/lib/action_view/helpers/url_helper.rb +102 -77
  43. data/lib/action_view/helpers.rb +25 -25
  44. data/lib/action_view/lookup_context.rb +33 -52
  45. data/lib/action_view/model_naming.rb +1 -1
  46. data/lib/action_view/path_set.rb +16 -22
  47. data/lib/action_view/railtie.rb +14 -1
  48. data/lib/action_view/render_parser.rb +188 -0
  49. data/lib/action_view/renderer/abstract_renderer.rb +2 -2
  50. data/lib/action_view/renderer/partial_renderer.rb +0 -34
  51. data/lib/action_view/renderer/renderer.rb +4 -4
  52. data/lib/action_view/renderer/streaming_template_renderer.rb +3 -3
  53. data/lib/action_view/renderer/template_renderer.rb +6 -2
  54. data/lib/action_view/rendering.rb +2 -2
  55. data/lib/action_view/ripper_ast_parser.rb +198 -0
  56. data/lib/action_view/routing_url_for.rb +1 -1
  57. data/lib/action_view/template/error.rb +108 -13
  58. data/lib/action_view/template/handlers/erb.rb +6 -0
  59. data/lib/action_view/template/handlers.rb +3 -3
  60. data/lib/action_view/template/html.rb +3 -3
  61. data/lib/action_view/template/inline.rb +3 -3
  62. data/lib/action_view/template/raw_file.rb +3 -3
  63. data/lib/action_view/template/resolver.rb +84 -311
  64. data/lib/action_view/template/text.rb +3 -3
  65. data/lib/action_view/template/types.rb +14 -12
  66. data/lib/action_view/template.rb +10 -1
  67. data/lib/action_view/template_details.rb +66 -0
  68. data/lib/action_view/template_path.rb +64 -0
  69. data/lib/action_view/test_case.rb +6 -2
  70. data/lib/action_view/testing/resolvers.rb +11 -12
  71. data/lib/action_view/unbound_template.rb +33 -7
  72. data/lib/action_view.rb +3 -4
  73. metadata +25 -19
@@ -1,15 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/enumerable"
3
4
  require "active_support/core_ext/string/output_safety"
4
5
  require "set"
6
+ require "action_view/helpers/capture_helper"
7
+ require "action_view/helpers/output_safety_helper"
5
8
 
6
9
  module ActionView
7
10
  # = Action View Tag Helpers
8
- module Helpers #:nodoc:
11
+ module Helpers # :nodoc:
9
12
  # Provides methods to generate HTML tags programmatically both as a modern
10
13
  # HTML5 compliant builder style and legacy XHTML compliant tags.
11
14
  module TagHelper
12
- extend ActiveSupport::Concern
13
15
  include CaptureHelper
14
16
  include OutputSafetyHelper
15
17
 
@@ -39,7 +41,7 @@ module ActionView
39
41
  PRE_CONTENT_STRINGS[:textarea] = "\n"
40
42
  PRE_CONTENT_STRINGS["textarea"] = "\n"
41
43
 
42
- class TagBuilder #:nodoc:
44
+ class TagBuilder # :nodoc:
43
45
  include CaptureHelper
44
46
  include OutputSafetyHelper
45
47
 
@@ -49,29 +51,31 @@ module ActionView
49
51
  @view_context = view_context
50
52
  end
51
53
 
54
+ # Transforms a Hash into HTML Attributes, ready to be interpolated into
55
+ # ERB.
56
+ #
57
+ # <input <%= tag.attributes(type: :text, aria: { label: "Search" }) %> >
58
+ # # => <input type="text" aria-label="Search">
59
+ def attributes(attributes)
60
+ tag_options(attributes.to_h).to_s.strip.html_safe
61
+ end
62
+
52
63
  def p(*arguments, **options, &block)
53
64
  tag_string(:p, *arguments, **options, &block)
54
65
  end
55
66
 
56
- def tag_string(name, content = nil, **options, &block)
57
- escape = handle_deprecated_escape_options(options)
58
-
67
+ def tag_string(name, content = nil, escape_attributes: true, **options, &block)
59
68
  content = @view_context.capture(self, &block) if block_given?
60
69
  if VOID_ELEMENTS.include?(name) && content.nil?
61
- "<#{name.to_s.dasherize}#{tag_options(options, escape)}>".html_safe
70
+ "<#{name.to_s.dasherize}#{tag_options(options, escape_attributes)}>".html_safe
62
71
  else
63
- content_tag_string(name.to_s.dasherize, content || "", options, escape)
72
+ content_tag_string(name.to_s.dasherize, content || "", options, escape_attributes)
64
73
  end
65
74
  end
66
75
 
67
76
  def content_tag_string(name, content, options, escape = true)
68
77
  tag_options = tag_options(options, escape) if options
69
-
70
- if escape
71
- name = ERB::Util.xml_name_escape(name)
72
- content = ERB::Util.unwrapped_html_escape(content)
73
- end
74
-
78
+ content = ERB::Util.unwrapped_html_escape(content) if escape
75
79
  "<#{name}#{tag_options}>#{PRE_CONTENT_STRINGS[name]}#{content}</#{name}>".html_safe
76
80
  end
77
81
 
@@ -122,17 +126,16 @@ module ActionView
122
126
  end
123
127
 
124
128
  def tag_option(key, value, escape)
125
- key = ERB::Util.xml_name_escape(key) if escape
126
-
127
129
  case value
128
130
  when Array, Hash
129
131
  value = TagHelper.build_tag_values(value) if key.to_s == "class"
130
132
  value = escape ? safe_join(value, " ") : value.join(" ")
133
+ when Regexp
134
+ value = escape ? ERB::Util.unwrapped_html_escape(value.source) : value.source
131
135
  else
132
136
  value = escape ? ERB::Util.unwrapped_html_escape(value) : value.to_s
133
137
  end
134
138
  value = value.gsub('"', "&quot;") if value.include?('"')
135
-
136
139
  %(#{key}="#{value}")
137
140
  end
138
141
 
@@ -149,27 +152,6 @@ module ActionView
149
152
  true
150
153
  end
151
154
 
152
- def handle_deprecated_escape_options(options)
153
- # The option :escape_attributes has been merged into the options hash to be
154
- # able to warn when it is used, so we need to handle default values here.
155
- escape_option_provided = options.has_key?(:escape)
156
- escape_attributes_option_provided = options.has_key?(:escape_attributes)
157
-
158
- if escape_attributes_option_provided
159
- ActiveSupport::Deprecation.warn(<<~MSG)
160
- Use of the option :escape_attributes is deprecated. It currently \
161
- escapes both names and values of tags and attributes and it is \
162
- equivalent to :escape. If any of them are enabled, the escaping \
163
- is fully enabled.
164
- MSG
165
- end
166
-
167
- return true unless escape_option_provided || escape_attributes_option_provided
168
- escape_option = options.delete(:escape)
169
- escape_attributes_option = options.delete(:escape_attributes)
170
- escape_option || escape_attributes_option
171
- end
172
-
173
155
  def method_missing(called, *args, **options, &block)
174
156
  tag_string(called, *args, **options, &block)
175
157
  end
@@ -233,13 +215,13 @@ module ActionView
233
215
  # tag.div data: { city_state: %w( Chicago IL ) }
234
216
  # # => <div data-city-state="[&quot;Chicago&quot;,&quot;IL&quot;]"></div>
235
217
  #
236
- # The generated tag names and attributes are escaped by default. This can be disabled using
237
- # +escape+.
218
+ # The generated attributes are escaped by default. This can be disabled using
219
+ # +escape_attributes+.
238
220
  #
239
221
  # tag.img src: 'open & shut.png'
240
222
  # # => <img src="open &amp; shut.png">
241
223
  #
242
- # tag.img src: 'open & shut.png', escape: false
224
+ # tag.img src: 'open & shut.png', escape_attributes: false
243
225
  # # => <img src="open & shut.png">
244
226
  #
245
227
  # The tag builder respects
@@ -303,7 +285,6 @@ module ActionView
303
285
  if name.nil?
304
286
  tag_builder
305
287
  else
306
- name = ERB::Util.xml_name_escape(name) if escape
307
288
  "<#{name}#{tag_builder.tag_options(options, escape) if options}#{open ? ">" : " />"}".html_safe
308
289
  end
309
290
  end
@@ -312,7 +293,7 @@ module ActionView
312
293
  # HTML attributes by passing an attributes hash to +options+.
313
294
  # Instead of passing the content as an argument, you can also use a block
314
295
  # in which case, you pass your +options+ as the second parameter.
315
- # Set escape to false to disable escaping.
296
+ # Set escape to false to disable attribute value escaping.
316
297
  # Note: this is legacy syntax, see +tag+ method description for details.
317
298
  #
318
299
  # ==== Options
@@ -377,7 +358,7 @@ module ActionView
377
358
  # cdata_section("hello]]>world")
378
359
  # # => <![CDATA[hello]]]]><![CDATA[>world]]>
379
360
  def cdata_section(content)
380
- splitted = content.to_s.gsub(/\]\]\>/, "]]]]><![CDATA[>")
361
+ splitted = content.to_s.gsub(/\]\]>/, "]]]]><![CDATA[>")
381
362
  "<![CDATA[#{splitted}]]>".html_safe
382
363
  end
383
364
 
@@ -117,19 +117,7 @@ module ActionView
117
117
  end
118
118
 
119
119
  def tag_id(index = nil)
120
- # a little duplication to construct fewer strings
121
- case
122
- when @object_name.empty?
123
- sanitized_method_name.dup
124
- when index
125
- "#{sanitized_object_name}_#{index}_#{sanitized_method_name}"
126
- else
127
- "#{sanitized_object_name}_#{sanitized_method_name}"
128
- end
129
- end
130
-
131
- def sanitized_object_name
132
- @sanitized_object_name ||= @object_name.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").delete_suffix("_")
120
+ @template_object.field_id(@object_name, @method_name, index: index)
133
121
  end
134
122
 
135
123
  def sanitized_method_name
@@ -137,7 +125,7 @@ module ActionView
137
125
  end
138
126
 
139
127
  def sanitized_value(value)
140
- value.to_s.gsub(/[\s\.]/, "_").gsub(/[^-[[:word:]]]/, "").downcase
128
+ value.to_s.gsub(/[\s.]/, "_").gsub(/[^-[[:word:]]]/, "").downcase
141
129
  end
142
130
 
143
131
  def select_content_tag(option_tags, options, html_options)
@@ -153,7 +141,7 @@ module ActionView
153
141
  select = content_tag("select", add_options(option_tags, options, value), html_options)
154
142
 
155
143
  if html_options["multiple"] && options.fetch(:include_hidden, true)
156
- tag("input", disabled: html_options["disabled"], name: html_options["name"], type: "hidden", value: "", autocomplete: "off") + select
144
+ tag("input", disabled: html_options["disabled"], name: html_options["name"], type: "hidden", value: "") + select
157
145
  else
158
146
  select
159
147
  end
@@ -5,7 +5,7 @@ require "action_view/helpers/tags/checkable"
5
5
  module ActionView
6
6
  module Helpers
7
7
  module Tags # :nodoc:
8
- class CheckBox < Base #:nodoc:
8
+ class CheckBox < Base # :nodoc:
9
9
  include Checkable
10
10
 
11
11
  def initialize(object_name, method_name, template_object, checked_value, unchecked_value, options)
@@ -57,7 +57,7 @@ module ActionView
57
57
  end
58
58
 
59
59
  def hidden_field_for_checkbox(options)
60
- @unchecked_value ? tag("input", options.slice("name", "disabled", "form").merge!("type" => "hidden", "value" => @unchecked_value, "autocomplete" => "off")) : "".html_safe
60
+ @unchecked_value ? tag("input", options.slice("name", "disabled", "form").merge!("type" => "hidden", "value" => @unchecked_value)) : "".html_safe
61
61
  end
62
62
  end
63
63
  end
@@ -3,7 +3,7 @@
3
3
  module ActionView
4
4
  module Helpers
5
5
  module Tags # :nodoc:
6
- class CollectionSelect < Base #:nodoc:
6
+ class CollectionSelect < Base # :nodoc:
7
7
  def initialize(object_name, method_name, template_object, collection, value_method, text_method, options, html_options)
8
8
  @collection = collection
9
9
  @value_method = value_method
@@ -4,10 +4,6 @@ module ActionView
4
4
  module Helpers
5
5
  module Tags # :nodoc:
6
6
  class HiddenField < TextField # :nodoc:
7
- def render
8
- @options[:autocomplete] = "off"
9
- super
10
- end
11
7
  end
12
8
  end
13
9
  end
@@ -4,9 +4,18 @@ module ActionView
4
4
  module Helpers
5
5
  module Tags # :nodoc:
6
6
  class TimeField < DatetimeField # :nodoc:
7
+ def initialize(object_name, method_name, template_object, options = {})
8
+ @include_seconds = options.delete(:include_seconds) { true }
9
+ super
10
+ end
11
+
7
12
  private
8
13
  def format_date(value)
9
- value&.strftime("%T.%L")
14
+ if @include_seconds
15
+ value&.strftime("%T.%L")
16
+ else
17
+ value&.strftime("%H:%M")
18
+ end
10
19
  end
11
20
  end
12
21
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionView
4
+ module Helpers
5
+ module Tags # :nodoc:
6
+ class WeekdaySelect < Base # :nodoc:
7
+ def initialize(object_name, method_name, template_object, options, html_options)
8
+ @html_options = html_options
9
+
10
+ super(object_name, method_name, template_object, options)
11
+ end
12
+
13
+ def render
14
+ select_content_tag(
15
+ weekday_options_for_select(
16
+ value || @options[:selected],
17
+ index_as_value: @options.fetch(:index_as_value, false),
18
+ day_format: @options.fetch(:day_format, :day_names)
19
+ ),
20
+ @options,
21
+ @html_options
22
+ )
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionView
4
- module Helpers #:nodoc:
5
- module Tags #:nodoc:
4
+ module Helpers # :nodoc:
5
+ module Tags # :nodoc:
6
6
  extend ActiveSupport::Autoload
7
7
 
8
8
  eager_autoload do
@@ -38,6 +38,7 @@ module ActionView
38
38
  autoload :TimeZoneSelect
39
39
  autoload :UrlField
40
40
  autoload :WeekField
41
+ autoload :WeekdaySelect
41
42
  end
42
43
  end
43
44
  end
@@ -1,11 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/string/filters"
4
+ require "active_support/core_ext/string/access"
4
5
  require "active_support/core_ext/array/extract_options"
6
+ require "action_view/helpers/sanitize_helper"
7
+ require "action_view/helpers/tag_helper"
8
+ require "action_view/helpers/output_safety_helper"
5
9
 
6
10
  module ActionView
7
11
  # = Action View Text Helpers
8
- module Helpers #:nodoc:
12
+ module Helpers # :nodoc:
9
13
  # The TextHelper module provides a set of methods for filtering, formatting
10
14
  # and transforming strings, which can reduce the amount of inline Ruby code in
11
15
  # your views. These helper methods extend Action View making them callable
@@ -129,7 +133,7 @@ module ActionView
129
133
  #
130
134
  # highlight('<a href="javascript:alert(\'no!\')">ruby</a> on rails', 'rails', sanitize: false)
131
135
  # # => <a href="javascript:alert('no!')">ruby</a> on <mark>rails</mark>
132
- def highlight(text, phrases, options = {})
136
+ def highlight(text, phrases, options = {}, &block)
133
137
  text = sanitize(text) if options.fetch(:sanitize, true)
134
138
 
135
139
  if text.blank? || phrases.blank?
@@ -140,7 +144,7 @@ module ActionView
140
144
  end.join("|")
141
145
 
142
146
  if block_given?
143
- text.gsub(/(#{match})(?![^<]*?>)/i) { |found| yield found }
147
+ text.gsub(/(#{match})(?![^<]*?>)/i, &block)
144
148
  else
145
149
  highlighter = options.fetch(:highlighter, '<mark>\1</mark>')
146
150
  text.gsub(/(#{match})(?![^<]*?>)/i, highlighter)
@@ -403,7 +407,7 @@ module ActionView
403
407
  cycle.reset if cycle
404
408
  end
405
409
 
406
- class Cycle #:nodoc:
410
+ class Cycle # :nodoc:
407
411
  attr_reader :values
408
412
 
409
413
  def initialize(first_value, *values)
@@ -467,18 +471,25 @@ module ActionView
467
471
  radius = options.fetch(:radius, 100)
468
472
  omission = options.fetch(:omission, "...")
469
473
 
470
- part = part.split(separator)
471
- part.delete("")
472
- affix = part.size > radius ? omission : ""
474
+ if separator != ""
475
+ part = part.split(separator)
476
+ part.delete("")
477
+ end
473
478
 
474
- part = if part_position == :first
475
- drop_index = [part.length - radius, 0].max
476
- part.drop(drop_index)
477
- else
478
- part.first(radius)
479
+ affix = part.length > radius ? omission : ""
480
+
481
+ part =
482
+ if part_position == :first
483
+ part.last(radius)
484
+ else
485
+ part.first(radius)
486
+ end
487
+
488
+ if separator != ""
489
+ part = part.join(separator)
479
490
  end
480
491
 
481
- return affix, part.join(separator)
492
+ return affix, part
482
493
  end
483
494
  end
484
495
  end
@@ -1,11 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "action_view/helpers/tag_helper"
4
- require "active_support/core_ext/symbol/starts_ends_with"
5
4
 
6
5
  module ActionView
7
6
  # = Action View Translation Helpers
8
- module Helpers #:nodoc:
7
+ module Helpers # :nodoc:
9
8
  module TranslationHelper
10
9
  extend ActiveSupport::Concern
11
10