activesupport 7.0.8 → 7.1.0.beta1

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 (170) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +736 -293
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -4
  5. data/lib/active_support/actionable_error.rb +3 -1
  6. data/lib/active_support/array_inquirer.rb +2 -0
  7. data/lib/active_support/backtrace_cleaner.rb +25 -5
  8. data/lib/active_support/benchmarkable.rb +1 -0
  9. data/lib/active_support/builder.rb +1 -1
  10. data/lib/active_support/cache/coder.rb +153 -0
  11. data/lib/active_support/cache/entry.rb +128 -0
  12. data/lib/active_support/cache/file_store.rb +36 -9
  13. data/lib/active_support/cache/mem_cache_store.rb +84 -68
  14. data/lib/active_support/cache/memory_store.rb +76 -24
  15. data/lib/active_support/cache/null_store.rb +6 -0
  16. data/lib/active_support/cache/redis_cache_store.rb +126 -131
  17. data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
  18. data/lib/active_support/cache/strategy/local_cache.rb +20 -8
  19. data/lib/active_support/cache.rb +304 -246
  20. data/lib/active_support/callbacks.rb +38 -18
  21. data/lib/active_support/concern.rb +4 -2
  22. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +42 -3
  23. data/lib/active_support/concurrency/null_lock.rb +13 -0
  24. data/lib/active_support/configurable.rb +10 -0
  25. data/lib/active_support/core_ext/array/conversions.rb +2 -1
  26. data/lib/active_support/core_ext/array.rb +0 -1
  27. data/lib/active_support/core_ext/class/subclasses.rb +13 -10
  28. data/lib/active_support/core_ext/date/conversions.rb +1 -0
  29. data/lib/active_support/core_ext/date.rb +0 -1
  30. data/lib/active_support/core_ext/date_and_time/calculations.rb +10 -0
  31. data/lib/active_support/core_ext/date_time/conversions.rb +6 -2
  32. data/lib/active_support/core_ext/date_time.rb +0 -1
  33. data/lib/active_support/core_ext/digest/uuid.rb +1 -10
  34. data/lib/active_support/core_ext/enumerable.rb +3 -75
  35. data/lib/active_support/core_ext/erb/util.rb +196 -0
  36. data/lib/active_support/core_ext/hash/conversions.rb +1 -1
  37. data/lib/active_support/core_ext/module/attribute_accessors.rb +6 -0
  38. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +34 -16
  39. data/lib/active_support/core_ext/module/delegation.rb +40 -11
  40. data/lib/active_support/core_ext/module/deprecation.rb +15 -12
  41. data/lib/active_support/core_ext/module/introspection.rb +0 -1
  42. data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
  43. data/lib/active_support/core_ext/numeric/conversions.rb +2 -0
  44. data/lib/active_support/core_ext/numeric.rb +0 -1
  45. data/lib/active_support/core_ext/object/deep_dup.rb +16 -0
  46. data/lib/active_support/core_ext/object/inclusion.rb +13 -5
  47. data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
  48. data/lib/active_support/core_ext/object/json.rb +10 -2
  49. data/lib/active_support/core_ext/object/with.rb +44 -0
  50. data/lib/active_support/core_ext/object/with_options.rb +3 -3
  51. data/lib/active_support/core_ext/object.rb +1 -0
  52. data/lib/active_support/core_ext/pathname/blank.rb +16 -0
  53. data/lib/active_support/core_ext/pathname/existence.rb +2 -0
  54. data/lib/active_support/core_ext/pathname.rb +1 -0
  55. data/lib/active_support/core_ext/range/conversions.rb +28 -7
  56. data/lib/active_support/core_ext/range/{overlaps.rb → overlap.rb} +5 -3
  57. data/lib/active_support/core_ext/range.rb +1 -2
  58. data/lib/active_support/core_ext/securerandom.rb +24 -12
  59. data/lib/active_support/core_ext/string/filters.rb +20 -14
  60. data/lib/active_support/core_ext/string/inflections.rb +16 -5
  61. data/lib/active_support/core_ext/string/output_safety.rb +38 -174
  62. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  63. data/lib/active_support/core_ext/time/calculations.rb +18 -2
  64. data/lib/active_support/core_ext/time/conversions.rb +2 -2
  65. data/lib/active_support/core_ext/time/zones.rb +4 -4
  66. data/lib/active_support/core_ext/time.rb +0 -1
  67. data/lib/active_support/current_attributes.rb +15 -6
  68. data/lib/active_support/dependencies/autoload.rb +17 -12
  69. data/lib/active_support/deprecation/behaviors.rb +53 -32
  70. data/lib/active_support/deprecation/constant_accessor.rb +5 -4
  71. data/lib/active_support/deprecation/deprecators.rb +104 -0
  72. data/lib/active_support/deprecation/disallowed.rb +3 -5
  73. data/lib/active_support/deprecation/instance_delegator.rb +31 -4
  74. data/lib/active_support/deprecation/method_wrappers.rb +6 -23
  75. data/lib/active_support/deprecation/proxy_wrappers.rb +37 -22
  76. data/lib/active_support/deprecation/reporting.rb +35 -21
  77. data/lib/active_support/deprecation.rb +32 -5
  78. data/lib/active_support/deprecator.rb +7 -0
  79. data/lib/active_support/descendants_tracker.rb +104 -132
  80. data/lib/active_support/duration/iso8601_serializer.rb +0 -2
  81. data/lib/active_support/duration.rb +2 -1
  82. data/lib/active_support/encrypted_configuration.rb +30 -9
  83. data/lib/active_support/encrypted_file.rb +8 -3
  84. data/lib/active_support/environment_inquirer.rb +22 -2
  85. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  86. data/lib/active_support/error_reporter.rb +121 -35
  87. data/lib/active_support/execution_wrapper.rb +4 -4
  88. data/lib/active_support/file_update_checker.rb +4 -2
  89. data/lib/active_support/fork_tracker.rb +10 -2
  90. data/lib/active_support/gem_version.rb +4 -4
  91. data/lib/active_support/gzip.rb +2 -0
  92. data/lib/active_support/hash_with_indifferent_access.rb +35 -17
  93. data/lib/active_support/i18n.rb +1 -1
  94. data/lib/active_support/i18n_railtie.rb +20 -13
  95. data/lib/active_support/inflector/inflections.rb +2 -0
  96. data/lib/active_support/inflector/methods.rb +22 -10
  97. data/lib/active_support/inflector/transliterate.rb +3 -1
  98. data/lib/active_support/isolated_execution_state.rb +26 -22
  99. data/lib/active_support/json/decoding.rb +2 -1
  100. data/lib/active_support/json/encoding.rb +25 -43
  101. data/lib/active_support/key_generator.rb +9 -1
  102. data/lib/active_support/lazy_load_hooks.rb +6 -4
  103. data/lib/active_support/locale/en.yml +2 -0
  104. data/lib/active_support/log_subscriber.rb +78 -33
  105. data/lib/active_support/logger.rb +1 -1
  106. data/lib/active_support/logger_thread_safe_level.rb +9 -21
  107. data/lib/active_support/message_encryptor.rb +197 -53
  108. data/lib/active_support/message_encryptors.rb +140 -0
  109. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  110. data/lib/active_support/message_pack/extensions.rb +292 -0
  111. data/lib/active_support/message_pack/serializer.rb +63 -0
  112. data/lib/active_support/message_pack.rb +50 -0
  113. data/lib/active_support/message_verifier.rb +212 -93
  114. data/lib/active_support/message_verifiers.rb +134 -0
  115. data/lib/active_support/messages/codec.rb +65 -0
  116. data/lib/active_support/messages/metadata.rb +111 -45
  117. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  118. data/lib/active_support/messages/rotator.rb +34 -32
  119. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  120. data/lib/active_support/multibyte/chars.rb +2 -0
  121. data/lib/active_support/multibyte/unicode.rb +9 -37
  122. data/lib/active_support/notifications/fanout.rb +239 -81
  123. data/lib/active_support/notifications/instrumenter.rb +71 -14
  124. data/lib/active_support/notifications.rb +1 -1
  125. data/lib/active_support/number_helper/number_converter.rb +2 -2
  126. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  127. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -0
  128. data/lib/active_support/ordered_hash.rb +3 -3
  129. data/lib/active_support/ordered_options.rb +14 -0
  130. data/lib/active_support/parameter_filter.rb +84 -69
  131. data/lib/active_support/proxy_object.rb +2 -0
  132. data/lib/active_support/railtie.rb +33 -21
  133. data/lib/active_support/reloader.rb +12 -4
  134. data/lib/active_support/rescuable.rb +2 -0
  135. data/lib/active_support/secure_compare_rotator.rb +16 -9
  136. data/lib/active_support/string_inquirer.rb +3 -1
  137. data/lib/active_support/subscriber.rb +9 -27
  138. data/lib/active_support/syntax_error_proxy.rb +49 -0
  139. data/lib/active_support/tagged_logging.rb +60 -24
  140. data/lib/active_support/test_case.rb +153 -6
  141. data/lib/active_support/testing/assertions.rb +25 -9
  142. data/lib/active_support/testing/autorun.rb +0 -2
  143. data/lib/active_support/testing/constant_stubbing.rb +32 -0
  144. data/lib/active_support/testing/deprecation.rb +25 -25
  145. data/lib/active_support/testing/error_reporter_assertions.rb +108 -0
  146. data/lib/active_support/testing/isolation.rb +1 -1
  147. data/lib/active_support/testing/method_call_assertions.rb +21 -8
  148. data/lib/active_support/testing/parallelize_executor.rb +8 -3
  149. data/lib/active_support/testing/stream.rb +1 -1
  150. data/lib/active_support/testing/strict_warnings.rb +38 -0
  151. data/lib/active_support/testing/time_helpers.rb +32 -14
  152. data/lib/active_support/time_with_zone.rb +4 -14
  153. data/lib/active_support/values/time_zone.rb +9 -7
  154. data/lib/active_support/version.rb +1 -1
  155. data/lib/active_support/xml_mini/jdom.rb +3 -10
  156. data/lib/active_support/xml_mini/nokogiri.rb +1 -1
  157. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  158. data/lib/active_support/xml_mini/rexml.rb +1 -1
  159. data/lib/active_support/xml_mini.rb +2 -2
  160. data/lib/active_support.rb +13 -3
  161. metadata +102 -17
  162. data/lib/active_support/core_ext/array/deprecated_conversions.rb +0 -25
  163. data/lib/active_support/core_ext/date/deprecated_conversions.rb +0 -40
  164. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +0 -36
  165. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +0 -60
  166. data/lib/active_support/core_ext/range/deprecated_conversions.rb +0 -36
  167. data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -5
  168. data/lib/active_support/core_ext/time/deprecated_conversions.rb +0 -73
  169. data/lib/active_support/core_ext/uri.rb +0 -5
  170. data/lib/active_support/per_thread_registry.rb +0 -65
