activesupport 7.0.8.7 → 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 (171) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +722 -314
  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/duplicable.rb +15 -24
  47. data/lib/active_support/core_ext/object/inclusion.rb +13 -5
  48. data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
  49. data/lib/active_support/core_ext/object/json.rb +10 -2
  50. data/lib/active_support/core_ext/object/with.rb +44 -0
  51. data/lib/active_support/core_ext/object/with_options.rb +3 -3
  52. data/lib/active_support/core_ext/object.rb +1 -0
  53. data/lib/active_support/core_ext/pathname/blank.rb +16 -0
  54. data/lib/active_support/core_ext/pathname/existence.rb +2 -0
  55. data/lib/active_support/core_ext/pathname.rb +1 -0
  56. data/lib/active_support/core_ext/range/conversions.rb +28 -7
  57. data/lib/active_support/core_ext/range/{overlaps.rb → overlap.rb} +5 -3
  58. data/lib/active_support/core_ext/range.rb +1 -2
  59. data/lib/active_support/core_ext/securerandom.rb +24 -12
  60. data/lib/active_support/core_ext/string/filters.rb +20 -14
  61. data/lib/active_support/core_ext/string/inflections.rb +16 -5
  62. data/lib/active_support/core_ext/string/output_safety.rb +38 -174
  63. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  64. data/lib/active_support/core_ext/time/calculations.rb +18 -2
  65. data/lib/active_support/core_ext/time/conversions.rb +2 -2
  66. data/lib/active_support/core_ext/time/zones.rb +4 -4
  67. data/lib/active_support/core_ext/time.rb +0 -1
  68. data/lib/active_support/current_attributes.rb +15 -6
  69. data/lib/active_support/dependencies/autoload.rb +17 -12
  70. data/lib/active_support/deprecation/behaviors.rb +53 -32
  71. data/lib/active_support/deprecation/constant_accessor.rb +5 -4
  72. data/lib/active_support/deprecation/deprecators.rb +104 -0
  73. data/lib/active_support/deprecation/disallowed.rb +3 -5
  74. data/lib/active_support/deprecation/instance_delegator.rb +31 -4
  75. data/lib/active_support/deprecation/method_wrappers.rb +6 -23
  76. data/lib/active_support/deprecation/proxy_wrappers.rb +37 -22
  77. data/lib/active_support/deprecation/reporting.rb +35 -21
  78. data/lib/active_support/deprecation.rb +32 -5
  79. data/lib/active_support/deprecator.rb +7 -0
  80. data/lib/active_support/descendants_tracker.rb +104 -132
  81. data/lib/active_support/duration/iso8601_serializer.rb +0 -2
  82. data/lib/active_support/duration.rb +2 -1
  83. data/lib/active_support/encrypted_configuration.rb +30 -9
  84. data/lib/active_support/encrypted_file.rb +8 -3
  85. data/lib/active_support/environment_inquirer.rb +22 -2
  86. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  87. data/lib/active_support/error_reporter.rb +121 -35
  88. data/lib/active_support/execution_wrapper.rb +4 -4
  89. data/lib/active_support/file_update_checker.rb +4 -2
  90. data/lib/active_support/fork_tracker.rb +10 -2
  91. data/lib/active_support/gem_version.rb +4 -4
  92. data/lib/active_support/gzip.rb +2 -0
  93. data/lib/active_support/hash_with_indifferent_access.rb +35 -17
  94. data/lib/active_support/i18n.rb +1 -1
  95. data/lib/active_support/i18n_railtie.rb +20 -13
  96. data/lib/active_support/inflector/inflections.rb +2 -0
  97. data/lib/active_support/inflector/methods.rb +22 -10
  98. data/lib/active_support/inflector/transliterate.rb +3 -1
  99. data/lib/active_support/isolated_execution_state.rb +26 -22
  100. data/lib/active_support/json/decoding.rb +2 -1
  101. data/lib/active_support/json/encoding.rb +25 -43
  102. data/lib/active_support/key_generator.rb +9 -1
  103. data/lib/active_support/lazy_load_hooks.rb +6 -4
  104. data/lib/active_support/locale/en.yml +2 -0
  105. data/lib/active_support/log_subscriber.rb +78 -33
  106. data/lib/active_support/logger.rb +1 -1
  107. data/lib/active_support/logger_thread_safe_level.rb +9 -21
  108. data/lib/active_support/message_encryptor.rb +197 -53
  109. data/lib/active_support/message_encryptors.rb +140 -0
  110. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  111. data/lib/active_support/message_pack/extensions.rb +292 -0
  112. data/lib/active_support/message_pack/serializer.rb +63 -0
  113. data/lib/active_support/message_pack.rb +50 -0
  114. data/lib/active_support/message_verifier.rb +212 -93
  115. data/lib/active_support/message_verifiers.rb +134 -0
  116. data/lib/active_support/messages/codec.rb +65 -0
  117. data/lib/active_support/messages/metadata.rb +111 -45
  118. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  119. data/lib/active_support/messages/rotator.rb +34 -32
  120. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  121. data/lib/active_support/multibyte/chars.rb +2 -0
  122. data/lib/active_support/multibyte/unicode.rb +9 -37
  123. data/lib/active_support/notifications/fanout.rb +239 -81
  124. data/lib/active_support/notifications/instrumenter.rb +71 -14
  125. data/lib/active_support/notifications.rb +1 -1
  126. data/lib/active_support/number_helper/number_converter.rb +2 -2
  127. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  128. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -0
  129. data/lib/active_support/ordered_hash.rb +3 -3
  130. data/lib/active_support/ordered_options.rb +14 -0
  131. data/lib/active_support/parameter_filter.rb +84 -69
  132. data/lib/active_support/proxy_object.rb +2 -0
  133. data/lib/active_support/railtie.rb +33 -21
  134. data/lib/active_support/reloader.rb +12 -4
  135. data/lib/active_support/rescuable.rb +2 -0
  136. data/lib/active_support/secure_compare_rotator.rb +16 -9
  137. data/lib/active_support/string_inquirer.rb +3 -1
  138. data/lib/active_support/subscriber.rb +9 -27
  139. data/lib/active_support/syntax_error_proxy.rb +49 -0
  140. data/lib/active_support/tagged_logging.rb +60 -24
  141. data/lib/active_support/test_case.rb +153 -6
  142. data/lib/active_support/testing/assertions.rb +25 -9
  143. data/lib/active_support/testing/autorun.rb +0 -2
  144. data/lib/active_support/testing/constant_stubbing.rb +32 -0
  145. data/lib/active_support/testing/deprecation.rb +25 -25
  146. data/lib/active_support/testing/error_reporter_assertions.rb +108 -0
  147. data/lib/active_support/testing/isolation.rb +1 -1
  148. data/lib/active_support/testing/method_call_assertions.rb +21 -8
  149. data/lib/active_support/testing/parallelize_executor.rb +8 -3
  150. data/lib/active_support/testing/stream.rb +1 -1
  151. data/lib/active_support/testing/strict_warnings.rb +38 -0
  152. data/lib/active_support/testing/time_helpers.rb +32 -14
  153. data/lib/active_support/time_with_zone.rb +4 -14
  154. data/lib/active_support/values/time_zone.rb +9 -7
  155. data/lib/active_support/version.rb +1 -1
  156. data/lib/active_support/xml_mini/jdom.rb +3 -10
  157. data/lib/active_support/xml_mini/nokogiri.rb +1 -1
  158. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  159. data/lib/active_support/xml_mini/rexml.rb +1 -1
  160. data/lib/active_support/xml_mini.rb +2 -2
  161. data/lib/active_support.rb +13 -3
  162. metadata +106 -21
  163. data/lib/active_support/core_ext/array/deprecated_conversions.rb +0 -25
  164. data/lib/active_support/core_ext/date/deprecated_conversions.rb +0 -40
  165. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +0 -36
  166. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +0 -60
  167. data/lib/active_support/core_ext/range/deprecated_conversions.rb +0 -36
  168. data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -5
  169. data/lib/active_support/core_ext/time/deprecated_conversions.rb +0 -73
  170. data/lib/active_support/core_ext/uri.rb +0 -5
  171. data/lib/active_support/per_thread_registry.rb +0 -65
