activesupport 7.0.3.1 → 7.2.3.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 (210) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +261 -246
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +7 -7
  5. data/lib/active_support/actionable_error.rb +3 -1
  6. data/lib/active_support/array_inquirer.rb +3 -1
  7. data/lib/active_support/backtrace_cleaner.rb +39 -7
  8. data/lib/active_support/benchmarkable.rb +1 -0
  9. data/lib/active_support/broadcast_logger.rb +238 -0
  10. data/lib/active_support/builder.rb +1 -1
  11. data/lib/active_support/cache/coder.rb +153 -0
  12. data/lib/active_support/cache/entry.rb +134 -0
  13. data/lib/active_support/cache/file_store.rb +51 -19
  14. data/lib/active_support/cache/mem_cache_store.rb +114 -134
  15. data/lib/active_support/cache/memory_store.rb +85 -30
  16. data/lib/active_support/cache/null_store.rb +8 -2
  17. data/lib/active_support/cache/redis_cache_store.rb +175 -154
  18. data/lib/active_support/cache/serializer_with_fallback.rb +152 -0
  19. data/lib/active_support/cache/strategy/local_cache.rb +64 -13
  20. data/lib/active_support/cache.rb +455 -378
  21. data/lib/active_support/callbacks.rb +121 -136
  22. data/lib/active_support/code_generator.rb +15 -10
  23. data/lib/active_support/concern.rb +4 -2
  24. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +42 -3
  25. data/lib/active_support/concurrency/null_lock.rb +13 -0
  26. data/lib/active_support/configurable.rb +10 -0
  27. data/lib/active_support/core_ext/array/conversions.rb +1 -2
  28. data/lib/active_support/core_ext/array.rb +0 -1
  29. data/lib/active_support/core_ext/benchmark.rb +1 -0
  30. data/lib/active_support/core_ext/class/attribute.rb +2 -2
  31. data/lib/active_support/core_ext/class/subclasses.rb +17 -34
  32. data/lib/active_support/core_ext/date/blank.rb +4 -0
  33. data/lib/active_support/core_ext/date/calculations.rb +15 -0
  34. data/lib/active_support/core_ext/date/conversions.rb +1 -2
  35. data/lib/active_support/core_ext/date.rb +0 -1
  36. data/lib/active_support/core_ext/date_and_time/calculations.rb +10 -0
  37. data/lib/active_support/core_ext/date_and_time/compatibility.rb +28 -1
  38. data/lib/active_support/core_ext/date_time/blank.rb +4 -0
  39. data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
  40. data/lib/active_support/core_ext/date_time/conversions.rb +6 -4
  41. data/lib/active_support/core_ext/date_time.rb +0 -1
  42. data/lib/active_support/core_ext/digest/uuid.rb +7 -10
  43. data/lib/active_support/core_ext/enumerable.rb +25 -80
  44. data/lib/active_support/core_ext/erb/util.rb +201 -0
  45. data/lib/active_support/core_ext/hash/conversions.rb +1 -1
  46. data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
  47. data/lib/active_support/core_ext/hash/deep_transform_values.rb +3 -3
  48. data/lib/active_support/core_ext/hash/keys.rb +7 -7
  49. data/lib/active_support/core_ext/integer/inflections.rb +12 -12
  50. data/lib/active_support/core_ext/module/attr_internal.rb +17 -6
  51. data/lib/active_support/core_ext/module/attribute_accessors.rb +6 -0
  52. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +34 -16
  53. data/lib/active_support/core_ext/module/concerning.rb +6 -6
  54. data/lib/active_support/core_ext/module/delegation.rb +20 -119
  55. data/lib/active_support/core_ext/module/deprecation.rb +12 -12
  56. data/lib/active_support/core_ext/module/introspection.rb +3 -1
  57. data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
  58. data/lib/active_support/core_ext/numeric/conversions.rb +5 -3
  59. data/lib/active_support/core_ext/numeric.rb +0 -1
  60. data/lib/active_support/core_ext/object/blank.rb +45 -1
  61. data/lib/active_support/core_ext/object/deep_dup.rb +16 -0
  62. data/lib/active_support/core_ext/object/duplicable.rb +25 -16
  63. data/lib/active_support/core_ext/object/inclusion.rb +13 -5
  64. data/lib/active_support/core_ext/object/instance_variables.rb +4 -2
  65. data/lib/active_support/core_ext/object/json.rb +17 -7
  66. data/lib/active_support/core_ext/object/to_query.rb +0 -2
  67. data/lib/active_support/core_ext/object/try.rb +2 -2
  68. data/lib/active_support/core_ext/object/with.rb +46 -0
  69. data/lib/active_support/core_ext/object/with_options.rb +9 -9
  70. data/lib/active_support/core_ext/object.rb +1 -0
  71. data/lib/active_support/core_ext/pathname/blank.rb +20 -0
  72. data/lib/active_support/core_ext/pathname/existence.rb +2 -0
  73. data/lib/active_support/core_ext/pathname.rb +1 -0
  74. data/lib/active_support/core_ext/range/conversions.rb +28 -7
  75. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  76. data/lib/active_support/core_ext/range/sole.rb +17 -0
  77. data/lib/active_support/core_ext/range.rb +2 -2
  78. data/lib/active_support/core_ext/securerandom.rb +24 -12
  79. data/lib/active_support/core_ext/string/conversions.rb +1 -1
  80. data/lib/active_support/core_ext/string/filters.rb +24 -18
  81. data/lib/active_support/core_ext/string/indent.rb +1 -1
  82. data/lib/active_support/core_ext/string/inflections.rb +16 -9
  83. data/lib/active_support/core_ext/string/multibyte.rb +3 -3
  84. data/lib/active_support/core_ext/string/output_safety.rb +41 -178
  85. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  86. data/lib/active_support/core_ext/time/calculations.rb +40 -30
  87. data/lib/active_support/core_ext/time/compatibility.rb +24 -0
  88. data/lib/active_support/core_ext/time/conversions.rb +1 -3
  89. data/lib/active_support/core_ext/time/zones.rb +7 -8
  90. data/lib/active_support/core_ext/time.rb +0 -1
  91. data/lib/active_support/core_ext.rb +0 -1
  92. data/lib/active_support/current_attributes.rb +60 -46
  93. data/lib/active_support/deep_mergeable.rb +53 -0
  94. data/lib/active_support/delegation.rb +202 -0
  95. data/lib/active_support/dependencies/autoload.rb +9 -16
  96. data/lib/active_support/deprecation/behaviors.rb +64 -41
  97. data/lib/active_support/deprecation/constant_accessor.rb +47 -25
  98. data/lib/active_support/deprecation/deprecators.rb +104 -0
  99. data/lib/active_support/deprecation/disallowed.rb +6 -8
  100. data/lib/active_support/deprecation/method_wrappers.rb +6 -23
  101. data/lib/active_support/deprecation/proxy_wrappers.rb +34 -22
  102. data/lib/active_support/deprecation/reporting.rb +49 -27
  103. data/lib/active_support/deprecation.rb +39 -9
  104. data/lib/active_support/deprecator.rb +7 -0
  105. data/lib/active_support/descendants_tracker.rb +66 -172
  106. data/lib/active_support/duration/iso8601_parser.rb +2 -2
  107. data/lib/active_support/duration/iso8601_serializer.rb +1 -4
  108. data/lib/active_support/duration.rb +13 -7
  109. data/lib/active_support/encrypted_configuration.rb +63 -11
  110. data/lib/active_support/encrypted_file.rb +29 -13
  111. data/lib/active_support/environment_inquirer.rb +22 -2
  112. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  113. data/lib/active_support/error_reporter.rb +163 -36
  114. data/lib/active_support/evented_file_update_checker.rb +17 -3
  115. data/lib/active_support/execution_wrapper.rb +5 -6
  116. data/lib/active_support/file_update_checker.rb +6 -4
  117. data/lib/active_support/fork_tracker.rb +4 -32
  118. data/lib/active_support/gem_version.rb +2 -2
  119. data/lib/active_support/gzip.rb +2 -0
  120. data/lib/active_support/hash_with_indifferent_access.rb +50 -30
  121. data/lib/active_support/html_safe_translation.rb +19 -6
  122. data/lib/active_support/i18n.rb +1 -1
  123. data/lib/active_support/i18n_railtie.rb +20 -13
  124. data/lib/active_support/inflector/inflections.rb +2 -0
  125. data/lib/active_support/inflector/methods.rb +28 -18
  126. data/lib/active_support/inflector/transliterate.rb +3 -1
  127. data/lib/active_support/isolated_execution_state.rb +26 -22
  128. data/lib/active_support/json/decoding.rb +3 -2
  129. data/lib/active_support/json/encoding.rb +48 -48
  130. data/lib/active_support/key_generator.rb +9 -1
  131. data/lib/active_support/lazy_load_hooks.rb +22 -7
  132. data/lib/active_support/locale/en.yml +2 -0
  133. data/lib/active_support/log_subscriber.rb +74 -34
  134. data/lib/active_support/logger.rb +22 -59
  135. data/lib/active_support/logger_thread_safe_level.rb +10 -32
  136. data/lib/active_support/message_encryptor.rb +197 -53
  137. data/lib/active_support/message_encryptors.rb +141 -0
  138. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  139. data/lib/active_support/message_pack/extensions.rb +305 -0
  140. data/lib/active_support/message_pack/serializer.rb +63 -0
  141. data/lib/active_support/message_pack.rb +50 -0
  142. data/lib/active_support/message_verifier.rb +229 -89
  143. data/lib/active_support/message_verifiers.rb +137 -0
  144. data/lib/active_support/messages/codec.rb +65 -0
  145. data/lib/active_support/messages/metadata.rb +111 -45
  146. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  147. data/lib/active_support/messages/rotator.rb +38 -31
  148. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  149. data/lib/active_support/multibyte/chars.rb +8 -3
  150. data/lib/active_support/multibyte/unicode.rb +9 -37
  151. data/lib/active_support/notifications/fanout.rb +248 -87
  152. data/lib/active_support/notifications/instrumenter.rb +93 -25
  153. data/lib/active_support/notifications.rb +36 -29
  154. data/lib/active_support/number_helper/number_converter.rb +16 -7
  155. data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -6
  156. data/lib/active_support/number_helper/number_to_delimited_converter.rb +17 -2
  157. data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -3
  158. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -0
  159. data/lib/active_support/number_helper.rb +379 -317
  160. data/lib/active_support/option_merger.rb +4 -4
  161. data/lib/active_support/ordered_hash.rb +3 -3
  162. data/lib/active_support/ordered_options.rb +67 -15
  163. data/lib/active_support/parameter_filter.rb +103 -84
  164. data/lib/active_support/proxy_object.rb +8 -3
  165. data/lib/active_support/railtie.rb +25 -20
  166. data/lib/active_support/reloader.rb +12 -4
  167. data/lib/active_support/rescuable.rb +10 -8
  168. data/lib/active_support/secure_compare_rotator.rb +16 -9
  169. data/lib/active_support/string_inquirer.rb +4 -2
  170. data/lib/active_support/subscriber.rb +10 -27
  171. data/lib/active_support/syntax_error_proxy.rb +60 -0
  172. data/lib/active_support/tagged_logging.rb +64 -40
  173. data/lib/active_support/test_case.rb +160 -7
  174. data/lib/active_support/testing/assertions.rb +28 -12
  175. data/lib/active_support/testing/autorun.rb +0 -2
  176. data/lib/active_support/testing/constant_stubbing.rb +54 -0
  177. data/lib/active_support/testing/deprecation.rb +20 -27
  178. data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
  179. data/lib/active_support/testing/isolation.rb +46 -33
  180. data/lib/active_support/testing/method_call_assertions.rb +7 -8
  181. data/lib/active_support/testing/parallelization/server.rb +18 -2
  182. data/lib/active_support/testing/parallelization/worker.rb +2 -2
  183. data/lib/active_support/testing/parallelization.rb +12 -1
  184. data/lib/active_support/testing/parallelize_executor.rb +8 -3
  185. data/lib/active_support/testing/setup_and_teardown.rb +2 -0
  186. data/lib/active_support/testing/stream.rb +1 -1
  187. data/lib/active_support/testing/tests_without_assertions.rb +19 -0
  188. data/lib/active_support/testing/time_helpers.rb +38 -16
  189. data/lib/active_support/time_with_zone.rb +18 -44
  190. data/lib/active_support/values/time_zone.rb +25 -14
  191. data/lib/active_support/version.rb +1 -1
  192. data/lib/active_support/xml_mini/jdom.rb +3 -10
  193. data/lib/active_support/xml_mini/nokogiri.rb +1 -1
  194. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  195. data/lib/active_support/xml_mini/rexml.rb +1 -1
  196. data/lib/active_support/xml_mini.rb +14 -3
  197. data/lib/active_support.rb +15 -3
  198. metadata +148 -24
  199. data/lib/active_support/core_ext/array/deprecated_conversions.rb +0 -25
  200. data/lib/active_support/core_ext/date/deprecated_conversions.rb +0 -26
  201. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +0 -22
  202. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +0 -60
  203. data/lib/active_support/core_ext/range/deprecated_conversions.rb +0 -26
  204. data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -7
  205. data/lib/active_support/core_ext/range/overlaps.rb +0 -10
  206. data/lib/active_support/core_ext/time/deprecated_conversions.rb +0 -22
  207. data/lib/active_support/core_ext/uri.rb +0 -5
  208. data/lib/active_support/deprecation/instance_delegator.rb +0 -38
  209. data/lib/active_support/per_thread_registry.rb +0 -65
  210. data/lib/active_support/ruby_features.rb +0 -7
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveSupport
4
+ # = \String Inquirer
5
+ #
4
6
  # Wrapping a string in this class gives you a prettier way to test
