activesupport 7.1.4.1 → 7.2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +127 -1129
  3. data/lib/active_support/array_inquirer.rb +1 -1
  4. data/lib/active_support/backtrace_cleaner.rb +10 -3
  5. data/lib/active_support/broadcast_logger.rb +18 -18
  6. data/lib/active_support/cache/file_store.rb +15 -10
  7. data/lib/active_support/cache/mem_cache_store.rb +16 -74
  8. data/lib/active_support/cache/memory_store.rb +2 -1
  9. data/lib/active_support/cache/redis_cache_store.rb +16 -13
  10. data/lib/active_support/cache/serializer_with_fallback.rb +0 -23
  11. data/lib/active_support/cache.rb +60 -68
  12. data/lib/active_support/callbacks.rb +74 -113
  13. data/lib/active_support/core_ext/array/conversions.rb +0 -2
  14. data/lib/active_support/core_ext/class/subclasses.rb +15 -35
  15. data/lib/active_support/core_ext/date/blank.rb +4 -0
  16. data/lib/active_support/core_ext/date/conversions.rb +0 -2
  17. data/lib/active_support/core_ext/date_and_time/compatibility.rb +28 -1
  18. data/lib/active_support/core_ext/date_time/blank.rb +4 -0
  19. data/lib/active_support/core_ext/date_time/conversions.rb +0 -4
  20. data/lib/active_support/core_ext/digest/uuid.rb +6 -0
  21. data/lib/active_support/core_ext/erb/util.rb +5 -0
  22. data/lib/active_support/core_ext/hash/keys.rb +4 -4
  23. data/lib/active_support/core_ext/module/attr_internal.rb +17 -6
  24. data/lib/active_support/core_ext/module/delegation.rb +20 -163
  25. data/lib/active_support/core_ext/module/deprecation.rb +1 -4
  26. data/lib/active_support/core_ext/numeric/conversions.rb +3 -3
  27. data/lib/active_support/core_ext/object/blank.rb +45 -1
  28. data/lib/active_support/core_ext/object/instance_variables.rb +11 -19
  29. data/lib/active_support/core_ext/object/json.rb +6 -4
  30. data/lib/active_support/core_ext/object/with.rb +5 -3
  31. data/lib/active_support/core_ext/pathname/blank.rb +4 -0
  32. data/lib/active_support/core_ext/range/overlap.rb +1 -1
  33. data/lib/active_support/core_ext/securerandom.rb +8 -24
  34. data/lib/active_support/core_ext/string/conversions.rb +1 -1
  35. data/lib/active_support/core_ext/string/filters.rb +1 -1
  36. data/lib/active_support/core_ext/string/multibyte.rb +1 -1
  37. data/lib/active_support/core_ext/string/output_safety.rb +0 -7
  38. data/lib/active_support/core_ext/time/calculations.rb +18 -28
  39. data/lib/active_support/core_ext/time/compatibility.rb +16 -0
  40. data/lib/active_support/core_ext/time/conversions.rb +0 -2
  41. data/lib/active_support/core_ext/time/zones.rb +1 -1
  42. data/lib/active_support/core_ext.rb +0 -1
  43. data/lib/active_support/current_attributes.rb +38 -40
  44. data/lib/active_support/delegation.rb +202 -0
  45. data/lib/active_support/dependencies/autoload.rb +0 -12
  46. data/lib/active_support/deprecation/constant_accessor.rb +47 -26
  47. data/lib/active_support/deprecation/proxy_wrappers.rb +9 -12
  48. data/lib/active_support/deprecation/reporting.rb +9 -4
  49. data/lib/active_support/deprecation.rb +8 -5
  50. data/lib/active_support/descendants_tracker.rb +9 -87
  51. data/lib/active_support/duration/iso8601_parser.rb +2 -2
  52. data/lib/active_support/duration/iso8601_serializer.rb +1 -2
  53. data/lib/active_support/duration.rb +11 -6
  54. data/lib/active_support/encrypted_file.rb +1 -1
  55. data/lib/active_support/error_reporter.rb +41 -3
  56. data/lib/active_support/evented_file_update_checker.rb +0 -1
  57. data/lib/active_support/execution_wrapper.rb +0 -1
  58. data/lib/active_support/file_update_checker.rb +1 -1
  59. data/lib/active_support/fork_tracker.rb +2 -38
  60. data/lib/active_support/gem_version.rb +2 -2
  61. data/lib/active_support/hash_with_indifferent_access.rb +6 -8
  62. data/lib/active_support/html_safe_translation.rb +3 -0
  63. data/lib/active_support/log_subscriber.rb +0 -12
  64. data/lib/active_support/logger.rb +15 -2
  65. data/lib/active_support/logger_thread_safe_level.rb +0 -8
  66. data/lib/active_support/message_pack/extensions.rb +15 -2
  67. data/lib/active_support/message_verifier.rb +12 -0
  68. data/lib/active_support/multibyte/chars.rb +2 -2
  69. data/lib/active_support/notifications/fanout.rb +4 -7
  70. data/lib/active_support/notifications/instrumenter.rb +21 -18
  71. data/lib/active_support/notifications.rb +28 -27
  72. data/lib/active_support/number_helper/number_converter.rb +2 -2
  73. data/lib/active_support/option_merger.rb +2 -2
  74. data/lib/active_support/ordered_options.rb +53 -15
  75. data/lib/active_support/proxy_object.rb +8 -5
  76. data/lib/active_support/railtie.rb +4 -11
  77. data/lib/active_support/string_inquirer.rb +1 -1
  78. data/lib/active_support/subscriber.rb +1 -0
  79. data/lib/active_support/tagged_logging.rb +0 -1
  80. data/lib/active_support/test_case.rb +3 -1
  81. data/lib/active_support/testing/assertions.rb +4 -4
  82. data/lib/active_support/testing/constant_stubbing.rb +30 -8
  83. data/lib/active_support/testing/deprecation.rb +5 -12
  84. data/lib/active_support/testing/isolation.rb +20 -8
  85. data/lib/active_support/testing/method_call_assertions.rb +2 -16
  86. data/lib/active_support/testing/parallelization/server.rb +3 -0
  87. data/lib/active_support/testing/strict_warnings.rb +8 -4
  88. data/lib/active_support/testing/tests_without_assertions.rb +19 -0
  89. data/lib/active_support/testing/time_helpers.rb +3 -3
  90. data/lib/active_support/time_with_zone.rb +8 -4
  91. data/lib/active_support/values/time_zone.rb +7 -7
  92. data/lib/active_support/xml_mini.rb +11 -2
  93. data/lib/active_support.rb +2 -1
  94. metadata +49 -15
  95. data/lib/active_support/deprecation/instance_delegator.rb +0 -65
  96. data/lib/active_support/ruby_features.rb +0 -7
