activesupport 6.1.4.1 → 7.0.8.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (185) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +325 -395
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -2
  5. data/lib/active_support/actionable_error.rb +1 -1
  6. data/lib/active_support/array_inquirer.rb +0 -2
  7. data/lib/active_support/backtrace_cleaner.rb +2 -2
  8. data/lib/active_support/benchmarkable.rb +2 -2
  9. data/lib/active_support/cache/file_store.rb +15 -9
  10. data/lib/active_support/cache/mem_cache_store.rb +148 -37
  11. data/lib/active_support/cache/memory_store.rb +24 -16
  12. data/lib/active_support/cache/null_store.rb +10 -2
  13. data/lib/active_support/cache/redis_cache_store.rb +68 -85
  14. data/lib/active_support/cache/strategy/local_cache.rb +38 -61
  15. data/lib/active_support/cache.rb +299 -147
  16. data/lib/active_support/callbacks.rb +184 -85
  17. data/lib/active_support/code_generator.rb +65 -0
  18. data/lib/active_support/concern.rb +5 -5
  19. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
  20. data/lib/active_support/concurrency/share_lock.rb +2 -2
  21. data/lib/active_support/configurable.rb +8 -5
  22. data/lib/active_support/configuration_file.rb +1 -1
  23. data/lib/active_support/core_ext/array/access.rb +1 -5
  24. data/lib/active_support/core_ext/array/conversions.rb +13 -12
  25. data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
  26. data/lib/active_support/core_ext/array/grouping.rb +6 -6
  27. data/lib/active_support/core_ext/array/inquiry.rb +2 -2
  28. data/lib/active_support/core_ext/array.rb +1 -0
  29. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  30. data/lib/active_support/core_ext/class/subclasses.rb +25 -17
  31. data/lib/active_support/core_ext/date/blank.rb +1 -1
  32. data/lib/active_support/core_ext/date/calculations.rb +24 -9
  33. data/lib/active_support/core_ext/date/conversions.rb +14 -14
  34. data/lib/active_support/core_ext/date/deprecated_conversions.rb +40 -0
  35. data/lib/active_support/core_ext/date.rb +1 -0
  36. data/lib/active_support/core_ext/date_and_time/calculations.rb +4 -4
  37. data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
  38. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  39. data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
  40. data/lib/active_support/core_ext/date_time/conversions.rb +13 -13
  41. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +36 -0
  42. data/lib/active_support/core_ext/date_time.rb +1 -0
  43. data/lib/active_support/core_ext/digest/uuid.rb +39 -13
  44. data/lib/active_support/core_ext/enumerable.rb +112 -38
  45. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  46. data/lib/active_support/core_ext/hash/conversions.rb +0 -1
  47. data/lib/active_support/core_ext/hash/deep_transform_values.rb +3 -3
  48. data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
  49. data/lib/active_support/core_ext/hash/keys.rb +4 -4
  50. data/lib/active_support/core_ext/integer/inflections.rb +12 -12
  51. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  52. data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
  53. data/lib/active_support/core_ext/module/attribute_accessors.rb +2 -0
  54. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +19 -10
  55. data/lib/active_support/core_ext/module/delegation.rb +2 -8
  56. data/lib/active_support/core_ext/name_error.rb +2 -8
  57. data/lib/active_support/core_ext/numeric/conversions.rb +80 -77
  58. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
  59. data/lib/active_support/core_ext/numeric.rb +1 -0
  60. data/lib/active_support/core_ext/object/acts_like.rb +29 -5
  61. data/lib/active_support/core_ext/object/blank.rb +2 -2
  62. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  63. data/lib/active_support/core_ext/object/duplicable.rb +15 -4
  64. data/lib/active_support/core_ext/object/json.rb +30 -25
  65. data/lib/active_support/core_ext/object/to_query.rb +2 -4
  66. data/lib/active_support/core_ext/object/try.rb +20 -20
  67. data/lib/active_support/core_ext/object/with_options.rb +21 -2
  68. data/lib/active_support/core_ext/pathname/existence.rb +21 -0
  69. data/lib/active_support/core_ext/pathname.rb +3 -0
  70. data/lib/active_support/core_ext/range/compare_range.rb +0 -25
  71. data/lib/active_support/core_ext/range/conversions.rb +8 -8
  72. data/lib/active_support/core_ext/range/deprecated_conversions.rb +36 -0
  73. data/lib/active_support/core_ext/range/each.rb +1 -1
  74. data/lib/active_support/core_ext/range/include_time_with_zone.rb +3 -26
  75. data/lib/active_support/core_ext/range/overlaps.rb +1 -1
  76. data/lib/active_support/core_ext/range.rb +1 -1
  77. data/lib/active_support/core_ext/securerandom.rb +1 -1
  78. data/lib/active_support/core_ext/string/conversions.rb +2 -2
  79. data/lib/active_support/core_ext/string/filters.rb +1 -1
  80. data/lib/active_support/core_ext/string/inflections.rb +1 -5
  81. data/lib/active_support/core_ext/string/inquiry.rb +1 -1
  82. data/lib/active_support/core_ext/string/output_safety.rb +94 -38
  83. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
  84. data/lib/active_support/core_ext/time/calculations.rb +13 -8
  85. data/lib/active_support/core_ext/time/conversions.rb +13 -12
  86. data/lib/active_support/core_ext/time/deprecated_conversions.rb +73 -0
  87. data/lib/active_support/core_ext/time/zones.rb +10 -26
  88. data/lib/active_support/core_ext/time.rb +1 -0
  89. data/lib/active_support/core_ext/uri.rb +3 -27
  90. data/lib/active_support/core_ext.rb +1 -0
  91. data/lib/active_support/current_attributes.rb +31 -14
  92. data/lib/active_support/dependencies/interlock.rb +10 -18
  93. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  94. data/lib/active_support/dependencies.rb +58 -788
  95. data/lib/active_support/deprecation/behaviors.rb +8 -5
  96. data/lib/active_support/deprecation/disallowed.rb +3 -3
  97. data/lib/active_support/deprecation/method_wrappers.rb +3 -3
  98. data/lib/active_support/deprecation/proxy_wrappers.rb +2 -2
  99. data/lib/active_support/deprecation.rb +2 -2
  100. data/lib/active_support/descendants_tracker.rb +174 -68
  101. data/lib/active_support/digest.rb +5 -3
  102. data/lib/active_support/duration/iso8601_parser.rb +3 -3
  103. data/lib/active_support/duration/iso8601_serializer.rb +9 -1
  104. data/lib/active_support/duration.rb +81 -51
  105. data/lib/active_support/encrypted_configuration.rb +45 -3
  106. data/lib/active_support/encrypted_file.rb +21 -10
  107. data/lib/active_support/environment_inquirer.rb +1 -1
  108. data/lib/active_support/error_reporter.rb +117 -0
  109. data/lib/active_support/evented_file_update_checker.rb +20 -7
  110. data/lib/active_support/execution_context/test_helper.rb +13 -0
  111. data/lib/active_support/execution_context.rb +53 -0
  112. data/lib/active_support/execution_wrapper.rb +43 -21
  113. data/lib/active_support/executor/test_helper.rb +7 -0
  114. data/lib/active_support/fork_tracker.rb +19 -12
  115. data/lib/active_support/gem_version.rb +5 -5
  116. data/lib/active_support/hash_with_indifferent_access.rb +3 -1
  117. data/lib/active_support/html_safe_translation.rb +43 -0
  118. data/lib/active_support/i18n.rb +1 -0
  119. data/lib/active_support/i18n_railtie.rb +1 -1
  120. data/lib/active_support/inflector/inflections.rb +23 -7
  121. data/lib/active_support/inflector/methods.rb +29 -55
  122. data/lib/active_support/inflector/transliterate.rb +1 -1
  123. data/lib/active_support/isolated_execution_state.rb +72 -0
  124. data/lib/active_support/json/encoding.rb +3 -3
  125. data/lib/active_support/key_generator.rb +22 -5
  126. data/lib/active_support/lazy_load_hooks.rb +28 -4
  127. data/lib/active_support/locale/en.yml +1 -1
  128. data/lib/active_support/log_subscriber/test_helper.rb +2 -2
  129. data/lib/active_support/log_subscriber.rb +15 -5
  130. data/lib/active_support/logger_thread_safe_level.rb +4 -13
  131. data/lib/active_support/message_encryptor.rb +12 -6
  132. data/lib/active_support/message_verifier.rb +46 -14
  133. data/lib/active_support/messages/metadata.rb +2 -2
  134. data/lib/active_support/multibyte/chars.rb +10 -11
  135. data/lib/active_support/multibyte/unicode.rb +0 -12
  136. data/lib/active_support/multibyte.rb +1 -1
  137. data/lib/active_support/notifications/fanout.rb +91 -65
  138. data/lib/active_support/notifications/instrumenter.rb +32 -15
  139. data/lib/active_support/notifications.rb +23 -23
  140. data/lib/active_support/number_helper/number_converter.rb +1 -3
  141. data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
  142. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  143. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  144. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
  145. data/lib/active_support/number_helper/rounding_helper.rb +1 -5
  146. data/lib/active_support/number_helper.rb +4 -5
  147. data/lib/active_support/option_merger.rb +10 -18
  148. data/lib/active_support/ordered_hash.rb +1 -1
  149. data/lib/active_support/ordered_options.rb +1 -1
  150. data/lib/active_support/parameter_filter.rb +20 -11
  151. data/lib/active_support/per_thread_registry.rb +5 -0
  152. data/lib/active_support/railtie.rb +69 -19
  153. data/lib/active_support/reloader.rb +1 -1
  154. data/lib/active_support/rescuable.rb +12 -12
  155. data/lib/active_support/ruby_features.rb +7 -0
  156. data/lib/active_support/secure_compare_rotator.rb +2 -2
  157. data/lib/active_support/string_inquirer.rb +0 -2
  158. data/lib/active_support/subscriber.rb +7 -18
  159. data/lib/active_support/tagged_logging.rb +2 -2
  160. data/lib/active_support/test_case.rb +13 -21
  161. data/lib/active_support/testing/assertions.rb +36 -6
  162. data/lib/active_support/testing/deprecation.rb +52 -1
  163. data/lib/active_support/testing/isolation.rb +30 -29
  164. data/lib/active_support/testing/method_call_assertions.rb +5 -5
  165. data/lib/active_support/testing/parallelization/server.rb +4 -0
  166. data/lib/active_support/testing/parallelization/worker.rb +3 -0
  167. data/lib/active_support/testing/parallelization.rb +4 -0
  168. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  169. data/lib/active_support/testing/stream.rb +3 -5
  170. data/lib/active_support/testing/tagged_logging.rb +1 -1
  171. data/lib/active_support/testing/time_helpers.rb +13 -2
  172. data/lib/active_support/time_with_zone.rb +43 -22
  173. data/lib/active_support/values/time_zone.rb +35 -14
  174. data/lib/active_support/version.rb +1 -1
  175. data/lib/active_support/xml_mini/jdom.rb +1 -1
  176. data/lib/active_support/xml_mini/libxml.rb +5 -5
  177. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  178. data/lib/active_support/xml_mini/nokogiri.rb +4 -4
  179. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  180. data/lib/active_support/xml_mini/rexml.rb +1 -1
  181. data/lib/active_support/xml_mini.rb +5 -4
  182. data/lib/active_support.rb +17 -1
  183. metadata +26 -23
  184. data/lib/active_support/core_ext/marshal.rb +0 -26
  185. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
