activesupport 6.1.1 → 7.0.2.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (168) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +231 -383
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/active_support/actionable_error.rb +1 -1
  6. data/lib/active_support/array_inquirer.rb +0 -2
  7. data/lib/active_support/benchmarkable.rb +2 -2
  8. data/lib/active_support/cache/file_store.rb +16 -10
  9. data/lib/active_support/cache/mem_cache_store.rb +133 -34
  10. data/lib/active_support/cache/memory_store.rb +23 -15
  11. data/lib/active_support/cache/null_store.rb +10 -2
  12. data/lib/active_support/cache/redis_cache_store.rb +42 -67
  13. data/lib/active_support/cache/strategy/local_cache.rb +35 -61
  14. data/lib/active_support/cache.rb +196 -46
  15. data/lib/active_support/callbacks.rb +180 -81
  16. data/lib/active_support/code_generator.rb +65 -0
  17. data/lib/active_support/concern.rb +5 -5
  18. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
  19. data/lib/active_support/concurrency/share_lock.rb +2 -2
  20. data/lib/active_support/configurable.rb +6 -3
  21. data/lib/active_support/configuration_file.rb +7 -2
  22. data/lib/active_support/core_ext/array/access.rb +1 -5
  23. data/lib/active_support/core_ext/array/conversions.rb +13 -11
  24. data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
  25. data/lib/active_support/core_ext/array/grouping.rb +6 -6
  26. data/lib/active_support/core_ext/array.rb +1 -0
  27. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  28. data/lib/active_support/core_ext/class/subclasses.rb +25 -17
  29. data/lib/active_support/core_ext/date/blank.rb +1 -1
  30. data/lib/active_support/core_ext/date/calculations.rb +4 -4
  31. data/lib/active_support/core_ext/date/conversions.rb +11 -11
  32. data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
  33. data/lib/active_support/core_ext/date.rb +1 -0
  34. data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
  35. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  36. data/lib/active_support/core_ext/date_time/conversions.rb +13 -13
  37. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
  38. data/lib/active_support/core_ext/date_time.rb +1 -0
  39. data/lib/active_support/core_ext/digest/uuid.rb +39 -13
  40. data/lib/active_support/core_ext/enumerable.rb +78 -26
  41. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  42. data/lib/active_support/core_ext/hash/keys.rb +1 -1
  43. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  44. data/lib/active_support/core_ext/module/attribute_accessors.rb +2 -0
  45. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +19 -10
  46. data/lib/active_support/core_ext/module/delegation.rb +2 -8
  47. data/lib/active_support/core_ext/name_error.rb +2 -8
  48. data/lib/active_support/core_ext/numeric/conversions.rb +79 -76
  49. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
  50. data/lib/active_support/core_ext/numeric.rb +1 -0
  51. data/lib/active_support/core_ext/object/acts_like.rb +29 -5
  52. data/lib/active_support/core_ext/object/blank.rb +2 -2
  53. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  54. data/lib/active_support/core_ext/object/duplicable.rb +11 -0
  55. data/lib/active_support/core_ext/object/json.rb +29 -24
  56. data/lib/active_support/core_ext/object/to_query.rb +2 -2
  57. data/lib/active_support/core_ext/object/try.rb +20 -20
  58. data/lib/active_support/core_ext/object/with_options.rb +20 -1
  59. data/lib/active_support/core_ext/pathname/existence.rb +21 -0
  60. data/lib/active_support/core_ext/pathname.rb +3 -0
  61. data/lib/active_support/core_ext/range/compare_range.rb +0 -25
  62. data/lib/active_support/core_ext/range/conversions.rb +8 -8
  63. data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
  64. data/lib/active_support/core_ext/range/each.rb +1 -1
  65. data/lib/active_support/core_ext/range/include_time_with_zone.rb +4 -25
  66. data/lib/active_support/core_ext/range.rb +1 -1
  67. data/lib/active_support/core_ext/string/filters.rb +1 -1
  68. data/lib/active_support/core_ext/string/inflections.rb +1 -1
  69. data/lib/active_support/core_ext/string/output_safety.rb +60 -36
  70. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
  71. data/lib/active_support/core_ext/time/calculations.rb +7 -5
  72. data/lib/active_support/core_ext/time/conversions.rb +13 -12
  73. data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
  74. data/lib/active_support/core_ext/time/zones.rb +4 -19
  75. data/lib/active_support/core_ext/time.rb +1 -0
  76. data/lib/active_support/core_ext/uri.rb +3 -27
  77. data/lib/active_support/core_ext.rb +1 -0
  78. data/lib/active_support/current_attributes.rb +32 -14
  79. data/lib/active_support/dependencies/interlock.rb +10 -18
  80. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  81. data/lib/active_support/dependencies.rb +58 -788
  82. data/lib/active_support/deprecation/behaviors.rb +4 -1
  83. data/lib/active_support/deprecation/method_wrappers.rb +3 -3
  84. data/lib/active_support/deprecation/proxy_wrappers.rb +1 -1
  85. data/lib/active_support/deprecation.rb +1 -1
  86. data/lib/active_support/descendants_tracker.rb +174 -68
  87. data/lib/active_support/digest.rb +5 -3
  88. data/lib/active_support/duration/iso8601_parser.rb +3 -3
  89. data/lib/active_support/duration/iso8601_serializer.rb +9 -1
  90. data/lib/active_support/duration.rb +81 -51
  91. data/lib/active_support/encrypted_configuration.rb +13 -2
  92. data/lib/active_support/encrypted_file.rb +1 -1
  93. data/lib/active_support/environment_inquirer.rb +1 -1
  94. data/lib/active_support/error_reporter.rb +117 -0
  95. data/lib/active_support/evented_file_update_checker.rb +1 -1
  96. data/lib/active_support/execution_context/test_helper.rb +13 -0
  97. data/lib/active_support/execution_context.rb +53 -0
  98. data/lib/active_support/execution_wrapper.rb +43 -21
  99. data/lib/active_support/executor/test_helper.rb +7 -0
  100. data/lib/active_support/fork_tracker.rb +19 -10
  101. data/lib/active_support/gem_version.rb +4 -4
  102. data/lib/active_support/hash_with_indifferent_access.rb +9 -2
  103. data/lib/active_support/html_safe_translation.rb +43 -0
  104. data/lib/active_support/i18n.rb +1 -0
  105. data/lib/active_support/i18n_railtie.rb +1 -1
  106. data/lib/active_support/inflector/inflections.rb +23 -7
  107. data/lib/active_support/inflector/methods.rb +24 -48
  108. data/lib/active_support/isolated_execution_state.rb +64 -0
  109. data/lib/active_support/json/encoding.rb +3 -3
  110. data/lib/active_support/key_generator.rb +18 -1
  111. data/lib/active_support/locale/en.yml +2 -2
  112. data/lib/active_support/log_subscriber.rb +13 -3
  113. data/lib/active_support/logger_thread_safe_level.rb +4 -13
  114. data/lib/active_support/message_encryptor.rb +8 -3
  115. data/lib/active_support/message_verifier.rb +46 -14
  116. data/lib/active_support/messages/metadata.rb +2 -2
  117. data/lib/active_support/multibyte/chars.rb +10 -11
  118. data/lib/active_support/multibyte/unicode.rb +0 -12
  119. data/lib/active_support/multibyte.rb +1 -1
  120. data/lib/active_support/notifications/fanout.rb +91 -65
  121. data/lib/active_support/notifications/instrumenter.rb +32 -15
  122. data/lib/active_support/notifications.rb +16 -22
  123. data/lib/active_support/number_helper/number_converter.rb +1 -3
  124. data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
  125. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  126. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  127. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
  128. data/lib/active_support/number_helper/number_to_rounded_converter.rb +10 -6
  129. data/lib/active_support/number_helper/rounding_helper.rb +2 -6
  130. data/lib/active_support/number_helper.rb +0 -2
  131. data/lib/active_support/option_merger.rb +8 -16
  132. data/lib/active_support/ordered_hash.rb +1 -1
  133. data/lib/active_support/parameter_filter.rb +6 -1
  134. data/lib/active_support/per_thread_registry.rb +5 -0
  135. data/lib/active_support/railtie.rb +69 -19
  136. data/lib/active_support/reloader.rb +1 -1
  137. data/lib/active_support/rescuable.rb +2 -2
  138. data/lib/active_support/ruby_features.rb +7 -0
  139. data/lib/active_support/secure_compare_rotator.rb +1 -1
  140. data/lib/active_support/security_utils.rb +1 -1
  141. data/lib/active_support/string_inquirer.rb +0 -2
  142. data/lib/active_support/subscriber.rb +7 -18
  143. data/lib/active_support/tagged_logging.rb +2 -2
  144. data/lib/active_support/test_case.rb +9 -21
  145. data/lib/active_support/testing/assertions.rb +35 -5
  146. data/lib/active_support/testing/deprecation.rb +52 -1
  147. data/lib/active_support/testing/isolation.rb +2 -2
  148. data/lib/active_support/testing/method_call_assertions.rb +5 -5
  149. data/lib/active_support/testing/parallelization/server.rb +4 -0
  150. data/lib/active_support/testing/parallelization/worker.rb +3 -0
  151. data/lib/active_support/testing/parallelization.rb +4 -0
  152. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  153. data/lib/active_support/testing/stream.rb +3 -5
  154. data/lib/active_support/testing/tagged_logging.rb +1 -1
  155. data/lib/active_support/testing/time_helpers.rb +13 -2
  156. data/lib/active_support/time_with_zone.rb +55 -14
  157. data/lib/active_support/values/time_zone.rb +31 -10
  158. data/lib/active_support/xml_mini/jdom.rb +1 -1
  159. data/lib/active_support/xml_mini/libxml.rb +5 -5
  160. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  161. data/lib/active_support/xml_mini/nokogiri.rb +4 -4
  162. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  163. data/lib/active_support/xml_mini/rexml.rb +1 -1
  164. data/lib/active_support/xml_mini.rb +5 -4
  165. data/lib/active_support.rb +17 -1
  166. metadata +26 -23
  167. data/lib/active_support/core_ext/marshal.rb +0 -26
  168. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
