activesupport 7.1.5.1 → 7.2.0.beta1

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 (88) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +113 -1178
  3. data/lib/active_support/array_inquirer.rb +1 -1
  4. data/lib/active_support/backtrace_cleaner.rb +10 -3
  5. data/lib/active_support/broadcast_logger.rb +18 -19
  6. data/lib/active_support/cache/file_store.rb +15 -10
  7. data/lib/active_support/cache/mem_cache_store.rb +16 -74
  8. data/lib/active_support/cache/memory_store.rb +2 -1
  9. data/lib/active_support/cache/redis_cache_store.rb +16 -13
  10. data/lib/active_support/cache/serializer_with_fallback.rb +0 -23
  11. data/lib/active_support/cache.rb +59 -67
  12. data/lib/active_support/callbacks.rb +74 -113
  13. data/lib/active_support/code_generator.rb +10 -15
  14. data/lib/active_support/core_ext/array/conversions.rb +0 -2
  15. data/lib/active_support/core_ext/class/subclasses.rb +15 -35
  16. data/lib/active_support/core_ext/date/blank.rb +4 -0
  17. data/lib/active_support/core_ext/date/conversions.rb +0 -2
  18. data/lib/active_support/core_ext/date_and_time/compatibility.rb +12 -9
  19. data/lib/active_support/core_ext/date_time/blank.rb +4 -0
  20. data/lib/active_support/core_ext/date_time/compatibility.rb +3 -5
  21. data/lib/active_support/core_ext/date_time/conversions.rb +0 -4
  22. data/lib/active_support/core_ext/erb/util.rb +5 -0
  23. data/lib/active_support/core_ext/hash/keys.rb +4 -4
  24. data/lib/active_support/core_ext/module/attr_internal.rb +17 -6
  25. data/lib/active_support/core_ext/module/delegation.rb +20 -163
  26. data/lib/active_support/core_ext/module/deprecation.rb +1 -4
  27. data/lib/active_support/core_ext/numeric/conversions.rb +3 -3
  28. data/lib/active_support/core_ext/object/blank.rb +45 -1
  29. data/lib/active_support/core_ext/object/instance_variables.rb +11 -19
  30. data/lib/active_support/core_ext/object/json.rb +4 -6
  31. data/lib/active_support/core_ext/object/with.rb +5 -3
  32. data/lib/active_support/core_ext/pathname/blank.rb +4 -0
  33. data/lib/active_support/core_ext/range/overlap.rb +1 -1
  34. data/lib/active_support/core_ext/string/conversions.rb +1 -1
  35. data/lib/active_support/core_ext/string/filters.rb +1 -1
  36. data/lib/active_support/core_ext/string/output_safety.rb +0 -7
  37. data/lib/active_support/core_ext/time/calculations.rb +12 -27
  38. data/lib/active_support/core_ext/time/compatibility.rb +2 -3
  39. data/lib/active_support/core_ext/time/conversions.rb +0 -2
  40. data/lib/active_support/core_ext.rb +0 -1
  41. data/lib/active_support/current_attributes.rb +33 -40
  42. data/lib/active_support/delegation.rb +188 -0
  43. data/lib/active_support/dependencies/autoload.rb +0 -12
  44. data/lib/active_support/deprecation/constant_accessor.rb +1 -3
  45. data/lib/active_support/deprecation/proxy_wrappers.rb +9 -12
  46. data/lib/active_support/deprecation/reporting.rb +9 -4
  47. data/lib/active_support/deprecation.rb +8 -5
  48. data/lib/active_support/descendants_tracker.rb +9 -87
  49. data/lib/active_support/duration/iso8601_parser.rb +2 -2
  50. data/lib/active_support/duration/iso8601_serializer.rb +1 -2
  51. data/lib/active_support/duration.rb +11 -6
  52. data/lib/active_support/error_reporter.rb +41 -3
  53. data/lib/active_support/evented_file_update_checker.rb +0 -1
  54. data/lib/active_support/execution_wrapper.rb +0 -1
  55. data/lib/active_support/file_update_checker.rb +1 -1
  56. data/lib/active_support/fork_tracker.rb +2 -38
  57. data/lib/active_support/gem_version.rb +3 -3
  58. data/lib/active_support/hash_with_indifferent_access.rb +6 -8
  59. data/lib/active_support/html_safe_translation.rb +3 -0
  60. data/lib/active_support/log_subscriber.rb +0 -12
  61. data/lib/active_support/logger.rb +15 -2
  62. data/lib/active_support/message_pack/extensions.rb +15 -2
  63. data/lib/active_support/multibyte/chars.rb +2 -2
  64. data/lib/active_support/notifications/fanout.rb +4 -7
  65. data/lib/active_support/notifications/instrumenter.rb +21 -18
  66. data/lib/active_support/notifications.rb +28 -27
  67. data/lib/active_support/number_helper/number_converter.rb +2 -2
  68. data/lib/active_support/option_merger.rb +2 -2
  69. data/lib/active_support/ordered_options.rb +53 -15
  70. data/lib/active_support/proxy_object.rb +8 -5
  71. data/lib/active_support/railtie.rb +4 -11
  72. data/lib/active_support/string_inquirer.rb +1 -1
  73. data/lib/active_support/syntax_error_proxy.rb +11 -1
  74. data/lib/active_support/test_case.rb +3 -1
  75. data/lib/active_support/testing/assertions.rb +4 -4
  76. data/lib/active_support/testing/constant_stubbing.rb +30 -8
  77. data/lib/active_support/testing/deprecation.rb +5 -12
  78. data/lib/active_support/testing/isolation.rb +18 -8
  79. data/lib/active_support/testing/method_call_assertions.rb +2 -16
  80. data/lib/active_support/testing/strict_warnings.rb +5 -4
  81. data/lib/active_support/testing/tests_without_assertions.rb +19 -0
  82. data/lib/active_support/time_with_zone.rb +9 -10
  83. data/lib/active_support/values/time_zone.rb +1 -1
  84. data/lib/active_support/xml_mini.rb +11 -2
  85. data/lib/active_support.rb +7 -8
  86. metadata +20 -70
  87. data/lib/active_support/deprecation/instance_delegator.rb +0 -65
  88. data/lib/active_support/ruby_features.rb +0 -7
