activesupport 5.2.0 → 6.0.3.2

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.

Potentially problematic release.


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

Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +479 -330
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -3
  5. data/lib/active_support.rb +2 -1
  6. data/lib/active_support/actionable_error.rb +48 -0
  7. data/lib/active_support/backtrace_cleaner.rb +27 -1
  8. data/lib/active_support/cache.rb +104 -84
  9. data/lib/active_support/cache/file_store.rb +29 -30
  10. data/lib/active_support/cache/mem_cache_store.rb +14 -19
  11. data/lib/active_support/cache/memory_store.rb +15 -9
  12. data/lib/active_support/cache/null_store.rb +8 -3
  13. data/lib/active_support/cache/redis_cache_store.rb +73 -34
  14. data/lib/active_support/cache/strategy/local_cache.rb +23 -23
  15. data/lib/active_support/callbacks.rb +16 -8
  16. data/lib/active_support/concern.rb +31 -4
  17. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
  18. data/lib/active_support/concurrency/share_lock.rb +0 -1
  19. data/lib/active_support/configurable.rb +7 -11
  20. data/lib/active_support/core_ext/array.rb +1 -1
  21. data/lib/active_support/core_ext/array/access.rb +18 -6
  22. data/lib/active_support/core_ext/array/conversions.rb +5 -5
  23. data/lib/active_support/core_ext/array/extract.rb +21 -0
  24. data/lib/active_support/core_ext/array/prepend_and_append.rb +2 -6
  25. data/lib/active_support/core_ext/class/attribute.rb +11 -16
  26. data/lib/active_support/core_ext/class/subclasses.rb +1 -1
  27. data/lib/active_support/core_ext/date/calculations.rb +6 -5
  28. data/lib/active_support/core_ext/date_and_time/calculations.rb +24 -47
  29. data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
  30. data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
  31. data/lib/active_support/core_ext/date_time/conversions.rb +0 -1
  32. data/lib/active_support/core_ext/digest.rb +3 -0
  33. data/lib/active_support/core_ext/enumerable.rb +97 -68
  34. data/lib/active_support/core_ext/file/atomic.rb +1 -1
  35. data/lib/active_support/core_ext/hash.rb +1 -2
  36. data/lib/active_support/core_ext/hash/compact.rb +2 -26
  37. data/lib/active_support/core_ext/hash/conversions.rb +1 -1
  38. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  39. data/lib/active_support/core_ext/hash/except.rb +1 -1
  40. data/lib/active_support/core_ext/hash/keys.rb +0 -29
  41. data/lib/active_support/core_ext/hash/slice.rb +3 -25
  42. data/lib/active_support/core_ext/hash/transform_values.rb +2 -29
  43. data/lib/active_support/core_ext/integer/multiple.rb +1 -1
  44. data/lib/active_support/core_ext/kernel.rb +0 -1
  45. data/lib/active_support/core_ext/load_error.rb +1 -1
  46. data/lib/active_support/core_ext/module.rb +0 -1
  47. data/lib/active_support/core_ext/module/attribute_accessors.rb +7 -10
  48. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +13 -19
  49. data/lib/active_support/core_ext/module/delegation.rb +41 -8
  50. data/lib/active_support/core_ext/module/introspection.rb +38 -13
  51. data/lib/active_support/core_ext/module/reachable.rb +1 -6
  52. data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
  53. data/lib/active_support/core_ext/numeric.rb +0 -1
  54. data/lib/active_support/core_ext/numeric/conversions.rb +124 -128
  55. data/lib/active_support/core_ext/numeric/inquiry.rb +2 -25
  56. data/lib/active_support/core_ext/object/blank.rb +1 -2
  57. data/lib/active_support/core_ext/object/duplicable.rb +7 -114
  58. data/lib/active_support/core_ext/object/json.rb +1 -0
  59. data/lib/active_support/core_ext/object/to_query.rb +5 -2
  60. data/lib/active_support/core_ext/object/try.rb +17 -7
  61. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  62. data/lib/active_support/core_ext/range.rb +1 -1
  63. data/lib/active_support/core_ext/range/compare_range.rb +76 -0
  64. data/lib/active_support/core_ext/range/conversions.rb +31 -29
  65. data/lib/active_support/core_ext/range/each.rb +0 -1
  66. data/lib/active_support/core_ext/range/include_range.rb +6 -22
  67. data/lib/active_support/core_ext/range/include_time_with_zone.rb +2 -2
  68. data/lib/active_support/core_ext/regexp.rb +0 -4
  69. data/lib/active_support/core_ext/securerandom.rb +23 -3
  70. data/lib/active_support/core_ext/string/access.rb +8 -0
  71. data/lib/active_support/core_ext/string/filters.rb +42 -1
  72. data/lib/active_support/core_ext/string/inflections.rb +7 -2
  73. data/lib/active_support/core_ext/string/multibyte.rb +4 -3
  74. data/lib/active_support/core_ext/string/output_safety.rb +63 -6
  75. data/lib/active_support/core_ext/string/strip.rb +3 -1
  76. data/lib/active_support/core_ext/time/calculations.rb +31 -2
  77. data/lib/active_support/core_ext/uri.rb +2 -4
  78. data/lib/active_support/current_attributes.rb +8 -0
  79. data/lib/active_support/dependencies.rb +77 -18
  80. data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
  81. data/lib/active_support/deprecation.rb +1 -1
  82. data/lib/active_support/deprecation/behaviors.rb +5 -1
  83. data/lib/active_support/deprecation/method_wrappers.rb +20 -13
  84. data/lib/active_support/deprecation/proxy_wrappers.rb +28 -5
  85. data/lib/active_support/deprecation/reporting.rb +1 -1
  86. data/lib/active_support/descendants_tracker.rb +55 -9
  87. data/lib/active_support/duration.rb +19 -16
  88. data/lib/active_support/duration/iso8601_parser.rb +2 -4
  89. data/lib/active_support/duration/iso8601_serializer.rb +3 -5
  90. data/lib/active_support/encrypted_configuration.rb +1 -5
  91. data/lib/active_support/encrypted_file.rb +4 -3
  92. data/lib/active_support/evented_file_update_checker.rb +39 -10
  93. data/lib/active_support/execution_wrapper.rb +1 -0
  94. data/lib/active_support/file_update_checker.rb +0 -1
  95. data/lib/active_support/gem_version.rb +4 -4
  96. data/lib/active_support/hash_with_indifferent_access.rb +36 -18
  97. data/lib/active_support/i18n.rb +1 -0
  98. data/lib/active_support/i18n_railtie.rb +18 -2
  99. data/lib/active_support/inflector/inflections.rb +1 -5
  100. data/lib/active_support/inflector/methods.rb +18 -29
  101. data/lib/active_support/inflector/transliterate.rb +47 -18
  102. data/lib/active_support/json/decoding.rb +23 -24
  103. data/lib/active_support/json/encoding.rb +6 -2
  104. data/lib/active_support/key_generator.rb +0 -32
  105. data/lib/active_support/lazy_load_hooks.rb +5 -2
  106. data/lib/active_support/locale/en.rb +33 -0
  107. data/lib/active_support/log_subscriber.rb +31 -9
  108. data/lib/active_support/logger.rb +1 -16
  109. data/lib/active_support/logger_silence.rb +28 -12
  110. data/lib/active_support/logger_thread_safe_level.rb +28 -5
  111. data/lib/active_support/message_encryptor.rb +4 -6
  112. data/lib/active_support/message_verifier.rb +5 -5
  113. data/lib/active_support/messages/metadata.rb +3 -2
  114. data/lib/active_support/messages/rotator.rb +4 -4
  115. data/lib/active_support/multibyte/chars.rb +29 -49
  116. data/lib/active_support/multibyte/unicode.rb +44 -282
  117. data/lib/active_support/notifications.rb +41 -4
  118. data/lib/active_support/notifications/fanout.rb +100 -15
  119. data/lib/active_support/notifications/instrumenter.rb +80 -9
  120. data/lib/active_support/number_helper.rb +11 -0
  121. data/lib/active_support/number_helper/number_converter.rb +4 -5
  122. data/lib/active_support/number_helper/number_to_currency_converter.rb +9 -10
  123. data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -2
  124. data/lib/active_support/number_helper/number_to_human_converter.rb +3 -2
  125. data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -2
  126. data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
  127. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
  128. data/lib/active_support/number_helper/number_to_rounded_converter.rb +5 -4
  129. data/lib/active_support/option_merger.rb +21 -3
  130. data/lib/active_support/ordered_hash.rb +1 -1
  131. data/lib/active_support/ordered_options.rb +5 -1
  132. data/lib/active_support/parameter_filter.rb +128 -0
  133. data/lib/active_support/rails.rb +0 -6
  134. data/lib/active_support/reloader.rb +4 -5
  135. data/lib/active_support/security_utils.rb +1 -1
  136. data/lib/active_support/string_inquirer.rb +0 -1
  137. data/lib/active_support/subscriber.rb +65 -22
  138. data/lib/active_support/tagged_logging.rb +13 -4
  139. data/lib/active_support/test_case.rb +92 -1
  140. data/lib/active_support/testing/assertions.rb +15 -1
  141. data/lib/active_support/testing/deprecation.rb +0 -1
  142. data/lib/active_support/testing/file_fixtures.rb +2 -0
  143. data/lib/active_support/testing/isolation.rb +2 -2
  144. data/lib/active_support/testing/method_call_assertions.rb +28 -1
  145. data/lib/active_support/testing/parallelization.rb +134 -0
  146. data/lib/active_support/testing/setup_and_teardown.rb +5 -9
  147. data/lib/active_support/testing/stream.rb +1 -2
  148. data/lib/active_support/testing/time_helpers.rb +7 -9
  149. data/lib/active_support/time_with_zone.rb +15 -5
  150. data/lib/active_support/values/time_zone.rb +14 -8
  151. data/lib/active_support/xml_mini.rb +2 -10
  152. data/lib/active_support/xml_mini/jdom.rb +2 -3
  153. data/lib/active_support/xml_mini/libxml.rb +2 -2
  154. data/lib/active_support/xml_mini/libxmlsax.rb +4 -4
  155. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  156. data/lib/active_support/xml_mini/nokogirisax.rb +3 -3
  157. data/lib/active_support/xml_mini/rexml.rb +2 -2
  158. metadata +42 -13
  159. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
  160. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/numeric/inquiry"
