activesupport 6.1.0 → 7.0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +263 -352
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/active_support/actionable_error.rb +1 -1
  6. data/lib/active_support/array_inquirer.rb +0 -2
  7. data/lib/active_support/backtrace_cleaner.rb +2 -2
  8. data/lib/active_support/benchmarkable.rb +2 -2
  9. data/lib/active_support/cache/file_store.rb +16 -10
  10. data/lib/active_support/cache/mem_cache_store.rb +154 -39
  11. data/lib/active_support/cache/memory_store.rb +24 -16
  12. data/lib/active_support/cache/null_store.rb +10 -2
  13. data/lib/active_support/cache/redis_cache_store.rb +59 -78
  14. data/lib/active_support/cache/strategy/local_cache.rb +38 -61
  15. data/lib/active_support/cache.rb +306 -148
  16. data/lib/active_support/callbacks.rb +184 -85
  17. data/lib/active_support/code_generator.rb +65 -0
  18. data/lib/active_support/concern.rb +5 -5
  19. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
  20. data/lib/active_support/concurrency/share_lock.rb +2 -2
  21. data/lib/active_support/configurable.rb +8 -5
  22. data/lib/active_support/configuration_file.rb +7 -2
  23. data/lib/active_support/core_ext/array/access.rb +1 -5
  24. data/lib/active_support/core_ext/array/conversions.rb +13 -12
  25. data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
  26. data/lib/active_support/core_ext/array/grouping.rb +6 -6
  27. data/lib/active_support/core_ext/array/inquiry.rb +2 -2
  28. data/lib/active_support/core_ext/array.rb +1 -0
  29. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  30. data/lib/active_support/core_ext/class/subclasses.rb +25 -17
  31. data/lib/active_support/core_ext/date/blank.rb +1 -1
  32. data/lib/active_support/core_ext/date/calculations.rb +9 -9
  33. data/lib/active_support/core_ext/date/conversions.rb +14 -14
  34. data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
  35. data/lib/active_support/core_ext/date.rb +1 -0
  36. data/lib/active_support/core_ext/date_and_time/calculations.rb +4 -4
  37. data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
  38. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  39. data/lib/active_support/core_ext/date_time/conversions.rb +13 -13
  40. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
  41. data/lib/active_support/core_ext/date_time.rb +1 -0
  42. data/lib/active_support/core_ext/digest/uuid.rb +39 -13
  43. data/lib/active_support/core_ext/enumerable.rb +101 -32
  44. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  45. data/lib/active_support/core_ext/hash/conversions.rb +0 -1
  46. data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
  47. data/lib/active_support/core_ext/hash/keys.rb +1 -1
  48. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  49. data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
  50. data/lib/active_support/core_ext/module/attribute_accessors.rb +2 -0
  51. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +19 -10
  52. data/lib/active_support/core_ext/module/delegation.rb +2 -8
  53. data/lib/active_support/core_ext/name_error.rb +2 -8
  54. data/lib/active_support/core_ext/numeric/conversions.rb +80 -77
  55. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
  56. data/lib/active_support/core_ext/numeric.rb +1 -0
  57. data/lib/active_support/core_ext/object/acts_like.rb +29 -5
  58. data/lib/active_support/core_ext/object/blank.rb +2 -2
  59. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  60. data/lib/active_support/core_ext/object/duplicable.rb +11 -0
  61. data/lib/active_support/core_ext/object/json.rb +37 -25
  62. data/lib/active_support/core_ext/object/to_query.rb +2 -2
  63. data/lib/active_support/core_ext/object/try.rb +20 -20
  64. data/lib/active_support/core_ext/object/with_options.rb +20 -1
  65. data/lib/active_support/core_ext/pathname/existence.rb +21 -0
  66. data/lib/active_support/core_ext/pathname.rb +3 -0
  67. data/lib/active_support/core_ext/range/compare_range.rb +0 -25
  68. data/lib/active_support/core_ext/range/conversions.rb +8 -8
  69. data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
  70. data/lib/active_support/core_ext/range/each.rb +1 -1
  71. data/lib/active_support/core_ext/range/include_time_with_zone.rb +4 -25
  72. data/lib/active_support/core_ext/range/overlaps.rb +1 -1
  73. data/lib/active_support/core_ext/range.rb +1 -1
  74. data/lib/active_support/core_ext/securerandom.rb +1 -1
  75. data/lib/active_support/core_ext/string/conversions.rb +2 -2
  76. data/lib/active_support/core_ext/string/filters.rb +1 -1
  77. data/lib/active_support/core_ext/string/inflections.rb +1 -1
  78. data/lib/active_support/core_ext/string/inquiry.rb +1 -1
  79. data/lib/active_support/core_ext/string/output_safety.rb +91 -39
  80. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
  81. data/lib/active_support/core_ext/time/calculations.rb +9 -7
  82. data/lib/active_support/core_ext/time/conversions.rb +14 -12
  83. data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
  84. data/lib/active_support/core_ext/time/zones.rb +7 -22
  85. data/lib/active_support/core_ext/time.rb +1 -0
  86. data/lib/active_support/core_ext/uri.rb +3 -27
  87. data/lib/active_support/core_ext.rb +2 -1
  88. data/lib/active_support/current_attributes.rb +32 -14
  89. data/lib/active_support/dependencies/interlock.rb +10 -18
  90. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  91. data/lib/active_support/dependencies.rb +58 -788
  92. data/lib/active_support/deprecation/behaviors.rb +8 -5
  93. data/lib/active_support/deprecation/method_wrappers.rb +3 -3
  94. data/lib/active_support/deprecation/proxy_wrappers.rb +2 -2
  95. data/lib/active_support/deprecation.rb +2 -2
  96. data/lib/active_support/descendants_tracker.rb +174 -68
  97. data/lib/active_support/digest.rb +5 -3
  98. data/lib/active_support/duration/iso8601_parser.rb +3 -3
  99. data/lib/active_support/duration/iso8601_serializer.rb +9 -1
  100. data/lib/active_support/duration.rb +81 -51
  101. data/lib/active_support/encrypted_configuration.rb +13 -2
  102. data/lib/active_support/encrypted_file.rb +13 -1
  103. data/lib/active_support/environment_inquirer.rb +1 -1
  104. data/lib/active_support/error_reporter.rb +117 -0
  105. data/lib/active_support/evented_file_update_checker.rb +3 -5
  106. data/lib/active_support/execution_context/test_helper.rb +13 -0
  107. data/lib/active_support/execution_context.rb +53 -0
  108. data/lib/active_support/execution_wrapper.rb +43 -21
  109. data/lib/active_support/executor/test_helper.rb +7 -0
  110. data/lib/active_support/fork_tracker.rb +19 -10
  111. data/lib/active_support/gem_version.rb +5 -5
  112. data/lib/active_support/hash_with_indifferent_access.rb +9 -2
  113. data/lib/active_support/html_safe_translation.rb +43 -0
  114. data/lib/active_support/i18n.rb +1 -0
  115. data/lib/active_support/i18n_railtie.rb +1 -1
  116. data/lib/active_support/inflector/inflections.rb +23 -7
  117. data/lib/active_support/inflector/methods.rb +24 -48
  118. data/lib/active_support/inflector/transliterate.rb +1 -1
  119. data/lib/active_support/isolated_execution_state.rb +72 -0
  120. data/lib/active_support/json/encoding.rb +3 -3
  121. data/lib/active_support/key_generator.rb +22 -5
  122. data/lib/active_support/lazy_load_hooks.rb +28 -4
  123. data/lib/active_support/locale/en.yml +2 -2
  124. data/lib/active_support/log_subscriber/test_helper.rb +2 -2
  125. data/lib/active_support/log_subscriber.rb +15 -5
  126. data/lib/active_support/logger_thread_safe_level.rb +4 -13
  127. data/lib/active_support/message_encryptor.rb +12 -6
  128. data/lib/active_support/message_verifier.rb +46 -14
  129. data/lib/active_support/messages/metadata.rb +2 -2
  130. data/lib/active_support/multibyte/chars.rb +10 -11
  131. data/lib/active_support/multibyte/unicode.rb +0 -12
  132. data/lib/active_support/multibyte.rb +1 -1
  133. data/lib/active_support/notifications/fanout.rb +91 -65
  134. data/lib/active_support/notifications/instrumenter.rb +32 -15
  135. data/lib/active_support/notifications.rb +24 -24
  136. data/lib/active_support/number_helper/number_converter.rb +1 -3
  137. data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
  138. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  139. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  140. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
  141. data/lib/active_support/number_helper/number_to_rounded_converter.rb +10 -6
  142. data/lib/active_support/number_helper/rounding_helper.rb +2 -6
  143. data/lib/active_support/number_helper.rb +0 -2
  144. data/lib/active_support/option_merger.rb +10 -18
  145. data/lib/active_support/ordered_hash.rb +1 -1
  146. data/lib/active_support/ordered_options.rb +1 -1
  147. data/lib/active_support/parameter_filter.rb +6 -1
  148. data/lib/active_support/per_thread_registry.rb +5 -0
  149. data/lib/active_support/railtie.rb +69 -19
  150. data/lib/active_support/reloader.rb +1 -1
  151. data/lib/active_support/rescuable.rb +16 -16
  152. data/lib/active_support/ruby_features.rb +7 -0
  153. data/lib/active_support/secure_compare_rotator.rb +2 -2
  154. data/lib/active_support/security_utils.rb +1 -1
  155. data/lib/active_support/string_inquirer.rb +0 -2
  156. data/lib/active_support/subscriber.rb +7 -18
  157. data/lib/active_support/tagged_logging.rb +2 -2
  158. data/lib/active_support/test_case.rb +13 -21
  159. data/lib/active_support/testing/assertions.rb +36 -6
  160. data/lib/active_support/testing/deprecation.rb +52 -1
  161. data/lib/active_support/testing/isolation.rb +2 -2
  162. data/lib/active_support/testing/method_call_assertions.rb +5 -5
  163. data/lib/active_support/testing/parallelization/server.rb +4 -0
  164. data/lib/active_support/testing/parallelization/worker.rb +3 -0
  165. data/lib/active_support/testing/parallelization.rb +4 -0
  166. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  167. data/lib/active_support/testing/stream.rb +3 -5
  168. data/lib/active_support/testing/tagged_logging.rb +1 -1
  169. data/lib/active_support/testing/time_helpers.rb +13 -2
  170. data/lib/active_support/time_with_zone.rb +60 -20
  171. data/lib/active_support/values/time_zone.rb +36 -15
  172. data/lib/active_support/version.rb +1 -1
  173. data/lib/active_support/xml_mini/jdom.rb +1 -1
  174. data/lib/active_support/xml_mini/libxml.rb +5 -5
  175. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  176. data/lib/active_support/xml_mini/nokogiri.rb +4 -4
  177. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  178. data/lib/active_support/xml_mini/rexml.rb +1 -1
  179. data/lib/active_support/xml_mini.rb +5 -4
  180. data/lib/active_support.rb +17 -1
  181. metadata +29 -26
  182. data/lib/active_support/core_ext/marshal.rb +0 -26
  183. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/range/conversions"
