activesupport 7.0.4 → 7.1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1076 -230
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -6
  5. data/lib/active_support/actionable_error.rb +3 -1
  6. data/lib/active_support/array_inquirer.rb +2 -0
  7. data/lib/active_support/backtrace_cleaner.rb +30 -5
  8. data/lib/active_support/benchmarkable.rb +1 -0
  9. data/lib/active_support/broadcast_logger.rb +251 -0
  10. data/lib/active_support/builder.rb +1 -1
  11. data/lib/active_support/cache/coder.rb +153 -0
  12. data/lib/active_support/cache/entry.rb +134 -0
  13. data/lib/active_support/cache/file_store.rb +37 -10
  14. data/lib/active_support/cache/mem_cache_store.rb +100 -76
  15. data/lib/active_support/cache/memory_store.rb +78 -24
  16. data/lib/active_support/cache/null_store.rb +6 -0
  17. data/lib/active_support/cache/redis_cache_store.rb +153 -141
  18. data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
  19. data/lib/active_support/cache/strategy/local_cache.rb +29 -14
  20. data/lib/active_support/cache.rb +333 -253
  21. data/lib/active_support/callbacks.rb +44 -21
  22. data/lib/active_support/code_generator.rb +15 -10
  23. data/lib/active_support/concern.rb +4 -2
  24. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +42 -3
  25. data/lib/active_support/concurrency/null_lock.rb +13 -0
  26. data/lib/active_support/configurable.rb +10 -0
  27. data/lib/active_support/core_ext/array/conversions.rb +2 -1
  28. data/lib/active_support/core_ext/array.rb +0 -1
  29. data/lib/active_support/core_ext/class/subclasses.rb +13 -10
  30. data/lib/active_support/core_ext/date/calculations.rb +15 -0
  31. data/lib/active_support/core_ext/date/conversions.rb +2 -1
  32. data/lib/active_support/core_ext/date.rb +0 -1
  33. data/lib/active_support/core_ext/date_and_time/calculations.rb +10 -0
  34. data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
  35. data/lib/active_support/core_ext/date_time/conversions.rb +6 -2
  36. data/lib/active_support/core_ext/date_time.rb +0 -1
  37. data/lib/active_support/core_ext/digest/uuid.rb +1 -10
  38. data/lib/active_support/core_ext/enumerable.rb +8 -75
  39. data/lib/active_support/core_ext/erb/util.rb +196 -0
  40. data/lib/active_support/core_ext/hash/conversions.rb +1 -1
  41. data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
  42. data/lib/active_support/core_ext/hash/deep_transform_values.rb +3 -3
  43. data/lib/active_support/core_ext/hash/keys.rb +3 -3
  44. data/lib/active_support/core_ext/integer/inflections.rb +12 -12
  45. data/lib/active_support/core_ext/module/attribute_accessors.rb +6 -0
  46. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +34 -16
  47. data/lib/active_support/core_ext/module/concerning.rb +6 -6
  48. data/lib/active_support/core_ext/module/delegation.rb +81 -37
  49. data/lib/active_support/core_ext/module/deprecation.rb +15 -12
  50. data/lib/active_support/core_ext/module/introspection.rb +0 -1
  51. data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
  52. data/lib/active_support/core_ext/numeric/conversions.rb +2 -0
  53. data/lib/active_support/core_ext/numeric.rb +0 -1
  54. data/lib/active_support/core_ext/object/deep_dup.rb +16 -0
  55. data/lib/active_support/core_ext/object/duplicable.rb +25 -16
  56. data/lib/active_support/core_ext/object/inclusion.rb +13 -5
  57. data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
  58. data/lib/active_support/core_ext/object/json.rb +16 -6
  59. data/lib/active_support/core_ext/object/to_query.rb +0 -2
  60. data/lib/active_support/core_ext/object/with.rb +44 -0
  61. data/lib/active_support/core_ext/object/with_options.rb +9 -9
  62. data/lib/active_support/core_ext/object.rb +1 -0
  63. data/lib/active_support/core_ext/pathname/blank.rb +16 -0
  64. data/lib/active_support/core_ext/pathname/existence.rb +2 -0
  65. data/lib/active_support/core_ext/pathname.rb +1 -0
  66. data/lib/active_support/core_ext/range/conversions.rb +28 -7
  67. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  68. data/lib/active_support/core_ext/range.rb +1 -2
  69. data/lib/active_support/core_ext/securerandom.rb +24 -12
  70. data/lib/active_support/core_ext/string/filters.rb +20 -14
  71. data/lib/active_support/core_ext/string/indent.rb +1 -1
  72. data/lib/active_support/core_ext/string/inflections.rb +16 -9
  73. data/lib/active_support/core_ext/string/output_safety.rb +42 -174
  74. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  75. data/lib/active_support/core_ext/time/calculations.rb +22 -2
  76. data/lib/active_support/core_ext/time/conversions.rb +2 -2
  77. data/lib/active_support/core_ext/time/zones.rb +7 -8
  78. data/lib/active_support/core_ext/time.rb +0 -1
  79. data/lib/active_support/current_attributes.rb +15 -6
  80. data/lib/active_support/deep_mergeable.rb +53 -0
  81. data/lib/active_support/dependencies/autoload.rb +17 -12
  82. data/lib/active_support/deprecation/behaviors.rb +65 -42
  83. data/lib/active_support/deprecation/constant_accessor.rb +5 -4
  84. data/lib/active_support/deprecation/deprecators.rb +104 -0
  85. data/lib/active_support/deprecation/disallowed.rb +6 -8
  86. data/lib/active_support/deprecation/instance_delegator.rb +31 -4
  87. data/lib/active_support/deprecation/method_wrappers.rb +6 -23
  88. data/lib/active_support/deprecation/proxy_wrappers.rb +37 -22
  89. data/lib/active_support/deprecation/reporting.rb +43 -26
  90. data/lib/active_support/deprecation.rb +32 -5
  91. data/lib/active_support/deprecator.rb +7 -0
  92. data/lib/active_support/descendants_tracker.rb +104 -132
  93. data/lib/active_support/duration/iso8601_serializer.rb +0 -2
  94. data/lib/active_support/duration.rb +2 -1
  95. data/lib/active_support/encrypted_configuration.rb +63 -11
  96. data/lib/active_support/encrypted_file.rb +16 -12
  97. data/lib/active_support/environment_inquirer.rb +22 -2
  98. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  99. data/lib/active_support/error_reporter.rb +121 -35
  100. data/lib/active_support/evented_file_update_checker.rb +17 -2
  101. data/lib/active_support/execution_wrapper.rb +4 -4
  102. data/lib/active_support/file_update_checker.rb +4 -2
  103. data/lib/active_support/fork_tracker.rb +10 -2
  104. data/lib/active_support/gem_version.rb +4 -4
  105. data/lib/active_support/gzip.rb +2 -0
  106. data/lib/active_support/hash_with_indifferent_access.rb +35 -17
  107. data/lib/active_support/html_safe_translation.rb +16 -6
  108. data/lib/active_support/i18n.rb +1 -1
  109. data/lib/active_support/i18n_railtie.rb +20 -13
  110. data/lib/active_support/inflector/inflections.rb +2 -0
  111. data/lib/active_support/inflector/methods.rb +28 -18
  112. data/lib/active_support/inflector/transliterate.rb +3 -1
  113. data/lib/active_support/isolated_execution_state.rb +26 -22
  114. data/lib/active_support/json/decoding.rb +2 -1
  115. data/lib/active_support/json/encoding.rb +25 -43
  116. data/lib/active_support/key_generator.rb +9 -1
  117. data/lib/active_support/lazy_load_hooks.rb +7 -5
  118. data/lib/active_support/locale/en.yml +2 -0
  119. data/lib/active_support/log_subscriber.rb +85 -33
  120. data/lib/active_support/logger.rb +9 -60
  121. data/lib/active_support/logger_thread_safe_level.rb +10 -24
  122. data/lib/active_support/message_encryptor.rb +197 -53
  123. data/lib/active_support/message_encryptors.rb +141 -0
  124. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  125. data/lib/active_support/message_pack/extensions.rb +292 -0
  126. data/lib/active_support/message_pack/serializer.rb +63 -0
  127. data/lib/active_support/message_pack.rb +50 -0
  128. data/lib/active_support/message_verifier.rb +212 -93
  129. data/lib/active_support/message_verifiers.rb +135 -0
  130. data/lib/active_support/messages/codec.rb +65 -0
  131. data/lib/active_support/messages/metadata.rb +111 -45
  132. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  133. data/lib/active_support/messages/rotator.rb +34 -32
  134. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  135. data/lib/active_support/multibyte/chars.rb +2 -0
  136. data/lib/active_support/multibyte/unicode.rb +9 -37
  137. data/lib/active_support/notifications/fanout.rb +245 -81
  138. data/lib/active_support/notifications/instrumenter.rb +87 -22
  139. data/lib/active_support/notifications.rb +3 -3
  140. data/lib/active_support/number_helper/number_converter.rb +14 -5
  141. data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -6
  142. data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -3
  143. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -0
  144. data/lib/active_support/number_helper.rb +379 -317
  145. data/lib/active_support/ordered_hash.rb +3 -3
  146. data/lib/active_support/ordered_options.rb +14 -0
  147. data/lib/active_support/parameter_filter.rb +103 -84
  148. data/lib/active_support/proxy_object.rb +2 -0
  149. data/lib/active_support/railtie.rb +33 -21
  150. data/lib/active_support/reloader.rb +12 -4
  151. data/lib/active_support/rescuable.rb +2 -0
  152. data/lib/active_support/secure_compare_rotator.rb +16 -9
  153. data/lib/active_support/string_inquirer.rb +3 -1
  154. data/lib/active_support/subscriber.rb +9 -27
  155. data/lib/active_support/syntax_error_proxy.rb +60 -0
  156. data/lib/active_support/tagged_logging.rb +64 -24
  157. data/lib/active_support/test_case.rb +153 -6
  158. data/lib/active_support/testing/assertions.rb +26 -10
  159. data/lib/active_support/testing/autorun.rb +0 -2
  160. data/lib/active_support/testing/constant_stubbing.rb +32 -0
  161. data/lib/active_support/testing/deprecation.rb +25 -25
  162. data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
  163. data/lib/active_support/testing/isolation.rb +29 -28
  164. data/lib/active_support/testing/method_call_assertions.rb +21 -8
  165. data/lib/active_support/testing/parallelize_executor.rb +8 -3
  166. data/lib/active_support/testing/setup_and_teardown.rb +2 -0
  167. data/lib/active_support/testing/stream.rb +1 -1
  168. data/lib/active_support/testing/strict_warnings.rb +39 -0
  169. data/lib/active_support/testing/time_helpers.rb +37 -15
  170. data/lib/active_support/time_with_zone.rb +8 -37
  171. data/lib/active_support/values/time_zone.rb +18 -7
  172. data/lib/active_support/version.rb +1 -1
  173. data/lib/active_support/xml_mini/jdom.rb +3 -10
  174. data/lib/active_support/xml_mini/nokogiri.rb +1 -1
  175. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  176. data/lib/active_support/xml_mini/rexml.rb +1 -1
  177. data/lib/active_support/xml_mini.rb +2 -2
  178. data/lib/active_support.rb +14 -3
  179. metadata +148 -19
  180. data/lib/active_support/core_ext/array/deprecated_conversions.rb +0 -25
  181. data/lib/active_support/core_ext/date/deprecated_conversions.rb +0 -26
  182. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +0 -22
  183. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +0 -60
  184. data/lib/active_support/core_ext/range/deprecated_conversions.rb +0 -26
  185. data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -7
  186. data/lib/active_support/core_ext/range/overlaps.rb +0 -10
  187. data/lib/active_support/core_ext/time/deprecated_conversions.rb +0 -22
  188. data/lib/active_support/core_ext/uri.rb +0 -5
  189. data/lib/active_support/per_thread_registry.rb +0 -65