@@ -160,9 +160,25 @@ class Time
160
160
  elsif utc?
161
161
  ::Time.utc(new_year, new_month, new_day, new_hour, new_min, new_sec)
162
162
  elsif zone&.respond_to?(:utc_to_local)
163
- ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, zone)
163
+ new_time = ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, zone)
164
+
165
+ # When there are two occurrences of a nominal time due to DST ending,
166
+ # `Time.new` chooses the first chronological occurrence (the one with a
167
+ # larger UTC offset). However, for `change`, we want to choose the
168
+ # occurrence that matches this time's UTC offset.
169
+ #
170
+ # If the new time's UTC offset is larger than this time's UTC offset, the
171
+ # new time might be a first chronological occurrence. So we add the offset
172
+ # difference to fast-forward the new time, and check if the result has the
173
+ # desired UTC offset (i.e. is the second chronological occurrence).
174
+ offset_difference = new_time.utc_offset - utc_offset
175
+ if offset_difference > 0 && (new_time_2 = new_time + offset_difference).utc_offset == utc_offset
176
+ new_time_2
177
+ else
178
+ new_time
179
+ end
164
180
  elsif zone
165
- ::Time.local(new_year, new_month, new_day, new_hour, new_min, new_sec)
181
+ ::Time.local(new_sec, new_min, new_hour, new_day, new_month, new_year, nil, nil, isdst, nil)
166
182
  else