@@ -151,7 +151,12 @@ module ActiveSupport
151
151
  end
152
152
 
153
153
  def _extract_callstack(callstack)
154
- warn "Please pass `caller_locations` to the deprecation API" if $VERBOSE
154
+ ActiveSupport.deprecator.warn(<<~MESSAGE)
155
+ Passing the result of `caller` to ActiveSupport::Deprecation#warn is deprecated and will be removed in Rails 8.0.
156
+
157
+ Please pass the result of `caller_locations` instead.
158
+ MESSAGE
159
+
155
160
  offending_line = callstack.find { |line| !ignored_callstack?(line) } || callstack.first
156
161
 
157
162
  if offending_line
@@ -163,11 +168,11 @@ module ActiveSupport
163
168
  end
164
169
  end
165
170
 
166
- RAILS_GEM_ROOT = File.expand_path("../../../..", __dir__) + "/"
167
- LIB_DIR = RbConfig::CONFIG["libdir"]
171
+ RAILS_GEM_ROOT = File.expand_path("../../../..", __dir__) + "/" # :nodoc:
172
+ LIB_DIR = RbConfig::CONFIG["libdir"] # :nodoc:
168
173
 
169
174
  def ignored_callstack?(path)
170
- path.start_with?(RAILS_GEM_ROOT, LIB_DIR)
175
+ path.start_with?(RAILS_GEM_ROOT, LIB_DIR) || path.include?("<internal:")
171
176
  end