@@ -7,7 +7,7 @@ YAML.add_builtin_type("omap") do |type, val|
7
7
  end
8
8
 
9
9
  module ActiveSupport
10
- # DEPRECATED: <tt>ActiveSupport::OrderedHash</tt> implements a hash that preserves
10
+ # DEPRECATED: +ActiveSupport::OrderedHash+ implements a hash that preserves
11
11
  # insertion order.
12
12
  #
13
13
  # oh = ActiveSupport::OrderedHash.new
@@ -17,9 +17,9 @@ module ActiveSupport
17
17
  #
18
18
  # Also, maps the +omap+ feature for YAML files
19
19
  # (See https://yaml.org/type/omap.html) to support ordered items
20
- # when loading from yaml.
20
+ # when loading from YAML.
21
21
  #
22
- # <tt>ActiveSupport::OrderedHash</tt> is namespaced to prevent conflicts
22
+ # +ActiveSupport::OrderedHash+ is namespaced to prevent conflicts
23
23
  # with other implementations.
24
24
  class OrderedHash < ::Hash # :nodoc:
25
25
  def to_yaml_type
@@ -3,6 +3,8 @@
3
3
  require "active_support/core_ext/object/blank"
4
4
 
5
5
  module ActiveSupport
6
+ # = Ordered Options
7
+ #
6
8
  # +OrderedOptions+ inherits from +Hash+ and provides dynamic accessor methods.
