activesupport 6.0.4.4 → 7.0.4.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activesupport might be problematic. Click here for more details.

Files changed (212) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +257 -532
  3. data/MIT-LICENSE +1 -1
  4. data/lib/active_support/actionable_error.rb +1 -1
  5. data/lib/active_support/array_inquirer.rb +2 -2
  6. data/lib/active_support/backtrace_cleaner.rb +5 -5
  7. data/lib/active_support/benchmarkable.rb +3 -3
  8. data/lib/active_support/cache/file_store.rb +16 -10
  9. data/lib/active_support/cache/mem_cache_store.rb +163 -42
  10. data/lib/active_support/cache/memory_store.rb +57 -29
  11. data/lib/active_support/cache/null_store.rb +10 -2
  12. data/lib/active_support/cache/redis_cache_store.rb +79 -98
  13. data/lib/active_support/cache/strategy/local_cache.rb +49 -57
  14. data/lib/active_support/cache.rb +378 -179
  15. data/lib/active_support/callbacks.rb +230 -122
  16. data/lib/active_support/code_generator.rb +65 -0
  17. data/lib/active_support/concern.rb +49 -5
  18. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
  19. data/lib/active_support/concurrency/share_lock.rb +2 -2
  20. data/lib/active_support/configurable.rb +9 -6
  21. data/lib/active_support/configuration_file.rb +51 -0
  22. data/lib/active_support/core_ext/array/access.rb +1 -5
  23. data/lib/active_support/core_ext/array/conversions.rb +13 -12
  24. data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
  25. data/lib/active_support/core_ext/array/grouping.rb +6 -6
  26. data/lib/active_support/core_ext/array/inquiry.rb +2 -2
  27. data/lib/active_support/core_ext/array.rb +1 -0
  28. data/lib/active_support/core_ext/benchmark.rb +2 -2
  29. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  30. data/lib/active_support/core_ext/class/attribute.rb +34 -44
  31. data/lib/active_support/core_ext/class/subclasses.rb +9 -22
  32. data/lib/active_support/core_ext/date/blank.rb +1 -1
  33. data/lib/active_support/core_ext/date/calculations.rb +9 -9
  34. data/lib/active_support/core_ext/date/conversions.rb +16 -15
  35. data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
  36. data/lib/active_support/core_ext/date.rb +1 -0
  37. data/lib/active_support/core_ext/date_and_time/calculations.rb +17 -4
  38. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  39. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  40. data/lib/active_support/core_ext/date_time/conversions.rb +13 -13
  41. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
  42. data/lib/active_support/core_ext/date_time.rb +1 -0
  43. data/lib/active_support/core_ext/digest/uuid.rb +39 -13
  44. data/lib/active_support/core_ext/enumerable.rb +164 -23
  45. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  46. data/lib/active_support/core_ext/hash/conversions.rb +2 -3
  47. data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
  48. data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
  49. data/lib/active_support/core_ext/hash/keys.rb +2 -2
  50. data/lib/active_support/core_ext/hash/slice.rb +3 -2
  51. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  52. data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
  53. data/lib/active_support/core_ext/load_error.rb +1 -1
  54. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  55. data/lib/active_support/core_ext/module/attribute_accessors.rb +25 -29
  56. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +26 -13
  57. data/lib/active_support/core_ext/module/concerning.rb +8 -2
  58. data/lib/active_support/core_ext/module/delegation.rb +40 -36
  59. data/lib/active_support/core_ext/module/introspection.rb +1 -25
  60. data/lib/active_support/core_ext/name_error.rb +23 -2
  61. data/lib/active_support/core_ext/numeric/conversions.rb +80 -73
  62. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
  63. data/lib/active_support/core_ext/numeric.rb +1 -0
  64. data/lib/active_support/core_ext/object/acts_like.rb +29 -5
  65. data/lib/active_support/core_ext/object/blank.rb +2 -2
  66. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  67. data/lib/active_support/core_ext/object/duplicable.rb +11 -0
  68. data/lib/active_support/core_ext/object/json.rb +42 -26
  69. data/lib/active_support/core_ext/object/to_query.rb +2 -2
  70. data/lib/active_support/core_ext/object/try.rb +20 -20
  71. data/lib/active_support/core_ext/object/with_options.rb +20 -1
  72. data/lib/active_support/core_ext/pathname/existence.rb +21 -0
  73. data/lib/active_support/core_ext/pathname.rb +3 -0
  74. data/lib/active_support/core_ext/range/compare_range.rb +6 -25
  75. data/lib/active_support/core_ext/range/conversions.rb +8 -8
  76. data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
  77. data/lib/active_support/core_ext/range/each.rb +1 -1
  78. data/lib/active_support/core_ext/range/include_time_with_zone.rb +4 -20
  79. data/lib/active_support/core_ext/range/overlaps.rb +1 -1
  80. data/lib/active_support/core_ext/range.rb +1 -1
  81. data/lib/active_support/core_ext/regexp.rb +8 -1
  82. data/lib/active_support/core_ext/securerandom.rb +1 -1
  83. data/lib/active_support/core_ext/string/access.rb +5 -24
  84. data/lib/active_support/core_ext/string/conversions.rb +3 -2
  85. data/lib/active_support/core_ext/string/filters.rb +1 -1
  86. data/lib/active_support/core_ext/string/inflections.rb +39 -5
  87. data/lib/active_support/core_ext/string/inquiry.rb +2 -1
  88. data/lib/active_support/core_ext/string/multibyte.rb +2 -2
  89. data/lib/active_support/core_ext/string/output_safety.rb +92 -41
  90. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  91. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
  92. data/lib/active_support/core_ext/symbol.rb +3 -0
  93. data/lib/active_support/core_ext/time/calculations.rb +25 -7
  94. data/lib/active_support/core_ext/time/conversions.rb +15 -12
  95. data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
  96. data/lib/active_support/core_ext/time/zones.rb +7 -22
  97. data/lib/active_support/core_ext/time.rb +1 -0
  98. data/lib/active_support/core_ext/uri.rb +3 -23
  99. data/lib/active_support/core_ext.rb +2 -1
  100. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  101. data/lib/active_support/current_attributes.rb +39 -16
  102. data/lib/active_support/dependencies/interlock.rb +10 -18
  103. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  104. data/lib/active_support/dependencies.rb +58 -769
  105. data/lib/active_support/deprecation/behaviors.rb +23 -7
  106. data/lib/active_support/deprecation/disallowed.rb +56 -0
  107. data/lib/active_support/deprecation/instance_delegator.rb +0 -1
  108. data/lib/active_support/deprecation/method_wrappers.rb +6 -5
  109. data/lib/active_support/deprecation/proxy_wrappers.rb +4 -4
  110. data/lib/active_support/deprecation/reporting.rb +50 -7
  111. data/lib/active_support/deprecation.rb +7 -2
  112. data/lib/active_support/descendants_tracker.rb +174 -64
  113. data/lib/active_support/digest.rb +5 -3
  114. data/lib/active_support/duration/iso8601_parser.rb +3 -3
  115. data/lib/active_support/duration/iso8601_serializer.rb +24 -10
  116. data/lib/active_support/duration.rb +134 -55
  117. data/lib/active_support/encrypted_configuration.rb +13 -2
  118. data/lib/active_support/encrypted_file.rb +32 -3
  119. data/lib/active_support/environment_inquirer.rb +20 -0
  120. data/lib/active_support/error_reporter.rb +117 -0
  121. data/lib/active_support/evented_file_update_checker.rb +72 -138
  122. data/lib/active_support/execution_context/test_helper.rb +13 -0
  123. data/lib/active_support/execution_context.rb +53 -0
  124. data/lib/active_support/execution_wrapper.rb +43 -21
  125. data/lib/active_support/executor/test_helper.rb +7 -0
  126. data/lib/active_support/fork_tracker.rb +71 -0
  127. data/lib/active_support/gem_version.rb +3 -3
  128. data/lib/active_support/hash_with_indifferent_access.rb +51 -25
  129. data/lib/active_support/html_safe_translation.rb +43 -0
  130. data/lib/active_support/i18n.rb +1 -0
  131. data/lib/active_support/i18n_railtie.rb +14 -19
  132. data/lib/active_support/inflector/inflections.rb +24 -9
  133. data/lib/active_support/inflector/methods.rb +29 -49
  134. data/lib/active_support/inflector/transliterate.rb +5 -5
  135. data/lib/active_support/isolated_execution_state.rb +72 -0
  136. data/lib/active_support/json/decoding.rb +4 -4
  137. data/lib/active_support/json/encoding.rb +8 -4
  138. data/lib/active_support/key_generator.rb +23 -6
  139. data/lib/active_support/lazy_load_hooks.rb +28 -4
  140. data/lib/active_support/locale/en.yml +8 -4
  141. data/lib/active_support/log_subscriber/test_helper.rb +2 -2
  142. data/lib/active_support/log_subscriber.rb +23 -5
  143. data/lib/active_support/logger.rb +1 -1
  144. data/lib/active_support/logger_silence.rb +2 -26
  145. data/lib/active_support/logger_thread_safe_level.rb +34 -21
  146. data/lib/active_support/message_encryptor.rb +16 -13
  147. data/lib/active_support/message_verifier.rb +50 -18
  148. data/lib/active_support/messages/metadata.rb +2 -2
  149. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  150. data/lib/active_support/messages/rotator.rb +6 -5
  151. data/lib/active_support/multibyte/chars.rb +13 -52
  152. data/lib/active_support/multibyte/unicode.rb +1 -87
  153. data/lib/active_support/multibyte.rb +1 -1
  154. data/lib/active_support/notifications/fanout.rb +110 -69
  155. data/lib/active_support/notifications/instrumenter.rb +37 -29
  156. data/lib/active_support/notifications.rb +55 -28
  157. data/lib/active_support/number_helper/number_converter.rb +2 -4
  158. data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
  159. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  160. data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
  161. data/lib/active_support/number_helper/number_to_human_size_converter.rb +2 -2
  162. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
  163. data/lib/active_support/number_helper/number_to_rounded_converter.rb +9 -5
  164. data/lib/active_support/number_helper/rounding_helper.rb +12 -32
  165. data/lib/active_support/number_helper.rb +29 -16
  166. data/lib/active_support/option_merger.rb +11 -18
  167. data/lib/active_support/ordered_hash.rb +1 -1
  168. data/lib/active_support/ordered_options.rb +9 -3
  169. data/lib/active_support/parameter_filter.rb +21 -11
  170. data/lib/active_support/per_thread_registry.rb +6 -1
  171. data/lib/active_support/rails.rb +1 -4
  172. data/lib/active_support/railtie.rb +77 -5
  173. data/lib/active_support/reloader.rb +1 -1
  174. data/lib/active_support/rescuable.rb +16 -16
  175. data/lib/active_support/ruby_features.rb +7 -0
  176. data/lib/active_support/secure_compare_rotator.rb +51 -0
  177. data/lib/active_support/security_utils.rb +19 -12
  178. data/lib/active_support/string_inquirer.rb +2 -2
  179. data/lib/active_support/subscriber.rb +19 -25
  180. data/lib/active_support/tagged_logging.rb +31 -6
  181. data/lib/active_support/test_case.rb +13 -21
  182. data/lib/active_support/testing/assertions.rb +50 -13
  183. data/lib/active_support/testing/deprecation.rb +52 -1
  184. data/lib/active_support/testing/isolation.rb +2 -2
  185. data/lib/active_support/testing/method_call_assertions.rb +5 -5
  186. data/lib/active_support/testing/parallelization/server.rb +82 -0
  187. data/lib/active_support/testing/parallelization/worker.rb +103 -0
  188. data/lib/active_support/testing/parallelization.rb +16 -95
  189. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  190. data/lib/active_support/testing/stream.rb +3 -5
  191. data/lib/active_support/testing/tagged_logging.rb +1 -1
  192. data/lib/active_support/testing/time_helpers.rb +53 -5
  193. data/lib/active_support/time_with_zone.rb +126 -62
  194. data/lib/active_support/values/time_zone.rb +54 -23
  195. data/lib/active_support/version.rb +1 -1
  196. data/lib/active_support/xml_mini/jdom.rb +1 -1
  197. data/lib/active_support/xml_mini/libxml.rb +5 -5
  198. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  199. data/lib/active_support/xml_mini/nokogiri.rb +4 -4
  200. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  201. data/lib/active_support/xml_mini/rexml.rb +9 -2
  202. data/lib/active_support/xml_mini.rb +5 -4
  203. data/lib/active_support.rb +29 -1
  204. metadata +46 -45
  205. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
  206. data/lib/active_support/core_ext/hash/compact.rb +0 -5
  207. data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
  208. data/lib/active_support/core_ext/marshal.rb +0 -24
  209. data/lib/active_support/core_ext/module/reachable.rb +0 -6
  210. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
  211. data/lib/active_support/core_ext/range/include_range.rb +0 -9
  212. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "erb"
