activesupport 6.0.6.1 → 7.1.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (245) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +865 -438
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -6
  5. data/lib/active_support/actionable_error.rb +4 -2
  6. data/lib/active_support/array_inquirer.rb +4 -2
  7. data/lib/active_support/backtrace_cleaner.rb +30 -10
  8. data/lib/active_support/benchmarkable.rb +4 -3
  9. data/lib/active_support/broadcast_logger.rb +250 -0
  10. data/lib/active_support/builder.rb +1 -1
  11. data/lib/active_support/cache/coder.rb +153 -0
  12. data/lib/active_support/cache/entry.rb +134 -0
  13. data/lib/active_support/cache/file_store.rb +53 -20
  14. data/lib/active_support/cache/mem_cache_store.rb +208 -63
  15. data/lib/active_support/cache/memory_store.rb +120 -38
  16. data/lib/active_support/cache/null_store.rb +16 -2
  17. data/lib/active_support/cache/redis_cache_store.rb +201 -208
  18. data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
  19. data/lib/active_support/cache/strategy/local_cache.rb +73 -66
  20. data/lib/active_support/cache.rb +539 -261
  21. data/lib/active_support/callbacks.rb +273 -142
  22. data/lib/active_support/code_generator.rb +65 -0
  23. data/lib/active_support/concern.rb +53 -7
  24. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +44 -7
  25. data/lib/active_support/concurrency/null_lock.rb +13 -0
  26. data/lib/active_support/concurrency/share_lock.rb +2 -2
  27. data/lib/active_support/configurable.rb +19 -6
  28. data/lib/active_support/configuration_file.rb +51 -0
  29. data/lib/active_support/core_ext/array/access.rb +1 -5
  30. data/lib/active_support/core_ext/array/conversions.rb +15 -13
  31. data/lib/active_support/core_ext/array/grouping.rb +6 -6
  32. data/lib/active_support/core_ext/array/inquiry.rb +2 -2
  33. data/lib/active_support/core_ext/benchmark.rb +2 -2
  34. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  35. data/lib/active_support/core_ext/class/attribute.rb +34 -44
  36. data/lib/active_support/core_ext/class/subclasses.rb +19 -29
  37. data/lib/active_support/core_ext/date/blank.rb +1 -1
  38. data/lib/active_support/core_ext/date/calculations.rb +24 -9
  39. data/lib/active_support/core_ext/date/conversions.rb +18 -16
  40. data/lib/active_support/core_ext/date_and_time/calculations.rb +27 -4
  41. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  42. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  43. data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
  44. data/lib/active_support/core_ext/date_time/conversions.rb +19 -15
  45. data/lib/active_support/core_ext/digest/uuid.rb +30 -13
  46. data/lib/active_support/core_ext/enumerable.rb +146 -72
  47. data/lib/active_support/core_ext/erb/util.rb +196 -0
  48. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  49. data/lib/active_support/core_ext/hash/conversions.rb +3 -4
  50. data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
  51. data/lib/active_support/core_ext/hash/deep_transform_values.rb +4 -4
  52. data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
  53. data/lib/active_support/core_ext/hash/keys.rb +5 -5
  54. data/lib/active_support/core_ext/hash/slice.rb +3 -2
  55. data/lib/active_support/core_ext/integer/inflections.rb +12 -12
  56. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  57. data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
  58. data/lib/active_support/core_ext/load_error.rb +1 -1
  59. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  60. data/lib/active_support/core_ext/module/attribute_accessors.rb +31 -29
  61. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +51 -20
  62. data/lib/active_support/core_ext/module/concerning.rb +14 -8
  63. data/lib/active_support/core_ext/module/delegation.rb +75 -42
  64. data/lib/active_support/core_ext/module/deprecation.rb +15 -12
  65. data/lib/active_support/core_ext/module/introspection.rb +1 -26
  66. data/lib/active_support/core_ext/name_error.rb +23 -2
  67. data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
  68. data/lib/active_support/core_ext/numeric/conversions.rb +82 -73
  69. data/lib/active_support/core_ext/object/acts_like.rb +29 -5
  70. data/lib/active_support/core_ext/object/blank.rb +2 -2
  71. data/lib/active_support/core_ext/object/deep_dup.rb +17 -1
  72. data/lib/active_support/core_ext/object/duplicable.rb +15 -4
  73. data/lib/active_support/core_ext/object/inclusion.rb +13 -5
  74. data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
  75. data/lib/active_support/core_ext/object/json.rb +52 -28
  76. data/lib/active_support/core_ext/object/to_query.rb +2 -4
  77. data/lib/active_support/core_ext/object/try.rb +20 -20
  78. data/lib/active_support/core_ext/object/with.rb +44 -0
  79. data/lib/active_support/core_ext/object/with_options.rb +25 -6
  80. data/lib/active_support/core_ext/object.rb +1 -0
  81. data/lib/active_support/core_ext/pathname/blank.rb +16 -0
  82. data/lib/active_support/core_ext/pathname/existence.rb +23 -0
  83. data/lib/active_support/core_ext/pathname.rb +4 -0
  84. data/lib/active_support/core_ext/range/compare_range.rb +6 -25
  85. data/lib/active_support/core_ext/range/conversions.rb +34 -13
  86. data/lib/active_support/core_ext/range/each.rb +1 -1
  87. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  88. data/lib/active_support/core_ext/range.rb +1 -2
  89. data/lib/active_support/core_ext/regexp.rb +8 -1
  90. data/lib/active_support/core_ext/securerandom.rb +25 -13
  91. data/lib/active_support/core_ext/string/access.rb +5 -24
  92. data/lib/active_support/core_ext/string/conversions.rb +3 -2
  93. data/lib/active_support/core_ext/string/filters.rb +21 -15
  94. data/lib/active_support/core_ext/string/indent.rb +1 -1
  95. data/lib/active_support/core_ext/string/inflections.rb +51 -10
  96. data/lib/active_support/core_ext/string/inquiry.rb +2 -1
  97. data/lib/active_support/core_ext/string/multibyte.rb +2 -2
  98. data/lib/active_support/core_ext/string/output_safety.rb +85 -194
  99. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  100. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
  101. data/lib/active_support/core_ext/symbol.rb +3 -0
  102. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  103. data/lib/active_support/core_ext/time/calculations.rb +46 -8
  104. data/lib/active_support/core_ext/time/conversions.rb +16 -13
  105. data/lib/active_support/core_ext/time/zones.rb +12 -28
  106. data/lib/active_support/core_ext.rb +2 -1
  107. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  108. data/lib/active_support/current_attributes.rb +54 -22
  109. data/lib/active_support/deep_mergeable.rb +53 -0
  110. data/lib/active_support/dependencies/autoload.rb +17 -12
  111. data/lib/active_support/dependencies/interlock.rb +10 -18
  112. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  113. data/lib/active_support/dependencies.rb +58 -769
  114. data/lib/active_support/deprecation/behaviors.rb +77 -38
  115. data/lib/active_support/deprecation/constant_accessor.rb +5 -4
  116. data/lib/active_support/deprecation/deprecators.rb +104 -0
  117. data/lib/active_support/deprecation/disallowed.rb +54 -0
  118. data/lib/active_support/deprecation/instance_delegator.rb +31 -5
  119. data/lib/active_support/deprecation/method_wrappers.rb +12 -28
  120. data/lib/active_support/deprecation/proxy_wrappers.rb +40 -25
  121. data/lib/active_support/deprecation/reporting.rb +76 -16
  122. data/lib/active_support/deprecation.rb +36 -4
  123. data/lib/active_support/deprecator.rb +7 -0
  124. data/lib/active_support/descendants_tracker.rb +150 -68
  125. data/lib/active_support/digest.rb +5 -3
  126. data/lib/active_support/duration/iso8601_parser.rb +3 -3
  127. data/lib/active_support/duration/iso8601_serializer.rb +24 -12
  128. data/lib/active_support/duration.rb +136 -56
  129. data/lib/active_support/encrypted_configuration.rb +72 -9
  130. data/lib/active_support/encrypted_file.rb +46 -13
  131. data/lib/active_support/environment_inquirer.rb +40 -0
  132. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  133. data/lib/active_support/error_reporter.rb +203 -0
  134. data/lib/active_support/evented_file_update_checker.rb +86 -137
  135. data/lib/active_support/execution_context/test_helper.rb +13 -0
  136. data/lib/active_support/execution_context.rb +53 -0
  137. data/lib/active_support/execution_wrapper.rb +31 -12
  138. data/lib/active_support/executor/test_helper.rb +7 -0
  139. data/lib/active_support/file_update_checker.rb +4 -2
  140. data/lib/active_support/fork_tracker.rb +79 -0
  141. data/lib/active_support/gem_version.rb +5 -5
  142. data/lib/active_support/gzip.rb +2 -0
  143. data/lib/active_support/hash_with_indifferent_access.rb +86 -42
  144. data/lib/active_support/html_safe_translation.rb +53 -0
  145. data/lib/active_support/i18n.rb +2 -1
  146. data/lib/active_support/i18n_railtie.rb +29 -27
  147. data/lib/active_support/inflector/inflections.rb +26 -9
  148. data/lib/active_support/inflector/methods.rb +54 -64
  149. data/lib/active_support/inflector/transliterate.rb +7 -5
  150. data/lib/active_support/isolated_execution_state.rb +76 -0
  151. data/lib/active_support/json/decoding.rb +6 -5
  152. data/lib/active_support/json/encoding.rb +31 -45
  153. data/lib/active_support/key_generator.rb +32 -7
  154. data/lib/active_support/lazy_load_hooks.rb +33 -7
  155. data/lib/active_support/locale/en.yml +10 -4
  156. data/lib/active_support/log_subscriber/test_helper.rb +2 -2
  157. data/lib/active_support/log_subscriber.rb +101 -32
  158. data/lib/active_support/logger.rb +9 -60
  159. data/lib/active_support/logger_silence.rb +2 -26
  160. data/lib/active_support/logger_thread_safe_level.rb +24 -25
  161. data/lib/active_support/message_encryptor.rb +205 -58
  162. data/lib/active_support/message_encryptors.rb +141 -0
  163. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  164. data/lib/active_support/message_pack/extensions.rb +292 -0
  165. data/lib/active_support/message_pack/serializer.rb +63 -0
  166. data/lib/active_support/message_pack.rb +50 -0
  167. data/lib/active_support/message_verifier.rb +237 -86
  168. data/lib/active_support/message_verifiers.rb +135 -0
  169. data/lib/active_support/messages/codec.rb +65 -0
  170. data/lib/active_support/messages/metadata.rb +112 -46
  171. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  172. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  173. data/lib/active_support/messages/rotator.rb +35 -32
  174. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  175. data/lib/active_support/multibyte/chars.rb +15 -52
  176. data/lib/active_support/multibyte/unicode.rb +8 -122
  177. data/lib/active_support/multibyte.rb +1 -1
  178. data/lib/active_support/notifications/fanout.rb +310 -105
  179. data/lib/active_support/notifications/instrumenter.rb +113 -48
  180. data/lib/active_support/notifications.rb +56 -29
  181. data/lib/active_support/number_helper/number_converter.rb +15 -8
  182. data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
  183. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  184. data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
  185. data/lib/active_support/number_helper/number_to_human_size_converter.rb +5 -5
  186. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
  187. data/lib/active_support/number_helper/number_to_rounded_converter.rb +9 -5
  188. data/lib/active_support/number_helper/rounding_helper.rb +12 -32
  189. data/lib/active_support/number_helper.rb +379 -304
  190. data/lib/active_support/option_merger.rb +11 -18
  191. data/lib/active_support/ordered_hash.rb +4 -4
  192. data/lib/active_support/ordered_options.rb +23 -3
  193. data/lib/active_support/parameter_filter.rb +104 -75
  194. data/lib/active_support/proxy_object.rb +2 -0
  195. data/lib/active_support/rails.rb +1 -4
  196. data/lib/active_support/railtie.rb +90 -6
  197. data/lib/active_support/reloader.rb +12 -4
  198. data/lib/active_support/rescuable.rb +18 -16
  199. data/lib/active_support/ruby_features.rb +7 -0
  200. data/lib/active_support/secure_compare_rotator.rb +58 -0
  201. data/lib/active_support/security_utils.rb +19 -12
  202. data/lib/active_support/string_inquirer.rb +5 -3
  203. data/lib/active_support/subscriber.rb +23 -47
  204. data/lib/active_support/syntax_error_proxy.rb +70 -0
  205. data/lib/active_support/tagged_logging.rb +84 -23
  206. data/lib/active_support/test_case.rb +166 -27
  207. data/lib/active_support/testing/assertions.rb +73 -20
  208. data/lib/active_support/testing/autorun.rb +0 -2
  209. data/lib/active_support/testing/constant_stubbing.rb +32 -0
  210. data/lib/active_support/testing/deprecation.rb +53 -2
  211. data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
  212. data/lib/active_support/testing/isolation.rb +30 -29
  213. data/lib/active_support/testing/method_call_assertions.rb +24 -11
  214. data/lib/active_support/testing/parallelization/server.rb +82 -0
  215. data/lib/active_support/testing/parallelization/worker.rb +103 -0
  216. data/lib/active_support/testing/parallelization.rb +16 -95
  217. data/lib/active_support/testing/parallelize_executor.rb +81 -0
  218. data/lib/active_support/testing/stream.rb +4 -6
  219. data/lib/active_support/testing/strict_warnings.rb +39 -0
  220. data/lib/active_support/testing/tagged_logging.rb +1 -1
  221. data/lib/active_support/testing/time_helpers.rb +89 -19
  222. data/lib/active_support/time_with_zone.rb +105 -70
  223. data/lib/active_support/values/time_zone.rb +59 -26
  224. data/lib/active_support/version.rb +1 -1
  225. data/lib/active_support/xml_mini/jdom.rb +4 -11
  226. data/lib/active_support/xml_mini/libxml.rb +5 -5
  227. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  228. data/lib/active_support/xml_mini/nokogiri.rb +5 -5
  229. data/lib/active_support/xml_mini/nokogirisax.rb +2 -2
  230. data/lib/active_support/xml_mini/rexml.rb +9 -2
  231. data/lib/active_support/xml_mini.rb +7 -6
  232. data/lib/active_support.rb +40 -1
  233. metadata +127 -40
  234. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
  235. data/lib/active_support/core_ext/hash/compact.rb +0 -5
  236. data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
  237. data/lib/active_support/core_ext/marshal.rb +0 -24
  238. data/lib/active_support/core_ext/module/reachable.rb +0 -6
  239. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
  240. data/lib/active_support/core_ext/range/include_range.rb +0 -9
  241. data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -23
  242. data/lib/active_support/core_ext/range/overlaps.rb +0 -10
  243. data/lib/active_support/core_ext/uri.rb +0 -25
  244. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
  245. data/lib/active_support/per_thread_registry.rb +0 -60