@@ -5,6 +5,7 @@ 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
@@ -15,19 +16,19 @@ module ActiveSupport
15
16
  # needing to override or redefine methods of the base class.
16
17
  #
17
18
  # 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+),
19
+ # life cycle that will support callbacks (via ClassMethods#define_callbacks),
19
20
  # set the instance methods, procs, or callback objects to be called (via
20
- # +ClassMethods.set_callback+), and run the installed callbacks at the
21
+ # ClassMethods#set_callback), and run the installed callbacks at the
21
22
  # appropriate times (via +run_callbacks+).
22
23
  #
23
24
  # By default callbacks are halted by throwing +:abort+.
24
- # See +ClassMethods.define_callbacks+ for details.
25
+ # See ClassMethods#define_callbacks for details.
25
26
  #
26
27
  # Three kinds of callbacks are supported: before callbacks, run before a
27
28
  # certain event; after callbacks, run after the event; and around callbacks,
28
29
  # blocks that surround the event, triggering it when they yield. Callback code
29
30
  # can be contained in instance methods, procs or lambdas, or callback objects
30
- # that respond to certain predetermined methods. See +ClassMethods.set_callback+
31
+ # that respond to certain predetermined methods. See ClassMethods#set_callback
31
32
  # for details.
32
33
  #