172
177
  end
173
178
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "singleton"
4
-
5
3
  module ActiveSupport
6
4
  # = Active Support \Deprecation
7
5
  #
@@ -41,7 +39,6 @@ module ActiveSupport
41
39
  # a circular require warning for active_support/deprecation.rb.
42
40
  #
43
41
  # So, we define the constant first, and load dependencies later.
44
- require "active_support/deprecation/instance_delegator"
45
42
  require "active_support/deprecation/behaviors"
46
43
  require "active_support/deprecation/reporting"
47
44
  require "active_support/deprecation/disallowed"
@@ -52,12 +49,18 @@ module ActiveSupport
52
49
  require "active_support/core_ext/module/deprecation"
53
50
  require "concurrent/atomic/thread_local_var"
54
51
 
55
- include InstanceDelegator
56
52
  include Behavior
57
53
  include Reporting
58
54
  include Disallowed
59
55
  include MethodWrapper
60
56
 
57
+ MUTEX = Mutex.new # :nodoc:
58
+ private_constant :MUTEX
59
+
60
+ def self._instance # :nodoc:
61
+ @_instance ||= MUTEX.synchronize { @_instance ||= new }
62
+ end
63
+
61
64
  # The version number in which the deprecated behavior will be removed, by default.
62
65
  attr_accessor :deprecation_horizon
63
66
 
@@ -65,7 +68,7 @@ module ActiveSupport
65
68
  # and the second is a library name.
66
69
  #
67
70
  # ActiveSupport::Deprecation.new('2.0', 'MyLibrary')
68
- def initialize(deprecation_horizon = "7.2", gem_name = "Rails")
71
+ def initialize(deprecation_horizon = "8.0", gem_name = "Rails")
69
72
  self.gem_name = gem_name
70
73
  self.deprecation_horizon = deprecation_horizon
71
74
  # By default, warnings are not silenced and debugging is off.
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "weakref"
4
- require "active_support/ruby_features"
5
4
 
6
5
  module ActiveSupport
7
6
  # = Active Support Descendants Tracker
@@ -95,96 +94,19 @@ module ActiveSupport
95
94
  end
96
95
  end
97
96
 
98
- if RubyFeatures::CLASS_SUBCLASSES
99
- class << self
100
- def subclasses(klass)
101
- klass.subclasses
102
- end
103
-
104
- def descendants(klass)
105
- klass.descendants
106
- end
107
- end
108
-
109
- def descendants
110
- subclasses = DescendantsTracker.reject!(self.subclasses)
111
- subclasses.concat(subclasses.flat_map(&:descendants))
112
- end
113
- else
114
- # DescendantsArray is an array that contains weak references to classes.
115
- # Note: DescendantsArray is redundant with WeakSet, however WeakSet when used
116
- # on Ruby 2.7 or 3.0 can trigger a Ruby crash: https://bugs.ruby-lang.org/issues/18928
117
- class DescendantsArray # :nodoc:
118
- include Enumerable
119
-
120
- def initialize
121
- @refs = []
122
- end
123
-
124
- def <<(klass)
125
- @refs << WeakRef.new(klass)
126
- end
127
-
128
- def each
129
- @refs.reject! do |ref|
130
- yield ref.__getobj__
131
- false
132
- rescue WeakRef::RefError
133
- true
134
- end
135
- self
136
- end
137
-
138
- def refs_size
139
- @refs.size
140
- end
141
-
142
- def cleanup!
143
- @refs.delete_if { |ref| !ref.weakref_alive? }
144
- end
145
-
146
- def reject!
147
- @refs.reject! do |ref|
148
- yield ref.__getobj__
149
- rescue WeakRef::RefError
150
- true
151
- end
152
- end
153
- end
154
-
155
- @direct_descendants = {}
156
-
157
- class << self
158
- def subclasses(klass)
159
- descendants = @direct_descendants[klass]
160
- descendants ? DescendantsTracker.reject!(descendants.to_a) : []
161
- end
162
-
163
- def descendants(klass)
164
- subclasses = self.subclasses(klass)
165
- subclasses.concat(subclasses.flat_map { |k| descendants(k) })
166
- end
167
-
168
- # This is the only method that is not thread safe, but is only ever called
169
- # during the eager loading phase.
170
- def store_inherited(klass, descendant) # :nodoc:
171
- (@direct_descendants[klass] ||= DescendantsArray.new) << descendant
172
- end
173
- end
174
-
175
- def subclasses
176
- DescendantsTracker.subclasses(self)
97
+ class << self
98
+ def subclasses(klass)
99
+ klass.subclasses
177
100
  end