@@ -2,23 +2,30 @@
2
2
 
3
3
  require "active_support/core_ext/module/redefine_method"
4
4
  require "active_support/core_ext/time/calculations"
5
- require "concurrent/map"
6
5
 
7
6
  module ActiveSupport
8
7
  module Testing
8
+ # Manages stubs for TimeHelpers
9
9
  class SimpleStubs # :nodoc:
10
10
  Stub = Struct.new(:object, :method_name, :original_method)
11
11
 
12
12
  def initialize
13
- @stubs = Concurrent::Map.new { |h, k| h[k] = {} }
13
+ @stubs = Hash.new { |h, k| h[k] = {} }
14
14
  end
15
15
 
16
+ # Stubs object.method_name with the given block
17
+ # If the method is already stubbed, remove that stub
18
+ # so that removing this stub will restore the original implementation.
19
+ # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
20
+ # target = Time.zone.local(2004, 11, 24, 1, 4, 44)
21
+ # simple_stubs.stub_object(Time, :now) { at(target.to_i) }
22
+ # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
16
23
  def stub_object(object, method_name, &block)
17
24
  if stub = stubbing(object, method_name)
18
25
  unstub_object(stub)
19
26
  end
20
27
 
21
- new_name = "__simple_stub__#{method_name}"
28
+ new_name = "__simple_stub__#{method_name}__#{object_id}"
22
29
 