5
7
  # for equality. The value returned by <tt>Rails.env</tt> is wrapped
6
8
  # in a StringInquirer object, so instead of calling this:
@@ -11,7 +13,7 @@ module ActiveSupport
11
13
  #
12
14
  # Rails.env.production?
13
15
  #
14
- # == Instantiating a new StringInquirer
16
+ # == Instantiating a new \StringInquirer
15
17
  #
16
18
  # vehicle = ActiveSupport::StringInquirer.new('car')
17
19
  # vehicle.car? # => true
@@ -22,7 +24,7 @@ module ActiveSupport
22
24
  method_name.end_with?("?") || super
23
25
  end
24
26
 
25
- def method_missing(method_name, *arguments)
27
+ def method_missing(method_name, ...)
26
28
  if method_name.end_with?("?")
27
29
  self == method_name[0..-2]
28
30
  else
@@ -3,7 +3,9 @@
3
3
  require "active_support/notifications"
4
4
 
5
5
  module ActiveSupport
6
- # ActiveSupport::Subscriber is an object set to consume
6
+ # = Active Support \Subscriber
7
+ #
8
+ # +ActiveSupport::Subscriber+ is an object set to consume
7
9
  # ActiveSupport::Notifications. The subscriber dispatches notifications to
8
10
  # a registered object based on its given namespace.
