activesupport 5.0.0 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activesupport might be problematic. Click here for more details.

Files changed (268) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +343 -590
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -4
  5. data/lib/active_support/actionable_error.rb +48 -0
  6. data/lib/active_support/all.rb +5 -3
  7. data/lib/active_support/array_inquirer.rb +11 -5
  8. data/lib/active_support/backtrace_cleaner.rb +33 -5
  9. data/lib/active_support/benchmarkable.rb +5 -3
  10. data/lib/active_support/builder.rb +3 -1
  11. data/lib/active_support/cache/file_store.rb +45 -53
  12. data/lib/active_support/cache/mem_cache_store.rb +81 -79
  13. data/lib/active_support/cache/memory_store.rb +69 -41
  14. data/lib/active_support/cache/null_store.rb +11 -4
  15. data/lib/active_support/cache/redis_cache_store.rb +493 -0
  16. data/lib/active_support/cache/strategy/local_cache.rb +74 -37
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
  18. data/lib/active_support/cache.rb +332 -161
  19. data/lib/active_support/callbacks.rb +657 -586
  20. data/lib/active_support/concern.rb +79 -6
  21. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +35 -0
  22. data/lib/active_support/concurrency/share_lock.rb +59 -19
  23. data/lib/active_support/configurable.rb +15 -17
  24. data/lib/active_support/configuration_file.rb +46 -0
  25. data/lib/active_support/core_ext/array/access.rb +21 -7
  26. data/lib/active_support/core_ext/array/conversions.rb +20 -18
  27. data/lib/active_support/core_ext/array/extract.rb +21 -0
  28. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  29. data/lib/active_support/core_ext/array/grouping.rb +3 -1
  30. data/lib/active_support/core_ext/array/inquiry.rb +3 -1
  31. data/lib/active_support/core_ext/array/wrap.rb +2 -0
  32. data/lib/active_support/core_ext/array.rb +9 -7
  33. data/lib/active_support/core_ext/benchmark.rb +5 -3
  34. data/lib/active_support/core_ext/big_decimal/conversions.rb +6 -6
  35. data/lib/active_support/core_ext/big_decimal.rb +3 -1
  36. data/lib/active_support/core_ext/class/attribute.rb +52 -49
  37. data/lib/active_support/core_ext/class/attribute_accessors.rb +3 -1
  38. data/lib/active_support/core_ext/class/subclasses.rb +18 -26
  39. data/lib/active_support/core_ext/class.rb +4 -2
  40. data/lib/active_support/core_ext/date/acts_like.rb +3 -1
  41. data/lib/active_support/core_ext/date/blank.rb +3 -1
  42. data/lib/active_support/core_ext/date/calculations.rb +16 -13
  43. data/lib/active_support/core_ext/date/conversions.rb +23 -21
  44. data/lib/active_support/core_ext/date/zones.rb +4 -2
  45. data/lib/active_support/core_ext/date.rb +7 -5
  46. data/lib/active_support/core_ext/date_and_time/calculations.rb +82 -53
  47. data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -5
  48. data/lib/active_support/core_ext/date_and_time/zones.rb +9 -9
  49. data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
  50. data/lib/active_support/core_ext/date_time/blank.rb +3 -1
  51. data/lib/active_support/core_ext/date_time/calculations.rb +23 -11
  52. data/lib/active_support/core_ext/date_time/compatibility.rb +15 -2
  53. data/lib/active_support/core_ext/date_time/conversions.rb +14 -13
  54. data/lib/active_support/core_ext/date_time.rb +7 -5
  55. data/lib/active_support/core_ext/digest/uuid.rb +7 -5
  56. data/lib/active_support/core_ext/digest.rb +3 -0
  57. data/lib/active_support/core_ext/enumerable.rb +165 -29
  58. data/lib/active_support/core_ext/file/atomic.rb +7 -5
  59. data/lib/active_support/core_ext/file.rb +3 -1
  60. data/lib/active_support/core_ext/hash/conversions.rb +40 -39
  61. data/lib/active_support/core_ext/hash/deep_merge.rb +8 -12
  62. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  63. data/lib/active_support/core_ext/hash/except.rb +4 -2
  64. data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -2
  65. data/lib/active_support/core_ext/hash/keys.rb +9 -36
  66. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  67. data/lib/active_support/core_ext/hash/slice.rb +8 -29
  68. data/lib/active_support/core_ext/hash.rb +10 -9
  69. data/lib/active_support/core_ext/integer/inflections.rb +3 -1
  70. data/lib/active_support/core_ext/integer/multiple.rb +3 -1
  71. data/lib/active_support/core_ext/integer/time.rb +11 -18
  72. data/lib/active_support/core_ext/integer.rb +5 -3
  73. data/lib/active_support/core_ext/kernel/concern.rb +3 -1
  74. data/lib/active_support/core_ext/kernel/reporting.rb +3 -1
  75. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  76. data/lib/active_support/core_ext/kernel.rb +5 -4
  77. data/lib/active_support/core_ext/load_error.rb +2 -23
  78. data/lib/active_support/core_ext/marshal.rb +6 -2
  79. data/lib/active_support/core_ext/module/aliasing.rb +5 -48
  80. data/lib/active_support/core_ext/module/anonymous.rb +2 -0
  81. data/lib/active_support/core_ext/module/attr_internal.rb +7 -5
  82. data/lib/active_support/core_ext/module/attribute_accessors.rb +53 -59
  83. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +31 -24
  84. data/lib/active_support/core_ext/module/concerning.rb +16 -11
  85. data/lib/active_support/core_ext/module/delegation.rb +159 -44
  86. data/lib/active_support/core_ext/module/deprecation.rb +2 -0
  87. data/lib/active_support/core_ext/module/introspection.rb +23 -26
  88. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  89. data/lib/active_support/core_ext/module/remove_method.rb +5 -23
  90. data/lib/active_support/core_ext/module.rb +13 -12
  91. data/lib/active_support/core_ext/name_error.rb +36 -2
  92. data/lib/active_support/core_ext/numeric/bytes.rb +2 -0
  93. data/lib/active_support/core_ext/numeric/conversions.rb +129 -134
  94. data/lib/active_support/core_ext/numeric/time.rb +18 -26
  95. data/lib/active_support/core_ext/numeric.rb +5 -4
  96. data/lib/active_support/core_ext/object/acts_like.rb +12 -1
  97. data/lib/active_support/core_ext/object/blank.rb +14 -2
  98. data/lib/active_support/core_ext/object/conversions.rb +6 -4
  99. data/lib/active_support/core_ext/object/deep_dup.rb +4 -2
  100. data/lib/active_support/core_ext/object/duplicable.rb +13 -62
  101. data/lib/active_support/core_ext/object/inclusion.rb +3 -1
  102. data/lib/active_support/core_ext/object/instance_variables.rb +2 -0
  103. data/lib/active_support/core_ext/object/json.rb +42 -15
  104. data/lib/active_support/core_ext/object/to_param.rb +3 -1
  105. data/lib/active_support/core_ext/object/to_query.rb +10 -5
  106. data/lib/active_support/core_ext/object/try.rb +20 -8
  107. data/lib/active_support/core_ext/object/with_options.rb +15 -2
  108. data/lib/active_support/core_ext/object.rb +14 -12
  109. data/lib/active_support/core_ext/range/compare_range.rb +82 -0
  110. data/lib/active_support/core_ext/range/conversions.rb +35 -25
  111. data/lib/active_support/core_ext/range/each.rb +5 -2
  112. data/lib/active_support/core_ext/range/include_time_with_zone.rb +28 -0
  113. data/lib/active_support/core_ext/range/overlaps.rb +2 -0
  114. data/lib/active_support/core_ext/range.rb +7 -4
  115. data/lib/active_support/core_ext/regexp.rb +10 -1
  116. data/lib/active_support/core_ext/securerandom.rb +28 -6
  117. data/lib/active_support/core_ext/string/access.rb +9 -18
  118. data/lib/active_support/core_ext/string/behavior.rb +2 -0
  119. data/lib/active_support/core_ext/string/conversions.rb +5 -2
  120. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  121. data/lib/active_support/core_ext/string/filters.rb +47 -4
  122. data/lib/active_support/core_ext/string/indent.rb +6 -4
  123. data/lib/active_support/core_ext/string/inflections.rb +78 -29
  124. data/lib/active_support/core_ext/string/inquiry.rb +4 -1
  125. data/lib/active_support/core_ext/string/multibyte.rb +10 -5
  126. data/lib/active_support/core_ext/string/output_safety.rb +86 -31
  127. data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
  128. data/lib/active_support/core_ext/string/strip.rb +5 -1
  129. data/lib/active_support/core_ext/string/zones.rb +4 -2
  130. data/lib/active_support/core_ext/string.rb +15 -13
  131. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
  132. data/lib/active_support/core_ext/symbol.rb +3 -0
  133. data/lib/active_support/core_ext/time/acts_like.rb +3 -1
  134. data/lib/active_support/core_ext/time/calculations.rb +117 -45
  135. data/lib/active_support/core_ext/time/compatibility.rb +13 -2
  136. data/lib/active_support/core_ext/time/conversions.rb +18 -12
  137. data/lib/active_support/core_ext/time/zones.rb +9 -7
  138. data/lib/active_support/core_ext/time.rb +7 -5
  139. data/lib/active_support/core_ext/uri.rb +12 -7
  140. data/lib/active_support/core_ext.rb +3 -2
  141. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  142. data/lib/active_support/current_attributes.rb +208 -0
  143. data/lib/active_support/dependencies/autoload.rb +2 -0
  144. data/lib/active_support/dependencies/interlock.rb +7 -1
  145. data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
  146. data/lib/active_support/dependencies.rb +172 -98
  147. data/lib/active_support/deprecation/behaviors.rb +45 -13
  148. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  149. data/lib/active_support/deprecation/disallowed.rb +56 -0
  150. data/lib/active_support/deprecation/instance_delegator.rb +16 -2
  151. data/lib/active_support/deprecation/method_wrappers.rb +32 -17
  152. data/lib/active_support/deprecation/proxy_wrappers.rb +35 -7
  153. data/lib/active_support/deprecation/reporting.rb +61 -16
  154. data/lib/active_support/deprecation.rb +17 -9
  155. data/lib/active_support/descendants_tracker.rb +61 -9
  156. data/lib/active_support/digest.rb +20 -0
  157. data/lib/active_support/duration/iso8601_parser.rb +67 -66
  158. data/lib/active_support/duration/iso8601_serializer.rb +25 -17
  159. data/lib/active_support/duration.rb +349 -46
  160. data/lib/active_support/encrypted_configuration.rb +45 -0
  161. data/lib/active_support/encrypted_file.rb +117 -0
  162. data/lib/active_support/environment_inquirer.rb +20 -0
  163. data/lib/active_support/evented_file_update_checker.rb +88 -112
  164. data/lib/active_support/execution_wrapper.rb +25 -13
  165. data/lib/active_support/executor.rb +3 -1
  166. data/lib/active_support/file_update_checker.rb +56 -51
  167. data/lib/active_support/fork_tracker.rb +62 -0
  168. data/lib/active_support/gem_version.rb +4 -2
  169. data/lib/active_support/gzip.rb +7 -5
  170. data/lib/active_support/hash_with_indifferent_access.rb +153 -49
  171. data/lib/active_support/i18n.rb +9 -6
  172. data/lib/active_support/i18n_railtie.rb +30 -20
  173. data/lib/active_support/inflections.rb +13 -11
  174. data/lib/active_support/inflector/inflections.rb +28 -15
  175. data/lib/active_support/inflector/methods.rb +120 -109
  176. data/lib/active_support/inflector/transliterate.rb +60 -25
  177. data/lib/active_support/inflector.rb +7 -5
  178. data/lib/active_support/json/decoding.rb +30 -29
  179. data/lib/active_support/json/encoding.rb +22 -11
  180. data/lib/active_support/json.rb +4 -2
  181. data/lib/active_support/key_generator.rb +6 -36
  182. data/lib/active_support/lazy_load_hooks.rb +53 -20
  183. data/lib/active_support/locale/en.rb +33 -0
  184. data/lib/active_support/locale/en.yml +7 -3
  185. data/lib/active_support/log_subscriber/test_helper.rb +11 -9
  186. data/lib/active_support/log_subscriber.rb +51 -18
  187. data/lib/active_support/logger.rb +9 -22
  188. data/lib/active_support/logger_silence.rb +14 -21
  189. data/lib/active_support/logger_thread_safe_level.rb +55 -8
  190. data/lib/active_support/message_encryptor.rb +170 -53
  191. data/lib/active_support/message_verifier.rb +91 -20
  192. data/lib/active_support/messages/metadata.rb +80 -0
  193. data/lib/active_support/messages/rotation_configuration.rb +23 -0
  194. data/lib/active_support/messages/rotator.rb +57 -0
  195. data/lib/active_support/multibyte/chars.rb +24 -78
  196. data/lib/active_support/multibyte/unicode.rb +21 -352
  197. data/lib/active_support/multibyte.rb +4 -2
  198. data/lib/active_support/notifications/fanout.rb +121 -19
  199. data/lib/active_support/notifications/instrumenter.rb +78 -14
  200. data/lib/active_support/notifications.rb +80 -12
  201. data/lib/active_support/number_helper/number_converter.rb +17 -16
  202. data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -9
  203. data/lib/active_support/number_helper/number_to_delimited_converter.rb +5 -3
  204. data/lib/active_support/number_helper/number_to_human_converter.rb +13 -12
  205. data/lib/active_support/number_helper/number_to_human_size_converter.rb +11 -13
  206. data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
  207. data/lib/active_support/number_helper/number_to_phone_converter.rb +5 -4
  208. data/lib/active_support/number_helper/number_to_rounded_converter.rb +18 -55
  209. data/lib/active_support/number_helper/rounding_helper.rb +50 -0
  210. data/lib/active_support/number_helper.rb +45 -16
  211. data/lib/active_support/option_merger.rb +25 -4
  212. data/lib/active_support/ordered_hash.rb +6 -4
  213. data/lib/active_support/ordered_options.rb +23 -9
  214. data/lib/active_support/parameter_filter.rb +133 -0
  215. data/lib/active_support/per_thread_registry.rb +7 -5
  216. data/lib/active_support/proxy_object.rb +2 -0
  217. data/lib/active_support/rails.rb +8 -9
  218. data/lib/active_support/railtie.rb +62 -11
  219. data/lib/active_support/reloader.rb +12 -11
  220. data/lib/active_support/rescuable.rb +20 -11
  221. data/lib/active_support/secure_compare_rotator.rb +51 -0
  222. data/lib/active_support/security_utils.rb +26 -15
  223. data/lib/active_support/string_inquirer.rb +12 -3
  224. data/lib/active_support/subscriber.rb +77 -23
  225. data/lib/active_support/tagged_logging.rb +52 -17
  226. data/lib/active_support/test_case.rb +106 -29
  227. data/lib/active_support/testing/assertions.rb +144 -8
  228. data/lib/active_support/testing/autorun.rb +5 -10
  229. data/lib/active_support/testing/constant_lookup.rb +2 -1
  230. data/lib/active_support/testing/declarative.rb +3 -1
  231. data/lib/active_support/testing/deprecation.rb +4 -2
  232. data/lib/active_support/testing/file_fixtures.rb +4 -0
  233. data/lib/active_support/testing/isolation.rb +19 -24
  234. data/lib/active_support/testing/method_call_assertions.rb +31 -2
  235. data/lib/active_support/testing/parallelization/server.rb +78 -0
  236. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  237. data/lib/active_support/testing/parallelization.rb +51 -0
  238. data/lib/active_support/testing/setup_and_teardown.rb +13 -8
  239. data/lib/active_support/testing/stream.rb +30 -29
  240. data/lib/active_support/testing/tagged_logging.rb +3 -1
  241. data/lib/active_support/testing/time_helpers.rb +125 -24
  242. data/lib/active_support/time.rb +14 -12
  243. data/lib/active_support/time_with_zone.rb +142 -55
  244. data/lib/active_support/values/time_zone.rb +160 -53
  245. data/lib/active_support/version.rb +3 -1
  246. data/lib/active_support/xml_mini/jdom.rb +115 -114
  247. data/lib/active_support/xml_mini/libxml.rb +15 -14
  248. data/lib/active_support/xml_mini/libxmlsax.rb +16 -18
  249. data/lib/active_support/xml_mini/nokogiri.rb +13 -13
  250. data/lib/active_support/xml_mini/nokogirisax.rb +15 -16
  251. data/lib/active_support/xml_mini/rexml.rb +18 -9
  252. data/lib/active_support/xml_mini.rb +44 -42
  253. data/lib/active_support.rb +19 -10
  254. metadata +79 -37
  255. data/lib/active_support/concurrency/latch.rb +0 -19
  256. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
  257. data/lib/active_support/core_ext/hash/compact.rb +0 -20
  258. data/lib/active_support/core_ext/hash/transform_values.rb +0 -29
  259. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
  260. data/lib/active_support/core_ext/kernel/debugger.rb +0 -3
  261. data/lib/active_support/core_ext/module/method_transplanting.rb +0 -3
  262. data/lib/active_support/core_ext/module/qualified_const.rb +0 -70
  263. data/lib/active_support/core_ext/module/reachable.rb +0 -8
  264. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -26
  265. data/lib/active_support/core_ext/range/include_range.rb +0 -23
  266. data/lib/active_support/core_ext/struct.rb +0 -3
  267. data/lib/active_support/core_ext/time/marshal.rb +0 -3
  268. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,4 +1,7 @@