23
30
  @stubs[object.object_id][method_name] = Stub.new(object, method_name, new_name)
24
31
 
@@ -26,6 +33,7 @@ module ActiveSupport
26
33
  object.define_singleton_method(method_name, &block)
27
34
  end
28
35
 
36
+ # Remove all object-method stubs held by this instance
29
37
  def unstub_all!
30
38
  @stubs.each_value do |object_stubs|
31
39
  object_stubs.each_value do |stub|
@@ -35,11 +43,19 @@ module ActiveSupport
35
43
  @stubs.clear
36
44
  end
37
45
 
46
+ # Returns the Stub for object#method_name
47
+ # (nil if it is not stubbed)
38
48
  def stubbing(object, method_name)
39
49
  @stubs[object.object_id][method_name]
40
50
  end
41
51
 
52
+ # Returns true if any stubs are set, false if there are none
53
+ def stubbed?
54
+ !@stubs.empty?
55
+ end
56
+
42
57
  private
58
+ # Restores the original object.method described by the Stub
43
59
  def unstub_object(stub)
44
60
  singleton_class = stub.object.singleton_class
45
61
  singleton_class.silence_redefinition_of_method stub.method_name
@@ -59,6 +75,11 @@ module ActiveSupport
59
75
  # stubbing +Time.now+, +Date.today+, and +DateTime.now+. The stubs are automatically removed