9
11
  #
@@ -20,9 +22,9 @@ module ActiveSupport
20
22
  # end
21
23
  # end
22
24
  #
23
- # After configured, whenever a "sql.active_record" notification is published,
24
- # it will properly dispatch the event (ActiveSupport::Notifications::Event) to
25
- # the +sql+ method.
25
+ # After configured, whenever a <tt>"sql.active_record"</tt> notification is
26
+ # published, it will properly dispatch the event
27
+ # (ActiveSupport::Notifications::Event) to the +sql+ method.
26
28
  #
27
29
  # We can detach a subscriber as well:
28
30
  #
@@ -65,6 +67,7 @@ module ActiveSupport
65
67
 
66
68
  # Adds event subscribers for all new methods added to the class.
67
69
  def method_added(event)
70
+ super
68
71
  # Only public methods are added as subscribers, and only if a notifier
69
72
  # has been set up. This means that subscribers will only be set up for
70
73
  # classes that call #attach_to.
@@ -126,38 +129,18 @@ module ActiveSupport
126
129
  attr_reader :patterns # :nodoc:
127
130
 
128
131
  def initialize
129
- @queue_key = [self.class.name, object_id].join "-"
130
132
  @patterns = {}
131
133
  super
132
134
  end
133
135
 
134
- def start(name, id, payload)
135
- event = ActiveSupport::Notifications::Event.new(name, nil, nil, id, payload)
136
- event.start!
137
- parent = event_stack.last
138
- parent << event if parent
139
-
140
- event_stack.push event
141
- end
142
-
143
- def finish(name, id, payload)
144
- event = event_stack.pop
145
- event.finish!
146
- event.payload.merge!(payload)
147
-
148
- method = name.split(".").first
136
+ def call(event)
137
+ method = event.name[0, event.name.index(".")]
149
138
  send(method, event)