1
- require 'active_support/per_thread_registry'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/per_thread_registry"
4
+ require "active_support/notifications"
2
5
 
3
6
  module ActiveSupport
4
7
  # ActiveSupport::Subscriber is an object set to consume
@@ -21,23 +24,46 @@ module ActiveSupport
21
24
  # After configured, whenever a "sql.active_record" notification is published,
22
25
  # it will properly dispatch the event (ActiveSupport::Notifications::Event) to
23
26
  # the +sql+ method.
27
+ #
28
+ # We can detach a subscriber as well:
29
+ #
30
+ # ActiveRecord::StatsSubscriber.detach_from(:active_record)
24
31
  class Subscriber
25
32
  class << self
26
-
27
33
  # Attach the subscriber to a namespace.
28
- def attach_to(namespace, subscriber=new, notifier=ActiveSupport::Notifications)
34
+ def attach_to(namespace, subscriber = new, notifier = ActiveSupport::Notifications, inherit_all: false)
29
35
  @namespace = namespace
30
36
  @subscriber = subscriber
31
37
  @notifier = notifier
38
+ @inherit_all = inherit_all
32
39
 
33
40
  subscribers << subscriber
34
41
 
35
42
  # Add event subscribers for all existing methods on the class.
36
- subscriber.public_methods(false).each do |event|
43
+ fetch_public_methods(subscriber, inherit_all).each do |event|
37
44
  add_event_subscriber(event)