60
76
  # at the end of the test.
61
77
  #
78
+ # Note that the usec for the resulting time will be set to 0 to prevent rounding
79
+ # errors with external services, like MySQL (which will round instead of floor,
80
+ # leading to off-by-one-second errors), unless the <tt>with_usec</tt> argument
81
+ # is set to <tt>true</tt>.
82
+ #
62
83
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
63
84
  # travel 1.day
64
85
  # Time.current # => Sun, 10 Nov 2013 15:34:49 EST -05:00
@@ -73,16 +94,16 @@ module ActiveSupport
73
94
  # User.create.created_at # => Sun, 10 Nov 2013 15:34:49 EST -05:00
74
95
  # end
75
96
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
76
- def travel(duration, &block)
77
- travel_to Time.now + duration, &block
97
+ def travel(duration, with_usec: false, &block)
98
+ travel_to Time.now + duration, with_usec: with_usec, &block
78
99
  end
79
100
 
80
- # Changes current time to the given time by stubbing +Time.now+,
101
+ # Changes current time to the given time by stubbing +Time.now+, +Time.new+,
81
102
  # +Date.today+, and +DateTime.now+ to return the time or date passed into this method.
82
103
  # The stubs are automatically removed at the end of the test.
83
104
  #
84
105
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
85
- # travel_to Time.zone.local(2004, 11, 24, 01, 04, 44)
106
+ # travel_to Time.zone.local(2004, 11, 24, 1, 4, 44)
86
107
  # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
87
108
  # Date.current # => Wed, 24 Nov 2004
88
109
  # DateTime.current # => Wed, 24 Nov 2004 01:04:44 -0500
@@ -98,18 +119,19 @@ module ActiveSupport
98
119
  #
99
120
  # Note that the usec for the time passed will be set to 0 to prevent rounding
100
121
  # errors with external services, like MySQL (which will round instead of floor,
101
- # leading to off-by-one-second errors).
122
+ # leading to off-by-one-second errors), unless the <tt>with_usec</tt> argument
123
+ # is set to <tt>true</tt>.
102
124
  #
103
125
  # This method also accepts a block, which will return the current time back to its original
104
126
  # state at the end of the block:
105
127
  #
106
128
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
107
- # travel_to Time.zone.local(2004, 11, 24, 01, 04, 44) do
129
+ # travel_to Time.zone.local(2004, 11, 24, 1, 4, 44) do
108
130
  # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
109
131
  # end
110
132
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
111
- def travel_to(date_or_time)
112
- if block_given? && simple_stubs.stubbing(Time, :now)
133
+ def travel_to(date_or_time, with_usec: false)
134
+ if block_given? && in_block
113
135
  travel_to_nested_block_call = <<~MSG
114
136
 
115
137
  Calling `travel_to` with a block, when we have previously already made a call to `travel_to`, can lead to confusing time stubbing.
@@ -139,19 +161,45 @@ module ActiveSupport
139
161
 
140
162
  if date_or_time.is_a?(Date) && !date_or_time.is_a?(DateTime)
141
163
  now = date_or_time.midnight.to_time
164
+ elsif date_or_time.is_a?(String)
165
+ now = Time.zone.parse(date_or_time)
166
+ elsif with_usec
167
+ now = date_or_time.to_time
142
168
  else
143
169
  now = date_or_time.to_time.change(usec: 0)
144
170
  end
145
171
 
146
- simple_stubs.stub_object(Time, :now) { at(now.to_i) }
147
- simple_stubs.stub_object(Date, :today) { jd(now.to_date.jd) }
148
- simple_stubs.stub_object(DateTime, :now) { jd(now.to_date.jd, now.hour, now.min, now.sec, Rational(now.utc_offset, 86400)) }
172
+ # +now+ must be in local system timezone, because +Time.at(now)+
173
+ # and +now.to_date+ (see stubs below) will use +now+'s timezone too!
174
+ now = now.getlocal
175
+
176
+ stubs = simple_stubs
177
+ stubbed_time = Time.now if stubs.stubbing(Time, :now)
178
+ stubs.stub_object(Time, :now) { at(now) }
179
+
180
+ stubs.stub_object(Time, :new) do |*args, **options|
181
+ if args.empty? && options.empty?
182
+ at(now)
183
+ else
184
+ stub = stubs.stubbing(Time, :new)
185
+ Time.send(stub.original_method, *args, **options)
186
+ end
187
+ end
188
+
189
+ stubs.stub_object(Date, :today) { jd(now.to_date.jd) }
190
+ stubs.stub_object(DateTime, :now) { jd(now.to_date.jd, now.hour, now.min, now.sec, Rational(now.utc_offset, 86400)) }
149
191
 
150
192
  if block_given?
151
193
  begin
194
+ self.in_block = true
152
195
  yield
153
196
  ensure
154
- travel_back
197
+ if stubbed_time
198
+ travel_to stubbed_time
199
+ else
200
+ travel_back
201
+ end
202
+ self.in_block = false
155
203
  end
156
204
  end
157
205
  end
@@ -160,16 +208,36 @@ module ActiveSupport
160
208
  # +travel+, +travel_to+, and +freeze_time+.
161
209
  #
162
210
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
163
- # travel_to Time.zone.local(2004, 11, 24, 01, 04, 44)
211
+ #
212
+ # travel_to Time.zone.local(2004, 11, 24, 1, 4, 44)
164
213
  # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
214
+ #
165
215
  # travel_back
166
216
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
217
+ #
218
+ # This method also accepts a block, which brings the stubs back at the end of the block:
219
+ #
220
+ # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
221
+ #
222
+ # travel_to Time.zone.local(2004, 11, 24, 1, 4, 44)
223
+ # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
224
+ #
225
+ # travel_back do
226
+ # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
227
+ # end
228
+ #
229
+ # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
167
230
  def travel_back
