activesupport 6.1.0 → 7.1.5.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 (225) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1075 -325
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +7 -7
  5. data/lib/active_support/actionable_error.rb +4 -2
  6. data/lib/active_support/array_inquirer.rb +2 -2
  7. data/lib/active_support/backtrace_cleaner.rb +32 -7
  8. data/lib/active_support/benchmarkable.rb +3 -2
  9. data/lib/active_support/broadcast_logger.rb +251 -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 +53 -20
  14. data/lib/active_support/cache/mem_cache_store.rb +201 -62
  15. data/lib/active_support/cache/memory_store.rb +86 -24
  16. data/lib/active_support/cache/null_store.rb +16 -2
  17. data/lib/active_support/cache/redis_cache_store.rb +186 -193
  18. data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
  19. data/lib/active_support/cache/strategy/local_cache.rb +63 -71
  20. data/lib/active_support/cache.rb +487 -249
  21. data/lib/active_support/callbacks.rb +227 -105
  22. data/lib/active_support/code_generator.rb +70 -0
  23. data/lib/active_support/concern.rb +9 -7
  24. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +44 -7
  25. data/lib/active_support/concurrency/null_lock.rb +13 -0
  26. data/lib/active_support/concurrency/share_lock.rb +2 -2
  27. data/lib/active_support/configurable.rb +18 -5
  28. data/lib/active_support/configuration_file.rb +7 -2
  29. data/lib/active_support/core_ext/array/access.rb +1 -5
  30. data/lib/active_support/core_ext/array/conversions.rb +15 -13
  31. data/lib/active_support/core_ext/array/grouping.rb +6 -6
  32. data/lib/active_support/core_ext/array/inquiry.rb +2 -2
  33. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  34. data/lib/active_support/core_ext/class/subclasses.rb +37 -26
  35. data/lib/active_support/core_ext/date/blank.rb +1 -1
  36. data/lib/active_support/core_ext/date/calculations.rb +24 -9
  37. data/lib/active_support/core_ext/date/conversions.rb +16 -15
  38. data/lib/active_support/core_ext/date_and_time/calculations.rb +14 -4
  39. data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
  40. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  41. data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
  42. data/lib/active_support/core_ext/date_time/conversions.rb +19 -15
  43. data/lib/active_support/core_ext/digest/uuid.rb +30 -13
  44. data/lib/active_support/core_ext/enumerable.rb +85 -83
  45. data/lib/active_support/core_ext/erb/util.rb +196 -0
  46. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  47. data/lib/active_support/core_ext/hash/conversions.rb +1 -2
  48. data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
  49. data/lib/active_support/core_ext/hash/deep_transform_values.rb +3 -3
  50. data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
  51. data/lib/active_support/core_ext/hash/keys.rb +4 -4
  52. data/lib/active_support/core_ext/integer/inflections.rb +12 -12
  53. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  54. data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
  55. data/lib/active_support/core_ext/module/attribute_accessors.rb +8 -0
  56. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +49 -22
  57. data/lib/active_support/core_ext/module/concerning.rb +6 -6
  58. data/lib/active_support/core_ext/module/delegation.rb +81 -43
  59. data/lib/active_support/core_ext/module/deprecation.rb +15 -12
  60. data/lib/active_support/core_ext/module/introspection.rb +0 -1
  61. data/lib/active_support/core_ext/name_error.rb +2 -8
  62. data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
  63. data/lib/active_support/core_ext/numeric/conversions.rb +82 -77
  64. data/lib/active_support/core_ext/object/acts_like.rb +29 -5
  65. data/lib/active_support/core_ext/object/blank.rb +2 -2
  66. data/lib/active_support/core_ext/object/deep_dup.rb +17 -1
  67. data/lib/active_support/core_ext/object/duplicable.rb +31 -11
  68. data/lib/active_support/core_ext/object/inclusion.rb +13 -5
  69. data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
  70. data/lib/active_support/core_ext/object/json.rb +49 -27
  71. data/lib/active_support/core_ext/object/to_query.rb +2 -4
  72. data/lib/active_support/core_ext/object/try.rb +20 -20
  73. data/lib/active_support/core_ext/object/with.rb +44 -0
  74. data/lib/active_support/core_ext/object/with_options.rb +25 -6
  75. data/lib/active_support/core_ext/object.rb +1 -0
  76. data/lib/active_support/core_ext/pathname/blank.rb +16 -0
  77. data/lib/active_support/core_ext/pathname/existence.rb +23 -0
  78. data/lib/active_support/core_ext/pathname.rb +4 -0
  79. data/lib/active_support/core_ext/range/compare_range.rb +0 -25
  80. data/lib/active_support/core_ext/range/conversions.rb +34 -13
  81. data/lib/active_support/core_ext/range/each.rb +1 -1
  82. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  83. data/lib/active_support/core_ext/range.rb +1 -2
  84. data/lib/active_support/core_ext/securerandom.rb +25 -13
  85. data/lib/active_support/core_ext/string/conversions.rb +2 -2
  86. data/lib/active_support/core_ext/string/filters.rb +21 -15
  87. data/lib/active_support/core_ext/string/indent.rb +1 -1
  88. data/lib/active_support/core_ext/string/inflections.rb +17 -10
  89. data/lib/active_support/core_ext/string/inquiry.rb +1 -1
  90. data/lib/active_support/core_ext/string/output_safety.rb +85 -165
  91. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
  92. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  93. data/lib/active_support/core_ext/time/calculations.rb +30 -8
  94. data/lib/active_support/core_ext/time/conversions.rb +15 -13
  95. data/lib/active_support/core_ext/time/zones.rb +12 -28
  96. data/lib/active_support/core_ext.rb +2 -1
  97. data/lib/active_support/current_attributes.rb +47 -20
  98. data/lib/active_support/deep_mergeable.rb +53 -0
  99. data/lib/active_support/dependencies/autoload.rb +17 -12
  100. data/lib/active_support/dependencies/interlock.rb +10 -18
  101. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  102. data/lib/active_support/dependencies.rb +58 -788
  103. data/lib/active_support/deprecation/behaviors.rb +66 -40
  104. data/lib/active_support/deprecation/constant_accessor.rb +5 -4
  105. data/lib/active_support/deprecation/deprecators.rb +104 -0
  106. data/lib/active_support/deprecation/disallowed.rb +6 -8
  107. data/lib/active_support/deprecation/instance_delegator.rb +31 -4
  108. data/lib/active_support/deprecation/method_wrappers.rb +9 -26
  109. data/lib/active_support/deprecation/proxy_wrappers.rb +38 -23
  110. data/lib/active_support/deprecation/reporting.rb +43 -26
  111. data/lib/active_support/deprecation.rb +32 -5
  112. data/lib/active_support/deprecator.rb +7 -0
  113. data/lib/active_support/descendants_tracker.rb +150 -72
  114. data/lib/active_support/digest.rb +5 -3
  115. data/lib/active_support/duration/iso8601_parser.rb +3 -3
  116. data/lib/active_support/duration/iso8601_serializer.rb +9 -3
  117. data/lib/active_support/duration.rb +83 -52
  118. data/lib/active_support/encrypted_configuration.rb +72 -9
  119. data/lib/active_support/encrypted_file.rb +29 -13
  120. data/lib/active_support/environment_inquirer.rb +23 -3
  121. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  122. data/lib/active_support/error_reporter.rb +203 -0
  123. data/lib/active_support/evented_file_update_checker.rb +20 -7
  124. data/lib/active_support/execution_context/test_helper.rb +13 -0
  125. data/lib/active_support/execution_context.rb +53 -0
  126. data/lib/active_support/execution_wrapper.rb +44 -22
  127. data/lib/active_support/executor/test_helper.rb +7 -0
  128. data/lib/active_support/file_update_checker.rb +4 -2
  129. data/lib/active_support/fork_tracker.rb +28 -11
  130. data/lib/active_support/gem_version.rb +4 -4
  131. data/lib/active_support/gzip.rb +2 -0
  132. data/lib/active_support/hash_with_indifferent_access.rb +44 -19
  133. data/lib/active_support/html_safe_translation.rb +53 -0
  134. data/lib/active_support/i18n.rb +2 -1
  135. data/lib/active_support/i18n_railtie.rb +21 -14
  136. data/lib/active_support/inflector/inflections.rb +25 -7
  137. data/lib/active_support/inflector/methods.rb +50 -64
  138. data/lib/active_support/inflector/transliterate.rb +4 -2
  139. data/lib/active_support/isolated_execution_state.rb +76 -0
  140. data/lib/active_support/json/decoding.rb +2 -1
  141. data/lib/active_support/json/encoding.rb +27 -45
  142. data/lib/active_support/key_generator.rb +31 -6
  143. data/lib/active_support/lazy_load_hooks.rb +33 -7
  144. data/lib/active_support/locale/en.yml +4 -2
  145. data/lib/active_support/log_subscriber/test_helper.rb +2 -2
  146. data/lib/active_support/log_subscriber.rb +97 -35
  147. data/lib/active_support/logger.rb +9 -60
  148. data/lib/active_support/logger_thread_safe_level.rb +11 -34
  149. data/lib/active_support/message_encryptor.rb +206 -56
  150. data/lib/active_support/message_encryptors.rb +141 -0
  151. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  152. data/lib/active_support/message_pack/extensions.rb +292 -0
  153. data/lib/active_support/message_pack/serializer.rb +63 -0
  154. data/lib/active_support/message_pack.rb +50 -0
  155. data/lib/active_support/message_verifier.rb +235 -84
  156. data/lib/active_support/message_verifiers.rb +135 -0
  157. data/lib/active_support/messages/codec.rb +65 -0
  158. data/lib/active_support/messages/metadata.rb +112 -46
  159. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  160. data/lib/active_support/messages/rotator.rb +34 -32
  161. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  162. data/lib/active_support/multibyte/chars.rb +12 -11
  163. data/lib/active_support/multibyte/unicode.rb +9 -49
  164. data/lib/active_support/multibyte.rb +1 -1
  165. data/lib/active_support/notifications/fanout.rb +304 -114
  166. data/lib/active_support/notifications/instrumenter.rb +117 -35
  167. data/lib/active_support/notifications.rb +25 -25
  168. data/lib/active_support/number_helper/number_converter.rb +14 -7
  169. data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
  170. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  171. data/lib/active_support/number_helper/number_to_human_size_converter.rb +4 -4
  172. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
  173. data/lib/active_support/number_helper/number_to_rounded_converter.rb +10 -6
  174. data/lib/active_support/number_helper/rounding_helper.rb +2 -6
  175. data/lib/active_support/number_helper.rb +379 -319
  176. data/lib/active_support/option_merger.rb +10 -18
  177. data/lib/active_support/ordered_hash.rb +4 -4
  178. data/lib/active_support/ordered_options.rb +15 -1
  179. data/lib/active_support/parameter_filter.rb +105 -81
  180. data/lib/active_support/proxy_object.rb +2 -0
  181. data/lib/active_support/railtie.rb +83 -21
  182. data/lib/active_support/reloader.rb +13 -5
  183. data/lib/active_support/rescuable.rb +18 -16
  184. data/lib/active_support/ruby_features.rb +7 -0
  185. data/lib/active_support/secure_compare_rotator.rb +18 -11
  186. data/lib/active_support/security_utils.rb +1 -1
  187. data/lib/active_support/string_inquirer.rb +3 -3
  188. data/lib/active_support/subscriber.rb +11 -40
  189. data/lib/active_support/syntax_error_proxy.rb +60 -0
  190. data/lib/active_support/tagged_logging.rb +65 -25
  191. data/lib/active_support/test_case.rb +166 -27
  192. data/lib/active_support/testing/assertions.rb +61 -15
  193. data/lib/active_support/testing/autorun.rb +0 -2
  194. data/lib/active_support/testing/constant_stubbing.rb +32 -0
  195. data/lib/active_support/testing/deprecation.rb +53 -2
  196. data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
  197. data/lib/active_support/testing/isolation.rb +30 -29
  198. data/lib/active_support/testing/method_call_assertions.rb +24 -11
  199. data/lib/active_support/testing/parallelization/server.rb +4 -0
  200. data/lib/active_support/testing/parallelization/worker.rb +3 -0
  201. data/lib/active_support/testing/parallelization.rb +4 -0
  202. data/lib/active_support/testing/parallelize_executor.rb +81 -0
  203. data/lib/active_support/testing/setup_and_teardown.rb +2 -0
  204. data/lib/active_support/testing/stream.rb +4 -6
  205. data/lib/active_support/testing/strict_warnings.rb +39 -0
  206. data/lib/active_support/testing/tagged_logging.rb +1 -1
  207. data/lib/active_support/testing/time_helpers.rb +49 -16
  208. data/lib/active_support/time_with_zone.rb +39 -28
  209. data/lib/active_support/values/time_zone.rb +50 -18
  210. data/lib/active_support/version.rb +1 -1
  211. data/lib/active_support/xml_mini/jdom.rb +4 -11
  212. data/lib/active_support/xml_mini/libxml.rb +5 -5
  213. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  214. data/lib/active_support/xml_mini/nokogiri.rb +5 -5
  215. data/lib/active_support/xml_mini/nokogirisax.rb +2 -2
  216. data/lib/active_support/xml_mini/rexml.rb +2 -2
  217. data/lib/active_support/xml_mini.rb +7 -6
  218. data/lib/active_support.rb +28 -1
  219. metadata +150 -18
  220. data/lib/active_support/core_ext/marshal.rb +0 -26
  221. data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -28
  222. data/lib/active_support/core_ext/range/overlaps.rb +0 -10
  223. data/lib/active_support/core_ext/uri.rb +0 -29
  224. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
  225. data/lib/active_support/per_thread_registry.rb +0 -60