4
- require "active_support/core_ext/kernel/singleton_class"
5
4
  require "active_support/core_ext/module/redefine_method"
6
5
  require "active_support/multibyte/unicode"
7
6
 
@@ -12,6 +11,14 @@ class ERB
12
11
  HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+)|(#[xX][\dA-Fa-f]+));)/
13
12
  JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/u
14
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
+
15
22
  # A utility method for escaping HTML tag characters.
16
23
  # This method is also aliased as <tt>h</tt>.
17
24
  #
@@ -85,7 +92,7 @@ class ERB
85
92
  # use inside HTML attributes.
86
93
  #
87
94
  # If your JSON is being used downstream for insertion into the DOM, be aware of
88
- # whether or not it is being inserted via +html()+. Most jQuery plugins do this.
95
+ # whether or not it is being inserted via <tt>html()</tt>. Most jQuery plugins do this.
89
96
  # If that is the case, be sure to +html_escape+ or +sanitize+ any user-generated
90
97
  # content returned by your JSON.
91
98
  #
@@ -98,7 +105,7 @@ class ERB
98
105
  # WARNING: this helper only works with valid JSON. Using this on non-JSON values
99
106
  # will open up serious XSS vulnerabilities. For example, if you replace the
100
107
  # +current_user.to_json+ in the example above with user input instead, the browser
101
- # will happily eval() that string as JavaScript.
108
+ # will happily <tt>eval()</tt> that string as JavaScript.
102
109
  #
103
110
  # The escaping performed in this method is identical to those performed in the
104
111
  # Active Support JSON encoder when +ActiveSupport.escape_html_entities_in_json+ is
@@ -116,6 +123,26 @@ class ERB
116
123
  end
117
124
 
118
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
119
146
  end
120
147
  end
121
148
 
@@ -131,7 +158,7 @@ class Numeric
131
158
  end
132
159
  end
133
160
 
134
- module ActiveSupport #:nodoc:
161
+ module ActiveSupport # :nodoc:
135
162
  class SafeBuffer < String
136
163
  UNSAFE_STRING_METHODS = %w(
137
164
  capitalize chomp chop delete delete_prefix delete_suffix
@@ -144,7 +171,7 @@ module ActiveSupport #:nodoc:
144
171
  alias_method :original_concat, :concat
145
172
  private :original_concat
146
173
 
147
- # Raised when <tt>ActiveSupport::SafeBuffer#safe_concat</tt> is called on unsafe buffers.
174
+ # Raised when ActiveSupport::SafeBuffer#safe_concat is called on unsafe buffers.
148
175
  class SafeConcatError < StandardError
149
176
  def initialize
150
177
  super "Could not concatenate to the buffer because it is not html safe."
@@ -185,27 +212,30 @@ module ActiveSupport #:nodoc:
185
212
  end
186
213
 
187
214
  def concat(value)
188
- super(html_escape_interpolated_argument(value))
215
+ unless value.nil?
216
+ super(implicit_html_escape_interpolated_argument(value))
217
+ end
218
+ self
189
219
  end
190
220
  alias << concat
191
221
 
192
222
  def insert(index, value)
193
- super(index, html_escape_interpolated_argument(value))
223
+ super(index, implicit_html_escape_interpolated_argument(value))
194
224
  end
195
225
 
196
226
  def prepend(value)
197
- super(html_escape_interpolated_argument(value))
227
+ super(implicit_html_escape_interpolated_argument(value))
198
228
  end
199
229
 
200
230
  def replace(value)
201
- super(html_escape_interpolated_argument(value))
231
+ super(implicit_html_escape_interpolated_argument(value))
202
232
  end
203
233
 
204
234
  def []=(*args)
205
- if args.count == 3
206
- super(args[0], args[1], html_escape_interpolated_argument(args[2]))
235
+ if args.length == 3
236
+ super(args[0], args[1], implicit_html_escape_interpolated_argument(args[2]))
207
237
  else
208
- super(args[0], html_escape_interpolated_argument(args[1]))
238
+ super(args[0], implicit_html_escape_interpolated_argument(args[1]))
209
239
  end
210
240
  end
211
241
 
@@ -223,9 +253,9 @@ module ActiveSupport #:nodoc:
223
253
  def %(args)
224
254
  case args
225
255
  when Hash
226
- escaped_args = Hash[args.map { |k, arg| [k, html_escape_interpolated_argument(arg)] }]
256
+ escaped_args = args.transform_values { |arg| explicit_html_escape_interpolated_argument(arg) }
227
257
  else
228
- escaped_args = Array(args).map { |arg| html_escape_interpolated_argument(arg) }
258
+ escaped_args = Array(args).map { |arg| explicit_html_escape_interpolated_argument(arg) }
229
259
  end
230
260
 
231
261
  self.class.new(super(escaped_args))
@@ -263,39 +293,60 @@ module ActiveSupport #:nodoc:
263
293
  end
264
294
 
265
295
  UNSAFE_STRING_METHODS_WITH_BACKREF.each do |unsafe_method|
266
- if unsafe_method.respond_to?(unsafe_method)
267
- class_eval <<-EOT, __FILE__, __LINE__ + 1
268
- def #{unsafe_method}(*args, &block) # def gsub(*args, &block)
269
- if block # if block
270
- to_str.#{unsafe_method}(*args) { |*params| # to_str.gsub(*args) { |*params|
271
- set_block_back_references(block, $~) # set_block_back_references(block, $~)
272
- block.call(*params) # block.call(*params)
273
- } # }
274
- else # else
275
- to_str.#{unsafe_method}(*args) # to_str.gsub(*args)
276
- end # end
277
- end # end
278
-
279
- def #{unsafe_method}!(*args, &block) # def gsub!(*args, &block)
280
- @html_safe = false # @html_safe = false
281
- if block # if block
282
- super(*args) { |*params| # super(*args) { |*params|
283
- set_block_back_references(block, $~) # set_block_back_references(block, $~)
284
- block.call(*params) # block.call(*params)
285
- } # }
286
- else # else
287
- super # super
288
- end # end
289
- end # end
290
- EOT
291
- end
296
+ class_eval <<-EOT, __FILE__, __LINE__ + 1
297
+ def #{unsafe_method}(*args, &block) # def gsub(*args, &block)
298
+ if block # if block
299
+ to_str.#{unsafe_method}(*args) { |*params| # to_str.gsub(*args) { |*params|
300
+ set_block_back_references(block, $~) # set_block_back_references(block, $~)
301
+ block.call(*params) # block.call(*params)
302
+ } # }
303
+ else # else
304
+ to_str.#{unsafe_method}(*args) # to_str.gsub(*args)
305
+ end # end
306
+ end # end
307
+
308
+ def #{unsafe_method}!(*args, &block) # def gsub!(*args, &block)
309
+ @html_safe = false # @html_safe = false
310
+ if block # if block
311
+ super(*args) { |*params| # super(*args) { |*params|
312
+ set_block_back_references(block, $~) # set_block_back_references(block, $~)
313
+ block.call(*params) # block.call(*params)
314
+ } # }
315
+ else # else
316
+ super # super
317
+ end # end
318
+ end # end
319
+ EOT
292
320
  end