231
+ stubbed_time = Time.current if block_given? && simple_stubs.stubbed?
232
+
168
233
  simple_stubs.unstub_all!
234
+ yield if block_given?
235
+ ensure
236
+ travel_to stubbed_time if stubbed_time
169
237
  end
170
238
  alias_method :unfreeze_time, :travel_back
171
239
 
172
- # Calls +travel_to+ with +Time.now+.
240
+ # Calls +travel_to+ with +Time.now+. Forwards optional <tt>with_usec</tt> argument.
173
241
  #
174
242
  # Time.current # => Sun, 09 Jul 2017 15:34:49 EST -05:00
175
243
  # freeze_time
@@ -185,14 +253,16 @@ module ActiveSupport
185
253
  # User.create.created_at # => Sun, 09 Jul 2017 15:34:49 EST -05:00
186
254
  # end
187
255
  # Time.current # => Sun, 09 Jul 2017 15:34:50 EST -05:00
188
- def freeze_time(&block)
189
- travel_to Time.now, &block
256
+ def freeze_time(with_usec: false, &block)
257
+ travel_to Time.now, with_usec: with_usec, &block
190
258
  end
191
259
 
192
260
  private
193
261
  def simple_stubs
194
262
  @simple_stubs ||= SimpleStubs.new
195
263
  end
264
+
265
+ attr_accessor :in_block
196
266
  end
197
267
  end
198
268
  end
@@ -1,48 +1,47 @@
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"
6
8
  require "active_support/core_ext/date_and_time/compatibility"
7
9
 
8
10
  module ActiveSupport
11
+ # = Active Support \Time With Zone
12
+ #
9
13
  # A Time-like class that can represent a time in any time zone. Necessary
10
14
  # because standard Ruby Time instances are limited to UTC and the
11
15
  # system's <tt>ENV['TZ']</tt> zone.
12
16
  #
13
17
  # 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,
18
+ # Instead use methods +local+, +parse+, +at+, and +now+ on TimeZone instances,
15
19
  # and +in_time_zone+ on Time and DateTime instances.
16
20
  #
17
21
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
18
- # Time.zone.local(2007, 2, 10, 15, 30, 45) # => Sat, 10 Feb 2007 15:30:45 EST -05:00
19
- # Time.zone.parse('2007-02-10 15:30:45') # => Sat, 10 Feb 2007 15:30:45 EST -05:00
20
- # Time.zone.at(1171139445) # => Sat, 10 Feb 2007 15:30:45 EST -05:00
21
- # Time.zone.now # => Sun, 18 May 2008 13:07:55 EDT -04:00
22
- # Time.utc(2007, 2, 10, 20, 30, 45).in_time_zone # => Sat, 10 Feb 2007 15:30:45 EST -05:00
22
+ # Time.zone.local(2007, 2, 10, 15, 30, 45) # => Sat, 10 Feb 2007 15:30:45.000000000 EST -05:00
23
+ # Time.zone.parse('2007-02-10 15:30:45') # => Sat, 10 Feb 2007 15:30:45.000000000 EST -05:00
24
+ # Time.zone.at(1171139445) # => Sat, 10 Feb 2007 15:30:45.000000000 EST -05:00
25
+ # Time.zone.now # => Sun, 18 May 2008 13:07:55.754107581 EDT -04:00
26
+ # Time.utc(2007, 2, 10, 20, 30, 45).in_time_zone # => Sat, 10 Feb 2007 15:30:45.000000000 EST -05:00
23
27
  #
24
28
  # See Time and TimeZone for further documentation of these methods.
25
29
  #
26
30
  # TimeWithZone instances implement the same API as Ruby Time instances, so
27
31
  # that Time and TimeWithZone instances are interchangeable.
28
32
  #
29
- # t = Time.zone.now # => Sun, 18 May 2008 13:27:25 EDT -04:00
33
+ # t = Time.zone.now # => Sun, 18 May 2008 13:27:25.031505668 EDT -04:00
30
34
  # t.hour # => 13
31
35
  # t.dst? # => true
32
36
  # t.utc_offset # => -14400
33
37
  # t.zone # => "EDT"
34
- # t.to_s(:rfc822) # => "Sun, 18 May 2008 13:27:25 -0400"
35
- # t + 1.day # => Mon, 19 May 2008 13:27:25 EDT -04:00
36
- # t.beginning_of_year # => Tue, 01 Jan 2008 00:00:00 EST -05:00
38
+ # t.to_fs(:rfc822) # => "Sun, 18 May 2008 13:27:25 -0400"
39
+ # t + 1.day # => Mon, 19 May 2008 13:27:25.031505668 EDT -04:00
40
+ # t.beginning_of_year # => Tue, 01 Jan 2008 00:00:00.000000000 EST -05:00
37
41
  # t > Time.utc(1999) # => true
38
42
  # t.is_a?(Time) # => true
39
43
  # t.is_a?(ActiveSupport::TimeWithZone) # => true
40
44
  class TimeWithZone
41
- # Report class name as 'Time' to thwart type checking.
42
- def self.name
43
- "Time"
44
- end
45
-
46
45
  PRECISIONS = Hash.new { |h, n| h[n] = "%FT%T.%#{n}N" }
47
46
  PRECISIONS[0] = "%FT%T"
48
47
 
@@ -57,19 +56,19 @@ module ActiveSupport
57
56
 
58
57
  # Returns a <tt>Time</tt> instance that represents the time in +time_zone+.
59
58
  def time
60
- @time ||= period.to_local(@utc)
59
+ @time ||= incorporate_utc_offset(@utc, utc_offset)
61
60
  end
62
61
 
63
62
  # Returns a <tt>Time</tt> instance of the simultaneous time in the UTC timezone.
64
63
  def utc