@@ -4,7 +4,30 @@ require "active_support/deprecation"
4
4
 
5
5
  module ActiveSupport
6
6
  module Testing
7
- module Deprecation #:nodoc:
7
+ module Deprecation
8
+ # Asserts that a matching deprecation warning was emitted by the given deprecator during the execution of the yielded block.
9
+ #
10
+ # assert_deprecated(/foo/, CustomDeprecator) do
11
+ # CustomDeprecator.warn "foo should no longer be used"
12
+ # end
13
+ #
14
+ # The +match+ object may be a +Regexp+, or +String+ appearing in the message.
15
+ #
16
+ # assert_deprecated('foo', CustomDeprecator) do
17
+ # CustomDeprecator.warn "foo should no longer be used"
18
+ # end
19
+ #
20
+ # If the +match+ is omitted (or explicitly +nil+), any deprecation warning will match.
21
+ #
22
+ # assert_deprecated(nil, CustomDeprecator) do
23
+ # CustomDeprecator.warn "foo should no longer be used"
24
+ # end
25
+ #
26
+ # If no +deprecator+ is given, defaults to ActiveSupport::Deprecation.
27
+ #
28
+ # assert_deprecated do
29
+ # ActiveSupport::Deprecation.warn "foo should no longer be used"
30
+ # end
8
31
  def assert_deprecated(match = nil, deprecator = nil, &block)
