activesupport 7.0.8.5 → 7.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (171) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +727 -309
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -4
  5. data/lib/active_support/actionable_error.rb +3 -1
  6. data/lib/active_support/array_inquirer.rb +2 -0
  7. data/lib/active_support/backtrace_cleaner.rb +25 -5
  8. data/lib/active_support/benchmarkable.rb +1 -0
  9. data/lib/active_support/builder.rb +1 -1
  10. data/lib/active_support/cache/coder.rb +153 -0
  11. data/lib/active_support/cache/entry.rb +128 -0
  12. data/lib/active_support/cache/file_store.rb +36 -9
  13. data/lib/active_support/cache/mem_cache_store.rb +84 -68
  14. data/lib/active_support/cache/memory_store.rb +76 -24
  15. data/lib/active_support/cache/null_store.rb +6 -0
  16. data/lib/active_support/cache/redis_cache_store.rb +126 -131
  17. data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
  18. data/lib/active_support/cache/strategy/local_cache.rb +20 -8
  19. data/lib/active_support/cache.rb +304 -246
  20. data/lib/active_support/callbacks.rb +38 -18
  21. data/lib/active_support/concern.rb +4 -2
  22. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +42 -3
  23. data/lib/active_support/concurrency/null_lock.rb +13 -0
  24. data/lib/active_support/configurable.rb +10 -0
  25. data/lib/active_support/core_ext/array/conversions.rb +2 -1
  26. data/lib/active_support/core_ext/array.rb +0 -1
  27. data/lib/active_support/core_ext/class/subclasses.rb +13 -10
  28. data/lib/active_support/core_ext/date/conversions.rb +1 -0
  29. data/lib/active_support/core_ext/date.rb +0 -1
  30. data/lib/active_support/core_ext/date_and_time/calculations.rb +10 -0
  31. data/lib/active_support/core_ext/date_time/conversions.rb +6 -2
  32. data/lib/active_support/core_ext/date_time.rb +0 -1
  33. data/lib/active_support/core_ext/digest/uuid.rb +1 -10
  34. data/lib/active_support/core_ext/enumerable.rb +3 -75
  35. data/lib/active_support/core_ext/erb/util.rb +196 -0
  36. data/lib/active_support/core_ext/hash/conversions.rb +1 -1
  37. data/lib/active_support/core_ext/module/attribute_accessors.rb +6 -0
  38. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +34 -16
  39. data/lib/active_support/core_ext/module/delegation.rb +40 -11
  40. data/lib/active_support/core_ext/module/deprecation.rb +15 -12
  41. data/lib/active_support/core_ext/module/introspection.rb +0 -1
  42. data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
  43. data/lib/active_support/core_ext/numeric/conversions.rb +2 -0
  44. data/lib/active_support/core_ext/numeric.rb +0 -1
  45. data/lib/active_support/core_ext/object/deep_dup.rb +16 -0
  46. data/lib/active_support/core_ext/object/duplicable.rb +15 -24
  47. data/lib/active_support/core_ext/object/inclusion.rb +13 -5
  48. data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
  49. data/lib/active_support/core_ext/object/json.rb +10 -2
  50. data/lib/active_support/core_ext/object/with.rb +44 -0
  51. data/lib/active_support/core_ext/object/with_options.rb +3 -3
  52. data/lib/active_support/core_ext/object.rb +1 -0
  53. data/lib/active_support/core_ext/pathname/blank.rb +16 -0
  54. data/lib/active_support/core_ext/pathname/existence.rb +2 -0
  55. data/lib/active_support/core_ext/pathname.rb +1 -0
  56. data/lib/active_support/core_ext/range/conversions.rb +28 -7
  57. data/lib/active_support/core_ext/range/{overlaps.rb → overlap.rb} +5 -3
  58. data/lib/active_support/core_ext/range.rb +1 -2
  59. data/lib/active_support/core_ext/securerandom.rb +24 -12
  60. data/lib/active_support/core_ext/string/filters.rb +20 -14
  61. data/lib/active_support/core_ext/string/inflections.rb +16 -5
  62. data/lib/active_support/core_ext/string/output_safety.rb +38 -174
  63. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  64. data/lib/active_support/core_ext/time/calculations.rb +18 -2
  65. data/lib/active_support/core_ext/time/conversions.rb +2 -2
  66. data/lib/active_support/core_ext/time/zones.rb +4 -4
  67. data/lib/active_support/core_ext/time.rb +0 -1
  68. data/lib/active_support/current_attributes.rb +15 -6
  69. data/lib/active_support/dependencies/autoload.rb +17 -12
  70. data/lib/active_support/deprecation/behaviors.rb +53 -32
  71. data/lib/active_support/deprecation/constant_accessor.rb +5 -4
  72. data/lib/active_support/deprecation/deprecators.rb +104 -0
  73. data/lib/active_support/deprecation/disallowed.rb +3 -5
  74. data/lib/active_support/deprecation/instance_delegator.rb +31 -4
  75. data/lib/active_support/deprecation/method_wrappers.rb +6 -23
  76. data/lib/active_support/deprecation/proxy_wrappers.rb +37 -22
  77. data/lib/active_support/deprecation/reporting.rb +35 -21
  78. data/lib/active_support/deprecation.rb +32 -5
  79. data/lib/active_support/deprecator.rb +7 -0
  80. data/lib/active_support/descendants_tracker.rb +104 -132
  81. data/lib/active_support/duration/iso8601_serializer.rb +0 -2
  82. data/lib/active_support/duration.rb +2 -1
  83. data/lib/active_support/encrypted_configuration.rb +30 -9
  84. data/lib/active_support/encrypted_file.rb +8 -3
  85. data/lib/active_support/environment_inquirer.rb +22 -2
  86. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  87. data/lib/active_support/error_reporter.rb +121 -35
  88. data/lib/active_support/execution_wrapper.rb +4 -4
  89. data/lib/active_support/file_update_checker.rb +4 -2
  90. data/lib/active_support/fork_tracker.rb +10 -2
  91. data/lib/active_support/gem_version.rb +4 -4
  92. data/lib/active_support/gzip.rb +2 -0
  93. data/lib/active_support/hash_with_indifferent_access.rb +35 -17
  94. data/lib/active_support/i18n.rb +1 -1
  95. data/lib/active_support/i18n_railtie.rb +20 -13
  96. data/lib/active_support/inflector/inflections.rb +2 -0
  97. data/lib/active_support/inflector/methods.rb +22 -10
  98. data/lib/active_support/inflector/transliterate.rb +3 -1
  99. data/lib/active_support/isolated_execution_state.rb +26 -22
  100. data/lib/active_support/json/decoding.rb +2 -1
  101. data/lib/active_support/json/encoding.rb +25 -43
  102. data/lib/active_support/key_generator.rb +9 -1
  103. data/lib/active_support/lazy_load_hooks.rb +6 -4
  104. data/lib/active_support/locale/en.yml +2 -0
  105. data/lib/active_support/log_subscriber.rb +78 -33
  106. data/lib/active_support/logger.rb +1 -1
  107. data/lib/active_support/logger_thread_safe_level.rb +9 -21
  108. data/lib/active_support/message_encryptor.rb +197 -53
  109. data/lib/active_support/message_encryptors.rb +140 -0
  110. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  111. data/lib/active_support/message_pack/extensions.rb +292 -0
  112. data/lib/active_support/message_pack/serializer.rb +63 -0
  113. data/lib/active_support/message_pack.rb +50 -0
  114. data/lib/active_support/message_verifier.rb +212 -93
  115. data/lib/active_support/message_verifiers.rb +134 -0
  116. data/lib/active_support/messages/codec.rb +65 -0
  117. data/lib/active_support/messages/metadata.rb +111 -45
  118. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  119. data/lib/active_support/messages/rotator.rb +34 -32
  120. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  121. data/lib/active_support/multibyte/chars.rb +2 -0
  122. data/lib/active_support/multibyte/unicode.rb +9 -37
  123. data/lib/active_support/notifications/fanout.rb +239 -81
  124. data/lib/active_support/notifications/instrumenter.rb +71 -14
  125. data/lib/active_support/notifications.rb +1 -1
  126. data/lib/active_support/number_helper/number_converter.rb +2 -2
  127. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  128. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -0
  129. data/lib/active_support/ordered_hash.rb +3 -3
  130. data/lib/active_support/ordered_options.rb +14 -0
  131. data/lib/active_support/parameter_filter.rb +84 -69
  132. data/lib/active_support/proxy_object.rb +2 -0
  133. data/lib/active_support/railtie.rb +33 -21
  134. data/lib/active_support/reloader.rb +12 -4
  135. data/lib/active_support/rescuable.rb +2 -0
  136. data/lib/active_support/secure_compare_rotator.rb +16 -9
  137. data/lib/active_support/string_inquirer.rb +3 -1
  138. data/lib/active_support/subscriber.rb +9 -27
  139. data/lib/active_support/syntax_error_proxy.rb +49 -0
  140. data/lib/active_support/tagged_logging.rb +60 -24
  141. data/lib/active_support/test_case.rb +153 -6
  142. data/lib/active_support/testing/assertions.rb +25 -9
  143. data/lib/active_support/testing/autorun.rb +0 -2
  144. data/lib/active_support/testing/constant_stubbing.rb +32 -0
  145. data/lib/active_support/testing/deprecation.rb +25 -25
  146. data/lib/active_support/testing/error_reporter_assertions.rb +108 -0
  147. data/lib/active_support/testing/isolation.rb +1 -1
  148. data/lib/active_support/testing/method_call_assertions.rb +21 -8
  149. data/lib/active_support/testing/parallelize_executor.rb +8 -3
  150. data/lib/active_support/testing/stream.rb +1 -1
  151. data/lib/active_support/testing/strict_warnings.rb +38 -0
  152. data/lib/active_support/testing/time_helpers.rb +32 -14
  153. data/lib/active_support/time_with_zone.rb +4 -14
  154. data/lib/active_support/values/time_zone.rb +9 -7
  155. data/lib/active_support/version.rb +1 -1
  156. data/lib/active_support/xml_mini/jdom.rb +3 -10
  157. data/lib/active_support/xml_mini/nokogiri.rb +1 -1
  158. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  159. data/lib/active_support/xml_mini/rexml.rb +1 -1
  160. data/lib/active_support/xml_mini.rb +2 -2
  161. data/lib/active_support.rb +13 -3
  162. metadata +106 -21
  163. data/lib/active_support/core_ext/array/deprecated_conversions.rb +0 -25
  164. data/lib/active_support/core_ext/date/deprecated_conversions.rb +0 -40
  165. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +0 -36
  166. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +0 -60
  167. data/lib/active_support/core_ext/range/deprecated_conversions.rb +0 -36
  168. data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -5
  169. data/lib/active_support/core_ext/time/deprecated_conversions.rb +0 -73
  170. data/lib/active_support/core_ext/uri.rb +0 -5
  171. data/lib/active_support/per_thread_registry.rb +0 -65