167
183
  ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, utc_offset)
168
184
  end
@@ -54,12 +54,12 @@ class Time
54
54
  if formatter = DATE_FORMATS[format]
55
55
  formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
56
56
  else
57
- # Change to `to_s` when deprecation is gone. Also deprecate `to_default_s`.
58
- to_default_s
57
+ to_s
59
58
  end
60
59
  end
61
60
  alias_method :to_formatted_s, :to_fs
62
61
  alias_method :to_default_s, :to_s
62
+ deprecate to_default_s: :to_s, deprecator: ActiveSupport.deprecator
63
63
 
64
64
  # Returns a formatted string of the offset from UTC, or an alternative
65
65
  # string if the time zone is already UTC.
@@ -19,10 +19,10 @@ class Time
19
19
  #
20
20
  # This method accepts any of the following:
21
21
  #
22
- # * A Rails TimeZone object.
23
- # * An identifier for a Rails TimeZone object (e.g., "Eastern Time (US & Canada)", <tt>-5.hours</tt>).
24
- # * A <tt>TZInfo::Timezone</tt> object.
25
- # * An identifier for a <tt>TZInfo::Timezone</tt> object (e.g., "America/New_York").
22
+ # * A \Rails TimeZone object.
23
+ # * An identifier for a \Rails TimeZone object (e.g., "Eastern Time (US & Canada)", <tt>-5.hours</tt>).
24
+ # * A +TZInfo::Timezone+ object.
25
+ # * An identifier for a +TZInfo::Timezone+ object (e.g., "America/New_York").
26
26
  #
27
27
  # Here's an example of how you might set <tt>Time.zone</tt> on a per request basis and reset it when the request is done.
28
28
  # <tt>current_user.time_zone</tt> just needs to return a string identifying the user's preferred time zone:
@@ -4,5 +4,4 @@ require "active_support/core_ext/time/acts_like"
4
4
  require "active_support/core_ext/time/calculations"
5
5
  require "active_support/core_ext/time/compatibility"
6
6
  require "active_support/core_ext/time/conversions"