@@ -5,29 +5,32 @@ require "active_support/descendants_tracker"
5
5
  require "active_support/core_ext/array/extract_options"
6
6
  require "active_support/core_ext/class/attribute"
7
7
  require "active_support/core_ext/string/filters"
8
+ require "active_support/core_ext/object/blank"
8
9
  require "thread"
9
10
 
10
11
  module ActiveSupport
11
- # Callbacks are code hooks that are run at key points in an object's life cycle.
12
+ # = Active Support \Callbacks
13
+ #
14
+ # \Callbacks are code hooks that are run at key points in an object's life cycle.
12
15
  # The typical use case is to have a base class define a set of callbacks
13
16
  # relevant to the other functionality it supplies, so that subclasses can
14
17
  # install callbacks that enhance or modify the base functionality without
15
18
  # needing to override or redefine methods of the base class.
16
19
  #
17
20
  # Mixing in this module allows you to define the events in the object's
18
- # life cycle that will support callbacks (via +ClassMethods.define_callbacks+),
21
+ # life cycle that will support callbacks (via ClassMethods#define_callbacks),
19
22
  # set the instance methods, procs, or callback objects to be called (via
20
- # +ClassMethods.set_callback+), and run the installed callbacks at the
23
+ # ClassMethods#set_callback), and run the installed callbacks at the
21
24
  # appropriate times (via +run_callbacks+).