@@ -1,151 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "erb"
4
- require "active_support/core_ext/module/redefine_method"
3
+ require "active_support/core_ext/erb/util"
5
4
  require "active_support/multibyte/unicode"
6
5
 
7
- class ERB
8
- module Util
9
- HTML_ESCAPE = { "&" => "&amp;", ">" => "&gt;", "<" => "&lt;", '"' => "&quot;", "'" => "&#39;" }
10
- JSON_ESCAPE = { "&" => '\u0026', ">" => '\u003e', "<" => '\u003c', "\u2028" => '\u2028', "\u2029" => '\u2029' }
11
- HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+)|(#[xX][\dA-Fa-f]+));)/
12
- JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/u
13
-
14
- # Following XML requirements: https://www.w3.org/TR/REC-xml/#NT-Name
15
- TAG_NAME_START_REGEXP_SET = "@:A-Z_a-z\u{C0}-\u{D6}\u{D8}-\u{F6}\u{F8}-\u{2FF}\u{370}-\u{37D}\u{37F}-\u{1FFF}" \
16
- "\u{200C}-\u{200D}\u{2070}-\u{218F}\u{2C00}-\u{2FEF}\u{3001}-\u{D7FF}\u{F900}-\u{FDCF}" \
17
- "\u{FDF0}-\u{FFFD}\u{10000}-\u{EFFFF}"
18
- TAG_NAME_START_REGEXP = /[^#{TAG_NAME_START_REGEXP_SET}]/
19
- TAG_NAME_FOLLOWING_REGEXP = /[^#{TAG_NAME_START_REGEXP_SET}\-.0-9\u{B7}\u{0300}-\u{036F}\u{203F}-\u{2040}]/
20
- TAG_NAME_REPLACEMENT_CHAR = "_"
21
-
22
- # A utility method for escaping HTML tag characters.
23
- # This method is also aliased as <tt>h</tt>.
24
- #
25
- # puts html_escape('is a > 0 & a < 10?')
26
- # # => is a &gt; 0 &amp; a &lt; 10?
27
- def html_escape(s)
28
- unwrapped_html_escape(s).html_safe
29
- end
30
-
31
- silence_redefinition_of_method :h
32
- alias h html_escape
33
-
34
- module_function :h
35
-
36
- singleton_class.silence_redefinition_of_method :html_escape
37
- module_function :html_escape
38
-
39
- # HTML escapes strings but doesn't wrap them with an ActiveSupport::SafeBuffer.
40
- # This method is not for public consumption! Seriously!
41
- def unwrapped_html_escape(s) # :nodoc:
42
- s = s.to_s
43
- if s.html_safe?
44
- s
45
- else
46
- CGI.escapeHTML(ActiveSupport::Multibyte::Unicode.tidy_bytes(s))
47
- end
48
- end
49
- module_function :unwrapped_html_escape
50
-
51
- # A utility method for escaping HTML without affecting existing escaped entities.
52
- #
53
- # html_escape_once('1 < 2 &amp; 3')
54
- # # => "1 &lt; 2 &amp; 3"
55
- #
56
- # html_escape_once('&lt;&lt; Accept & Checkout')
57
- # # => "&lt;&lt; Accept &amp; Checkout"
58
- def html_escape_once(s)
59
- result = ActiveSupport::Multibyte::Unicode.tidy_bytes(s.to_s).gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE)
60
- s.html_safe? ? result.html_safe : result
61
- end
62
-
63
- module_function :html_escape_once
64
-
65
- # A utility method for escaping HTML entities in JSON strings. Specifically, the
66
- # &, > and < characters are replaced with their equivalent unicode escaped form -
67
- # \u0026, \u003e, and \u003c. The Unicode sequences \u2028 and \u2029 are also
68
- # escaped as they are treated as newline characters in some JavaScript engines.
69
- # These sequences have identical meaning as the original characters inside the
70
- # context of a JSON string, so assuming the input is a valid and well-formed
71
- # JSON value, the output will have equivalent meaning when parsed:
72
- #
73
- # json = JSON.generate({ name: "</script><script>alert('PWNED!!!')</script>"})
74
- # # => "{\"name\":\"</script><script>alert('PWNED!!!')</script>\"}"
75
- #
76
- # json_escape(json)
77
- # # => "{\"name\":\"\\u003C/script\\u003E\\u003Cscript\\u003Ealert('PWNED!!!')\\u003C/script\\u003E\"}"
78
- #
79
- # JSON.parse(json) == JSON.parse(json_escape(json))
80
- # # => true
81
- #
82
- # The intended use case for this method is to escape JSON strings before including
83
- # them inside a script tag to avoid XSS vulnerability:
84
- #
85
- # <script>
86
- # var currentUser = <%= raw json_escape(current_user.to_json) %>;
87
- # </script>
88
- #
89
- # It is necessary to +raw+ the result of +json_escape+, so that quotation marks
90
- # don't get converted to <tt>&quot;</tt> entities. +json_escape+ doesn't
91
- # automatically flag the result as HTML safe, since the raw value is unsafe to
92
- # use inside HTML attributes.
93
- #
94
- # If your JSON is being used downstream for insertion into the DOM, be aware of
95
- # whether or not it is being inserted via <tt>html()</tt>. Most jQuery plugins do this.
96
- # If that is the case, be sure to +html_escape+ or +sanitize+ any user-generated
97
- # content returned by your JSON.
98
- #
99
- # If you need to output JSON elsewhere in your HTML, you can just do something
100
- # like this, as any unsafe characters (including quotation marks) will be
101
- # automatically escaped for you:
102
- #
103
- # <div data-user-info="<%= current_user.to_json %>">...</div>
104
- #
105
- # WARNING: this helper only works with valid JSON. Using this on non-JSON values
106
- # will open up serious XSS vulnerabilities. For example, if you replace the
107
- # +current_user.to_json+ in the example above with user input instead, the browser
108
- # will happily <tt>eval()</tt> that string as JavaScript.
109
- #
110
- # The escaping performed in this method is identical to those performed in the
111
- # Active Support JSON encoder when +ActiveSupport.escape_html_entities_in_json+ is
112
- # set to true. Because this transformation is idempotent, this helper can be
113
- # applied even if +ActiveSupport.escape_html_entities_in_json+ is already true.
114
- #
115
- # Therefore, when you are unsure if +ActiveSupport.escape_html_entities_in_json+
116
- # is enabled, or if you are unsure where your JSON string originated from, it
117
- # is recommended that you always apply this helper (other libraries, such as the
118
- # JSON gem, do not provide this kind of protection by default; also some gems
119
- # might override +to_json+ to bypass Active Support's encoder).
120
- def json_escape(s)
121
- result = s.to_s.gsub(JSON_ESCAPE_REGEXP, JSON_ESCAPE)
122
- s.html_safe? ? result.html_safe : result
123
- end
124
-
125
- module_function :json_escape
126
-
127
- # A utility method for escaping XML names of tags and names of attributes.
128
- #
129
- # xml_name_escape('1 < 2 & 3')
130
- # # => "1___2___3"
131
- #
132
- # It follows the requirements of the specification: https://www.w3.org/TR/REC-xml/#NT-Name
133
- def xml_name_escape(name)
134
- name = name.to_s
135
- return "" if name.blank?
136
-
137
- starting_char = name[0].gsub(TAG_NAME_START_REGEXP, TAG_NAME_REPLACEMENT_CHAR)
138
-
139
- return starting_char if name.size == 1
140
-
141
- following_chars = name[1..-1].gsub(TAG_NAME_FOLLOWING_REGEXP, TAG_NAME_REPLACEMENT_CHAR)
142
-
143
- starting_char + following_chars
144
- end
145
- module_function :xml_name_escape
146
- end
147
- end
148
-
149
6
  class Object
150
7
  def html_safe?
151
8
  false
@@ -162,7 +19,7 @@ module ActiveSupport # :nodoc:
162
19
  class SafeBuffer < String
163
20
  UNSAFE_STRING_METHODS = %w(
164
21
  capitalize chomp chop delete delete_prefix delete_suffix
165
- downcase lstrip next reverse rstrip scrub slice squeeze strip
22
+ downcase lstrip next reverse rstrip scrub squeeze strip
166
23
  succ swapcase tr tr_s unicode_normalize upcase
167
24
  )
168
25
 
@@ -174,7 +31,7 @@ module ActiveSupport # :nodoc:
174
31
  # Raised when ActiveSupport::SafeBuffer#safe_concat is called on unsafe buffers.
175
32
  class SafeConcatError < StandardError
176
33
  def initialize
177
- super "Could not concatenate to the buffer because it is not html safe."
34
+ super "Could not concatenate to the buffer because it is not HTML safe."
178
35
  end
179
36
  end
180
37
 
@@ -184,13 +41,26 @@ module ActiveSupport # :nodoc:
184
41
 
185
42
  return unless new_string
186
43
 
187
- new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
188
- new_safe_buffer.instance_variable_set :@html_safe, true
189
- new_safe_buffer
44
+ string_into_safe_buffer(new_string, true)
190
45
  else
191
46
  to_str[*args]
192
47
  end
193
48
  end
49
+ alias_method :slice, :[]
50
+
51
+ def slice!(*args)
52
+ new_string = super
53
+
54
+ return new_string if !html_safe? || new_string.nil?
55
+
56
+ string_into_safe_buffer(new_string, true)
57
+ end
58
+
59
+ def chr
60
+ return super unless html_safe?
61
+
62
+ string_into_safe_buffer(super, true)
63
+ end
194
64
 
195
65
  def safe_concat(value)
196
66
  raise SafeConcatError unless html_safe?
@@ -207,7 +77,10 @@ module ActiveSupport # :nodoc:
207
77
  @html_safe = other.html_safe?
208
78
  end
209
79
 
210
- def clone_empty
80
+ def clone_empty # :nodoc:
81
+ ActiveSupport.deprecator.warn <<~EOM
82
+ ActiveSupport::SafeBuffer#clone_empty is deprecated and will be removed in Rails 7.2.
83
+ EOM
211
84
  self[0, 0]
212
85
  end
213
86
 
@@ -235,11 +108,11 @@ module ActiveSupport # :nodoc:
235
108
  super(implicit_html_escape_interpolated_argument(value))
236
109
  end
237
110
 
238
- def []=(*args)
239
- if args.length == 3
240
- super(args[0], args[1], implicit_html_escape_interpolated_argument(args[2]))
111
+ def []=(arg1, arg2, arg3 = nil)
112
+ if arg3
113
+ super(arg1, arg2, implicit_html_escape_interpolated_argument(arg3))
241
114
  else
242
- super(args[0], implicit_html_escape_interpolated_argument(args[1]))
115
+ super(arg1, implicit_html_escape_interpolated_argument(arg2))
243
116
  end
244
117
  end
245
118
 
@@ -247,7 +120,7 @@ module ActiveSupport # :nodoc:
247
120
  dup.concat(other)
248
121
  end
249
122
 
250
- def *(*)
123
+ def *(_)
251
124
  new_string = super
252
125
  new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
253
126
  new_safe_buffer.instance_variable_set(:@html_safe, @html_safe)
@@ -265,9 +138,9 @@ module ActiveSupport # :nodoc:
265
138
  self.class.new(super(escaped_args))
266
139
  end
267
140
 
268
- def html_safe?
269
- defined?(@html_safe) && @html_safe
270
- end
141
+ attr_reader :html_safe
142
+ alias_method :html_safe?, :html_safe
143
+ remove_method :html_safe
271
144
 
272
145
  def to_s
273
146
  self
@@ -332,22 +205,7 @@ module ActiveSupport # :nodoc:
332
205
  if !html_safe? || arg.html_safe?
333
206
  arg
334
207
  else
335
- arg_string = begin
336
- arg.to_str
337
- rescue NoMethodError => error
338
- if error.name == :to_str
339
- str = arg.to_s
340
- ActiveSupport::Deprecation.warn <<~MSG.squish
341
- Implicit conversion of #{arg.class} into String by ActiveSupport::SafeBuffer
342
- is deprecated and will be removed in Rails 7.1.
343
- You must explicitly cast it to a String.
344
- MSG
345
- str
346
- else
347
- raise
348
- end
349
- end
350
- CGI.escapeHTML(arg_string)
208
+ CGI.escapeHTML(arg.to_str)
351
209
  end
352
210
  end
353
211
 
@@ -356,6 +214,12 @@ module ActiveSupport # :nodoc:
356
214
  rescue ArgumentError
357
215
  # Can't create binding from C level Proc
358
216
  end
217
+
218
+ def string_into_safe_buffer(new_string, is_html_safe)
219
+ new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
220
+ new_safe_buffer.instance_variable_set :@html_safe, is_html_safe
221
+ new_safe_buffer
222
+ end
359
223
  end
360
224
  end
361
225
 
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Thread::Backtrace::Location # :nodoc:
4
+ if defined?(ErrorHighlight) && Gem::Version.new(ErrorHighlight::VERSION) >= Gem::Version.new("0.4.0")
5
+ def spot(ex)
6
+ ErrorHighlight.spot(ex, backtrace_location: self)
7
+ end
8
+ else
9
+ def spot(ex)
10
+ end
11
+ end
12
+ end
@@ -160,9 +160,25 @@ class Time
160
160
  elsif utc?
161
161
  ::Time.utc(new_year, new_month, new_day, new_hour, new_min, new_sec)
162
162
  elsif zone&.respond_to?(:utc_to_local)
163
- ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, zone)
163
+ new_time = ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, zone)
164
+
165
+ # When there are two occurrences of a nominal time due to DST ending,
166
+ # `Time.new` chooses the first chronological occurrence (the one with a
167
+ # larger UTC offset). However, for `change`, we want to choose the
168
+ # occurrence that matches this time's UTC offset.
169
+ #
170
+ # If the new time's UTC offset is larger than this time's UTC offset, the
171
+ # new time might be a first chronological occurrence. So we add the offset
172
+ # difference to fast-forward the new time, and check if the result has the
173
+ # desired UTC offset (i.e. is the second chronological occurrence).
174
+ offset_difference = new_time.utc_offset - utc_offset
175
+ if offset_difference > 0 && (new_time_2 = new_time + offset_difference).utc_offset == utc_offset
176
+ new_time_2
177
+ else
178
+ new_time
179
+ end
164
180
  elsif zone
