activesupport 6.0.4 → 6.1.4

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 (130) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +388 -460
  3. data/MIT-LICENSE +1 -1
  4. data/lib/active_support/array_inquirer.rb +4 -2
  5. data/lib/active_support/backtrace_cleaner.rb +3 -3
  6. data/lib/active_support/benchmarkable.rb +1 -1
  7. data/lib/active_support/cache/file_store.rb +3 -3
  8. data/lib/active_support/cache/mem_cache_store.rb +28 -18
  9. data/lib/active_support/cache/memory_store.rb +46 -26
  10. data/lib/active_support/cache/redis_cache_store.rb +25 -25
  11. data/lib/active_support/cache/strategy/local_cache.rb +20 -5
  12. data/lib/active_support/cache.rb +87 -40
  13. data/lib/active_support/callbacks.rb +65 -56
  14. data/lib/active_support/concern.rb +46 -2
  15. data/lib/active_support/configurable.rb +3 -3
  16. data/lib/active_support/configuration_file.rb +51 -0
  17. data/lib/active_support/core_ext/benchmark.rb +2 -2
  18. data/lib/active_support/core_ext/class/attribute.rb +34 -44
  19. data/lib/active_support/core_ext/class/subclasses.rb +17 -38
  20. data/lib/active_support/core_ext/date/conversions.rb +2 -1
  21. data/lib/active_support/core_ext/date_and_time/calculations.rb +13 -0
  22. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  23. data/lib/active_support/core_ext/enumerable.rb +76 -4
  24. data/lib/active_support/core_ext/hash/conversions.rb +2 -2
  25. data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
  26. data/lib/active_support/core_ext/hash/keys.rb +1 -1
  27. data/lib/active_support/core_ext/hash/slice.rb +3 -2
  28. data/lib/active_support/core_ext/load_error.rb +1 -1
  29. data/lib/active_support/core_ext/marshal.rb +2 -0
  30. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  31. data/lib/active_support/core_ext/module/attribute_accessors.rb +23 -29
  32. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +8 -4
  33. data/lib/active_support/core_ext/module/concerning.rb +8 -2
  34. data/lib/active_support/core_ext/module/delegation.rb +38 -28
  35. data/lib/active_support/core_ext/module/introspection.rb +1 -25
  36. data/lib/active_support/core_ext/name_error.rb +29 -2
  37. data/lib/active_support/core_ext/numeric/conversions.rb +22 -18
  38. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  39. data/lib/active_support/core_ext/object/json.rb +12 -1
  40. data/lib/active_support/core_ext/object/try.rb +2 -2
  41. data/lib/active_support/core_ext/range/compare_range.rb +9 -3
  42. data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
  43. data/lib/active_support/core_ext/regexp.rb +8 -1
  44. data/lib/active_support/core_ext/string/access.rb +5 -24
  45. data/lib/active_support/core_ext/string/conversions.rb +1 -0
  46. data/lib/active_support/core_ext/string/inflections.rb +38 -4
  47. data/lib/active_support/core_ext/string/inquiry.rb +1 -0
  48. data/lib/active_support/core_ext/string/multibyte.rb +2 -2
  49. data/lib/active_support/core_ext/string/output_safety.rb +3 -4
  50. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  51. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
  52. data/lib/active_support/core_ext/symbol.rb +3 -0
  53. data/lib/active_support/core_ext/time/calculations.rb +17 -0
  54. data/lib/active_support/core_ext/time/conversions.rb +2 -0
  55. data/lib/active_support/core_ext/uri.rb +5 -1
  56. data/lib/active_support/core_ext.rb +1 -1
  57. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  58. data/lib/active_support/current_attributes.rb +8 -2
  59. data/lib/active_support/dependencies.rb +37 -18
  60. data/lib/active_support/deprecation/behaviors.rb +15 -2
  61. data/lib/active_support/deprecation/disallowed.rb +56 -0
  62. data/lib/active_support/deprecation/instance_delegator.rb +0 -1
  63. data/lib/active_support/deprecation/method_wrappers.rb +3 -2
  64. data/lib/active_support/deprecation/proxy_wrappers.rb +2 -2
  65. data/lib/active_support/deprecation/reporting.rb +50 -7
  66. data/lib/active_support/deprecation.rb +6 -1
  67. data/lib/active_support/descendants_tracker.rb +6 -2
  68. data/lib/active_support/duration/iso8601_serializer.rb +15 -9
  69. data/lib/active_support/duration.rb +71 -22
  70. data/lib/active_support/encrypted_file.rb +19 -2
  71. data/lib/active_support/environment_inquirer.rb +20 -0
  72. data/lib/active_support/evented_file_update_checker.rb +69 -133
  73. data/lib/active_support/fork_tracker.rb +64 -0
  74. data/lib/active_support/gem_version.rb +1 -1
  75. data/lib/active_support/hash_with_indifferent_access.rb +48 -24
  76. data/lib/active_support/i18n_railtie.rb +14 -19
  77. data/lib/active_support/inflector/inflections.rb +1 -2
  78. data/lib/active_support/inflector/methods.rb +35 -31
  79. data/lib/active_support/inflector/transliterate.rb +4 -4
  80. data/lib/active_support/json/decoding.rb +4 -4
  81. data/lib/active_support/json/encoding.rb +5 -1
  82. data/lib/active_support/key_generator.rb +1 -1
  83. data/lib/active_support/locale/en.yml +7 -3
  84. data/lib/active_support/log_subscriber.rb +8 -0
  85. data/lib/active_support/logger.rb +1 -1
  86. data/lib/active_support/logger_silence.rb +2 -26
  87. data/lib/active_support/logger_thread_safe_level.rb +34 -12
  88. data/lib/active_support/message_encryptor.rb +4 -7
  89. data/lib/active_support/message_verifier.rb +5 -5
  90. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  91. data/lib/active_support/messages/rotator.rb +6 -5
  92. data/lib/active_support/multibyte/chars.rb +4 -42
  93. data/lib/active_support/multibyte/unicode.rb +9 -83
  94. data/lib/active_support/notifications/fanout.rb +23 -8
  95. data/lib/active_support/notifications/instrumenter.rb +6 -15
  96. data/lib/active_support/notifications.rb +32 -5
  97. data/lib/active_support/number_helper/number_converter.rb +1 -1
  98. data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
  99. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  100. data/lib/active_support/number_helper/number_to_rounded_converter.rb +9 -5
  101. data/lib/active_support/number_helper/rounding_helper.rb +12 -28
  102. data/lib/active_support/number_helper.rb +29 -14
  103. data/lib/active_support/option_merger.rb +2 -1
  104. data/lib/active_support/ordered_options.rb +8 -2
  105. data/lib/active_support/parameter_filter.rb +16 -11
  106. data/lib/active_support/per_thread_registry.rb +1 -1
  107. data/lib/active_support/rails.rb +1 -4
  108. data/lib/active_support/railtie.rb +23 -1
  109. data/lib/active_support/rescuable.rb +4 -4
  110. data/lib/active_support/secure_compare_rotator.rb +51 -0
  111. data/lib/active_support/security_utils.rb +19 -12
  112. data/lib/active_support/string_inquirer.rb +4 -2
  113. data/lib/active_support/subscriber.rb +12 -7
  114. data/lib/active_support/tagged_logging.rb +29 -4
  115. data/lib/active_support/testing/assertions.rb +18 -11
  116. data/lib/active_support/testing/parallelization/server.rb +78 -0
  117. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  118. data/lib/active_support/testing/parallelization.rb +12 -95
  119. data/lib/active_support/testing/time_helpers.rb +40 -3
  120. data/lib/active_support/time_with_zone.rb +67 -43
  121. data/lib/active_support/values/time_zone.rb +20 -10
  122. data/lib/active_support/xml_mini/rexml.rb +8 -1
  123. data/lib/active_support.rb +13 -1
  124. metadata +33 -35
  125. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
  126. data/lib/active_support/core_ext/hash/compact.rb +0 -5
  127. data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
  128. data/lib/active_support/core_ext/module/reachable.rb +0 -6
  129. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
  130. data/lib/active_support/core_ext/range/include_range.rb +0 -9