293
321
 
294
322
  private
295
- def html_escape_interpolated_argument(arg)
323
+ def explicit_html_escape_interpolated_argument(arg)
296
324
  (!html_safe? || arg.html_safe?) ? arg : CGI.escapeHTML(arg.to_s)
297
325
  end
298
326
 
327
+ def implicit_html_escape_interpolated_argument(arg)
328
+ if !html_safe? || arg.html_safe?
329
+ arg
330
+ else
331
+ arg_string = begin
332
+ arg.to_str
333
+ rescue NoMethodError => error
334
+ if error.name == :to_str
335
+ str = arg.to_s
336
+ ActiveSupport::Deprecation.warn <<~MSG.squish
337
+ Implicit conversion of #{arg.class} into String by ActiveSupport::SafeBuffer
338
+ is deprecated and will be removed in Rails 7.1.
339
+ You must explicitly cast it to a String.
340
+ MSG
341
+ str
342
+ else
343
+ raise
344
+ end
345
+ end
346
+ CGI.escapeHTML(arg_string)
347
+ end
348
+ end
349
+
299
350
  def set_block_back_references(block, match_data)
300
351
  block.binding.eval("proc { |m| $~ = m }").call(match_data)
301
352
  rescue ArgumentError
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class String
4
- alias_method :starts_with?, :start_with?
5
- alias_method :ends_with?, :end_with?
4
+ alias :starts_with? :start_with?
5
+ alias :ends_with? :end_with?
6
6
  end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Symbol