@@ -46,18 +46,14 @@ module ActiveSupport
46
46
  super(key.to_sym, *identifiers)
47
47
  end
48
48
 
49
- def method_missing(name, *args)
50
- name_string = +name.to_s
51
- if name_string.chomp!("=")
52
- self[name_string] = args.first
49
+ def method_missing(method, *args)
50
+ if method.end_with?("=")
51
+ self[method.name.chomp("=")] = args.first
52
+ elsif method.end_with?("!")
53
+ name_string = method.name.chomp("!")
54
+ self[name_string].presence || raise(KeyError.new(":#{name_string} is blank"))
53
55
  else
54
- bangs = name_string.chomp!("!")
55
-
56
- if bangs
57
- self[name_string].presence || raise(KeyError.new(":#{name_string} is blank"))
58
- else
59
- self[name_string]
60
- end
56
+ self[method.name]
61
57
  end
62
58
  end
63
59
 
@@ -92,18 +88,60 @@ module ActiveSupport
92
88
  # h.boy # => 'John'
93
89
  class InheritableOptions < OrderedOptions
94
90
  def initialize(parent = nil)
95
- if parent.kind_of?(OrderedOptions)
91
+ @parent = parent
92
+ if @parent.kind_of?(OrderedOptions)
96
93
  # use the faster _get when dealing with OrderedOptions
97
- super() { |h, k| parent._get(k) }
98
- elsif parent
99
- super() { |h, k| parent[k] }
94
+ super() { |h, k| @parent._get(k) }
95
+ elsif @parent
96
+ super() { |h, k| @parent[k] }
100
97
  else
101
98
  super()
99
+ @parent = {}
102
100
  end
103
101
  end
104
102
 