7
9
  #
8
10
  # With a +Hash+, key-value pairs are typically managed like this:
@@ -40,6 +42,10 @@ module ActiveSupport
40
42
  super(key.to_sym)
41
43
  end
42
44
 
45
+ def dig(key, *identifiers)
46
+ super(key.to_sym, *identifiers)
47
+ end
48
+
43
49
  def method_missing(name, *args)
44
50
  name_string = +name.to_s
45
51
  if name_string.chomp!("=")
@@ -68,6 +74,8 @@ module ActiveSupport
68
74
  end
69
75
  end
70
76
 
77
+ # = Inheritable Options
78
+ #
71
79
  # +InheritableOptions+ provides a constructor to build an OrderedOptions
72
80
  # hash inherited from another hash.
73
81
  #
@@ -76,6 +84,12 @@ module ActiveSupport
76
84
  # h = ActiveSupport::InheritableOptions.new({ girl: 'Mary', boy: 'John' })
77
85
  # h.girl # => 'Mary'
78
86
  # h.boy # => 'John'
87
+ #
88
+ # If the existing hash has string keys, call Hash#symbolize_keys on it.
89
+ #
90
+ # h = ActiveSupport::InheritableOptions.new({ 'girl' => 'Mary', 'boy' => 'John' }.symbolize_keys)
91
+ # h.girl # => 'Mary'
92
+ # h.boy # => 'John'
79
93
  class InheritableOptions < OrderedOptions