22
25
  #
23
26
  # By default callbacks are halted by throwing +:abort+.
24
- # See +ClassMethods.define_callbacks+ for details.
27
+ # See ClassMethods#define_callbacks for details.
25
28
  #
26
29
  # Three kinds of callbacks are supported: before callbacks, run before a
27
30
  # certain event; after callbacks, run after the event; and around callbacks,
28
31
  # blocks that surround the event, triggering it when they yield. Callback code
29
32
  # can be contained in instance methods, procs or lambdas, or callback objects
30
- # that respond to certain predetermined methods. See +ClassMethods.set_callback+
33
+ # that respond to certain predetermined methods. See ClassMethods#set_callback
31
34
  # for details.
32
35
  #
33
36
  # class Record
@@ -67,7 +70,7 @@ module ActiveSupport
67
70
  class_attribute :__callbacks, instance_writer: false, default: {}
68
71
  end
69
72
 
70
- CALLBACK_FILTER_TYPES = [:before, :after, :around]
73
+ CALLBACK_FILTER_TYPES = [:before, :after, :around].freeze
71
74
 
72
75
  # Runs the callbacks for the given event.
73
76
  #
@@ -91,14 +94,15 @@ module ActiveSupport
91
94
  # callback can be as noisy as it likes -- but when control has passed
