activesupport 6.0.6.1 → 7.1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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"