178
101
 
179
- def descendants
180
- DescendantsTracker.descendants(self)
102
+ def descendants(klass)
103
+ klass.descendants
181
104
  end
105
+ end
182
106
 
183
- private
184
- def inherited(base) # :nodoc:
185
- DescendantsTracker.store_inherited(self, base)
186
- super
187
- end
107
+ def descendants
108
+ subclasses = DescendantsTracker.reject!(self.subclasses)
109
+ subclasses.concat(subclasses.flat_map(&:descendants))
188
110
  end
189
111
  end
190
112
  end
@@ -102,12 +102,12 @@ module ActiveSupport
102
102
  raise_parsing_error("is empty duration") if parts.empty?
103
103
 
104
104
  # Mixing any of Y, M, D with W is invalid.
105
- if parts.key?(:weeks) && (parts.keys & DATE_COMPONENTS).any?
105
+ if parts.key?(:weeks) && parts.keys.intersect?(DATE_COMPONENTS)
106
106
  raise_parsing_error("mixing weeks with other date parts not allowed")
107
107
  end
108
108
 
109
109
  # Specifying an empty T part is invalid.
110
- if mode == :time && (parts.keys & TIME_COMPONENTS).empty?
110
+ if mode == :time && !parts.keys.intersect?(TIME_COMPONENTS)
111
111
  raise_parsing_error("time part marker is present but time part is empty")
112
112
  end
113
113
 
@@ -35,7 +35,6 @@ module ActiveSupport
35
35
  # Return pair of duration's parts and whole duration sign.
36
36
  # Parts are summarized (as they can become repetitive due to addition, etc).
37
37
  # Zero parts are removed as not significant.
38
- # If all parts are negative it will negate all of them and return minus as a sign.
39
38
  def normalize
40
39
  parts = @duration.parts.each_with_object(Hash.new(0)) do |(k, v), p|
41
40
  p[k] += v unless v.zero?
@@ -50,7 +49,7 @@ module ActiveSupport
50
49
  end
51
50
 
52
51
  def week_mixed_with_date?(parts)
53
- parts.key?(:weeks) && (parts.keys & DATE_COMPONENTS).any?
52
+ parts.key?(:weeks) && parts.keys.intersect?(DATE_COMPONENTS)
54
53
  end
55
54
 
56
55
  def format_seconds(seconds)
@@ -14,7 +14,7 @@ module ActiveSupport
14
14
  class Duration
15
15
  class Scalar < Numeric # :nodoc:
16
16
  attr_reader :value
17
- delegate :to_i, :to_f, :to_s, to: :value
17
+ delegate :to_i, :to_f, :to_s, to: :@value
18
18
 
19
19
  def initialize(value)
20
20
  @value = value
@@ -221,6 +221,8 @@ module ActiveSupport
221
221
  end
222
222
  end
223
223
 
224
+ Delegation.generate(self, [:to_f, :positive?, :negative?, :zero?, :abs], to: :@value, as: Integer, nilable: false)
225
+
224
226
  def initialize(value, parts, variable = nil) # :nodoc:
225
227
  @value, @parts = value, parts
226
228
  @parts.reject! { |k, v| v.zero? } unless value == 0