4
+ alias :starts_with? :start_with?
5
+ alias :ends_with? :end_with?
6
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/symbol/starts_ends_with"
@@ -6,6 +6,7 @@ require "active_support/time_with_zone"
6
6
  require "active_support/core_ext/time/zones"
7
7
  require "active_support/core_ext/date_and_time/calculations"
8
8
  require "active_support/core_ext/date/calculations"
9
+ require "active_support/core_ext/module/remove_method"
9
10
 
10
11
  class Time
11
12
  include DateAndTime::Calculations
@@ -41,8 +42,8 @@ class Time
41
42
 
42
43
  # Layers additional behavior on Time.at so that ActiveSupport::TimeWithZone and DateTime
43
44
  # instances can be used when called with a single argument
44
- def at_with_coercion(*args)
45
- return at_without_coercion(*args) if args.size != 1
45
+ def at_with_coercion(*args, **kwargs)
46
+ return at_without_coercion(*args, **kwargs) if args.size != 1 || !kwargs.empty?
46
47
 
47
48
  # Time.at can be called with a time or numerical value
48
49
  time_or_number = args.first
@@ -107,11 +108,26 @@ class Time
107
108
  subsec
108
109
  end
109
110
 
111
+ unless Time.method_defined?(:floor)
112
+ def floor(precision = 0)
113
+ change(nsec: 0) + subsec.floor(precision)
114
+ end
115
+ end
116
+
117
+ # Restricted Ruby version due to a bug in `Time#ceil`
118
+ # See https://bugs.ruby-lang.org/issues/17025 for more details
119
+ if RUBY_VERSION <= "2.8"
120
+ remove_possible_method :ceil
121
+ def ceil(precision = 0)
122
+ change(nsec: 0) + subsec.ceil(precision)
123
+ end
124
+ end
125
+
110
126
  # Returns a new Time where one or more of the elements have been changed according