@@ -47,9 +47,9 @@ class String
47
47
  # iso_str.is_utf8? # => false
48
48
  def is_utf8?
49
49
  case encoding
50
- when Encoding::UTF_8
50
+ when Encoding::UTF_8, Encoding::US_ASCII
51
51
  valid_encoding?
52
- when Encoding::ASCII_8BIT, Encoding::US_ASCII
52
+ when Encoding::ASCII_8BIT
53
53
  dup.force_encoding(Encoding::UTF_8).valid_encoding?
54
54
  else
55
55
  false
@@ -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
 
@@ -85,7 +84,7 @@ class ERB
85
84
  # use inside HTML attributes.
86
85
  #
87
86
  # 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.
87
+ # whether or not it is being inserted via <tt>html()</tt>. Most jQuery plugins do this.
89
88
  # If that is the case, be sure to +html_escape+ or +sanitize+ any user-generated
90
89
  # content returned by your JSON.
91
90
  #
@@ -202,7 +201,7 @@ module ActiveSupport #:nodoc:
202
201
  end
203
202
 
204
203
  def []=(*args)
205
- if args.count == 3
204
+ if args.length == 3
206
205
  super(args[0], args[1], html_escape_interpolated_argument(args[2]))
207
206
  else
208
207
  super(args[0], html_escape_interpolated_argument(args[1]))