@@ -232,7 +234,10 @@ module ActiveSupport
232
234
  end
233
235
  end
234
236
 
235
- # Returns a copy of the parts hash that defines the duration
237
+ # Returns a copy of the parts hash that defines the duration.
238
+ #
239
+ # 5.minutes.parts # => {:minutes=>5}
240
+ # 3.years.parts # => {:years=>3}
236
241
  def parts
237
242
  @parts.dup
238
243
  end
@@ -366,8 +371,8 @@ module ActiveSupport
366
371
  # 1.year.to_i # => 31556952
367
372
  #
368
373
  # In such cases, Ruby's core
369
- # Date[https://ruby-doc.org/stdlib/libdoc/date/rdoc/Date.html] and
370
- # Time[https://ruby-doc.org/stdlib/libdoc/time/rdoc/Time.html] should be used for precision
374
+ # Date[https://docs.ruby-lang.org/en/master/Date.html] and
375
+ # Time[https://docs.ruby-lang.org/en/master/Time.html] should be used for precision
371
376
  # date and time arithmetic.
372
377
  def to_i
373
378
  @value.to_i
@@ -504,8 +509,8 @@ module ActiveSupport
504
509
  value.respond_to?(method)
505
510
  end
506
511
 
507
- def method_missing(method, *args, &block)
508
- value.public_send(method, *args, &block)
512
+ def method_missing(...)
513
+ value.public_send(...)
509
514
  end
510
515
 
511
516
  def raise_type_error(other)
@@ -69,7 +69,7 @@ module ActiveSupport
69
69
  # decrypted or verified.
70
70
  def read
71
71
  if !key.nil? && content_path.exist?
72
- decrypt content_path.binread
72
+ decrypt content_path.binread.strip
73
73
  else
74
74
  raise MissingContentError, content_path
75
75
  end
@@ -26,12 +26,16 @@ module ActiveSupport
26
26
  class ErrorReporter
27
27
  SEVERITIES = %i(error warning info)
28
28
  DEFAULT_SOURCE = "application"
29
+ DEFAULT_RESCUE = [StandardError].freeze
29
30
 
30
- attr_accessor :logger
31
+ attr_accessor :logger, :debug_mode
32
+
33
+ UnexpectedError = Class.new(Exception)
31
34
 
32
35
  def initialize(*subscribers, logger: nil)
33
36
  @subscribers = subscribers.flatten
34
37
  @logger = logger
38
+ @debug_mode = false
35
39
  end
36
40
 
37
41
  # Evaluates the given block, reporting and swallowing any unhandled error.
@@ -72,7 +76,7 @@ module ActiveSupport
72
76
  # source of the error. Subscribers can use this value to ignore certain
73
77
  # errors. Defaults to <tt>"application"</tt>.
74
78
  def handle(*error_classes, severity: :warning, context: {}, fallback: nil, source: DEFAULT_SOURCE)
75
- error_classes = [StandardError] if error_classes.blank?
79
+ error_classes = DEFAULT_RESCUE if error_classes.empty?
76
80
  yield
77
81
  rescue *error_classes => error
78
82
  report(error, handled: true, severity: severity, context: context, source: source)
@@ -108,13 +112,47 @@ module ActiveSupport
108
112
  # source of the error. Subscribers can use this value to ignore certain
109
113
  # errors. Defaults to <tt>"application"</tt>.
110
114
  def record(*error_classes, severity: :error, context: {}, source: DEFAULT_SOURCE)
111
- error_classes = [StandardError] if error_classes.blank?
115
+ error_classes = DEFAULT_RESCUE if error_classes.empty?
112
116
  yield
113
117
  rescue *error_classes => error
114
118
  report(error, handled: false, severity: severity, context: context, source: source)
115
119
  raise
116
120
  end
117
121
 