165
- ::Time.local(new_year, new_month, new_day, new_hour, new_min, new_sec)
181
+ ::Time.local(new_sec, new_min, new_hour, new_day, new_month, new_year, nil, nil, isdst, nil)
166
182
  else
167
183
  ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, utc_offset)
168
184
  end
@@ -54,12 +54,12 @@ class Time
54
54
  if formatter = DATE_FORMATS[format]
55
55
  formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
56
56
  else
57
- # Change to `to_s` when deprecation is gone. Also deprecate `to_default_s`.
58
- to_default_s
57
+ to_s
59
58
  end
60
59
  end
61
60
  alias_method :to_formatted_s, :to_fs
62
61
  alias_method :to_default_s, :to_s
62
+ deprecate to_default_s: :to_s, deprecator: ActiveSupport.deprecator
63
63
 
64
64
  # Returns a formatted string of the offset from UTC, or an alternative
65
65
  # string if the time zone is already UTC.
@@ -19,10 +19,10 @@ class Time
19
19
  #
20
20
  # This method accepts any of the following:
21
21
  #
22
- # * A Rails TimeZone object.
23
- # * An identifier for a Rails TimeZone object (e.g., "Eastern Time (US & Canada)", <tt>-5.hours</tt>).
24
- # * A <tt>TZInfo::Timezone</tt> object.
25
- # * An identifier for a <tt>TZInfo::Timezone</tt> object (e.g., "America/New_York").
22
+ # * A \Rails TimeZone object.
23
+ # * An identifier for a \Rails TimeZone object (e.g., "Eastern Time (US & Canada)", <tt>-5.hours</tt>).
24
+ # * A +TZInfo::Timezone+ object.
25
+ # * An identifier for a +TZInfo::Timezone+ object (e.g., "America/New_York").
26
26
  #