150
139
  end
151
140
 
152
141
  def publish_event(event) # :nodoc:
153
- method = event.name.split(".").first
142
+ method = event.name[0, event.name.index(".")]
154
143
  send(method, event)
155
144
  end
156
-
157
- private
158
- def event_stack
159
- registry = ActiveSupport::IsolatedExecutionState[:active_support_subscriber_queue_registry] ||= {}
160
- registry[@queue_key] ||= []
161
- end
162
145
  end
163
146
  end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "delegate"
4
+
5
+ module ActiveSupport
6
+ # This is a class for wrapping syntax errors. The purpose of this class
7
+ # is to enhance the backtraces on SyntaxError exceptions to include the
8
+ # source location of the syntax error. That way we can display the error
9
+ # source on error pages in development.
10
+ class SyntaxErrorProxy < DelegateClass(SyntaxError) # :nodoc:
11
+ def backtrace
12
+ parse_message_for_trace + super
13
+ end
14
+
15
+ class BacktraceLocation < Struct.new(:path, :lineno, :to_s) # :nodoc:
16
+ def spot(_)
17
+ end
18
+
19
+ def label
20
+ end
21
+ end
22
+
23
+ class BacktraceLocationProxy < DelegateClass(Thread::Backtrace::Location) # :nodoc:
24
+ def initialize(loc, ex)
25
+ super(loc)
26
+ @ex = ex
27
+ end
28
+
29
+ def spot(_)
30
+ super(@ex.__getobj__)
31
+ end
32
+ end
33
+
34
+ def backtrace_locations
35
+ return nil if super.nil?
36
+
37
+ parse_message_for_trace.map { |trace|
38
+ file, line = trace.match(/^(.+?):(\d+).*$/, &:captures) || trace
39
+ BacktraceLocation.new(file, line.to_i, trace)
40
+ # We have to wrap these backtrace locations because we need the
41
+ # spot information to come from the originating exception, not the
42
+ # proxy object that's generating these
43
+ } + super.map { |loc| BacktraceLocationProxy.new(loc, self) }
44
+ end
45
+
46
+ private
47
+ def parse_message_for_trace
48
+ if __getobj__.to_s.start_with?("(eval")
49
+ # If the exception is coming from a call to eval, we need to keep
50
+ # the path of the file in which eval was called to ensure we can
51
+ # return the right source fragment to show the location of the
52
+ # error
53
+ location = __getobj__.backtrace_locations[0]
54
+ ["#{location.path}:#{location.lineno}: #{__getobj__}"]
55
+ else
56
+ __getobj__.to_s.split("\n")
57
+ end
58
+ end
59
+ end
60
+ end
@@ -1,20 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/module/delegation"
4
- require "active_support/core_ext/module/redefine_method"
5
4
  require "active_support/core_ext/object/blank"
6
- require "logger"
7
5
  require "active_support/logger"
8
6
 
9
7
  module ActiveSupport
8
+ # = Active Support Tagged Logging
9
+ #
10
10
  # Wraps any standard Logger object to provide tagging capabilities.
11
11
  #
12
12
  # May be called with a block:
13
13
  #
14
14
  # logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