80
94
  def initialize(parent = nil)
81
95
  if parent.kind_of?(OrderedOptions)
@@ -1,37 +1,72 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/object/duplicable"
4
+ require "active_support/core_ext/array/extract"
4
5
 
5
6
  module ActiveSupport
6
- # +ParameterFilter+ allows you to specify keys for sensitive data from
7
- # hash-like object and replace corresponding value. Filtering only certain
8
- # sub-keys from a hash is possible by using the dot notation:
9
- # 'credit_card.number'. If a proc is given, each key and value of a hash and
10
- # all sub-hashes are passed to it, where the value or the key can be replaced
11
- # using String#replace or similar methods.
7
+ # = Active Support Parameter Filter
12
8
  #
9
+ # +ParameterFilter+ replaces values in a <tt>Hash</tt>-like object if their
10
+ # keys match one of the specified filters.
11
+ #
12
+ # Matching based on nested keys is possible by using dot notation, e.g.
13
+ # <tt>"credit_card.number"</tt>.
14
+ #
15
+ # If a proc is given as a filter, each key and value of the <tt>Hash</tt>-like
16
+ # and of any nested <tt>Hash</tt>es will be passed to it. The value or key can
17
+ # then be mutated as desired using methods such as <tt>String#replace</tt>.
18
+ #
19
+ # # Replaces values with "[FILTERED]" for keys that match /password/i.
13
20
  # ActiveSupport::ParameterFilter.new([:password])
14
- # => replaces the value to all keys matching /password/i with "[FILTERED]"
15
21
  #
22
+ # # Replaces values with "[FILTERED]" for keys that match /foo|bar/i.
16
23
  # ActiveSupport::ParameterFilter.new([:foo, "bar"])
17
- # => replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
18
24
  #
19
- # ActiveSupport::ParameterFilter.new([/\Apin\z/i, /\Apin_/i])
20
- # => replaces the value for the exact (case-insensitive) key 'pin' and all
21
- # (case-insensitive) keys beginning with 'pin_', with "[FILTERED]".
22
- # Does not match keys with 'pin' as a substring, such as 'shipping_id'.
25
+ # # Replaces values for the exact key "pin" and for keys that begin with
26
+ # # "pin_". Does not match keys that otherwise include "pin" as a
27
+ # # substring, such as "shipping_id".
28
+ # ActiveSupport::ParameterFilter.new([/\Apin\z/, /\Apin_/])
23
29
  #
30
+ # # Replaces the value for :code in `{ credit_card: { code: "xxxx" } }`.
31
+ # # Does not change `{ file: { code: "xxxx" } }`.
24
32
  # ActiveSupport::ParameterFilter.new(["credit_card.code"])
25
- # => replaces { credit_card: {code: "xxxx"} } with "[FILTERED]", does not
26
- # change { file: { code: "xxxx"} }
27
33
  #
34
+ # # Reverses values for keys that match /secret/i.
28
35
  # ActiveSupport::ParameterFilter.new([-> (k, v) do
29
36
  # v.reverse! if /secret/i.match?(k)
30
37
  # end])
31
- # => reverses the value to all keys matching /secret/i
38
+ #
32
39
  class ParameterFilter
33
40
  FILTERED = "[FILTERED]" # :nodoc:
34
41
 
42
+ # Precompiles an array of filters that otherwise would be passed directly to
43
+ # #initialize. Depending on the quantity and types of filters,
44
+ # precompilation can improve filtering performance, especially in the case
45
+ # where the ParameterFilter instance itself cannot be retained (but the
46
+ # precompiled filters can be retained).
47
+ #
48
+ # filters = [/foo/, :bar, "nested.baz", /nested\.qux/]
49
+ #
50
+ # precompiled = ActiveSupport::ParameterFilter.precompile_filters(filters)
51
+ # # => [/(?-mix:foo)|(?i:bar)/, /(?i:nested\.baz)|(?-mix:nested\.qux)/]
52
+ #
53
+ # ActiveSupport::ParameterFilter.new(precompiled)
54
+ #
55
+ def self.precompile_filters(filters)
56
+ filters, patterns = filters.partition { |filter| filter.is_a?(Proc) }
57
+
58
+ patterns.map! do |pattern|
59
+ pattern.is_a?(Regexp) ? pattern : "(?i:#{Regexp.escape pattern.to_s})"
60
+ end
61
+
62
+ deep_patterns = patterns.extract! { |pattern| pattern.to_s.include?("\\.") }
63
+
64
+ filters << Regexp.new(patterns.join("|")) if patterns.any?
65
+ filters << Regexp.new(deep_patterns.join("|")) if deep_patterns.any?
66
+
67
+ filters
68
+ end
69
+
35
70
  # Create instance with given filters. Supported type of filters are +String+, +Regexp+, and +Proc+.
36
71
  # Other types of filters are treated as +String+ using +to_s+.
37
72
  # For +Proc+ filters, key, value, and optional original hash is passed to block arguments.