103
+ def to_h
104
+ @parent.merge(self)
105
+ end
106
+
107
+ def ==(other)
108
+ to_h == other.to_h
109
+ end
110
+
111
+ def inspect
112
+ "#<#{self.class.name} #{to_h.inspect}>"
113
+ end
114
+
115
+ def to_s
116
+ to_h.to_s
117
+ end
118
+
119
+ def pretty_print(pp)
120
+ pp.pp_hash(to_h)
121
+ end
122
+
123
+ alias_method :own_key?, :key?
124
+ private :own_key?
125
+
126
+ def key?(key)
127
+ super || @parent.key?(key)
128
+ end
129
+
130
+ def overridden?(key)
131
+ !!(@parent && @parent.key?(key) && own_key?(key.to_sym))
132
+ end
133
+
105
134
  def inheritable_copy
106
135
  self.class.new(self)
107
136
  end
137
+
138
+ def to_a
139
+ entries
140
+ end
141
+
142
+ def each(&block)
143
+ to_h.each(&block)
144
+ self
145
+ end
108
146
  end
109
147
  end
@@ -1,11 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveSupport
4
- # = Active Support Proxy \Object
5
- #
6
- # A class with no predefined methods that behaves similarly to Builder's
7
- # BlankSlate. Used for proxy classes.
8
- class ProxyObject < ::BasicObject
4
+ class ProxyObject < ::BasicObject # :nodoc:
9
5
  undef_method :==
10
6
  undef_method :equal?
11
7
 
@@ -13,5 +9,12 @@ module ActiveSupport
13
9
  def raise(*args)
14
10
  ::Object.send(:raise, *args)
15
11
  end
12
+
13
+ def self.inherited(_subclass)
14
+ ::ActiveSupport.deprecator.warn(<<~MSG)
15
+ ActiveSupport::ProxyObject is deprecated and will be removed in Rails 7.3.
16
+ Use Ruby's built-in BasicObject instead.
17
+ MSG
18
+ end
16
19
  end
17
20
  end
@@ -89,10 +89,11 @@ module ActiveSupport
89
89
  begin
90
90
  TZInfo::DataSource.get
91
91
  rescue TZInfo::DataSourceNotFound => e
92
- raise e.exception "tzinfo-data is not present. Please add gem 'tzinfo-data' to your Gemfile and run bundle install"
92
+ raise e.exception('tzinfo-data is not present. Please add gem "tzinfo-data" to your Gemfile and run bundle install')
93
93
  end
94
94
  require "active_support/core_ext/time/zones"
95
95
  Time.zone_default = Time.find_zone!(app.config.time_zone)
96
+ config.eager_load_namespaces << TZInfo
96
97
  end
97
98
 
98
99
  # Sets the default week start
@@ -117,16 +118,8 @@ module ActiveSupport
117
118
 
118
119
  initializer "active_support.set_configs" do |app|
119
120
  app.config.active_support.each do |k, v|
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
121
+ k = "#{k}="
122
+ ActiveSupport.public_send(k, v) if ActiveSupport.respond_to? k
130
123
  end
131
124
  end
132
125
 
@@ -24,7 +24,7 @@ module ActiveSupport
24
24
  method_name.end_with?("?") || super
25
25
  end
26
26
 
27
- def method_missing(method_name, *arguments)
27
+ def method_missing(method_name, ...)
28
28
  if method_name.end_with?("?")
29
29
  self == method_name[0..-2]
30
30
  else
@@ -45,7 +45,7 @@ module ActiveSupport
45
45
 
46
46
  private
47
47
  def parse_message_for_trace
48
- if __getobj__.to_s.start_with?("(eval")
48
+ if source_location_eval?
49
49
  # If the exception is coming from a call to eval, we need to keep
50
50
  # the path of the file in which eval was called to ensure we can
51
51
  # return the right source fragment to show the location of the
@@ -56,5 +56,15 @@ module ActiveSupport
56
56
  __getobj__.to_s.split("\n")
57
57
  end
58
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
59
69
  end
60
70
  end
@@ -3,6 +3,7 @@
3
3
  require "minitest"
4
4
  require "active_support/testing/tagged_logging"
5
5
  require "active_support/testing/setup_and_teardown"
6
+ require "active_support/testing/tests_without_assertions"
6
7
  require "active_support/testing/assertions"
7
8
  require "active_support/testing/error_reporter_assertions"
8
9
  require "active_support/testing/deprecation"