27
27
  # Here's an example of how you might set <tt>Time.zone</tt> on a per request basis and reset it when the request is done.
28
28
  # <tt>current_user.time_zone</tt> just needs to return a string identifying the user's preferred time zone:
@@ -4,5 +4,4 @@ require "active_support/core_ext/time/acts_like"
4
4
  require "active_support/core_ext/time/calculations"
5
5
  require "active_support/core_ext/time/compatibility"
6
6
  require "active_support/core_ext/time/conversions"
7
- require "active_support/core_ext/time/deprecated_conversions" unless ENV["RAILS_DISABLE_DEPRECATED_TO_S_CONVERSION"]
8
7
  require "active_support/core_ext/time/zones"
@@ -5,6 +5,8 @@ require "active_support/core_ext/enumerable"
5
5
  require "active_support/core_ext/module/delegation"
6
6
 
7
7
  module ActiveSupport
8
+ # = Current Attributes
9
+ #
8
10
  # Abstract super class that provides a thread-isolated attributes singleton, which resets automatically
9
11
  # before and after each request. This allows you to keep all the per-request attributes easily
10
12
  # available to the whole system.
@@ -90,6 +92,8 @@ module ActiveSupport
90
92
  include ActiveSupport::Callbacks
91
93
  define_callbacks :reset