92
95
  # smoothly through and into the supplied block, we want as little evidence
93
96
  # as possible that we were here.
94
- def run_callbacks(kind)
97
+ def run_callbacks(kind, type = nil)
95
98
  callbacks = __callbacks[kind.to_sym]
96
99
 
97
100
  if callbacks.empty?
98
101
  yield if block_given?
99
102
  else
100
103
  env = Filters::Environment.new(self, false, nil)
101
- next_sequence = callbacks.compile
104
+
105
+ next_sequence = callbacks.compile(type)
102
106
 
103
107
  # Common case: no 'around' callbacks defined
104
108
  if next_sequence.final?
@@ -276,7 +280,7 @@ module ActiveSupport
276
280
  end
277
281
  end
278
282
 
279
- class Callback #:nodoc:#
283
+ class Callback # :nodoc:#
280
284
  def self.build(chain, filter, kind, options)
281
285
  if filter.is_a?(String)
282
286
  raise ArgumentError, <<-MSG.squish
@@ -289,21 +293,17 @@ module ActiveSupport
289
293
  end
290
294
 
291
295
  attr_accessor :kind, :name
292
- attr_reader :chain_config
296
+ attr_reader :chain_config, :filter
293
297
 
294
298
  def initialize(name, filter, kind, options, chain_config)
295
299
  @chain_config = chain_config
296
300
  @name = name
297
301
  @kind = kind
298
302
  @filter = filter
299
- @key = compute_identifier filter
300
303
  @if = check_conditionals(options[:if])
301
304
  @unless = check_conditionals(options[:unless])
302
305
  end
303
306
 
304
- def filter; @key; end
305
- def raw_filter; @filter; end
306
-
307
307
  def merge_conditional_options(chain, if_option:, unless_option:)