@@ -223,7 +222,7 @@ module ActiveSupport #:nodoc:
223
222
  def %(args)
224
223
  case args
225
224
  when Hash
226
- escaped_args = Hash[args.map { |k, arg| [k, html_escape_interpolated_argument(arg)] }]
225
+ escaped_args = args.transform_values { |arg| html_escape_interpolated_argument(arg) }
227
226
  else
228
227
  escaped_args = Array(args).map { |arg| html_escape_interpolated_argument(arg) }
229
228
  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
@@ -55,6 +56,7 @@ class Time
55
56
  at_without_coercion(time_or_number)
56
57
  end
57
58
  end
59
+ ruby2_keywords(:at_with_coercion) if respond_to?(:ruby2_keywords, true)
58
60
  alias_method :at_without_coercion, :at
59
61
  alias_method :at, :at_with_coercion
60
62
 
@@ -107,6 +109,21 @@ class Time
107
109
  subsec
108
110
  end
109
111
 
112
+ unless Time.method_defined?(:floor)
113
+ def floor(precision = 0)
114
+ change(nsec: 0) + subsec.floor(precision)
115
+ end
116
+ end
117
+
118
+ # Restricted Ruby version due to a bug in `Time#ceil`
119
+ # See https://bugs.ruby-lang.org/issues/17025 for more details
120
+ if RUBY_VERSION <= "2.8"
121
+ remove_possible_method :ceil
122
+ def ceil(precision = 0)
123
+ change(nsec: 0) + subsec.ceil(precision)
124
+ end
125
+ end
126
+
110
127
  # Returns a new Time where one or more of the elements have been changed according
111
128
  # to the +options+ parameter. The time options (<tt>:hour</tt>, <tt>:min</tt>,
112
129
  # <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>) reset cascadingly, so if only
@@ -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",
@@ -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
@@ -1,5 +1,5 @@
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
4
  require path
5
5
  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,7 +93,7 @@ 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.
@@ -150,6 +152,10 @@ module ActiveSupport
150
152
  Thread.current[:current_attributes_instances] ||= {}
151
153
  end
152
154
 
155
+ def current_instances_key
156
+ @current_instances_key ||= name.to_sym
157
+ end
158
+
153
159
  def method_missing(name, *args, &block)
154
160
  # Caches the method definition as a singleton method of the receiver.
155
161
  #
@@ -197,7 +203,7 @@ module ActiveSupport
197
203
  end
198
204
 
199
205
  def compute_attributes(keys)
200
- keys.collect { |key| [ key, public_send(key) ] }.to_h
206
+ keys.index_with { |key| public_send(key) }
201
207
  end
202
208
  end
203
209
  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)
@@ -458,7 +466,7 @@ module ActiveSupport #:nodoc:
458
466
 
459
467
  # Search for a file in autoload_paths matching the provided suffix.
460
468
  def search_for_file(path_suffix)
461
- path_suffix += ".rb" unless path_suffix.ends_with?(".rb")
469
+ path_suffix += ".rb" unless path_suffix.end_with?(".rb")
462
470
 
463
471
  autoload_paths.each do |root|
464
472
  path = File.join(root, path_suffix)
@@ -478,9 +486,9 @@ module ActiveSupport #:nodoc:
478
486
  end
479
487
 
480
488
  def load_once_path?(path)
481
- # to_s works around a ruby issue where String#starts_with?(Pathname)
489
+ # to_s works around a ruby issue where String#start_with?(Pathname)
482
490
  # will raise a TypeError: no implicit conversion of Pathname into String
483
- autoload_once_paths.any? { |base| path.starts_with? base.to_s }
491
+ autoload_once_paths.any? { |base| path.start_with?(base.to_s) }
484
492
  end
485
493
 
486
494
  # Attempt to autoload the provided module name by searching for a directory
@@ -530,7 +538,8 @@ module ActiveSupport #:nodoc:
530
538
  # it is not possible to load the constant into from_mod, try its parent
531
539
  # module using +const_missing+.
532
540
  def load_missing_constant(from_mod, const_name)