111
127
  # to the +options+ parameter. The time options (<tt>:hour</tt>, <tt>:min</tt>,
112
128
  # <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>) reset cascadingly, so if only
113
- # the hour is passed, then minute, sec, usec and nsec is set to 0. If the hour
114
- # and minute is passed, then sec, usec and nsec is set to 0. The +options+ parameter
129
+ # the hour is passed, then minute, sec, usec, and nsec is set to 0. If the hour
130
+ # and minute is passed, then sec, usec, and nsec is set to 0. The +options+ parameter
115
131
  # takes a hash with any of these keys: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>,
116
132
  # <tt>:hour</tt>, <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>,
117
133
  # <tt>:offset</tt>. Pass either <tt>:usec</tt> or <tt>:nsec</tt>, not both.
@@ -143,6 +159,8 @@ class Time
143
159
  ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, new_offset)
144
160
  elsif utc?
145
161
  ::Time.utc(new_year, new_month, new_day, new_hour, new_min, new_sec)
162
+ elsif zone&.respond_to?(:utc_to_local)
163
+ ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, zone)
146
164
  elsif zone
147
165
  ::Time.local(new_year, new_month, new_day, new_hour, new_min, new_sec)
148
166
  else
@@ -259,7 +277,7 @@ class Time
259
277
  end