@@ -40,99 +75,83 @@ module ActiveSupport
40
75
  #
41
76
  # * <tt>:mask</tt> - A replaced object when filtered. Defaults to <tt>"[FILTERED]"</tt>.
42
77
  def initialize(filters = [], mask: FILTERED)
43
- @filters = filters
44
78
  @mask = mask
79
+ compile_filters!(filters)
45
80
  end
46
81
 
47
82
  # Mask value of +params+ if key matches one of filters.
48
83
  def filter(params)
49
- compiled_filter.call(params)
84
+ @no_filters ? params.dup : call(params)
50
85
  end
51
86
 
52
87
  # Returns filtered value for given key. For +Proc+ filters, third block argument is not populated.
53
88
  def filter_param(key, value)
54
- @filters.empty? ? value : compiled_filter.value_for_key(key, value)
89
+ @no_filters ? value : value_for_key(key, value)
55
90
  end
56
91
 
57
92
  private
58
- def compiled_filter
59
- @compiled_filter ||= CompiledFilter.compile(@filters, mask: @mask)
60
- end
61
-
62
- class CompiledFilter # :nodoc:
63
- def self.compile(filters, mask:)
64
- return lambda { |params| params.dup } if filters.empty?
65
-
66
- strings, regexps, blocks, deep_regexps, deep_strings = [], [], [], nil, nil
67
-
68
- filters.each do |item|
69
- case item
70
- when Proc
71
- blocks << item
72
- when Regexp
73
- if item.to_s.include?("\\.")
74
- (deep_regexps ||= []) << item
75
- else
76
- regexps << item
77
- end
93
+ def compile_filters!(filters)
94
+ @no_filters = filters.empty?
95
+ return if @no_filters
96
+
97
+ @regexps, strings = [], []
98
+ @deep_regexps, deep_strings = nil, nil
99
+ @blocks = nil
100
+
101
+ filters.each do |item|
102
+ case item
103
+ when Proc
104
+ (@blocks ||= []) << item
105
+ when Regexp
106
+ if item.to_s.include?("\\.")
107
+ (@deep_regexps ||= []) << item
78
108
  else
79
- s = Regexp.escape(item.to_s)
80
- if s.include?("\\.")
81
- (deep_strings ||= []) << s
82
- else
83
- strings << s
84
- end
109
+ @regexps << item
110
+ end
111
+ else
112
+ s = Regexp.escape(item.to_s)
113
+ if s.include?("\\.")
114
+ (deep_strings ||= []) << s
115
+ else
116
+ strings << s
85
117
  end
86
118
  end
87
-
88
- regexps << Regexp.new(strings.join("|"), true) unless strings.empty?
89
- (deep_regexps ||= []) << Regexp.new(deep_strings.join("|"), true) if deep_strings&.any?
90
-
91
- new regexps, deep_regexps, blocks, mask: mask
92
119
  end
93
120
 
94
- attr_reader :regexps, :deep_regexps, :blocks
121
+ @regexps << Regexp.new(strings.join("|"), true) unless strings.empty?
122
+ (@deep_regexps ||= []) << Regexp.new(deep_strings.join("|"), true) if deep_strings
123
+ end
95
124
 
96
- def initialize(regexps, deep_regexps, blocks, mask:)
97
- @regexps = regexps
98
- @deep_regexps = deep_regexps&.any? ? deep_regexps : nil
99
- @blocks = blocks
100
- @mask = mask
101
- end
125
+ def call(params, full_parent_key = nil, original_params = params)
126
+ filtered_params = params.class.new
102
127
 
103
- def call(params, parents = [], original_params = params)
104
- filtered_params = params.class.new
128
+ params.each do |key, value|
129
+ filtered_params[key] = value_for_key(key, value, full_parent_key, original_params)
130
+ end
105
131
 
106
- params.each do |key, value|
107
- filtered_params[key] = value_for_key(key, value, parents, original_params)
108
- end
132
+ filtered_params
133
+ end
109
134
 
110
- filtered_params
135
+ def value_for_key(key, value, full_parent_key = nil, original_params = nil)
136
+ if @deep_regexps
137
+ full_key = full_parent_key ? "#{full_parent_key}.#{key}" : key.to_s
111
138
  end
112
139
 