@@ -1,9 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveSupport
4
+ # = Active Support \Error Reporter
5
+ #
4
6
  # +ActiveSupport::ErrorReporter+ is a common interface for error reporting services.
5
7
  #
6
- # To rescue and report any unhandled error, you can use the +handle+ method:
8
+ # To rescue and report any unhandled error, you can use the #handle method:
7
9
  #
8
10
  # Rails.error.handle do
9
11
  # do_something!
@@ -11,35 +13,19 @@ module ActiveSupport
11
13
  #
12
14
  # If an error is raised, it will be reported and swallowed.
13
15
  #
14
- # Alternatively if you want to report the error but not swallow it, you can use +record+
16
+ # Alternatively, if you want to report the error but not swallow it, you can use #record:
15
17
  #
16
18
  # Rails.error.record do
17
19
  # do_something!
18
20
  # end
19
21
  #
20
- # Both methods can be restricted to only handle a specific exception class
22
+ # Both methods can be restricted to handle only a specific error class:
21
23
  #
22
24
  # maybe_tags = Rails.error.handle(Redis::BaseError) { redis.get("tags") }
23
25
  #
24
- # You can also pass some extra context information that may be used by the error subscribers:
25
- #
26
- # Rails.error.handle(context: { section: "admin" }) do
27
- # # ...
28
- # end
29
- #
30
- # Additionally a +severity+ can be passed along to communicate how important the error report is.
31
- # +severity+ can be one of +:error+, +:warning+, or +:info+. Handled errors default to the +:warning+
32
- # severity, and unhandled ones to +:error+.
33
- #
34
- # Both +handle+ and +record+ pass through the return value from the block. In the case of +handle+
35
- # rescuing an error, a fallback can be provided. The fallback must be a callable whose result will
36
- # be returned when the block raises and is handled:
37
- #
38
- # user = Rails.error.handle(fallback: -> { User.anonymous }) do
39
- # User.find_by(params)
40
- # end
41
26
  class ErrorReporter
