activesupport 6.1.7.2 → 7.0.7

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 (183) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +286 -491
  3. data/README.rdoc +2 -2
  4. data/lib/active_support/actionable_error.rb +1 -1
  5. data/lib/active_support/array_inquirer.rb +0 -2
  6. data/lib/active_support/backtrace_cleaner.rb +2 -2
  7. data/lib/active_support/benchmarkable.rb +2 -2
  8. data/lib/active_support/cache/file_store.rb +15 -9
  9. data/lib/active_support/cache/mem_cache_store.rb +148 -37
  10. data/lib/active_support/cache/memory_store.rb +24 -16
  11. data/lib/active_support/cache/null_store.rb +10 -2
  12. data/lib/active_support/cache/redis_cache_store.rb +59 -78
  13. data/lib/active_support/cache/strategy/local_cache.rb +38 -61
  14. data/lib/active_support/cache.rb +299 -147
  15. data/lib/active_support/callbacks.rb +184 -85
  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 +8 -5
  21. data/lib/active_support/configuration_file.rb +1 -1
  22. data/lib/active_support/core_ext/array/access.rb +1 -5
  23. data/lib/active_support/core_ext/array/conversions.rb +13 -12
  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/inquiry.rb +2 -2
  27. data/lib/active_support/core_ext/array.rb +1 -0
  28. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  29. data/lib/active_support/core_ext/class/subclasses.rb +25 -17
  30. data/lib/active_support/core_ext/date/blank.rb +1 -1
  31. data/lib/active_support/core_ext/date/calculations.rb +24 -9
  32. data/lib/active_support/core_ext/date/conversions.rb +14 -14
  33. data/lib/active_support/core_ext/date/deprecated_conversions.rb +37 -0
  34. data/lib/active_support/core_ext/date.rb +1 -0
  35. data/lib/active_support/core_ext/date_and_time/calculations.rb +4 -4
  36. data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
  37. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  38. data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
  39. data/lib/active_support/core_ext/date_time/conversions.rb +13 -13
  40. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +33 -0
  41. data/lib/active_support/core_ext/date_time.rb +1 -0
  42. data/lib/active_support/core_ext/digest/uuid.rb +39 -14
  43. data/lib/active_support/core_ext/enumerable.rb +112 -38
  44. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  45. data/lib/active_support/core_ext/hash/conversions.rb +0 -1
  46. data/lib/active_support/core_ext/hash/deep_transform_values.rb +3 -3
  47. data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
  48. data/lib/active_support/core_ext/hash/keys.rb +4 -4
  49. data/lib/active_support/core_ext/integer/inflections.rb +12 -12
  50. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  51. data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
  52. data/lib/active_support/core_ext/module/attribute_accessors.rb +2 -0
  53. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +19 -10
  54. data/lib/active_support/core_ext/module/delegation.rb +2 -8
  55. data/lib/active_support/core_ext/name_error.rb +2 -8
  56. data/lib/active_support/core_ext/numeric/conversions.rb +80 -77
  57. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
  58. data/lib/active_support/core_ext/numeric.rb +1 -0
  59. data/lib/active_support/core_ext/object/acts_like.rb +29 -5
  60. data/lib/active_support/core_ext/object/blank.rb +2 -2
  61. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  62. data/lib/active_support/core_ext/object/duplicable.rb +15 -4
  63. data/lib/active_support/core_ext/object/json.rb +30 -25
  64. data/lib/active_support/core_ext/object/to_query.rb +2 -4
  65. data/lib/active_support/core_ext/object/try.rb +20 -20
  66. data/lib/active_support/core_ext/object/with_options.rb +21 -2
  67. data/lib/active_support/core_ext/pathname/existence.rb +21 -0
  68. data/lib/active_support/core_ext/pathname.rb +3 -0
  69. data/lib/active_support/core_ext/range/compare_range.rb +0 -25
  70. data/lib/active_support/core_ext/range/conversions.rb +8 -8
  71. data/lib/active_support/core_ext/range/deprecated_conversions.rb +33 -0
  72. data/lib/active_support/core_ext/range/each.rb +1 -1
  73. data/lib/active_support/core_ext/range/include_time_with_zone.rb +3 -26
  74. data/lib/active_support/core_ext/range/overlaps.rb +1 -1
  75. data/lib/active_support/core_ext/range.rb +1 -1
  76. data/lib/active_support/core_ext/securerandom.rb +1 -1
  77. data/lib/active_support/core_ext/string/conversions.rb +2 -2
  78. data/lib/active_support/core_ext/string/filters.rb +1 -1
  79. data/lib/active_support/core_ext/string/inflections.rb +1 -5
  80. data/lib/active_support/core_ext/string/inquiry.rb +1 -1
  81. data/lib/active_support/core_ext/string/output_safety.rb +66 -38
  82. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
  83. data/lib/active_support/core_ext/time/calculations.rb +11 -8
  84. data/lib/active_support/core_ext/time/conversions.rb +13 -12
  85. data/lib/active_support/core_ext/time/deprecated_conversions.rb +33 -0
  86. data/lib/active_support/core_ext/time/zones.rb +10 -26
  87. data/lib/active_support/core_ext/time.rb +1 -0
  88. data/lib/active_support/core_ext/uri.rb +3 -27
  89. data/lib/active_support/core_ext.rb +1 -0
  90. data/lib/active_support/current_attributes.rb +31 -15
  91. data/lib/active_support/dependencies/interlock.rb +10 -18
  92. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  93. data/lib/active_support/dependencies.rb +58 -788
  94. data/lib/active_support/deprecation/behaviors.rb +8 -5
  95. data/lib/active_support/deprecation/disallowed.rb +3 -3
  96. data/lib/active_support/deprecation/method_wrappers.rb +3 -3
  97. data/lib/active_support/deprecation/proxy_wrappers.rb +2 -2
  98. data/lib/active_support/deprecation.rb +2 -2
  99. data/lib/active_support/descendants_tracker.rb +174 -68
  100. data/lib/active_support/digest.rb +4 -4
  101. data/lib/active_support/duration/iso8601_parser.rb +3 -3
  102. data/lib/active_support/duration/iso8601_serializer.rb +9 -1
  103. data/lib/active_support/duration.rb +77 -48
  104. data/lib/active_support/encrypted_configuration.rb +45 -3
  105. data/lib/active_support/encrypted_file.rb +13 -1
  106. data/lib/active_support/environment_inquirer.rb +1 -1
  107. data/lib/active_support/error_reporter.rb +117 -0
  108. data/lib/active_support/evented_file_update_checker.rb +20 -7
  109. data/lib/active_support/execution_context/test_helper.rb +13 -0
  110. data/lib/active_support/execution_context.rb +53 -0
  111. data/lib/active_support/execution_wrapper.rb +30 -11
  112. data/lib/active_support/executor/test_helper.rb +7 -0
  113. data/lib/active_support/fork_tracker.rb +19 -12
  114. data/lib/active_support/gem_version.rb +4 -4
  115. data/lib/active_support/hash_with_indifferent_access.rb +3 -1
  116. data/lib/active_support/html_safe_translation.rb +43 -0
  117. data/lib/active_support/i18n.rb +1 -0
  118. data/lib/active_support/i18n_railtie.rb +1 -1
  119. data/lib/active_support/inflector/inflections.rb +23 -7
  120. data/lib/active_support/inflector/methods.rb +28 -53
  121. data/lib/active_support/inflector/transliterate.rb +1 -1
  122. data/lib/active_support/isolated_execution_state.rb +72 -0
  123. data/lib/active_support/json/encoding.rb +3 -3
  124. data/lib/active_support/key_generator.rb +22 -5
  125. data/lib/active_support/lazy_load_hooks.rb +28 -4
  126. data/lib/active_support/locale/en.yml +1 -1
  127. data/lib/active_support/log_subscriber/test_helper.rb +2 -2
  128. data/lib/active_support/log_subscriber.rb +15 -5
  129. data/lib/active_support/logger_thread_safe_level.rb +4 -13
  130. data/lib/active_support/message_encryptor.rb +12 -6
  131. data/lib/active_support/message_verifier.rb +46 -14
  132. data/lib/active_support/messages/metadata.rb +2 -2
  133. data/lib/active_support/multibyte/chars.rb +10 -11
  134. data/lib/active_support/multibyte/unicode.rb +0 -12
  135. data/lib/active_support/multibyte.rb +1 -1
  136. data/lib/active_support/notifications/fanout.rb +91 -65
  137. data/lib/active_support/notifications/instrumenter.rb +32 -15
  138. data/lib/active_support/notifications.rb +23 -23
  139. data/lib/active_support/number_helper/number_converter.rb +1 -3
  140. data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
  141. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  142. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  143. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
  144. data/lib/active_support/number_helper/rounding_helper.rb +1 -5
  145. data/lib/active_support/number_helper.rb +4 -5
  146. data/lib/active_support/option_merger.rb +10 -18
  147. data/lib/active_support/ordered_hash.rb +1 -1
  148. data/lib/active_support/ordered_options.rb +1 -1
  149. data/lib/active_support/parameter_filter.rb +20 -11
  150. data/lib/active_support/per_thread_registry.rb +5 -1
  151. data/lib/active_support/railtie.rb +69 -19
  152. data/lib/active_support/rescuable.rb +12 -12
  153. data/lib/active_support/ruby_features.rb +7 -0
  154. data/lib/active_support/secure_compare_rotator.rb +2 -2
  155. data/lib/active_support/string_inquirer.rb +0 -2
  156. data/lib/active_support/subscriber.rb +7 -18
  157. data/lib/active_support/tagged_logging.rb +1 -1
  158. data/lib/active_support/test_case.rb +13 -21
  159. data/lib/active_support/testing/assertions.rb +35 -5
  160. data/lib/active_support/testing/deprecation.rb +52 -1
  161. data/lib/active_support/testing/isolation.rb +30 -29
  162. data/lib/active_support/testing/method_call_assertions.rb +5 -5
  163. data/lib/active_support/testing/parallelization/server.rb +4 -0
  164. data/lib/active_support/testing/parallelization/worker.rb +3 -0
  165. data/lib/active_support/testing/parallelization.rb +4 -0
  166. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  167. data/lib/active_support/testing/stream.rb +3 -5
  168. data/lib/active_support/testing/tagged_logging.rb +1 -1
  169. data/lib/active_support/testing/time_helpers.rb +13 -2
  170. data/lib/active_support/time_with_zone.rb +69 -22
  171. data/lib/active_support/values/time_zone.rb +33 -14
  172. data/lib/active_support/version.rb +1 -1
  173. data/lib/active_support/xml_mini/jdom.rb +1 -1
  174. data/lib/active_support/xml_mini/libxml.rb +5 -5
  175. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  176. data/lib/active_support/xml_mini/nokogiri.rb +4 -4
  177. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  178. data/lib/active_support/xml_mini/rexml.rb +1 -1
  179. data/lib/active_support/xml_mini.rb +5 -4
  180. data/lib/active_support.rb +16 -0
  181. metadata +25 -23
  182. data/lib/active_support/core_ext/marshal.rb +0 -26
  183. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -120