3
+ require "active_support/number_helper/number_converter"
4
4
 
5
5
  module ActiveSupport
6
6
  module NumberHelper
@@ -9,23 +9,22 @@ module ActiveSupport
9
9
 
10
10
  def convert
11
11
  number = self.number.to_s.strip
12
+ number_f = number.to_f
12
13
  format = options[:format]
13
14
 
14
- if number.to_f.negative?
15
- format = options[:negative_format]
16
- number = absolute_value(number)
15
+ if number_f.negative?
16
+ number = number_f.abs
17
+
18
+ unless options[:precision] == 0 && number < 0.5
19
+ format = options[:negative_format]
20
+ end
17
21
  end
18
22
 
19
23
  rounded_number = NumberToRoundedConverter.convert(number, options)
20
- format.gsub("%n".freeze, rounded_number).gsub("%u".freeze, options[:unit])
24
+ format.gsub("%n", rounded_number).gsub("%u", options[:unit])
21
25
  end
22
26
 
23
27
  private
24
-
25
- def absolute_value(number)
26
- number.respond_to?(:abs) ? number.abs : number.sub(/\A-/, "")
27
- end
28
-
29
28
  def options
30
29
  @options ||= begin
31
30
  defaults = default_format_options.merge(i18n_opts)
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/number_helper/number_converter"
4
+
3
5
  module ActiveSupport