92
94
 
95
+ INVALID_ATTRIBUTE_NAMES = [:set, :reset, :resets, :instance, :before_reset, :after_reset, :reset_all, :clear_all] # :nodoc:
96
+
93
97
  class << self
94
98
  # Returns singleton instance for this class in this thread. If none exists, one is created.
95
99
  def instance
@@ -98,6 +102,11 @@ module ActiveSupport
98
102
 
99
103
  # Declares one or more attributes that will be given both class and instance accessor methods.
100
104
  def attribute(*names)
105
+ invalid_attribute_names = names.map(&:to_sym) & INVALID_ATTRIBUTE_NAMES
106
+ if invalid_attribute_names.any?
107
+ raise ArgumentError, "Restricted attribute names: #{invalid_attribute_names.join(", ")}"
108
+ end
109
+
101
110
  ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |owner|
102
111
  names.each do |name|
103
112
  owner.define_cached_method(name, namespace: :current_attributes) do |batch|
@@ -133,14 +142,14 @@ module ActiveSupport
133
142
  end
134
143
  end
135
144
 
136
- # Calls this block before #reset is called on the instance. Used for resetting external collaborators that depend on current values.
137
- def before_reset(&block)
138
- set_callback :reset, :before, &block
145
+ # Calls this callback before #reset is called on the instance. Used for resetting external collaborators that depend on current values.
146
+ def before_reset(*methods, &block)
147
+ set_callback :reset, :before, *methods, &block
139
148
  end