113
- def value_for_key(key, value, parents = [], original_params = nil)
114
- parents.push(key) if deep_regexps
115
- if regexps.any? { |r| r.match?(key.to_s) }
116
- value = @mask
117
- elsif deep_regexps && (joined = parents.join(".")) && deep_regexps.any? { |r| r.match?(joined) }
118
- value = @mask
119
- elsif value.is_a?(Hash)
120
- value = call(value, parents, original_params)
121
- elsif value.is_a?(Array)
122
- # If we don't pop the current parent it will be duplicated as we
123
- # process each array value.
124
- parents.pop if deep_regexps
125
- value = value.map { |v| value_for_key(key, v, parents, original_params) }
126
- # Restore the parent stack after processing the array.
127
- parents.push(key) if deep_regexps
128
- elsif blocks.any?
129
- key = key.dup if key.duplicable?
130
- value = value.dup if value.duplicable?
131
- blocks.each { |b| b.arity == 2 ? b.call(key, value) : b.call(key, value, original_params) }
132
- end
133
- parents.pop if deep_regexps
134
- value
140
+ if @regexps.any? { |r| r.match?(key.to_s) }
141
+ value = @mask
142
+ elsif @deep_regexps&.any? { |r| r.match?(full_key) }
143
+ value = @mask
144
+ elsif value.is_a?(Hash)
145
+ value = call(value, full_key, original_params)
146
+ elsif value.is_a?(Array)
147
+ value = value.map { |v| value_for_key(key, v, full_parent_key, original_params) }
148
+ elsif @blocks
149
+ key = key.dup if key.duplicable?
150
+ value = value.dup if value.duplicable?
151
+ @blocks.each { |b| b.arity == 2 ? b.call(key, value) : b.call(key, value, original_params) }
135
152
  end
153
+
154
+ value
136
155
  end
137
156
  end
138
157
  end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveSupport
4
+ # = Active Support Proxy \Object
5
+ #
4
6
  # A class with no predefined methods that behaves similarly to Builder's
5
7
  # BlankSlate. Used for proxy classes.
6
8
  class ProxyObject < ::BasicObject
@@ -6,10 +6,13 @@ require "active_support/i18n_railtie"
6
6
  module ActiveSupport
7
7
  class Railtie < Rails::Railtie # :nodoc:
8
8
  config.active_support = ActiveSupport::OrderedOptions.new
9
- config.active_support.disable_to_s_conversion = false
10
9
 
11
10
  config.eager_load_namespaces << ActiveSupport
12
11
 
12
+ initializer "active_support.deprecator", before: :load_environment_config do |app|
13
+ app.deprecators[:active_support] = ActiveSupport.deprecator
14
+ end
15
+
13
16
  initializer "active_support.isolation_level" do |app|
14
17
  config.after_initialize do
15
18
  if level = app.config.active_support.delete(:isolation_level)
@@ -18,11 +21,10 @@ module ActiveSupport
18
21
  end
19
22
  end
20
23
 
21
- initializer "active_support.remove_deprecated_time_with_zone_name" do |app|
24
+ initializer "active_support.raise_on_invalid_cache_expiration_time" do |app|
22
25
  config.after_initialize do
23
- if app.config.active_support.remove_deprecated_time_with_zone_name
24
- require "active_support/time_with_zone"
25
- TimeWithZone.singleton_class.remove_method(:name)
26
+ if app.config.active_support.raise_on_invalid_cache_expiration_time
27
+ ActiveSupport::Cache::Store.raise_on_invalid_cache_expiration_time = true
26
28
  end
27
29
  end
28
30
  end
@@ -63,20 +65,20 @@ module ActiveSupport
63
65
 
64
66
  initializer "active_support.deprecation_behavior" do |app|
65
67
  if app.config.active_support.report_deprecations == false
66
- ActiveSupport::Deprecation.silenced = true
67
- ActiveSupport::Deprecation.behavior = :silence
68
- ActiveSupport::Deprecation.disallowed_behavior = :silence
68
+ app.deprecators.silenced = true
69
+ app.deprecators.behavior = :silence
70
+ app.deprecators.disallowed_behavior = :silence
69
71
  else
70
72
  if deprecation = app.config.active_support.deprecation
71
- ActiveSupport::Deprecation.behavior = deprecation
73
+ app.deprecators.behavior = deprecation
72
74
  end
73
75
 
74
76
  if disallowed_deprecation = app.config.active_support.disallowed_deprecation
75
- ActiveSupport::Deprecation.disallowed_behavior = disallowed_deprecation
77
+ app.deprecators.disallowed_behavior = disallowed_deprecation
76
78
  end
77
79
 
78
80
  if disallowed_warnings = app.config.active_support.disallowed_deprecation_warnings
79
- ActiveSupport::Deprecation.disallowed_warnings = disallowed_warnings
81
+ app.deprecators.disallowed_warnings = disallowed_warnings
80
82
  end
81
83
  end
82
84
  end
@@ -113,14 +115,18 @@ module ActiveSupport
113
115
  end
114
116
  end
115
117
 
116
- initializer "active_support.set_error_reporter" do |app|
117
- ActiveSupport.error_reporter = app.executor.error_reporter
118
- end
119
-
120
118
  initializer "active_support.set_configs" do |app|
121
119
  app.config.active_support.each do |k, v|