4
+ require "active_support/core_ext/range/deprecated_conversions" unless ENV["RAILS_DISABLE_DEPRECATED_TO_S_CONVERSION"]
4
5
  require "active_support/core_ext/range/compare_range"
5
- require "active_support/core_ext/range/include_time_with_zone"
6
6
  require "active_support/core_ext/range/overlaps"
7
7
  require "active_support/core_ext/range/each"
@@ -12,7 +12,7 @@ module SecureRandom
12
12
  #
13
13
  # If _n_ is not specified or is +nil+, 16 is assumed. It may be larger in the future.
14
14
  #
15
- # The result may contain alphanumeric characters except 0, O, I and l.
15
+ # The result may contain alphanumeric characters except 0, O, I, and l.
16
16
  #
17
17
  # p SecureRandom.base58 # => "4kUgL2pdQMSCQtjE"
18
18
  # p SecureRandom.base58(24) # => "77TMHrHJFvFDwodq8w7Ev2m7"
@@ -5,10 +5,10 @@ require "active_support/core_ext/time/calculations"
5
5
 
6
6
  class String
7
7
  # Converts a string to a Time value.
8
- # The +form+ can be either :utc or :local (default :local).
8
+ # The +form+ can be either +:utc+ or +:local+ (default +:local+).
9
9
  #
