activesupport 6.0.6.1 → 6.1.0.rc1

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 (129) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +337 -573
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/active_support/array_inquirer.rb +4 -2
  6. data/lib/active_support/backtrace_cleaner.rb +3 -3
  7. data/lib/active_support/benchmarkable.rb +1 -1
  8. data/lib/active_support/cache/file_store.rb +2 -2
  9. data/lib/active_support/cache/mem_cache_store.rb +20 -14
  10. data/lib/active_support/cache/memory_store.rb +38 -26
  11. data/lib/active_support/cache/redis_cache_store.rb +25 -25
  12. data/lib/active_support/cache/strategy/local_cache.rb +13 -4
  13. data/lib/active_support/cache.rb +75 -34
  14. data/lib/active_support/callbacks.rb +65 -56
  15. data/lib/active_support/concern.rb +46 -2
  16. data/lib/active_support/configurable.rb +3 -3
  17. data/lib/active_support/configuration_file.rb +46 -0
  18. data/lib/active_support/core_ext/benchmark.rb +2 -2
  19. data/lib/active_support/core_ext/class/attribute.rb +34 -44
  20. data/lib/active_support/core_ext/class/subclasses.rb +17 -38
  21. data/lib/active_support/core_ext/date/conversions.rb +2 -1
  22. data/lib/active_support/core_ext/date_and_time/calculations.rb +13 -0
  23. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  24. data/lib/active_support/core_ext/enumerable.rb +76 -4
  25. data/lib/active_support/core_ext/hash/conversions.rb +2 -2
  26. data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
  27. data/lib/active_support/core_ext/hash/keys.rb +1 -1
  28. data/lib/active_support/core_ext/hash/slice.rb +3 -2
  29. data/lib/active_support/core_ext/load_error.rb +1 -1
  30. data/lib/active_support/core_ext/marshal.rb +2 -0
  31. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  32. data/lib/active_support/core_ext/module/attribute_accessors.rb +23 -29
  33. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +8 -4
  34. data/lib/active_support/core_ext/module/concerning.rb +8 -2
  35. data/lib/active_support/core_ext/module/delegation.rb +38 -28
  36. data/lib/active_support/core_ext/module/introspection.rb +1 -25
  37. data/lib/active_support/core_ext/name_error.rb +29 -2
  38. data/lib/active_support/core_ext/numeric/conversions.rb +22 -18
  39. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  40. data/lib/active_support/core_ext/object/json.rb +5 -1
  41. data/lib/active_support/core_ext/object/try.rb +2 -2
  42. data/lib/active_support/core_ext/range/compare_range.rb +9 -3
  43. data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
  44. data/lib/active_support/core_ext/string/access.rb +5 -24
  45. data/lib/active_support/core_ext/string/inflections.rb +38 -4
  46. data/lib/active_support/core_ext/string/inquiry.rb +1 -0
  47. data/lib/active_support/core_ext/string/multibyte.rb +2 -2
  48. data/lib/active_support/core_ext/string/output_safety.rb +8 -38
  49. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  50. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
  51. data/lib/active_support/core_ext/symbol.rb +3 -0
  52. data/lib/active_support/core_ext/time/calculations.rb +16 -0
  53. data/lib/active_support/core_ext/time/conversions.rb +1 -0
  54. data/lib/active_support/core_ext/uri.rb +5 -1
  55. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  56. data/lib/active_support/current_attributes.rb +7 -2
  57. data/lib/active_support/dependencies.rb +38 -24
  58. data/lib/active_support/deprecation/behaviors.rb +15 -2
  59. data/lib/active_support/deprecation/disallowed.rb +56 -0
  60. data/lib/active_support/deprecation/instance_delegator.rb +0 -1
  61. data/lib/active_support/deprecation/method_wrappers.rb +3 -2
  62. data/lib/active_support/deprecation/proxy_wrappers.rb +2 -2
  63. data/lib/active_support/deprecation/reporting.rb +50 -7
  64. data/lib/active_support/deprecation.rb +6 -1
  65. data/lib/active_support/descendants_tracker.rb +6 -2
  66. data/lib/active_support/duration/iso8601_serializer.rb +15 -9
  67. data/lib/active_support/duration.rb +71 -22
  68. data/lib/active_support/encrypted_file.rb +19 -2
  69. data/lib/active_support/environment_inquirer.rb +20 -0
  70. data/lib/active_support/evented_file_update_checker.rb +69 -133
  71. data/lib/active_support/execution_wrapper.rb +13 -16
  72. data/lib/active_support/fork_tracker.rb +58 -0
  73. data/lib/active_support/gem_version.rb +3 -3
  74. data/lib/active_support/hash_with_indifferent_access.rb +35 -22
  75. data/lib/active_support/i18n_railtie.rb +14 -19
  76. data/lib/active_support/inflector/inflections.rb +1 -2
  77. data/lib/active_support/inflector/methods.rb +35 -31
  78. data/lib/active_support/inflector/transliterate.rb +4 -4
  79. data/lib/active_support/json/decoding.rb +4 -4
  80. data/lib/active_support/json/encoding.rb +5 -1
  81. data/lib/active_support/key_generator.rb +1 -1
  82. data/lib/active_support/locale/en.yml +7 -3
  83. data/lib/active_support/log_subscriber.rb +8 -0
  84. data/lib/active_support/logger.rb +1 -1
  85. data/lib/active_support/logger_silence.rb +2 -26
  86. data/lib/active_support/logger_thread_safe_level.rb +34 -12
  87. data/lib/active_support/message_encryptor.rb +4 -7
  88. data/lib/active_support/message_verifier.rb +5 -5
  89. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  90. data/lib/active_support/messages/rotator.rb +6 -5
  91. data/lib/active_support/multibyte/chars.rb +4 -42
  92. data/lib/active_support/multibyte/unicode.rb +9 -83
  93. data/lib/active_support/notifications/fanout.rb +23 -8
  94. data/lib/active_support/notifications/instrumenter.rb +6 -15
  95. data/lib/active_support/notifications.rb +31 -4
  96. data/lib/active_support/number_helper/number_converter.rb +1 -1
  97. data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
  98. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  99. data/lib/active_support/number_helper/number_to_rounded_converter.rb +3 -3
  100. data/lib/active_support/number_helper/rounding_helper.rb +12 -28
  101. data/lib/active_support/number_helper.rb +29 -14
  102. data/lib/active_support/option_merger.rb +2 -1
  103. data/lib/active_support/ordered_options.rb +8 -2
  104. data/lib/active_support/parameter_filter.rb +15 -10
  105. data/lib/active_support/per_thread_registry.rb +1 -1
  106. data/lib/active_support/rails.rb +1 -4
  107. data/lib/active_support/railtie.rb +23 -1
  108. data/lib/active_support/reloader.rb +1 -1
  109. data/lib/active_support/secure_compare_rotator.rb +51 -0
  110. data/lib/active_support/security_utils.rb +19 -12
  111. data/lib/active_support/string_inquirer.rb +4 -2
  112. data/lib/active_support/subscriber.rb +12 -7
  113. data/lib/active_support/tagged_logging.rb +29 -4
  114. data/lib/active_support/testing/assertions.rb +18 -11
  115. data/lib/active_support/testing/parallelization/server.rb +78 -0
  116. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  117. data/lib/active_support/testing/parallelization.rb +12 -95
  118. data/lib/active_support/testing/time_helpers.rb +40 -3
  119. data/lib/active_support/time_with_zone.rb +66 -42
  120. data/lib/active_support/values/time_zone.rb +20 -10
  121. data/lib/active_support/xml_mini/rexml.rb +8 -1
  122. data/lib/active_support.rb +13 -1
  123. metadata +39 -42
  124. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
  125. data/lib/active_support/core_ext/hash/compact.rb +0 -5
  126. data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
  127. data/lib/active_support/core_ext/module/reachable.rb +0 -6
  128. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
  129. data/lib/active_support/core_ext/range/include_range.rb +0 -9