38
45
  end
39
46
  end
40
47
 
48
+ # Detach the subscriber from a namespace.
49
+ def detach_from(namespace, notifier = ActiveSupport::Notifications)
50
+ @namespace = namespace
51
+ @subscriber = find_attached_subscriber
52
+ @notifier = notifier
53
+
54
+ return unless subscriber
55
+
56
+ subscribers.delete(subscriber)
57
+
58
+ # Remove event subscribers of all existing methods on the class.
59
+ fetch_public_methods(subscriber, true).each do |event|
60
+ remove_event_subscriber(event)
61
+ end
62
+
63
+ # Reset notifier so that event subscribers will not add for new methods added to the class.
64
+ @notifier = nil
65
+ end
66
+
41
67
  # Adds event subscribers for all new methods added to the class.
42
68
  def method_added(event)
43
69
  # Only public methods are added as subscribers, and only if a notifier
@@ -52,51 +78,79 @@ module ActiveSupport
52
78
  @@subscribers ||= []
53
79
  end
54
80
 
55
- protected
81
+ private
82
+ attr_reader :subscriber, :notifier, :namespace
56
83
 
57
- attr_reader :subscriber, :notifier, :namespace
84
+ def add_event_subscriber(event) # :doc:
85
+ return if invalid_event?(event)
58
86
 