122
- k = "#{k}="
123
- ActiveSupport.public_send(k, v) if ActiveSupport.respond_to? k
120
+ if k == :disable_to_s_conversion
121
+ ActiveSupport.deprecator.warn("config.active_support.disable_to_s_conversion is deprecated and will be removed in Rails 7.2.")
122
+ elsif k == :remove_deprecated_time_with_zone_name
123
+ ActiveSupport.deprecator.warn("config.active_support.remove_deprecated_time_with_zone_name is deprecated and will be removed in Rails 7.2.")
124
+ elsif k == :use_rfc4122_namespaced_uuids
125
+ ActiveSupport.deprecator.warn("config.active_support.use_rfc4122_namespaced_uuids is deprecated and will be removed in Rails 7.2.")
126
+ else
127
+ k = "#{k}="
128
+ ActiveSupport.public_send(k, v) if ActiveSupport.respond_to? k
129
+ end
124
130
  end
125
131
  end
126
132
 
@@ -140,13 +146,19 @@ module ActiveSupport
140
146
  end
141
147
  end
142
148
 
143
- initializer "active_support.set_rfc4122_namespaced_uuids" do |app|
149
+ initializer "active_support.set_default_message_serializer" do |app|
144
150
  config.after_initialize do
145
- if app.config.active_support.use_rfc4122_namespaced_uuids
146
- require "active_support/core_ext/digest"
147
- ::Digest::UUID.use_rfc4122_namespaced_uuids = app.config.active_support.use_rfc4122_namespaced_uuids
151
+ if message_serializer = app.config.active_support.message_serializer
152
+ ActiveSupport::Messages::Codec.default_serializer = message_serializer
148
153
  end
149
154
  end
150
155
  end
156
+
157
+ initializer "active_support.set_use_message_serializer_for_metadata" do |app|
158
+ config.after_initialize do
159
+ ActiveSupport::Messages::Metadata.use_message_serializer_for_metadata =
160
+ app.config.active_support.use_message_serializer_for_metadata
161
+ end
162
+ end
151
163
  end
152
164
  end
@@ -4,7 +4,8 @@ require "active_support/execution_wrapper"
4
4
  require "active_support/executor"
5
5
 
6
6
  module ActiveSupport
7
- #--
7
+ # = Active Support \Reloader
8
+ #
8
9
  # This class defines several callbacks:
9
10
  #
10
11
  # to_prepare -- Run once at application startup, and also from
@@ -67,9 +68,16 @@ module ActiveSupport
67
68
  end
68
69
 
69
70
  # Run the supplied block as a work unit, reloading code as needed
70
- def self.wrap
71
- executor.wrap do
72
- super
71
+ def self.wrap(**kwargs)
72
+ return yield if active?
73
+
74
+ executor.wrap(**kwargs) do
75
+ instance = run!
76
+ begin
77
+ yield
78
+ ensure
79
+ instance.complete!
80
+ end
73
81
  end
74
82
  end
75
83
 
@@ -5,6 +5,8 @@ require "active_support/core_ext/class/attribute"
5
5
  require "active_support/core_ext/string/inflections"
6
6
 
7
7
  module ActiveSupport
8
+ # = Active Support \Rescuable
9
+ #
8
10
  # Rescuable module adds support for easier exception handling.
9
11
  module Rescuable
10
12
  extend Concern
@@ -4,6 +4,8 @@ require "active_support/security_utils"
4
4
  require "active_support/messages/rotator"
5
5
 
6
6
  module ActiveSupport
7
+ # = Secure Compare Rotator
8
+ #
7
9
  # The ActiveSupport::SecureCompareRotator is a wrapper around ActiveSupport::SecurityUtils.secure_compare
8
10
  # and allows you to rotate a previously defined value to a new one.
9
11
  #
@@ -29,23 +31,28 @@ module ActiveSupport
29
31
  # end
30
32
  class SecureCompareRotator
31
33
  include SecurityUtils
32
- prepend Messages::Rotator
33
34
 
34
35
  InvalidMatch = Class.new(StandardError)
35
36
 
36
- def initialize(value, **_options)
37
+ def initialize(value, on_rotation: nil)
37
38
  @value = value
39
+ @rotate_values = []
40
+ @on_rotation = on_rotation
38
41
  end
39
42
 
40
- def secure_compare!(other_value, on_rotation: @on_rotation)
41
- secure_compare(@value, other_value) ||
42
- run_rotations(on_rotation) { |wrapper| wrapper.secure_compare!(other_value) } ||
43
- raise(InvalidMatch)
43
+ def rotate(previous_value)
44
+ @rotate_values << previous_value
44
45
  end
45
46
 
46
- private
47
- def build_rotation(previous_value, _options)
48
- self.class.new(previous_value)
47
+ def secure_compare!(other_value, on_rotation: @on_rotation)
48
+ if secure_compare(@value, other_value)
49
+ true
50
+ elsif @rotate_values.any? { |value| secure_compare(value, other_value) }
51
+ on_rotation&.call
52
+ true
53
+ else
54
+ raise InvalidMatch
49
55
  end
56
+ end
50
57
  end
51
58
  end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveSupport
4
+ # = \String Inquirer
5
+ #
4
6
  # Wrapping a string in this class gives you a prettier way to test
5
7
  # for equality. The value returned by <tt>Rails.env</tt> is wrapped