15
- # logger.tagged('BCX') { logger.info 'Stuff' } # Logs "[BCX] Stuff"
16
- # logger.tagged('BCX', "Jason") { logger.info 'Stuff' } # Logs "[BCX] [Jason] Stuff"
17
- # logger.tagged('BCX') { logger.tagged('Jason') { logger.info 'Stuff' } } # Logs "[BCX] [Jason] Stuff"
15
+ # logger.tagged('BCX') { logger.info 'Stuff' } # Logs "[BCX] Stuff"
16
+ # logger.tagged('BCX', "Jason") { |tagged_logger| tagged_logger.info 'Stuff' } # Logs "[BCX] [Jason] Stuff"
17
+ # logger.tagged('BCX') { logger.tagged('Jason') { logger.info 'Stuff' } } # Logs "[BCX] [Jason] Stuff"
18
18
  #
19
19
  # If called without a block, a new logger will be returned with applied tags:
20
20
  #
@@ -30,52 +30,86 @@ module ActiveSupport
30
30
  module Formatter # :nodoc:
31
31
  # This method is invoked when a log event occurs.
32
32
  def call(severity, timestamp, progname, msg)
33
- super(severity, timestamp, progname, "#{tags_text}#{msg}")
33
+ super(severity, timestamp, progname, tag_stack.format_message(msg))
34
34
  end
35
35
 
36
36
  def tagged(*tags)
37
- new_tags = push_tags(*tags)
37
+ pushed_count = tag_stack.push_tags(tags).size
38
38
  yield self
39
39
  ensure
40
- pop_tags(new_tags.size)
40
+ pop_tags(pushed_count)
41
41
  end
42
42
 
43
43
  def push_tags(*tags)
44
- tags.flatten!
45
- tags.reject!(&:blank?)
46
- current_tags.concat tags
47
- tags
44
+ tag_stack.push_tags(tags)
48
45
  end
49
46
 
50
- def pop_tags(size = 1)
51
- current_tags.pop size
47
+ def pop_tags(count = 1)
48
+ tag_stack.pop_tags(count)
52
49
  end
53
50
 
54
51
  def clear_tags!
55
- current_tags.clear
52
+ tag_stack.clear
56
53
  end
57
54
 
58
- def current_tags
55
+ def tag_stack
59
56
  # We use our object ID here to avoid conflicting with other instances
60
- thread_key = @thread_key ||= "activesupport_tagged_logging_tags:#{object_id}"
61
- IsolatedExecutionState[thread_key] ||= []
57
+ @thread_key ||= "activesupport_tagged_logging_tags:#{object_id}"
58
+ IsolatedExecutionState[@thread_key] ||= TagStack.new
59
+ end
60
+
61
+ def current_tags
62
+ tag_stack.tags
62
63
  end
63
64
 
64
65
  def tags_text