@@ -78,7 +79,7 @@ module ActiveSupport
78
79
  # number of tests to run is above the +threshold+ param. The default value is
79
80
  # 50, and it's configurable via +config.active_support.test_parallelization_threshold+.
80
81
  def parallelize(workers: :number_of_processors, with: :processes, threshold: ActiveSupport.test_parallelization_threshold)
81
- workers = Concurrent.physical_processor_count if workers == :number_of_processors
82
+ workers = Concurrent.processor_count if workers == :number_of_processors
82
83
  workers = ENV["PARALLEL_WORKERS"].to_i if ENV["PARALLEL_WORKERS"]
83
84
 
84
85
  Minitest.parallel_executor = ActiveSupport::Testing::ParallelizeExecutor.new(size: workers, with: with, threshold: threshold)
@@ -142,6 +143,7 @@ module ActiveSupport
142
143
 
143
144
  include ActiveSupport::Testing::TaggedLogging
144
145
  prepend ActiveSupport::Testing::SetupAndTeardown
146
+ prepend ActiveSupport::Testing::TestsWithoutAssertions
145
147
  include ActiveSupport::Testing::Assertions
146
148
  include ActiveSupport::Testing::ErrorReporterAssertions
147
149
  include ActiveSupport::Testing::Deprecation
@@ -195,7 +195,7 @@ module ActiveSupport
195
195
  retval = _assert_nothing_raised_or_warn("assert_changes", &block)
196
196
 
197
197
  unless from == UNTRACKED
198
- error = "Expected change from #{from.inspect}, got #{before}"
198
+ error = "Expected change from #{from.inspect}, got #{before.inspect}"
199
199
  error = "#{message}.\n#{error}" if message
200
200
  assert from === before, error
201
201
  end
@@ -203,12 +203,12 @@ module ActiveSupport
203
203
  after = exp.call
204
204
 
205
205
  error = "#{expression.inspect} didn't change"
206
- error = "#{error}. It was already #{to}" if before == to
206
+ error = "#{error}. It was already #{to.inspect}" if before == to
207
207
  error = "#{message}.\n#{error}" if message
208
208
  refute_equal before, after, error
209
209
 
210
210
  unless to == UNTRACKED
211
- error = "Expected change to #{to}, got #{after}\n"
211
+ error = "Expected change to #{to.inspect}, got #{after.inspect}\n"
212
212
  error = "#{message}.\n#{error}" if message
213
213
  assert to === after, error
214
214
  end
@@ -242,7 +242,7 @@ module ActiveSupport
242
242
  retval = _assert_nothing_raised_or_warn("assert_no_changes", &block)
243
243
 
244
244
  unless from == UNTRACKED
245
- error = "Expected initial value of #{from.inspect}"
245
+ error = "Expected initial value of #{from.inspect}, got #{before.inspect}"
246
246
  error = "#{message}.\n#{error}" if message
247
247
  assert from === before, error
248
248
  end
@@ -15,17 +15,39 @@ module ActiveSupport
15
15
  # Using this method rather than forcing <tt>World::List::Import::LARGE_IMPORT_THRESHOLD = 5000</tt> prevents
16
16
  # warnings from being thrown, and ensures that the old value is returned after the test has completed.
17
17
  #
18
+ # If the constant doesn't already exists, but you need it set for the duration of the block
19
+ # you can do so by passing `exists: false`.
20
+ #
21
+ # stub_const(object, :SOME_CONST, 1, exists: false) do
22
+ # assert_equal 1, SOME_CONST
23
+ # end
24
+ #
18
25
  # Note: Stubbing a const will stub it across all threads. So if you have concurrent threads
19
26
  # (like separate test suites running in parallel) that all depend on the same constant, it's possible
20
27
  # divergent stubbing will trample on each other.