9
32
  result, warnings = collect_deprecations(deprecator, &block)
10
33
  assert !warnings.empty?, "Expected a deprecation warning within the block but received none"
@@ -15,12 +38,40 @@ module ActiveSupport
15
38
  result
16
39
  end
17
40
 
41
+ # Asserts that no deprecation warnings are emitted by the given deprecator during the execution of the yielded block.
42
+ #
43
+ # assert_not_deprecated(CustomDeprecator) do
44
+ # CustomDeprecator.warn "message" # fails assertion
45
+ # end
46
+ #
47
+ # If no +deprecator+ is given, defaults to ActiveSupport::Deprecation.
48
+ #
49
+ # assert_not_deprecated do
50
+ # ActiveSupport::Deprecation.warn "message" # fails assertion
51
+ # end
52
+ #
53
+ # assert_not_deprecated do
54
+ # CustomDeprecator.warn "message" # passes assertion
55
+ # end
18
56
  def assert_not_deprecated(deprecator = nil, &block)
19
57
  result, deprecations = collect_deprecations(deprecator, &block)
20
58
  assert deprecations.empty?, "Expected no deprecation warning within the block but received #{deprecations.size}: \n #{deprecations * "\n "}"
21
59
  result
22
60
  end
23
61
 
62
+ # Returns an array of all the deprecation warnings emitted by the given
63
+ # +deprecator+ during the execution of the yielded block.
64
+ #
65
+ # collect_deprecations(CustomDeprecator) do
66
+ # CustomDeprecator.warn "message"
67
+ # end # => ["message"]
68
+ #
69
+ # If no +deprecator+ is given, defaults to ActiveSupport::Deprecation.
70
+ #
71
+ # collect_deprecations do
72
+ # CustomDeprecator.warn "custom message"
73
+ # ActiveSupport::Deprecation.warn "message"
74
+ # end # => ["message"]
24
75
  def collect_deprecations(deprecator = nil)
25
76
  deprecator ||= ActiveSupport::Deprecation
26
77
  old_behavior = deprecator.behavior
@@ -5,7 +5,7 @@ module ActiveSupport
5
5
  module Isolation
6
6
  require "thread"
7
7
 
8
- def self.included(klass) #:nodoc:
8
+ def self.included(klass) # :nodoc:
9
9
  klass.class_eval do
10
10
  parallelize_me!
11
11
  end
@@ -63,7 +63,7 @@ module ActiveSupport
63
63
  module Subprocess
64
64
  ORIG_ARGV = ARGV.dup unless defined?(ORIG_ARGV)
65
65
 