65
- @utc ||= period.to_utc(@time)
64
+ @utc ||= incorporate_utc_offset(@time, -utc_offset)
66
65
  end
67
66
  alias_method :comparable_time, :utc
68
67
  alias_method :getgm, :utc
69
68
  alias_method :getutc, :utc
70
69
  alias_method :gmtime, :utc
71
70
 
72
- # Returns the underlying TZInfo::TimezonePeriod.
71
+ # Returns the underlying +TZInfo::TimezonePeriod+.
73
72
  def period
74
73
  @period ||= time_zone.period_for_utc(@utc)
75
74
  end
@@ -104,13 +103,13 @@ module ActiveSupport
104
103
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
105
104
  # Time.zone.now.utc? # => false
106
105
  def utc?
107
- period.offset.abbreviation == :UTC || period.offset.abbreviation == :UCT
106
+ zone == "UTC" || zone == "UCT"
108
107
  end
109
108
  alias_method :gmt?, :utc?
110
109
 
111
110
  # Returns the offset from current time to UTC time in seconds.
112
111
  def utc_offset
113
- period.utc_total_offset
112
+ period.observed_utc_offset
114
113
  end
115
114
  alias_method :gmt_offset, :utc_offset
116
115
  alias_method :gmtoff, :utc_offset
@@ -132,14 +131,14 @@ module ActiveSupport
132
131
  # Time.zone = 'Eastern Time (US & Canada)' # => "Eastern Time (US & Canada)"
133
132
  # Time.zone.now.zone # => "EST"
134
133
  def zone
135
- period.zone_identifier.to_s
134
+ period.abbreviation
136
135
  end
137
136
 
138
137
  # Returns a string of the object's date, time, zone, and offset from UTC.
139
138
  #
140
- # Time.zone.now.inspect # => "Thu, 04 Dec 2014 11:00:25 EST -05:00"
139
+ # Time.zone.now.inspect # => "Thu, 04 Dec 2014 11:00:25.624541392 EST -05:00"
141
140
  def inspect
142
- "#{time.strftime('%a, %d %b %Y %H:%M:%S')} #{zone} #{formatted_offset}"
141
+ "#{time.strftime('%a, %d %b %Y %H:%M:%S.%9N')} #{zone} #{formatted_offset}"
143
142
  end
144
143
 
145
144
  # Returns a string of the object's date and time in the ISO 8601 standard
@@ -172,12 +171,11 @@ module ActiveSupport
172
171
  end
173
172
  end
174
173
 
175
- def init_with(coder) #:nodoc:
174
+ def init_with(coder) # :nodoc:
176
175
  initialize(coder["utc"], coder["zone"], coder["time"])
177
176
  end
178
177
 
179
- def encode_with(coder) #:nodoc:
180
- coder.tag = "!ruby/object:ActiveSupport::TimeWithZone"
178
+ def encode_with(coder) # :nodoc:
181
179
  coder.map = { "utc" => utc, "zone" => time_zone, "time" => time }
182
180
  end
183
181
 
@@ -194,25 +192,34 @@ module ActiveSupport
194
192
  #
195
193
  # Time.zone.now.rfc2822 # => "Tue, 01 Jan 2013 04:51:39 +0000"
196
194
  def rfc2822
197
- to_s(:rfc822)
195
+ to_fs(:rfc822)
198
196
  end
199
197
  alias_method :rfc822, :rfc2822
200
198
 
201
199
  # Returns a string of the object's date and time.
200
+ def to_s
201
+ "#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}" # mimicking Ruby Time#to_s format
202
+ end
203
+
204
+ # Returns a string of the object's date and time.
205
+ #
206
+ # This method is aliased to <tt>to_formatted_s</tt>.
207
+ #
202
208
  # Accepts an optional <tt>format</tt>:
203
209
  # * <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).
205
- # * 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)
210
+ # * <tt>:db</tt> - format outputs time in UTC :db time. See Time#to_fs(:db).
211
+ # * Any key in +Time::DATE_FORMATS+ can be used. See active_support/core_ext/time/conversions.rb.
212
+ def to_fs(format = :default)
207
213
  if format == :db
208
- utc.to_s(format)
214
+ utc.to_fs(format)
209
215
  elsif formatter = ::Time::DATE_FORMATS[format]
210
216
  formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
211
217
  else
212
- "#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}" # mimicking Ruby Time#to_s format
218
+ # Change to to_s when deprecation is gone.
219
+ "#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}"
213
220
  end
214
221
  end
215
- alias_method :to_formatted_s, :to_s
222
+ alias_method :to_formatted_s, :to_fs
216
223
 
217
224
  # Replaces <tt>%Z</tt> directive with +zone before passing to Time#strftime,
218
225
  # so that zone information is correct.
@@ -245,6 +252,20 @@ module ActiveSupport
245
252
  time.today?
246
253
  end
247
254
 
255
+ # Returns true if the current object's time falls within
256
+ # the next day (tomorrow).
257
+ def tomorrow?
258
+ time.tomorrow?
259
+ end
260
+ alias :next_day? :tomorrow?
261
+
262
+ # Returns true if the current object's time falls within
263
+ # the previous day (yesterday).
264
+ def yesterday?
265
+ time.yesterday?
266
+ end
267
+ alias :prev_day? :yesterday?
268
+
248
269
  # Returns true if the current object's time is in the future.
249
270
  def future?
250
271
  utc.future?
@@ -263,8 +284,8 @@ module ActiveSupport
263
284
  # value as a new TimeWithZone object.
264
285
  #
265
286
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
266
- # now = Time.zone.now # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
267
- # now + 1000 # => Sun, 02 Nov 2014 01:43:08 EDT -04:00
287
+ # now = Time.zone.now # => Sun, 02 Nov 2014 01:26:28.725182881 EDT -04:00
288
+ # now + 1000 # => Sun, 02 Nov 2014 01:43:08.725182881 EDT -04:00
268
289
  #