21
- def stub_const(mod, constant, new_value)
22
- old_value = mod.const_get(constant, false)
23
- mod.send(:remove_const, constant)
24
- mod.const_set(constant, new_value)
25
- yield
26
- ensure
27
- mod.send(:remove_const, constant)
28
- mod.const_set(constant, old_value)
28
+ def stub_const(mod, constant, new_value, exists: true)
29
+ if exists
30
+ begin
31
+ old_value = mod.const_get(constant, false)
32
+ mod.send(:remove_const, constant)
33
+ mod.const_set(constant, new_value)
34
+ yield
35
+ ensure
36
+ mod.send(:remove_const, constant)
37
+ mod.const_set(constant, old_value)
38
+ end
39
+ else
40
+ if mod.const_defined?(constant)
41
+ raise NameError, "already defined constant #{constant} in #{mod.name}"
42
+ end
43
+
44
+ begin
45
+ mod.const_set(constant, new_value)
46
+ yield
47
+ ensure
48
+ mod.send(:remove_const, constant)
49
+ end
50
+ end
29
51
  end
30
52
  end
31
53
  end
@@ -29,10 +29,11 @@ module ActiveSupport
29
29
  # end
30
30
  def assert_deprecated(match = nil, deprecator = nil, &block)
31
31
  match, deprecator = nil, match if match.is_a?(ActiveSupport::Deprecation)
32
+
32
33
  unless deprecator
33
- ActiveSupport.deprecator.warn("assert_deprecated without a deprecator is deprecated")
34
- deprecator = ActiveSupport::Deprecation._instance
34
+ raise ArgumentError, "No deprecator given"
35
35
  end
36
+
36
37
  result, warnings = collect_deprecations(deprecator, &block)
37
38
  assert !warnings.empty?, "Expected a deprecation warning within the block but received none"
38
39
  if match
@@ -51,11 +52,7 @@ module ActiveSupport
51
52
  # assert_not_deprecated(ActiveSupport::Deprecation.new) do
52
53
  # CustomDeprecator.warn "message" # passes assertion, different deprecator
53
54
  # end
54
- def assert_not_deprecated(deprecator = nil, &block)
55
- unless deprecator
56
- ActiveSupport.deprecator.warn("assert_not_deprecated without a deprecator is deprecated")
57
- deprecator = ActiveSupport::Deprecation._instance
58
- end
55
+ def assert_not_deprecated(deprecator, &block)
59
56
  result, deprecations = collect_deprecations(deprecator, &block)
60
57
  assert deprecations.empty?, "Expected no deprecation warning within the block but received #{deprecations.size}: \n #{deprecations * "\n "}"
61
58
  result
@@ -69,11 +66,7 @@ module ActiveSupport
69
66
  # ActiveSupport::Deprecation.new.warn "other message"
70
67
  # :result
71
68
  # end # => [:result, ["message"]]
72
- def collect_deprecations(deprecator = nil)
73
- unless deprecator
74
- ActiveSupport.deprecator.warn("collect_deprecations without a deprecator is deprecated")
75
- deprecator = ActiveSupport::Deprecation._instance
76
- end
69
+ def collect_deprecations(deprecator)
77
70
  old_behavior = deprecator.behavior
78
71
  deprecations = []
79
72
  deprecator.behavior = Proc.new do |message, callstack|
@@ -5,9 +5,11 @@ module ActiveSupport
5
5
  module Isolation
6
6
  require "thread"
7
7
 
8
+ SubprocessCrashed = Class.new(StandardError)
9
+
8
10
  def self.included(klass) # :nodoc:
9
11
  klass.class_eval do
10
- parallelize_me!
12
+ parallelize_me! unless Minitest.parallel_executor.is_a?(ActiveSupport::Testing::ParallelizeExecutor)
11
13
  end
12
14
  end
13
15
 
@@ -16,10 +18,17 @@ module ActiveSupport
16
18
  end
17
19
 
18
20
  def run
19
- serialized = run_in_isolation do
21
+ status, serialized = run_in_isolation do
20
22
  super
21
23
  end
22
24
 
25
+ unless status&.success?
26
+ error = SubprocessCrashed.new("Subprocess exited with an error: #{status.inspect}\noutput: #{serialized.inspect}")
27
+ error.set_backtrace(caller)
28
+ self.failures << Minitest::UnexpectedError.new(error)
29
+ return defined?(Minitest::Result) ? Minitest::Result.from(self) : dup
30
+ end
31
+
23
32
  Marshal.load(serialized)