122
+ # Either report the given error when in production, or raise it when in development or test.
123
+ #
124
+ # When called in production, after the error is reported, this method will return
125
+ # nil and execution will continue.
126
+ #
127
+ # When called in development, the original error is wrapped in a different error class to ensure
128
+ # it's not being rescued higher in the stack and will be surfaced to the developer.
129
+ #
130
+ # This method is intended for reporting violated assertions about preconditions, or similar
131
+ # cases that can and should be gracefully handled in production, but that aren't supposed to happen.
132
+ #
133
+ # The error can be either an exception instance or a String.
134
+ #
135
+ # example:
136
+ #
137
+ # def edit
138
+ # if published?
139
+ # Rails.error.unexpected("[BUG] Attempting to edit a published article, that shouldn't be possible")
140
+ # return false
141
+ # end
142
+ # # ...
143
+ # end
144
+ #
145
+ def unexpected(error, severity: :warning, context: {}, source: DEFAULT_SOURCE)
146
+ error = RuntimeError.new(error) if error.is_a?(String)
147
+ error.set_backtrace(caller(1)) if error.backtrace.nil?
148
+
149
+ if @debug_mode
150
+ raise UnexpectedError, "#{error.class.name}: #{error.message}", error.backtrace, cause: error
151
+ else
152
+ report(error, handled: true, severity: severity, context: context, source: source)
153
+ end
154
+ end
155
+
118
156
  # Register a new error subscriber. The subscriber must respond to
119
157
  #
120
158
  # report(Exception, handled: Boolean, severity: (:error OR :warning OR :info), context: Hash, source: String)
@@ -6,7 +6,6 @@ require "listen"
6
6
  require "set"
7
7
  require "pathname"
8
8
  require "concurrent/atomic/atomic_boolean"
9
- require "active_support/fork_tracker"
10
9
 
11
10
  module ActiveSupport
12
11
  # Allows you to "listen" to changes in a file system.
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "active_support/error_reporter"
4
4
  require "active_support/callbacks"
5
- require "concurrent/hash"
6
5
 
7
6
  module ActiveSupport
8
7
  class ExecutionWrapper
@@ -104,7 +104,7 @@ module ActiveSupport
104
104
  @watched || begin
105
105
  all = @files.select { |f| File.exist?(f) }
106
106
  all.concat(Dir[@glob]) if @glob
107
- all
107
+ all.tap(&:uniq!)
108
108
  end
109
109
  end
110
110
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  module ActiveSupport
4
4
  module ForkTracker # :nodoc:
5
- module ModernCoreExt
5
+ module CoreExt
6
6
  def _fork
7
7
  pid = super
8
8
  if pid == 0
@@ -12,27 +12,6 @@ module ActiveSupport
12
12
  end
13
13
  end
14
14
 
15
- module CoreExt
16
- def fork(...)
17
- if block_given?
18
- super do
19
- ForkTracker.check!
20
- yield
21
- end
22
- else
23
- unless pid = super
24
- ForkTracker.check!
25
- end
26
- pid
27
- end
28
- end
29
- end
30
-
31
- module CoreExtPrivate
32
- include CoreExt
33
- private :fork
34
- end
35
-
36
15
  @pid = Process.pid
37
16
  @callbacks = []
38
17
 
@@ -45,23 +24,8 @@ module ActiveSupport
45
24
  end
46
25
  end
47
26
 
48
- if Process.respond_to?(:_fork) # Ruby 3.1+
49
- def check!
50
- # We trust the `_fork` callback
51
- end
52
- else
53
- alias_method :check!, :after_fork_callback
54
- end
55
-
56
27
  def hook!
57
- if Process.respond_to?(:_fork) # Ruby 3.1+
58
- ::Process.singleton_class.prepend(ModernCoreExt)
59
- elsif Process.respond_to?(:fork)
60
- ::Object.prepend(CoreExtPrivate) if RUBY_VERSION < "3.0"
61
- ::Kernel.prepend(CoreExtPrivate)
62
- ::Kernel.singleton_class.prepend(CoreExt)
63
- ::Process.singleton_class.prepend(CoreExt)
64
- end
28
+ ::Process.singleton_class.prepend(CoreExt)
65
29
  end
66
30
 
67
31
  def after_fork(&block)