42
27
  SEVERITIES = %i(error warning info)
28
+ DEFAULT_SOURCE = "application"
43
29
 
44
30
  attr_accessor :logger
45
31
 
@@ -48,31 +34,92 @@ module ActiveSupport
48
34
  @logger = logger
49
35
  end
50
36
 
51
- # Report any unhandled exception, and swallow it.
37
+ # Evaluates the given block, reporting and swallowing any unhandled error.
38
+ # If no error is raised, returns the return value of the block. Otherwise,
39
+ # returns the result of +fallback.call+, or +nil+ if +fallback+ is not
40
+ # specified.
52
41
  #
42
+ # # Will report a TypeError to all subscribers and return nil.
53
43
  # Rails.error.handle do
54
44
  # 1 + '1'
55
45
  # end
56
46
  #
57
- def handle(error_class = StandardError, severity: :warning, context: {}, fallback: nil)
47
+ # Can be restricted to handle only specific error classes:
48
+ #
49
+ # maybe_tags = Rails.error.handle(Redis::BaseError) { redis.get("tags") }
50
+ #
51
+ # ==== Options
52
+ #
53
+ # * +:severity+ - This value is passed along to subscribers to indicate how
54
+ # important the error report is. Can be +:error+, +:warning+, or +:info+.
55
+ # Defaults to +:warning+.
56
+ #
57
+ # * +:context+ - Extra information that is passed along to subscribers. For
58
+ # example:
59
+ #
60
+ # Rails.error.handle(context: { section: "admin" }) do
61
+ # # ...
62
+ # end
63
+ #
64
+ # * +:fallback+ - A callable that provides +handle+'s return value when an
65
+ # unhandled error is raised. For example:
66
+ #
67
+ # user = Rails.error.handle(fallback: -> { User.anonymous }) do
68
+ # User.find_by(params)
69
+ # end
70
+ #
71
+ # * +:source+ - This value is passed along to subscribers to indicate the
72
+ # source of the error. Subscribers can use this value to ignore certain
73
+ # errors. Defaults to <tt>"application"</tt>.
74
+ def handle(*error_classes, severity: :warning, context: {}, fallback: nil, source: DEFAULT_SOURCE)
75
+ error_classes = [StandardError] if error_classes.blank?
58
76
  yield
59
- rescue error_class => error
60
- report(error, handled: true, severity: severity, context: context)
77
+ rescue *error_classes => error
78
+ report(error, handled: true, severity: severity, context: context, source: source)
61
79
  fallback.call if fallback
62
80
  end
63
81
 
64
- def record(error_class = StandardError, severity: :error, context: {})
82
+ # Evaluates the given block, reporting and re-raising any unhandled error.
83
+ # If no error is raised, returns the return value of the block.
84
+ #
85
+ # # Will report a TypeError to all subscribers and re-raise it.
86
+ # Rails.error.record do
87
+ # 1 + '1'
88
+ # end
89
+ #
90
+ # Can be restricted to handle only specific error classes:
91
+ #
92
+ # tags = Rails.error.record(Redis::BaseError) { redis.get("tags") }
93
+ #
94
+ # ==== Options
95
+ #
96
+ # * +:severity+ - This value is passed along to subscribers to indicate how
97
+ # important the error report is. Can be +:error+, +:warning+, or +:info+.
98
+ # Defaults to +:error+.
99
+ #
100
+ # * +:context+ - Extra information that is passed along to subscribers. For
101
+ # example:
102
+ #
103
+ # Rails.error.record(context: { section: "admin" }) do
104
+ # # ...
105
+ # end
106
+ #
107
+ # * +:source+ - This value is passed along to subscribers to indicate the
108
+ # source of the error. Subscribers can use this value to ignore certain
109
+ # errors. Defaults to <tt>"application"</tt>.
110
+ def record(*error_classes, severity: :error, context: {}, source: DEFAULT_SOURCE)
111
+ error_classes = [StandardError] if error_classes.blank?
65
112
  yield