24
33
  end
25
34
 
@@ -50,13 +59,13 @@ module ActiveSupport
50
59
  end
51
60
 
52
61
  write.puts [result].pack("m")
53
- exit!
62
+ exit!(0)
54
63
  end
55
64
 
56
65
  write.close
57
66
  result = read.read
58
- Process.wait2(pid)
59
- result.unpack1("m")
67
+ _, status = Process.wait2(pid)
68
+ return status, result.unpack1("m")
60
69
  end
61
70
  end
62
71
  end
@@ -75,7 +84,7 @@ module ActiveSupport
75
84
  File.open(ENV["ISOLATION_OUTPUT"], "w") do |file|
76
85
  file.puts [Marshal.dump(test_result)].pack("m")
77
86
  end
78
- exit!
87
+ exit!(0)
79
88
  else
80
89
  Tempfile.open("isolation") do |tmpfile|
81
90
  env = {
@@ -93,13 +102,14 @@ module ActiveSupport
93
102
 
94
103
  child = IO.popen([env, Gem.ruby, *load_path_args, $0, *ORIG_ARGV, test_opts])
95
104
 
105
+ status = nil
96
106
  begin
97
- Process.wait(child.pid)
107
+ _, status = Process.wait2(child.pid)
98
108
  rescue Errno::ECHILD # The child process may exit before we wait
99
109
  nil
100
110
  end
101
111
 
102
- return tmpfile.read.unpack1("m")
112
+ return status, tmpfile.read.unpack1("m")
103
113
  end
104
114
  end
105
115
  end
@@ -30,22 +30,8 @@ module ActiveSupport
30
30
  assert_called(object, method_name, message, times: 0, &block)
31
31
  end
32
32
 
33
- #--
34
- # This method is a temporary wrapper for mock.expect as part of
35
- # the Minitest 5.16 / Ruby 3.0 kwargs transition. It can go away
36
- # when we drop support for Ruby 2.7.
37
- if Minitest::Mock.instance_method(:expect).parameters.map(&:first).include?(:keyrest)
38
- def expect_called_with(mock, args, returns: false, **kwargs)
39
- mock.expect(:call, returns, args, **kwargs)
40
- end
41
- else
42
- def expect_called_with(mock, args, returns: false, **kwargs)
43
- if !kwargs.empty?
44
- mock.expect(:call, returns, [*args, kwargs])
45
- else
46
- mock.expect(:call, returns, args)
47
- end
48
- end
33
+ def expect_called_with(mock, args, returns: false, **kwargs)
34
+ mock.expect(:call, returns, args, **kwargs)
49
35
  end
50
36
 
51
37
  def assert_called_on_instance_of(klass, method_name, message = nil, times: 1, returns: nil)
@@ -5,6 +5,8 @@ Warning[:deprecated] = true
5
5
 
6
6
  module ActiveSupport
7
7
  module RaiseWarnings # :nodoc:
8
+ class WarningError < StandardError; end
9
+
8
10
  PROJECT_ROOT = File.expand_path("../../../../", __dir__)
9
11
  ALLOWED_WARNINGS = Regexp.union(
10
12
  /circular require considered harmful.*delayed_job/, # Bug in delayed job.
@@ -21,18 +23,17 @@ module ActiveSupport
21
23
  %r{/lib/mail/parsers/.*assigned but unused variable - testEof}
22
24
  )
23
25
 
24
- def warn(message, *)
26
+ def warn(message, ...)
25
27
  return if SUPPRESSED_WARNINGS.match?(message)
26
28
 
27
29
  super
28
30
 
29
31
  return unless message.include?(PROJECT_ROOT)
30
32
  return if ALLOWED_WARNINGS.match?(message)
31
- return unless ENV["RAILS_STRICT_WARNINGS"] || ENV["CI"]
33
+ return unless ENV["RAILS_STRICT_WARNINGS"] || ENV["BUILDKITE"]
32
34
 
33
- raise message
35
+ raise WarningError.new(message)
34
36
  end
35
- ruby2_keywords :warn if respond_to?(:ruby2_keywords, true)
36
37
  end
37
38
  end
38
39
 
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module Testing
5
+ # Warns when a test case does not perform any assertions.
6
+ #
7
+ # This is helpful in detecting broken tests that do not perform intended assertions.
8
+ module TestsWithoutAssertions # :nodoc:
9
+ def after_teardown
10
+ super
11
+
12
+ if assertions.zero? && !skipped? && !error?
13
+ file, line = method(name).source_location
14
+ warn "Test is missing assertions: `#{name}` #{file}:#{line}"
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -375,8 +375,8 @@ module ActiveSupport
375
375
  #
376
376
  # t = Time.zone.now # => Fri, 14 Apr 2017 11:45:15.116992711 EST -05:00
377
377
  # t.change(year: 2020) # => Tue, 14 Apr 2020 11:45:15.116992711 EST -05:00
378
- # t.change(hour: 12) # => Fri, 14 Apr 2017 12:00:00.116992711 EST -05:00
379
- # t.change(min: 30) # => Fri, 14 Apr 2017 11:30:00.116992711 EST -05:00
378
+ # t.change(hour: 12) # => Fri, 14 Apr 2017 12:00:00.000000000 EST -05:00
379
+ # t.change(min: 30) # => Fri, 14 Apr 2017 11:30:00.000000000 EST -05:00
380
380
  # t.change(offset: "-10:00") # => Fri, 14 Apr 2017 11:45:15.116992711 HST -10:00
381
381
  # t.change(zone: "Hawaii") # => Fri, 14 Apr 2017 11:45:15.116992711 HST -10:00
382
382
  def change(options)
@@ -479,15 +479,10 @@ module ActiveSupport
479
479
  @to_datetime ||= utc.to_datetime.new_offset(Rational(utc_offset, 86_400))
480
480
  end
481
481
 
482
- # Returns an instance of +Time+, either with the same UTC offset
483
- # as +self+ or in the local system timezone depending on the setting
484
- # of +ActiveSupport.to_time_preserves_timezone+.
482
+ # Returns an instance of +Time+ with the same UTC offset
483
+ # as +self+.
485
484
  def to_time
486
- if preserve_timezone
487
- @to_time_with_instance_offset ||= getlocal(utc_offset)
488
- else
489
- @to_time_with_system_offset ||= getlocal
490
- end
485
+ @to_time_with_instance_offset ||= getlocal(utc_offset)
491
486
  end
492
487
 
493
488
  # So that +self+ <tt>acts_like?(:time)</tt>.
@@ -506,6 +501,10 @@ module ActiveSupport
506
501
  false
507
502
  end
508
503
 
504
+ def present? # :nodoc:
505
+ true
506
+ end
507
+
509
508
  def freeze
510
509
  # preload instance variables before freezing
511
510
  period; utc; time; to_datetime; to_time
@@ -134,10 +134,10 @@ module ActiveSupport
134
134
  "Mumbai" => "Asia/Kolkata",
135
135
  "New Delhi" => "Asia/Kolkata",
136
136
  "Kathmandu" => "Asia/Kathmandu",
137
- "Astana" => "Asia/Dhaka",
138
137
  "Dhaka" => "Asia/Dhaka",
139
138
  "Sri Jayawardenepura" => "Asia/Colombo",
140
139
  "Almaty" => "Asia/Almaty",
140
+ "Astana" => "Asia/Almaty",
141
141
  "Novosibirsk" => "Asia/Novosibirsk",
142
142
  "Rangoon" => "Asia/Rangoon",
143
143
  "Bangkok" => "Asia/Bangkok",
@@ -12,7 +12,7 @@ module ActiveSupport
12
12
  # = \XmlMini
13
13
  #
14
14
  # To use the much faster libxml parser:
15
- # gem 'libxml-ruby'
15
+ # gem "libxml-ruby"
16
16
  # XmlMini.backend = 'LibXML'
17
17
  module XmlMini
18
18
  extend self
@@ -46,6 +46,7 @@ module ActiveSupport
46
46
  "Date" => "date",
47
47
  "DateTime" => "dateTime",
48
48
  "Time" => "dateTime",
49
+ "ActiveSupport::Duration" => "duration",
49
50
  "Array" => "array",
50
51
  "Hash" => "hash"
51
52
  }