66
- # Crazy H4X to get this working in windows / jruby with
66
+ # Complicated H4X to get this working in windows / jruby with
67
67
  # no forking.
68
68
  def run_in_isolation(&blk)
69
69
  require "tempfile"
@@ -6,10 +6,10 @@ module ActiveSupport
6
6
  module Testing
7
7
  module MethodCallAssertions # :nodoc:
8
8
  private
9
- def assert_called(object, method_name, message = nil, times: 1, returns: nil)
9
+ def assert_called(object, method_name, message = nil, times: 1, returns: nil, &block)
10
10
  times_called = 0
11
11
 
12
- object.stub(method_name, proc { times_called += 1; returns }) { yield }
12
+ object.stub(method_name, proc { times_called += 1; returns }, &block)
13
13
 
14
14
  error = "Expected #{method_name} to be called #{times} times, " \
15
15
  "but was called #{times_called} times"
@@ -17,16 +17,16 @@ module ActiveSupport
17
17
  assert_equal times, times_called, error
18
18
  end
19
19
 
20
- def assert_called_with(object, method_name, args, returns: nil)
20
+ def assert_called_with(object, method_name, args, returns: nil, &block)
21
21
  mock = Minitest::Mock.new
22
22
 
23
- if args.all? { |arg| arg.is_a?(Array) }
23
+ if args.all?(Array)
24
24
  args.each { |arg| mock.expect(:call, returns, arg) }
25
25
  else
26
26
  mock.expect(:call, returns, args)
27
27
  end
28
28
 
29
- object.stub(method_name, mock) { yield }
29
+ object.stub(method_name, mock, &block)
30
30
 
31
31
  mock.verify
32
32
  end
@@ -49,6 +49,10 @@ module ActiveSupport
49
49
  @active_workers.size > 0
50
50
  end
51
51
 
52
+ def interrupt
53
+ @queue.clear
54
+ end
55
+
52
56
  def shutdown
53
57
  # Wait for initial queue to drain
54
58
  while @queue.length != 0
@@ -69,6 +69,9 @@ module ActiveSupport
69
69
  Minitest::UnexpectedError.new(error)
70
70
  end
71
71
  @queue.record(reporter, result)
72
+ rescue Interrupt
73
+ @queue.interrupt
74
+ raise
72
75
  end
73
76
 
74
77
  set_process_title("(idle)")
@@ -42,6 +42,10 @@ module ActiveSupport
42
42
  @queue_server << work
43
43
  end
44
44
 
45
+ def size
46
+ @worker_count
47
+ end
48
+
45
49
  def shutdown
46
50
  @queue_server.shutdown
47
51
  @worker_pool.each { |pid| Process.waitpid pid }
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module Testing
5
+ class ParallelizeExecutor # :nodoc:
6
+ attr_reader :size, :parallelize_with, :threshold
7
+
8
+ def initialize(size:, with:, threshold: ActiveSupport.test_parallelization_threshold)
9
+ @size = size
10
+ @parallelize_with = with
11
+ @threshold = threshold
12
+ end
13
+
14
+ def start
15
+ parallelize if should_parallelize?
16
+ show_execution_info
17
+
18
+ parallel_executor.start if parallelized?
19
+ end
20
+
21
+ def <<(work)
22
+ parallel_executor << work if parallelized?
23
+ end
24
+
25
+ def shutdown
26
+ parallel_executor.shutdown if parallelized?
27
+ end
28
+
29
+ private
30
+ def parallel_executor
31
+ @parallel_executor ||= build_parallel_executor
32
+ end
33
+
34
+ def build_parallel_executor
35
+ case parallelize_with
36
+ when :processes
37
+ Testing::Parallelization.new(size)
38
+ when :threads
39
+ ActiveSupport::TestCase.lock_threads = false if defined?(ActiveSupport::TestCase.lock_threads)
40
+ Minitest::Parallel::Executor.new(size)
41
+ else
42
+ raise ArgumentError, "#{parallelize_with} is not a supported parallelization executor."
43
+ end
44
+ end
45
+
46
+ def parallelize
47
+ @parallelized = true
48
+ Minitest::Test.parallelize_me!
49
+ end
50
+
51
+ def parallelized?
52
+ @parallelized if defined?(@parallelized)
53
+ end
54
+
55
+ def should_parallelize?
56
+ ENV["PARALLEL_WORKERS"] || tests_count > threshold
57
+ end
58
+
59
+ def tests_count
60
+ @tests_count ||= Minitest::Runnable.runnables.sum { |runnable| runnable.runnable_methods.size }
61
+ end
62
+
63
+ def show_execution_info
64
+ puts execution_info
65
+ end
66
+
67
+ def execution_info
68
+ if parallelized?
69
+ "Running #{tests_count} tests in parallel using #{parallel_executor.size} #{parallelize_with}"
70
+ else
71
+ "Running #{tests_count} tests in a single process (parallelization threshold is #{threshold})"
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module ActiveSupport
4
4
  module Testing
