activesupport 5.2.0 → 6.1.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +362 -333
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -3
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/array_inquirer.rb +4 -2
- data/lib/active_support/backtrace_cleaner.rb +29 -3
- data/lib/active_support/benchmarkable.rb +1 -1
- data/lib/active_support/cache/file_store.rb +33 -33
- data/lib/active_support/cache/mem_cache_store.rb +31 -29
- data/lib/active_support/cache/memory_store.rb +59 -33
- data/lib/active_support/cache/null_store.rb +8 -3
- data/lib/active_support/cache/redis_cache_store.rb +84 -45
- data/lib/active_support/cache/strategy/local_cache.rb +41 -26
- data/lib/active_support/cache.rb +174 -113
- data/lib/active_support/callbacks.rb +81 -64
- data/lib/active_support/concern.rb +76 -5
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
- data/lib/active_support/concurrency/share_lock.rb +0 -1
- data/lib/active_support/configurable.rb +10 -14
- data/lib/active_support/configuration_file.rb +46 -0
- data/lib/active_support/core_ext/array/access.rb +18 -6
- data/lib/active_support/core_ext/array/conversions.rb +5 -5
- data/lib/active_support/core_ext/array/extract.rb +21 -0
- data/lib/active_support/core_ext/array.rb +1 -1
- data/lib/active_support/core_ext/benchmark.rb +2 -2
- data/lib/active_support/core_ext/class/attribute.rb +32 -47
- data/lib/active_support/core_ext/class/subclasses.rb +17 -38
- data/lib/active_support/core_ext/date/calculations.rb +6 -5
- data/lib/active_support/core_ext/date/conversions.rb +2 -1
- data/lib/active_support/core_ext/date_and_time/calculations.rb +37 -47
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
- data/lib/active_support/core_ext/date_time/conversions.rb +0 -1
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/enumerable.rb +171 -70
- data/lib/active_support/core_ext/file/atomic.rb +1 -1
- data/lib/active_support/core_ext/hash/conversions.rb +3 -3
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +2 -2
- data/lib/active_support/core_ext/hash/keys.rb +1 -30
- data/lib/active_support/core_ext/hash/slice.rb +6 -27
- data/lib/active_support/core_ext/hash.rb +1 -2
- data/lib/active_support/core_ext/integer/multiple.rb +1 -1
- data/lib/active_support/core_ext/kernel.rb +0 -1
- data/lib/active_support/core_ext/load_error.rb +1 -1
- data/lib/active_support/core_ext/marshal.rb +2 -0
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +30 -39
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +17 -19
- data/lib/active_support/core_ext/module/concerning.rb +8 -2
- data/lib/active_support/core_ext/module/delegation.rb +76 -33
- data/lib/active_support/core_ext/module/introspection.rb +16 -15
- data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
- data/lib/active_support/core_ext/module.rb +0 -1
- data/lib/active_support/core_ext/name_error.rb +29 -2
- data/lib/active_support/core_ext/numeric/conversions.rb +129 -129
- data/lib/active_support/core_ext/numeric.rb +0 -1
- data/lib/active_support/core_ext/object/blank.rb +1 -2
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/duplicable.rb +7 -114
- data/lib/active_support/core_ext/object/json.rb +7 -2
- data/lib/active_support/core_ext/object/to_query.rb +5 -2
- data/lib/active_support/core_ext/object/try.rb +17 -7
- data/lib/active_support/core_ext/object/with_options.rb +1 -1
- data/lib/active_support/core_ext/range/compare_range.rb +82 -0
- data/lib/active_support/core_ext/range/conversions.rb +31 -29
- data/lib/active_support/core_ext/range/each.rb +0 -1
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
- data/lib/active_support/core_ext/range.rb +1 -1
- data/lib/active_support/core_ext/regexp.rb +8 -5
- data/lib/active_support/core_ext/securerandom.rb +23 -3
- data/lib/active_support/core_ext/string/access.rb +5 -16
- data/lib/active_support/core_ext/string/conversions.rb +1 -0
- data/lib/active_support/core_ext/string/filters.rb +42 -1
- data/lib/active_support/core_ext/string/inflections.rb +45 -6
- data/lib/active_support/core_ext/string/inquiry.rb +1 -0
- data/lib/active_support/core_ext/string/multibyte.rb +6 -5
- data/lib/active_support/core_ext/string/output_safety.rb +69 -12
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
- data/lib/active_support/core_ext/string/strip.rb +3 -1
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/time/calculations.rb +50 -3
- data/lib/active_support/core_ext/time/conversions.rb +1 -0
- data/lib/active_support/core_ext/uri.rb +7 -5
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +15 -2
- data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
- data/lib/active_support/dependencies.rb +118 -35
- data/lib/active_support/deprecation/behaviors.rb +20 -3
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +0 -1
- data/lib/active_support/deprecation/method_wrappers.rb +21 -13
- data/lib/active_support/deprecation/proxy_wrappers.rb +29 -6
- data/lib/active_support/deprecation/reporting.rb +51 -8
- data/lib/active_support/deprecation.rb +6 -1
- data/lib/active_support/descendants_tracker.rb +59 -9
- data/lib/active_support/duration/iso8601_parser.rb +2 -4
- data/lib/active_support/duration/iso8601_serializer.rb +18 -14
- data/lib/active_support/duration.rb +90 -38
- data/lib/active_support/encrypted_configuration.rb +1 -5
- data/lib/active_support/encrypted_file.rb +23 -5
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/evented_file_update_checker.rb +82 -117
- data/lib/active_support/execution_wrapper.rb +1 -0
- data/lib/active_support/file_update_checker.rb +0 -1
- data/lib/active_support/fork_tracker.rb +62 -0
- data/lib/active_support/gem_version.rb +2 -2
- data/lib/active_support/hash_with_indifferent_access.rb +78 -41
- data/lib/active_support/i18n.rb +1 -0
- data/lib/active_support/i18n_railtie.rb +16 -5
- data/lib/active_support/inflector/inflections.rb +2 -7
- data/lib/active_support/inflector/methods.rb +50 -57
- data/lib/active_support/inflector/transliterate.rb +47 -18
- data/lib/active_support/json/decoding.rb +25 -26
- data/lib/active_support/json/encoding.rb +11 -3
- data/lib/active_support/key_generator.rb +1 -33
- data/lib/active_support/lazy_load_hooks.rb +5 -2
- data/lib/active_support/locale/en.rb +33 -0
- data/lib/active_support/locale/en.yml +7 -3
- data/lib/active_support/log_subscriber.rb +39 -9
- data/lib/active_support/logger.rb +2 -17
- data/lib/active_support/logger_silence.rb +11 -19
- data/lib/active_support/logger_thread_safe_level.rb +52 -7
- data/lib/active_support/message_encryptor.rb +8 -13
- data/lib/active_support/message_verifier.rb +10 -10
- data/lib/active_support/messages/metadata.rb +11 -2
- data/lib/active_support/messages/rotation_configuration.rb +2 -1
- data/lib/active_support/messages/rotator.rb +10 -9
- data/lib/active_support/multibyte/chars.rb +10 -68
- data/lib/active_support/multibyte/unicode.rb +15 -327
- data/lib/active_support/notifications/fanout.rb +116 -16
- data/lib/active_support/notifications/instrumenter.rb +71 -9
- data/lib/active_support/notifications.rb +72 -8
- data/lib/active_support/number_helper/number_converter.rb +5 -6
- data/lib/active_support/number_helper/number_to_currency_converter.rb +4 -9
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -2
- data/lib/active_support/number_helper/number_to_human_converter.rb +4 -3
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +4 -3
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +8 -7
- data/lib/active_support/number_helper/rounding_helper.rb +12 -28
- data/lib/active_support/number_helper.rb +38 -12
- data/lib/active_support/option_merger.rb +22 -3
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/ordered_options.rb +13 -3
- data/lib/active_support/parameter_filter.rb +133 -0
- data/lib/active_support/per_thread_registry.rb +1 -1
- data/lib/active_support/rails.rb +1 -10
- data/lib/active_support/railtie.rb +23 -1
- data/lib/active_support/reloader.rb +4 -5
- data/lib/active_support/secure_compare_rotator.rb +51 -0
- data/lib/active_support/security_utils.rb +19 -12
- data/lib/active_support/string_inquirer.rb +4 -3
- data/lib/active_support/subscriber.rb +72 -24
- data/lib/active_support/tagged_logging.rb +42 -8
- data/lib/active_support/test_case.rb +92 -1
- data/lib/active_support/testing/assertions.rb +30 -9
- data/lib/active_support/testing/deprecation.rb +0 -1
- data/lib/active_support/testing/file_fixtures.rb +2 -0
- data/lib/active_support/testing/isolation.rb +2 -2
- data/lib/active_support/testing/method_call_assertions.rb +28 -1
- data/lib/active_support/testing/parallelization/server.rb +78 -0
- data/lib/active_support/testing/parallelization/worker.rb +100 -0
- data/lib/active_support/testing/parallelization.rb +51 -0
- data/lib/active_support/testing/setup_and_teardown.rb +5 -9
- data/lib/active_support/testing/stream.rb +1 -2
- data/lib/active_support/testing/time_helpers.rb +47 -12
- data/lib/active_support/time_with_zone.rb +81 -47
- data/lib/active_support/values/time_zone.rb +34 -18
- data/lib/active_support/xml_mini/jdom.rb +2 -3
- data/lib/active_support/xml_mini/libxml.rb +2 -2
- data/lib/active_support/xml_mini/libxmlsax.rb +4 -4
- data/lib/active_support/xml_mini/nokogiri.rb +2 -2
- data/lib/active_support/xml_mini/nokogirisax.rb +3 -3
- data/lib/active_support/xml_mini/rexml.rb +10 -3
- data/lib/active_support/xml_mini.rb +2 -10
- data/lib/active_support.rb +14 -1
- metadata +57 -30
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -9
- data/lib/active_support/core_ext/hash/compact.rb +0 -29
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -32
- data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
- data/lib/active_support/core_ext/module/reachable.rb +0 -11
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -28
- data/lib/active_support/core_ext/range/include_range.rb +0 -25
- data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -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
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "drb"
|
4
|
+
require "drb/unix" unless Gem.win_platform?
|
5
|
+
require "active_support/core_ext/module/attribute_accessors"
|
6
|
+
require "active_support/testing/parallelization/server"
|
7
|
+
require "active_support/testing/parallelization/worker"
|
8
|
+
|
9
|
+
module ActiveSupport
|
10
|
+
module Testing
|
11
|
+
class Parallelization # :nodoc:
|
12
|
+
@@after_fork_hooks = []
|
13
|
+
|
14
|
+
def self.after_fork_hook(&blk)
|
15
|
+
@@after_fork_hooks << blk
|
16
|
+
end
|
17
|
+
|
18
|
+
cattr_reader :after_fork_hooks
|
19
|
+
|
20
|
+
@@run_cleanup_hooks = []
|
21
|
+
|
22
|
+
def self.run_cleanup_hook(&blk)
|
23
|
+
@@run_cleanup_hooks << blk
|
24
|
+
end
|
25
|
+
|
26
|
+
cattr_reader :run_cleanup_hooks
|
27
|
+
|
28
|
+
def initialize(worker_count)
|
29
|
+
@worker_count = worker_count
|
30
|
+
@queue_server = Server.new
|
31
|
+
@worker_pool = []
|
32
|
+
@url = DRb.start_service("drbunix:", @queue_server).uri
|
33
|
+
end
|
34
|
+
|
35
|
+
def start
|
36
|
+
@worker_pool = @worker_count.times.map do |worker|
|
37
|
+
Worker.new(worker, @url).start
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def <<(work)
|
42
|
+
@queue_server << work
|
43
|
+
end
|
44
|
+
|
45
|
+
def shutdown
|
46
|
+
@queue_server.shutdown
|
47
|
+
@worker_pool.each { |pid| Process.waitpid pid }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/concern"
|
4
3
|
require "active_support/callbacks"
|
5
4
|
|
6
5
|
module ActiveSupport
|
@@ -19,11 +18,10 @@ module ActiveSupport
|
|
19
18
|
# end
|
20
19
|
# end
|
21
20
|
module SetupAndTeardown
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
define_callbacks :setup, :teardown
|
21
|
+
def self.prepended(klass)
|
22
|
+
klass.include ActiveSupport::Callbacks
|
23
|
+
klass.define_callbacks :setup, :teardown
|
24
|
+
klass.extend ClassMethods
|
27
25
|
end
|
28
26
|
|
29
27
|
module ClassMethods
|
@@ -47,12 +45,10 @@ module ActiveSupport
|
|
47
45
|
begin
|
48
46
|
run_callbacks :teardown
|
49
47
|
rescue => e
|
50
|
-
|
48
|
+
self.failures << Minitest::UnexpectedError.new(e)
|
51
49
|
end
|
52
50
|
|
53
51
|
super
|
54
|
-
ensure
|
55
|
-
raise error if error
|
56
52
|
end
|
57
53
|
end
|
58
54
|
end
|
@@ -4,7 +4,6 @@ module ActiveSupport
|
|
4
4
|
module Testing
|
5
5
|
module Stream #:nodoc:
|
6
6
|
private
|
7
|
-
|
8
7
|
def silence_stream(stream)
|
9
8
|
old_stream = stream.dup
|
10
9
|
stream.reopen(IO::NULL)
|
@@ -33,7 +32,7 @@ module ActiveSupport
|
|
33
32
|
yield
|
34
33
|
|
35
34
|
stream_io.rewind
|
36
|
-
|
35
|
+
captured_stream.read
|
37
36
|
ensure
|
38
37
|
captured_stream.close
|
39
38
|
captured_stream.unlink
|
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/core_ext/module/redefine_method"
|
4
|
-
require "active_support/core_ext/string/strip" # for strip_heredoc
|
5
4
|
require "active_support/core_ext/time/calculations"
|
6
5
|
require "concurrent/map"
|
7
6
|
|
8
7
|
module ActiveSupport
|
9
8
|
module Testing
|
9
|
+
# Manages stubs for TimeHelpers
|
10
10
|
class SimpleStubs # :nodoc:
|
11
11
|
Stub = Struct.new(:object, :method_name, :original_method)
|
12
12
|
|
@@ -14,6 +14,13 @@ module ActiveSupport
|
|
14
14
|
@stubs = Concurrent::Map.new { |h, k| h[k] = {} }
|
15
15
|
end
|
16
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
|
17
24
|
def stub_object(object, method_name, &block)
|
18
25
|
if stub = stubbing(object, method_name)
|
19
26
|
unstub_object(stub)
|
@@ -23,10 +30,11 @@ module ActiveSupport
|
|
23
30
|
|
24
31
|
@stubs[object.object_id][method_name] = Stub.new(object, method_name, new_name)
|
25
32
|
|
26
|
-
object.singleton_class.
|
33
|
+
object.singleton_class.alias_method new_name, method_name
|
27
34
|
object.define_singleton_method(method_name, &block)
|
28
35
|
end
|
29
36
|
|
37
|
+
# Remove all object-method stubs held by this instance
|
30
38
|
def unstub_all!
|
31
39
|
@stubs.each_value do |object_stubs|
|
32
40
|
object_stubs.each_value do |stub|
|
@@ -36,17 +44,24 @@ module ActiveSupport
|
|
36
44
|
@stubs.clear
|
37
45
|
end
|
38
46
|
|
47
|
+
# Returns the Stub for object#method_name
|
48
|
+
# (nil if it is not stubbed)
|
39
49
|
def stubbing(object, method_name)
|
40
50
|
@stubs[object.object_id][method_name]
|
41
51
|
end
|
42
52
|
|
43
|
-
|
53
|
+
# Returns true if any stubs are set, false if there are none
|
54
|
+
def stubbed?
|
55
|
+
!@stubs.empty?
|
56
|
+
end
|
44
57
|
|
58
|
+
private
|
59
|
+
# Restores the original object.method described by the Stub
|
45
60
|
def unstub_object(stub)
|
46
61
|
singleton_class = stub.object.singleton_class
|
47
|
-
singleton_class.
|
48
|
-
singleton_class.
|
49
|
-
singleton_class.
|
62
|
+
singleton_class.silence_redefinition_of_method stub.method_name
|
63
|
+
singleton_class.alias_method stub.method_name, stub.original_method
|
64
|
+
singleton_class.undef_method stub.original_method
|
50
65
|
end
|
51
66
|
end
|
52
67
|
|
@@ -84,7 +99,7 @@ module ActiveSupport
|
|
84
99
|
# The stubs are automatically removed at the end of the test.
|
85
100
|
#
|
86
101
|
# Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
|
87
|
-
# travel_to Time.zone.local(2004, 11, 24,
|
102
|
+
# travel_to Time.zone.local(2004, 11, 24, 1, 4, 44)
|
88
103
|
# Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
|
89
104
|
# Date.current # => Wed, 24 Nov 2004
|
90
105
|
# DateTime.current # => Wed, 24 Nov 2004 01:04:44 -0500
|
@@ -106,13 +121,13 @@ module ActiveSupport
|
|
106
121
|
# state at the end of the block:
|
107
122
|
#
|
108
123
|
# Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
|
109
|
-
# travel_to Time.zone.local(2004, 11, 24,
|
124
|
+
# travel_to Time.zone.local(2004, 11, 24, 1, 4, 44) do
|
110
125
|
# Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
|
111
126
|
# end
|
112
127
|
# Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
|
113
128
|
def travel_to(date_or_time)
|
114
129
|
if block_given? && simple_stubs.stubbing(Time, :now)
|
115
|
-
travel_to_nested_block_call =
|
130
|
+
travel_to_nested_block_call = <<~MSG
|
116
131
|
|
117
132
|
Calling `travel_to` with a block, when we have previously already made a call to `travel_to`, can lead to confusing time stubbing.
|
118
133
|
|
@@ -159,16 +174,37 @@ module ActiveSupport
|
|
159
174
|
end
|
160
175
|
|
161
176
|
# Returns the current time back to its original state, by removing the stubs added by
|
162
|
-
# +travel+ and +
|
177
|
+
# +travel+, +travel_to+, and +freeze_time+.
|
163
178
|
#
|
164
179
|
# Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
|
165
|
-
#
|
180
|
+
#
|
181
|
+
# travel_to Time.zone.local(2004, 11, 24, 1, 4, 44)
|
166
182
|
# Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
|
183
|
+
#
|
167
184
|
# travel_back
|
168
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
|
169
199
|
def travel_back
|
200
|
+
stubbed_time = Time.current if block_given? && simple_stubs.stubbed?
|
201
|
+
|
170
202
|
simple_stubs.unstub_all!
|
203
|
+
yield if block_given?
|
204
|
+
ensure
|
205
|
+
travel_to stubbed_time if stubbed_time
|
171
206
|
end
|
207
|
+
alias_method :unfreeze_time, :travel_back
|
172
208
|
|
173
209
|
# Calls +travel_to+ with +Time.now+.
|
174
210
|
#
|
@@ -191,7 +227,6 @@ module ActiveSupport
|
|
191
227
|
end
|
192
228
|
|
193
229
|
private
|
194
|
-
|
195
230
|
def simple_stubs
|
196
231
|
@simple_stubs ||= SimpleStubs.new
|
197
232
|
end
|
@@ -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
|
@@ -43,8 +43,8 @@ module ActiveSupport
|
|
43
43
|
"Time"
|
44
44
|
end
|
45
45
|
|
46
|
-
PRECISIONS = Hash.new { |h, n| h[n] = "%FT%T.%#{n}N"
|
47
|
-
PRECISIONS[0] = "%FT%T"
|
46
|
+
PRECISIONS = Hash.new { |h, n| h[n] = "%FT%T.%#{n}N" }
|
47
|
+
PRECISIONS[0] = "%FT%T"
|
48
48
|
|
49
49
|
include Comparable, DateAndTime::Compatibility
|
50
50
|
attr_reader :time_zone
|
@@ -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 ||=
|
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 ||=
|
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
|
-
|
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.
|
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.
|
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
|
@@ -147,7 +147,7 @@ module ActiveSupport
|
|
147
147
|
#
|
148
148
|
# Time.zone.now.xmlschema # => "2014-12-04T11:02:37-05:00"
|
149
149
|
def xmlschema(fraction_digits = 0)
|
150
|
-
"#{time.strftime(PRECISIONS[fraction_digits.to_i])}#{formatted_offset(true, 'Z'
|
150
|
+
"#{time.strftime(PRECISIONS[fraction_digits.to_i])}#{formatted_offset(true, 'Z')}"
|
151
151
|
end
|
152
152
|
alias_method :iso8601, :xmlschema
|
153
153
|
alias_method :rfc3339, :xmlschema
|
@@ -225,6 +225,8 @@ module ActiveSupport
|
|
225
225
|
def <=>(other)
|
226
226
|
utc <=> other
|
227
227
|
end
|
228
|
+
alias_method :before?, :<
|
229
|
+
alias_method :after?, :>
|
228
230
|
|
229
231
|
# Returns true if the current object's time is within the specified
|
230
232
|
# +min+ and +max+ time.
|
@@ -243,6 +245,20 @@ module ActiveSupport
|
|
243
245
|
time.today?
|
244
246
|
end
|
245
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
|
+
|
246
262
|
# Returns true if the current object's time is in the future.
|
247
263
|
def future?
|
248
264
|
utc.future?
|
@@ -261,8 +277,8 @@ module ActiveSupport
|
|
261
277
|
# value as a new TimeWithZone object.
|
262
278
|
#
|
263
279
|
# Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
|
264
|
-
# now = Time.zone.now # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
|
265
|
-
# 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
|
266
282
|
#
|
267
283
|
# If we're adding a Duration of variable length (i.e., years, months, days),
|
268
284
|
# move forward from #time, otherwise move forward from #utc, for accuracy
|
@@ -271,8 +287,8 @@ module ActiveSupport
|
|
271
287
|
# For instance, a time + 24.hours will advance exactly 24 hours, while a
|
272
288
|
# time + 1.day will advance 23-25 hours, depending on the day.
|
273
289
|
#
|
274
|
-
# now + 24.hours # => Mon, 03 Nov 2014 00:26:28 EST -05:00
|
275
|
-
# 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
|
276
292
|
def +(other)
|
277
293
|
if duration_of_variable_length?(other)
|
278
294
|
method_missing(:+, other)
|
@@ -284,12 +300,14 @@ module ActiveSupport
|
|
284
300
|
alias_method :since, :+
|
285
301
|
alias_method :in, :+
|
286
302
|
|
287
|
-
#
|
288
|
-
# the
|
303
|
+
# Subtracts an interval of time and returns a new TimeWithZone object unless
|
304
|
+
# the other value `acts_like?` time. Then it will return a Float of the difference
|
305
|
+
# between the two times that represents the difference between the current
|
306
|
+
# object's time and the +other+ time.
|
289
307
|
#
|
290
308
|
# Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
|
291
|
-
# now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28 EST -05:00
|
292
|
-
# 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
|
293
311
|
#
|
294
312
|
# If subtracting a Duration of variable length (i.e., years, months, days),
|
295
313
|
# move backward from #time, otherwise move backward from #utc, for accuracy
|
@@ -298,8 +316,14 @@ module ActiveSupport
|
|
298
316
|
# For instance, a time - 24.hours will go subtract exactly 24 hours, while a
|
299
317
|
# time - 1.day will subtract 23-25 hours, depending on the day.
|
300
318
|
#
|
301
|
-
# now - 24.hours # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
|
302
|
-
# 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
|
321
|
+
#
|
322
|
+
# If both the TimeWithZone object and the other value act like Time, a Float
|
323
|
+
# will be returned.
|
324
|
+
#
|
325
|
+
# Time.zone.now - 1.day.ago # => 86399.999967
|
326
|
+
#
|
303
327
|
def -(other)
|
304
328
|
if other.acts_like?(:time)
|
305
329
|
to_time - other.to_time
|
@@ -315,8 +339,8 @@ module ActiveSupport
|
|
315
339
|
# the result as a new TimeWithZone object.
|
316
340
|
#
|
317
341
|
# Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
|
318
|
-
# now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28 EST -05:00
|
319
|
-
# 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
|
320
344
|
#
|
321
345
|
# If we're subtracting a Duration of variable length (i.e., years, months,
|
322
346
|
# days), move backward from #time, otherwise move backward from #utc, for
|
@@ -326,8 +350,8 @@ module ActiveSupport
|
|
326
350
|
# while <tt>time.ago(1.day)</tt> will move back 23-25 hours, depending on
|
327
351
|
# the day.
|
328
352
|
#
|
329
|
-
# now.ago(24.hours) # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
|
330
|
-
# 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
|
331
355
|
def ago(other)
|
332
356
|
since(-other)
|
333
357
|
end
|
@@ -343,12 +367,12 @@ module ActiveSupport
|
|
343
367
|
# or <tt>:nsec</tt>, not both. Similarly, pass either <tt>:zone</tt> or
|
344
368
|
# <tt>:offset</tt>, not both.
|
345
369
|
#
|
346
|
-
# t = Time.zone.now # => Fri, 14 Apr 2017 11:45:15 EST -05:00
|
347
|
-
# t.change(year: 2020) # => Tue, 14 Apr 2020 11:45:15 EST -05:00
|
348
|
-
# t.change(hour: 12) # => Fri, 14 Apr 2017 12:00:00 EST -05:00
|
349
|
-
# t.change(min: 30) # => Fri, 14 Apr 2017 11:30:00 EST -05:00
|
350
|
-
# t.change(offset: "-10:00") # => Fri, 14 Apr 2017 11:45:15 HST -10:00
|
351
|
-
# 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
|
352
376
|
def change(options)
|
353
377
|
if options[:zone] && options[:offset]
|
354
378
|
raise ArgumentError, "Can't change both :offset and :zone at the same time: #{options.inspect}"
|
@@ -381,14 +405,14 @@ module ActiveSupport
|
|
381
405
|
# accuracy when moving across DST boundaries.
|
382
406
|
#
|
383
407
|
# Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
|
384
|
-
# now = Time.zone.now # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
|
385
|
-
# now.advance(seconds: 1) # => Sun, 02 Nov 2014 01:26:29 EDT -04:00
|
386
|
-
# now.advance(minutes: 1) # => Sun, 02 Nov 2014 01:27:28 EDT -04:00
|
387
|
-
# now.advance(hours: 1) # => Sun, 02 Nov 2014 01:26:28 EST -05:00
|
388
|
-
# now.advance(days: 1) # => Mon, 03 Nov 2014 01:26:28 EST -05:00
|
389
|
-
# now.advance(weeks: 1) # => Sun, 09 Nov 2014 01:26:28 EST -05:00
|
390
|
-
# now.advance(months: 1) # => Tue, 02 Dec 2014 01:26:28 EST -05:00
|
391
|
-
# 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
|
392
416
|
def advance(options)
|
393
417
|
# If we're advancing a value of variable length (i.e., years, weeks, months, days), advance from #time,
|
394
418
|
# otherwise advance from #utc, for accuracy when moving across DST boundaries
|
@@ -410,7 +434,7 @@ module ActiveSupport
|
|
410
434
|
# Returns Array of parts of Time in sequence of
|
411
435
|
# [seconds, minutes, hours, day, month, year, weekday, yearday, dst?, zone].
|
412
436
|
#
|
413
|
-
# 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
|
414
438
|
# now.to_a # => [27, 29, 2, 18, 8, 2015, 2, 230, false, "UTC"]
|
415
439
|
def to_a
|
416
440
|
[time.sec, time.min, time.hour, time.day, time.mon, time.year, time.wday, time.yday, dst?, zone]
|
@@ -514,6 +538,16 @@ module ActiveSupport
|
|
514
538
|
end
|
515
539
|
|
516
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
|
+
|
517
551
|
def get_period_and_ensure_valid_local_time(period)
|
518
552
|
# we don't want a Time.local instance enforcing its own DST rules as well,
|
519
553
|
# so transfer time values to a utc constructor if necessary
|