7
- require "active_support/core_ext/time/deprecated_conversions" unless ENV["RAILS_DISABLE_DEPRECATED_TO_S_CONVERSION"]
8
7
  require "active_support/core_ext/time/zones"
@@ -5,6 +5,8 @@ require "active_support/core_ext/enumerable"
5
5
  require "active_support/core_ext/module/delegation"
6
6
 
7
7
  module ActiveSupport
8
+ # = Current Attributes
9
+ #
8
10
  # Abstract super class that provides a thread-isolated attributes singleton, which resets automatically
9
11
  # before and after each request. This allows you to keep all the per-request attributes easily
10
12
  # available to the whole system.
@@ -90,6 +92,8 @@ module ActiveSupport
90
92
  include ActiveSupport::Callbacks
91
93
  define_callbacks :reset
92
94
 
95
+ INVALID_ATTRIBUTE_NAMES = [:set, :reset, :resets, :instance, :before_reset, :after_reset, :reset_all, :clear_all] # :nodoc:
96
+
93
97
  class << self
94
98
  # Returns singleton instance for this class in this thread. If none exists, one is created.
95
99
  def instance
@@ -98,6 +102,11 @@ module ActiveSupport
98
102
 
99
103
  # Declares one or more attributes that will be given both class and instance accessor methods.
100
104
  def attribute(*names)
105
+ invalid_attribute_names = names.map(&:to_sym) & INVALID_ATTRIBUTE_NAMES
106
+ if invalid_attribute_names.any?
107
+ raise ArgumentError, "Restricted attribute names: #{invalid_attribute_names.join(", ")}"
108
+ end
109
+
101
110
  ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |owner|
102
111
  names.each do |name|
103
112
  owner.define_cached_method(name, namespace: :current_attributes) do |batch|
@@ -133,14 +142,14 @@ module ActiveSupport
133
142
  end
134
143
  end
135
144
 
136
- # Calls this block before #reset is called on the instance. Used for resetting external collaborators that depend on current values.
137
- def before_reset(&block)
138
- set_callback :reset, :before, &block
145
+ # Calls this callback before #reset is called on the instance. Used for resetting external collaborators that depend on current values.
146
+ def before_reset(*methods, &block)
147
+ set_callback :reset, :before, *methods, &block
139
148
  end
140
149
 
141
- # Calls this block after #reset is called on the instance. Used for resetting external collaborators, like Time.zone.
142
- def resets(&block)
143
- set_callback :reset, :after, &block
150
+ # Calls this callback after #reset is called on the instance. Used for resetting external collaborators, like Time.zone.
151
+ def resets(*methods, &block)
152
+ set_callback :reset, :after, *methods, &block
144
153
  end
145
154
  alias_method :after_reset, :resets
146
155
 
@@ -3,10 +3,12 @@
3
3
  require "active_support/inflector/methods"
4
4
 
5
5
  module ActiveSupport
6
+ # = Active Support \Autoload
7
+ #
6
8
  # Autoload and eager load conveniences for your library.
7
9
  #
8
10
  # This module allows you to define autoloads based on
9
- # Rails conventions (i.e. no need to define the path
11
+ # \Rails conventions (i.e. no need to define the path
10
12
  # it is automatically guessed based on the filename)
11
13
  # and also define a set of constants that needs to be
12
14
  # eager loaded:
@@ -26,11 +28,14 @@ module ActiveSupport
26
28
  # MyLib.eager_load!
27
29
  module Autoload
28
30
  def self.extended(base) # :nodoc:
29
- base.class_eval do
30
- @_autoloads = {}
31
- @_under_path = nil
32
- @_at_path = nil
33
- @_eager_autoload = false
31
+ if RUBY_VERSION < "3"
32
+ base.class_eval do
33
+ @_autoloads = nil
34
+ @_under_path = nil
35
+ @_at_path = nil
36
+ @_eager_autoload = false
37
+ @_eagerloaded_constants = nil
38
+ end
34
39
  end
35
40
  end
36
41
 
@@ -41,7 +46,8 @@ module ActiveSupport
41
46
  end
42
47
 
43
48
  if @_eager_autoload
44
- @_autoloads[const_name] = path
49
+ @_eagerloaded_constants ||= []
50
+ @_eagerloaded_constants << const_name
45
51
  end
46
52
 
47
53
  super const_name, path
@@ -69,11 +75,10 @@ module ActiveSupport
69
75
  end
70
76
 
71
77
  def eager_load!
72
- @_autoloads.each_value { |file| require file }
73
- end
74
-
75
- def autoloads
76
- @_autoloads
78
+ if @_eagerloaded_constants
79
+ @_eagerloaded_constants.each { |const_name| const_get(const_name) }
80
+ @_eagerloaded_constants = nil
81
+ end
77
82
  end
78
83
  end
79
84
  end
@@ -11,18 +11,18 @@ module ActiveSupport
11
11
  class Deprecation