59
- def add_event_subscriber(event)
60
- return if %w{ start finish }.include?(event.to_s)
87
+ pattern = prepare_pattern(event)
61
88
 
62
- pattern = "#{event}.#{namespace}"
89
+ # Don't add multiple subscribers (e.g. if methods are redefined).
90
+ return if pattern_subscribed?(pattern)
63
91
 
64
- # Don't add multiple subscribers (eg. if methods are redefined).
65
- return if subscriber.patterns.include?(pattern)
92
+ subscriber.patterns[pattern] = notifier.subscribe(pattern, subscriber)
93
+ end
66
94
 
67
- subscriber.patterns << pattern
68
- notifier.subscribe(pattern, subscriber)
69
- end
95
+ def remove_event_subscriber(event) # :doc:
96
+ return if invalid_event?(event)
97
+
98
+ pattern = prepare_pattern(event)
99
+
100
+ return unless pattern_subscribed?(pattern)
101
+
102
+ notifier.unsubscribe(subscriber.patterns[pattern])
103
+ subscriber.patterns.delete(pattern)
104
+ end
105
+
106
+ def find_attached_subscriber
107
+ subscribers.find { |attached_subscriber| attached_subscriber.instance_of?(self) }
108
+ end
109
+
110
+ def invalid_event?(event)
111
+ %i{ start finish }.include?(event.to_sym)
112
+ end
113
+
114
+ def prepare_pattern(event)
115
+ "#{event}.#{namespace}"
116
+ end
117
+
118
+ def pattern_subscribed?(pattern)
119
+ subscriber.patterns.key?(pattern)
120
+ end
121
+
122
+ def fetch_public_methods(subscriber, inherit_all)
123
+ subscriber.public_methods(inherit_all) - Subscriber.public_instance_methods(true)
124
+ end
70
125
  end