6
8
  # in a StringInquirer object, so instead of calling this:
@@ -11,7 +13,7 @@ module ActiveSupport
11
13
  #
12
14
  # Rails.env.production?
13
15
  #
14
- # == Instantiating a new StringInquirer
16
+ # == Instantiating a new \StringInquirer
15
17
  #
16
18
  # vehicle = ActiveSupport::StringInquirer.new('car')
17
19
  # vehicle.car? # => true
@@ -3,7 +3,9 @@
3
3
  require "active_support/notifications"
4
4
 
5
5
  module ActiveSupport
6
- # ActiveSupport::Subscriber is an object set to consume
6
+ # = Active Support \Subscriber
7
+ #
8
+ # +ActiveSupport::Subscriber+ is an object set to consume
7
9
  # ActiveSupport::Notifications. The subscriber dispatches notifications to
8
10
  # a registered object based on its given namespace.
9
11
  #
@@ -20,9 +22,9 @@ module ActiveSupport
20
22
  # end
21
23
  # end
22
24
  #
23
- # After configured, whenever a "sql.active_record" notification is published,
24
- # it will properly dispatch the event (ActiveSupport::Notifications::Event) to
25
- # the +sql+ method.
25
+ # After configured, whenever a <tt>"sql.active_record"</tt> notification is
26
+ # published, it will properly dispatch the event
27
+ # (ActiveSupport::Notifications::Event) to the +sql+ method.
26
28
  #
27
29
  # We can detach a subscriber as well:
28
30
  #
@@ -126,38 +128,18 @@ module ActiveSupport
126
128
  attr_reader :patterns # :nodoc:
127
129
 
128
130
  def initialize
129
- @queue_key = [self.class.name, object_id].join "-"
130
131
  @patterns = {}
131
132
  super
132
133
  end
133
134
 
134
- def start(name, id, payload)
135
- event = ActiveSupport::Notifications::Event.new(name, nil, nil, id, payload)
136
- event.start!
137
- parent = event_stack.last
138
- parent << event if parent
139
-
140
- event_stack.push event
141
- end
142
-
143
- def finish(name, id, payload)
144
- event = event_stack.pop
145
- event.finish!
146
- event.payload.merge!(payload)
147
-
148
- method = name.split(".").first
135
+ def call(event)
136
+ method = event.name[0, event.name.index(".")]
149
137
  send(method, event)
150
138
  end
151
139
 
152
140
  def publish_event(event) # :nodoc:
153
- method = event.name.split(".").first
141
+ method = event.name[0, event.name.index(".")]
154
142
  send(method, event)
155
143
  end
156
-
157
- private
158
- def event_stack
159
- registry = ActiveSupport::IsolatedExecutionState[:active_support_subscriber_queue_registry] ||= {}
160
- registry[@queue_key] ||= []
161
- end
162
144
  end
163
145
  end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "delegate"
4
+
5
+ module ActiveSupport
6
+ # This is a class for wrapping syntax errors. The purpose of this class
7
+ # is to enhance the backtraces on SyntaxError exceptions to include the
8
+ # source location of the syntax error. That way we can display the error
9
+ # source on error pages in development.
10
+ class SyntaxErrorProxy < DelegateClass(SyntaxError) # :nodoc:
11
+ def backtrace
12
+ parse_message_for_trace + super
13
+ end
14
+
15
+ class BacktraceLocation < Struct.new(:path, :lineno, :to_s) # :nodoc:
16
+ def spot(_)
17
+ end
18
+
19
+ def label
20
+ end
21
+ end
22
+
23
+ class BacktraceLocationProxy < DelegateClass(Thread::Backtrace::Location) # :nodoc:
24
+ def initialize(loc, ex)
25
+ super(loc)
26
+ @ex = ex
27
+ end
28
+
29
+ def spot(_)
30
+ super(@ex.__getobj__)
31
+ end
32
+ end
33
+
34
+ def backtrace_locations
35
+ return nil if super.nil?
36
+
37
+ parse_message_for_trace.map { |trace|
38
+ file, line = trace.match(/^(.+?):(\d+).*$/, &:captures) || trace
39
+ BacktraceLocation.new(file, line.to_i, trace)
40
+ # We have to wrap these backtrace locations because we need the
41
+ # spot information to come from the originating exception, not the
42
+ # proxy object that's generating these
43
+ } + super.map { |loc| BacktraceLocationProxy.new(loc, self) }
44
+ end
45
+
46
+ private
47
+ def parse_message_for_trace
48
+ if __getobj__.to_s.start_with?("(eval")
49
+ # If the exception is coming from a call to eval, we need to keep
50
+ # the path of the file in which eval was called to ensure we can
51
+ # return the right source fragment to show the location of the
52
+ # error
53
+ location = __getobj__.backtrace_locations[0]
54
+ ["#{location.path}:#{location.lineno}: #{__getobj__}"]
55
+ else
56
+ __getobj__.to_s.split("\n")
57
+ end
58
+ end
59
+ end
60
+ end