@@ -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"
@@ -11,7 +13,7 @@ module ActiveSupport
11
13
  # system's <tt>ENV['TZ']</tt> zone.
12
14
  #
13
15
  # You shouldn't ever need to create a TimeWithZone instance directly via +new+.
14
- # Instead use methods +local+, +parse+, +at+ and +now+ on TimeZone instances,
16
+ # Instead use methods +local+, +parse+, +at+, and +now+ on TimeZone instances,
15
17
  # and +in_time_zone+ on Time and DateTime instances.
16
18
  #
17
19
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
@@ -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
 
@@ -69,7 +78,7 @@ module ActiveSupport
69
78
  alias_method :getutc, :utc
70
79
  alias_method :gmtime, :utc
71
80
 
72
- # Returns the underlying TZInfo::TimezonePeriod.
81
+ # Returns the underlying <tt>TZInfo::TimezonePeriod</tt>.
73
82
  def period
74
83
  @period ||= time_zone.period_for_utc(@utc)
75
84
  end
@@ -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,60 @@ 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
+
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
+ if formatter = ::Time::DATE_FORMATS[:default]
225
+ ActiveSupport::Deprecation.warn(
226
+ "Using a :default format for TimeWithZone#to_s is deprecated. Please use TimeWithZone#to_fs instead."
227
+ )
228
+ formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
229
+ else
230
+ "#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}" # mimicking Ruby Time#to_s format
231
+ end
232
+ else
233
+ ActiveSupport::Deprecation.warn(
234
+ "TimeWithZone#to_s(#{format.inspect}) is deprecated. Please use TimeWithZone#to_fs(#{format.inspect}) instead."
235
+ )
236
+ "#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}" # mimicking Ruby Time#to_s format
237
+ end
238
+ end
239
+
201
240
  # Returns a string of the object's date and time.