10
10
  # The time is parsed using Time.parse method.
11
- # If +form+ is :local, then the time is in the system timezone.
11
+ # If +form+ is +:local+, then the time is in the system timezone.
12
12
  # If the date part is missing then the current date is used and if
13
13
  # the time part is missing then it is assumed to be 00:00:00.
14
14
  #
@@ -106,7 +106,7 @@ class String
106
106
  self.class.new.tap do |cut|
107
107
  cut_at = truncate_at - omission.bytesize
108
108
 
109
- scan(/\X/) do |grapheme|
109
+ each_grapheme_cluster do |grapheme|
110
110
  if cut.bytesize + grapheme.bytesize <= cut_at
111
111
  cut << grapheme
112
112
  else
@@ -260,7 +260,7 @@ class String
260
260
  # 'author_id'.humanize # => "Author"
261
261
  # 'author_id'.humanize(capitalize: false) # => "author"
262
262
  # '_id'.humanize # => "Id"
263
- # 'author_id'.humanize(keep_id_suffix: true) # => "Author Id"
263
+ # 'author_id'.humanize(keep_id_suffix: true) # => "Author id"
264
264
  #
265
265
  # See ActiveSupport::Inflector.humanize.
266
266
  def humanize(capitalize: true, keep_id_suffix: false)