33
34
  # class Record
@@ -276,7 +277,7 @@ module ActiveSupport
276
277
  end
277
278
  end
278
279
 
279
- class Callback #:nodoc:#
280
+ class Callback # :nodoc:#
280
281
  def self.build(chain, filter, kind, options)
281
282
  if filter.is_a?(String)
282
283
  raise ArgumentError, <<-MSG.squish
@@ -289,21 +290,17 @@ module ActiveSupport
289
290
  end
290
291
 
291
292
  attr_accessor :kind, :name
292
- attr_reader :chain_config
293
+ attr_reader :chain_config, :filter
293
294
 
294
295
  def initialize(name, filter, kind, options, chain_config)
295
296
  @chain_config = chain_config
296
297
  @name = name
297
298
  @kind = kind
298
299
  @filter = filter
299
- @key = compute_identifier filter
300
300
  @if = check_conditionals(options[:if])
301
301
  @unless = check_conditionals(options[:unless])
302
302
  end
303
303
 
304
- def filter; @key; end
305
- def raw_filter; @filter; end
306
-
307
304
  def merge_conditional_options(chain, if_option:, unless_option:)
308
305
  options = {
309
306
  if: @if.dup,
@@ -356,7 +353,7 @@ module ActiveSupport
356
353
  return EMPTY_ARRAY if conditionals.blank?
357
354
 
358
355
  conditionals = Array(conditionals)
359
- if conditionals.any? { |c| c.is_a?(String) }
356
+ if conditionals.any?(String)
360
357
  raise ArgumentError, <<-MSG.squish
361
358
  Passing string to be evaluated in :if and :unless conditional
362
359
  options is not supported. Pass a symbol for an instance method,
@@ -367,15 +364,6 @@ module ActiveSupport
367
364
  conditionals.freeze
368
365
  end
369
366
 
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
367
  def conditions_lambdas
380
368
  @if.map { |c| CallTemplate.build(c, self).make_lambda } +
381
369
  @unless.map { |c| CallTemplate.build(c, self).inverted_lambda }
@@ -384,56 +372,153 @@ module ActiveSupport
384
372
 
385
373
  # A future invocation of user-supplied code (either as a callback,
386
374
  # 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
375
+ module CallTemplate # :nodoc:
376
+ class MethodCall
377
+ def initialize(method)
378
+ @method_name = method
379
+ end
380
+
381
+ # Return the parts needed to make this call, with the given
382
+ # input values.
383
+ #
384
+ # Returns an array of the form:
385
+ #
386
+ # [target, block, method, *arguments]
387
+ #
388
+ # This array can be used as such:
389
+ #
390
+ # target.send(method, *arguments, &block)
391
+ #
392
+ # The actual invocation is left up to the caller to minimize
393
+ # call stack pollution.
394
+ def expand(target, value, block)
395
+ [target, block, @method_name]
396
+ end
397
+
398
+ def make_lambda
399
+ lambda do |target, value, &block|
400
+ target.send(@method_name, &block)
401
+ end
402
+ end
403
+
404
+ def inverted_lambda
405
+ lambda do |target, value, &block|
406
+ !target.send(@method_name, &block)
407
+ end
408
+ end
393
409
  end
394
410
 
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]
411
+ class ObjectCall
412
+ def initialize(target, method)
413
+ @override_target = target
414
+ @method_name = method
415
+ end
416
+
417
+ def expand(target, value, block)
418
+ [@override_target || target, block, @method_name, target]
419
+ end
410
420
 
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))
421
+ def make_lambda
422
+ lambda do |target, value, &block|
423
+ (@override_target || target).send(@method_name, target, &block)
416
424
  end
