activesupport 7.0.4 → 7.1.3.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (187) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +996 -232
  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 +25 -5
  8. data/lib/active_support/benchmarkable.rb +1 -0
  9. data/lib/active_support/broadcast_logger.rb +250 -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 +331 -252
  21. data/lib/active_support/callbacks.rb +44 -21
  22. data/lib/active_support/concern.rb +4 -2
  23. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +42 -3
  24. data/lib/active_support/concurrency/null_lock.rb +13 -0
  25. data/lib/active_support/configurable.rb +10 -0
  26. data/lib/active_support/core_ext/array/conversions.rb +2 -1
  27. data/lib/active_support/core_ext/array.rb +0 -1
  28. data/lib/active_support/core_ext/class/subclasses.rb +13 -10
  29. data/lib/active_support/core_ext/date/calculations.rb +15 -0
  30. data/lib/active_support/core_ext/date/conversions.rb +2 -1
  31. data/lib/active_support/core_ext/date.rb +0 -1
  32. data/lib/active_support/core_ext/date_and_time/calculations.rb +10 -0
  33. data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
  34. data/lib/active_support/core_ext/date_time/conversions.rb +6 -2
  35. data/lib/active_support/core_ext/date_time.rb +0 -1
  36. data/lib/active_support/core_ext/digest/uuid.rb +1 -10
  37. data/lib/active_support/core_ext/enumerable.rb +8 -75
  38. data/lib/active_support/core_ext/erb/util.rb +196 -0
  39. data/lib/active_support/core_ext/hash/conversions.rb +1 -1
  40. data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
  41. data/lib/active_support/core_ext/hash/deep_transform_values.rb +3 -3
  42. data/lib/active_support/core_ext/hash/keys.rb +3 -3
  43. data/lib/active_support/core_ext/integer/inflections.rb +12 -12
  44. data/lib/active_support/core_ext/module/attribute_accessors.rb +6 -0
  45. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +34 -16
  46. data/lib/active_support/core_ext/module/concerning.rb +6 -6
  47. data/lib/active_support/core_ext/module/delegation.rb +40 -11
  48. data/lib/active_support/core_ext/module/deprecation.rb +15 -12
  49. data/lib/active_support/core_ext/module/introspection.rb +0 -1
  50. data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
  51. data/lib/active_support/core_ext/numeric/conversions.rb +2 -0
  52. data/lib/active_support/core_ext/numeric.rb +0 -1
  53. data/lib/active_support/core_ext/object/deep_dup.rb +16 -0
  54. data/lib/active_support/core_ext/object/duplicable.rb +5 -5
  55. data/lib/active_support/core_ext/object/inclusion.rb +13 -5
  56. data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
  57. data/lib/active_support/core_ext/object/json.rb +11 -3
  58. data/lib/active_support/core_ext/object/to_query.rb +0 -2
  59. data/lib/active_support/core_ext/object/with.rb +44 -0
  60. data/lib/active_support/core_ext/object/with_options.rb +9 -9
  61. data/lib/active_support/core_ext/object.rb +1 -0
  62. data/lib/active_support/core_ext/pathname/blank.rb +16 -0
  63. data/lib/active_support/core_ext/pathname/existence.rb +2 -0
  64. data/lib/active_support/core_ext/pathname.rb +1 -0
  65. data/lib/active_support/core_ext/range/conversions.rb +28 -7
  66. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  67. data/lib/active_support/core_ext/range.rb +1 -2
  68. data/lib/active_support/core_ext/securerandom.rb +24 -12
  69. data/lib/active_support/core_ext/string/filters.rb +20 -14
  70. data/lib/active_support/core_ext/string/indent.rb +1 -1
  71. data/lib/active_support/core_ext/string/inflections.rb +16 -9
  72. data/lib/active_support/core_ext/string/output_safety.rb +42 -174
  73. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  74. data/lib/active_support/core_ext/time/calculations.rb +22 -2
  75. data/lib/active_support/core_ext/time/conversions.rb +2 -2
  76. data/lib/active_support/core_ext/time/zones.rb +7 -8
  77. data/lib/active_support/core_ext/time.rb +0 -1
  78. data/lib/active_support/current_attributes.rb +15 -6
  79. data/lib/active_support/deep_mergeable.rb +53 -0
  80. data/lib/active_support/dependencies/autoload.rb +17 -12
  81. data/lib/active_support/deprecation/behaviors.rb +65 -42
  82. data/lib/active_support/deprecation/constant_accessor.rb +5 -4
  83. data/lib/active_support/deprecation/deprecators.rb +104 -0
  84. data/lib/active_support/deprecation/disallowed.rb +6 -8
  85. data/lib/active_support/deprecation/instance_delegator.rb +31 -4
  86. data/lib/active_support/deprecation/method_wrappers.rb +6 -23
  87. data/lib/active_support/deprecation/proxy_wrappers.rb +37 -22
  88. data/lib/active_support/deprecation/reporting.rb +42 -25
  89. data/lib/active_support/deprecation.rb +32 -5
  90. data/lib/active_support/deprecator.rb +7 -0
  91. data/lib/active_support/descendants_tracker.rb +104 -132
  92. data/lib/active_support/duration/iso8601_serializer.rb +0 -2
  93. data/lib/active_support/duration.rb +2 -1
  94. data/lib/active_support/encrypted_configuration.rb +63 -11
  95. data/lib/active_support/encrypted_file.rb +16 -12
  96. data/lib/active_support/environment_inquirer.rb +22 -2
  97. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  98. data/lib/active_support/error_reporter.rb +121 -35
  99. data/lib/active_support/evented_file_update_checker.rb +17 -2
  100. data/lib/active_support/execution_wrapper.rb +4 -4
  101. data/lib/active_support/file_update_checker.rb +4 -2
  102. data/lib/active_support/fork_tracker.rb +10 -2
  103. data/lib/active_support/gem_version.rb +4 -4
  104. data/lib/active_support/gzip.rb +2 -0
  105. data/lib/active_support/hash_with_indifferent_access.rb +35 -17
  106. data/lib/active_support/html_safe_translation.rb +12 -2
  107. data/lib/active_support/i18n.rb +1 -1
  108. data/lib/active_support/i18n_railtie.rb +20 -13
  109. data/lib/active_support/inflector/inflections.rb +2 -0
  110. data/lib/active_support/inflector/methods.rb +28 -18
  111. data/lib/active_support/inflector/transliterate.rb +3 -1
  112. data/lib/active_support/isolated_execution_state.rb +26 -22
  113. data/lib/active_support/json/decoding.rb +2 -1
  114. data/lib/active_support/json/encoding.rb +25 -43
  115. data/lib/active_support/key_generator.rb +9 -1
  116. data/lib/active_support/lazy_load_hooks.rb +7 -5
  117. data/lib/active_support/locale/en.yml +2 -0
  118. data/lib/active_support/log_subscriber.rb +84 -33
  119. data/lib/active_support/logger.rb +9 -60
  120. data/lib/active_support/logger_thread_safe_level.rb +10 -24
  121. data/lib/active_support/message_encryptor.rb +197 -53
  122. data/lib/active_support/message_encryptors.rb +141 -0
  123. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  124. data/lib/active_support/message_pack/extensions.rb +292 -0
  125. data/lib/active_support/message_pack/serializer.rb +63 -0
  126. data/lib/active_support/message_pack.rb +50 -0
  127. data/lib/active_support/message_verifier.rb +212 -93
  128. data/lib/active_support/message_verifiers.rb +135 -0
  129. data/lib/active_support/messages/codec.rb +65 -0
  130. data/lib/active_support/messages/metadata.rb +111 -45
  131. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  132. data/lib/active_support/messages/rotator.rb +34 -32
  133. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  134. data/lib/active_support/multibyte/chars.rb +2 -0
  135. data/lib/active_support/multibyte/unicode.rb +9 -37
  136. data/lib/active_support/notifications/fanout.rb +245 -81
  137. data/lib/active_support/notifications/instrumenter.rb +77 -20
  138. data/lib/active_support/notifications.rb +3 -3
  139. data/lib/active_support/number_helper/number_converter.rb +14 -5
  140. data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -6
  141. data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -3
  142. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -0
  143. data/lib/active_support/number_helper.rb +379 -317
  144. data/lib/active_support/ordered_hash.rb +3 -3
  145. data/lib/active_support/ordered_options.rb +14 -0
  146. data/lib/active_support/parameter_filter.rb +103 -84
  147. data/lib/active_support/proxy_object.rb +2 -0
  148. data/lib/active_support/railtie.rb +33 -21
  149. data/lib/active_support/reloader.rb +12 -4
  150. data/lib/active_support/rescuable.rb +2 -0
  151. data/lib/active_support/secure_compare_rotator.rb +16 -9
  152. data/lib/active_support/string_inquirer.rb +3 -1
  153. data/lib/active_support/subscriber.rb +9 -27
  154. data/lib/active_support/syntax_error_proxy.rb +70 -0
  155. data/lib/active_support/tagged_logging.rb +60 -24
  156. data/lib/active_support/test_case.rb +153 -6
  157. data/lib/active_support/testing/assertions.rb +26 -10
  158. data/lib/active_support/testing/autorun.rb +0 -2
  159. data/lib/active_support/testing/constant_stubbing.rb +32 -0
  160. data/lib/active_support/testing/deprecation.rb +25 -25
  161. data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
  162. data/lib/active_support/testing/isolation.rb +29 -28
  163. data/lib/active_support/testing/method_call_assertions.rb +21 -8
  164. data/lib/active_support/testing/parallelize_executor.rb +8 -3
  165. data/lib/active_support/testing/stream.rb +1 -1
  166. data/lib/active_support/testing/strict_warnings.rb +39 -0
  167. data/lib/active_support/testing/time_helpers.rb +37 -15
  168. data/lib/active_support/time_with_zone.rb +8 -37
  169. data/lib/active_support/values/time_zone.rb +9 -7
  170. data/lib/active_support/version.rb +1 -1
  171. data/lib/active_support/xml_mini/jdom.rb +3 -10
  172. data/lib/active_support/xml_mini/nokogiri.rb +1 -1
  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 +2 -2
  176. data/lib/active_support.rb +14 -3
  177. metadata +103 -16
  178. data/lib/active_support/core_ext/array/deprecated_conversions.rb +0 -25
  179. data/lib/active_support/core_ext/date/deprecated_conversions.rb +0 -26
  180. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +0 -22
  181. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +0 -60
  182. data/lib/active_support/core_ext/range/deprecated_conversions.rb +0 -26
  183. data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -7
  184. data/lib/active_support/core_ext/range/overlaps.rb +0 -10
  185. data/lib/active_support/core_ext/time/deprecated_conversions.rb +0 -22
  186. data/lib/active_support/core_ext/uri.rb +0 -5
  187. 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,70 @@
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 source_location_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
+
60
+ if SyntaxError.method_defined?(:path) # Ruby 3.3+
61
+ def source_location_eval?
62
+ __getobj__.path.start_with?("(eval")
63
+ end
64
+ else # 3.2 and older versions of Ruby
65
+ def source_location_eval?
66
+ __getobj__.to_s.start_with?("(eval")
67
+ end
68
+ end
69
+ end
70
+ end