@@ -8,8 +8,8 @@ module ActiveSupport
8
8
 
9
9
  module VERSION
10
10
  MAJOR = 7
11
- MINOR = 1
12
- TINY = 4
11
+ MINOR = 2
12
+ TINY = 2
13
13
  PRE = "1"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
@@ -387,15 +387,13 @@ module ActiveSupport
387
387
  _new_hash
388
388
  end
389
389
 
390
+ def to_proc
391
+ proc { |key| self[key] }
392
+ end
393
+
390
394
  private
391
- if Symbol.method_defined?(:name)
392
- def convert_key(key)
393
- key.kind_of?(Symbol) ? key.name : key
394
- end
395
- else
396
- def convert_key(key)
397
- key.kind_of?(Symbol) ? key.to_s : key
398
- end
395
+ def convert_key(key)
396
+ Symbol === key ? key.name : key
399
397
  end
400
398
 
401
399
  def convert_value(value, conversion: nil)
@@ -9,11 +9,14 @@ module ActiveSupport
9
9
  html_safe_options = html_escape_translation_options(options)
10
10
 
11
11
  exception = false
12
+
12
13
  exception_handler = ->(*args) do
13
14
  exception = true
14
15
  I18n.exception_handler.call(*args)
15
16
  end
17
+
16
18
  translation = I18n.translate(key, **html_safe_options, exception_handler: exception_handler)
19
+
17
20
  if exception
18
21
  translation
19
22
  else
@@ -62,10 +62,6 @@ module ActiveSupport
62
62
  # that all logs are flushed, and it is called in Rails::Rack::Logger after a
63
63
  # request finishes.
64
64
  class LogSubscriber < Subscriber
65
- # Embed in a String to clear all previous ANSI sequences.
66
- CLEAR = ActiveSupport::Deprecation::DeprecatedObjectProxy.new("\e[0m", "CLEAR is deprecated! Use MODES[:clear] instead.", ActiveSupport.deprecator)
67
- BOLD = ActiveSupport::Deprecation::DeprecatedObjectProxy.new("\e[1m", "BOLD is deprecated! Use MODES[:bold] instead.", ActiveSupport.deprecator)
68
-
69
65
  # ANSI sequence modes