417
425
  end
418
426
 
419
- expanded
427
+ def inverted_lambda
428
+ lambda do |target, value, &block|
429
+ !(@override_target || target).send(@method_name, target, &block)
430
+ end
431
+ end
420
432
  end
421
433
 
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)
434
+ class InstanceExec0
435
+ def initialize(block)
436
+ @override_block = block
437
+ end
438
+
439
+ def expand(target, value, block)
440
+ [target, @override_block, :instance_exec]
441
+ end
442
+
443
+ def make_lambda
444
+ lambda do |target, value, &block|
445
+ target.instance_exec(&@override_block)
446
+ end
447
+ end
448
+
449
+ def inverted_lambda
450
+ lambda do |target, value, &block|
451
+ !target.instance_exec(&@override_block)
452
+ end
428
453
  end
429
454
  end
430
455
 
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)
456
+ class InstanceExec1
457
+ def initialize(block)
458
+ @override_block = block
459
+ end
460
+
461
+ def expand(target, value, block)
462
+ [target, @override_block, :instance_exec, target]
463
+ end
464
+
465
+ def make_lambda
466
+ lambda do |target, value, &block|
467
+ target.instance_exec(target, &@override_block)
468
+ end
469
+ end
470
+
471
+ def inverted_lambda
472
+ lambda do |target, value, &block|
473
+ !target.instance_exec(target, &@override_block)
474
+ end
475
+ end
476
+ end
477
+
478
+ class InstanceExec2
479
+ def initialize(block)
480
+ @override_block = block
481
+ end
482
+
483
+ def expand(target, value, block)
484
+ raise ArgumentError unless block
485
+ [target, @override_block || block, :instance_exec, target, block]
486
+ end
487
+
488
+ def make_lambda
489
+ lambda do |target, value, &block|
490
+ raise ArgumentError unless block
491
+ target.instance_exec(target, block, &@override_block)
492
+ end
493
+ end
494
+
495
+ def inverted_lambda
496
+ lambda do |target, value, &block|
497
+ raise ArgumentError unless block
498
+ !target.instance_exec(target, block, &@override_block)
499
+ end
500
+ end
501
+ end
502
+
503
+ class ProcCall
504
+ def initialize(target)
505
+ @override_target = target
506
+ end
507
+
508
+ def expand(target, value, block)
509
+ [@override_target || target, block, :call, target, value]
510
+ end
511
+
512
+ def make_lambda
513
+ lambda do |target, value, &block|
514
+ (@override_target || target).call(target, value, &block)
515
+ end
516
+ end
517
+
518
+ def inverted_lambda
519
+ lambda do |target, value, &block|
520
+ !(@override_target || target).call(target, value, &block)
521
+ end
437
522
  end