5
- module Stream #:nodoc:
5
+ module Stream # :nodoc:
6
6
  private
7
7
  def silence_stream(stream)
8
8
  old_stream = stream.dup
@@ -14,11 +14,9 @@ module ActiveSupport
14
14
  old_stream.close
15
15
  end
16
16
 
17
- def quietly
17
+ def quietly(&block)
18
18
  silence_stream(STDOUT) do
19
- silence_stream(STDERR) do
20
- yield
21
- end
19
+ silence_stream(STDERR, &block)
22
20
  end
23
21
  end
24
22
 
@@ -4,7 +4,7 @@ module ActiveSupport
4
4
  module Testing
5
5
  # Logs a "PostsControllerTest: test name" heading before each test to
6
6
  # make test.log easier to search and follow along with.
7
- module TaggedLogging #:nodoc:
7
+ module TaggedLogging # :nodoc:
8
8
  attr_writer :tagged_logger
9
9
 
10
10
  def before_setup
@@ -126,7 +126,7 @@ module ActiveSupport
126
126
  # end
127
127
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
128
128
  def travel_to(date_or_time)
129
- if block_given? && simple_stubs.stubbing(Time, :now)
129
+ if block_given? && in_block
130
130
  travel_to_nested_block_call = <<~MSG
131
131
 
132
132
  Calling `travel_to` with a block, when we have previously already made a call to `travel_to`, can lead to confusing time stubbing.
@@ -156,19 +156,28 @@ module ActiveSupport
156
156
 
157
157
  if date_or_time.is_a?(Date) && !date_or_time.is_a?(DateTime)
158
158
  now = date_or_time.midnight.to_time
159
+ elsif date_or_time.is_a?(String)
160
+ now = Time.zone.parse(date_or_time)
159
161
  else
160
162
  now = date_or_time.to_time.change(usec: 0)
161
163
  end
162
164
 
165
+ stubbed_time = Time.now if simple_stubs.stubbing(Time, :now)
163
166
  simple_stubs.stub_object(Time, :now) { at(now.to_i) }
164
167
  simple_stubs.stub_object(Date, :today) { jd(now.to_date.jd) }
165
168
  simple_stubs.stub_object(DateTime, :now) { jd(now.to_date.jd, now.hour, now.min, now.sec, Rational(now.utc_offset, 86400)) }
166
169
 
167
170
  if block_given?
168
171
  begin
172
+ self.in_block = true
169
173
  yield
170
174
  ensure
171
- travel_back
175
+ if stubbed_time
176
+ travel_to stubbed_time
177
+ else
178
+ travel_back
179
+ end
180
+ self.in_block = false
172
181
  end
173
182
  end
174
183
  end
@@ -230,6 +239,8 @@ module ActiveSupport
230
239
  def simple_stubs
231
240
  @simple_stubs ||= SimpleStubs.new
232
241
  end
242
+
243
+ attr_accessor :in_block
233
244
  end
234
245
  end
235
246
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "yaml"
4
+
3
5
  require "active_support/duration"
4
6
  require "active_support/values/time_zone"
5
7
  require "active_support/core_ext/object/acts_like"
@@ -31,7 +33,7 @@ module ActiveSupport
31
33
  # t.dst? # => true
32
34
  # t.utc_offset # => -14400
33
35
  # t.zone # => "EDT"
34
- # t.to_s(:rfc822) # => "Sun, 18 May 2008 13:27:25 -0400"
36
+ # t.to_fs(:rfc822) # => "Sun, 18 May 2008 13:27:25 -0400"
35
37
  # t + 1.day # => Mon, 19 May 2008 13:27:25.031505668 EDT -04:00
36
38
  # t.beginning_of_year # => Tue, 01 Jan 2008 00:00:00.000000000 EST -05:00
37
39
  # t > Time.utc(1999) # => true
@@ -40,6 +42,13 @@ module ActiveSupport
40
42
  class TimeWithZone
41
43
  # Report class name as 'Time' to thwart type checking.
42
44
  def self.name
45
+ ActiveSupport::Deprecation.warn(<<~EOM)
46
+ ActiveSupport::TimeWithZone.name has been deprecated and
47
+ from Rails 7.1 will use the default Ruby implementation.
48
+ You can set `config.active_support.remove_deprecated_time_with_zone_name = true`
49
+ to enable the new behavior now.
50
+ EOM
51
+
43
52
  "Time"
44
53
  end
45
54
 
@@ -172,12 +181,11 @@ module ActiveSupport
172
181
  end
173
182
  end
174
183
 
