activesupport 6.0.4 → 6.1.4
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 +388 -460
- data/MIT-LICENSE +1 -1
- data/lib/active_support/array_inquirer.rb +4 -2
- data/lib/active_support/backtrace_cleaner.rb +3 -3
- data/lib/active_support/benchmarkable.rb +1 -1
- data/lib/active_support/cache/file_store.rb +3 -3
- data/lib/active_support/cache/mem_cache_store.rb +28 -18
- data/lib/active_support/cache/memory_store.rb +46 -26
- data/lib/active_support/cache/redis_cache_store.rb +25 -25
- data/lib/active_support/cache/strategy/local_cache.rb +20 -5
- data/lib/active_support/cache.rb +87 -40
- data/lib/active_support/callbacks.rb +65 -56
- data/lib/active_support/concern.rb +46 -2
- data/lib/active_support/configurable.rb +3 -3
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/benchmark.rb +2 -2
- data/lib/active_support/core_ext/class/attribute.rb +34 -44
- data/lib/active_support/core_ext/class/subclasses.rb +17 -38
- data/lib/active_support/core_ext/date/conversions.rb +2 -1
- data/lib/active_support/core_ext/date_and_time/calculations.rb +13 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/enumerable.rb +76 -4
- data/lib/active_support/core_ext/hash/conversions.rb +2 -2
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
- data/lib/active_support/core_ext/hash/keys.rb +1 -1
- data/lib/active_support/core_ext/hash/slice.rb +3 -2
- 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 +23 -29
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +8 -4
- data/lib/active_support/core_ext/module/concerning.rb +8 -2
- data/lib/active_support/core_ext/module/delegation.rb +38 -28
- data/lib/active_support/core_ext/module/introspection.rb +1 -25
- data/lib/active_support/core_ext/name_error.rb +29 -2
- data/lib/active_support/core_ext/numeric/conversions.rb +22 -18
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/json.rb +12 -1
- data/lib/active_support/core_ext/object/try.rb +2 -2
- data/lib/active_support/core_ext/range/compare_range.rb +9 -3
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
- data/lib/active_support/core_ext/regexp.rb +8 -1
- data/lib/active_support/core_ext/string/access.rb +5 -24
- data/lib/active_support/core_ext/string/conversions.rb +1 -0
- data/lib/active_support/core_ext/string/inflections.rb +38 -4
- data/lib/active_support/core_ext/string/inquiry.rb +1 -0
- data/lib/active_support/core_ext/string/multibyte.rb +2 -2
- data/lib/active_support/core_ext/string/output_safety.rb +3 -4
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
- 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 +17 -0
- data/lib/active_support/core_ext/time/conversions.rb +2 -0
- data/lib/active_support/core_ext/uri.rb +5 -1
- data/lib/active_support/core_ext.rb +1 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +8 -2
- data/lib/active_support/dependencies.rb +37 -18
- data/lib/active_support/deprecation/behaviors.rb +15 -2
- 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 +3 -2
- data/lib/active_support/deprecation/proxy_wrappers.rb +2 -2
- data/lib/active_support/deprecation/reporting.rb +50 -7
- data/lib/active_support/deprecation.rb +6 -1
- data/lib/active_support/descendants_tracker.rb +6 -2
- data/lib/active_support/duration/iso8601_serializer.rb +15 -9
- data/lib/active_support/duration.rb +71 -22
- data/lib/active_support/encrypted_file.rb +19 -2
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/evented_file_update_checker.rb +69 -133
- data/lib/active_support/fork_tracker.rb +64 -0
- data/lib/active_support/gem_version.rb +1 -1
- data/lib/active_support/hash_with_indifferent_access.rb +48 -24
- data/lib/active_support/i18n_railtie.rb +14 -19
- data/lib/active_support/inflector/inflections.rb +1 -2
- data/lib/active_support/inflector/methods.rb +35 -31
- data/lib/active_support/inflector/transliterate.rb +4 -4
- data/lib/active_support/json/decoding.rb +4 -4
- data/lib/active_support/json/encoding.rb +5 -1
- data/lib/active_support/key_generator.rb +1 -1
- data/lib/active_support/locale/en.yml +7 -3
- data/lib/active_support/log_subscriber.rb +8 -0
- data/lib/active_support/logger.rb +1 -1
- data/lib/active_support/logger_silence.rb +2 -26
- data/lib/active_support/logger_thread_safe_level.rb +34 -12
- data/lib/active_support/message_encryptor.rb +4 -7
- data/lib/active_support/message_verifier.rb +5 -5
- data/lib/active_support/messages/rotation_configuration.rb +2 -1
- data/lib/active_support/messages/rotator.rb +6 -5
- data/lib/active_support/multibyte/chars.rb +4 -42
- data/lib/active_support/multibyte/unicode.rb +9 -83
- data/lib/active_support/notifications/fanout.rb +23 -8
- data/lib/active_support/notifications/instrumenter.rb +6 -15
- data/lib/active_support/notifications.rb +32 -5
- data/lib/active_support/number_helper/number_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +9 -5
- data/lib/active_support/number_helper/rounding_helper.rb +12 -28
- data/lib/active_support/number_helper.rb +29 -14
- data/lib/active_support/option_merger.rb +2 -1
- data/lib/active_support/ordered_options.rb +8 -2
- data/lib/active_support/parameter_filter.rb +16 -11
- data/lib/active_support/per_thread_registry.rb +1 -1
- data/lib/active_support/rails.rb +1 -4
- data/lib/active_support/railtie.rb +23 -1
- data/lib/active_support/rescuable.rb +4 -4
- 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 -2
- data/lib/active_support/subscriber.rb +12 -7
- data/lib/active_support/tagged_logging.rb +29 -4
- data/lib/active_support/testing/assertions.rb +18 -11
- 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 +12 -95
- data/lib/active_support/testing/time_helpers.rb +40 -3
- data/lib/active_support/time_with_zone.rb +67 -43
- data/lib/active_support/values/time_zone.rb +20 -10
- data/lib/active_support/xml_mini/rexml.rb +8 -1
- data/lib/active_support.rb +13 -1
- metadata +33 -35
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
- data/lib/active_support/core_ext/hash/compact.rb +0 -5
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
- data/lib/active_support/core_ext/module/reachable.rb +0 -6
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
- data/lib/active_support/core_ext/range/include_range.rb +0 -9
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/enumerable"
|
4
|
+
|
3
5
|
module ActiveSupport
|
4
6
|
module Testing
|
5
7
|
module Assertions
|
@@ -30,6 +32,8 @@ module ActiveSupport
|
|
30
32
|
# end
|
31
33
|
def assert_nothing_raised
|
32
34
|
yield
|
35
|
+
rescue => error
|
36
|
+
raise Minitest::UnexpectedError.new(error)
|
33
37
|
end
|
34
38
|
|
35
39
|
# Test numeric difference between the return value of an expression as a
|
@@ -87,7 +91,7 @@ module ActiveSupport
|
|
87
91
|
else
|
88
92
|
difference = args[0] || 1
|
89
93
|
message = args[1]
|
90
|
-
|
94
|
+
Array(expression).index_with(difference)
|
91
95
|
end
|
92
96
|
|
93
97
|
exps = expressions.keys.map { |e|
|
@@ -95,7 +99,7 @@ module ActiveSupport
|
|
95
99
|
}
|
96
100
|
before = exps.map(&:call)
|
97
101
|
|
98
|
-
retval =
|
102
|
+
retval = assert_nothing_raised(&block)
|
99
103
|
|
100
104
|
expressions.zip(exps, before) do |(code, diff), exp, before_value|
|
101
105
|
error = "#{code.inspect} didn't change by #{diff}"
|
@@ -172,10 +176,10 @@ module ActiveSupport
|
|
172
176
|
exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) }
|
173
177
|
|
174
178
|
before = exp.call
|
175
|
-
retval =
|
179
|
+
retval = assert_nothing_raised(&block)
|
176
180
|
|
177
181
|
unless from == UNTRACKED
|
178
|
-
error = "
|
182
|
+
error = "Expected change from #{from.inspect}"
|
179
183
|
error = "#{message}.\n#{error}" if message
|
180
184
|
assert from === before, error
|
181
185
|
end
|
@@ -185,12 +189,10 @@ module ActiveSupport
|
|
185
189
|
error = "#{expression.inspect} didn't change"
|
186
190
|
error = "#{error}. It was already #{to}" if before == to
|
187
191
|
error = "#{message}.\n#{error}" if message
|
188
|
-
|
192
|
+
assert_not_equal before, after, error
|
189
193
|
|
190
194
|
unless to == UNTRACKED
|
191
|
-
error = "
|
192
|
-
error = "#{error}Expected: #{to.inspect}\n"
|
193
|
-
error = "#{error} Actual: #{after.inspect}"
|
195
|
+
error = "Expected change to #{to}\n"
|
194
196
|
error = "#{message}.\n#{error}" if message
|
195
197
|
assert to === after, error
|
196
198
|
end
|
@@ -214,12 +216,17 @@ module ActiveSupport
|
|
214
216
|
exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) }
|
215
217
|
|
216
218
|
before = exp.call
|
217
|
-
retval =
|
219
|
+
retval = assert_nothing_raised(&block)
|
218
220
|
after = exp.call
|
219
221
|
|
220
|
-
error = "#{expression.inspect}
|
222
|
+
error = "#{expression.inspect} changed"
|
221
223
|
error = "#{message}.\n#{error}" if message
|
222
|
-
|
224
|
+
|
225
|
+
if before.nil?
|
226
|
+
assert_nil after, error
|
227
|
+
else
|
228
|
+
assert_equal before, after, error
|
229
|
+
end
|
223
230
|
|
224
231
|
retval
|
225
232
|
end
|
@@ -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
|
@@ -3,37 +3,12 @@
|
|
3
3
|
require "drb"
|
4
4
|
require "drb/unix" unless Gem.win_platform?
|
5
5
|
require "active_support/core_ext/module/attribute_accessors"
|
6
|
+
require "active_support/testing/parallelization/server"
|
7
|
+
require "active_support/testing/parallelization/worker"
|
6
8
|
|
7
9
|
module ActiveSupport
|
8
10
|
module Testing
|
9
11
|
class Parallelization # :nodoc:
|
10
|
-
class Server
|
11
|
-
include DRb::DRbUndumped
|
12
|
-
|
13
|
-
def initialize
|
14
|
-
@queue = Queue.new
|
15
|
-
end
|
16
|
-
|
17
|
-
def record(reporter, result)
|
18
|
-
raise DRb::DRbConnError if result.is_a?(DRb::DRbUnknown)
|
19
|
-
|
20
|
-
reporter.synchronize do
|
21
|
-
reporter.record(result)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def <<(o)
|
26
|
-
o[2] = DRbObject.new(o[2]) if o
|
27
|
-
@queue << o
|
28
|
-
end
|
29
|
-
|
30
|
-
def length
|
31
|
-
@queue.length
|
32
|
-
end
|
33
|
-
|
34
|
-
def pop; @queue.pop; end
|
35
|
-
end
|
36
|
-
|
37
12
|
@@after_fork_hooks = []
|
38
13
|
|
39
14
|
def self.after_fork_hook(&blk)
|
@@ -50,85 +25,27 @@ module ActiveSupport
|
|
50
25
|
|
51
26
|
cattr_reader :run_cleanup_hooks
|
52
27
|
|
53
|
-
def initialize(
|
54
|
-
@
|
55
|
-
@
|
56
|
-
@
|
57
|
-
|
58
|
-
@url = DRb.start_service("drbunix:", @queue).uri
|
59
|
-
end
|
60
|
-
|
61
|
-
def after_fork(worker)
|
62
|
-
self.class.after_fork_hooks.each do |cb|
|
63
|
-
cb.call(worker)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def run_cleanup(worker)
|
68
|
-
self.class.run_cleanup_hooks.each do |cb|
|
69
|
-
cb.call(worker)
|
70
|
-
end
|
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
|
71
33
|
end
|
72
34
|
|
73
35
|
def start
|
74
|
-
@
|
75
|
-
|
76
|
-
DRb.stop_service
|
77
|
-
|
78
|
-
begin
|
79
|
-
after_fork(worker)
|
80
|
-
rescue => setup_exception; end
|
81
|
-
|
82
|
-
queue = DRbObject.new_with_uri(@url)
|
83
|
-
|
84
|
-
while job = queue.pop
|
85
|
-
klass = job[0]
|
86
|
-
method = job[1]
|
87
|
-
reporter = job[2]
|
88
|
-
result = klass.with_info_handler reporter do
|
89
|
-
Minitest.run_one_method(klass, method)
|
90
|
-
end
|
91
|
-
|
92
|
-
add_setup_exception(result, setup_exception) if setup_exception
|
93
|
-
|
94
|
-
begin
|
95
|
-
queue.record(reporter, result)
|
96
|
-
rescue DRb::DRbConnError
|
97
|
-
result.failures.map! do |failure|
|
98
|
-
if failure.respond_to?(:error)
|
99
|
-
# minitest >5.14.0
|
100
|
-
error = DRb::DRbRemoteError.new(failure.error)
|
101
|
-
else
|
102
|
-
error = DRb::DRbRemoteError.new(failure.exception)
|
103
|
-
end
|
104
|
-
Minitest::UnexpectedError.new(error)
|
105
|
-
end
|
106
|
-
queue.record(reporter, result)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
ensure
|
110
|
-
run_cleanup(worker)
|
111
|
-
end
|
36
|
+
@worker_pool = @worker_count.times.map do |worker|
|
37
|
+
Worker.new(worker, @url).start
|
112
38
|
end
|
113
39
|
end
|
114
40
|
|
115
41
|
def <<(work)
|
116
|
-
@
|
42
|
+
@queue_server << work
|
117
43
|
end
|
118
44
|
|
119
45
|
def shutdown
|
120
|
-
@
|
121
|
-
@
|
122
|
-
|
123
|
-
if @queue.length > 0
|
124
|
-
raise "Queue not empty, but all workers have finished. This probably means that a worker crashed and #{@queue.length} tests were missed."
|
125
|
-
end
|
46
|
+
@queue_server.shutdown
|
47
|
+
@worker_pool.each { |pid| Process.waitpid pid }
|
126
48
|
end
|
127
|
-
|
128
|
-
private
|
129
|
-
def add_setup_exception(result, setup_exception)
|
130
|
-
result.failures.prepend Minitest::UnexpectedError.new(setup_exception)
|
131
|
-
end
|
132
49
|
end
|
133
50
|
end
|
134
51
|
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,
|
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,
|
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
|
-
#
|
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
|
|