438
523
  end
439
524
 
@@ -448,21 +533,19 @@ module ActiveSupport
448
533
  def self.build(filter, callback)
449
534
  case filter
450
535
  when Symbol
451
- new(nil, filter, [], nil)
536
+ MethodCall.new(filter)
452
537
  when Conditionals::Value
453
- new(filter, :call, [:target, :value], nil)
538
+ ProcCall.new(filter)
454
539
  when ::Proc
455
540
  if filter.arity > 1
456
- new(nil, :instance_exec, [:target, :block], filter)
541
+ InstanceExec2.new(filter)
457
542
  elsif filter.arity > 0
458
- new(nil, :instance_exec, [:target], filter)
543
+ InstanceExec1.new(filter)
459
544
  else
460
- new(nil, :instance_exec, [], filter)
545
+ InstanceExec0.new(filter)
461
546
  end
462
547
  else
463
- method_to_call = callback.current_scopes.join("_")
464
-
465
- new(filter, method_to_call, [:target], nil)
548
+ ObjectCall.new(filter, callback.current_scopes.join("_").to_sym)
466
549
  end
467
550
  end
468
551
  end
@@ -517,7 +600,7 @@ module ActiveSupport
517
600
  end
518
601
  end
519
602
 
520
- class CallbackChain #:nodoc:#
603
+ class CallbackChain # :nodoc:
521
604
  include Enumerable
522
605
 
523
606
  attr_reader :name, :config
@@ -619,8 +702,8 @@ module ActiveSupport
619
702
 
620
703
  # This is used internally to append, prepend and skip callbacks to the
621
704
  # CallbackChain.
622
- def __update_callbacks(name) #:nodoc:
623
- ([self] + ActiveSupport::DescendantsTracker.descendants(self)).reverse_each do |target|
705
+ def __update_callbacks(name) # :nodoc:
706
+ ([self] + self.descendants).reverse_each do |target|
624
707
  chain = target.get_callbacks name
625
708
  yield target, chain.dup
626
709
  end
@@ -688,10 +771,32 @@ module ActiveSupport
688
771
  # <tt>:unless</tt> options may be passed in order to control when the
689
772
  # callback is skipped.
690
773
  #
691
- # class Writer < Person
692
- # skip_callback :validate, :before, :check_membership, if: -> { age > 18 }
774
+ # class Writer < PersonRecord
775
+ # attr_accessor :age
776
+ # skip_callback :save, :before, :saving_message, if: -> { age > 18 }
693
777
  # end