140
149
 
141
- # Calls this block after #reset is called on the instance. Used for resetting external collaborators, like Time.zone.
142
- def resets(&block)
143
- set_callback :reset, :after, &block
150
+ # Calls this callback after #reset is called on the instance. Used for resetting external collaborators, like Time.zone.
151
+ def resets(*methods, &block)
152
+ set_callback :reset, :after, *methods, &block
144
153
  end
145
154
  alias_method :after_reset, :resets
146
155
 
@@ -3,10 +3,12 @@
3
3
  require "active_support/inflector/methods"
4
4
 
5
5
  module ActiveSupport
6
+ # = Active Support \Autoload
7
+ #
6
8
  # Autoload and eager load conveniences for your library.
7
9
  #
8
10
  # This module allows you to define autoloads based on
9
- # Rails conventions (i.e. no need to define the path
11
+ # \Rails conventions (i.e. no need to define the path
10
12
  # it is automatically guessed based on the filename)
11
13
  # and also define a set of constants that needs to be
12
14
  # eager loaded:
@@ -26,11 +28,14 @@ module ActiveSupport
26
28
  # MyLib.eager_load!
27
29
  module Autoload
28
30
  def self.extended(base) # :nodoc:
29
- base.class_eval do
30
- @_autoloads = {}
31
- @_under_path = nil
32
- @_at_path = nil
33
- @_eager_autoload = false
31
+ if RUBY_VERSION < "3"
32
+ base.class_eval do
33
+ @_autoloads = nil
34
+ @_under_path = nil
35
+ @_at_path = nil
36
+ @_eager_autoload = false
37
+ @_eagerloaded_constants = nil
38
+ end
34
39
  end