70
66
  MODES = {
71
67
  clear: 0,
@@ -182,14 +178,6 @@ module ActiveSupport
182
178
  end
183
179
 
184
180
  def mode_from(options)
185
- if options.is_a?(TrueClass) || options.is_a?(FalseClass)
186
- ActiveSupport.deprecator.warn(<<~MSG.squish)
187
- Bolding log text with a positional boolean is deprecated and will be removed
188
- in Rails 7.2. Use an option hash instead (eg. `color("my text", :red, bold: true)`).
189
- MSG
190
- options = { bold: options }
191
- end
192
-
193
181
  modes = MODES.values_at(*options.compact_blank.keys)
194
182
 
195
183
  "\e[#{modes.join(";")}m" if modes.any?
@@ -13,6 +13,10 @@ module ActiveSupport
13
13
  # logger = Logger.new(STDOUT)
14
14
  # ActiveSupport::Logger.logger_outputs_to?(logger, STDOUT)
15
15
  # # => true
16
+ #
17
+ # logger = Logger.new('/var/log/rails.log')
18
+ # ActiveSupport::Logger.logger_outputs_to?(logger, '/var/log/rails.log')
19
+ # # => true
16
20
  def self.logger_outputs_to?(logger, *sources)
17
21
  loggers = if logger.is_a?(BroadcastLogger)
18
22
  logger.broadcasts
@@ -21,9 +25,9 @@ module ActiveSupport
21
25
  end
22
26
 
23
27
  logdevs = loggers.map { |logger| logger.instance_variable_get(:@logdev) }
24
- logger_sources = logdevs.filter_map { |logdev| logdev.dev if logdev.respond_to?(:dev) }
28
+ logger_sources = logdevs.filter_map { |logdev| logdev.try(:filename) || logdev.try(:dev) }
25
29
 
26
- (sources & logger_sources).any?
30
+ normalize_sources(sources).intersect?(normalize_sources(logger_sources))
27
31
  end
28
32
 
29
33
  def initialize(*args, **kwargs)
@@ -38,5 +42,14 @@ module ActiveSupport
38
42
  "#{String === msg ? msg : msg.inspect}\n"
39
43
  end
40
44
  end
45
+
46
+ private
47
+ def self.normalize_sources(sources)
48
+ sources.map do |source|
49
+ source = source.path if source.respond_to?(:path)
50
+ source = File.realpath(source) if source.is_a?(String) && File.exist?(source)
51
+ source
52
+ end
53
+ end
41
54
  end
42
55
  end
@@ -7,14 +7,6 @@ module ActiveSupport
7
7
  module LoggerThreadSafeLevel # :nodoc:
8
8
  extend ActiveSupport::Concern
9
9
 
10
- Logger::Severity.constants.each do |severity|
11
- class_eval(<<-EOT, __FILE__, __LINE__ + 1)
12
- def #{severity.downcase}? # def debug?
13
- Logger::#{severity} >= level # DEBUG >= level
14
- end # end
15
- EOT
16
- end
17
-
18
10
  def local_level
19
11
  IsolatedExecutionState[local_level_key]
20
12
  end
@@ -86,8 +86,9 @@ module ActiveSupport
86
86
  unpacker: URI.method(:parse)
87
87
 
88
88
  registry.register_type 14, IPAddr,
89
- packer: :to_s,
90
- unpacker: :new
89
+ packer: method(:write_ipaddr),
90
+ unpacker: method(:read_ipaddr),
91
+ recursive: true
91
92
 
92
93
  registry.register_type 15, Pathname,
93
94
  packer: :to_s,
@@ -221,6 +222,18 @@ module ActiveSupport
221
222
  Set.new(unpacker.read)
222
223
  end
223
224
 
225
+ def write_ipaddr(ipaddr, packer)
226
+ if ipaddr.prefix < 32 || (ipaddr.ipv6? && ipaddr.prefix < 128)
227
+ packer.write("#{ipaddr}/#{ipaddr.prefix}")
228
+ else
229
+ packer.write(ipaddr.to_s)
230
+ end
231
+ end
232
+
233
+ def read_ipaddr(unpacker)
234
+ IPAddr.new(unpacker.read)
235
+ end
236
+
224
237
  def write_hash_with_indifferent_access(hwia, packer)
225
238
  packer.write(hwia.to_h)
226
239
  end
@@ -30,6 +30,18 @@ module ActiveSupport
30
30
  # self.current_user = User.find(id)
31
31
  # end
32
32
  #
33
+ # === Signing is not encryption
34
+ #
35
+ # The signed messages are not encrypted. The payload is merely encoded (Base64 by default) and can be decoded by
36
+ # anyone. The signature is just assuring that the message wasn't tampered with. For example:
37
+ #
38
+ # message = Rails.application.message_verifier('my_purpose').generate('never put secrets here')
39
+ # # => "BAhJIhtuZXZlciBwdXQgc2VjcmV0cyBoZXJlBjoGRVQ=--a0c1c0827919da5e949e989c971249355735e140"
40
+ # Base64.decode64(message.split("--").first) # no key needed
41
+ # # => 'never put secrets here'
42
+ #
43
+ # If you also need to encrypt the contents, you must use ActiveSupport::MessageEncryptor instead.
44
+ #
33
45
  # === Confine messages to a specific purpose
34
46
  #
35
47
  # It's not recommended to use the same verifier for different purposes in your application.
@@ -59,8 +59,8 @@ module ActiveSupport # :nodoc:
59
59
  end
60
60
 
61
61
  # Forward all undefined methods to the wrapped string.
62
- def method_missing(method, *args, &block)
63
- result = @wrapped_string.__send__(method, *args, &block)
62
+ def method_missing(method, ...)
63
+ result = @wrapped_string.__send__(method, ...)
64
64
  if method.end_with?("!")
65
65
  self if result
66
66
  else