4
6
  module NumberHelper
5
7
  class NumberToDelimitedConverter < NumberConverter #:nodoc:
@@ -12,9 +14,8 @@ module ActiveSupport
12
14
  end
13
15
 
14
16
  private
15
-
16
17
  def parts
17
- left, right = number.to_s.split(".".freeze)
18
+ left, right = number.to_s.split(".")
18
19
  left.gsub!(delimiter_pattern) do |digit_to_delimit|
19
20
  "#{digit_to_delimit}#{options[:delimiter]}"
20
21
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/number_helper/number_converter"
4
+
3
5
  module ActiveSupport
4
6
  module NumberHelper
5
7
  class NumberToHumanConverter < NumberConverter # :nodoc:
@@ -25,11 +27,10 @@ module ActiveSupport
25
27
 
26
28
  rounded_number = NumberToRoundedConverter.convert(number, options)
27
29
  unit = determine_unit(units, exponent)
28
- format.gsub("%n".freeze, rounded_number).gsub("%u".freeze, unit).strip
30
+ format.gsub("%n", rounded_number).gsub("%u", unit).strip
29
31
  end
30
32
 
31
33
  private
32
-
33
34
  def format
34
35
  options[:format] || translate_in_locale("human.decimal_units.format")
35
36
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/number_helper/number_converter"
4
+
3
5
  module ActiveSupport