12
12
  # Default warning behaviors per Rails.env.
13
13
  DEFAULT_BEHAVIORS = {
14
- raise: ->(message, callstack, deprecation_horizon, gem_name) {
14
+ raise: ->(message, callstack, deprecator) do
15
15
  e = DeprecationException.new(message)
16
16
  e.set_backtrace(callstack.map(&:to_s))
17
17
  raise e
18
- },
18
+ end,
19
19
 
20
- stderr: ->(message, callstack, deprecation_horizon, gem_name) {
20
+ stderr: ->(message, callstack, deprecator) do
21
21
  $stderr.puts(message)
22
- $stderr.puts callstack.join("\n ") if debug
23
- },
22
+ $stderr.puts callstack.join("\n ") if deprecator.debug
23
+ end,
24
24
 
25
- log: ->(message, callstack, deprecation_horizon, gem_name) {
25
+ log: ->(message, callstack, deprecator) do
26
26
  logger =
27
27
  if defined?(Rails.logger) && Rails.logger
28
28
  Rails.logger
@@ -31,30 +31,38 @@ module ActiveSupport
31
31
  ActiveSupport::Logger.new($stderr)
32
32
  end
33
33
  logger.warn message
34
- logger.debug callstack.join("\n ") if debug
35
- },
36
-
37
- notify: ->(message, callstack, deprecation_horizon, gem_name) {
38
- notification_name = "deprecation.#{gem_name.underscore.tr('/', '_')}"
39
- ActiveSupport::Notifications.instrument(notification_name,
40
- message: message,
41
- callstack: callstack,
42
- gem_name: gem_name,
43
- deprecation_horizon: deprecation_horizon)
44
- },
45
-
46
- silence: ->(message, callstack, deprecation_horizon, gem_name) { },
34
+ logger.debug callstack.join("\n ") if deprecator.debug
35
+ end,
36
+
37
+ notify: ->(message, callstack, deprecator) do
38
+ ActiveSupport::Notifications.instrument(
39
+ "deprecation.#{deprecator.gem_name.underscore.tr("/", "_")}",
40
+ message: message,
41
+ callstack: callstack,
42
+ gem_name: deprecator.gem_name,
43
+ deprecation_horizon: deprecator.deprecation_horizon,
44
+ )
45
+ end,
46
+
47
+ silence: ->(message, callstack, deprecator) { },
48
+
49
+ report: ->(message, callstack, deprecator) do
50
+ error = DeprecationException.new(message)
51
+ error.set_backtrace(callstack.map(&:to_s))
52
+ ActiveSupport.error_reporter.report(error)
53
+ end
47
54
  }
48
55
 
49
56
  # Behavior module allows to determine how to display deprecation messages.
50
57
  # You can create a custom behavior or set any from the +DEFAULT_BEHAVIORS+
51
58
  # constant. Available behaviors are:
52
59
  #
53
- # [+raise+] Raise <tt>ActiveSupport::DeprecationException</tt>.
60
+ # [+raise+] Raise ActiveSupport::DeprecationException.
54
61
  # [+stderr+] Log all deprecation warnings to <tt>$stderr</tt>.
55
62
  # [+log+] Log all deprecation warnings to +Rails.logger+.
56
63
  # [+notify+] Use +ActiveSupport::Notifications+ to notify +deprecation.rails+.
57
- # [+silence+] Do nothing. On Rails, set <tt>config.active_support.report_deprecations = false</tt> to disable all behaviors.
64
+ # [+report+] Use +ActiveSupport::ErrorReporter+ to report deprecations.
65
+ # [+silence+] Do nothing. On \Rails, set <tt>config.active_support.report_deprecations = false</tt> to disable all behaviors.
58
66
  #
59
67
  # Setting behaviors only affects deprecations that happen after boot time.
60
68
  # For more information you can read the documentation of the +behavior=+ method.
@@ -77,31 +85,33 @@ module ActiveSupport
77
85
  #
78
86
  # Available behaviors:
79
87
  #
80
- # [+raise+] Raise <tt>ActiveSupport::DeprecationException</tt>.
88
+ # [+raise+] Raise ActiveSupport::DeprecationException.
81
89
  # [+stderr+] Log all deprecation warnings to <tt>$stderr</tt>.
82
90
  # [+log+] Log all deprecation warnings to +Rails.logger+.
83
91
  # [+notify+] Use +ActiveSupport::Notifications+ to notify +deprecation.rails+.
92
+ # [+report+] Use +ActiveSupport::ErrorReporter+ to report deprecations.
84
93
  # [+silence+] Do nothing.
85
94
  #
86
95
  # Setting behaviors only affects deprecations that happen after boot time.
87
96
  # Deprecation warnings raised by gems are not affected by this setting
88
- # because they happen before Rails boots up.
97
+ # because they happen before \Rails boots up.
89
98
  #