241
+ #
242
+ # This method is aliased to <tt>to_formatted_s</tt>.
243
+ #
202
244
  # Accepts an optional <tt>format</tt>:
203
245
  # * <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).
246
+ # * <tt>:db</tt> - format outputs time in UTC :db time. See Time#to_fs(:db).
205
247
  # * 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)
248
+ def to_fs(format = :default)
207
249
  if format == :db
208
- utc.to_s(format)
250
+ utc.to_fs(format)
209
251
  elsif formatter = ::Time::DATE_FORMATS[format]
210
252
  formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
211
253
  else
212
- "#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}" # mimicking Ruby Time#to_s format
254
+ # Change to to_s when deprecation is gone.
255
+ "#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}"
213
256
  end
214
257
  end
215
- alias_method :to_formatted_s, :to_s
258
+ alias_method :to_formatted_s, :to_fs
216
259
 
217
260
  # Replaces <tt>%Z</tt> directive with +zone before passing to Time#strftime,
218
261
  # so that zone information is correct.
@@ -301,9 +344,8 @@ module ActiveSupport
301
344
  alias_method :in, :+
302
345
 
303
346
  # 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
305
- # between the two times that represents the difference between the current
306
- # object's time and the +other+ time.
347
+ # the other value +acts_like?+ time. In which case, it will subtract the
348
+ # other time and return the difference in seconds as a Float.
307
349
  #