308
308
  options = {
309
309
  if: @if.dup,
@@ -356,7 +356,7 @@ module ActiveSupport
356
356
  return EMPTY_ARRAY if conditionals.blank?
357
357
 
358
358
  conditionals = Array(conditionals)
359
- if conditionals.any? { |c| c.is_a?(String) }
359
+ if conditionals.any?(String)
360
360
  raise ArgumentError, <<-MSG.squish
361
361
  Passing string to be evaluated in :if and :unless conditional
362
362
  options is not supported. Pass a symbol for an instance method,
@@ -367,15 +367,6 @@ module ActiveSupport
367
367
  conditionals.freeze
368
368
  end
369
369
 
370
- def compute_identifier(filter)
371
- case filter
372
- when ::Proc
373
- filter.object_id
374
- else
375
- filter
376
- end
377
- end
378
-
379
370
  def conditions_lambdas
380
371
  @if.map { |c| CallTemplate.build(c, self).make_lambda } +
381
372
  @unless.map { |c| CallTemplate.build(c, self).inverted_lambda }
@@ -384,56 +375,153 @@ module ActiveSupport
384
375
 
385
376
  # A future invocation of user-supplied code (either as a callback,
386
377
  # or a condition filter).
387
- class CallTemplate # :nodoc:
388
- def initialize(target, method, arguments, block)
389
- @override_target = target
390
- @method_name = method
391
- @arguments = arguments
392
- @override_block = block
378
+ module CallTemplate # :nodoc:
379
+ class MethodCall
380
+ def initialize(method)
381
+ @method_name = method
382
+ end
383
+
384
+ # Return the parts needed to make this call, with the given
385
+ # input values.
386
+ #
387
+ # Returns an array of the form:
388
+ #
389
+ # [target, block, method, *arguments]
390
+ #
391
+ # This array can be used as such:
392
+ #
393
+ # target.send(method, *arguments, &block)
394
+ #
395
+ # The actual invocation is left up to the caller to minimize
396
+ # call stack pollution.
397
+ def expand(target, value, block)
398
+ [target, block, @method_name]
399
+ end
400
+
401
+ def make_lambda
402
+ lambda do |target, value, &block|
403
+ target.send(@method_name, &block)
404
+ end
405
+ end
406
+
407
+ def inverted_lambda
408
+ lambda do |target, value, &block|
409
+ !target.send(@method_name, &block)
410
+ end
411
+ end
393
412
  end
394
413
 
395
- # Return the parts needed to make this call, with the given
396
- # input values.
397
- #
398
- # Returns an array of the form:
399
- #
400
- # [target, block, method, *arguments]
401
- #
402
- # This array can be used as such:
403
- #
404
- # target.send(method, *arguments, &block)
405
- #
406
- # The actual invocation is left up to the caller to minimize
407
- # call stack pollution.
408
- def expand(target, value, block)
409
- expanded = [@override_target || target, @override_block || block, @method_name]
414
+ class ObjectCall
415
+ def initialize(target, method)
416
+ @override_target = target
417
+ @method_name = method
418
+ end
419
+
420
+ def expand(target, value, block)
421
+ [@override_target || target, block, @method_name, target]
422
+ end
423
+
424
+ def make_lambda
425
+ lambda do |target, value, &block|
426
+ (@override_target || target).send(@method_name, target, &block)
427
+ end
428
+ end
429
+
430
+ def inverted_lambda
431
+ lambda do |target, value, &block|
432
+ !(@override_target || target).send(@method_name, target, &block)
433
+ end
434
+ end
435
+ end
436
+
437
+ class InstanceExec0
438
+ def initialize(block)
439
+ @override_block = block
440
+ end
441
+
442
+ def expand(target, value, block)
443
+ [target, @override_block, :instance_exec]
444
+ end
445
+
446
+ def make_lambda
447
+ lambda do |target, value, &block|
448
+ target.instance_exec(&@override_block)
449
+ end
450
+ end
451
+
452
+ def inverted_lambda
453
+ lambda do |target, value, &block|
454
+ !target.instance_exec(&@override_block)
455
+ end
456
+ end
457
+ end
458
+
459
+ class InstanceExec1
460
+ def initialize(block)
461
+ @override_block = block
462
+ end
463
+
464
+ def expand(target, value, block)
465
+ [target, @override_block, :instance_exec, target]
466
+ end
410
467
 
411
- @arguments.each do |arg|
412
- case arg
413
- when :value then expanded << value
414
- when :target then expanded << target
415
- when :block then expanded << (block || raise(ArgumentError))
468
+ def make_lambda
469
+ lambda do |target, value, &block|
470
+ target.instance_exec(target, &@override_block)
416
471
  end
417
472
  end
418
473
 
419
- expanded
474
+ def inverted_lambda
475
+ lambda do |target, value, &block|
476
+ !target.instance_exec(target, &@override_block)
477
+ end
478
+ end
420
479
  end
421
480
 
422
- # Return a lambda that will make this call when given the input
423
- # values.
424
- def make_lambda
425
- lambda do |target, value, &block|
426
- target, block, method, *arguments = expand(target, value, block)
427
- target.send(method, *arguments, &block)
481
+ class InstanceExec2
482
+ def initialize(block)
483
+ @override_block = block
484
+ end
485
+
486
+ def expand(target, value, block)
487
+ raise ArgumentError unless block
488
+ [target, @override_block || block, :instance_exec, target, block]
489
+ end
490
+
491
+ def make_lambda
492
+ lambda do |target, value, &block|
493
+ raise ArgumentError unless block
494
+ target.instance_exec(target, block, &@override_block)
495
+ end
496
+ end
497
+
498
+ def inverted_lambda
499
+ lambda do |target, value, &block|
500
+ raise ArgumentError unless block
501
+ !target.instance_exec(target, block, &@override_block)
502
+ end
428
503
  end
429
504
  end
430
505
 
431
- # Return a lambda that will make this call when given the input
432
- # values, but then return the boolean inverse of that result.
433
- def inverted_lambda
434
- lambda do |target, value, &block|
435
- target, block, method, *arguments = expand(target, value, block)
436
- ! target.send(method, *arguments, &block)
506
+ class ProcCall
507
+ def initialize(target)
508
+ @override_target = target
509
+ end
510
+
511
+ def expand(target, value, block)
512
+ [@override_target || target, block, :call, target, value]
513
+ end
514
+
515
+ def make_lambda
516
+ lambda do |target, value, &block|
517
+ (@override_target || target).call(target, value, &block)
518
+ end
519
+ end
520
+
521
+ def inverted_lambda
522
+ lambda do |target, value, &block|
523
+ !(@override_target || target).call(target, value, &block)
524
+ end
437
525
  end
438
526
  end
439
527
 
@@ -448,21 +536,19 @@ module ActiveSupport
448
536
  def self.build(filter, callback)
449
537
  case filter
450
538
  when Symbol
451
- new(nil, filter, [], nil)
539
+ MethodCall.new(filter)
452
540
  when Conditionals::Value
453
- new(filter, :call, [:target, :value], nil)
541
+ ProcCall.new(filter)
454
542
  when ::Proc
455
543
  if filter.arity > 1
456
- new(nil, :instance_exec, [:target, :block], filter)
544
+ InstanceExec2.new(filter)
457
545
  elsif filter.arity > 0
458
- new(nil, :instance_exec, [:target], filter)
546
+ InstanceExec1.new(filter)
459
547
  else
460
- new(nil, :instance_exec, [], filter)
548
+ InstanceExec0.new(filter)
461
549
  end
462
550
  else
463
- method_to_call = callback.current_scopes.join("_")
464
-
465
- new(filter, method_to_call, [:target], nil)
551
+ ObjectCall.new(filter, callback.current_scopes.join("_").to_sym)
466
552
  end
467
553
  end
468
554
  end
@@ -517,7 +603,7 @@ module ActiveSupport
517
603
  end
518
604
  end
519
605
 
520
- class CallbackChain #:nodoc:#
606
+ class CallbackChain # :nodoc:
521
607
  include Enumerable
522
608
 
523
609
  attr_reader :name, :config
@@ -529,7 +615,8 @@ module ActiveSupport
529
615
  terminator: default_terminator
530
616
  }.merge!(config)