65
- tags = current_tags
66
- if tags.one?
67
- "[#{tags[0]}] "
68
- elsif tags.any?
69
- tags.collect { |tag| "[#{tag}] " }.join
66
+ tag_stack.format_message("")
67
+ end
68
+ end
69
+
70
+ class TagStack # :nodoc:
71
+ attr_reader :tags
72
+
73
+ def initialize
74
+ @tags = []
75
+ @tags_string = nil
76
+ end
77
+
78
+ def push_tags(tags)
79
+ @tags_string = nil
80
+ tags.flatten!
81
+ tags.reject!(&:blank?)
82
+ @tags.concat(tags)
83
+ tags
84
+ end
85
+
86
+ def pop_tags(count)
87
+ @tags_string = nil
88
+ @tags.pop(count)
89
+ end
90
+
91
+ def clear
92
+ @tags_string = nil
93
+ @tags.clear
94
+ end
95
+
96
+ def format_message(message)
97
+ if @tags.empty?
98
+ message
99
+ elsif @tags.size == 1
100
+ "[#{@tags[0]}] #{message}"
101
+ else
102
+ @tags_string ||= "[#{@tags.join("] [")}] "
103
+ "#{@tags_string}#{message}"
70
104
  end
71
105
  end
72
106
  end
73
107
 
74
108
  module LocalTagStorage # :nodoc:
75
- attr_accessor :current_tags
109
+ attr_accessor :tag_stack
76
110
 
77
111
  def self.extended(base)
78
- base.current_tags = []
112
+ base.tag_stack = TagStack.new
79
113
  end
80
114
  end
81
115
 
@@ -83,7 +117,11 @@ module ActiveSupport
83
117
  logger = logger.clone
84
118
 
85
119
  if logger.formatter
86
- logger.formatter = logger.formatter.dup
120
+ logger.formatter = logger.formatter.clone
121
+
122
+ # Workaround for https://bugs.ruby-lang.org/issues/20250
123
+ # Can be removed when Ruby 3.4 is the least supported version.
124
+ logger.formatter.object_id if logger.formatter.is_a?(Proc)
87
125
  else
88
126
  # Ensure we set a default formatter so we aren't extending nil!
89
127
  logger.formatter = ActiveSupport::Logger::SimpleFormatter.new
@@ -95,20 +133,6 @@ module ActiveSupport
95
133
 
96
134
  delegate :push_tags, :pop_tags, :clear_tags!, to: :formatter
97
135
 
98
- def broadcast_to(other_logger) # :nodoc:
99
- define_singleton_method(:formatter=) do |formatter|
100
- other_logger.formatter ||= formatter
101
-
102
- other_logger.formatter.singleton_class.redefine_method(:current_tags) do
103
- formatter.current_tags
104
- end
105
-
106
- super(formatter)
107
- end
108
-
109
- self.formatter = self.formatter.clone
110
- end
111
-
112
136
  def tagged(*tags)
113
137
  if block_given?
114
138
  formatter.tagged(*tags) { yield self }
@@ -1,15 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- gem "minitest" # make sure we get the gem, not stdlib
4
3
  require "minitest"
5
4
  require "active_support/testing/tagged_logging"
6
5
  require "active_support/testing/setup_and_teardown"
6
+ require "active_support/testing/tests_without_assertions"
7
7
  require "active_support/testing/assertions"
8
+ require "active_support/testing/error_reporter_assertions"
8
9
  require "active_support/testing/deprecation"
9
10
  require "active_support/testing/declarative"
10
11
  require "active_support/testing/isolation"
11
12
  require "active_support/testing/constant_lookup"
12
13
  require "active_support/testing/time_helpers"
14
+ require "active_support/testing/constant_stubbing"
13
15
  require "active_support/testing/file_fixtures"
14
16
  require "active_support/testing/parallelization"
15
17
  require "active_support/testing/parallelize_executor"
@@ -66,7 +68,7 @@ module ActiveSupport
66
68
  # The default parallelization method is to fork processes. If you'd like to
67
69
  # use threads instead you can pass <tt>with: :threads</tt> to the +parallelize+
68
70
  # method. Note the threaded parallelization does not create multiple
69
- # database and will not work with system tests at this time.
71
+ # databases and will not work with system tests.
70
72
  #
71
73
  # parallelize(workers: :number_of_processors, with: :threads)
72
74
  #
@@ -77,11 +79,9 @@ module ActiveSupport
77
79
  # number of tests to run is above the +threshold+ param. The default value is
78
80
  # 50, and it's configurable via +config.active_support.test_parallelization_threshold+.
79
81
  def parallelize(workers: :number_of_processors, with: :processes, threshold: ActiveSupport.test_parallelization_threshold)
80
- workers = Concurrent.physical_processor_count if workers == :number_of_processors
82
+ workers = Concurrent.processor_count if workers == :number_of_processors
81
83
  workers = ENV["PARALLEL_WORKERS"].to_i if ENV["PARALLEL_WORKERS"]
82
84
 
83
- return if workers <= 1
84
-
85
85
  Minitest.parallel_executor = ActiveSupport::Testing::ParallelizeExecutor.new(size: workers, with: with, threshold: threshold)
86
86
  end
87
87
 
@@ -118,34 +118,187 @@ module ActiveSupport
118
118
  def parallelize_teardown(&block)
119
119
  ActiveSupport::Testing::Parallelization.run_cleanup_hook(&block)
120
120
  end
121
+
122
+ # :singleton-method: fixture_paths
123
+ #
124
+ # Returns the ActiveRecord::FixtureSet collection.
125
+ #
126
+ # In your +test_helper.rb+ you must have <tt>require "rails/test_help"</tt>.
127
+
128
+ # :singleton-method: fixture_paths=
129
+ #
130
+ # :call-seq:
131
+ # fixture_paths=(fixture_paths)
132
+ #
133
+ # Sets the given path to the fixture set.
134
+ #
135
+ # Can also append multiple paths.
136
+ #
137
+ # ActiveSupport::TestCase.fixture_paths << "component1/test/fixtures"
138
+ #
139
+ # In your +test_helper.rb+ you must have <tt>require "rails/test_help"</tt>.
121
140
  end
122
141
 
123
142
  alias_method :method_name, :name
124
143
 
125
144
  include ActiveSupport::Testing::TaggedLogging
126
145
  prepend ActiveSupport::Testing::SetupAndTeardown
146
+ prepend ActiveSupport::Testing::TestsWithoutAssertions
127
147
  include ActiveSupport::Testing::Assertions
148
+ include ActiveSupport::Testing::ErrorReporterAssertions
128
149
  include ActiveSupport::Testing::Deprecation
150
+ include ActiveSupport::Testing::ConstantStubbing
129
151
  include ActiveSupport::Testing::TimeHelpers
130
152
  include ActiveSupport::Testing::FileFixtures
131
153
  extend ActiveSupport::Testing::Declarative
132
154
 
133
- # test/unit backwards compatibility methods
134
- alias :assert_raise :assert_raises
155
+ ##
156
+ # :method: assert_not_empty
157
+ #
158
+ # :call-seq:
159
+ # assert_not_empty(obj, msg = nil)
160
+ #
161
+ # Alias for: refute_empty[https://docs.seattlerb.org/minitest/Minitest/Assertions.html#method-i-refute_empty]
162
+
163
+ #
135
164
  alias :assert_not_empty :refute_empty
165
+
166
+ ##
167
+ # :method: assert_not_equal
168
+ #
169
+ # :call-seq:
170
+ # assert_not_equal(exp, act, msg = nil)
171
+ #
172
+ # Alias for: refute_equal[https://docs.seattlerb.org/minitest/Minitest/Assertions.html#method-i-refute_equal]
173
+
174
+ #
136
175
  alias :assert_not_equal :refute_equal
176
+
177
+ ##
178
+ # :method: assert_not_in_delta
179
+ #
180
+ # :call-seq:
181
+ # assert_not_in_delta(exp, act, delta = 0.001, msg = nil)
182
+ #
183
+ # Alias for: refute_in_delta[https://docs.seattlerb.org/minitest/Minitest/Assertions.html#method-i-refute_in_delta]
184
+
185
+ #
137
186
  alias :assert_not_in_delta :refute_in_delta
187
+
188
+ ##
189
+ # :method: assert_not_in_epsilon
190
+ #
191
+ # :call-seq:
192
+ # assert_not_in_epsilon(a, b, epsilon = 0.001, msg = nil)
193
+ #
194
+ # Alias for: refute_in_epsilon[https://docs.seattlerb.org/minitest/Minitest/Assertions.html#method-i-refute_in_epsilon]
195
+
196
+ #
138
197
  alias :assert_not_in_epsilon :refute_in_epsilon
198
+
199
+ ##
200
+ # :method: assert_not_includes
201
+ #
202
+ # :call-seq:
203
+ # assert_not_includes(collection, obj, msg = nil)
204
+ #
205
+ # Alias for: refute_includes[https://docs.seattlerb.org/minitest/Minitest/Assertions.html#method-i-refute_includes]
206
+
207
+ #
139
208
  alias :assert_not_includes :refute_includes
209
+
210
+ ##
211
+ # :method: assert_not_instance_of
212
+ #
213
+ # :call-seq:
214
+ # assert_not_instance_of(cls, obj, msg = nil)
215
+ #
216
+ # Alias for: refute_instance_of[https://docs.seattlerb.org/minitest/Minitest/Assertions.html#method-i-refute_instance_of]
217
+
218
+ #
140
219
  alias :assert_not_instance_of :refute_instance_of
220
+
221
+ ##
222
+ # :method: assert_not_kind_of
223
+ #
224
+ # :call-seq:
225
+ # assert_not_kind_of(cls, obj, msg = nil)
226
+ #
227
+ # Alias for: refute_kind_of[https://docs.seattlerb.org/minitest/Minitest/Assertions.html#method-i-refute_kind_of]
228
+
229
+ #
141
230
  alias :assert_not_kind_of :refute_kind_of
231
+
232
+ ##
233
+ # :method: assert_no_match
234
+ #
235
+ # :call-seq:
236
+ # assert_no_match(matcher, obj, msg = nil)
237
+ #
238
+ # Alias for: refute_match[https://docs.seattlerb.org/minitest/Minitest/Assertions.html#method-i-refute_match]
239
+
240
+ #
142
241
  alias :assert_no_match :refute_match
242
+
243
+ ##
244
+ # :method: assert_not_nil
245
+ #
246
+ # :call-seq:
247
+ # assert_not_nil(obj, msg = nil)
248
+ #
249
+ # Alias for: refute_nil[https://docs.seattlerb.org/minitest/Minitest/Assertions.html#method-i-refute_nil]
250
+
251
+ #
143
252
  alias :assert_not_nil :refute_nil
253
+
254
+ ##
255
+ # :method: assert_not_operator
256
+ #
257
+ # :call-seq:
258
+ # assert_not_operator(o1, op, o2 = UNDEFINED, msg = nil)
259
+ #
260
+ # Alias for: refute_operator[https://docs.seattlerb.org/minitest/Minitest/Assertions.html#method-i-refute_operator]
261
+
262
+ #
144
263
  alias :assert_not_operator :refute_operator
264
+
265
+ ##
266
+ # :method: assert_not_predicate
267
+ #
268
+ # :call-seq:
269
+ # assert_not_predicate(o1, op, msg = nil)
270
+ #
271
+ # Alias for: refute_predicate[https://docs.seattlerb.org/minitest/Minitest/Assertions.html#method-i-refute_predicate]
272
+
273
+ #
145
274
  alias :assert_not_predicate :refute_predicate
275
+
276
+ ##
277
+ # :method: assert_not_respond_to
278
+ #
279
+ # :call-seq:
280
+ # assert_not_respond_to(obj, meth, msg = nil)
281
+ #
282
+ # Alias for: refute_respond_to[https://docs.seattlerb.org/minitest/Minitest/Assertions.html#method-i-refute_respond_to]
283
+
284
+ #
146
285
  alias :assert_not_respond_to :refute_respond_to
286
+
287
+ ##
288
+ # :method: assert_not_same
289
+ #
290
+ # :call-seq:
291
+ # assert_not_same(exp, act, msg = nil)
292
+ #
293
+ # Alias for: refute_same[https://docs.seattlerb.org/minitest/Minitest/Assertions.html#method-i-refute_same]
294
+
295
+ #
147
296
  alias :assert_not_same :refute_same
148
297
 
149
298
  ActiveSupport.run_load_hooks(:active_support_test_case, self)
299
+
300
+ def inspect # :nodoc:
301
+ Object.instance_method(:to_s).bind_call(self)
302
+ end
150
303
  end
151
304
  end
@@ -7,9 +7,9 @@ module ActiveSupport
7
7
  module Assertions
8
8
  UNTRACKED = Object.new # :nodoc:
9
9
 
10
- # Asserts that an expression is not truthy. Passes if <tt>object</tt> is
11
- # +nil+ or +false+. "Truthy" means "considered true in a conditional"
12
- # like <tt>if foo</tt>.
10
+ # Asserts that an expression is not truthy. Passes if +object+ is +nil+ or
11
+ # +false+. "Truthy" means "considered true in a conditional" like <tt>if
12
+ # foo</tt>.
13
13
  #
14
14
  # assert_not nil # => true
15
15
  # assert_not false # => true
@@ -23,6 +23,21 @@ module ActiveSupport
23
23
  assert !object, message
24
24
  end
25
25
 
26
+ # Asserts that a block raises one of +exp+. This is an enhancement of the
27
+ # standard Minitest assertion method with the ability to test error
28
+ # messages.
29
+ #
30
+ # assert_raises(ArgumentError, match: /incorrect param/i) do
31
+ # perform_service(param: 'exception')
32
+ # end
33
+ #
34
+ def assert_raises(*exp, match: nil, &block)
35
+ error = super(*exp, &block)
36
+ assert_match(match, error.message) if match
37
+ error
38
+ end
39
+ alias :assert_raise :assert_raises
40
+
26
41
  # Assertion that the block should not raise an exception.
27
42
  #
28
43
  # Passes if evaluated code in the yielded block raises no exception.
@@ -31,7 +46,7 @@ module ActiveSupport
31
46
  # perform_service(param: 'no_exception')
32
47
  # end
33
48
  def assert_nothing_raised
34
- yield
49
+ yield.tap { assert(true) }
35
50
  rescue => error
36
51
  raise Minitest::UnexpectedError.new(error)
37
52
  end
@@ -50,7 +65,7 @@ module ActiveSupport
50
65
  # end
51
66
  #
52
67
  # An arbitrary positive or negative difference can be specified.
53
- # The default is <tt>1</tt>.
68
+ # The default is +1+.
54
69
  #
55
70
  # assert_difference 'Article.count', -1 do
56
71
  # post :delete, params: { id: ... }
@@ -102,9 +117,10 @@ module ActiveSupport
102
117
  retval = _assert_nothing_raised_or_warn("assert_difference", &block)
103
118
 
104
119
  expressions.zip(exps, before) do |(code, diff), exp, before_value|
105
- error = "#{code.inspect} didn't change by #{diff}"
120
+ actual = exp.call
121
+ error = "#{code.inspect} didn't change by #{diff}, but by #{actual - before_value}"
106
122
  error = "#{message}.\n#{error}" if message
107
- assert_equal(before_value + diff, exp.call, error)
123
+ assert_equal(before_value + diff, actual, error)
108
124
  end
109
125
 
110
126
  retval
@@ -179,7 +195,7 @@ module ActiveSupport
179
195
  retval = _assert_nothing_raised_or_warn("assert_changes", &block)
180
196
 
181
197
  unless from == UNTRACKED
182
- error = "Expected change from #{from.inspect}"
198
+ error = "Expected change from #{from.inspect}, got #{before.inspect}"
183
199
  error = "#{message}.\n#{error}" if message
184
200
  assert from === before, error
185
201
  end
@@ -187,12 +203,12 @@ module ActiveSupport
187
203
  after = exp.call
188
204
 
189
205
  error = "#{expression.inspect} didn't change"
190
- error = "#{error}. It was already #{to}" if before == to
206
+ error = "#{error}. It was already #{to.inspect}" if before == to
191
207
  error = "#{message}.\n#{error}" if message
192
208
  refute_equal before, after, error
193
209
 
194
210
  unless to == UNTRACKED
195
- error = "Expected change to #{to}\n"
211
+ error = "Expected change to #{to.inspect}, got #{after.inspect}\n"
196
212
  error = "#{message}.\n#{error}" if message
197
213
  assert to === after, error
198
214
  end
@@ -207,7 +223,7 @@ module ActiveSupport
207
223
  # post :create, params: { status: { ok: true } }
208
224
  # end
209
225
  #
210
- # Provide the optional keyword argument :from to specify the expected
226
+ # Provide the optional keyword argument +:from+ to specify the expected
211
227
  # initial value.
212
228
  #
213
229
  # assert_no_changes -> { Status.all_good? }, from: true do
@@ -226,7 +242,7 @@ module ActiveSupport
226
242
  retval = _assert_nothing_raised_or_warn("assert_no_changes", &block)
227
243
 
228
244
  unless from == UNTRACKED
229
- error = "Expected initial value of #{from.inspect}"
245
+ error = "Expected initial value of #{from.inspect}, got #{before.inspect}"
230
246
  error = "#{message}.\n#{error}" if message
231
247
  assert from === before, error
232
248
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- gem "minitest"
4
-
5
3
  require "minitest"
6
4
 
7
5
  Minitest.autorun