4
6
  module NumberHelper
5
7
  class NumberToHumanSizeConverter < NumberConverter #:nodoc:
@@ -22,11 +24,10 @@ module ActiveSupport
22
24
  human_size = number / (base**exponent)
23
25
  number_to_format = NumberToRoundedConverter.convert(human_size, options)
24
26
  end
25
- conversion_format.gsub("%n".freeze, number_to_format).gsub("%u".freeze, unit)
27
+ conversion_format.gsub("%n", number_to_format).gsub("%u", unit)
26
28
  end
27
29
 
28
30
  private
29
-
30
31
  def conversion_format
31
32
  translate_number_value_with_default("human.storage_units.format", locale: options[:locale], raise: true)
32
33
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/number_helper/number_converter"
4
+
3
5
  module ActiveSupport
4
6
  module NumberHelper
5
7
  class NumberToPercentageConverter < NumberConverter # :nodoc:
@@ -7,7 +9,7 @@ module ActiveSupport
7
9
 
8
10
  def convert
9
11
  rounded_number = NumberToRoundedConverter.convert(number, options)
10
- options[:format].gsub("%n".freeze, rounded_number)
12
+ options[:format].gsub("%n", rounded_number)
11
13
  end
12
14
  end
13
15
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/number_helper/number_converter"
4
+
3
5
  module ActiveSupport
4
6
  module NumberHelper
5
7
  class NumberToPhoneConverter < NumberConverter #:nodoc:
@@ -10,7 +12,6 @@ module ActiveSupport
10
12
  end
11
13
 
12
14
  private
13
-
14
15
  def convert_to_phone_number(number)
15
16
  if opts[:area_code]
16
17
  convert_with_area_code(number)
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/number_helper/number_converter"
4
+
3
5
  module ActiveSupport
4
6
  module NumberHelper
5
7
  class NumberToRoundedConverter < NumberConverter # :nodoc:
@@ -20,9 +22,9 @@ module ActiveSupport
20
22
  formatted_string =
21
23
  if BigDecimal === rounded_number && rounded_number.finite?
22
24
  s = rounded_number.to_s("F")
23
- s << "0".freeze * precision
24
- a, b = s.split(".".freeze, 2)
25
- a << ".".freeze
25
+ s << "0" * precision
26
+ a, b = s.split(".", 2)
27
+ a << "."
26
28
  a << b[0, precision]