260
278
  alias :at_end_of_minute :end_of_minute
261
279
 
262
- def plus_with_duration(other) #:nodoc:
280
+ def plus_with_duration(other) # :nodoc:
263
281
  if ActiveSupport::Duration === other
264
282
  other.since(self)
265
283
  else
@@ -269,7 +287,7 @@ class Time
269
287
  alias_method :plus_without_duration, :+
270
288
  alias_method :+, :plus_with_duration
271
289
 
272
- def minus_with_duration(other) #:nodoc:
290
+ def minus_with_duration(other) # :nodoc:
273
291
  if ActiveSupport::Duration === other
274
292
  other.until(self)
275
293
  else
@@ -287,7 +305,7 @@ class Time
287
305
  other.is_a?(DateTime) ? to_f - other.to_f : minus_without_coercion(other)
288
306
  end
289
307
  alias_method :minus_without_coercion, :-
290
- alias_method :-, :minus_with_coercion
308
+ alias_method :-, :minus_with_coercion # rubocop:disable Lint/DuplicateMethods
291
309
 
292
310
  # Layers additional behavior on Time#<=> so that DateTime and ActiveSupport::TimeWithZone instances
293
311
  # can be chronologically compared with a Time
@@ -1,11 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "time"
3
4
  require "active_support/inflector/methods"
4
5
  require "active_support/values/time_zone"
5
6
 
6
7
  class Time