71
126
 
72
127
  attr_reader :patterns # :nodoc:
73
128
 
74
129
  def initialize
75
130
  @queue_key = [self.class.name, object_id].join "-"
76
- @patterns = []
131
+ @patterns = {}
77
132
  super
78
133
  end
79
134
 
80
135
  def start(name, id, payload)
81
- e = ActiveSupport::Notifications::Event.new(name, Time.now, nil, id, payload)
136
+ event = ActiveSupport::Notifications::Event.new(name, nil, nil, id, payload)
137
+ event.start!
82
138
  parent = event_stack.last
83
- parent << e if parent
139
+ parent << event if parent
84
140
 
85
- event_stack.push e
141
+ event_stack.push event
86
142
  end
87
143
 
88
144
  def finish(name, id, payload)
89
- finished = Time.now
90
- event = event_stack.pop
91
- event.end = finished
145
+ event = event_stack.pop
146
+ event.finish!
92
147
  event.payload.merge!(payload)
93
148
 
94
- method = name.split('.'.freeze).first
149
+ method = name.split(".").first
95
150
  send(method, event)
96
151
  end
97
152
 
98
153
  private
99
-
100
154
  def event_stack
101
155
  SubscriberQueueRegistry.instance.get_queue(@queue_key)
102
156
  end
@@ -1,16 +1,27 @@
1
- require 'active_support/core_ext/module/delegation'
2
- require 'active_support/core_ext/object/blank'
3
- require 'logger'
4
- require 'active_support/logger'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module/delegation"
4
+ require "active_support/core_ext/object/blank"
5
+ require "logger"
6
+ require "active_support/logger"
5
7
 
6
8
  module ActiveSupport
7
9
  # Wraps any standard Logger object to provide tagging capabilities.
8
10
  #
11
+ # May be called with a block:
12
+ #
9
13
  # logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
10
14
  # logger.tagged('BCX') { logger.info 'Stuff' } # Logs "[BCX] Stuff"
11
15
  # logger.tagged('BCX', "Jason") { logger.info 'Stuff' } # Logs "[BCX] [Jason] Stuff"
12
16
  # logger.tagged('BCX') { logger.tagged('Jason') { logger.info 'Stuff' } } # Logs "[BCX] [Jason] Stuff"
13
17
  #
18
+ # If called without a block, a new logger will be returned with applied tags:
19
+ #
20
+ # logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
21
+ # logger.tagged("BCX").info "Stuff" # Logs "[BCX] Stuff"
22
+ # logger.tagged("BCX", "Jason").info "Stuff" # Logs "[BCX] [Jason] Stuff"
23
+ # logger.tagged("BCX").tagged("Jason").info "Stuff" # Logs "[BCX] [Jason] Stuff"
24
+ #
14
25
  # This is used by the default Rails.logger as configured by Railties to make
15
26
  # it easy to stamp log lines with subdomains, request ids, and anything else
16
27
  # to aid debugging of multi-user production applications.
@@ -29,9 +40,10 @@ module ActiveSupport
29
40
  end
30
41
 
31
42
  def push_tags(*tags)
32
- tags.flatten.reject(&:blank?).tap do |new_tags|
33
- current_tags.concat new_tags
34
- end
43
+ tags.flatten!
44
+ tags.reject!(&:blank?)
45
+ current_tags.concat tags
46
+ tags
35
47
  end
36
48
 
37
49
  def pop_tags(size = 1)
@@ -44,22 +56,38 @@ module ActiveSupport
44
56
 
45
57
  def current_tags
46
58
  # We use our object ID here to avoid conflicting with other instances
47
- thread_key = @thread_key ||= "activesupport_tagged_logging_tags:#{object_id}".freeze
59
+ thread_key = @thread_key ||= "activesupport_tagged_logging_tags:#{object_id}"
48
60
  Thread.current[thread_key] ||= []
49
61
  end
50
62
 
51
- private
52
- def tags_text
53
- tags = current_tags
54
- if tags.any?
55
- tags.collect { |tag| "[#{tag}] " }.join
56
- end
63
+ def tags_text
64
+ tags = current_tags
65
+ if tags.one?
66
+ "[#{tags[0]}] "
67
+ elsif tags.any?
68
+ tags.collect { |tag| "[#{tag}] " }.join
57
69
  end
70
+ end
71
+ end
72
+
73
+ module LocalTagStorage # :nodoc:
74
+ attr_accessor :current_tags
75
+
76
+ def self.extended(base)
77
+ base.current_tags = []
78
+ end
58
79
  end
59
80
 
60
81
  def self.new(logger)