@@ -4,7 +4,7 @@ require "active_support/string_inquirer"
4
4
  require "active_support/environment_inquirer"
5
5
 
6
6
  class String
7
- # Wraps the current string in the <tt>ActiveSupport::StringInquirer</tt> class,
7
+ # Wraps the current string in the ActiveSupport::StringInquirer class,
8
8
  # which gives you a prettier way to test for equality.
9
9
  #
10
10
  # env = 'production'.inquiry
@@ -11,6 +11,14 @@ class ERB
11
11
  HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+)|(#[xX][\dA-Fa-f]+));)/
12
12
  JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/u
13
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
+
14
22
  # A utility method for escaping HTML tag characters.
15
23
  # This method is also aliased as <tt>h</tt>.
16
24
  #
@@ -84,7 +92,7 @@ class ERB
84
92
  # use inside HTML attributes.
85
93
  #
86
94
  # If your JSON is being used downstream for insertion into the DOM, be aware of
87
- # 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.
88
96
  # If that is the case, be sure to +html_escape+ or +sanitize+ any user-generated
89
97
  # content returned by your JSON.
90
98
  #
@@ -97,7 +105,7 @@ class ERB
97
105
  # WARNING: this helper only works with valid JSON. Using this on non-JSON values
98
106
  # will open up serious XSS vulnerabilities. For example, if you replace the
99
107
  # +current_user.to_json+ in the example above with user input instead, the browser
100
- # will happily eval() that string as JavaScript.
108
+ # will happily <tt>eval()</tt> that string as JavaScript.
101
109
  #
102
110
  # The escaping performed in this method is identical to those performed in the
103
111
  # Active Support JSON encoder when +ActiveSupport.escape_html_entities_in_json+ is
@@ -115,6 +123,26 @@ class ERB
115
123
  end
116
124
 
117
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
118
146
  end
119
147
  end
120
148
 
@@ -130,7 +158,7 @@ class Numeric
130
158
  end
131
159
  end
132
160
 
133
- module ActiveSupport #:nodoc:
161
+ module ActiveSupport # :nodoc:
134
162
  class SafeBuffer < String
135
163
  UNSAFE_STRING_METHODS = %w(
136
164
  capitalize chomp chop delete delete_prefix delete_suffix
@@ -143,7 +171,7 @@ module ActiveSupport #:nodoc:
143
171
  alias_method :original_concat, :concat
144
172
  private :original_concat
145
173
 
146
- # 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.
147
175
  class SafeConcatError < StandardError
148
176
  def initialize
149
177
  super "Could not concatenate to the buffer because it is not html safe."
@@ -184,27 +212,30 @@ module ActiveSupport #:nodoc:
184
212
  end
185
213
 
186
214
  def concat(value)
187
- super(html_escape_interpolated_argument(value))
215
+ unless value.nil?
216
+ super(implicit_html_escape_interpolated_argument(value))
217
+ end
218
+ self
188
219
  end
189
220
  alias << concat
190
221
 
191
222
  def insert(index, value)
192
- super(index, html_escape_interpolated_argument(value))
223
+ super(index, implicit_html_escape_interpolated_argument(value))
193
224
  end
194
225
 
195
226
  def prepend(value)
196
- super(html_escape_interpolated_argument(value))
227
+ super(implicit_html_escape_interpolated_argument(value))
197
228
  end
198
229
 
199
230
  def replace(value)
200
- super(html_escape_interpolated_argument(value))
231
+ super(implicit_html_escape_interpolated_argument(value))
201
232
  end
202
233
 
203
234
  def []=(*args)
204
235
  if args.length == 3
205
- super(args[0], args[1], html_escape_interpolated_argument(args[2]))
236
+ super(args[0], args[1], implicit_html_escape_interpolated_argument(args[2]))
206
237
  else
207
- super(args[0], html_escape_interpolated_argument(args[1]))
238
+ super(args[0], implicit_html_escape_interpolated_argument(args[1]))
208
239
  end
209
240
  end
210
241
 
@@ -222,9 +253,9 @@ module ActiveSupport #:nodoc:
222
253
  def %(args)
223
254
  case args
224
255
  when Hash
225
- escaped_args = args.transform_values { |arg| html_escape_interpolated_argument(arg) }
256
+ escaped_args = args.transform_values { |arg| explicit_html_escape_interpolated_argument(arg) }
226
257
  else
227
- escaped_args = Array(args).map { |arg| html_escape_interpolated_argument(arg) }
258
+ escaped_args = Array(args).map { |arg| explicit_html_escape_interpolated_argument(arg) }
228
259
  end
229
260
 
230
261
  self.class.new(super(escaped_args))
@@ -262,39 +293,60 @@ module ActiveSupport #:nodoc:
262
293
  end
263
294
 
264
295
  UNSAFE_STRING_METHODS_WITH_BACKREF.each do |unsafe_method|
265
- if unsafe_method.respond_to?(unsafe_method)
266
- class_eval <<-EOT, __FILE__, __LINE__ + 1
267
- def #{unsafe_method}(*args, &block) # def gsub(*args, &block)
268
- if block # if block
269
- to_str.#{unsafe_method}(*args) { |*params| # to_str.gsub(*args) { |*params|
270
- set_block_back_references(block, $~) # set_block_back_references(block, $~)
271
- block.call(*params) # block.call(*params)
272
- } # }
273
- else # else
274
- to_str.#{unsafe_method}(*args) # to_str.gsub(*args)
275
- end # end
276
- end # end
277
-
278
- def #{unsafe_method}!(*args, &block) # def gsub!(*args, &block)
279
- @html_safe = false # @html_safe = false
280
- if block # if block
281
- super(*args) { |*params| # super(*args) { |*params|
282
- set_block_back_references(block, $~) # set_block_back_references(block, $~)
283
- block.call(*params) # block.call(*params)
284
- } # }
285
- else # else
286
- super # super
287
- end # end
288
- end # end
289
- EOT
290
- 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
291
320
  end
292
321
 
293
322
  private
294
- def html_escape_interpolated_argument(arg)
323
+ def explicit_html_escape_interpolated_argument(arg)
295
324
  (!html_safe? || arg.html_safe?) ? arg : CGI.escapeHTML(arg.to_s)
296
325
  end
297
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
+
298
350
  def set_block_back_references(block, match_data)
299
351
  block.binding.eval("proc { |m| $~ = m }").call(match_data)
300
352
  rescue ArgumentError
@@ -1,14 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Symbol
4
- def start_with?(*prefixes)
5
- to_s.start_with?(*prefixes)
6
- end unless method_defined?(:start_with?)
7
-
8
- def end_with?(*suffixes)
9
- to_s.end_with?(*suffixes)
10
- end unless method_defined?(:end_with?)
11
-
12
4
  alias :starts_with? :start_with?
13
5
  alias :ends_with? :end_with?
14
6
  end
@@ -42,8 +42,8 @@ class Time
42
42
 
43
43
  # Layers additional behavior on Time.at so that ActiveSupport::TimeWithZone and DateTime
44
44
  # instances can be used when called with a single argument
45
- def at_with_coercion(*args)
46
- 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?
47
47
 
48
48
  # Time.at can be called with a time or numerical value
49
49
  time_or_number = args.first
@@ -126,8 +126,8 @@ class Time
126
126
  # Returns a new Time where one or more of the elements have been changed according
127
127
  # to the +options+ parameter. The time options (<tt>:hour</tt>, <tt>:min</tt>,
128
128
  # <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>) reset cascadingly, so if only
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
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
131
131
  # takes a hash with any of these keys: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>,
132
132
  # <tt>:hour</tt>, <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>,
133
133
  # <tt>:offset</tt>. Pass either <tt>:usec</tt> or <tt>:nsec</tt>, not both.
@@ -159,6 +159,8 @@ class Time
159
159
  ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, new_offset)