35
40
  end
36
41
 
@@ -41,7 +46,8 @@ module ActiveSupport
41
46
  end
42
47
 
43
48
  if @_eager_autoload
44
- @_autoloads[const_name] = path
49
+ @_eagerloaded_constants ||= []
50
+ @_eagerloaded_constants << const_name
45
51
  end
46
52
 
47
53
  super const_name, path
@@ -69,11 +75,10 @@ module ActiveSupport
69
75
  end
70
76
 
71
77
  def eager_load!
72
- @_autoloads.each_value { |file| require file }
73
- end
74
-
75
- def autoloads
76
- @_autoloads
78
+ if @_eagerloaded_constants
79
+ @_eagerloaded_constants.each { |const_name| const_get(const_name) }
80
+ @_eagerloaded_constants = nil
81
+ end
77
82
  end
78
83
  end
79
84
  end
@@ -11,18 +11,18 @@ module ActiveSupport
11
11
  class Deprecation
12
12
  # Default warning behaviors per Rails.env.
13
13
  DEFAULT_BEHAVIORS = {
14
- raise: ->(message, callstack, deprecation_horizon, gem_name) {
14
+ raise: ->(message, callstack, deprecator) do
15
15
  e = DeprecationException.new(message)
16
16
  e.set_backtrace(callstack.map(&:to_s))
17
17
  raise e
18
- },
18
+ end,
19
19
 
20
- stderr: ->(message, callstack, deprecation_horizon, gem_name) {
20
+ stderr: ->(message, callstack, deprecator) do
21
21
  $stderr.puts(message)
22
- $stderr.puts callstack.join("\n ") if debug
23
- },
22
+ $stderr.puts callstack.join("\n ") if deprecator.debug
23
+ end,
24
24
 
25
- log: ->(message, callstack, deprecation_horizon, gem_name) {
25
+ log: ->(message, callstack, deprecator) do
26
26
  logger =
27
27
  if defined?(Rails.logger) && Rails.logger
28
28
  Rails.logger
@@ -31,30 +31,38 @@ module ActiveSupport
31
31
  ActiveSupport::Logger.new($stderr)
32
32
  end
33
33
  logger.warn message
34
- logger.debug callstack.join("\n ") if debug
35
- },
36
-
37
- notify: ->(message, callstack, deprecation_horizon, gem_name) {
38
- notification_name = "deprecation.#{gem_name.underscore.tr('/', '_')}"
39
- ActiveSupport::Notifications.instrument(notification_name,
40
- message: message,
41
- callstack: callstack,
42
- gem_name: gem_name,
43
- deprecation_horizon: deprecation_horizon)
44
- },
45
-
46
- silence: ->(message, callstack, deprecation_horizon, gem_name) { },
34
+ logger.debug callstack.join("\n ") if deprecator.debug
35
+ end,
36
+
37
+ notify: ->(message, callstack, deprecator) do
38
+ ActiveSupport::Notifications.instrument(
39
+ "deprecation.#{deprecator.gem_name.underscore.tr("/", "_")}",
40
+ message: message,
41
+ callstack: callstack,
42
+ gem_name: deprecator.gem_name,
43
+ deprecation_horizon: deprecator.deprecation_horizon,
44
+ )
45
+ end,
46
+
47
+ silence: ->(message, callstack, deprecator) { },
48
+
49
+ report: ->(message, callstack, deprecator) do
50
+ error = DeprecationException.new(message)
51
+ error.set_backtrace(callstack.map(&:to_s))
52
+ ActiveSupport.error_reporter.report(error)
53
+ end
47
54
  }
48
55
 
49
56
  # Behavior module allows to determine how to display deprecation messages.
50
57
  # You can create a custom behavior or set any from the +DEFAULT_BEHAVIORS+
51
58
  # constant. Available behaviors are:
52
59
  #
53
- # [+raise+] Raise <tt>ActiveSupport::DeprecationException</tt>.
60
+ # [+raise+] Raise ActiveSupport::DeprecationException.
54
61
  # [+stderr+] Log all deprecation warnings to <tt>$stderr</tt>.
55
62
  # [+log+] Log all deprecation warnings to +Rails.logger+.
56
63
  # [+notify+] Use +ActiveSupport::Notifications+ to notify +deprecation.rails+.
57
- # [+silence+] Do nothing. On Rails, set <tt>config.active_support.report_deprecations = false</tt> to disable all behaviors.
64
+ # [+report+] Use +ActiveSupport::ErrorReporter+ to report deprecations.
65
+ # [+silence+] Do nothing. On \Rails, set <tt>config.active_support.report_deprecations = false</tt> to disable all behaviors.
58
66
  #
59
67
  # Setting behaviors only affects deprecations that happen after boot time.
60
68
  # For more information you can read the documentation of the +behavior=+ method.
@@ -77,31 +85,33 @@ module ActiveSupport
77
85
  #
78
86
  # Available behaviors:
79
87
  #
80
- # [+raise+] Raise <tt>ActiveSupport::DeprecationException</tt>.
88
+ # [+raise+] Raise ActiveSupport::DeprecationException.
81
89
  # [+stderr+] Log all deprecation warnings to <tt>$stderr</tt>.