66
- rescue error_class => error
67
- report(error, handled: false, severity: severity, context: context)
113
+ rescue *error_classes => error
114
+ report(error, handled: false, severity: severity, context: context, source: source)
68
115
  raise
69
116
  end
70
117
 
71
118
  # Register a new error subscriber. The subscriber must respond to
72
119
  #
73
- # report(Exception, handled: Boolean, context: Hash)
120
+ # report(Exception, handled: Boolean, severity: (:error OR :warning OR :info), context: Hash, source: String)
74
121
  #
75
- # The +report+ method +should+ never raise an error.
122
+ # The +report+ method <b>should never</b> raise an error.
76
123
  def subscribe(subscriber)
77
124
  unless subscriber.respond_to?(:report)
78
125
  raise ArgumentError, "Error subscribers must respond to #report"
@@ -80,26 +127,61 @@ module ActiveSupport
80
127
  @subscribers << subscriber
81
128
  end
82
129
 
83
- # Update the execution context that is accessible to error subscribers
130
+ # Unregister an error subscriber. Accepts either a subscriber or a class.
131
+ #
132
+ # subscriber = MyErrorSubscriber.new
133
+ # Rails.error.subscribe(subscriber)
134
+ #
135
+ # Rails.error.unsubscribe(subscriber)
136
+ # # or
137
+ # Rails.error.unsubscribe(MyErrorSubscriber)
138
+ def unsubscribe(subscriber)
139
+ @subscribers.delete_if { |s| subscriber === s }
140
+ end
141
+
142
+ # Prevent a subscriber from being notified of errors for the
143
+ # duration of the block. You may pass in the subscriber itself, or its class.
144
+ #
145
+ # This can be helpful for error reporting service integrations, when they wish
146
+ # to handle any errors higher in the stack.
147
+ def disable(subscriber)
148
+ disabled_subscribers = (ActiveSupport::IsolatedExecutionState[self] ||= [])
149
+ disabled_subscribers << subscriber
150
+ begin
151
+ yield
152
+ ensure
153
+ disabled_subscribers.delete(subscriber)
154
+ end
155
+ end
156
+
157
+ # Update the execution context that is accessible to error subscribers. Any
158
+ # context passed to #handle, #record, or #report will be merged with the
159
+ # context set here.
84
160
  #
85
161
  # Rails.error.set_context(section: "checkout", user_id: @user.id)
86
162
  #
87
- # See +ActiveSupport::ExecutionContext.set+
88
163
  def set_context(...)
89
164
  ActiveSupport::ExecutionContext.set(...)
90
165
  end
91
166
 
92
- # When the block based +handle+ and +record+ methods are not suitable, you can directly use +report+
167
+ # Report an error directly to subscribers. You can use this method when the
168
+ # block-based #handle and #record methods are not suitable.
169
+ #
170
+ # Rails.error.report(error)
93
171
  #
94
- # Rails.error.report(error, handled: true)
95
- def report(error, handled:, severity: handled ? :warning : :error, context: {})
172
+ def report(error, handled: true, severity: handled ? :warning : :error, context: {}, source: DEFAULT_SOURCE)
173
+ return if error.instance_variable_defined?(:@__rails_error_reported)
174
+
96
175
  unless SEVERITIES.include?(severity)
97
176
  raise ArgumentError, "severity must be one of #{SEVERITIES.map(&:inspect).join(", ")}, got: #{severity.inspect}"
98
177
  end
99
178
 
100
179
  full_context = ActiveSupport::ExecutionContext.to_h.merge(context)
180
+ disabled_subscribers = ActiveSupport::IsolatedExecutionState[self]
101
181
  @subscribers.each do |subscriber|
102
- subscriber.report(error, handled: handled, severity: severity, context: full_context)
182
+ unless disabled_subscribers&.any? { |s| s === subscriber }
183
+ subscriber.report(error, handled: handled, severity: severity, context: full_context, source: source)
184
+ end
103
185
  rescue => subscriber_error
104
186
  if logger