531
617
  @chain = []
532
- @callbacks = nil
618
+ @all_callbacks = nil
619
+ @single_callbacks = {}
533
620
  @mutex = Mutex.new
534
621
  end
535
622
 
@@ -538,32 +625,45 @@ module ActiveSupport
538
625
  def empty?; @chain.empty?; end
539
626
 
540
627
  def insert(index, o)
541
- @callbacks = nil
628
+ @all_callbacks = nil
629
+ @single_callbacks.clear
542
630
  @chain.insert(index, o)
543
631
  end
544
632
 
545
633
  def delete(o)
546
- @callbacks = nil
634
+ @all_callbacks = nil
635
+ @single_callbacks.clear
547
636
  @chain.delete(o)
548
637
  end
549
638
 
550
639
  def clear
551
- @callbacks = nil
640
+ @all_callbacks = nil
641
+ @single_callbacks.clear
552
642
  @chain.clear
553
643
  self
554
644
  end
555
645
 
556
646
  def initialize_copy(other)
557
- @callbacks = nil
647
+ @all_callbacks = nil
648
+ @single_callbacks = {}
558
649
  @chain = other.chain.dup
559
650
  @mutex = Mutex.new
560
651
  end
561
652
 
562
- def compile
563
- @callbacks || @mutex.synchronize do
564
- final_sequence = CallbackSequence.new
565
- @callbacks ||= @chain.reverse.inject(final_sequence) do |callback_sequence, callback|
566
- callback.apply callback_sequence
653
+ def compile(type)
654
+ if type.nil?
655
+ @all_callbacks || @mutex.synchronize do
656
+ final_sequence = CallbackSequence.new
657
+ @all_callbacks ||= @chain.reverse.inject(final_sequence) do |callback_sequence, callback|
658
+ callback.apply(callback_sequence)
659
+ end
660
+ end
661
+ else
662
+ @single_callbacks[type] || @mutex.synchronize do
663
+ final_sequence = CallbackSequence.new
664
+ @single_callbacks[type] ||= @chain.reverse.inject(final_sequence) do |callback_sequence, callback|
665
+ type == callback.kind ? callback.apply(callback_sequence) : callback_sequence
666
+ end
567
667
  end
568
668
  end
569
669
  end
@@ -581,19 +681,22 @@ module ActiveSupport
581
681
 
582
682
  private
583
683
  def append_one(callback)
584
- @callbacks = nil
684
+ @all_callbacks = nil
685
+ @single_callbacks.clear
585
686
  remove_duplicates(callback)
586
687
  @chain.push(callback)
587
688
  end
588
689
 
589
690
  def prepend_one(callback)
590
- @callbacks = nil
691
+ @all_callbacks = nil
692
+ @single_callbacks.clear
591
693
  remove_duplicates(callback)
592
694
  @chain.unshift(callback)
593
695
  end
594
696
 
595
697
  def remove_duplicates(callback)
596
- @callbacks = nil
698
+ @all_callbacks = nil
699
+ @single_callbacks.clear
597
700
  @chain.delete_if { |c| callback.duplicates?(c) }
598
701
  end
599
702
 