@@ -56,6 +57,7 @@ module ActiveSupport
56
57
  "symbol" => Proc.new { |symbol| symbol.to_s },
57
58
  "date" => Proc.new { |date| date.to_fs(:db) },
58
59
  "dateTime" => Proc.new { |time| time.xmlschema },
60
+ "duration" => Proc.new { |duration| duration.iso8601 },
59
61
  "binary" => Proc.new { |binary| ::Base64.encode64(binary) },
60
62
  "yaml" => Proc.new { |yaml| yaml.to_yaml }
61
63
  } unless defined?(FORMATTING)
@@ -66,6 +68,7 @@ module ActiveSupport
66
68
  "symbol" => Proc.new { |symbol| symbol.to_s.to_sym },
67
69
  "date" => Proc.new { |date| ::Date.parse(date) },
68
70
  "datetime" => Proc.new { |time| Time.xmlschema(time).utc rescue ::DateTime.parse(time).utc },
71
+ "duration" => Proc.new { |duration| Duration.parse(duration) },
69
72
  "integer" => Proc.new { |integer| integer.to_i },
70
73
  "float" => Proc.new { |float| float.to_f },
71
74
  "decimal" => Proc.new do |number|
@@ -79,6 +82,7 @@ module ActiveSupport
79
82
  "string" => Proc.new { |string| string.to_s },