7
8
  DATE_FORMATS = {
8
9
  db: "%Y-%m-%d %H:%M:%S",
10
+ inspect: "%Y-%m-%d %H:%M:%S.%9N %z",
9
11
  number: "%Y%m%d%H%M%S",
10
12
  nsec: "%Y%m%d%H%M%S%9N",
11
13
  usec: "%Y%m%d%H%M%S%6N",
@@ -25,22 +27,22 @@ class Time
25
27
 
26
28
  # Converts to a formatted string. See DATE_FORMATS for built-in formats.
27
29
  #
28
- # This method is aliased to <tt>to_s</tt>.
30
+ # This method is aliased to <tt>to_formatted_s</tt>.
29
31
  #
30
32
  # time = Time.now # => 2007-01-18 06:10:17 -06:00
31
33
  #
34
+ # time.to_fs(:time) # => "06:10"
32
35
  # time.to_formatted_s(:time) # => "06:10"
33
- # time.to_s(:time) # => "06:10"
34
36
  #
35
- # time.to_formatted_s(:db) # => "2007-01-18 06:10:17"
36
- # time.to_formatted_s(:number) # => "20070118061017"
37
- # time.to_formatted_s(:short) # => "18 Jan 06:10"
38
- # time.to_formatted_s(:long) # => "January 18, 2007 06:10"
39
- # time.to_formatted_s(:long_ordinal) # => "January 18th, 2007 06:10"
40
- # time.to_formatted_s(:rfc822) # => "Thu, 18 Jan 2007 06:10:17 -0600"
41
- # time.to_formatted_s(:iso8601) # => "2007-01-18T06:10:17-06:00"
37
+ # time.to_fs(:db) # => "2007-01-18 06:10:17"
38
+ # time.to_fs(:number) # => "20070118061017"
39
+ # time.to_fs(:short) # => "18 Jan 06:10"
40
+ # time.to_fs(:long) # => "January 18, 2007 06:10"
41
+ # time.to_fs(:long_ordinal) # => "January 18th, 2007 06:10"
42
+ # time.to_fs(:rfc822) # => "Thu, 18 Jan 2007 06:10:17 -0600"
43
+ # time.to_fs(:iso8601) # => "2007-01-18T06:10:17-06:00"
42
44
  #
43
- # == Adding your own time formats to +to_formatted_s+
45
+ # == Adding your own time formats to +to_fs+
44
46
  # You can add your own formats to the Time::DATE_FORMATS hash.
45
47
  # Use the format name as the hash key and either a strftime string
46
48
  # or Proc instance that takes a time argument as the value.
@@ -48,15 +50,16 @@ class Time
48
50
  # # config/initializers/time_formats.rb
49
51
  # Time::DATE_FORMATS[:month_and_year] = '%B %Y'
50
52
  # Time::DATE_FORMATS[:short_ordinal] = ->(time) { time.strftime("%B #{time.day.ordinalize}") }
51
- def to_formatted_s(format = :default)
53
+ def to_fs(format = :default)
52
54
  if formatter = DATE_FORMATS[format]
53
55
  formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
54
56
  else
57
+ # Change to `to_s` when deprecation is gone. Also deprecate `to_default_s`.
55
58
  to_default_s
56
59
  end
57
60
  end
61
+ alias_method :to_formatted_s, :to_fs
58
62
  alias_method :to_default_s, :to_s
59
- alias_method :to_s, :to_formatted_s
60
63
 
61
64
  # Returns a formatted string of the offset from UTC, or an alternative
62
65
  # string if the time zone is already UTC.
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "time"
4
+
5
+ class Time
6
+ NOT_SET = Object.new # :nodoc:
7
+ def to_s(format = NOT_SET) # :nodoc:
8
+ if formatter = DATE_FORMATS[format]
9
+ ActiveSupport::Deprecation.warn(
10
+ "Time#to_s(#{format.inspect}) is deprecated. Please use Time#to_fs(#{format.inspect}) instead."
11
+ )
12
+ formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
13
+ elsif format == NOT_SET
14
+ to_default_s
15
+ else
16
+ ActiveSupport::Deprecation.warn(
17
+ "Time#to_s(#{format.inspect}) is deprecated. Please use Time#to_fs(#{format.inspect}) instead."
18
+ )
19
+ to_default_s
20
+ end
21
+ end
22
+ end
@@ -12,7 +12,7 @@ class Time
12
12
  # Returns the TimeZone for the current request, if this has been set (via Time.zone=).
13
13
  # If <tt>Time.zone</tt> has not been set for the current request, returns the TimeZone specified in <tt>config.time_zone</tt>.
14
14
  def zone
15
- Thread.current[:time_zone] || zone_default
15
+ ::ActiveSupport::IsolatedExecutionState[:time_zone] || zone_default
16
16
  end
17
17
 
18
18
  # Sets <tt>Time.zone</tt> to a TimeZone object for the current request/thread.
@@ -21,8 +21,8 @@ class Time
21
21
  #
22
22
  # * A Rails TimeZone object.
23
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").
24
+ # * A <tt>TZInfo::Timezone</tt> object.
25
+ # * An identifier for a <tt>TZInfo::Timezone</tt> 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:
@@ -39,7 +39,7 @@ class Time
39
39
  # end
40
40
  # end
41
41
  def zone=(time_zone)
42
- Thread.current[:time_zone] = find_zone!(time_zone)
42
+ ::ActiveSupport::IsolatedExecutionState[:time_zone] = find_zone!(time_zone)
43
43
  end
44
44
 
45
45
  # Allows override of <tt>Time.zone</tt> locally inside supplied block;
@@ -55,7 +55,7 @@ class Time
55
55
  # end
56
56
  # end
57
57
  #
58
- # NOTE: This won't affect any <tt>ActiveSupport::TimeWithZone</tt>
58
+ # NOTE: This won't affect any ActiveSupport::TimeWithZone
59
59
  # objects that have already been created, e.g. any model timestamp
60
60
  # attributes that have been read before the block will remain in
61
61
  # the application's default timezone.
@@ -80,24 +80,9 @@ class Time
80
80
  # Time.find_zone! false # => false
81
81
  # Time.find_zone! "NOT-A-TIMEZONE" # => ArgumentError: Invalid Timezone: NOT-A-TIMEZONE
82
82
  def find_zone!(time_zone)
83
- if !time_zone || time_zone.is_a?(ActiveSupport::TimeZone)
84
- time_zone
85
- else
86
- # Look up the timezone based on the identifier (unless we've been
87
- # passed a TZInfo::Timezone)
88
- unless time_zone.respond_to?(:period_for_local)
89
- time_zone = ActiveSupport::TimeZone[time_zone] || TZInfo::Timezone.get(time_zone)
90
- end
83
+ return time_zone unless time_zone
91
84
 
92
- # Return if a TimeZone instance, or wrap in a TimeZone instance if a TZInfo::Timezone
93
- if time_zone.is_a?(ActiveSupport::TimeZone)
94
- time_zone
95
- else
96
- ActiveSupport::TimeZone.create(time_zone.name, nil, time_zone)
97
- end
98
- end
99
- rescue TZInfo::InvalidTimezoneIdentifier
100
- raise ArgumentError, "Invalid Timezone: #{time_zone}"
85
+ ActiveSupport::TimeZone[time_zone] || raise(ArgumentError, "Invalid Timezone: #{time_zone}")
101
86
  end
102
87
 
103
88
  # Returns a TimeZone instance matching the time zone provided.
@@ -4,4 +4,5 @@ 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"]
7
8
  require "active_support/core_ext/time/zones"
@@ -1,25 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "uri"
4
-
5
- if RUBY_VERSION < "2.6.0"
6
- require "active_support/core_ext/module/redefine_method"
7
- URI::Parser.class_eval do
8
- silence_redefinition_of_method :unescape
9
- def unescape(str, escaped = /%[a-fA-F\d]{2}/)
10
- # TODO: Are we actually sure that ASCII == UTF-8?
11
- # YK: My initial experiments say yes, but let's be sure please
12
- enc = str.encoding
13
- enc = Encoding::UTF_8 if enc == Encoding::US_ASCII
14
- str.dup.force_encoding(Encoding::ASCII_8BIT).gsub(escaped) { |match| [match[1, 2].hex].pack("C") }.force_encoding(enc)
15
- end
16
- end
17
- end
18
-
19
- module URI
20
- class << self
21
- def parser
22
- @parser ||= URI::Parser.new
23
- end
24
- end
25
- end
3
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
4
+ `active_support/core_ext/uri` is deprecated and will be removed in Rails 7.1.
5
+ MSG
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- Dir.glob(File.expand_path("core_ext/*.rb", __dir__)).each do |path|
3
+ Dir.glob(File.expand_path("core_ext/*.rb", __dir__)).sort.each do |path|
4
+ next if path.end_with?("core_ext/uri.rb")
4
5
  require path
5
6
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport::CurrentAttributes::TestHelper # :nodoc:
4
+ def before_setup
5
+ ActiveSupport::CurrentAttributes.reset_all
6
+ super
7
+ end
8
+
9
+ def after_teardown
10
+ super
11
+ ActiveSupport::CurrentAttributes.reset_all
12
+ end
13
+ end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/callbacks"
4
+ require "active_support/core_ext/enumerable"
5
+ require "active_support/core_ext/module/delegation"
4
6
 
5
7
  module ActiveSupport
6
8
  # Abstract super class that provides a thread-isolated attributes singleton, which resets automatically
@@ -91,30 +93,42 @@ module ActiveSupport
91
93
  class << self
92
94
  # Returns singleton instance for this class in this thread. If none exists, one is created.
93
95
  def instance
94
- current_instances[name] ||= new
96
+ current_instances[current_instances_key] ||= new
95
97
  end
96
98
 
97
99
  # Declares one or more attributes that will be given both class and instance accessor methods.
98
100
  def attribute(*names)
99
- generated_attribute_methods.module_eval do
101
+ ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |owner|
100
102
  names.each do |name|
101
- define_method(name) do
102
- attributes[name.to_sym]
103
+ owner.define_cached_method(name, namespace: :current_attributes) do |batch|
104
+ batch <<
105
+ "def #{name}" <<
106
+ "attributes[:#{name}]" <<
107
+ "end"
103
108
  end
104
-
105
- define_method("#{name}=") do |attribute|
106
- attributes[name.to_sym] = attribute
109
+ owner.define_cached_method("#{name}=", namespace: :current_attributes) do |batch|
110
+ batch <<
111
+ "def #{name}=(value)" <<
112
+ "attributes[:#{name}] = value" <<
113
+ "end"
107
114
  end
108
115
  end
109
116
  end
110
117
 
111
- names.each do |name|
112
- define_singleton_method(name) do
113
- instance.public_send(name)
114
- end
115
-
116
- define_singleton_method("#{name}=") do |attribute|
117
- instance.public_send("#{name}=", attribute)
118
+ ActiveSupport::CodeGenerator.batch(singleton_class, __FILE__, __LINE__) do |owner|
119
+ names.each do |name|
120
+ owner.define_cached_method(name, namespace: :current_attributes_delegation) do |batch|
121
+ batch <<
122
+ "def #{name}" <<
123
+ "instance.#{name}" <<
124
+ "end"
125
+ end
126
+ owner.define_cached_method("#{name}=", namespace: :current_attributes_delegation) do |batch|
127
+ batch <<
128
+ "def #{name}=(value)" <<
129
+ "instance.#{name} = value" <<
130
+ "end"
131
+ end
118
132
  end
119
133
  end
120
134
  end
@@ -147,7 +161,11 @@ module ActiveSupport
147
161
  end
148
162
 
149
163
  def current_instances
150
- Thread.current[:current_attributes_instances] ||= {}
164
+ IsolatedExecutionState[:current_attributes_instances] ||= {}
165
+ end
166
+
167
+ def current_instances_key
168
+ @current_instances_key ||= name.to_sym
151
169
  end
152
170
 
153
171
  def method_missing(name, *args, &block)
@@ -158,6 +176,11 @@ module ActiveSupport
158
176
 
159
177
  send(name, *args, &block)
160
178
  end
179
+ ruby2_keywords(:method_missing)
180
+
181
+ def respond_to_missing?(name, _)
182
+ super || instance.respond_to?(name)
183
+ end
161
184
  end
162
185
 
163
186
  attr_accessor :attributes
@@ -197,7 +220,7 @@ module ActiveSupport
197
220
  end
198
221
 
199
222
  def compute_attributes(keys)
200
- keys.collect { |key| [ key, public_send(key) ] }.to_h
223
+ keys.index_with { |key| public_send(key) }
201
224
  end
202
225
  end
203
226
  end