175
- def init_with(coder) #:nodoc:
184
+ def init_with(coder) # :nodoc:
176
185
  initialize(coder["utc"], coder["zone"], coder["time"])
177
186
  end
178
187
 
179
- def encode_with(coder) #:nodoc:
180
- coder.tag = "!ruby/object:ActiveSupport::TimeWithZone"
188
+ def encode_with(coder) # :nodoc:
181
189
  coder.map = { "utc" => utc, "zone" => time_zone, "time" => time }
182
190
  end
183
191
 
@@ -194,25 +202,53 @@ module ActiveSupport
194
202
  #
195
203
  # Time.zone.now.rfc2822 # => "Tue, 01 Jan 2013 04:51:39 +0000"
196
204
  def rfc2822
197
- to_s(:rfc822)
205
+ to_fs(:rfc822)
198
206
  end
199
207
  alias_method :rfc822, :rfc2822
200
208
 
209
+ NOT_SET = Object.new # :nodoc:
210
+
201
211
  # Returns a string of the object's date and time.
212
+ def to_s(format = NOT_SET)
213
+ if format == :db
214
+ ActiveSupport::Deprecation.warn(
215
+ "TimeWithZone#to_s(:db) is deprecated. Please use TimeWithZone#to_fs(:db) instead."
216
+ )
217
+ utc.to_fs(format)
218
+ elsif formatter = ::Time::DATE_FORMATS[format]
219
+ ActiveSupport::Deprecation.warn(
220
+ "TimeWithZone#to_s(#{format.inspect}) is deprecated. Please use TimeWithZone#to_fs(#{format.inspect}) instead."
221
+ )
222
+ formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
223
+ elsif format == NOT_SET
224
+ "#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}" # mimicking Ruby Time#to_s format
225
+ else
226
+ ActiveSupport::Deprecation.warn(
227
+ "TimeWithZone#to_s(#{format.inspect}) is deprecated. Please use TimeWithZone#to_fs(#{format.inspect}) instead."
228
+ )
229
+ "#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}" # mimicking Ruby Time#to_s format
230
+ end
231
+ end
232
+
233
+ # Returns a string of the object's date and time.
234
+ #
235
+ # This method is aliased to <tt>to_formatted_s</tt>.
236
+ #
202
237
  # Accepts an optional <tt>format</tt>:
203
238
  # * <tt>:default</tt> - default value, mimics Ruby Time#to_s format.
204
- # * <tt>:db</tt> - format outputs time in UTC :db time. See Time#to_formatted_s(:db).
239
+ # * <tt>:db</tt> - format outputs time in UTC :db time. See Time#to_fs(:db).
205
240
  # * Any key in <tt>Time::DATE_FORMATS</tt> can be used. See active_support/core_ext/time/conversions.rb.
206
- def to_s(format = :default)
241
+ def to_fs(format = :default)
207
242
  if format == :db
208
- utc.to_s(format)
243
+ utc.to_fs(format)
209
244
  elsif formatter = ::Time::DATE_FORMATS[format]
210
245
  formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
211
246
  else
212
- "#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}" # mimicking Ruby Time#to_s format
247
+ # Change to to_s when deprecation is gone.
248
+ "#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}"
213
249
  end
214
250
  end
215
- alias_method :to_formatted_s, :to_s
251
+ alias_method :to_formatted_s, :to_fs
216
252
 
217
253
  # Replaces <tt>%Z</tt> directive with +zone before passing to Time#strftime,
218
254
  # so that zone information is correct.
@@ -301,7 +337,7 @@ module ActiveSupport
301
337
  alias_method :in, :+
302
338
 
303
339
  # Subtracts an interval of time and returns a new TimeWithZone object unless
304
- # the other value `acts_like?` time. Then it will return a Float of the difference
340
+ # the other value +acts_like?+ time. Then it will return a Float of the difference
305
341
  # between the two times that represents the difference between the current
306
342
  # object's time and the +other+ time.
307
343
  #
@@ -440,7 +476,7 @@ module ActiveSupport
440
476
  [time.sec, time.min, time.hour, time.day, time.mon, time.year, time.wday, time.yday, dst?, zone]
441
477
  end
442
478
 
443
- # Returns the object's date and time as a floating point number of seconds
479
+ # Returns the object's date and time as a floating-point number of seconds
444
480
  # since the Epoch (January 1, 1970 00:00 UTC).
445
481
  #
446
482
  # Time.zone.now.to_f # => 1417709320.285418
@@ -534,7 +570,7 @@ module ActiveSupport
534
570
  def method_missing(sym, *args, &block)
535
571
  wrap_with_time_zone time.__send__(sym, *args, &block)
536
572
  rescue NoMethodError => e