90
- # ActiveSupport::Deprecation.behavior = :stderr
91
- # ActiveSupport::Deprecation.behavior = [:stderr, :log]
92
- # ActiveSupport::Deprecation.behavior = MyCustomHandler
93
- # ActiveSupport::Deprecation.behavior = ->(message, callstack, deprecation_horizon, gem_name) {
99
+ # deprecator = ActiveSupport::Deprecation.new
100
+ # deprecator.behavior = :stderr
101
+ # deprecator.behavior = [:stderr, :log]
102
+ # deprecator.behavior = MyCustomHandler
103
+ # deprecator.behavior = ->(message, callstack, deprecation_horizon, gem_name) {
94
104
  # # custom stuff
95
105
  # }
96
106
  #
97
- # If you are using Rails, you can set <tt>config.active_support.report_deprecations = false</tt> to disable
107
+ # If you are using \Rails, you can set <tt>config.active_support.report_deprecations = false</tt> to disable
98
108
  # all deprecation behaviors. This is similar to the +silence+ option but more performant.
99
109
  def behavior=(behavior)
100
110
  @behavior = Array(behavior).map { |b| DEFAULT_BEHAVIORS[b] || arity_coerce(b) }
101
111
  end
102
112
 
103
113
  # Sets the behavior for disallowed deprecations (those configured by
104
- # ActiveSupport::Deprecation.disallowed_warnings=) to the specified
114
+ # ActiveSupport::Deprecation#disallowed_warnings=) to the specified
105
115
  # value. As with +behavior=+, this can be a single value, array, or an
106
116
  # object that responds to +call+.
107
117
  def disallowed_behavior=(behavior)
@@ -114,12 +124,23 @@ module ActiveSupport
114
124
  raise ArgumentError, "#{behavior.inspect} is not a valid deprecation behavior."
115
125
  end
116
126
 
117
- if behavior.respond_to?(:arity) && behavior.arity == 2
118
- -> message, callstack, _, _ { behavior.call(message, callstack) }
119
- else
127
+ case arity_of_callable(behavior)
128
+ when 2
129
+ ->(message, callstack, deprecator) do
130
+ behavior.call(message, callstack)
131
+ end
132
+ when -2..3
120
133
  behavior
134
+ else
135
+ ->(message, callstack, deprecator) do
136
+ behavior.call(message, callstack, deprecator.deprecation_horizon, deprecator.gem_name)
137
+ end
121
138
  end
122
139
  end
140
+
141
+ def arity_of_callable(callable)
142
+ callable.respond_to?(:arity) ? callable.arity : callable.method(:call).arity
143
+ end
123
144
  end
124
145
  end
125
146
  end
@@ -6,8 +6,7 @@ module ActiveSupport
6
6
  # hooking +const_missing+.
7
7
  #
8
8
  # It takes the names of an old (deprecated) constant and of a new constant
9
- # (both in string form) and optionally a deprecator. The deprecator defaults
10
- # to +ActiveSupport::Deprecator+ if none is specified.
9
+ # (both in string form) and a deprecator.
11
10
  #
12
11
  # The deprecated constant now returns the same object as the new one rather
13
12
  # than a proxy object, so it can be used transparently in +rescue+ blocks
@@ -19,7 +18,7 @@ module ActiveSupport
19
18
  #
20
19
  # PLANETS_POST_2006 = %w(mercury venus earth mars jupiter saturn uranus neptune)
21
20
  # include ActiveSupport::Deprecation::DeprecatedConstantAccessor
22
- # deprecate_constant 'PLANETS', 'PLANETS_POST_2006'
21
+ # deprecate_constant 'PLANETS', 'PLANETS_POST_2006', deprecator: ActiveSupport::Deprecation.new
23
22
  #
24
23
  # PLANETS.map { |planet| planet.capitalize }
25
24
  # # => DEPRECATION WARNING: PLANETS is deprecated! Use PLANETS_POST_2006 instead.
@@ -40,7 +39,9 @@ module ActiveSupport
40
39
  super
41
40
  end
42
41
 
43
- def deprecate_constant(const_name, new_constant, message: nil, deprecator: ActiveSupport::Deprecation.instance)
42
+ def deprecate_constant(const_name, new_constant, message: nil, deprecator: nil)
43
+ ActiveSupport.deprecator.warn("DeprecatedConstantAccessor.deprecate_constant without a deprecator is deprecated") unless deprecator
44
+ deprecator ||= ActiveSupport::Deprecation._instance
44
45
  class_variable_set(:@@_deprecated_constants, {}) unless class_variable_defined?(:@@_deprecated_constants)
45
46
  class_variable_get(:@@_deprecated_constants)[const_name.to_s] = { new: new_constant, message: message, deprecator: deprecator }
46
47
  end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ class Deprecation