160
160
  elsif utc?
161
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)
162
164
  elsif zone
163
165
  ::Time.local(new_year, new_month, new_day, new_hour, new_min, new_sec)
164
166
  else
@@ -275,7 +277,7 @@ class Time
275
277
  end
276
278
  alias :at_end_of_minute :end_of_minute
277
279
 
278
- def plus_with_duration(other) #:nodoc:
280
+ def plus_with_duration(other) # :nodoc:
279
281
  if ActiveSupport::Duration === other
280
282
  other.since(self)
281
283
  else
@@ -285,7 +287,7 @@ class Time
285
287
  alias_method :plus_without_duration, :+
286
288
  alias_method :+, :plus_with_duration
287
289
 
288
- def minus_with_duration(other) #:nodoc:
290
+ def minus_with_duration(other) # :nodoc:
289
291
  if ActiveSupport::Duration === other
290
292
  other.until(self)
291
293
  else
@@ -303,7 +305,7 @@ class Time
303
305
  other.is_a?(DateTime) ? to_f - other.to_f : minus_without_coercion(other)
304
306
  end
305
307
  alias_method :minus_without_coercion, :-
306
- alias_method :-, :minus_with_coercion
308
+ alias_method :-, :minus_with_coercion # rubocop:disable Lint/DuplicateMethods
307
309
 