537
- raise e, e.message.sub(time.inspect, inspect), e.backtrace
573
+ raise e, e.message.sub(time.inspect, inspect).sub("Time", "ActiveSupport::TimeWithZone"), e.backtrace
538
574
  end
539
575
 
540
576
  private
@@ -568,7 +604,7 @@ module ActiveSupport
568
604
  end
569
605
 
570
606
  def duration_of_variable_length?(obj)
571
- ActiveSupport::Duration === obj && obj.parts.any? { |p| [:years, :months, :weeks, :days].include?(p[0]) }
607
+ ActiveSupport::Duration === obj && obj.variable?
572
608
  end
573
609
 
574
610
  def wrap_with_time_zone(time)
@@ -583,3 +619,8 @@ module ActiveSupport
583
619
  end
584
620
  end
585
621
  end
622
+
623
+ # These prevent Psych from calling `ActiveSupport::TimeWithZone.name`
624
+ # and triggering the deprecation warning about the change in Rails 7.1.
625
+ YAML.load_tags["!ruby/object:ActiveSupport::TimeWithZone"] = "ActiveSupport::TimeWithZone"
626
+ YAML.dump_tags[ActiveSupport::TimeWithZone] = "!ruby/object:ActiveSupport::TimeWithZone"
@@ -229,12 +229,16 @@ module ActiveSupport
229
229
  # Returns +nil+ if no such time zone is known to the system.
230
230
  def [](arg)
231
231
  case arg
232
+ when self
233
+ arg
232
234
  when String
233
235
  begin
234
236
  @lazy_zones_map[arg] ||= create(arg)
235
237
  rescue TZInfo::InvalidTimezoneIdentifier
236
238
  nil
237
239
  end
240
+ when TZInfo::Timezone
241
+ @lazy_zones_map[arg.name] ||= create(arg.name, nil, arg)
238
242
  when Numeric, ActiveSupport::Duration
239
243
  arg *= 3600 if arg.abs <= 13
240
244
  all.find { |z| z.utc_offset == arg.to_i }
@@ -256,7 +260,7 @@ module ActiveSupport
256
260
  @country_zones[code] ||= load_country_zones(code)
257
261
  end
258
262
 
259
- def clear #:nodoc:
263
+ def clear # :nodoc:
260
264
  @lazy_zones_map = Concurrent::Map.new
261
265
  @country_zones = Concurrent::Map.new
262
266
  @zones = nil
@@ -381,14 +385,28 @@ module ActiveSupport
381
385
  # If the string is invalid then an +ArgumentError+ will be raised unlike +parse+
382
386
  # which usually returns +nil+ when given an invalid date string.
383
387
  def iso8601(str)
388
+ # Historically `Date._iso8601(nil)` returns `{}`, but in the `date` gem versions `3.2.1`, `3.1.2`, `3.0.2`,
389
+ # and `2.0.1`, `Date._iso8601(nil)` raises `TypeError` https://github.com/ruby/date/issues/39
390
+ # Future `date` releases are expected to revert back to the original behavior.
391
+ raise ArgumentError, "invalid date" if str.nil?
392
+
384
393
  parts = Date._iso8601(str)
385
394
 
386
- raise ArgumentError, "invalid date" if parts.empty?
395
+ year = parts.fetch(:year)
396
+
397
+ if parts.key?(:yday)
398
+ ordinal_date = Date.ordinal(year, parts.fetch(:yday))
399
+ month = ordinal_date.month
400
+ day = ordinal_date.day
401
+ else
402
+ month = parts.fetch(:mon)
403
+ day = parts.fetch(:mday)
404
+ end
387
405
 