308
350
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
309
351
  # now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28.725182881 EST -05:00
@@ -359,8 +401,8 @@ module ActiveSupport
359
401
  # Returns a new +ActiveSupport::TimeWithZone+ where one or more of the elements have
360
402
  # been changed according to the +options+ parameter. The time options (<tt>:hour</tt>,
361
403
  # <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>) reset cascadingly,
362
- # so if only the hour is passed, then minute, sec, usec and nsec is set to 0. If the
363
- # hour and minute is passed, then sec, usec and nsec is set to 0. The +options+
404
+ # so if only the hour is passed, then minute, sec, usec, and nsec is set to 0. If the
405
+ # hour and minute is passed, then sec, usec, and nsec is set to 0. The +options+
364
406
  # parameter takes a hash with any of these keys: <tt>:year</tt>, <tt>:month</tt>,
365
407
  # <tt>:day</tt>, <tt>:hour</tt>, <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>,
366
408
  # <tt>:nsec</tt>, <tt>:offset</tt>, <tt>:zone</tt>. Pass either <tt>:usec</tt>
@@ -440,7 +482,7 @@ module ActiveSupport
440
482
  [time.sec, time.min, time.hour, time.day, time.mon, time.year, time.wday, time.yday, dst?, zone]
441
483
  end
442
484
 
443
- # Returns the object's date and time as a floating point number of seconds
485
+ # Returns the object's date and time as a floating-point number of seconds
444
486
  # since the Epoch (January 1, 1970 00:00 UTC).
445
487
  #
446
488
  # Time.zone.now.to_f # => 1417709320.285418
@@ -531,10 +573,10 @@ module ActiveSupport
531
573
 
532
574
  # Send the missing method to +time+ instance, and wrap result in a new
533
575
  # TimeWithZone with the existing +time_zone+.
534
- def method_missing(sym, *args, &block)
535
- wrap_with_time_zone time.__send__(sym, *args, &block)
576
+ def method_missing(...)
577
+ wrap_with_time_zone time.__send__(...)
536
578
  rescue NoMethodError => e
537
- raise e, e.message.sub(time.inspect, inspect), e.backtrace
579
+ raise e, e.message.sub(time.inspect, inspect).sub("Time", "ActiveSupport::TimeWithZone"), e.backtrace
538
580
  end
539
581
 
540
582
  private
@@ -568,7 +610,7 @@ module ActiveSupport
568
610
  end
569
611
 
570
612
  def duration_of_variable_length?(obj)
571
- ActiveSupport::Duration === obj && obj.parts.any? { |p| [:years, :months, :weeks, :days].include?(p[0]) }
613
+ ActiveSupport::Duration === obj && obj.variable?
572
614
  end
573
615
 
574
616
  def wrap_with_time_zone(time)
@@ -583,3 +625,8 @@ module ActiveSupport
583
625
  end
584
626
  end
585
627
  end
628
+
629
+ # These prevent Psych from calling `ActiveSupport::TimeWithZone.name`
630
+ # and triggering the deprecation warning about the change in Rails 7.1.
631
+ YAML.load_tags["!ruby/object:ActiveSupport::TimeWithZone"] = "ActiveSupport::TimeWithZone"
632
+ YAML.dump_tags[ActiveSupport::TimeWithZone] = "!ruby/object:ActiveSupport::TimeWithZone"
@@ -4,16 +4,16 @@ require "tzinfo"
4
4
  require "concurrent/map"