694
778
  #
779
+ # When if option returns true, callback is skipped.
780
+ #
781
+ # writer = Writer.new
782
+ # writer.age = 20
783
+ # writer.save
784
+ #
785
+ # Output:
786
+ # - save
787
+ # saved
788
+ #
789
+ # When if option returns false, callback is NOT skipped.
790
+ #
791
+ # young_writer = Writer.new
792
+ # young_writer.age = 17
793
+ # young_writer.save
794
+ #
795
+ # Output:
796
+ # saving...
797
+ # - save
798
+ # saved
799
+ #
695
800
  # An <tt>ArgumentError</tt> will be raised if the callback has not
696
801
  # already been set (unless the <tt>:raise</tt> option is set to <tt>false</tt>).
697
802
  def skip_callback(name, *filter_list, &block)
@@ -722,7 +827,7 @@ module ActiveSupport
722
827
  def reset_callbacks(name)
723
828
  callbacks = get_callbacks name
724
829
 
725
- ActiveSupport::DescendantsTracker.descendants(self).each do |target|
830
+ self.descendants.each do |target|
726
831
  chain = target.get_callbacks(name).dup
727
832
  callbacks.each { |c| chain.delete(c) }
728
833
  target.set_callbacks name, chain
@@ -815,7 +920,7 @@ module ActiveSupport
815
920
  names.each do |name|
816
921
  name = name.to_sym
817
922
 
818
- ([self] + ActiveSupport::DescendantsTracker.descendants(self)).each do |target|
923
+ ([self] + self.descendants).each do |target|
819
924
  target.set_callbacks name, CallbackChain.new(name, options)
820
925
  end
821
926
 
@@ -844,18 +949,12 @@ module ActiveSupport
844
949
  __callbacks[name.to_sym]
845
950
  end
846
951
 
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
952
+ def set_callbacks(name, callbacks) # :nodoc:
953
+ unless singleton_class.method_defined?(:__callbacks, false)
954
+ self.__callbacks = __callbacks.dup
858
955
  end
956
+ self.__callbacks[name.to_sym] = callbacks
957
+ self.__callbacks
859
958
  end
860
959
  end
861
960
  end
@@ -0,0 +1,65 @@
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
+ end
13
+
14
+ def define_cached_method(name, as: name)
15
+ name = name.to_sym
16
+ as = as.to_sym
17
+ @methods.fetch(name) do
18
+ unless @cache.method_defined?(as)
19
+ yield @sources
20
+ end
21
+ @methods[name] = as
22
+ end
23
+ end
24
+
25
+ def apply(owner, path, line)
26
+ unless @sources.empty?
27
+ @cache.module_eval("# frozen_string_literal: true\n" + @sources.join(";"), path, line)
28
+ end
29
+ @methods.each do |name, as|
30
+ owner.define_method(name, @cache.instance_method(as))
31
+ end
32
+ end
33
+ end
34
+
35
+ class << self
36
+ def batch(owner, path, line)
37
+ if owner.is_a?(CodeGenerator)
38
+ yield owner
39
+ else
40
+ instance = new(owner, path, line)
41
+ result = yield instance
42
+ instance.execute
43
+ result
44
+ end
45
+ end
46
+ end
47
+
48
+ def initialize(owner, path, line)
49
+ @owner = owner
50
+ @path = path
51
+ @line = line
52
+ @namespaces = Hash.new { |h, k| h[k] = MethodSet.new(k) }
53
+ end
54
+
55
+ def define_cached_method(name, namespace:, as: name, &block)
56
+ @namespaces[namespace].define_cached_method(name, as: as, &block)
57
+ end
58
+
59
+ def execute
60
+ @namespaces.each_value do |method_set|
61
+ method_set.apply(@owner, @path, @line - 1)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -108,23 +108,23 @@ module ActiveSupport
108
108
  #
109
109
  # <tt>prepend</tt> is also used for any dependencies.
110
110
  module Concern
111
- class MultipleIncludedBlocks < StandardError #:nodoc:
111
+ class MultipleIncludedBlocks < StandardError # :nodoc:
112
112
  def initialize
113
113
  super "Cannot define multiple 'included' blocks for a Concern"
114
114
  end
115
115
  end
116
116
 
117
- class MultiplePrependBlocks < StandardError #:nodoc:
117
+ class MultiplePrependBlocks < StandardError # :nodoc:
118
118
  def initialize
