activesupport 6.0.3.4 → 6.1.3

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

Potentially problematic release.


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

Files changed (134) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +371 -448
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/active_support.rb +13 -1
  6. data/lib/active_support/array_inquirer.rb +4 -2
  7. data/lib/active_support/backtrace_cleaner.rb +3 -3
  8. data/lib/active_support/benchmarkable.rb +1 -1
  9. data/lib/active_support/cache.rb +85 -44
  10. data/lib/active_support/cache/file_store.rb +4 -3
  11. data/lib/active_support/cache/mem_cache_store.rb +29 -18
  12. data/lib/active_support/cache/memory_store.rb +46 -26
  13. data/lib/active_support/cache/redis_cache_store.rb +27 -27
  14. data/lib/active_support/cache/strategy/local_cache.rb +21 -6
  15. data/lib/active_support/callbacks.rb +65 -56
  16. data/lib/active_support/concern.rb +46 -2
  17. data/lib/active_support/configurable.rb +3 -3
  18. data/lib/active_support/configuration_file.rb +46 -0
  19. data/lib/active_support/core_ext.rb +1 -1
  20. data/lib/active_support/core_ext/benchmark.rb +2 -2
  21. data/lib/active_support/core_ext/class/attribute.rb +34 -44
  22. data/lib/active_support/core_ext/class/subclasses.rb +17 -38
  23. data/lib/active_support/core_ext/date/conversions.rb +2 -1
  24. data/lib/active_support/core_ext/date_and_time/calculations.rb +13 -0
  25. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  26. data/lib/active_support/core_ext/enumerable.rb +76 -4
  27. data/lib/active_support/core_ext/hash/conversions.rb +2 -2
  28. data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
  29. data/lib/active_support/core_ext/hash/except.rb +1 -1
  30. data/lib/active_support/core_ext/hash/keys.rb +1 -1
  31. data/lib/active_support/core_ext/hash/slice.rb +3 -2
  32. data/lib/active_support/core_ext/load_error.rb +1 -1
  33. data/lib/active_support/core_ext/marshal.rb +2 -0
  34. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  35. data/lib/active_support/core_ext/module/attribute_accessors.rb +23 -29
  36. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +8 -4
  37. data/lib/active_support/core_ext/module/concerning.rb +8 -2
  38. data/lib/active_support/core_ext/module/delegation.rb +38 -28
  39. data/lib/active_support/core_ext/module/introspection.rb +1 -25
  40. data/lib/active_support/core_ext/name_error.rb +29 -2
  41. data/lib/active_support/core_ext/numeric/conversions.rb +22 -18
  42. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  43. data/lib/active_support/core_ext/object/json.rb +13 -2
  44. data/lib/active_support/core_ext/object/try.rb +2 -2
  45. data/lib/active_support/core_ext/range/compare_range.rb +9 -3
  46. data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
  47. data/lib/active_support/core_ext/regexp.rb +8 -1
  48. data/lib/active_support/core_ext/string/access.rb +5 -24
  49. data/lib/active_support/core_ext/string/conversions.rb +1 -0
  50. data/lib/active_support/core_ext/string/inflections.rb +38 -4
  51. data/lib/active_support/core_ext/string/inquiry.rb +1 -0
  52. data/lib/active_support/core_ext/string/multibyte.rb +2 -2
  53. data/lib/active_support/core_ext/string/output_safety.rb +10 -10
  54. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  55. data/lib/active_support/core_ext/symbol.rb +3 -0
  56. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
  57. data/lib/active_support/core_ext/time/calculations.rb +27 -3
  58. data/lib/active_support/core_ext/time/conversions.rb +2 -0
  59. data/lib/active_support/core_ext/uri.rb +5 -1
  60. data/lib/active_support/current_attributes.rb +7 -2
  61. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  62. data/lib/active_support/dependencies.rb +43 -19
  63. data/lib/active_support/deprecation.rb +6 -1
  64. data/lib/active_support/deprecation/behaviors.rb +15 -2
  65. data/lib/active_support/deprecation/disallowed.rb +56 -0
  66. data/lib/active_support/deprecation/instance_delegator.rb +0 -1
  67. data/lib/active_support/deprecation/method_wrappers.rb +3 -2
  68. data/lib/active_support/deprecation/proxy_wrappers.rb +3 -3
  69. data/lib/active_support/deprecation/reporting.rb +50 -7
  70. data/lib/active_support/descendants_tracker.rb +6 -2
  71. data/lib/active_support/duration.rb +71 -22
  72. data/lib/active_support/duration/iso8601_serializer.rb +15 -9
  73. data/lib/active_support/encrypted_file.rb +19 -2
  74. data/lib/active_support/environment_inquirer.rb +20 -0
  75. data/lib/active_support/evented_file_update_checker.rb +69 -133
  76. data/lib/active_support/fork_tracker.rb +62 -0
  77. data/lib/active_support/gem_version.rb +2 -2
  78. data/lib/active_support/hash_with_indifferent_access.rb +43 -24
  79. data/lib/active_support/i18n_railtie.rb +14 -19
  80. data/lib/active_support/inflector/inflections.rb +1 -2
  81. data/lib/active_support/inflector/methods.rb +35 -31
  82. data/lib/active_support/inflector/transliterate.rb +4 -4
  83. data/lib/active_support/json/decoding.rb +4 -4
  84. data/lib/active_support/json/encoding.rb +5 -1
  85. data/lib/active_support/key_generator.rb +1 -1
  86. data/lib/active_support/locale/en.yml +7 -3
  87. data/lib/active_support/log_subscriber.rb +8 -0
  88. data/lib/active_support/logger.rb +1 -1
  89. data/lib/active_support/logger_silence.rb +2 -26
  90. data/lib/active_support/logger_thread_safe_level.rb +34 -12
  91. data/lib/active_support/message_encryptor.rb +4 -7
  92. data/lib/active_support/message_verifier.rb +5 -5
  93. data/lib/active_support/messages/metadata.rb +9 -1
  94. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  95. data/lib/active_support/messages/rotator.rb +6 -5
  96. data/lib/active_support/multibyte/chars.rb +4 -42
  97. data/lib/active_support/multibyte/unicode.rb +9 -83
  98. data/lib/active_support/notifications.rb +32 -5
  99. data/lib/active_support/notifications/fanout.rb +23 -8
  100. data/lib/active_support/notifications/instrumenter.rb +6 -15
  101. data/lib/active_support/number_helper.rb +29 -14
  102. data/lib/active_support/number_helper/number_converter.rb +1 -1
  103. data/lib/active_support/number_helper/number_to_currency_converter.rb +3 -7
  104. data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
  105. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  106. data/lib/active_support/number_helper/number_to_rounded_converter.rb +3 -3
  107. data/lib/active_support/number_helper/rounding_helper.rb +12 -28
  108. data/lib/active_support/option_merger.rb +3 -2
  109. data/lib/active_support/ordered_options.rb +8 -2
  110. data/lib/active_support/parameter_filter.rb +16 -11
  111. data/lib/active_support/per_thread_registry.rb +1 -1
  112. data/lib/active_support/rails.rb +1 -4
  113. data/lib/active_support/railtie.rb +23 -1
  114. data/lib/active_support/rescuable.rb +4 -4
  115. data/lib/active_support/secure_compare_rotator.rb +51 -0
  116. data/lib/active_support/security_utils.rb +19 -12
  117. data/lib/active_support/string_inquirer.rb +4 -2
  118. data/lib/active_support/subscriber.rb +12 -7
  119. data/lib/active_support/tagged_logging.rb +29 -4
  120. data/lib/active_support/testing/assertions.rb +18 -11
  121. data/lib/active_support/testing/parallelization.rb +12 -95
  122. data/lib/active_support/testing/parallelization/server.rb +78 -0
  123. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  124. data/lib/active_support/testing/time_helpers.rb +40 -3
  125. data/lib/active_support/time_with_zone.rb +67 -43
  126. data/lib/active_support/values/time_zone.rb +20 -10
  127. data/lib/active_support/xml_mini/rexml.rb +8 -1
  128. metadata +34 -36
  129. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
  130. data/lib/active_support/core_ext/hash/compact.rb +0 -5
  131. data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
  132. data/lib/active_support/core_ext/module/reachable.rb +0 -6
  133. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
  134. data/lib/active_support/core_ext/range/include_range.rb +0 -9
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "drb"
4
+ require "drb/unix" unless Gem.win_platform?
5
+
6
+ module ActiveSupport
7
+ module Testing
8
+ class Parallelization # :nodoc:
9
+ class Server
10
+ include DRb::DRbUndumped
11
+
12
+ def initialize
13
+ @queue = Queue.new
14
+ @active_workers = Concurrent::Map.new
15
+ @in_flight = Concurrent::Map.new
16
+ end
17
+
18
+ def record(reporter, result)
19
+ raise DRb::DRbConnError if result.is_a?(DRb::DRbUnknown)
20
+
21
+ @in_flight.delete([result.klass, result.name])
22
+
23
+ reporter.synchronize do
24
+ reporter.record(result)
25
+ end
26
+ end
27
+
28
+ def <<(o)
29
+ o[2] = DRbObject.new(o[2]) if o
30
+ @queue << o
31
+ end
32
+
33
+ def pop
34
+ if test = @queue.pop
35
+ @in_flight[[test[0].to_s, test[1]]] = test
36
+ test
37
+ end
38
+ end
39
+
40
+ def start_worker(worker_id)
41
+ @active_workers[worker_id] = true
42
+ end
43
+
44
+ def stop_worker(worker_id)
45
+ @active_workers.delete(worker_id)
46
+ end
47
+
48
+ def active_workers?
49
+ @active_workers.size > 0
50
+ end
51
+
52
+ def shutdown
53
+ # Wait for initial queue to drain
54
+ while @queue.length != 0
55
+ sleep 0.1
56
+ end
57
+
58
+ @queue.close
59
+
60
+ # Wait until all workers have finished
61
+ while active_workers?
62
+ sleep 0.1
63
+ end
64
+
65
+ @in_flight.values.each do |(klass, name, reporter)|
66
+ result = Minitest::Result.from(klass.new(name))
67
+ error = RuntimeError.new("result not reported")
68
+ error.set_backtrace([""])
69
+ result.failures << Minitest::UnexpectedError.new(error)
70
+ reporter.synchronize do
71
+ reporter.record(result)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module Testing
5
+ class Parallelization # :nodoc:
6
+ class Worker
7
+ def initialize(number, url)
8
+ @id = SecureRandom.uuid
9
+ @number = number
10
+ @url = url
11
+ @setup_exception = nil
12
+ end
13
+
14
+ def start
15
+ fork do
16
+ set_process_title("(starting)")
17
+
18
+ DRb.stop_service
19
+
20
+ @queue = DRbObject.new_with_uri(@url)
21
+ @queue.start_worker(@id)
22
+
23
+ begin
24
+ after_fork
25
+ rescue => @setup_exception; end
26
+
27
+ work_from_queue
28
+ ensure
29
+ set_process_title("(stopping)")
30
+
31
+ run_cleanup
32
+ @queue.stop_worker(@id)
33
+ end
34
+ end
35
+
36
+ def work_from_queue
37
+ while job = @queue.pop
38
+ perform_job(job)
39
+ end
40
+ end
41
+
42
+ def perform_job(job)
43
+ klass = job[0]
44
+ method = job[1]
45
+ reporter = job[2]
46
+
47
+ set_process_title("#{klass}##{method}")
48
+
49
+ result = klass.with_info_handler reporter do
50
+ Minitest.run_one_method(klass, method)
51
+ end
52
+
53
+ safe_record(reporter, result)
54
+ end
55
+
56
+ def safe_record(reporter, result)
57
+ add_setup_exception(result) if @setup_exception
58
+
59
+ begin
60
+ @queue.record(reporter, result)
61
+ rescue DRb::DRbConnError
62
+ result.failures.map! do |failure|
63
+ if failure.respond_to?(:error)
64
+ # minitest >5.14.0
65
+ error = DRb::DRbRemoteError.new(failure.error)
66
+ else
67
+ error = DRb::DRbRemoteError.new(failure.exception)
68
+ end
69
+ Minitest::UnexpectedError.new(error)
70
+ end
71
+ @queue.record(reporter, result)
72
+ end
73
+
74
+ set_process_title("(idle)")
75
+ end
76
+
77
+ def after_fork
78
+ Parallelization.after_fork_hooks.each do |cb|
79
+ cb.call(@number)
80
+ end
81
+ end
82
+
83
+ def run_cleanup
84
+ Parallelization.run_cleanup_hooks.each do |cb|
85
+ cb.call(@number)
86
+ end
87
+ end
88
+
89
+ private
90
+ def add_setup_exception(result)
91
+ result.failures.prepend Minitest::UnexpectedError.new(@setup_exception)
92
+ end
93
+
94
+ def set_process_title(status)
95
+ Process.setproctitle("Rails test worker #{@number} - #{status}")
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -6,6 +6,7 @@ require "concurrent/map"
6
6
 