533
- unless qualified_const_defined?(from_mod.name) && Inflector.constantize(from_mod.name).equal?(from_mod)
541
+ from_mod_name = real_mod_name(from_mod)
542
+ unless qualified_const_defined?(from_mod_name) && Inflector.constantize(from_mod_name).equal?(from_mod)
534
543
  raise ArgumentError, "A copy of #{from_mod} has been removed from the module tree but is still active!"
535
544
  end
536
545
 
@@ -541,7 +550,7 @@ module ActiveSupport #:nodoc:
541
550
 
542
551
  if file_path
543
552
  expanded = File.expand_path(file_path)
544
- expanded.sub!(/\.rb\z/, "")
553
+ expanded.delete_suffix!(".rb")
545
554
 
546
555
  if loading.include?(expanded)
547
556
  raise "Circular dependency detected while autoloading constant #{qualified_name}"
@@ -589,8 +598,8 @@ module ActiveSupport #:nodoc:
589
598
  end
590
599
  end
591
600
 
592
- name_error = NameError.new("uninitialized constant #{qualified_name}", const_name)
593
- name_error.set_backtrace(caller.reject { |l| l.starts_with? __FILE__ })
601
+ name_error = uninitialized_constant(qualified_name, const_name, receiver: from_mod)
602
+ name_error.set_backtrace(caller.reject { |l| l.start_with? __FILE__ })
594
603
  raise name_error
595
604
  end
596
605
 
@@ -719,7 +728,7 @@ module ActiveSupport #:nodoc:
719
728
  # A module, class, symbol, or string may be provided.
720
729
  def to_constant_name(desc) #:nodoc:
721
730
  case desc
722
- when String then desc.sub(/^::/, "")
731
+ when String then desc.delete_prefix("::")
723
732
  when Symbol then desc.to_s
724
733
  when Module
725
734
  real_mod_name(desc) ||
@@ -730,7 +739,7 @@ module ActiveSupport #:nodoc:
730
739
 
731
740
  def remove_constant(const) #:nodoc:
732
741
  # Normalize ::Foo, ::Object::Foo, Object::Foo, Object::Object::Foo, etc. as Foo.
733
- normalized = const.to_s.sub(/\A::/, "")
742
+ normalized = const.to_s.delete_prefix("::")
734
743
  normalized.sub!(/\A(Object::)+/, "")
735
744
 
736
745
  constants = normalized.split("::")
@@ -740,7 +749,7 @@ module ActiveSupport #:nodoc:
740
749
  file_path = search_for_file(const.underscore)
741
750
  if file_path
742
751
  expanded = File.expand_path(file_path)
743
- expanded.sub!(/\.rb\z/, "")
752
+ expanded.delete_suffix!(".rb")
744
753
  loaded.delete(expanded)
745
754
  end
746
755
 
@@ -798,6 +807,16 @@ module ActiveSupport #:nodoc:
798
807
  end
799
808
 
800
809
  private
810
+ if RUBY_VERSION < "2.6"
811
+ def uninitialized_constant(qualified_name, const_name, receiver:)
812
+ NameError.new("uninitialized constant #{qualified_name}", const_name)
813
+ end
814
+ else
815
+ def uninitialized_constant(qualified_name, const_name, receiver:)
816
+ NameError.new("uninitialized constant #{qualified_name}", const_name, receiver: receiver)
817
+ end
818
+ end
819
+
801
820
  # Returns the original name of a class or module even if `name` has been
802
821
  # overridden.
803
822
  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
@@ -13,6 +13,7 @@ module ActiveSupport
13
13
  descendants = @@direct_descendants[klass]
14
14
  descendants ? descendants.to_a : []
15
15
  end
16
+ alias_method :subclasses, :direct_descendants
16
17
 
17
18
  def descendants(klass)
18
19
  arr = []
@@ -59,6 +60,7 @@ module ActiveSupport
59
60
  def direct_descendants
60
61
  DescendantsTracker.direct_descendants(self)
61
62
  end
63
+ alias_method :subclasses, :direct_descendants
62
64
 
63
65
  def descendants
64
66
  DescendantsTracker.descendants(self)
@@ -77,15 +79,17 @@ module ActiveSupport
77
79
  end
78
80
 
79
81
  def <<(klass)
80
- cleanup!
81
82
  @refs << WeakRef.new(klass)
82
83
  end
83
84
 
84
85
  def each
85
- @refs.each do |ref|
86
+ @refs.reject! do |ref|
86
87
  yield ref.__getobj__
88
+ false
87
89
  rescue WeakRef::RefError
90
+ true
88
91
  end
92
+ self
89
93
  end
90
94
 
91
95
  def refs_size