82
90
  # [+log+] Log all deprecation warnings to +Rails.logger+.
83
91
  # [+notify+] Use +ActiveSupport::Notifications+ to notify +deprecation.rails+.
92
+ # [+report+] Use +ActiveSupport::ErrorReporter+ to report deprecations.
84
93
  # [+silence+] Do nothing.
85
94
  #
86
95
  # Setting behaviors only affects deprecations that happen after boot time.
87
96
  # Deprecation warnings raised by gems are not affected by this setting
88
- # because they happen before Rails boots up.
97
+ # because they happen before \Rails boots up.
89
98
  #
90
- # ActiveSupport::Deprecation.behavior = :stderr
91
- # ActiveSupport::Deprecation.behavior = [:stderr, :log]
92
- # ActiveSupport::Deprecation.behavior = MyCustomHandler
93
- # ActiveSupport::Deprecation.behavior = ->(message, callstack, deprecation_horizon, gem_name) {
99
+ # deprecator = ActiveSupport::Deprecation.new
100
+ # deprecator.behavior = :stderr
101
+ # deprecator.behavior = [:stderr, :log]
102
+ # deprecator.behavior = MyCustomHandler
103
+ # deprecator.behavior = ->(message, callstack, deprecation_horizon, gem_name) {
94
104
  # # custom stuff
95
105
  # }
96
106
  #
97
- # If you are using Rails, you can set <tt>config.active_support.report_deprecations = false</tt> to disable
107
+ # If you are using \Rails, you can set <tt>config.active_support.report_deprecations = false</tt> to disable
98
108
  # all deprecation behaviors. This is similar to the +silence+ option but more performant.
99
109
  def behavior=(behavior)
100
110
  @behavior = Array(behavior).map { |b| DEFAULT_BEHAVIORS[b] || arity_coerce(b) }
101
111
  end
102
112
 
103
113
  # Sets the behavior for disallowed deprecations (those configured by
104
- # ActiveSupport::Deprecation.disallowed_warnings=) to the specified
114
+ # ActiveSupport::Deprecation#disallowed_warnings=) to the specified
105
115
  # value. As with +behavior=+, this can be a single value, array, or an
106
116
  # object that responds to +call+.
107
117
  def disallowed_behavior=(behavior)
@@ -114,12 +124,23 @@ module ActiveSupport
114
124
  raise ArgumentError, "#{behavior.inspect} is not a valid deprecation behavior."
115
125
  end
116
126
 
117
- if behavior.respond_to?(:arity) && behavior.arity == 2
118
- -> message, callstack, _, _ { behavior.call(message, callstack) }
119
- else
127
+ case arity_of_callable(behavior)
128
+ when 2
129
+ ->(message, callstack, deprecator) do
130
+ behavior.call(message, callstack)
131
+ end
132
+ when -2..3
120
133
  behavior
134
+ else
135
+ ->(message, callstack, deprecator) do
136
+ behavior.call(message, callstack, deprecator.deprecation_horizon, deprecator.gem_name)
137
+ end
121
138
  end
122
139
  end
140
+
141
+ def arity_of_callable(callable)
142
+ callable.respond_to?(:arity) ? callable.arity : callable.method(:call).arity
143
+ end
123
144
  end
124
145
  end
125
146
  end
@@ -6,8 +6,7 @@ module ActiveSupport
6
6
  # hooking +const_missing+.
7
7
  #
8
8
  # It takes the names of an old (deprecated) constant and of a new constant
9
- # (both in string form) and optionally a deprecator. The deprecator defaults
10
- # to +ActiveSupport::Deprecator+ if none is specified.
9
+ # (both in string form) and a deprecator.
11
10
  #
12
11
  # The deprecated constant now returns the same object as the new one rather
13
12
  # than a proxy object, so it can be used transparently in +rescue+ blocks
@@ -19,7 +18,7 @@ module ActiveSupport
19
18
  #
20
19
  # PLANETS_POST_2006 = %w(mercury venus earth mars jupiter saturn uranus neptune)
21
20
  # include ActiveSupport::Deprecation::DeprecatedConstantAccessor
22
- # deprecate_constant 'PLANETS', 'PLANETS_POST_2006'
21
+ # deprecate_constant 'PLANETS', 'PLANETS_POST_2006', deprecator: ActiveSupport::Deprecation.new
23
22
  #
24
23
  # PLANETS.map { |planet| planet.capitalize }
25
24
  # # => DEPRECATION WARNING: PLANETS is deprecated! Use PLANETS_POST_2006 instead.
@@ -40,7 +39,9 @@ module ActiveSupport
40
39
  super
41
40
  end
42
41
 
43
- def deprecate_constant(const_name, new_constant, message: nil, deprecator: ActiveSupport::Deprecation.instance)
42
+ def deprecate_constant(const_name, new_constant, message: nil, deprecator: nil)
43
+ ActiveSupport.deprecator.warn("DeprecatedConstantAccessor.deprecate_constant without a deprecator is deprecated") unless deprecator
44
+ deprecator ||= ActiveSupport::Deprecation._instance
44
45
  class_variable_set(:@@_deprecated_constants, {}) unless class_variable_defined?(:@@_deprecated_constants)
45
46
  class_variable_get(:@@_deprecated_constants)[const_name.to_s] = { new: new_constant, message: message, deprecator: deprecator }
46
47
  end