7
7
  module ActiveSupport
8
8
  module Testing
9
+ # Manages stubs for TimeHelpers
9
10
  class SimpleStubs # :nodoc:
10
11
  Stub = Struct.new(:object, :method_name, :original_method)
11
12
 
@@ -13,6 +14,13 @@ module ActiveSupport
13
14
  @stubs = Concurrent::Map.new { |h, k| h[k] = {} }
14
15
  end
15
16
 
17
+ # Stubs object.method_name with the given block
18
+ # If the method is already stubbed, remove that stub
19
+ # so that removing this stub will restore the original implementation.
20
+ # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
21
+ # target = Time.zone.local(2004, 11, 24, 1, 4, 44)
22
+ # simple_stubs.stub_object(Time, :now) { at(target.to_i) }
23
+ # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
16
24
  def stub_object(object, method_name, &block)
17
25
  if stub = stubbing(object, method_name)
18
26
  unstub_object(stub)
@@ -26,6 +34,7 @@ module ActiveSupport
26
34
  object.define_singleton_method(method_name, &block)
27
35
  end
28
36
 
37
+ # Remove all object-method stubs held by this instance
29
38
  def unstub_all!
30
39
  @stubs.each_value do |object_stubs|
31
40
  object_stubs.each_value do |stub|
@@ -35,11 +44,19 @@ module ActiveSupport
35
44
  @stubs.clear