269
290
  # If we're adding a Duration of variable length (i.e., years, months, days),
270
291
  # move forward from #time, otherwise move forward from #utc, for accuracy
@@ -273,8 +294,8 @@ module ActiveSupport
273
294
  # For instance, a time + 24.hours will advance exactly 24 hours, while a
274
295
  # time + 1.day will advance 23-25 hours, depending on the day.
275
296
  #
276
- # now + 24.hours # => Mon, 03 Nov 2014 00:26:28 EST -05:00
277
- # now + 1.day # => Mon, 03 Nov 2014 01:26:28 EST -05:00
297
+ # now + 24.hours # => Mon, 03 Nov 2014 00:26:28.725182881 EST -05:00
298
+ # now + 1.day # => Mon, 03 Nov 2014 01:26:28.725182881 EST -05:00
278
299
  def +(other)
279
300
  if duration_of_variable_length?(other)
280
301
  method_missing(:+, other)
@@ -287,13 +308,12 @@ module ActiveSupport
287
308
  alias_method :in, :+
288
309
 
289
310
  # Subtracts an interval of time and returns a new TimeWithZone object unless
290
- # the other value `acts_like?` time. Then it will return a Float of the difference
291
- # between the two times that represents the difference between the current
292
- # object's time and the +other+ time.
311
+ # the other value +acts_like?+ time. In which case, it will subtract the
312
+ # other time and return the difference in seconds as a Float.
293
313
  #
294
314
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
295
- # now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28 EST -05:00
296
- # now - 1000 # => Mon, 03 Nov 2014 00:09:48 EST -05:00
315
+ # now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28.725182881 EST -05:00
316
+ # now - 1000 # => Mon, 03 Nov 2014 00:09:48.725182881 EST -05:00
297
317
  #
298
318
  # If subtracting a Duration of variable length (i.e., years, months, days),
299
319
  # move backward from #time, otherwise move backward from #utc, for accuracy
@@ -302,8 +322,8 @@ module ActiveSupport
302
322
  # For instance, a time - 24.hours will go subtract exactly 24 hours, while a
303
323
  # time - 1.day will subtract 23-25 hours, depending on the day.
304
324
  #
305
- # now - 24.hours # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
306
- # now - 1.day # => Sun, 02 Nov 2014 00:26:28 EDT -04:00
325
+ # now - 24.hours # => Sun, 02 Nov 2014 01:26:28.725182881 EDT -04:00
326
+ # now - 1.day # => Sun, 02 Nov 2014 00:26:28.725182881 EDT -04:00
307
327
  #
308
328
  # If both the TimeWithZone object and the other value act like Time, a Float
309
329
  # will be returned.
@@ -325,8 +345,8 @@ module ActiveSupport
325
345
  # the result as a new TimeWithZone object.
326
346
  #
327
347
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
328
- # now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28 EST -05:00
329
- # now.ago(1000) # => Mon, 03 Nov 2014 00:09:48 EST -05:00
348
+ # now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28.725182881 EST -05:00
349
+ # now.ago(1000) # => Mon, 03 Nov 2014 00:09:48.725182881 EST -05:00
330
350
  #
331
351
  # If we're subtracting a Duration of variable length (i.e., years, months,
332
352
  # days), move backward from #time, otherwise move backward from #utc, for
@@ -336,8 +356,8 @@ module ActiveSupport
336
356
  # while <tt>time.ago(1.day)</tt> will move back 23-25 hours, depending on
337
357
  # the day.
338
358
  #
339
- # now.ago(24.hours) # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
340
- # now.ago(1.day) # => Sun, 02 Nov 2014 00:26:28 EDT -04:00
359
+ # now.ago(24.hours) # => Sun, 02 Nov 2014 01:26:28.725182881 EDT -04:00
360
+ # now.ago(1.day) # => Sun, 02 Nov 2014 00:26:28.725182881 EDT -04:00
341
361
  def ago(other)
342
362
  since(-other)
343
363
  end
@@ -345,20 +365,20 @@ module ActiveSupport
345
365
  # Returns a new +ActiveSupport::TimeWithZone+ where one or more of the elements have
346
366
  # been changed according to the +options+ parameter. The time options (<tt>:hour</tt>,
347
367
  # <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>) reset cascadingly,
348
- # so if only the hour is passed, then minute, sec, usec and nsec is set to 0. If the
349
- # hour and minute is passed, then sec, usec and nsec is set to 0. The +options+
368
+ # so if only the hour is passed, then minute, sec, usec, and nsec is set to 0. If the
369
+ # hour and minute is passed, then sec, usec, and nsec is set to 0. The +options+
350
370
  # parameter takes a hash with any of these keys: <tt>:year</tt>, <tt>:month</tt>,
351
371
  # <tt>:day</tt>, <tt>:hour</tt>, <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>,
352
372
  # <tt>:nsec</tt>, <tt>:offset</tt>, <tt>:zone</tt>. Pass either <tt>:usec</tt>
353
373
  # or <tt>:nsec</tt>, not both. Similarly, pass either <tt>:zone</tt> or
354
374
  # <tt>:offset</tt>, not both.
355
375
  #
356
- # t = Time.zone.now # => Fri, 14 Apr 2017 11:45:15 EST -05:00
357
- # t.change(year: 2020) # => Tue, 14 Apr 2020 11:45:15 EST -05:00
358
- # t.change(hour: 12) # => Fri, 14 Apr 2017 12:00:00 EST -05:00
359
- # t.change(min: 30) # => Fri, 14 Apr 2017 11:30:00 EST -05:00
360
- # t.change(offset: "-10:00") # => Fri, 14 Apr 2017 11:45:15 HST -10:00
361
- # t.change(zone: "Hawaii") # => Fri, 14 Apr 2017 11:45:15 HST -10:00
376
+ # t = Time.zone.now # => Fri, 14 Apr 2017 11:45:15.116992711 EST -05:00
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
380
+ # t.change(offset: "-10:00") # => Fri, 14 Apr 2017 11:45:15.116992711 HST -10:00
381
+ # t.change(zone: "Hawaii") # => Fri, 14 Apr 2017 11:45:15.116992711 HST -10:00
362
382
  def change(options)