27
29
  else
28
30
  "%00.#{precision}f" % rounded_number
@@ -36,7 +38,6 @@ module ActiveSupport
36
38
  end
37
39
 
38
40
  private
39
-
40
41
  def strip_insignificant_zeros
41
42
  options[:strip_insignificant_zeros]
42
43
  end
@@ -5,7 +5,7 @@ require "active_support/core_ext/hash/deep_merge"
5
5
  module ActiveSupport
6
6
  class OptionMerger #:nodoc:
7
7
  instance_methods.each do |method|
8
- undef_method(method) if method !~ /^(__|instance_eval|class|object_id)/
8
+ undef_method(method) if !/^(__|instance_eval|class|object_id)/.match?(method)
9
9
  end
10
10
 
11
11
  def initialize(context, options)
@@ -14,14 +14,32 @@ module ActiveSupport
14
14
 
15
15
  private
16
16
  def method_missing(method, *arguments, &block)
17
+ options = nil
17
18
  if arguments.first.is_a?(Proc)
18
19
  proc = arguments.pop
19
20
  arguments << lambda { |*args| @options.deep_merge(proc.call(*args)) }
21
+ elsif arguments.last.respond_to?(:to_hash)
22
+ options = @options.deep_merge(arguments.pop)
20
23
  else
21
- arguments << (arguments.last.respond_to?(:to_hash) ? @options.deep_merge(arguments.pop) : @options.dup)
24
+ options = @options
22
25
  end
23
26
 
24
- @context.__send__(method, *arguments, &block)
27
+ invoke_method(method, arguments, options, &block)
28
+ end
29
+
30
+ if RUBY_VERSION >= "2.7"
31
+ def invoke_method(method, arguments, options, &block)
32
+ if options
33
+ @context.__send__(method, *arguments, **options, &block)
34
+ else
35
+ @context.__send__(method, *arguments, &block)
36
+ end
37
+ end
38
+ else
39
+ def invoke_method(method, arguments, options, &block)
40
+ arguments << options if options
41
+ @context.__send__(method, *arguments, &block)
42
+ end
25
43
  end
26
44
  end
27
45
  end
@@ -16,7 +16,7 @@ module ActiveSupport
16
16
  # oh.keys # => [:a, :b], this order is guaranteed
17
17
  #
18
18
  # Also, maps the +omap+ feature for YAML files
19
- # (See http://yaml.org/type/omap.html) to support ordered items
19
+ # (See https://yaml.org/type/omap.html) to support ordered items
20
20
  # when loading from yaml.
21
21
  #
22
22
  # <tt>ActiveSupport::OrderedHash</tt> is namespaced to prevent conflicts
@@ -39,7 +39,7 @@ module ActiveSupport
39
39
  end
40
40
 
41
41
  def method_missing(name, *args)
42
- name_string = name.to_s
42
+ name_string = +name.to_s
43
43
  if name_string.chomp!("=")
44
44
  self[name_string] = args.first
45
45
  else
@@ -56,6 +56,10 @@ module ActiveSupport
56
56
  def respond_to_missing?(name, include_private)
57
57
  true
58
58
  end
59
+
60
+ def extractable_options?
61
+ true
62
+ end
59
63
  end
60
64
 