36
45
  end
37
46
 
47
+ # Returns the Stub for object#method_name
48
+ # (nil if it is not stubbed)
38
49
  def stubbing(object, method_name)
39
50
  @stubs[object.object_id][method_name]
40
51
  end
41
52
 
53
+ # Returns true if any stubs are set, false if there are none
54
+ def stubbed?
55
+ !@stubs.empty?
56
+ end
57
+
42
58
  private
59
+ # Restores the original object.method described by the Stub
43
60
  def unstub_object(stub)
44
61
  singleton_class = stub.object.singleton_class
45
62
  singleton_class.silence_redefinition_of_method stub.method_name
@@ -82,7 +99,7 @@ module ActiveSupport
82
99
  # The stubs are automatically removed at the end of the test.
83
100
  #
84
101
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
85
- # travel_to Time.zone.local(2004, 11, 24, 01, 04, 44)
102
+ # travel_to Time.zone.local(2004, 11, 24, 1, 4, 44)
86
103
  # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
87
104
  # Date.current # => Wed, 24 Nov 2004
88
105
  # DateTime.current # => Wed, 24 Nov 2004 01:04:44 -0500
@@ -104,7 +121,7 @@ module ActiveSupport
104
121
  # state at the end of the block:
105
122
  #
106
123
  # 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