5
5
 
6
6
  module ActiveSupport
7
- # The TimeZone class serves as a wrapper around TZInfo::Timezone instances.
7
+ # The TimeZone class serves as a wrapper around <tt>TZInfo::Timezone</tt> instances.
8
8
  # It allows us to do the following:
9
9
  #
10
10
  # * Limit the set of zones provided by TZInfo to a meaningful subset of 134
11
11
  # zones.
12
12
  # * Retrieve and display zones with a friendlier name
13
13
  # (e.g., "Eastern Time (US & Canada)" instead of "America/New_York").
14
- # * Lazily load TZInfo::Timezone instances only when they're needed.
14
+ # * Lazily load <tt>TZInfo::Timezone</tt> instances only when they're needed.
15
15
  # * Create ActiveSupport::TimeWithZone instances via TimeZone's +local+,
16
- # +parse+, +at+ and +now+ methods.
16
+ # +parse+, +at+, and +now+ methods.
17
17
  #
18
18
  # If you set <tt>config.time_zone</tt> in the Rails Application, you can
19
19
  # access this TimeZone object via <tt>Time.zone</tt>:
@@ -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,16 +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.
384
391
  raise ArgumentError, "invalid date" if str.nil?
385
392
 
386
393
  parts = Date._iso8601(str)
387
394
 
388
- 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
389
405
 
390
406
  time = Time.new(
391
- parts.fetch(:year),
392
- parts.fetch(:mon),
393
- parts.fetch(:mday),
407
+ year,
408
+ month,
409
+ day,
394
410
  parts.fetch(:hour, 0),
395
411
  parts.fetch(:min, 0),
396
412
  parts.fetch(:sec, 0) + parts.fetch(:sec_fraction, 0),
@@ -402,6 +418,9 @@ module ActiveSupport
402
418
  else
403
419
  TimeWithZone.new(nil, self, time)
404
420
  end
421
+
422
+ rescue Date::Error, KeyError
423
+ raise ArgumentError, "invalid date"
405
424
  end
406
425
 
407
426
  # Method for creating new ActiveSupport::TimeWithZone instance in time zone
@@ -514,7 +533,7 @@ module ActiveSupport
514
533
  def utc_to_local(time)
515
534
  tzinfo.utc_to_local(time).yield_self do |t|
516
535
  ActiveSupport.utc_to_local_returns_utc_offset_times ?
517
- 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)
518
537
  end
519
538
  end
520
539
 
@@ -524,27 +543,27 @@ module ActiveSupport
524
543
  tzinfo.local_to_utc(time, dst)
525
544
  end
526
545
 
527
- # Available so that TimeZone instances respond like TZInfo::Timezone
546
+ # Available so that TimeZone instances respond like <tt>TZInfo::Timezone</tt>
528
547
  # instances.
529
548
  def period_for_utc(time)
530
549
  tzinfo.period_for_utc(time)
531
550
  end
532
551
 
533
- # Available so that TimeZone instances respond like TZInfo::Timezone
552
+ # Available so that TimeZone instances respond like <tt>TZInfo::Timezone</tt>
534
553
  # instances.
535
554
  def period_for_local(time, dst = true)
536
555
  tzinfo.period_for_local(time, dst) { |periods| periods.last }
537
556
  end
538
557
 
539
- def periods_for_local(time) #:nodoc:
558
+ def periods_for_local(time) # :nodoc:
540
559
  tzinfo.periods_for_local(time)
541
560
  end
542
561
 
543
- def init_with(coder) #:nodoc:
562
+ def init_with(coder) # :nodoc:
544
563
  initialize(coder["name"])
545
564
  end
546
565
 
547
- def encode_with(coder) #:nodoc:
566
+ def encode_with(coder) # :nodoc:
548
567
  coder.tag = "!ruby/object:#{self.class}"
549
568
  coder.map = { "name" => tzinfo.name }
550
569
  end
@@ -3,7 +3,7 @@
3
3
  require_relative "gem_version"
4
4
 
5
5
  module ActiveSupport
6
- # Returns the version of the currently loaded ActiveSupport as a <tt>Gem::Version</tt>
6
+ # Returns the currently loaded version of Active Support as a <tt>Gem::Version</tt>.
7
7
  def self.version
8
8
  gem_version
9
9
  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__"