61
- # Ensure we set a default formatter so we aren't extending nil!
62
- logger.formatter ||= ActiveSupport::Logger::SimpleFormatter.new
82
+ logger = logger.dup
83
+
84
+ if logger.formatter
85
+ logger.formatter = logger.formatter.dup
86
+ else
87
+ # Ensure we set a default formatter so we aren't extending nil!
88
+ logger.formatter = ActiveSupport::Logger::SimpleFormatter.new
89
+ end
90
+
63
91
  logger.formatter.extend Formatter
64
92
  logger.extend(self)
65
93
  end
@@ -67,7 +95,14 @@ module ActiveSupport
67
95
  delegate :push_tags, :pop_tags, :clear_tags!, to: :formatter
68
96
 
69
97
  def tagged(*tags)
70
- formatter.tagged(*tags) { yield self }
98
+ if block_given?
99
+ formatter.tagged(*tags) { yield self }
100
+ else
101
+ logger = ActiveSupport::TaggedLogging.new(self)
102
+ logger.formatter.extend LocalTagStorage
103
+ logger.push_tags(*formatter.current_tags, *tags)
104
+ logger
105
+ end
71
106
  end
72
107
 
73
108
  def flush
@@ -1,15 +1,18 @@
1
- gem 'minitest' # make sure we get the gem, not stdlib
2
- require 'minitest'
3
- require 'active_support/testing/tagged_logging'
4
- require 'active_support/testing/setup_and_teardown'
5
- require 'active_support/testing/assertions'
6
- require 'active_support/testing/deprecation'
7
- require 'active_support/testing/declarative'
8
- require 'active_support/testing/isolation'
9
- require 'active_support/testing/constant_lookup'
10
- require 'active_support/testing/time_helpers'
11
- require 'active_support/testing/file_fixtures'
12
- require 'active_support/core_ext/kernel/reporting'
1
+ # frozen_string_literal: true
2
+
3
+ gem "minitest" # make sure we get the gem, not stdlib
4
+ require "minitest"
5
+ require "active_support/testing/tagged_logging"
6
+ require "active_support/testing/setup_and_teardown"
7
+ require "active_support/testing/assertions"
8
+ require "active_support/testing/deprecation"
9
+ require "active_support/testing/declarative"
10
+ require "active_support/testing/isolation"
11
+ require "active_support/testing/constant_lookup"
12
+ require "active_support/testing/time_helpers"
13
+ require "active_support/testing/file_fixtures"
14
+ require "active_support/testing/parallelization"
15
+ require "concurrent/utility/processor_counter"
13
16
 
14
17
  module ActiveSupport
15
18
  class TestCase < ::Minitest::Test
@@ -38,12 +41,101 @@ module ActiveSupport
38
41
  def test_order
39
42
  ActiveSupport.test_order ||= :random
40
43
  end
44
+
45
+ # Parallelizes the test suite.
46
+ #
47
+ # Takes a +workers+ argument that controls how many times the process
48
+ # is forked. For each process a new database will be created suffixed
49
+ # with the worker number.
50
+ #
51
+ # test-database-0
52
+ # test-database-1
53
+ #
54
+ # If <tt>ENV["PARALLEL_WORKERS"]</tt> is set the workers argument will be ignored
55
+ # and the environment variable will be used instead. This is useful for CI
56
+ # environments, or other environments where you may need more workers than
57
+ # you do for local testing.
58
+ #
59
+ # If the number of workers is set to +1+ or fewer, the tests will not be
60
+ # parallelized.
61
+ #
62
+ # If +workers+ is set to +:number_of_processors+, the number of workers will be
63
+ # set to the actual core count on the machine you are on.
64
+ #
65
+ # The default parallelization method is to fork processes. If you'd like to
66
+ # use threads instead you can pass <tt>with: :threads</tt> to the +parallelize+
67
+ # method. Note the threaded parallelization does not create multiple
68
+ # database and will not work with system tests at this time.
69
+ #
70
+ # parallelize(workers: :number_of_processors, with: :threads)
71
+ #
72
+ # The threaded parallelization uses minitest's parallel executor directly.
73
+ # The processes parallelization uses a Ruby DRb server.
74
+ def parallelize(workers: :number_of_processors, with: :processes)
75
+ workers = Concurrent.physical_processor_count if workers == :number_of_processors
76
+ workers = ENV["PARALLEL_WORKERS"].to_i if ENV["PARALLEL_WORKERS"]
77
+
78
+ return if workers <= 1
79
+
80
+ executor = case with
81
+ when :processes
82
+ Testing::Parallelization.new(workers)
83
+ when :threads
84
+ Minitest::Parallel::Executor.new(workers)
85
+ else
86
+ raise ArgumentError, "#{with} is not a supported parallelization executor."
87
+ end
88
+
89
+ self.lock_threads = false if defined?(self.lock_threads) && with == :threads
90
+
91
+ Minitest.parallel_executor = executor
92
+
93
+ parallelize_me!
94
+ end
95
+
96
+ # Set up hook for parallel testing. This can be used if you have multiple
97
+ # databases or any behavior that needs to be run after the process is forked
98
+ # but before the tests run.
99
+ #
100
+ # Note: this feature is not available with the threaded parallelization.
101
+ #
102
+ # In your +test_helper.rb+ add the following:
103
+ #
104
+ # class ActiveSupport::TestCase
105
+ # parallelize_setup do
106
+ # # create databases
107
+ # end
108
+ # end
109
+ def parallelize_setup(&block)
110
+ ActiveSupport::Testing::Parallelization.after_fork_hook do |worker|
111
+ yield worker
112
+ end
113
+ end
114
+
115
+ # Clean up hook for parallel testing. This can be used to drop databases
116
+ # if your app uses multiple write/read databases or other clean up before
117
+ # the tests finish. This runs before the forked process is closed.
118
+ #
119
+ # Note: this feature is not available with the threaded parallelization.
120
+ #
121
+ # In your +test_helper.rb+ add the following:
122
+ #
123
+ # class ActiveSupport::TestCase
124
+ # parallelize_teardown do
125
+ # # drop databases
126
+ # end
127
+ # end
128
+ def parallelize_teardown(&block)
129
+ ActiveSupport::Testing::Parallelization.run_cleanup_hook do |worker|
130
+ yield worker
131
+ end
132
+ end
41
133
  end