308
310
  # Layers additional behavior on Time#<=> so that DateTime and ActiveSupport::TimeWithZone instances
309
311
  # can be chronologically compared with a Time
@@ -1,5 +1,6 @@
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
 
@@ -26,22 +27,22 @@ class Time
26
27
 
27
28
  # Converts to a formatted string. See DATE_FORMATS for built-in formats.
28
29
  #
29
- # This method is aliased to <tt>to_s</tt>.
30
+ # This method is aliased to <tt>to_formatted_s</tt>.
30
31
  #
31
32
  # time = Time.now # => 2007-01-18 06:10:17 -06:00
32
33
  #
34
+ # time.to_fs(:time) # => "06:10"
33
35
  # time.to_formatted_s(:time) # => "06:10"
34
- # time.to_s(:time) # => "06:10"
35
36
  #
36
- # time.to_formatted_s(:db) # => "2007-01-18 06:10:17"
37
- # time.to_formatted_s(:number) # => "20070118061017"
38
- # time.to_formatted_s(:short) # => "18 Jan 06:10"
39
- # time.to_formatted_s(:long) # => "January 18, 2007 06:10"
40
- # time.to_formatted_s(:long_ordinal) # => "January 18th, 2007 06:10"
41
- # time.to_formatted_s(:rfc822) # => "Thu, 18 Jan 2007 06:10:17 -0600"
42
- # 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"
43
44
  #