388
406
  time = Time.new(
389
- parts.fetch(:year),
390
- parts.fetch(:mon),
391
- parts.fetch(:mday),
407
+ year,
408
+ month,
409
+ day,
392
410
  parts.fetch(:hour, 0),
393
411
  parts.fetch(:min, 0),
394
412
  parts.fetch(:sec, 0) + parts.fetch(:sec_fraction, 0),
@@ -400,6 +418,9 @@ module ActiveSupport
400
418
  else
401
419
  TimeWithZone.new(nil, self, time)
402
420
  end
421
+
422
+ rescue Date::Error, KeyError
423
+ raise ArgumentError, "invalid date"
403
424
  end
404
425
 
405
426
  # Method for creating new ActiveSupport::TimeWithZone instance in time zone
@@ -508,11 +529,11 @@ module ActiveSupport
508
529
  # Time#in_time_zone() instead.
509
530
  #
510
531
  # As of tzinfo 2, utc_to_local returns a Time with a non-zero utc_offset.
511
- # See the `utc_to_local_returns_utc_offset_times` config for more info.
532
+ # See the +utc_to_local_returns_utc_offset_times+ config for more info.
512
533
  def utc_to_local(time)
513
534
  tzinfo.utc_to_local(time).yield_self do |t|
514
535
  ActiveSupport.utc_to_local_returns_utc_offset_times ?
515
- t : Time.utc(t.year, t.month, t.day, t.hour, t.min, t.sec, t.sec_fraction)
536
+ t : Time.utc(t.year, t.month, t.day, t.hour, t.min, t.sec, t.sec_fraction * 1_000_000)
516
537
  end
517
538
  end
518
539
 
@@ -534,15 +555,15 @@ module ActiveSupport
534
555
  tzinfo.period_for_local(time, dst) { |periods| periods.last }
535
556
  end
536
557
 
537
- def periods_for_local(time) #:nodoc:
558
+ def periods_for_local(time) # :nodoc:
538
559
  tzinfo.periods_for_local(time)
539
560
  end
540
561
 
541
- def init_with(coder) #:nodoc:
562
+ def init_with(coder) # :nodoc:
542
563
  initialize(coder["name"])
543
564
  end
544
565
 
545
- def encode_with(coder) #:nodoc:
566
+ def encode_with(coder) # :nodoc:
546
567
  coder.tag = "!ruby/object:#{self.class}"
547
568
  coder.map = { "name" => tzinfo.name }
548
569
  end
@@ -15,7 +15,7 @@ java_import org.xml.sax.Attributes unless defined? Attributes
15
15
  java_import org.w3c.dom.Node unless defined? Node
16
16
 
17
17
  module ActiveSupport
18
- module XmlMini_JDOM #:nodoc:
18
+ module XmlMini_JDOM # :nodoc:
19
19
  extend self
20
20
 
21
21
  CONTENT_KEY = "__content__"
@@ -5,7 +5,7 @@ require "active_support/core_ext/object/blank"
5
5
  require "stringio"
6
6
 
7
7
  module ActiveSupport
8
- module XmlMini_LibXML #:nodoc:
8
+ module XmlMini_LibXML # :nodoc:
9
9
  extend self
10
10
 
11
11
  # Parse an XML Document string or IO into a simple hash using libxml.
@@ -25,15 +25,15 @@ module ActiveSupport
25
25
  end
26
26
  end
27
27
 
28
- module LibXML #:nodoc:
29
- module Conversions #:nodoc:
30
- module Document #:nodoc:
28
+ module LibXML # :nodoc:
29
+ module Conversions # :nodoc:
30
+ module Document # :nodoc:
31
31
  def to_hash
32
32
  root.to_hash
33
33
  end
34
34
  end
35
35
 
36
- module Node #:nodoc:
36
+ module Node # :nodoc:
37
37
  CONTENT_ROOT = "__content__"
38
38
 
39
39
  # Convert XML document to hash.
@@ -5,7 +5,7 @@ require "active_support/core_ext/object/blank"
5
5
  require "stringio"
6
6
 
7
7
  module ActiveSupport
8
- module XmlMini_LibXMLSAX #:nodoc:
8
+ module XmlMini_LibXMLSAX # :nodoc:
9
9
  extend self
10
10
 
11
11
  # Class that will build the hash while the XML document
@@ -10,7 +10,7 @@ require "active_support/core_ext/object/blank"
10
10
  require "stringio"
11
11
 
12
12
  module ActiveSupport
13
- module XmlMini_Nokogiri #:nodoc:
13
+ module XmlMini_Nokogiri # :nodoc:
14
14
  extend self
15
15
 
16
16
  # Parse an XML Document string or IO into a simple hash using libxml / nokogiri.
@@ -30,14 +30,14 @@ module ActiveSupport
30
30
  end
31
31
  end
32
32
 
33
- module Conversions #:nodoc:
34
- module Document #:nodoc:
33
+ module Conversions # :nodoc:
34
+ module Document # :nodoc:
35
35
  def to_hash
36
36
  root.to_hash
37
37
  end
38
38
  end
39
39
 
40
- module Node #:nodoc:
40
+ module Node # :nodoc:
41
41
  CONTENT_ROOT = "__content__"
42
42
 
43
43
  # Convert XML document to hash.
@@ -10,7 +10,7 @@ require "active_support/core_ext/object/blank"
10
10
  require "stringio"
11
11
 
12
12
  module ActiveSupport
13
- module XmlMini_NokogiriSAX #:nodoc:
13
+ module XmlMini_NokogiriSAX # :nodoc:
14
14
  extend self
15
15
 
16
16
  # Class that will build the hash while the XML document
@@ -5,7 +5,7 @@ require "active_support/core_ext/object/blank"
5
5
  require "stringio"
6
6
 
7
7
  module ActiveSupport
8
- module XmlMini_REXML #:nodoc:
8
+ module XmlMini_REXML # :nodoc:
9
9
  extend self
10
10
 
11
11
  CONTENT_KEY = "__content__"