61
65
  # +InheritableOptions+ provides a constructor to build an +OrderedOptions+
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/object/duplicable"
4
+ require "active_support/core_ext/array/extract"
5
+
6
+ module ActiveSupport
7
+ # +ParameterFilter+ allows you to specify keys for sensitive data from
8
+ # hash-like object and replace corresponding value. Filtering only certain
9
+ # sub-keys from a hash is possible by using the dot notation:
10
+ # 'credit_card.number'. If a proc is given, each key and value of a hash and
11
+ # all sub-hashes are passed to it, where the value or the key can be replaced
12
+ # using String#replace or similar methods.
13
+ #
14
+ # ActiveSupport::ParameterFilter.new([:password])
15
+ # => replaces the value to all keys matching /password/i with "[FILTERED]"
16
+ #
17
+ # ActiveSupport::ParameterFilter.new([:foo, "bar"])
18
+ # => replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
19
+ #
20
+ # ActiveSupport::ParameterFilter.new(["credit_card.code"])
21
+ # => replaces { credit_card: {code: "xxxx"} } with "[FILTERED]", does not
22
+ # change { file: { code: "xxxx"} }
23
+ #
24
+ # ActiveSupport::ParameterFilter.new([-> (k, v) do
25
+ # v.reverse! if k =~ /secret/i
26
+ # end])
27
+ # => reverses the value to all keys matching /secret/i
28
+ class ParameterFilter
29
+ FILTERED = "[FILTERED]" # :nodoc:
30
+
31
+ # Create instance with given filters. Supported type of filters are +String+, +Regexp+, and +Proc+.
32
+ # Other types of filters are treated as +String+ using +to_s+.
33
+ # For +Proc+ filters, key, value, and optional original hash is passed to block arguments.
34
+ #
35
+ # ==== Options
36
+ #
37
+ # * <tt>:mask</tt> - A replaced object when filtered. Defaults to +"[FILTERED]"+
38
+ def initialize(filters = [], mask: FILTERED)
39
+ @filters = filters
40
+ @mask = mask
41
+ end
42
+
43
+ # Mask value of +params+ if key matches one of filters.
44
+ def filter(params)
45
+ compiled_filter.call(params)
46
+ end
47
+
48
+ # Returns filtered value for given key. For +Proc+ filters, third block argument is not populated.
49
+ def filter_param(key, value)
50
+ @filters.empty? ? value : compiled_filter.value_for_key(key, value)
51
+ end
52
+
53
+ private
54
+ def compiled_filter
55
+ @compiled_filter ||= CompiledFilter.compile(@filters, mask: @mask)
56
+ end
57
+
58
+ class CompiledFilter # :nodoc:
59
+ def self.compile(filters, mask:)
60
+ return lambda { |params| params.dup } if filters.empty?
61
+
62
+ strings, regexps, blocks = [], [], []
63
+
64
+ filters.each do |item|
65
+ case item
66
+ when Proc
67
+ blocks << item
68
+ when Regexp
69
+ regexps << item
70
+ else
71
+ strings << Regexp.escape(item.to_s)
72
+ end
73
+ end
74
+
75
+ deep_regexps = regexps.extract! { |r| r.to_s.include?("\\.") }
76
+ deep_strings = strings.extract! { |s| s.include?("\\.") }
77
+
78
+ regexps << Regexp.new(strings.join("|"), true) unless strings.empty?
79
+ deep_regexps << Regexp.new(deep_strings.join("|"), true) unless deep_strings.empty?
80
+
81
+ new regexps, deep_regexps, blocks, mask: mask
82
+ end
83
+
84
+ attr_reader :regexps, :deep_regexps, :blocks
85
+
86
+ def initialize(regexps, deep_regexps, blocks, mask:)
87
+ @regexps = regexps
88
+ @deep_regexps = deep_regexps.any? ? deep_regexps : nil
89
+ @blocks = blocks
90
+ @mask = mask
91
+ end
92
+
93
+ def call(params, parents = [], original_params = params)
94
+ filtered_params = params.class.new
95
+
96
+ params.each do |key, value|
97
+ filtered_params[key] = value_for_key(key, value, parents, original_params)
98
+ end
99
+
100
+ filtered_params
101
+ end
102
+
103
+ def value_for_key(key, value, parents = [], original_params = nil)
104
+ parents.push(key) if deep_regexps
105
+ if regexps.any? { |r| r.match?(key.to_s) }
106
+ value = @mask
107
+ elsif deep_regexps && (joined = parents.join(".")) && deep_regexps.any? { |r| r.match?(joined) }
108
+ value = @mask
109
+ elsif value.is_a?(Hash)
110
+ value = call(value, parents, original_params)
111
+ elsif value.is_a?(Array)
112
+ # If we don't pop the current parent it will be duplicated as we
113
+ # process each array value.
114
+ parents.pop if deep_regexps
115
+ value = value.map { |v| value_for_key(key, v, parents, original_params) }
116
+ # Restore the parent stack after processing the array.
117
+ parents.push(key) if deep_regexps
118
+ elsif blocks.any?
119
+ key = key.dup if key.duplicable?
120
+ value = value.dup if value.duplicable?
121
+ blocks.each { |b| b.arity == 2 ? b.call(key, value) : b.call(key, value, original_params) }
122
+ end
123
+ parents.pop if deep_regexps
124
+ value
125
+ end
126
+ end
127
+ end
128
+ end
@@ -27,9 +27,3 @@ require "active_support/core_ext/module/delegation"
27
27
 