124
+ # travel_to Time.zone.local(2004, 11, 24, 1, 4, 44) do
108
125
  # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
109
126
  # end
110
127
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
@@ -160,12 +177,32 @@ module ActiveSupport
160
177
  # +travel+, +travel_to+, and +freeze_time+.
161
178
  #
162
179
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
163
- # travel_to Time.zone.local(2004, 11, 24, 01, 04, 44)
180
+ #
181
+ # travel_to Time.zone.local(2004, 11, 24, 1, 4, 44)
164
182
  # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
183
+ #
165
184
  # travel_back
166
185
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
186
+ #
187
+ # This method also accepts a block, which brings the stubs back at the end of the block:
188
+ #
189
+ # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
190
+ #
191
+ # travel_to Time.zone.local(2004, 11, 24, 1, 4, 44)
192
+ # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
193
+ #
194
+ # travel_back do
195
+ # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
196
+ # end
197
+ #
198
+ # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
167
199
  def travel_back
200
+ stubbed_time = Time.current if block_given? && simple_stubs.stubbed?
201
+
168
202
  simple_stubs.unstub_all!
203
+ yield if block_given?
204
+ ensure
205
+ travel_to stubbed_time if stubbed_time
169
206
  end
170
207
  alias_method :unfreeze_time, :travel_back