5
+ # A managed collection of deprecators. Configuration methods, such as
6
+ # #behavior=, affect all deprecators in the collection. Additionally, the
7
+ # #silence method silences all deprecators in the collection for the
8
+ # duration of a given block.
9
+ class Deprecators
10
+ def initialize
11
+ @options = {}
12
+ @deprecators = {}
13
+ end
14
+
15
+ # Returns a deprecator added to this collection via #[]=.
16
+ def [](name)
17
+ @deprecators[name]
18
+ end
19
+
20
+ # Adds a given +deprecator+ to this collection. The deprecator will be
21
+ # immediately configured with any options previously set on this
22
+ # collection.
23
+ #
24
+ # deprecators = ActiveSupport::Deprecation::Deprecators.new
25
+ # deprecators.debug = true
26
+ #
27
+ # foo_deprecator = ActiveSupport::Deprecation.new("2.0", "Foo")
28
+ # foo_deprecator.debug # => false
29
+ #
30
+ # deprecators[:foo] = foo_deprecator
31
+ # deprecators[:foo].debug # => true
32
+ # foo_deprecator.debug # => true
33
+ #
34
+ def []=(name, deprecator)
35
+ apply_options(deprecator)
36
+ @deprecators[name] = deprecator
37
+ end
38
+
39
+ # Iterates over all deprecators in this collection. If no block is given,
40
+ # returns an +Enumerator+.
41
+ def each(&block)
42
+ return to_enum(__method__) unless block
43
+ @deprecators.each_value(&block)
44
+ end
45
+
46
+ # Sets the silenced flag for all deprecators in this collection.
47
+ def silenced=(silenced)
48
+ set_option(:silenced, silenced)
49
+ end
50
+
51
+ # Sets the debug flag for all deprecators in this collection.
52
+ def debug=(debug)
53
+ set_option(:debug, debug)
54
+ end
55
+
56
+ # Sets the deprecation warning behavior for all deprecators in this
57
+ # collection.
58
+ #
59
+ # See ActiveSupport::Deprecation#behavior=.
60
+ def behavior=(behavior)
61
+ set_option(:behavior, behavior)
62
+ end
63
+
64
+ # Sets the disallowed deprecation warning behavior for all deprecators in
65
+ # this collection.
66
+ #
67
+ # See ActiveSupport::Deprecation#disallowed_behavior=.
68
+ def disallowed_behavior=(disallowed_behavior)
69
+ set_option(:disallowed_behavior, disallowed_behavior)
70
+ end
71
+
72
+ # Sets the disallowed deprecation warnings for all deprecators in this
73
+ # collection.
74
+ #
75
+ # See ActiveSupport::Deprecation#disallowed_warnings=.
76
+ def disallowed_warnings=(disallowed_warnings)
77
+ set_option(:disallowed_warnings, disallowed_warnings)
78
+ end
79
+
80
+ # Silences all deprecators in this collection for the duration of the
81
+ # given block.
82
+ #
83
+ # See ActiveSupport::Deprecation#silence.
84
+ def silence(&block)
85
+ each { |deprecator| deprecator.begin_silence }
86
+ block.call
87
+ ensure
88
+ each { |deprecator| deprecator.end_silence }
89
+ end
90
+
91
+ private
92
+ def set_option(name, value)
93
+ @options[name] = value
94
+ each { |deprecator| deprecator.public_send("#{name}=", value) }
95
+ end
96
+
97
+ def apply_options(deprecator)
98
+ @options.each do |name, value|
99
+ deprecator.public_send("#{name}=", value)
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -24,10 +24,9 @@ module ActiveSupport
24
24
 
25
25
  private
26
26
  def deprecation_disallowed?(message)
27
- disallowed = ActiveSupport::Deprecation.disallowed_warnings
28
27
  return false if explicitly_allowed?(message)
29
- return true if disallowed == :all
30
- disallowed.any? do |rule|
28
+ return true if disallowed_warnings == :all
29
+ message && disallowed_warnings.any? do |rule|
31
30
  case rule
32
31
  when String, Symbol
33
32
  message.include?(rule.to_s)
@@ -41,8 +40,7 @@ module ActiveSupport
41
40
  allowances = @explicitly_allowed_warnings.value
42
41
  return false unless allowances
43
42
  return true if allowances == :all
44
- allowances = [allowances] unless allowances.kind_of?(Array)
45
- allowances.any? do |rule|
43
+ message && Array(allowances).any? do |rule|
46
44
  case rule
47
45
  when String, Symbol
48
46
  message.include?(rule.to_s)
@@ -1,24 +1,51 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/module/delegation"
4
-
5
3
  module ActiveSupport
6
4
  class Deprecation
7
5
  module InstanceDelegator # :nodoc:
8
6
  def self.included(base)
9
7
  base.extend(ClassMethods)
10
8
  base.singleton_class.prepend(OverrideDelegators)
11
- base.public_class_method :new
12
9
  end
13
10
 
14
11
  module ClassMethods # :nodoc:
12
+ MUTEX = Mutex.new
13
+ private_constant :MUTEX
14
+
15
15
  def include(included_module)
16
16
  included_module.instance_methods.each { |m| method_added(m) }
17
17
  super
18
18
  end
19
19
 
20
20
  def method_added(method_name)
21
- singleton_class.delegate(method_name, to: :instance)
21
+ use_instead =
22
+ case method_name
23
+ when :silence, :behavior=, :disallowed_behavior=, :disallowed_warnings=, :silenced=, :debug=
24
+ target = "(defined?(Rails.application.deprecators) ? Rails.application.deprecators : ActiveSupport::Deprecation._instance)"
25
+ "Rails.application.deprecators.#{method_name}"
26
+ when :warn, :deprecate_methods, :gem_name, :gem_name=, :deprecation_horizon, :deprecation_horizon=
27
+ "your own Deprecation object"
28
+ else
29
+ "Rails.application.deprecators[framework].#{method_name} where framework is for example :active_record"
30
+ end
31
+ args = /[^\]]=\z/.match?(method_name) ? "arg" : "..."
32
+ target ||= "ActiveSupport::Deprecation._instance"
33
+ singleton_class.module_eval <<~RUBY, __FILE__, __LINE__ + 1
34
+ def #{method_name}(#{args})
35
+ #{target}.#{method_name}(#{args})
36
+ ensure
37
+ ActiveSupport.deprecator.warn("Calling #{method_name} on ActiveSupport::Deprecation is deprecated and will be removed from Rails (use #{use_instead} instead)")
38
+ end
39
+ RUBY
40
+ end
41
+
42
+ def instance
43
+ ActiveSupport.deprecator.warn("ActiveSupport::Deprecation.instance is deprecated (use your own Deprecation object)")
44
+ _instance
45
+ end
46
+
47
+ def _instance
48
+ @_instance ||= MUTEX.synchronize { @_instance ||= new }
22
49
  end
23
50
  end
24
51
 
@@ -16,38 +16,21 @@ module ActiveSupport
16
16
  # def eee; end
17
17
  # end
18
18
  #
19
- # Using the default deprecator:
20
- # ActiveSupport::Deprecation.deprecate_methods(Fred, :aaa, bbb: :zzz, ccc: 'use Bar#ccc instead')
19
+ # deprecator = ActiveSupport::Deprecation.new('next-release', 'MyGem')
20
+ #
21
+ # deprecator.deprecate_methods(Fred, :aaa, bbb: :zzz, ccc: 'use Bar#ccc instead')
21
22
  # # => Fred
22
23
  #
23
24
  # Fred.new.aaa
24
- # # DEPRECATION WARNING: aaa is deprecated and will be removed from Rails 5.1. (called from irb_binding at (irb):10)
25
+ # # DEPRECATION WARNING: aaa is deprecated and will be removed from MyGem next-release. (called from irb_binding at (irb):10)
25
26
  # # => nil
26
27
  #
27
28
  # Fred.new.bbb
28
- # # DEPRECATION WARNING: bbb is deprecated and will be removed from Rails 5.1 (use zzz instead). (called from irb_binding at (irb):11)
29
+ # # DEPRECATION WARNING: bbb is deprecated and will be removed from MyGem next-release (use zzz instead). (called from irb_binding at (irb):11)
29
30
  # # => nil
30
31
  #
31
32
  # Fred.new.ccc
32
- # # DEPRECATION WARNING: ccc is deprecated and will be removed from Rails 5.1 (use Bar#ccc instead). (called from irb_binding at (irb):12)
33
- # # => nil
34
- #
35
- # Passing in a custom deprecator:
36
- # custom_deprecator = ActiveSupport::Deprecation.new('next-release', 'MyGem')
37
- # ActiveSupport::Deprecation.deprecate_methods(Fred, ddd: :zzz, deprecator: custom_deprecator)
38
- # # => [:ddd]
39
- #
40
- # Fred.new.ddd
41
- # DEPRECATION WARNING: ddd is deprecated and will be removed from MyGem next-release (use zzz instead). (called from irb_binding at (irb):15)
42
- # # => nil
43
- #
44
- # Using a custom deprecator directly:
45
- # custom_deprecator = ActiveSupport::Deprecation.new('next-release', 'MyGem')
46
- # custom_deprecator.deprecate_methods(Fred, eee: :zzz)
47
- # # => [:eee]
48
- #
49
- # Fred.new.eee
50
- # DEPRECATION WARNING: eee is deprecated and will be removed from MyGem next-release (use zzz instead). (called from irb_binding at (irb):18)
33
+ # # DEPRECATION WARNING: ccc is deprecated and will be removed from MyGem next-release (use Bar#ccc instead). (called from irb_binding at (irb):12)
51
34
  # # => nil
52
35
  def deprecate_methods(target_module, *method_names)
53
36
  options = method_names.extract_options!