363
383
  if options[:zone] && options[:offset]
364
384
  raise ArgumentError, "Can't change both :offset and :zone at the same time: #{options.inspect}"
@@ -391,14 +411,14 @@ module ActiveSupport
391
411
  # accuracy when moving across DST boundaries.
392
412
  #
393
413
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
394
- # now = Time.zone.now # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
395
- # now.advance(seconds: 1) # => Sun, 02 Nov 2014 01:26:29 EDT -04:00
396
- # now.advance(minutes: 1) # => Sun, 02 Nov 2014 01:27:28 EDT -04:00
397
- # now.advance(hours: 1) # => Sun, 02 Nov 2014 01:26:28 EST -05:00
398
- # now.advance(days: 1) # => Mon, 03 Nov 2014 01:26:28 EST -05:00
399
- # now.advance(weeks: 1) # => Sun, 09 Nov 2014 01:26:28 EST -05:00
400
- # now.advance(months: 1) # => Tue, 02 Dec 2014 01:26:28 EST -05:00
401
- # now.advance(years: 1) # => Mon, 02 Nov 2015 01:26:28 EST -05:00
414
+ # now = Time.zone.now # => Sun, 02 Nov 2014 01:26:28.558049687 EDT -04:00
415
+ # now.advance(seconds: 1) # => Sun, 02 Nov 2014 01:26:29.558049687 EDT -04:00
416
+ # now.advance(minutes: 1) # => Sun, 02 Nov 2014 01:27:28.558049687 EDT -04:00
417
+ # now.advance(hours: 1) # => Sun, 02 Nov 2014 01:26:28.558049687 EST -05:00
418
+ # now.advance(days: 1) # => Mon, 03 Nov 2014 01:26:28.558049687 EST -05:00
419
+ # now.advance(weeks: 1) # => Sun, 09 Nov 2014 01:26:28.558049687 EST -05:00
420
+ # now.advance(months: 1) # => Tue, 02 Dec 2014 01:26:28.558049687 EST -05:00
421
+ # now.advance(years: 1) # => Mon, 02 Nov 2015 01:26:28.558049687 EST -05:00
402
422
  def advance(options)
403
423
  # If we're advancing a value of variable length (i.e., years, weeks, months, days), advance from #time,
404
424
  # otherwise advance from #utc, for accuracy when moving across DST boundaries
@@ -420,13 +440,13 @@ module ActiveSupport
420
440
  # Returns Array of parts of Time in sequence of
421
441
  # [seconds, minutes, hours, day, month, year, weekday, yearday, dst?, zone].
422
442
  #
423
- # now = Time.zone.now # => Tue, 18 Aug 2015 02:29:27 UTC +00:00
443
+ # now = Time.zone.now # => Tue, 18 Aug 2015 02:29:27.485278555 UTC +00:00
424
444
  # now.to_a # => [27, 29, 2, 18, 8, 2015, 2, 230, false, "UTC"]
425
445
  def to_a
426
446
  [time.sec, time.min, time.hour, time.day, time.mon, time.year, time.wday, time.yday, dst?, zone]
427
447
  end
428
448
 
429
- # Returns the object's date and time as a floating point number of seconds
449
+ # Returns the object's date and time as a floating-point number of seconds
430
450
  # since the Epoch (January 1, 1970 00:00 UTC).
431
451
  #
432
452
  # Time.zone.now.to_f # => 1417709320.285418
@@ -517,13 +537,23 @@ module ActiveSupport
517
537
 
518
538
  # Send the missing method to +time+ instance, and wrap result in a new
519
539
  # TimeWithZone with the existing +time_zone+.
520
- def method_missing(sym, *args, &block)
521
- wrap_with_time_zone time.__send__(sym, *args, &block)
540
+ def method_missing(...)
541
+ wrap_with_time_zone time.__send__(...)
522
542
  rescue NoMethodError => e
523
- raise e, e.message.sub(time.inspect, inspect), e.backtrace
543
+ raise e, e.message.sub(time.inspect, inspect).sub("Time", "ActiveSupport::TimeWithZone"), e.backtrace
524
544
  end
525
545
 
526
546
  private
547
+ SECONDS_PER_DAY = 86400
548
+
549
+ def incorporate_utc_offset(time, offset)
550
+ if time.kind_of?(Date)
551
+ time + Rational(offset, SECONDS_PER_DAY)
552
+ else
553
+ time + offset
554
+ end
555
+ end
556
+
527
557
  def get_period_and_ensure_valid_local_time(period)
528
558
  # we don't want a Time.local instance enforcing its own DST rules as well,
529
559
  # so transfer time values to a utc constructor if necessary
@@ -544,7 +574,7 @@ module ActiveSupport
544
574
  end
545
575
 
546
576
  def duration_of_variable_length?(obj)
547
- ActiveSupport::Duration === obj && obj.parts.any? { |p| [:years, :months, :weeks, :days].include?(p[0]) }
577
+ ActiveSupport::Duration === obj && obj.variable?
548
578
  end
549
579
 
550
580
  def wrap_with_time_zone(time)
@@ -559,3 +589,8 @@ module ActiveSupport
559
589
  end
560
590
  end
561
591
  end
592
+
593
+ # These prevent Psych from calling `ActiveSupport::TimeWithZone.name`
594
+ # and triggering the deprecation warning about the change in Rails 7.1.
595
+ YAML.load_tags["!ruby/object:ActiveSupport::TimeWithZone"] = "ActiveSupport::TimeWithZone"
596
+ YAML.dump_tags[ActiveSupport::TimeWithZone] = "!ruby/object:ActiveSupport::TimeWithZone"