42
134
 
43
135
  alias_method :method_name, :name
44
136
 
45
137
  include ActiveSupport::Testing::TaggedLogging
46
- include ActiveSupport::Testing::SetupAndTeardown
138
+ prepend ActiveSupport::Testing::SetupAndTeardown
47
139
  include ActiveSupport::Testing::Assertions
48
140
  include ActiveSupport::Testing::Deprecation
49
141
  include ActiveSupport::Testing::TimeHelpers
@@ -66,21 +158,6 @@ module ActiveSupport
66
158
  alias :assert_not_respond_to :refute_respond_to
67
159
  alias :assert_not_same :refute_same
68
160
 
69
-
70
- # Assertion that the block should not raise an exception.
71
- #
72
- # Passes if evaluated code in the yielded block raises no exception.
73
- #
74
- # assert_nothing_raised do
75
- # perform_service(param: 'no_exception')
76
- # end
77
- def assert_nothing_raised(*args)
78
- if args.present?
79
- ActiveSupport::Deprecation.warn(
80
- "Passing arguments to assert_nothing_raised " \
81
- "is deprecated and will be removed in Rails 5.1.")
82
- end
83
- yield
84
- end
161
+ ActiveSupport.run_load_hooks(:active_support_test_case, self)
85
162
  end
86
163
  end
@@ -1,8 +1,12 @@
1
- require 'active_support/core_ext/object/blank'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/enumerable"
2
4
 
3
5
  module ActiveSupport
4
6
  module Testing
5
7
  module Assertions
8
+ UNTRACKED = Object.new # :nodoc:
9
+
6
10
  # Asserts that an expression is not truthy. Passes if <tt>object</tt> is
7
11
  # +nil+ or +false+. "Truthy" means "considered true in a conditional"
8
12
  # like <tt>if foo</tt>.
@@ -19,6 +23,19 @@ module ActiveSupport
19
23
  assert !object, message
20
24
  end
21
25
 
26
+ # Assertion that the block should not raise an exception.
27
+ #
28
+ # Passes if evaluated code in the yielded block raises no exception.
29
+ #
30
+ # assert_nothing_raised do
31
+ # perform_service(param: 'no_exception')
32
+ # end
33
+ def assert_nothing_raised
34
+ yield
35
+ rescue => error
36
+ raise Minitest::UnexpectedError.new(error)
37
+ end
38
+
22
39
  # Test numeric difference between the return value of an expression as a
23
40
  # result of what is evaluated in the yielded block.
24
41
  #
@@ -45,6 +62,12 @@ module ActiveSupport
45
62
  # post :create, params: { article: {...} }
46
63
  # end
47
64
  #
65
+ # A hash of expressions/numeric differences can also be passed in and evaluated.
66
+ #
67
+ # assert_difference ->{ Article.count } => 1, ->{ Notification.count } => 2 do
68
+ # post :create, params: { article: {...} }
69
+ # end
70
+ #
48
71
  # A lambda or a list of lambdas can be passed in and evaluated:
49
72
  #
50
73
  # assert_difference ->{ Article.count }, 2 do
@@ -60,20 +83,28 @@ module ActiveSupport
60
83
  # assert_difference 'Article.count', -1, 'An Article should be destroyed' do
61
84
  # post :delete, params: { id: ... }
62
85
  # end
63
- def assert_difference(expression, difference = 1, message = nil, &block)
64
- expressions = Array(expression)
86
+ def assert_difference(expression, *args, &block)
87
+ expressions =
88
+ if expression.is_a?(Hash)
89
+ message = args[0]
90
+ expression
91
+ else
92
+ difference = args[0] || 1
93
+ message = args[1]
94
+ Array(expression).index_with(difference)
95
+ end
65
96
 