28
28
  # Defines ActiveSupport::Deprecation.
29
29
  require "active_support/deprecation"
30
-
31
- # Defines Regexp#match?.
32
- #
33
- # This should be removed when Rails needs Ruby 2.4 or later, and the require
34
- # added where other Regexp extensions are being used (easy to grep).
35
- require "active_support/core_ext/regexp"
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/execution_wrapper"
4
+ require "active_support/executor"
4
5
 
5
6
  module ActiveSupport
6
7
  #--
@@ -49,11 +50,9 @@ module ActiveSupport
49
50
  def self.reload!
50
51
  executor.wrap do
51
52
  new.tap do |instance|
52
- begin
53
- instance.run!
54
- ensure
55
- instance.complete!
56
- end
53
+ instance.run!
54
+ ensure
55
+ instance.complete!
57
56
  end
58
57
  end
59
58
  prepare!
@@ -24,7 +24,7 @@ module ActiveSupport
24
24
  # The values are first processed by SHA256, so that we don't leak length info
25
25
  # via timing attacks.
26
26
  def secure_compare(a, b)
27
- fixed_length_secure_compare(::Digest::SHA256.hexdigest(a), ::Digest::SHA256.hexdigest(b)) && a == b
27
+ fixed_length_secure_compare(::Digest::SHA256.digest(a), ::Digest::SHA256.digest(b)) && a == b
28
28
  end
29
29
  module_function :secure_compare
30
30
  end
@@ -18,7 +18,6 @@ module ActiveSupport
18
18
  # vehicle.bike? # => false
19
19
  class StringInquirer < String
20
20
  private
21
-
22
21
  def respond_to_missing?(method_name, include_private = false)
23
22
  (method_name[-1] == "?") || super
24
23
  end
@@ -24,6 +24,10 @@ module ActiveSupport
24
24
  # After configured, whenever a "sql.active_record" notification is published,
25
25
  # it will properly dispatch the event (ActiveSupport::Notifications::Event) to
26
26
  # the +sql+ method.
27
+ #
28
+ # We can detach a subscriber as well:
29
+ #
30
+ # ActiveRecord::StatsSubscriber.detach_from(:active_record)
27
31
  class Subscriber
28
32
  class << self
29
33
  # Attach the subscriber to a namespace.
@@ -40,6 +44,25 @@ module ActiveSupport
40
44
  end
41
45
  end
42
46
 
47
+ # Detach the subscriber from a namespace.
48
+ def detach_from(namespace, notifier = ActiveSupport::Notifications)
49
+ @namespace = namespace
50
+ @subscriber = find_attached_subscriber
51
+ @notifier = notifier
52
+
53
+ return unless subscriber
54
+
55
+ subscribers.delete(subscriber)
56
+
57
+ # Remove event subscribers of all existing methods on the class.
58
+ subscriber.public_methods(false).each do |event|
59
+ remove_event_subscriber(event)
60
+ end
61
+
62
+ # Reset notifier so that event subscribers will not add for new methods added to the class.
63
+ @notifier = nil
64
+ end
65
+
43
66
  # Adds event subscribers for all new methods added to the class.