44
- # == Adding your own time formats to +to_formatted_s+
45
+ # == Adding your own time formats to +to_fs+
45
46
  # You can add your own formats to the Time::DATE_FORMATS hash.
46
47
  # Use the format name as the hash key and either a strftime string
47
48
  # or Proc instance that takes a time argument as the value.
@@ -49,15 +50,16 @@ class Time
49
50
  # # config/initializers/time_formats.rb
50
51
  # Time::DATE_FORMATS[:month_and_year] = '%B %Y'
51
52
  # Time::DATE_FORMATS[:short_ordinal] = ->(time) { time.strftime("%B #{time.day.ordinalize}") }
52
- def to_formatted_s(format = :default)
53
+ def to_fs(format = :default)
53
54
  if formatter = DATE_FORMATS[format]
54
55
  formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
55
56
  else
57
+ # Change to `to_s` when deprecation is gone. Also deprecate `to_default_s`.
56
58
  to_default_s
57
59
  end
58
60
  end
61
+ alias_method :to_formatted_s, :to_fs
59
62
  alias_method :to_default_s, :to_s
60
- alias_method :to_s, :to_formatted_s
61
63
 
62
64
  # Returns a formatted string of the offset from UTC, or an alternative
63
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,29 +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
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
23
- URI.parser is deprecated and will be removed in Rails 6.2.
24
- Use `URI::DEFAULT_PARSER` instead.
25
- MSG
26
- URI::DEFAULT_PARSER
27
- end
28
- end
29
- 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
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "active_support/callbacks"
4
4
  require "active_support/core_ext/enumerable"
5
+ require "active_support/core_ext/module/delegation"
5
6
 
6
7
  module ActiveSupport
7
8
  # Abstract super class that provides a thread-isolated attributes singleton, which resets automatically
@@ -97,25 +98,37 @@ module ActiveSupport
97
98
 
98
99
  # Declares one or more attributes that will be given both class and instance accessor methods.
99
100
  def attribute(*names)
100
- generated_attribute_methods.module_eval do
101
+ ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |owner|
101
102
  names.each do |name|
102
- define_method(name) do
103
- 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"
104
108
  end
105
-
106
- define_method("#{name}=") do |attribute|
107
- 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"
108
114
  end
109
115
  end
110
116
  end
111
117
 
112
- names.each do |name|
113
- define_singleton_method(name) do
114
- instance.public_send(name)
115
- end
116
-
117
- define_singleton_method("#{name}=") do |attribute|
118
- 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
119
132
  end
120
133
  end
121
134
  end
@@ -148,7 +161,7 @@ module ActiveSupport
148
161
  end
149
162
 
150
163
  def current_instances
151
- Thread.current[:current_attributes_instances] ||= {}
164
+ IsolatedExecutionState[:current_attributes_instances] ||= {}
152
165
  end
153
166
 
154
167
  def current_instances_key
@@ -163,6 +176,11 @@ module ActiveSupport
163
176
 
164
177
  send(name, *args, &block)
165
178
  end
179
+ ruby2_keywords(:method_missing)
180
+
181
+ def respond_to_missing?(name, _)
182
+ super || instance.respond_to?(name)
183
+ end
166
184
  end
167
185
 
168
186
  attr_accessor :attributes