66
- exps = expressions.map { |e|
97
+ exps = expressions.keys.map { |e|
67
98
  e.respond_to?(:call) ? e : lambda { eval(e, block.binding) }
68
99
  }
69
100
  before = exps.map(&:call)
70
101
 
71
- retval = yield
102
+ retval = assert_nothing_raised(&block)
72
103
 
73
- expressions.zip(exps).each_with_index do |(code, e), i|
74
- error = "#{code.inspect} didn't change by #{difference}"
104
+ expressions.zip(exps, before) do |(code, diff), exp, before_value|
105
+ error = "#{code.inspect} didn't change by #{diff}"
75
106
  error = "#{message}.\n#{error}" if message
76
- assert_equal(before[i] + difference, e.call, error)
107
+ assert_equal(before_value + diff, exp.call, error)
77
108
  end
78
109
 
79
110
  retval
@@ -86,14 +117,119 @@ module ActiveSupport
86
117
  # post :create, params: { article: invalid_attributes }
87
118
  # end
88
119
  #
120
+ # A lambda can be passed in and evaluated.
121
+ #
122
+ # assert_no_difference -> { Article.count } do
123
+ # post :create, params: { article: invalid_attributes }
124
+ # end
125
+ #
89
126
  # An error message can be specified.
90
127
  #
91
128
  # assert_no_difference 'Article.count', 'An Article should not be created' do
92
129
  # post :create, params: { article: invalid_attributes }
93
130
  # end
131
+ #
132
+ # An array of expressions can also be passed in and evaluated.
133
+ #
134
+ # assert_no_difference [ 'Article.count', -> { Post.count } ] do
135
+ # post :create, params: { article: invalid_attributes }
136
+ # end
94
137
  def assert_no_difference(expression, message = nil, &block)
95
138
  assert_difference expression, 0, message, &block
96
139
  end
140
+
141
+ # Assertion that the result of evaluating an expression is changed before
142
+ # and after invoking the passed in block.
143
+ #
144
+ # assert_changes 'Status.all_good?' do
145
+ # post :create, params: { status: { ok: false } }
146
+ # end
147
+ #
148
+ # You can pass the block as a string to be evaluated in the context of
149
+ # the block. A lambda can be passed for the block as well.
150
+ #
151
+ # assert_changes -> { Status.all_good? } do
152
+ # post :create, params: { status: { ok: false } }
153
+ # end
154
+ #
155
+ # The assertion is useful to test side effects. The passed block can be
156
+ # anything that can be converted to string with #to_s.
157
+ #
158
+ # assert_changes :@object do
159
+ # @object = 42
160
+ # end
161
+ #
162
+ # The keyword arguments :from and :to can be given to specify the
163
+ # expected initial value and the expected value after the block was
164
+ # executed.
165
+ #
166
+ # assert_changes :@object, from: nil, to: :foo do
167
+ # @object = :foo
168
+ # end
169
+ #
170
+ # An error message can be specified.
171
+ #
172
+ # assert_changes -> { Status.all_good? }, 'Expected the status to be bad' do
173
+ # post :create, params: { status: { incident: true } }
174
+ # end
175
+ def assert_changes(expression, message = nil, from: UNTRACKED, to: UNTRACKED, &block)
176
+ exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) }
177
+
178
+ before = exp.call
179
+ retval = assert_nothing_raised(&block)
180
+
181
+ unless from == UNTRACKED
182
+ error = "Expected change from #{from.inspect}"
183
+ error = "#{message}.\n#{error}" if message
184
+ assert from === before, error
185
+ end
186
+
187
+ after = exp.call
188
+
189
+ error = "#{expression.inspect} didn't change"
190
+ error = "#{error}. It was already #{to}" if before == to
191
+ error = "#{message}.\n#{error}" if message
192
+ assert_not_equal before, after, error
193
+
194
+ unless to == UNTRACKED
195
+ error = "Expected change to #{to}\n"
196
+ error = "#{message}.\n#{error}" if message
197
+ assert to === after, error
198
+ end
199
+
200
+ retval
201
+ end
202
+
203
+ # Assertion that the result of evaluating an expression is not changed before
204
+ # and after invoking the passed in block.
205
+ #
206
+ # assert_no_changes 'Status.all_good?' do
207
+ # post :create, params: { status: { ok: true } }
208
+ # end
209
+ #
210
+ # An error message can be specified.
211
+ #
212
+ # assert_no_changes -> { Status.all_good? }, 'Expected the status to be good' do
213
+ # post :create, params: { status: { ok: false } }
214
+ # end
215
+ def assert_no_changes(expression, message = nil, &block)
216
+ exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) }
217
+
218
+ before = exp.call
219
+ retval = assert_nothing_raised(&block)
220
+ after = exp.call
221
+
222
+ error = "#{expression.inspect} changed"
223
+ error = "#{message}.\n#{error}" if message
224
+
225
+ if before.nil?
226
+ assert_nil after, error
227
+ else
228
+ assert_equal before, after, error
229
+ end
230
+
231
+ retval
232
+ end
97
233
  end
98
234
  end
99
235
  end
@@ -1,12 +1,7 @@
1
- gem 'minitest'
1
+ # frozen_string_literal: true
2
2
 
3
- require 'minitest'
3
+ gem "minitest"
4
4
 
5
- if Minitest.respond_to?(:run_with_rails_extension)
6
- unless Minitest.run_with_rails_extension
7
- Minitest.run_with_autorun = true
8
- Minitest.autorun
9
- end
10
- else
11
- Minitest.autorun
12
- end
5
+ require "minitest"
6
+
7
+ Minitest.autorun
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/concern"
2
4
  require "active_support/inflector"
3
5
 
@@ -44,7 +46,6 @@ module ActiveSupport
44
46
  end
45
47
  end
46
48
  end
47
-
48
49
  end
49
50
  end
50
51
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveSupport
2
4
  module Testing
3
5
  module Declarative
@@ -9,7 +11,7 @@ module ActiveSupport
9
11
  # ...
10
12
  # end
11
13
  def test(name, &block)
12
- test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym
14
+ test_name = "test_#{name.gsub(/\s+/, '_')}".to_sym
13
15
  defined = method_defined? test_name
14
16
  raise "#{test_name} is already defined in #{self}" if defined
15
17
  if block_given?