@@ -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,14 +11,6 @@ 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
 
15
- # Following XML requirements: https://www.w3.org/TR/REC-xml/#NT-Name
16
- 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}" \
17
- "\u{200C}-\u{200D}\u{2070}-\u{218F}\u{2C00}-\u{2FEF}\u{3001}-\u{D7FF}\u{F900}-\u{FDCF}" \
18
- "\u{FDF0}-\u{FFFD}\u{10000}-\u{EFFFF}"
19
- TAG_NAME_START_REGEXP = /[^#{TAG_NAME_START_REGEXP_SET}]/
20
- TAG_NAME_FOLLOWING_REGEXP = /[^#{TAG_NAME_START_REGEXP_SET}\-.0-9\u{B7}\u{0300}-\u{036F}\u{203F}-\u{2040}]/
21
- TAG_NAME_REPLACEMENT_CHAR = "_"
22
-
23
14
  # A utility method for escaping HTML tag characters.
24
15
  # This method is also aliased as <tt>h</tt>.
25
16
  #
@@ -124,26 +115,6 @@ class ERB
124
115
  end
125
116
 
126
117
  module_function :json_escape
127
-
128
- # A utility method for escaping XML names of tags and names of attributes.
129
- #
130
- # xml_name_escape('1 < 2 & 3')
131
- # # => "1___2___3"
132
- #
133
- # It follows the requirements of the specification: https://www.w3.org/TR/REC-xml/#NT-Name
134
- def xml_name_escape(name)
135
- name = name.to_s
136
- return "" if name.blank?
137
-
138
- starting_char = name[0].gsub(TAG_NAME_START_REGEXP, TAG_NAME_REPLACEMENT_CHAR)
139
-
140
- return starting_char if name.size == 1
141
-
142
- following_chars = name[1..-1].gsub(TAG_NAME_FOLLOWING_REGEXP, TAG_NAME_REPLACEMENT_CHAR)
143
-
144
- starting_char + following_chars
145
- end
146
- module_function :xml_name_escape
147
118
  end
148
119
  end
149
120
 
@@ -163,7 +134,7 @@ module ActiveSupport #:nodoc:
163
134
  class SafeBuffer < String
164
135
  UNSAFE_STRING_METHODS = %w(
165
136
  capitalize chomp chop delete delete_prefix delete_suffix
166
- downcase lstrip next reverse rstrip scrub slice squeeze strip
137
+ downcase lstrip next reverse rstrip slice squeeze strip
167
138
  succ swapcase tr tr_s unicode_normalize upcase
168
139
  )
169
140
 
@@ -181,12 +152,12 @@ module ActiveSupport #:nodoc:
181
152
 
182
153
  def [](*args)
183
154
  if html_safe?
184
- new_string = super
155
+ new_safe_buffer = super
185
156
 
186
- return unless new_string
157
+ if new_safe_buffer
158
+ new_safe_buffer.instance_variable_set :@html_safe, true
159
+ end
187
160
 
188
- new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
189
- new_safe_buffer.instance_variable_set :@html_safe, true
190
161
  new_safe_buffer
191
162
  else
192
163
  to_str[*args]
@@ -230,7 +201,7 @@ module ActiveSupport #:nodoc:
230
201
  end
231
202
 
232
203
  def []=(*args)
233
- if args.count == 3
204
+ if args.length == 3
234
205
  super(args[0], args[1], html_escape_interpolated_argument(args[2]))
235
206
  else
236
207
  super(args[0], html_escape_interpolated_argument(args[1]))
@@ -242,8 +213,7 @@ module ActiveSupport #:nodoc:
242
213
  end
243
214
 
244
215
  def *(*)
245
- new_string = super
246
- new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
216
+ new_safe_buffer = super
247
217
  new_safe_buffer.instance_variable_set(:@html_safe, @html_safe)
248
218
  new_safe_buffer
249
219
  end
@@ -251,7 +221,7 @@ module ActiveSupport #:nodoc:
251
221
  def %(args)
252
222
  case args
253
223
  when Hash
254
- escaped_args = Hash[args.map { |k, arg| [k, html_escape_interpolated_argument(arg)] }]
224
+ escaped_args = args.transform_values { |arg| html_escape_interpolated_argument(arg) }
255
225
  else
256
226
  escaped_args = Array(args).map { |arg| html_escape_interpolated_argument(arg) }
257
227
  end
@@ -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,14 @@
1
+ # frozen_string_literal: true
2
+
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
+ alias :starts_with? :start_with?
13
+ alias :ends_with? :end_with?
14
+ 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
@@ -107,6 +108,21 @@ 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
@@ -6,6 +6,7 @@ require "active_support/values/time_zone"
6
6
  class Time
7
7
  DATE_FORMATS = {
8
8
  db: "%Y-%m-%d %H:%M:%S",
9
+ inspect: "%Y-%m-%d %H:%M:%S.%9N %z",
9
10
  number: "%Y%m%d%H%M%S",
10
11
  nsec: "%Y%m%d%H%M%S%9N",
11
12
  usec: "%Y%m%d%H%M%S%6N",
@@ -19,7 +19,11 @@ end
19
19
  module URI
20
20
  class << self
21
21
  def parser
22
- @parser ||= URI::Parser.new
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
23
27
  end
24
28
  end
25
29
  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 before_teardown
10
+ ActiveSupport::CurrentAttributes.reset_all
11
+ super
12
+ end
13
+ end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/callbacks"
4
+ require "active_support/core_ext/enumerable"
4
5
 
5
6
  module ActiveSupport
6
7
  # Abstract super class that provides a thread-isolated attributes singleton, which resets automatically
@@ -91,7 +92,7 @@ module ActiveSupport
91
92
  class << self
92
93
  # Returns singleton instance for this class in this thread. If none exists, one is created.
93
94
  def instance
94
- current_instances[name] ||= new
95
+ current_instances[current_instances_key] ||= new
95
96
  end
96
97
 
97
98
  # Declares one or more attributes that will be given both class and instance accessor methods.
@@ -150,6 +151,10 @@ module ActiveSupport
150
151
  Thread.current[:current_attributes_instances] ||= {}
151
152
  end
152
153
 
154
+ def current_instances_key
155
+ @current_instances_key ||= name.to_sym
156
+ end
157
+
153
158
  def method_missing(name, *args, &block)
154
159
  # Caches the method definition as a singleton method of the receiver.
155
160
  #
@@ -197,7 +202,7 @@ module ActiveSupport
197
202
  end
198
203
 
199
204
  def compute_attributes(keys)
200
- keys.collect { |key| [ key, public_send(key) ] }.to_h
205
+ keys.index_with { |key| public_send(key) }
201
206
  end
202
207
  end
203
208
  end
@@ -12,7 +12,6 @@ require "active_support/core_ext/object/blank"
12
12
  require "active_support/core_ext/kernel/reporting"
13
13
  require "active_support/core_ext/load_error"
14
14
  require "active_support/core_ext/name_error"
15
- require "active_support/core_ext/string/starts_ends_with"
16
15
  require "active_support/dependencies/interlock"
17
16
  require "active_support/inflector"
18
17
 
@@ -262,15 +261,24 @@ module ActiveSupport #:nodoc:
262
261
 
263
262
  # :doc:
264
263
 
265
- # Interprets a file using <tt>mechanism</tt> and marks its defined
266
- # constants as autoloaded. <tt>file_name</tt> can be either a string or
264
+ # <b>Warning:</b> This method is obsolete in +:zeitwerk+ mode. In
265
+ # +:zeitwerk+ mode semantics match Ruby's and you do not need to be
266
+ # defensive with load order. Just refer to classes and modules normally.
267
+ # If the constant name is dynamic, camelize if needed, and constantize.
268
+ #
269
+ # In +:classic+ mode, interprets a file using +mechanism+ and marks its
270
+ # defined constants as autoloaded. +file_name+ can be either a string or
267
271
  # respond to <tt>to_path</tt>.
268
272
  #
269
- # Use this method in code that absolutely needs a certain constant to be
270
- # defined at that point. A typical use case is to make constant name
271
- # resolution deterministic for constants with the same relative name in
272
- # different namespaces whose evaluation would depend on load order
273
- # otherwise.
273
+ # In +:classic+ mode, use this method in code that absolutely needs a
274
+ # certain constant to be defined at that point. A typical use case is to
275
+ # make constant name resolution deterministic for constants with the same
276
+ # relative name in different namespaces whose evaluation would depend on
277
+ # load order otherwise.
278
+ #
279
+ # Engines that do not control the mode in which their parent application
280
+ # runs should call +require_dependency+ where needed in case the runtime
281
+ # mode is +:classic+.
274
282
  def require_dependency(file_name, message = "No such file to load -- %s.rb")
275
283
  file_name = file_name.to_path if file_name.respond_to?(:to_path)
276
284
  unless file_name.is_a?(String)
@@ -367,12 +375,7 @@ module ActiveSupport #:nodoc:
367
375
  require_or_load(path || file_name)
368
376
  rescue LoadError => load_error
369
377
  if file_name = load_error.message[/ -- (.*?)(\.rb)?$/, 1]
370
- load_error_message = if load_error.respond_to?(:original_message)
371
- load_error.original_message
372
- else
373
- load_error.message
374
- end
375
- load_error_message.replace(message % file_name)
378
+ load_error.message.replace(message % file_name)
376
379
  load_error.copy_blame!(load_error)
377
380
  end
378
381
  raise
@@ -458,7 +461,7 @@ module ActiveSupport #:nodoc:
458
461
 
459
462
  # Search for a file in autoload_paths matching the provided suffix.
460
463
  def search_for_file(path_suffix)
461
- path_suffix += ".rb" unless path_suffix.ends_with?(".rb")
464
+ path_suffix += ".rb" unless path_suffix.end_with?(".rb")
462
465
 
463
466
  autoload_paths.each do |root|
464
467
  path = File.join(root, path_suffix)
@@ -478,9 +481,9 @@ module ActiveSupport #:nodoc:
478
481
  end
479
482
 
480
483
  def load_once_path?(path)
481
- # to_s works around a ruby issue where String#starts_with?(Pathname)
484
+ # to_s works around a ruby issue where String#start_with?(Pathname)
482
485
  # will raise a TypeError: no implicit conversion of Pathname into String
483
- autoload_once_paths.any? { |base| path.starts_with? base.to_s }
486
+ autoload_once_paths.any? { |base| path.start_with?(base.to_s) }
484
487
  end
485
488
 
486
489
  # Attempt to autoload the provided module name by searching for a directory
@@ -530,7 +533,8 @@ module ActiveSupport #:nodoc:
530
533
  # it is not possible to load the constant into from_mod, try its parent
531
534
  # module using +const_missing+.
532
535
  def load_missing_constant(from_mod, const_name)
533
- unless qualified_const_defined?(from_mod.name) && Inflector.constantize(from_mod.name).equal?(from_mod)
536
+ from_mod_name = real_mod_name(from_mod)
537
+ unless qualified_const_defined?(from_mod_name) && Inflector.constantize(from_mod_name).equal?(from_mod)
534
538
  raise ArgumentError, "A copy of #{from_mod} has been removed from the module tree but is still active!"
535
539
  end
536
540
 
@@ -541,7 +545,7 @@ module ActiveSupport #:nodoc:
541
545
 
542
546
  if file_path
543
547
  expanded = File.expand_path(file_path)
544
- expanded.sub!(/\.rb\z/, "")
548
+ expanded.delete_suffix!(".rb")
545
549
 
546
550
  if loading.include?(expanded)
547
551
  raise "Circular dependency detected while autoloading constant #{qualified_name}"
@@ -589,8 +593,8 @@ module ActiveSupport #:nodoc:
589
593
  end
590
594
  end
591
595
 
592
- name_error = NameError.new("uninitialized constant #{qualified_name}", const_name)
593
- name_error.set_backtrace(caller.reject { |l| l.starts_with? __FILE__ })
596
+ name_error = uninitialized_constant(qualified_name, const_name, receiver: from_mod)
597
+ name_error.set_backtrace(caller.reject { |l| l.start_with? __FILE__ })
594
598
  raise name_error
595
599
  end
596
600
 
@@ -719,7 +723,7 @@ module ActiveSupport #:nodoc:
719
723
  # A module, class, symbol, or string may be provided.
720
724
  def to_constant_name(desc) #:nodoc:
721
725
  case desc
722
- when String then desc.sub(/^::/, "")
726
+ when String then desc.delete_prefix("::")
723
727
  when Symbol then desc.to_s
724
728
  when Module
725
729
  real_mod_name(desc) ||
@@ -730,7 +734,7 @@ module ActiveSupport #:nodoc:
730
734
 
731
735
  def remove_constant(const) #:nodoc:
732
736
  # Normalize ::Foo, ::Object::Foo, Object::Foo, Object::Object::Foo, etc. as Foo.
733
- normalized = const.to_s.sub(/\A::/, "")
737
+ normalized = const.to_s.delete_prefix("::")
734
738
  normalized.sub!(/\A(Object::)+/, "")
735
739
 
736
740
  constants = normalized.split("::")
@@ -740,7 +744,7 @@ module ActiveSupport #:nodoc:
740
744
  file_path = search_for_file(const.underscore)
741
745
  if file_path
742
746
  expanded = File.expand_path(file_path)
743
- expanded.sub!(/\.rb\z/, "")
747
+ expanded.delete_suffix!(".rb")
744
748
  loaded.delete(expanded)
745
749
  end
746
750
 
@@ -798,6 +802,16 @@ module ActiveSupport #:nodoc:
798
802
  end
799
803
 
800
804
  private
805
+ if RUBY_VERSION < "2.6"
806
+ def uninitialized_constant(qualified_name, const_name, receiver:)
807
+ NameError.new("uninitialized constant #{qualified_name}", const_name)
808
+ end
809
+ else
810
+ def uninitialized_constant(qualified_name, const_name, receiver:)
811
+ NameError.new("uninitialized constant #{qualified_name}", const_name, receiver: receiver)
812
+ end
813
+ end
814
+
801
815
  # Returns the original name of a class or module even if `name` has been
802
816
  # overridden.
803
817
  def real_mod_name(mod)
@@ -51,7 +51,7 @@ module ActiveSupport
51
51
  # constant. Available behaviors are:
52
52
  #
53
53
  # [+raise+] Raise <tt>ActiveSupport::DeprecationException</tt>.
54
- # [+stderr+] Log all deprecation warnings to +$stderr+.
54
+ # [+stderr+] Log all deprecation warnings to <tt>$stderr</tt>.
55
55
  # [+log+] Log all deprecation warnings to +Rails.logger+.
56
56
  # [+notify+] Use +ActiveSupport::Notifications+ to notify +deprecation.rails+.
57
57
  # [+silence+] Do nothing.
@@ -67,13 +67,18 @@ module ActiveSupport
67
67
  @behavior ||= [DEFAULT_BEHAVIORS[:stderr]]
68
68
  end
69
69
 
70
+ # Returns the current behavior for disallowed deprecations or if one isn't set, defaults to +:raise+.
71
+ def disallowed_behavior
72
+ @disallowed_behavior ||= [DEFAULT_BEHAVIORS[:raise]]
73
+ end
74
+
70
75
  # Sets the behavior to the specified value. Can be a single value, array,
71
76
  # or an object that responds to +call+.
72
77
  #
73
78
  # Available behaviors:
74
79
  #
75
80
  # [+raise+] Raise <tt>ActiveSupport::DeprecationException</tt>.
76
- # [+stderr+] Log all deprecation warnings to +$stderr+.
81
+ # [+stderr+] Log all deprecation warnings to <tt>$stderr</tt>.
77
82
  # [+log+] Log all deprecation warnings to +Rails.logger+.
78
83
  # [+notify+] Use +ActiveSupport::Notifications+ to notify +deprecation.rails+.
79
84
  # [+silence+] Do nothing.
@@ -92,6 +97,14 @@ module ActiveSupport
92
97
  @behavior = Array(behavior).map { |b| DEFAULT_BEHAVIORS[b] || arity_coerce(b) }
93
98
  end
94
99
 
100
+ # Sets the behavior for disallowed deprecations (those configured by
101
+ # ActiveSupport::Deprecation.disallowed_warnings=) to the specified
102
+ # value. As with +behavior=+, this can be a single value, array, or an
103
+ # object that responds to +call+.
104
+ def disallowed_behavior=(behavior)
105
+ @disallowed_behavior = Array(behavior).map { |b| DEFAULT_BEHAVIORS[b] || arity_coerce(b) }
106
+ end
107
+
95
108
  private
96
109
  def arity_coerce(behavior)
97
110
  unless behavior.respond_to?(:call)
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ class Deprecation
5
+ module Disallowed
6
+ # Sets the criteria used to identify deprecation messages which should be
7
+ # disallowed. Can be an array containing strings, symbols, or regular
8
+ # expressions. (Symbols are treated as strings). These are compared against
9
+ # the text of the generated deprecation warning.
10
+ #
11
+ # Additionally the scalar symbol +:all+ may be used to treat all
12
+ # deprecations as disallowed.
13
+ #
14
+ # Deprecations matching a substring or regular expression will be handled
15
+ # using the configured +ActiveSupport::Deprecation.disallowed_behavior+
16
+ # rather than +ActiveSupport::Deprecation.behavior+
17
+ attr_writer :disallowed_warnings
18
+
19
+ # Returns the configured criteria used to identify deprecation messages
20
+ # which should be treated as disallowed.
21
+ def disallowed_warnings
22
+ @disallowed_warnings ||= []
23
+ end
24
+
25
+ private
26
+ def deprecation_disallowed?(message)
27
+ disallowed = ActiveSupport::Deprecation.disallowed_warnings
28
+ return false if explicitly_allowed?(message)
29
+ return true if disallowed == :all
30
+ disallowed.any? do |rule|
31
+ case rule
32
+ when String, Symbol
33
+ message.include?(rule.to_s)
34
+ when Regexp
35
+ rule.match?(message)
36
+ end
37
+ end
38
+ end
39
+
40
+ def explicitly_allowed?(message)
41
+ allowances = @explicitly_allowed_warnings.value
42
+ return false unless allowances
43
+ return true if allowances == :all
44
+ allowances = [allowances] unless allowances.kind_of?(Array)
45
+ allowances.any? do |rule|
46
+ case rule
47
+ when String, Symbol
48
+ message.include?(rule.to_s)
49
+ when Regexp
50
+ rule.match?(message)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/kernel/singleton_class"
4
3
  require "active_support/core_ext/module/delegation"
5
4
 
6
5
  module ActiveSupport
@@ -56,11 +56,12 @@ module ActiveSupport
56
56
  mod = nil
57
57
 
58
58
  method_names.each do |method_name|
59
+ message = options[method_name]
59
60
  if target_module.method_defined?(method_name) || target_module.private_method_defined?(method_name)
60
61
  method = target_module.instance_method(method_name)
61
62
  target_module.module_eval do
62
63
  redefine_method(method_name) do |*args, &block|
63
- deprecator.deprecation_warning(method_name, options[method_name])
64
+ deprecator.deprecation_warning(method_name, message)
64
65
  method.bind(self).call(*args, &block)
65
66
  end
66
67
  ruby2_keywords(method_name) if respond_to?(:ruby2_keywords, true)
@@ -69,7 +70,7 @@ module ActiveSupport
69
70
  mod ||= Module.new
70
71
  mod.module_eval do
71
72
  define_method(method_name) do |*args, &block|
72
- deprecator.deprecation_warning(method_name, options[method_name])
73
+ deprecator.deprecation_warning(method_name, message)
73
74
  super(*args, &block)
74
75
  end
75
76
  ruby2_keywords(method_name) if respond_to?(:ruby2_keywords, true)
@@ -121,7 +121,7 @@ module ActiveSupport
121
121
  # (Backtrace information…)
122
122
  # ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
123
123
  class DeprecatedConstantProxy < Module
124
- def self.new(*args, **kwargs, &block)
124
+ def self.new(*args, **options, &block)
125
125
  object = args.first
126
126
 
127
127
  return object unless object
@@ -129,7 +129,7 @@ module ActiveSupport
129
129
  end
130
130
 
131
131
  def initialize(old_const, new_const, deprecator = ActiveSupport::Deprecation.instance, message: "#{old_const} is deprecated! Use #{new_const} instead.")
132
- require "active_support/inflector/methods"
132
+ Kernel.require "active_support/inflector/methods"
133
133
 
134
134
  @old_const = old_const
135
135
  @new_const = new_const
@@ -6,7 +6,7 @@ module ActiveSupport
6
6
  class Deprecation
7
7
  module Reporting
8
8
  # Whether to print a message (silent mode)
9
- attr_accessor :silenced
9
+ attr_writer :silenced
10
10
  # Name of gem where method is deprecated
11
11
  attr_accessor :gem_name
12
12
 
@@ -20,7 +20,11 @@ module ActiveSupport
20
20
 
21
21
  callstack ||= caller_locations(2)
22
22
  deprecation_message(callstack, message).tap do |m|
23
- behavior.each { |b| b.call(m, callstack, deprecation_horizon, gem_name) }
23
+ if deprecation_disallowed?(message)
24
+ disallowed_behavior.each { |b| b.call(m, callstack, deprecation_horizon, gem_name) }
25
+ else
26
+ behavior.each { |b| b.call(m, callstack, deprecation_horizon, gem_name) }
27
+ end
24
28
  end
25
29
  end
26
30
 
@@ -33,11 +37,50 @@ module ActiveSupport
33
37
  # ActiveSupport::Deprecation.warn('something broke!')
34
38
  # end
35
39
  # # => nil
36
- def silence
37
- old_silenced, @silenced = @silenced, true
38
- yield
39
- ensure
40
- @silenced = old_silenced
40
+ def silence(&block)
41
+ @silenced_thread.bind(true, &block)
42
+ end
43
+
44
+ # Allow previously disallowed deprecation warnings within the block.
45
+ # <tt>allowed_warnings</tt> can be an array containing strings, symbols, or regular
46
+ # expressions. (Symbols are treated as strings). These are compared against
47
+ # the text of deprecation warning messages generated within the block.
48
+ # Matching warnings will be exempt from the rules set by
49
+ # +ActiveSupport::Deprecation.disallowed_warnings+
50
+ #
51
+ # The optional <tt>if:</tt> argument accepts a truthy/falsy value or an object that
52
+ # responds to <tt>.call</tt>. If truthy, then matching warnings will be allowed.
53
+ # If falsey then the method yields to the block without allowing the warning.
54
+ #
55
+ # ActiveSupport::Deprecation.disallowed_behavior = :raise
56
+ # ActiveSupport::Deprecation.disallowed_warnings = [
57
+ # "something broke"
58
+ # ]
59
+ #
60
+ # ActiveSupport::Deprecation.warn('something broke!')
61
+ # # => ActiveSupport::DeprecationException
62
+ #
63
+ # ActiveSupport::Deprecation.allow ['something broke'] do
64
+ # ActiveSupport::Deprecation.warn('something broke!')
65
+ # end
66
+ # # => nil
67
+ #
68
+ # ActiveSupport::Deprecation.allow ['something broke'], if: Rails.env.production? do
69
+ # ActiveSupport::Deprecation.warn('something broke!')
70
+ # end
71
+ # # => ActiveSupport::DeprecationException for dev/test, nil for production
72
+ def allow(allowed_warnings = :all, if: true, &block)
73
+ conditional = binding.local_variable_get(:if)
74
+ conditional = conditional.call if conditional.respond_to?(:call)
75
+ if conditional
76
+ @explicitly_allowed_warnings.bind(allowed_warnings, &block)
77
+ else
78
+ yield
79
+ end
80
+ end
81
+
82
+ def silenced
83
+ @silenced || @silenced_thread.value
41
84
  end
42
85
 
43
86
  def deprecation_warning(deprecated_method_name, message = nil, caller_backtrace = nil)
@@ -17,15 +17,18 @@ module ActiveSupport
17
17
  require "active_support/deprecation/instance_delegator"
18
18
  require "active_support/deprecation/behaviors"
19
19
  require "active_support/deprecation/reporting"
20
+ require "active_support/deprecation/disallowed"
20
21
  require "active_support/deprecation/constant_accessor"
21
22
  require "active_support/deprecation/method_wrappers"
22
23
  require "active_support/deprecation/proxy_wrappers"
23
24
  require "active_support/core_ext/module/deprecation"
25
+ require "concurrent/atomic/thread_local_var"
24
26
 
25
27
  include Singleton
26
28
  include InstanceDelegator
27
29
  include Behavior
28
30
  include Reporting
31
+ include Disallowed
29
32
  include MethodWrapper
30
33
 
31
34
  # The version number in which the deprecated behavior will be removed, by default.
@@ -35,12 +38,14 @@ module ActiveSupport
35
38
  # and the second is a library name.
36
39
  #
37
40
  # ActiveSupport::Deprecation.new('2.0', 'MyLibrary')
38
- def initialize(deprecation_horizon = "6.1", gem_name = "Rails")
41
+ def initialize(deprecation_horizon = "6.2", gem_name = "Rails")
39
42
  self.gem_name = gem_name
40
43
  self.deprecation_horizon = deprecation_horizon
41
44
  # By default, warnings are not silenced and debugging is off.
42
45
  self.silenced = false
43
46
  self.debug = false
47
+ @silenced_thread = Concurrent::ThreadLocalVar.new(false)
48
+ @explicitly_allowed_warnings = Concurrent::ThreadLocalVar.new(nil)
44
49
  end
45
50
  end
46
51
  end