119
119
  super "Cannot define multiple 'prepended' blocks for a Concern"
120
120
  end
121
121
  end
122
122
 
123
- def self.extended(base) #:nodoc:
123
+ def self.extended(base) # :nodoc:
124
124
  base.instance_variable_set(:@_dependencies, [])
125
125
  end
126
126
 
127
- def append_features(base) #:nodoc:
127
+ def append_features(base) # :nodoc:
128
128
  if base.instance_variable_defined?(:@_dependencies)
129
129
  base.instance_variable_get(:@_dependencies) << self
130
130
  false
@@ -137,7 +137,7 @@ module ActiveSupport
137
137
  end
138
138
  end
139
139
 
140
- def prepend_features(base) #:nodoc:
140
+ def prepend_features(base) # :nodoc:
141
141
  if base.instance_variable_defined?(:@_dependencies)
142
142
  base.instance_variable_get(:@_dependencies).unshift self
143
143
  false
@@ -17,14 +17,12 @@ module ActiveSupport
17
17
  ActiveSupport::Dependencies.interlock.permit_concurrent_loads { super }
18
18
  end
19
19
 
20
- def synchronize
20
+ def synchronize(&block)
21
21
  Thread.handle_interrupt(EXCEPTION_NEVER) do
22
22
  mon_enter
23
23
 
24
24
  begin
25
- Thread.handle_interrupt(EXCEPTION_IMMEDIATE) do
26
- yield
27
- end
25
+ Thread.handle_interrupt(EXCEPTION_IMMEDIATE, &block)
28
26
  ensure
29
27
  mon_exit
30
28
  end
@@ -215,9 +215,9 @@ module ActiveSupport
215
215
  @waiting.any? { |t, (p, _)| compatible.include?(p) && @waiting.all? { |t2, (_, c2)| t == t2 || c2.include?(p) } }
216
216
  end
217
217
 
218
- def wait_for(method)
218
+ def wait_for(method, &block)
219
219
  @sleeping[Thread.current] = method
220
- @cv.wait_while { yield }
220
+ @cv.wait_while(&block)
221
221
  ensure
222
222
  @sleeping.delete Thread.current
223
223
  end
@@ -5,7 +5,7 @@ require "active_support/ordered_options"
5
5
 
6
6
  module ActiveSupport
7
7
  # Configurable provides a <tt>config</tt> method to store and retrieve
8
- # configuration options as an <tt>OrderedOptions</tt>.
8
+ # configuration options as an OrderedOptions.
9
9
  module Configurable
10
10
  extend ActiveSupport::Concern
11
11
 
@@ -94,17 +94,19 @@ module ActiveSupport
94
94
  # User.new.allowed_access = true # => NoMethodError
95
95
  # User.new.allowed_access # => NoMethodError
96
96
  #
97
- # Also you can pass a block to set up the attribute with a default value.
97
+ # Also you can pass <tt>default</tt> or a block to set up the attribute with a default value.
98
98
  #
99
99
  # class User
100
100
  # include ActiveSupport::Configurable
101
+ # config_accessor :allowed_access, default: false
101
102
  # config_accessor :hair_colors do
102
103
  # [:brown, :black, :blonde, :red]
103
104
  # end
104
105
  # end
105
106
  #
107
+ # User.allowed_access # => false
106
108
  # User.hair_colors # => [:brown, :black, :blonde, :red]
107
- def config_accessor(*names, instance_reader: true, instance_writer: true, instance_accessor: true) # :doc:
109
+ def config_accessor(*names, instance_reader: true, instance_writer: true, instance_accessor: true, default: nil) # :doc:
108
110
  names.each do |name|
109
111
  raise NameError.new("invalid config attribute name") unless /\A[_A-Za-z]\w*\z/.match?(name)
110
112
 
@@ -118,13 +120,14 @@ module ActiveSupport
118
120
  class_eval reader, __FILE__, reader_line if instance_reader
119
121
  class_eval writer, __FILE__, writer_line if instance_writer
120
122
  end
121
- send("#{name}=", yield) if block_given?
123
+
124
+ send("#{name}=", block_given? ? yield : default)
122
125
  end
123
126
  end
124
127
  private :config_accessor
125
128
  end
126
129
 
127
- # Reads and writes attributes from a configuration <tt>OrderedOptions</tt>.
130
+ # Reads and writes attributes from a configuration OrderedOptions.
128
131
  #