@@ -619,8 +722,8 @@ module ActiveSupport
619
722
 
620
723
  # This is used internally to append, prepend and skip callbacks to the
621
724
  # CallbackChain.
622
- def __update_callbacks(name) #:nodoc:
623
- ([self] + ActiveSupport::DescendantsTracker.descendants(self)).reverse_each do |target|
725
+ def __update_callbacks(name) # :nodoc:
726
+ self.descendants.prepend(self).reverse_each do |target|
624
727
  chain = target.get_callbacks name
625
728
  yield target, chain.dup
626
729
  end
@@ -640,7 +743,7 @@ module ActiveSupport
640
743
  #
641
744
  # The callback can be specified as a symbol naming an instance method; as a
642
745
  # proc, lambda, or block; or as an object that responds to a certain method
643
- # determined by the <tt>:scope</tt> argument to +define_callbacks+.
746
+ # determined by the <tt>:scope</tt> argument to #define_callbacks.
644
747
  #
645
748
  # If a proc, lambda, or block is given, its body is evaluated in the context
646
749
  # of the current object. It can also optionally accept the current object as
@@ -684,14 +787,39 @@ module ActiveSupport
684
787
  end
685
788
  end
686
789
 
687
- # Skip a previously set callback. Like +set_callback+, <tt>:if</tt> or
790
+ # Skip a previously set callback. Like #set_callback, <tt>:if</tt> or
688
791
  # <tt>:unless</tt> options may be passed in order to control when the
689
792
  # callback is skipped.
690
793
  #
691
- # class Writer < Person
692
- # skip_callback :validate, :before, :check_membership, if: -> { age > 18 }
794
+ # Note: this example uses +PersonRecord+ and +#saving_message+, which you
795
+ # can see defined here[rdoc-ref:ActiveSupport::Callbacks]
796
+ #
797
+ # class Writer < PersonRecord
798
+ # attr_accessor :age
799
+ # skip_callback :save, :before, :saving_message, if: -> { age > 18 }
693
800
  # end
694
801
  #
802
+ # When if option returns true, callback is skipped.
803
+ #
804
+ # writer = Writer.new
805
+ # writer.age = 20
806
+ # writer.save
807
+ #
808
+ # Output:
809
+ # - save
810
+ # saved
811
+ #
812
+ # When if option returns false, callback is NOT skipped.
813
+ #
814
+ # young_writer = Writer.new
815
+ # young_writer.age = 17
816
+ # young_writer.save
817
+ #
818
+ # Output:
819
+ # saving...
820
+ # - save
821
+ # saved
822
+ #
695
823
  # An <tt>ArgumentError</tt> will be raised if the callback has not
696
824
  # already been set (unless the <tt>:raise</tt> option is set to <tt>false</tt>).
697
825
  def skip_callback(name, *filter_list, &block)
@@ -722,7 +850,7 @@ module ActiveSupport
722
850
  def reset_callbacks(name)
723
851
  callbacks = get_callbacks name
724
852
 
725
- ActiveSupport::DescendantsTracker.descendants(self).each do |target|
853
+ self.descendants.each do |target|
726
854
  chain = target.get_callbacks(name).dup
727
855
  callbacks.each { |c| chain.delete(c) }
728
856
  target.set_callbacks name, chain
@@ -808,14 +936,14 @@ module ActiveSupport
808
936
  # <tt>!</tt>, <tt>?</tt> or <tt>=</tt>.
809
937
  #
810
938
  # Calling +define_callbacks+ multiple times with the same +names+ will
811
- # overwrite previous callbacks registered with +set_callback+.
939
+ # overwrite previous callbacks registered with #set_callback.
812
940
  def define_callbacks(*names)
813
941
  options = names.extract_options!
814
942
 
815
943
  names.each do |name|
816
944
  name = name.to_sym
817
945
 
818
- ([self] + ActiveSupport::DescendantsTracker.descendants(self)).each do |target|
946
+ ([self] + self.descendants).each do |target|
819
947
  target.set_callbacks name, CallbackChain.new(name, options)
820
948
  end
821
949
 
@@ -844,18 +972,12 @@ module ActiveSupport
844
972
  __callbacks[name.to_sym]
845
973
  end
846
974
 
847
- if Module.instance_method(:method_defined?).arity == 1 # Ruby 2.5 and older
848
- def set_callbacks(name, callbacks) # :nodoc:
849
- self.__callbacks = __callbacks.merge(name.to_sym => callbacks)
850
- end
851
- else # Ruby 2.6 and newer
852
- def set_callbacks(name, callbacks) # :nodoc:
853
- unless singleton_class.method_defined?(:__callbacks, false)
854
- self.__callbacks = __callbacks.dup
855
- end
856
- self.__callbacks[name.to_sym] = callbacks
857
- self.__callbacks
975
+ def set_callbacks(name, callbacks) # :nodoc:
976
+ unless singleton_class.method_defined?(:__callbacks, false)
977
+ self.__callbacks = __callbacks.dup
858
978
  end