171
208
 
@@ -15,25 +15,25 @@ module ActiveSupport
15
15
  # and +in_time_zone+ on Time and DateTime instances.
16
16
  #
17
17
  # 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
18
+ # Time.zone.local(2007, 2, 10, 15, 30, 45) # => Sat, 10 Feb 2007 15:30:45.000000000 EST -05:00
19
+ # Time.zone.parse('2007-02-10 15:30:45') # => Sat, 10 Feb 2007 15:30:45.000000000 EST -05:00
20
+ # Time.zone.at(1171139445) # => Sat, 10 Feb 2007 15:30:45.000000000 EST -05:00
21
+ # Time.zone.now # => Sun, 18 May 2008 13:07:55.754107581 EDT -04:00
22
+ # Time.utc(2007, 2, 10, 20, 30, 45).in_time_zone # => Sat, 10 Feb 2007 15:30:45.000000000 EST -05:00
23
23
  #
24
24
  # See Time and TimeZone for further documentation of these methods.
25
25
  #
26
26
  # TimeWithZone instances implement the same API as Ruby Time instances, so
27
27
  # that Time and TimeWithZone instances are interchangeable.
28
28
  #
29
- # t = Time.zone.now # => Sun, 18 May 2008 13:27:25 EDT -04:00
29
+ # t = Time.zone.now # => Sun, 18 May 2008 13:27:25.031505668 EDT -04:00
30
30
  # t.hour # => 13
31
31
  # t.dst? # => true
32
32
  # t.utc_offset # => -14400
33
33
  # t.zone # => "EDT"
34
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
35
+ # t + 1.day # => Mon, 19 May 2008 13:27:25.031505668 EDT -04:00
36
+ # t.beginning_of_year # => Tue, 01 Jan 2008 00:00:00.000000000 EST -05:00
37
37
  # t > Time.utc(1999) # => true
38
38
  # t.is_a?(Time) # => true
39
39
  # t.is_a?(ActiveSupport::TimeWithZone) # => true
@@ -57,12 +57,12 @@ module ActiveSupport
57
57
 
58
58
  # Returns a <tt>Time</tt> instance that represents the time in +time_zone+.
59
59
  def time
60
- @time ||= period.to_local(@utc)
60
+ @time ||= incorporate_utc_offset(@utc, utc_offset)
61
61
  end
62
62
 
63
63
  # Returns a <tt>Time</tt> instance of the simultaneous time in the UTC timezone.
64
64
  def utc
65
- @utc ||= period.to_utc(@time)
65
+ @utc ||= incorporate_utc_offset(@time, -utc_offset)
66
66
  end
67
67
  alias_method :comparable_time, :utc
68
68
  alias_method :getgm, :utc
@@ -104,13 +104,13 @@ module ActiveSupport
104
104
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
105
105
  # Time.zone.now.utc? # => false
106
106
  def utc?
107
- period.offset.abbreviation == :UTC || period.offset.abbreviation == :UCT
107
+ zone == "UTC" || zone == "UCT"
108
108
  end
109
109
  alias_method :gmt?, :utc?
110
110
 
111
111
  # Returns the offset from current time to UTC time in seconds.
112
112
  def utc_offset
113
- period.utc_total_offset
113
+ period.observed_utc_offset
114
114
  end
115
115
  alias_method :gmt_offset, :utc_offset
116
116
  alias_method :gmtoff, :utc_offset
@@ -132,14 +132,14 @@ module ActiveSupport
132
132
  # Time.zone = 'Eastern Time (US & Canada)' # => "Eastern Time (US & Canada)"
133
133
  # Time.zone.now.zone # => "EST"
134
134
  def zone
135
- period.zone_identifier.to_s
135
+ period.abbreviation
136
136
  end
137
137
 
138
138
  # Returns a string of the object's date, time, zone, and offset from UTC.
139
139
  #
140
- # Time.zone.now.inspect # => "Thu, 04 Dec 2014 11:00:25 EST -05:00"
140
+ # Time.zone.now.inspect # => "Thu, 04 Dec 2014 11:00:25.624541392 EST -05:00"
141
141
  def inspect