129
132
  # require "active_support/configurable"
130
133
  #
@@ -38,7 +38,7 @@ module ActiveSupport
38
38
 
39
39
  File.read(content_path).tap do |content|
40
40
  if content.include?("\u00A0")
41
- warn "File contains invisible non-breaking spaces, you may want to remove those"
41
+ warn "#{content_path} contains invisible non-breaking spaces, you may want to remove those"
42
42
  end
43
43
  end
44
44
  end
@@ -47,11 +47,7 @@ class Array
47
47
  def excluding(*elements)
48
48
  self - elements.flatten(1)
49
49
  end
50
-
51
- # Alias for #excluding.
52
- def without(*elements)
53
- excluding(*elements)
54
- end
50
+ alias :without :excluding
55
51
 
56
52
  # Equal to <tt>self[1]</tt>.
57
53
  #
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/xml_mini"
4
3
  require "active_support/core_ext/hash/keys"
5
4
  require "active_support/core_ext/string/inflections"
6
5
  require "active_support/core_ext/object/to_param"
@@ -16,12 +15,12 @@ class Array
16
15
  #
17
16
  # ==== Options
18
17
  #
19
- # * <tt>:words_connector</tt> - The sign or word used to join the elements
20
- # in arrays with two or more elements (default: ", ").
21
- # * <tt>:two_words_connector</tt> - The sign or word used to join the elements
22
- # in arrays with two elements (default: " and ").
18
+ # * <tt>:words_connector</tt> - The sign or word used to join all but the last
19
+ # element in arrays with three or more elements (default: ", ").
23
20
  # * <tt>:last_word_connector</tt> - The sign or word used to join the last element
24
21
  # in arrays with three or more elements (default: ", and ").
22
+ # * <tt>:two_words_connector</tt> - The sign or word used to join the elements
23
+ # in arrays with two elements (default: " and ").
25
24
  # * <tt>:locale</tt> - If +i18n+ is available, you can set a locale and use
26
25
  # the connector options defined on the 'support.array' namespace in the
27
26
  # corresponding dictionary file.
@@ -66,7 +65,7 @@ class Array
66
65
  two_words_connector: " and ",
67
66
  last_word_connector: ", and "
68
67
  }
69
- if defined?(I18n)
68
+ if options[:locale] != false && defined?(I18n)
70
69
  i18n_connectors = I18n.translate(:'support.array', locale: options[:locale], default: {})
71
70
  default_connectors.merge!(i18n_connectors)
72
71
  end
@@ -87,10 +86,12 @@ class Array
87
86
  # Extends <tt>Array#to_s</tt> to convert a collection of elements into a
88
87
  # comma separated id list if <tt>:db</tt> argument is given as the format.
89
88
  #
90
- # Blog.all.to_formatted_s(:db) # => "1,2,3"
91
- # Blog.none.to_formatted_s(:db) # => "null"
92
- # [1,2].to_formatted_s # => "[1, 2]"
93
- def to_formatted_s(format = :default)
89
+ # This method is aliased to <tt>to_formatted_s</tt>.
90
+ #
91
+ # Blog.all.to_fs(:db) # => "1,2,3"
92
+ # Blog.none.to_fs(:db) # => "null"
93
+ # [1,2].to_fs # => "[1, 2]"
94
+ def to_fs(format = :default)
94
95
  case format
95
96
  when :db
96
97
  if empty?
@@ -102,8 +103,8 @@ class Array
102
103
  to_default_s
103
104
  end
104
105
  end
106
+ alias_method :to_formatted_s, :to_fs
105
107
  alias_method :to_default_s, :to_s
106
- alias_method :to_s, :to_formatted_s
107
108
 
108
109
  # Returns a string that represents the array in XML by invoking +to_xml+
109
110
  # on each element. Active Record collections delegate their representation
@@ -187,7 +188,7 @@ class Array
187
188
  options[:indent] ||= 2
188
189
  options[:builder] ||= Builder::XmlMarkup.new(indent: options[:indent])
189
190
  options[:root] ||= \
190
- if first.class != Hash && all? { |e| e.is_a?(first.class) }
191
+ if first.class != Hash && all?(first.class)
191
192
  underscored = ActiveSupport::Inflector.underscore(first.class.name)
192
193
  ActiveSupport::Inflector.pluralize(underscored).tr("/", "_")
193
194
  else