80
83
  "yaml" => Proc.new { |yaml| YAML.load(yaml) rescue yaml },
81
84
  "base64Binary" => Proc.new { |bin| ::Base64.decode64(bin) },
85
+ "hexBinary" => Proc.new { |bin| _parse_hex_binary(bin) },
82
86
  "binary" => Proc.new { |bin, entity| _parse_binary(bin, entity) },
83
87
  "file" => Proc.new { |file, entity| _parse_file(file, entity) }
84
88
  }
@@ -162,11 +166,12 @@ module ActiveSupport
162
166
  "#{left}#{middle.tr('_ ', '--')}#{right}"
163
167
  end
164
168
 
165
- # TODO: Add support for other encodings
166
169
  def _parse_binary(bin, entity)
167
170
  case entity["encoding"]
168
171
  when "base64"
169
172
  ::Base64.decode64(bin)
173
+ when "hex", "hexBinary"
174
+ _parse_hex_binary(bin)
170
175
  else
171
176
  bin
172
177
  end
@@ -180,6 +185,10 @@ module ActiveSupport
180
185
  f
181
186
  end
182
187
 
188
+ def _parse_hex_binary(bin)
189
+ [bin].pack("H*")
190
+ end
191
+
183
192
  def current_thread_backend
184
193
  IsolatedExecutionState[:xml_mini_backend]
185
194
  end
@@ -63,6 +63,7 @@ module ActiveSupport
63
63
  autoload :Callbacks
64
64
  autoload :Configurable
65
65
  autoload :Deprecation
66
+ autoload :Delegation
66
67
  autoload :Digest
67
68
  autoload :ExecutionContext
68
69
  autoload :Gzip
@@ -110,17 +111,15 @@ module ActiveSupport
110
111
  end
111
112
 
112
113
  def self.to_time_preserves_timezone
113
- DateAndTime::Compatibility.preserve_timezone
114
+ ActiveSupport.deprecator.warn(
115
+ "`config.active_support.to_time_preserves_timezone` has been deprecated and will be removed in Rails 7.3."
116
+ )
114
117
  end
115
118
 
116
119
  def self.to_time_preserves_timezone=(value)
117
- unless value
118
- ActiveSupport.deprecator.warn(
119
- "Support for the pre-Ruby 2.4 behavior of to_time has been deprecated and will be removed in Rails 7.2."
120
- )
121
- end
122
-
123
- DateAndTime::Compatibility.preserve_timezone = value
120
+ ActiveSupport.deprecator.warn(
121
+ "`config.active_support.to_time_preserves_timezone` has been deprecated and will be removed in Rails 7.3."
122
+ )
124
123
  end
125
124
 
126
125
  def self.utc_to_local_returns_utc_offset_times