105
187
  logger.fatal(
@@ -111,6 +193,10 @@ module ActiveSupport
111
193
  end
112
194
  end
113
195
 
196
+ unless error.frozen?
197
+ error.instance_variable_set(:@__rails_error_reported, true)
198
+ end
199
+
114
200
  nil
115
201
  end
116
202
  end
@@ -84,14 +84,14 @@ module ActiveSupport
84
84
  end
85
85
 
86
86
  # Perform the work in the supplied block as an execution.
87
- def self.wrap
87
+ def self.wrap(source: "application.active_support")
88
88
  return yield if active?
89
89
 
90
90
  instance = run!
91
91
  begin
92
92
  yield
93
93
  rescue => error
94
- error_reporter.report(error, handled: false)
94
+ error_reporter&.report(error, handled: false, source: source)
95
95
  raise
96
96
  ensure
97
97
  instance.complete!
@@ -108,8 +108,8 @@ module ActiveSupport
108
108
  end
109
109
  end
110
110
 
111
- def self.error_reporter
112
- @error_reporter ||= ActiveSupport::ErrorReporter.new
111
+ def self.error_reporter # :nodoc:
112
+ ActiveSupport.error_reporter
113
113
  end
114
114
 
115
115
  def self.active_key # :nodoc:
@@ -3,7 +3,9 @@
3
3
  require "active_support/core_ext/time/calculations"
4
4
 
5
5
  module ActiveSupport
6
- # FileUpdateChecker specifies the API used by Rails to watch files
6
+ # = \File Update Checker
7
+ #
8
+ # FileUpdateChecker specifies the API used by \Rails to watch files
7
9
  # and control reloading. The API depends on four methods:
8
10
  #
9
11
  # * +initialize+ which expects two parameters and one block as
@@ -20,7 +22,7 @@ module ActiveSupport
20
22
  # After initialization, a call to +execute_if_updated+ must execute
21
23
  # the block only if there was really a change in the filesystem.
22
24
  #
23
- # This class is used by Rails to reload the I18n framework whenever
25
+ # This class is used by \Rails to reload the I18n framework whenever
24
26
  # they are changed upon a new request.
25
27
  #
26
28
  # i18n_reloader = ActiveSupport::FileUpdateChecker.new(paths) do
@@ -6,7 +6,7 @@ module ActiveSupport
6
6
  def _fork
7
7
  pid = super
8
8
  if pid == 0
9
- ForkTracker.check!
9
+ ForkTracker.after_fork_callback
10
10
  end
11
11
  pid
12
12
  end
@@ -37,7 +37,7 @@ module ActiveSupport
37
37
  @callbacks = []
38
38
 
39
39
  class << self
40
- def check!
40
+ def after_fork_callback
41
41
  new_pid = Process.pid
42
42
  if @pid != new_pid
43
43
  @callbacks.each(&:call)
@@ -45,6 +45,14 @@ module ActiveSupport
45
45
  end
46
46
  end
47
47
 
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
+
48
56
  def hook!
49
57
  if Process.respond_to?(:_fork) # Ruby 3.1+
50
58
  ::Process.singleton_class.prepend(ModernCoreExt)
@@ -1,16 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveSupport
4
- # Returns the currently loaded version of Active Support as a <tt>Gem::Version</tt>.
4
+ # Returns the currently loaded version of Active Support as a +Gem::Version+.
5
5
  def self.gem_version
6
6
  Gem::Version.new VERSION::STRING
7
7
  end
8
8
 
9
9
  module VERSION
10
10
  MAJOR = 7
11
- MINOR = 0
12
- TINY = 8
13
- PRE = "7"
11
+ MINOR = 1
12
+ TINY = 0
13
+ PRE = "beta1"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -4,6 +4,8 @@ require "zlib"
4
4
  require "stringio"
5
5
 
6
6
  module ActiveSupport
7
+ # = Active Support \Gzip
8
+ #
7
9
  # A convenient wrapper for the zlib standard library that allows
8
10
  # compression/decompression of strings with gzip.
9
11
  #
@@ -6,6 +6,8 @@ require "active_support/core_ext/hash/except"
6
6
  require "active_support/core_ext/hash/slice"
7
7
 
8
8
  module ActiveSupport
9
+ # = \Hash With Indifferent Access
10
+ #
9
11
  # Implements a hash where keys <tt>:foo</tt> and <tt>"foo"</tt> are considered
10
12
  # to be the same.
11
13
  #
@@ -37,7 +39,7 @@ module ActiveSupport
37
39
  #
38
40
  # but this class is intended for use cases where strings or symbols are the
39
41
  # expected keys and it is convenient to understand both as the same. For
40
- # example the +params+ hash in Ruby on Rails.
42
+ # example the +params+ hash in Ruby on \Rails.
41
43
  #
42
44
  # Note that core extensions define <tt>Hash#with_indifferent_access</tt>:
43
45
  #
@@ -45,7 +47,7 @@ module ActiveSupport
45
47
  #
46
48
  # which may be handy.
47
49
  #
48
- # To access this class outside of Rails, require the core extension with:
50
+ # To access this class outside of \Rails, require the core extension with:
49
51
  #
50
52
  # require "active_support/core_ext/hash/indifferent_access"
51
53
  #
@@ -113,7 +115,7 @@ module ActiveSupport
113
115
  # hash.update({ "a" => 1 }, { "b" => 2 }) # => { "a" => 1, "b" => 2 }
114
116
  #
115
117
  # The arguments can be either an
116
- # <tt>ActiveSupport::HashWithIndifferentAccess</tt> or a regular +Hash+.
118
+ # +ActiveSupport::HashWithIndifferentAccess+ or a regular +Hash+.
117
119
  # In either case the merge respects the semantics of indifferent access.
118
120
  #
119
121
  # If the argument is a regular hash with keys +:key+ and <tt>"key"</tt> only one
@@ -218,8 +220,12 @@ module ActiveSupport
218
220
  # hash.default # => nil
219
221
  # hash.default('foo') # => 'foo'
220
222
  # hash.default(:foo) # => 'foo'
221
- def default(*args)
222
- super(*args.map { |arg| convert_key(arg) })
223
+ def default(key = (no_key = true))
224
+ if no_key
225
+ super()
226
+ else
227
+ super(convert_key(key))
228
+ end
223
229
  end
224
230
 
225
231
  # Returns an array of the values at the specified indices:
@@ -229,7 +235,8 @@ module ActiveSupport
229
235
  # hash[:b] = 'y'
230
236
  # hash.values_at('a', 'b') # => ["x", "y"]
231
237
  def values_at(*keys)
232
- super(*keys.map { |key| convert_key(key) })
238
+ keys.map! { |key| convert_key(key) }
239
+ super
233
240
  end
234
241
 
235
242
  # Returns an array of the values at the specified indices, but also
@@ -242,7 +249,8 @@ module ActiveSupport
242
249
  # hash.fetch_values('a', 'c') { |key| 'z' } # => ["x", "z"]
243
250
  # hash.fetch_values('a', 'c') # => KeyError: key not found: "c"
244
251
  def fetch_values(*indices, &block)
245
- super(*indices.map { |key| convert_key(key) }, &block)
252
+ indices.map! { |key| convert_key(key) }
253
+ super
246
254
  end
247
255
 
248
256
  # Returns a shallow copy of the hash.
@@ -301,7 +309,7 @@ module ActiveSupport
301
309
  # hash.except(:a, "b") # => {c: 10}.with_indifferent_access
302
310
  # hash # => { a: "x", b: "y", c: 10 }.with_indifferent_access
303
311
  def except(*keys)
304
- slice(*self.keys - keys.map { |key| convert_key(key) })
312
+ dup.except!(*keys)
305
313
  end
306
314
  alias_method :without, :except
307
315
 
@@ -326,21 +334,31 @@ module ActiveSupport
326
334
  dup.tap { |hash| hash.reject!(*args, &block) }
327
335
  end
328
336
 
329
- def transform_values(*args, &block)
337
+ def transform_values(&block)
330
338
  return to_enum(:transform_values) unless block_given?
331
- dup.tap { |hash| hash.transform_values!(*args, &block) }
339
+ dup.tap { |hash| hash.transform_values!(&block) }
332
340
  end
333
341
 
334
- def transform_keys(*args, &block)
335
- return to_enum(:transform_keys) unless block_given?
336
- dup.tap { |hash| hash.transform_keys!(*args, &block) }
342
+ NOT_GIVEN = Object.new # :nodoc:
343
+
344
+ def transform_keys(hash = NOT_GIVEN, &block)
345
+ return to_enum(:transform_keys) if NOT_GIVEN.equal?(hash) && !block_given?
346
+ dup.tap { |h| h.transform_keys!(hash, &block) }
337
347
  end
338
348
 
339
- def transform_keys!
340
- return enum_for(:transform_keys!) { size } unless block_given?
341
- keys.each do |key|
342
- self[yield(key)] = delete(key)
349
+ def transform_keys!(hash = NOT_GIVEN, &block)
350
+ return to_enum(:transform_keys!) if NOT_GIVEN.equal?(hash) && !block_given?
351
+
352
+ if hash.nil?
353
+ super
354
+ elsif NOT_GIVEN.equal?(hash)
355
+ keys.each { |key| self[yield(key)] = delete(key) }
356
+ elsif block_given?
357
+ keys.each { |key| self[hash[key] || yield(key)] = delete(key) }
358
+ else
359
+ keys.each { |key| self[hash[key] || key] = delete(key) }
343
360
  end
361
+
344
362
  self
345
363
  end
346
364
 
@@ -7,7 +7,7 @@ begin
7
7
  require "i18n"
8
8
  require "i18n/backend/fallbacks"
9
9
  rescue LoadError => e
10
- $stderr.puts "The i18n gem is not available. Please add it to your Gemfile and run bundle install"
10
+ warn "The i18n gem is not available. Please add it to your Gemfile and run bundle install"
11
11
  raise e
12
12
  end
13
13
  require "active_support/lazy_load_hooks"
@@ -49,7 +49,7 @@ module I18n
49
49
  when :load_path
50
50
  I18n.load_path += value
51
51
  when :raise_on_missing_translations
52
- forward_raise_on_missing_translations_config(app)
52
+ setup_raise_on_missing_translations_config(app)
53
53
  else
54
54
  I18n.public_send("#{setting}=", value)
55
55
  end
@@ -60,28 +60,35 @@ module I18n
60
60
  # Restore available locales check so it will take place from now on.
61
61
  I18n.enforce_available_locales = enforce_available_locales
62
62
 
63
- directories = watched_dirs_with_extensions(reloadable_paths)
64
- reloader = app.config.file_watcher.new(I18n.load_path.dup, directories) do
65
- I18n.load_path.keep_if { |p| File.exist?(p) }
66
- I18n.load_path |= reloadable_paths.flat_map(&:existent)
67
- end
63
+ if app.config.reloading_enabled?
64
+ directories = watched_dirs_with_extensions(reloadable_paths)
65
+ reloader = app.config.file_watcher.new(I18n.load_path.dup, directories) do
66
+ I18n.load_path.keep_if { |p| File.exist?(p) }
67
+ I18n.load_path |= reloadable_paths.flat_map(&:existent)
68
+ end
68
69
 
69
- app.reloaders << reloader
70
- app.reloader.to_run do
71
- reloader.execute_if_updated { require_unload_lock! }
70
+ app.reloaders << reloader
71
+ app.reloader.to_run do
72
+ reloader.execute_if_updated { require_unload_lock! }
73
+ end
74
+ reloader.execute
72
75
  end
73
- reloader.execute
74
76
 
75
77
  @i18n_inited = true
76
78
  end
77
79
 
78
- def self.forward_raise_on_missing_translations_config(app)
80
+ def self.setup_raise_on_missing_translations_config(app)
79
81
  ActiveSupport.on_load(:action_view) do
80
82
  ActionView::Helpers::TranslationHelper.raise_on_missing_translations = app.config.i18n.raise_on_missing_translations
81
83
  end
82
84
 
83
- ActiveSupport.on_load(:action_controller) do
84
- AbstractController::Translation.raise_on_missing_translations = app.config.i18n.raise_on_missing_translations
85
+ if app.config.i18n.raise_on_missing_translations &&
86
+ I18n.exception_handler.is_a?(I18n::ExceptionHandler) # Only override the i18n gem's default exception handler.
87
+
88
+ I18n.exception_handler = ->(exception, *) {
89
+ exception = exception.to_exception if exception.is_a?(I18n::MissingTranslation)
90
+ raise exception
91
+ }
85
92
  end
86
93
  end
87
94
 
@@ -7,6 +7,8 @@ module ActiveSupport
7
7
  module Inflector
8
8
  extend self
9
9
 
10
+ # = Active Support \Inflections
11
+ #
10
12
  # A singleton instance of this class is yielded by Inflector.inflections,
11
13
  # which can then be used to specify additional inflection rules. If passed
12
14
  # an optional locale, rules for other languages can be specified. The
@@ -1,15 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/inflections"
4
- require "active_support/core_ext/object/blank"
5
4
 
6
5
  module ActiveSupport
6
+ # = Active Support \Inflector
7
+ #
7
8
  # The Inflector transforms words from singular to plural, class names to table
8
9
  # names, modularized class names to ones without, and class names to foreign
9
10
  # keys. The default inflections for pluralization, singularization, and
10
11
  # uncountable words are kept in inflections.rb.
11
12
  #
12
- # The Rails core team has stated patches for the inflections library will not
13
+ # The \Rails core team has stated patches for the inflections library will not
13
14
  # be accepted in order to avoid breaking legacy applications which may be
14
15
  # relying on errant inflections. If you discover an incorrect inflection and
15
16
  # require it for your application or wish to define rules for languages other
@@ -71,6 +72,8 @@ module ActiveSupport
71
72
  # String#camelize takes a symbol (:upper or :lower), so here we also support :lower to keep the methods consistent.
72
73
  if !uppercase_first_letter || uppercase_first_letter == :lower
73
74
  string = string.sub(inflections.acronyms_camelize_regex) { |match| match.downcase! || match }
75
+ elsif string.match?(/\A[a-z\d]*\z/)
76
+ return inflections.acronyms[string]&.dup || string.capitalize
74
77
  else
75
78
  string = string.sub(/^[a-z\d]*/) { |match| inflections.acronyms[match] || match.capitalize! || match }
76
79
  end
@@ -94,10 +97,10 @@ module ActiveSupport
94
97
  #
95
98
  # camelize(underscore('SSLError')) # => "SslError"
96
99
  def underscore(camel_cased_word)
97
- return camel_cased_word.to_s unless /[A-Z-]|::/.match?(camel_cased_word)
100
+ return camel_cased_word.to_s.dup unless /[A-Z-]|::/.match?(camel_cased_word)
98
101
  word = camel_cased_word.to_s.gsub("::", "/")
99
102
  word.gsub!(inflections.acronyms_underscore_regex) { "#{$1 && '_' }#{$2.downcase}" }
100
- word.gsub!(/([A-Z])(?=[A-Z][a-z])|([a-z\d])(?=[A-Z])/) { ($1 || $2) << "_" }
103
+ word.gsub!(/(?<=[A-Z])(?=[A-Z][a-z])|(?<=[a-z\d])(?=[A-Z])/, "_")
101
104
  word.tr!("-", "_")
102
105
  word.downcase!
103
106
  word
@@ -155,7 +158,7 @@ module ActiveSupport
155
158
  result
156
159
  end
157
160
 
158
- # Converts just the first character to uppercase.
161
+ # Converts the first character in the string to uppercase.
159
162
  #
160
163
  # upcase_first('what a Lovely Day') # => "What a Lovely Day"
161
164
  # upcase_first('w') # => "W"
@@ -164,9 +167,18 @@ module ActiveSupport
164
167
  string.length > 0 ? string[0].upcase.concat(string[1..-1]) : ""
165
168
  end
166
169
 
170
+ # Converts the first character in the string to lowercase.
171
+ #
172
+ # downcase_first('If they enjoyed The Matrix') # => "if they enjoyed The Matrix"
173
+ # downcase_first('I') # => "i"
174
+ # downcase_first('') # => ""
175
+ def downcase_first(string)
176
+ string.length > 0 ? string[0].downcase.concat(string[1..-1]) : ""
177
+ end
178
+
167
179
  # Capitalizes all the words and replaces some characters in the string to
168
180
  # create a nicer looking title. +titleize+ is meant for creating pretty
169
- # output. It is not used in the Rails internals.
181
+ # output. It is not used in the \Rails internals.
170
182
  #
171
183
  # The trailing '_id','Id'.. can be kept and capitalized by setting the
172
184
  # optional parameter +keep_id_suffix+ to true.
@@ -183,7 +195,7 @@ module ActiveSupport
183
195
  end
184
196
  end
185
197
 
186
- # Creates the name of a table like Rails does for models to table names.
198
+ # Creates the name of a table like \Rails does for models to table names.
187
199
  # This method uses the #pluralize method on the last word in the string.
188
200
  #
189
201
  # tableize('RawScaledScorer') # => "raw_scaled_scorers"
@@ -193,7 +205,7 @@ module ActiveSupport
193
205
  pluralize(underscore(class_name))
194
206
  end
195
207
 
196
- # Creates a class name from a plural table name like Rails does for table
208
+ # Creates a class name from a plural table name like \Rails does for table
197
209
  # names to models. Note that this returns a string and not a Class. (To
198
210
  # convert to an actual class follow +classify+ with #constantize.)
199
211
  #
@@ -226,7 +238,7 @@ module ActiveSupport
226
238
  def demodulize(path)
227
239
  path = path.to_s
228
240
  if i = path.rindex("::")
229
- path[(i + 2)..-1]
241
+ path[(i + 2), path.length]
230
242
  else
231
243
  path
232
244
  end
@@ -345,7 +357,7 @@ module ActiveSupport
345
357
  def const_regexp(camel_cased_word)
346
358
  parts = camel_cased_word.split("::")
347
359
 
348
- return Regexp.escape(camel_cased_word) if parts.blank?
360
+ return Regexp.escape(camel_cased_word) if parts.empty?
349
361
 
350
362
  last = parts.pop
351
363
 
@@ -62,10 +62,12 @@ module ActiveSupport
62
62
  # Transliteration is restricted to UTF-8, US-ASCII, and GB18030 strings.
63
63
  # Other encodings will raise an ArgumentError.
64
64
  def transliterate(string, replacement = "?", locale: nil)
65
- string = string.dup if string.frozen?
66
65
  raise ArgumentError, "Can only transliterate strings. Received #{string.class.name}" unless string.is_a?(String)
67
66
  raise ArgumentError, "Cannot transliterate strings with #{string.encoding} encoding" unless ALLOWED_ENCODINGS_FOR_TRANSLITERATE.include?(string.encoding)
68
67
 
68
+ return string.dup if string.ascii_only?
69
+ string = string.dup if string.frozen?
70
+
69
71
  input_encoding = string.encoding
70
72
 
71
73
  # US-ASCII is a subset of UTF-8 so we'll force encoding as UTF-8 if