142
- "#{time.strftime('%a, %d %b %Y %H:%M:%S')} #{zone} #{formatted_offset}"
142
+ "#{time.strftime('%a, %d %b %Y %H:%M:%S.%9N')} #{zone} #{formatted_offset}"
143
143
  end
144
144
 
145
145
  # Returns a string of the object's date and time in the ISO 8601 standard
@@ -245,6 +245,20 @@ module ActiveSupport
245
245
  time.today?
246
246
  end
247
247
 
248
+ # Returns true if the current object's time falls within
249
+ # the next day (tomorrow).
250
+ def tomorrow?
251
+ time.tomorrow?
252
+ end
253
+ alias :next_day? :tomorrow?
254
+
255
+ # Returns true if the current object's time falls within
256
+ # the previous day (yesterday).
257
+ def yesterday?
258
+ time.yesterday?
259
+ end
260
+ alias :prev_day? :yesterday?
261
+
248
262
  # Returns true if the current object's time is in the future.
249
263
  def future?
250
264
  utc.future?
@@ -263,8 +277,8 @@ module ActiveSupport
263
277
  # value as a new TimeWithZone object.
264
278
  #
265
279
  # 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
280
+ # now = Time.zone.now # => Sun, 02 Nov 2014 01:26:28.725182881 EDT -04:00
281
+ # now + 1000 # => Sun, 02 Nov 2014 01:43:08.725182881 EDT -04:00
268
282
  #
269
283
  # If we're adding a Duration of variable length (i.e., years, months, days),
270
284
  # move forward from #time, otherwise move forward from #utc, for accuracy
@@ -273,8 +287,8 @@ module ActiveSupport
273
287
  # For instance, a time + 24.hours will advance exactly 24 hours, while a
274
288
  # time + 1.day will advance 23-25 hours, depending on the day.
275
289
  #
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
290
+ # now + 24.hours # => Mon, 03 Nov 2014 00:26:28.725182881 EST -05:00
291
+ # now + 1.day # => Mon, 03 Nov 2014 01:26:28.725182881 EST -05:00
278
292
  def +(other)
279
293
  if duration_of_variable_length?(other)
280
294
  method_missing(:+, other)
@@ -287,13 +301,13 @@ module ActiveSupport
287
301
  alias_method :in, :+
288
302
 
289
303
  # 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
304
+ # the other value +acts_like?+ time. Then it will return a Float of the difference
291
305
  # between the two times that represents the difference between the current
292
306
  # object's time and the +other+ time.
293
307
  #
294
308
  # 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
309
+ # now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28.725182881 EST -05:00
310
+ # now - 1000 # => Mon, 03 Nov 2014 00:09:48.725182881 EST -05:00
297
311
  #
298
312
  # If subtracting a Duration of variable length (i.e., years, months, days),
299
313
  # move backward from #time, otherwise move backward from #utc, for accuracy
@@ -302,8 +316,8 @@ module ActiveSupport
302
316
  # For instance, a time - 24.hours will go subtract exactly 24 hours, while a
303
317
  # time - 1.day will subtract 23-25 hours, depending on the day.
304
318
  #
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
319
+ # now - 24.hours # => Sun, 02 Nov 2014 01:26:28.725182881 EDT -04:00
320
+ # now - 1.day # => Sun, 02 Nov 2014 00:26:28.725182881 EDT -04:00
307
321
  #
308
322
  # If both the TimeWithZone object and the other value act like Time, a Float
309
323
  # will be returned.
@@ -325,8 +339,8 @@ module ActiveSupport
325
339
  # the result as a new TimeWithZone object.
326
340
  #
327
341
  # 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
342
+ # now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28.725182881 EST -05:00
343
+ # now.ago(1000) # => Mon, 03 Nov 2014 00:09:48.725182881 EST -05:00
330
344
  #
331
345
  # If we're subtracting a Duration of variable length (i.e., years, months,
332
346
  # days), move backward from #time, otherwise move backward from #utc, for
@@ -336,8 +350,8 @@ module ActiveSupport
336
350
  # while <tt>time.ago(1.day)</tt> will move back 23-25 hours, depending on
