activesupport 6.1.6.1 → 7.0.3.1

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 (179) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +231 -515
  3. data/lib/active_support/actionable_error.rb +1 -1
  4. data/lib/active_support/array_inquirer.rb +0 -2
  5. data/lib/active_support/backtrace_cleaner.rb +2 -2
  6. data/lib/active_support/benchmarkable.rb +2 -2
  7. data/lib/active_support/cache/file_store.rb +15 -9
  8. data/lib/active_support/cache/mem_cache_store.rb +132 -37
  9. data/lib/active_support/cache/memory_store.rb +24 -16
  10. data/lib/active_support/cache/null_store.rb +10 -2
  11. data/lib/active_support/cache/redis_cache_store.rb +47 -72
  12. data/lib/active_support/cache/strategy/local_cache.rb +38 -61
  13. data/lib/active_support/cache.rb +193 -46
  14. data/lib/active_support/callbacks.rb +184 -85
  15. data/lib/active_support/code_generator.rb +65 -0
  16. data/lib/active_support/concern.rb +5 -5
  17. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
  18. data/lib/active_support/concurrency/share_lock.rb +2 -2
  19. data/lib/active_support/configurable.rb +8 -5
  20. data/lib/active_support/configuration_file.rb +1 -1
  21. data/lib/active_support/core_ext/array/access.rb +1 -5
  22. data/lib/active_support/core_ext/array/conversions.rb +13 -12
  23. data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
  24. data/lib/active_support/core_ext/array/grouping.rb +6 -6
  25. data/lib/active_support/core_ext/array/inquiry.rb +2 -2
  26. data/lib/active_support/core_ext/array.rb +1 -0
  27. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  28. data/lib/active_support/core_ext/class/subclasses.rb +25 -17
  29. data/lib/active_support/core_ext/date/blank.rb +1 -1
  30. data/lib/active_support/core_ext/date/calculations.rb +9 -9
  31. data/lib/active_support/core_ext/date/conversions.rb +14 -14
  32. data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
  33. data/lib/active_support/core_ext/date.rb +1 -0
  34. data/lib/active_support/core_ext/date_and_time/calculations.rb +4 -4
  35. data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
  36. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  37. data/lib/active_support/core_ext/date_time/conversions.rb +13 -13
  38. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
  39. data/lib/active_support/core_ext/date_time.rb +1 -0
  40. data/lib/active_support/core_ext/digest/uuid.rb +39 -14
  41. data/lib/active_support/core_ext/enumerable.rb +101 -32
  42. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  43. data/lib/active_support/core_ext/hash/conversions.rb +0 -1
  44. data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
  45. data/lib/active_support/core_ext/hash/keys.rb +1 -1
  46. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  47. data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
  48. data/lib/active_support/core_ext/module/attribute_accessors.rb +2 -0
  49. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +19 -10
  50. data/lib/active_support/core_ext/module/delegation.rb +2 -8
  51. data/lib/active_support/core_ext/name_error.rb +2 -8
  52. data/lib/active_support/core_ext/numeric/conversions.rb +80 -77
  53. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
  54. data/lib/active_support/core_ext/numeric.rb +1 -0
  55. data/lib/active_support/core_ext/object/acts_like.rb +29 -5
  56. data/lib/active_support/core_ext/object/blank.rb +2 -2
  57. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  58. data/lib/active_support/core_ext/object/duplicable.rb +11 -0
  59. data/lib/active_support/core_ext/object/json.rb +30 -25
  60. data/lib/active_support/core_ext/object/to_query.rb +2 -2
  61. data/lib/active_support/core_ext/object/try.rb +20 -20
  62. data/lib/active_support/core_ext/object/with_options.rb +20 -1
  63. data/lib/active_support/core_ext/pathname/existence.rb +21 -0
  64. data/lib/active_support/core_ext/pathname.rb +3 -0
  65. data/lib/active_support/core_ext/range/compare_range.rb +0 -25
  66. data/lib/active_support/core_ext/range/conversions.rb +8 -8
  67. data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
  68. data/lib/active_support/core_ext/range/each.rb +1 -1
  69. data/lib/active_support/core_ext/range/include_time_with_zone.rb +4 -25
  70. data/lib/active_support/core_ext/range/overlaps.rb +1 -1
  71. data/lib/active_support/core_ext/range.rb +1 -1
  72. data/lib/active_support/core_ext/securerandom.rb +1 -1
  73. data/lib/active_support/core_ext/string/conversions.rb +2 -2
  74. data/lib/active_support/core_ext/string/filters.rb +1 -1
  75. data/lib/active_support/core_ext/string/inflections.rb +1 -1
  76. data/lib/active_support/core_ext/string/inquiry.rb +1 -1
  77. data/lib/active_support/core_ext/string/output_safety.rb +62 -38
  78. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
  79. data/lib/active_support/core_ext/time/calculations.rb +7 -8
  80. data/lib/active_support/core_ext/time/conversions.rb +13 -12
  81. data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
  82. data/lib/active_support/core_ext/time/zones.rb +7 -22
  83. data/lib/active_support/core_ext/time.rb +1 -0
  84. data/lib/active_support/core_ext/uri.rb +3 -27
  85. data/lib/active_support/core_ext.rb +1 -0
  86. data/lib/active_support/current_attributes.rb +31 -14
  87. data/lib/active_support/dependencies/interlock.rb +10 -18
  88. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  89. data/lib/active_support/dependencies.rb +58 -788
  90. data/lib/active_support/deprecation/behaviors.rb +5 -2
  91. data/lib/active_support/deprecation/method_wrappers.rb +3 -3
  92. data/lib/active_support/deprecation/proxy_wrappers.rb +2 -2
  93. data/lib/active_support/deprecation.rb +2 -2
  94. data/lib/active_support/descendants_tracker.rb +174 -68
  95. data/lib/active_support/digest.rb +4 -4
  96. data/lib/active_support/duration/iso8601_parser.rb +3 -3
  97. data/lib/active_support/duration/iso8601_serializer.rb +9 -1
  98. data/lib/active_support/duration.rb +77 -48
  99. data/lib/active_support/encrypted_configuration.rb +13 -2
  100. data/lib/active_support/encrypted_file.rb +1 -1
  101. data/lib/active_support/environment_inquirer.rb +1 -1
  102. data/lib/active_support/error_reporter.rb +117 -0
  103. data/lib/active_support/evented_file_update_checker.rb +3 -5
  104. data/lib/active_support/execution_context/test_helper.rb +13 -0
  105. data/lib/active_support/execution_context.rb +53 -0
  106. data/lib/active_support/execution_wrapper.rb +30 -11
  107. data/lib/active_support/executor/test_helper.rb +7 -0
  108. data/lib/active_support/fork_tracker.rb +19 -12
  109. data/lib/active_support/gem_version.rb +4 -4
  110. data/lib/active_support/hash_with_indifferent_access.rb +3 -1
  111. data/lib/active_support/html_safe_translation.rb +43 -0
  112. data/lib/active_support/i18n.rb +1 -0
  113. data/lib/active_support/i18n_railtie.rb +1 -1
  114. data/lib/active_support/inflector/inflections.rb +23 -7
  115. data/lib/active_support/inflector/methods.rb +24 -48
  116. data/lib/active_support/inflector/transliterate.rb +1 -1
  117. data/lib/active_support/isolated_execution_state.rb +72 -0
  118. data/lib/active_support/json/encoding.rb +3 -3
  119. data/lib/active_support/key_generator.rb +22 -5
  120. data/lib/active_support/lazy_load_hooks.rb +14 -3
  121. data/lib/active_support/locale/en.yml +1 -1
  122. data/lib/active_support/log_subscriber/test_helper.rb +2 -2
  123. data/lib/active_support/log_subscriber.rb +15 -5
  124. data/lib/active_support/logger.rb +4 -5
  125. data/lib/active_support/logger_thread_safe_level.rb +4 -13
  126. data/lib/active_support/message_encryptor.rb +12 -6
  127. data/lib/active_support/message_verifier.rb +46 -14
  128. data/lib/active_support/messages/metadata.rb +2 -2
  129. data/lib/active_support/multibyte/chars.rb +10 -11
  130. data/lib/active_support/multibyte/unicode.rb +0 -12
  131. data/lib/active_support/multibyte.rb +1 -1
  132. data/lib/active_support/notifications/fanout.rb +91 -65
  133. data/lib/active_support/notifications/instrumenter.rb +32 -15
  134. data/lib/active_support/notifications.rb +17 -23
  135. data/lib/active_support/number_helper/number_converter.rb +1 -3
  136. data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
  137. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  138. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  139. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
  140. data/lib/active_support/number_helper/rounding_helper.rb +1 -5
  141. data/lib/active_support/number_helper.rb +0 -2
  142. data/lib/active_support/option_merger.rb +8 -16
  143. data/lib/active_support/ordered_hash.rb +1 -1
  144. data/lib/active_support/ordered_options.rb +1 -1
  145. data/lib/active_support/parameter_filter.rb +5 -0
  146. data/lib/active_support/per_thread_registry.rb +5 -1
  147. data/lib/active_support/railtie.rb +69 -19
  148. data/lib/active_support/rescuable.rb +4 -4
  149. data/lib/active_support/ruby_features.rb +7 -0
  150. data/lib/active_support/secure_compare_rotator.rb +2 -2
  151. data/lib/active_support/string_inquirer.rb +0 -2
  152. data/lib/active_support/subscriber.rb +7 -18
  153. data/lib/active_support/tagged_logging.rb +16 -1
  154. data/lib/active_support/test_case.rb +9 -21
  155. data/lib/active_support/testing/assertions.rb +35 -5
  156. data/lib/active_support/testing/deprecation.rb +52 -1
  157. data/lib/active_support/testing/isolation.rb +2 -2
  158. data/lib/active_support/testing/method_call_assertions.rb +5 -5
  159. data/lib/active_support/testing/parallelization/server.rb +4 -0
  160. data/lib/active_support/testing/parallelization/worker.rb +3 -0
  161. data/lib/active_support/testing/parallelization.rb +4 -0
  162. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  163. data/lib/active_support/testing/stream.rb +3 -5
  164. data/lib/active_support/testing/tagged_logging.rb +1 -1
  165. data/lib/active_support/testing/time_helpers.rb +13 -2
  166. data/lib/active_support/time_with_zone.rb +58 -17
  167. data/lib/active_support/values/time_zone.rb +33 -14
  168. data/lib/active_support/version.rb +1 -1
  169. data/lib/active_support/xml_mini/jdom.rb +1 -1
  170. data/lib/active_support/xml_mini/libxml.rb +5 -5
  171. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  172. data/lib/active_support/xml_mini/nokogiri.rb +4 -4
  173. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  174. data/lib/active_support/xml_mini/rexml.rb +1 -1
  175. data/lib/active_support/xml_mini.rb +5 -4
  176. data/lib/active_support.rb +16 -0
  177. metadata +23 -21
  178. data/lib/active_support/core_ext/marshal.rb +0 -26
  179. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -120
@@ -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