44
67
  def method_added(event)
45
68
  # Only public methods are added as subscribers, and only if a notifier
@@ -54,55 +77,75 @@ module ActiveSupport
54
77
  @@subscribers ||= []
55
78
  end
56
79
 
57
- # TODO Change this to private once we've dropped Ruby 2.2 support.
58
- # Workaround for Ruby 2.2 "private attribute?" warning.
59
- protected
80
+ private
81
+ attr_reader :subscriber, :notifier, :namespace
60
82
 
61
- attr_reader :subscriber, :notifier, :namespace
83
+ def add_event_subscriber(event) # :doc:
84
+ return if invalid_event?(event.to_s)
62
85
 
63
- private
86
+ pattern = prepare_pattern(event)
64
87
 
65
- def add_event_subscriber(event) # :doc:
66
- return if %w{ start finish }.include?(event.to_s)
88
+ # Don't add multiple subscribers (eg. if methods are redefined).
89
+ return if pattern_subscribed?(pattern)
67
90
 
68
- pattern = "#{event}.#{namespace}"
91
+ subscriber.patterns[pattern] = notifier.subscribe(pattern, subscriber)
92
+ end
69
93
 
70
- # Don't add multiple subscribers (eg. if methods are redefined).
71
- return if subscriber.patterns.include?(pattern)
94
+ def remove_event_subscriber(event) # :doc:
95
+ return if invalid_event?(event.to_s)
72
96
 
73
- subscriber.patterns << pattern
74
- notifier.subscribe(pattern, subscriber)
75
- end
97
+ pattern = prepare_pattern(event)
98
+
99
+ return unless pattern_subscribed?(pattern)
100
+
101
+ notifier.unsubscribe(subscriber.patterns[pattern])
102
+ subscriber.patterns.delete(pattern)
103
+ end
104
+
105
+ def find_attached_subscriber
106
+ subscribers.find { |attached_subscriber| attached_subscriber.instance_of?(self) }
107
+ end
108
+
109
+ def invalid_event?(event)
110
+ %w{ start finish }.include?(event.to_s)
111
+ end
112
+
113
+ def prepare_pattern(event)
114
+ "#{event}.#{namespace}"
115
+ end
116
+
117
+ def pattern_subscribed?(pattern)
118
+ subscriber.patterns.key?(pattern)
119
+ end
76
120
  end
77
121
 
78
122
  attr_reader :patterns # :nodoc:
79
123
 
80
124
  def initialize
81
125
  @queue_key = [self.class.name, object_id].join "-"
82
- @patterns = []
126
+ @patterns = {}
83
127
  super
84
128
  end
85
129
 
86
130
  def start(name, id, payload)
87
- e = ActiveSupport::Notifications::Event.new(name, Time.now, nil, id, payload)
131
+ event = ActiveSupport::Notifications::Event.new(name, nil, nil, id, payload)
132
+ event.start!
88
133
  parent = event_stack.last
89
- parent << e if parent
134
+ parent << event if parent
90
135
 
91
- event_stack.push e
136
+ event_stack.push event
92
137
  end
93
138
 
94
139
  def finish(name, id, payload)
95
- finished = Time.now
96
- event = event_stack.pop
97
- event.end = finished
140
+ event = event_stack.pop
141
+ event.finish!
98
142
  event.payload.merge!(payload)
99
143
 
100
- method = name.split(".".freeze).first
144
+ method = name.split(".").first
101
145
  send(method, event)
102
146
  end
103
147
 
104
148
  private
105
-
106
149
  def event_stack
107
150
  SubscriberQueueRegistry.instance.get_queue(@queue_key)
108
151
  end