979
+ self.__callbacks[name.to_sym] = callbacks
980
+ self.__callbacks
859
981
  end
860
982
  end
861
983
  end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ class CodeGenerator # :nodoc:
5
+ class MethodSet
6
+ METHOD_CACHES = Hash.new { |h, k| h[k] = Module.new }
7
+
8
+ def initialize(namespace)
9
+ @cache = METHOD_CACHES[namespace]
10
+ @sources = []
11
+ @methods = {}
12
+ @canonical_methods = {}
13
+ end
14
+
15
+ def define_cached_method(canonical_name, as: nil)
16
+ canonical_name = canonical_name.to_sym
17
+ as = (as || canonical_name).to_sym
18
+
19
+ @methods.fetch(as) do
20
+ unless @cache.method_defined?(canonical_name) || @canonical_methods[canonical_name]
21
+ yield @sources
22
+ end
23
+ @canonical_methods[canonical_name] = true
24
+ @methods[as] = canonical_name
25
+ end
26
+ end
27
+
28
+ def apply(owner, path, line)
29
+ unless @sources.empty?
30
+ @cache.module_eval("# frozen_string_literal: true\n" + @sources.join(";"), path, line)
31
+ end
32
+ @canonical_methods.clear
33
+
34
+ @methods.each do |as, canonical_name|
35
+ owner.define_method(as, @cache.instance_method(canonical_name))
36
+ end
37
+ end
38
+ end
39
+
40
+ class << self
41
+ def batch(owner, path, line)
42
+ if owner.is_a?(CodeGenerator)
43
+ yield owner
44
+ else
45
+ instance = new(owner, path, line)
46
+ result = yield instance
47
+ instance.execute
48
+ result
49
+ end
50
+ end
51
+ end
52
+
53
+ def initialize(owner, path, line)
54
+ @owner = owner
55
+ @path = path
56
+ @line = line
57
+ @namespaces = Hash.new { |h, k| h[k] = MethodSet.new(k) }
58
+ end
59
+
60
+ def define_cached_method(canonical_name, namespace:, as: nil, &block)
61
+ @namespaces[namespace].define_cached_method(canonical_name, as: as, &block)
62
+ end
63
+
64
+ def execute
65
+ @namespaces.each_value do |method_set|
66
+ method_set.apply(@owner, @path, @line - 1)
67
+ end
68
+ end
69
+ end
70
+ end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveSupport
4
+ # = Active Support \Concern
5
+ #
4
6
  # A typical module looks like this:
5
7
  #
6
8
  # module M
@@ -16,7 +18,7 @@ module ActiveSupport
16
18
  # end
17
19
  # end
18
20
  #
19
- # By using <tt>ActiveSupport::Concern</tt> the above module could instead be
21
+ # By using +ActiveSupport::Concern+ the above module could instead be
20
22
  # written as:
21
23
  #
22
24
  # require "active_support/concern"
@@ -73,7 +75,7 @@ module ActiveSupport
73
75
  # end
74
76
  #
75
77
  # Unfortunately this won't work, since when +Foo+ is included, its <tt>base</tt>
76
- # is the +Bar+ module, not the +Host+ class. With <tt>ActiveSupport::Concern</tt>,
78
+ # is the +Bar+ module, not the +Host+ class. With +ActiveSupport::Concern+,
77
79
  # module dependencies are properly resolved:
78
80
  #
79
81
  # require "active_support/concern"
@@ -108,23 +110,23 @@ module ActiveSupport
108
110
  #
109
111
  # <tt>prepend</tt> is also used for any dependencies.
110
112
  module Concern
111
- class MultipleIncludedBlocks < StandardError #:nodoc:
113
+ class MultipleIncludedBlocks < StandardError # :nodoc:
112
114
  def initialize
113
115
  super "Cannot define multiple 'included' blocks for a Concern"
114
116
  end
115
117
  end
116
118
 
117
- class MultiplePrependBlocks < StandardError #:nodoc:
119
+ class MultiplePrependBlocks < StandardError # :nodoc:
118
120
  def initialize
119
121
  super "Cannot define multiple 'prepended' blocks for a Concern"
120
122
  end
121
123
  end
122
124
 
123
- def self.extended(base) #:nodoc:
125
+ def self.extended(base) # :nodoc:
124
126
  base.instance_variable_set(:@_dependencies, [])
125
127
  end
126
128
 
127
- def append_features(base) #:nodoc:
129
+ def append_features(base) # :nodoc:
128
130
  if base.instance_variable_defined?(:@_dependencies)
129
131
  base.instance_variable_get(:@_dependencies) << self
130
132
  false
@@ -137,7 +139,7 @@ module ActiveSupport
137
139
  end
138
140
  end
139
141
 
140
- def prepend_features(base) #:nodoc:
142
+ def prepend_features(base) # :nodoc:
141
143
  if base.instance_variable_defined?(:@_dependencies)
142
144
  base.instance_variable_get(:@_dependencies).unshift self
143
145
  false