337
351
  # the day.
338
352
  #
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
353
+ # now.ago(24.hours) # => Sun, 02 Nov 2014 01:26:28.725182881 EDT -04:00
354
+ # now.ago(1.day) # => Sun, 02 Nov 2014 00:26:28.725182881 EDT -04:00
341
355
  def ago(other)
342
356
  since(-other)
343
357
  end
@@ -353,12 +367,12 @@ module ActiveSupport
353
367
  # or <tt>:nsec</tt>, not both. Similarly, pass either <tt>:zone</tt> or
354
368
  # <tt>:offset</tt>, not both.
355
369
  #
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
370
+ # t = Time.zone.now # => Fri, 14 Apr 2017 11:45:15.116992711 EST -05:00
371
+ # t.change(year: 2020) # => Tue, 14 Apr 2020 11:45:15.116992711 EST -05:00
372
+ # t.change(hour: 12) # => Fri, 14 Apr 2017 12:00:00.116992711 EST -05:00
373
+ # t.change(min: 30) # => Fri, 14 Apr 2017 11:30:00.116992711 EST -05:00
374
+ # t.change(offset: "-10:00") # => Fri, 14 Apr 2017 11:45:15.116992711 HST -10:00
375
+ # t.change(zone: "Hawaii") # => Fri, 14 Apr 2017 11:45:15.116992711 HST -10:00
362
376
  def change(options)
363
377
  if options[:zone] && options[:offset]
364
378
  raise ArgumentError, "Can't change both :offset and :zone at the same time: #{options.inspect}"
@@ -391,14 +405,14 @@ module ActiveSupport
391
405
  # accuracy when moving across DST boundaries.
392
406
  #
393
407
  # 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
408
+ # now = Time.zone.now # => Sun, 02 Nov 2014 01:26:28.558049687 EDT -04:00
409
+ # now.advance(seconds: 1) # => Sun, 02 Nov 2014 01:26:29.558049687 EDT -04:00
410
+ # now.advance(minutes: 1) # => Sun, 02 Nov 2014 01:27:28.558049687 EDT -04:00
411
+ # now.advance(hours: 1) # => Sun, 02 Nov 2014 01:26:28.558049687 EST -05:00
412
+ # now.advance(days: 1) # => Mon, 03 Nov 2014 01:26:28.558049687 EST -05:00
413
+ # now.advance(weeks: 1) # => Sun, 09 Nov 2014 01:26:28.558049687 EST -05:00
414
+ # now.advance(months: 1) # => Tue, 02 Dec 2014 01:26:28.558049687 EST -05:00
415
+ # now.advance(years: 1) # => Mon, 02 Nov 2015 01:26:28.558049687 EST -05:00
402
416
  def advance(options)
403
417
  # If we're advancing a value of variable length (i.e., years, weeks, months, days), advance from #time,
404
418
  # otherwise advance from #utc, for accuracy when moving across DST boundaries
@@ -420,7 +434,7 @@ module ActiveSupport
420
434
  # Returns Array of parts of Time in sequence of
421
435
  # [seconds, minutes, hours, day, month, year, weekday, yearday, dst?, zone].
422
436
  #
423
- # now = Time.zone.now # => Tue, 18 Aug 2015 02:29:27 UTC +00:00
437
+ # now = Time.zone.now # => Tue, 18 Aug 2015 02:29:27.485278555 UTC +00:00
424
438
  # now.to_a # => [27, 29, 2, 18, 8, 2015, 2, 230, false, "UTC"]
425
439
  def to_a
426
440
  [time.sec, time.min, time.hour, time.day, time.mon, time.year, time.wday, time.yday, dst?, zone]
@@ -524,6 +538,16 @@ module ActiveSupport
524
538
  end
525
539
 
526
540
  private
541
+ SECONDS_PER_DAY = 86400
542
+
543
+ def incorporate_utc_offset(time, offset)
544
+ if time.kind_of?(Date)
545
+ time + Rational(offset, SECONDS_PER_DAY)
546
+ else
547
+ time + offset
548
+ end
549
+ end
550
+
527
551
  def get_period_and_ensure_valid_local_time(period)
528
552
  # we don't want a Time.local instance enforcing its own DST rules as well,
529
553
  # so transfer time values to a utc constructor if necessary