activesupport 5.2.7 → 6.0.0.beta1
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 +182 -566
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/active_support/backtrace_cleaner.rb +23 -0
- data/lib/active_support/cache/file_store.rb +19 -12
- data/lib/active_support/cache/mem_cache_store.rb +16 -2
- data/lib/active_support/cache/memory_store.rb +5 -0
- data/lib/active_support/cache/null_store.rb +5 -0
- data/lib/active_support/cache/redis_cache_store.rb +39 -20
- data/lib/active_support/cache.rb +40 -18
- data/lib/active_support/callbacks.rb +16 -5
- data/lib/active_support/configurable.rb +4 -8
- data/lib/active_support/core_ext/array/extract.rb +21 -0
- data/lib/active_support/core_ext/array/prepend_and_append.rb +2 -6
- data/lib/active_support/core_ext/array.rb +1 -1
- data/lib/active_support/core_ext/class/attribute.rb +1 -1
- data/lib/active_support/core_ext/class/subclasses.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +6 -5
- data/lib/active_support/core_ext/date_and_time/calculations.rb +24 -17
- data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
- data/lib/active_support/core_ext/enumerable.rb +71 -67
- data/lib/active_support/core_ext/hash/compact.rb +2 -26
- data/lib/active_support/core_ext/hash/keys.rb +0 -29
- data/lib/active_support/core_ext/hash/slice.rb +3 -25
- data/lib/active_support/core_ext/hash/transform_values.rb +2 -29
- data/lib/active_support/core_ext/hash.rb +0 -2
- data/lib/active_support/core_ext/integer/multiple.rb +1 -1
- data/lib/active_support/core_ext/load_error.rb +1 -1
- data/lib/active_support/core_ext/module/attribute_accessors.rb +2 -5
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +8 -14
- data/lib/active_support/core_ext/module/delegation.rb +27 -7
- data/lib/active_support/core_ext/module/introspection.rb +37 -13
- data/lib/active_support/core_ext/module/reachable.rb +1 -6
- 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/numeric/conversions.rb +124 -128
- data/lib/active_support/core_ext/numeric/inquiry.rb +2 -25
- 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/duplicable.rb +5 -2
- data/lib/active_support/core_ext/object/json.rb +1 -0
- data/lib/active_support/core_ext/object/try.rb +15 -7
- data/lib/active_support/core_ext/object/with_options.rb +1 -1
- data/lib/active_support/core_ext/range/compare_range.rb +1 -1
- data/lib/active_support/core_ext/range/conversions.rb +31 -29
- data/lib/active_support/core_ext/range/include_range.rb +6 -0
- data/lib/active_support/core_ext/regexp.rb +0 -4
- data/lib/active_support/core_ext/securerandom.rb +23 -3
- data/lib/active_support/core_ext/string/access.rb +8 -0
- data/lib/active_support/core_ext/string/filters.rb +41 -0
- data/lib/active_support/core_ext/string/multibyte.rb +4 -3
- data/lib/active_support/core_ext/string/output_safety.rb +16 -5
- data/lib/active_support/core_ext/string/strip.rb +3 -1
- data/lib/active_support/core_ext/uri.rb +1 -0
- data/lib/active_support/current_attributes.rb +2 -0
- data/lib/active_support/dependencies.rb +28 -11
- data/lib/active_support/deprecation/behaviors.rb +1 -1
- data/lib/active_support/deprecation/method_wrappers.rb +4 -5
- data/lib/active_support/deprecation/proxy_wrappers.rb +0 -2
- data/lib/active_support/deprecation.rb +1 -1
- data/lib/active_support/descendants_tracker.rb +6 -5
- data/lib/active_support/duration/iso8601_parser.rb +2 -3
- data/lib/active_support/duration/iso8601_serializer.rb +3 -4
- data/lib/active_support/duration.rb +12 -14
- data/lib/active_support/encrypted_configuration.rb +0 -4
- data/lib/active_support/evented_file_update_checker.rb +25 -7
- data/lib/active_support/execution_wrapper.rb +14 -16
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/hash_with_indifferent_access.rb +16 -28
- data/lib/active_support/i18n.rb +1 -0
- data/lib/active_support/i18n_railtie.rb +8 -1
- data/lib/active_support/inflector/inflections.rb +1 -4
- data/lib/active_support/inflector/methods.rb +15 -27
- data/lib/active_support/inflector/transliterate.rb +6 -6
- data/lib/active_support/json/decoding.rb +23 -23
- data/lib/active_support/json/encoding.rb +6 -2
- data/lib/active_support/key_generator.rb +0 -32
- data/lib/active_support/lazy_load_hooks.rb +5 -1
- data/lib/active_support/locale/en.rb +31 -0
- data/lib/active_support/log_subscriber.rb +31 -8
- data/lib/active_support/logger.rb +0 -15
- data/lib/active_support/logger_silence.rb +28 -12
- data/lib/active_support/logger_thread_safe_level.rb +27 -6
- data/lib/active_support/message_encryptor.rb +2 -4
- data/lib/active_support/message_verifier.rb +2 -2
- data/lib/active_support/multibyte/chars.rb +29 -48
- data/lib/active_support/multibyte/unicode.rb +44 -281
- data/lib/active_support/notifications/fanout.rb +42 -4
- data/lib/active_support/notifications/instrumenter.rb +73 -2
- data/lib/active_support/notifications.rb +32 -4
- data/lib/active_support/number_helper/number_to_currency_converter.rb +2 -2
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -1
- data/lib/active_support/number_helper/number_to_human_converter.rb +3 -1
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -1
- 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 -0
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +5 -3
- data/lib/active_support/number_helper.rb +7 -0
- data/lib/active_support/ordered_options.rb +1 -1
- data/lib/active_support/parameter_filter.rb +124 -0
- data/lib/active_support/rails.rb +0 -6
- data/lib/active_support/reloader.rb +5 -6
- data/lib/active_support/subscriber.rb +16 -26
- data/lib/active_support/tagged_logging.rb +13 -4
- data/lib/active_support/test_case.rb +91 -0
- data/lib/active_support/testing/assertions.rb +15 -1
- 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.rb +109 -0
- data/lib/active_support/testing/stream.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +7 -7
- data/lib/active_support/time_with_zone.rb +15 -5
- data/lib/active_support/values/time_zone.rb +12 -7
- data/lib/active_support/xml_mini/jdom.rb +2 -2
- 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 +2 -2
- data/lib/active_support/xml_mini.rb +2 -9
- data/lib/active_support.rb +1 -1
- metadata +12 -10
- data/lib/active_support/core_ext/digest.rb +0 -3
- data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -11,6 +11,8 @@ require "active_support/testing/isolation"
|
|
11
11
|
require "active_support/testing/constant_lookup"
|
12
12
|
require "active_support/testing/time_helpers"
|
13
13
|
require "active_support/testing/file_fixtures"
|
14
|
+
require "active_support/testing/parallelization"
|
15
|
+
require "concurrent/utility/processor_counter"
|
14
16
|
|
15
17
|
module ActiveSupport
|
16
18
|
class TestCase < ::Minitest::Test
|
@@ -39,6 +41,95 @@ module ActiveSupport
|
|
39
41
|
def test_order
|
40
42
|
ActiveSupport.test_order ||= :random
|
41
43
|
end
|
44
|
+
|
45
|
+
# Parallelizes the test suite.
|
46
|
+
#
|
47
|
+
# Takes a +workers+ argument that controls how many times the process
|
48
|
+
# is forked. For each process a new database will be created suffixed
|
49
|
+
# with the worker number.
|
50
|
+
#
|
51
|
+
# test-database-0
|
52
|
+
# test-database-1
|
53
|
+
#
|
54
|
+
# If <tt>ENV["PARALLEL_WORKERS"]</tt> is set the workers argument will be ignored
|
55
|
+
# and the environment variable will be used instead. This is useful for CI
|
56
|
+
# environments, or other environments where you may need more workers than
|
57
|
+
# you do for local testing.
|
58
|
+
#
|
59
|
+
# If the number of workers is set to +1+ or fewer, the tests will not be
|
60
|
+
# parallelized.
|
61
|
+
#
|
62
|
+
# If +workers+ is set to +:number_of_processors+, the number of workers will be
|
63
|
+
# set to the actual core count on the machine you are on.
|
64
|
+
#
|
65
|
+
# The default parallelization method is to fork processes. If you'd like to
|
66
|
+
# use threads instead you can pass <tt>with: :threads</tt> to the +parallelize+
|
67
|
+
# method. Note the threaded parallelization does not create multiple
|
68
|
+
# database and will not work with system tests at this time.
|
69
|
+
#
|
70
|
+
# parallelize(workers: :number_of_processors, with: :threads)
|
71
|
+
#
|
72
|
+
# The threaded parallelization uses minitest's parallel executor directly.
|
73
|
+
# The processes parallelization uses a Ruby DRb server.
|
74
|
+
def parallelize(workers: :number_of_processors, with: :processes)
|
75
|
+
workers = Concurrent.physical_processor_count if workers == :number_of_processors
|
76
|
+
workers = ENV["PARALLEL_WORKERS"].to_i if ENV["PARALLEL_WORKERS"]
|
77
|
+
|
78
|
+
return if workers <= 1
|
79
|
+
|
80
|
+
executor = case with
|
81
|
+
when :processes
|
82
|
+
Testing::Parallelization.new(workers)
|
83
|
+
when :threads
|
84
|
+
Minitest::Parallel::Executor.new(workers)
|
85
|
+
else
|
86
|
+
raise ArgumentError, "#{with} is not a supported parallelization executor."
|
87
|
+
end
|
88
|
+
|
89
|
+
self.lock_threads = false if defined?(self.lock_threads) && with == :threads
|
90
|
+
|
91
|
+
Minitest.parallel_executor = executor
|
92
|
+
|
93
|
+
parallelize_me!
|
94
|
+
end
|
95
|
+
|
96
|
+
# Set up hook for parallel testing. This can be used if you have multiple
|
97
|
+
# databases or any behavior that needs to be run after the process is forked
|
98
|
+
# but before the tests run.
|
99
|
+
#
|
100
|
+
# Note: this feature is not available with the threaded parallelization.
|
101
|
+
#
|
102
|
+
# In your +test_helper.rb+ add the following:
|
103
|
+
#
|
104
|
+
# class ActiveSupport::TestCase
|
105
|
+
# parallelize_setup do
|
106
|
+
# # create databases
|
107
|
+
# end
|
108
|
+
# end
|
109
|
+
def parallelize_setup(&block)
|
110
|
+
ActiveSupport::Testing::Parallelization.after_fork_hook do |worker|
|
111
|
+
yield worker
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Clean up hook for parallel testing. This can be used to drop databases
|
116
|
+
# if your app uses multiple write/read databases or other clean up before
|
117
|
+
# the tests finish. This runs before the forked process is closed.
|
118
|
+
#
|
119
|
+
# Note: this feature is not available with the threaded parallelization.
|
120
|
+
#
|
121
|
+
# In your +test_helper.rb+ add the following:
|
122
|
+
#
|
123
|
+
# class ActiveSupport::TestCase
|
124
|
+
# parallelize_teardown do
|
125
|
+
# # drop databases
|
126
|
+
# end
|
127
|
+
# end
|
128
|
+
def parallelize_teardown(&block)
|
129
|
+
ActiveSupport::Testing::Parallelization.run_cleanup_hook do |worker|
|
130
|
+
yield worker
|
131
|
+
end
|
132
|
+
end
|
42
133
|
end
|
43
134
|
|
44
135
|
alias_method :method_name, :name
|
@@ -113,11 +113,23 @@ module ActiveSupport
|
|
113
113
|
# post :create, params: { article: invalid_attributes }
|
114
114
|
# end
|
115
115
|
#
|
116
|
+
# A lambda can be passed in and evaluated.
|
117
|
+
#
|
118
|
+
# assert_no_difference -> { Article.count } do
|
119
|
+
# post :create, params: { article: invalid_attributes }
|
120
|
+
# end
|
121
|
+
#
|
116
122
|
# An error message can be specified.
|
117
123
|
#
|
118
124
|
# assert_no_difference 'Article.count', 'An Article should not be created' do
|
119
125
|
# post :create, params: { article: invalid_attributes }
|
120
126
|
# end
|
127
|
+
#
|
128
|
+
# An array of expressions can also be passed in and evaluated.
|
129
|
+
#
|
130
|
+
# assert_no_difference [ 'Article.count', -> { Post.count } ] do
|
131
|
+
# post :create, params: { article: invalid_attributes }
|
132
|
+
# end
|
121
133
|
def assert_no_difference(expression, message = nil, &block)
|
122
134
|
assert_difference expression, 0, message, &block
|
123
135
|
end
|
@@ -176,7 +188,9 @@ module ActiveSupport
|
|
176
188
|
assert before != after, error
|
177
189
|
|
178
190
|
unless to == UNTRACKED
|
179
|
-
error = "#{expression.inspect} didn't change to
|
191
|
+
error = "#{expression.inspect} didn't change to as expected\n"
|
192
|
+
error = "#{error}Expected: #{to.inspect}\n"
|
193
|
+
error = "#{error} Actual: #{after.inspect}"
|
180
194
|
error = "#{message}.\n#{error}" if message
|
181
195
|
assert to === after, error
|
182
196
|
end
|
@@ -56,7 +56,7 @@ module ActiveSupport
|
|
56
56
|
write.close
|
57
57
|
result = read.read
|
58
58
|
Process.wait2(pid)
|
59
|
-
result.
|
59
|
+
result.unpack1("m")
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
@@ -98,7 +98,7 @@ module ActiveSupport
|
|
98
98
|
nil
|
99
99
|
end
|
100
100
|
|
101
|
-
return tmpfile.read.
|
101
|
+
return tmpfile.read.unpack1("m")
|
102
102
|
end
|
103
103
|
end
|
104
104
|
end
|
@@ -17,7 +17,7 @@ module ActiveSupport
|
|
17
17
|
assert_equal times, times_called, error
|
18
18
|
end
|
19
19
|
|
20
|
-
def assert_called_with(object, method_name, args
|
20
|
+
def assert_called_with(object, method_name, args, returns: nil)
|
21
21
|
mock = Minitest::Mock.new
|
22
22
|
|
23
23
|
if args.all? { |arg| arg.is_a?(Array) }
|
@@ -35,6 +35,33 @@ module ActiveSupport
|
|
35
35
|
assert_called(object, method_name, message, times: 0, &block)
|
36
36
|
end
|
37
37
|
|
38
|
+
def assert_called_on_instance_of(klass, method_name, message = nil, times: 1, returns: nil)
|
39
|
+
times_called = 0
|
40
|
+
klass.define_method("stubbed_#{method_name}") do |*|
|
41
|
+
times_called += 1
|
42
|
+
|
43
|
+
returns
|
44
|
+
end
|
45
|
+
|
46
|
+
klass.alias_method "original_#{method_name}", method_name
|
47
|
+
klass.alias_method method_name, "stubbed_#{method_name}"
|
48
|
+
|
49
|
+
yield
|
50
|
+
|
51
|
+
error = "Expected #{method_name} to be called #{times} times, but was called #{times_called} times"
|
52
|
+
error = "#{message}.\n#{error}" if message
|
53
|
+
|
54
|
+
assert_equal times, times_called, error
|
55
|
+
ensure
|
56
|
+
klass.alias_method method_name, "original_#{method_name}"
|
57
|
+
klass.undef_method "original_#{method_name}"
|
58
|
+
klass.undef_method "stubbed_#{method_name}"
|
59
|
+
end
|
60
|
+
|
61
|
+
def assert_not_called_on_instance_of(klass, method_name, message = nil, &block)
|
62
|
+
assert_called_on_instance_of(klass, method_name, message, times: 0, &block)
|
63
|
+
end
|
64
|
+
|
38
65
|
def stub_any_instance(klass, instance: klass.new)
|
39
66
|
klass.stub(:new, instance) { yield instance }
|
40
67
|
end
|
@@ -0,0 +1,109 @@
|
|
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
|
+
|
7
|
+
module ActiveSupport
|
8
|
+
module Testing
|
9
|
+
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 pop; @queue.pop; end
|
31
|
+
end
|
32
|
+
|
33
|
+
@@after_fork_hooks = []
|
34
|
+
|
35
|
+
def self.after_fork_hook(&blk)
|
36
|
+
@@after_fork_hooks << blk
|
37
|
+
end
|
38
|
+
|
39
|
+
cattr_reader :after_fork_hooks
|
40
|
+
|
41
|
+
@@run_cleanup_hooks = []
|
42
|
+
|
43
|
+
def self.run_cleanup_hook(&blk)
|
44
|
+
@@run_cleanup_hooks << blk
|
45
|
+
end
|
46
|
+
|
47
|
+
cattr_reader :run_cleanup_hooks
|
48
|
+
|
49
|
+
def initialize(queue_size)
|
50
|
+
@queue_size = queue_size
|
51
|
+
@queue = Server.new
|
52
|
+
@pool = []
|
53
|
+
|
54
|
+
@url = DRb.start_service("drbunix:", @queue).uri
|
55
|
+
end
|
56
|
+
|
57
|
+
def after_fork(worker)
|
58
|
+
self.class.after_fork_hooks.each do |cb|
|
59
|
+
cb.call(worker)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def run_cleanup(worker)
|
64
|
+
self.class.run_cleanup_hooks.each do |cb|
|
65
|
+
cb.call(worker)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def start
|
70
|
+
@pool = @queue_size.times.map do |worker|
|
71
|
+
fork do
|
72
|
+
DRb.stop_service
|
73
|
+
|
74
|
+
after_fork(worker)
|
75
|
+
|
76
|
+
queue = DRbObject.new_with_uri(@url)
|
77
|
+
|
78
|
+
while job = queue.pop
|
79
|
+
klass = job[0]
|
80
|
+
method = job[1]
|
81
|
+
reporter = job[2]
|
82
|
+
result = Minitest.run_one_method(klass, method)
|
83
|
+
|
84
|
+
begin
|
85
|
+
queue.record(reporter, result)
|
86
|
+
rescue DRb::DRbConnError
|
87
|
+
result.failures.each do |failure|
|
88
|
+
failure.exception = DRb::DRbRemoteError.new(failure.exception)
|
89
|
+
end
|
90
|
+
queue.record(reporter, result)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
ensure
|
94
|
+
run_cleanup(worker)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def <<(work)
|
100
|
+
@queue << work
|
101
|
+
end
|
102
|
+
|
103
|
+
def shutdown
|
104
|
+
@queue_size.times { @queue << nil }
|
105
|
+
@pool.each { |pid| Process.waitpid pid }
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -1,7 +1,6 @@
|
|
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
|
|
@@ -23,7 +22,7 @@ module ActiveSupport
|
|
23
22
|
|
24
23
|
@stubs[object.object_id][method_name] = Stub.new(object, method_name, new_name)
|
25
24
|
|
26
|
-
object.singleton_class.
|
25
|
+
object.singleton_class.alias_method new_name, method_name
|
27
26
|
object.define_singleton_method(method_name, &block)
|
28
27
|
end
|
29
28
|
|
@@ -44,9 +43,9 @@ module ActiveSupport
|
|
44
43
|
|
45
44
|
def unstub_object(stub)
|
46
45
|
singleton_class = stub.object.singleton_class
|
47
|
-
singleton_class.
|
48
|
-
singleton_class.
|
49
|
-
singleton_class.
|
46
|
+
singleton_class.silence_redefinition_of_method stub.method_name
|
47
|
+
singleton_class.alias_method stub.method_name, stub.original_method
|
48
|
+
singleton_class.undef_method stub.original_method
|
50
49
|
end
|
51
50
|
end
|
52
51
|
|
@@ -112,7 +111,7 @@ module ActiveSupport
|
|
112
111
|
# Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
|
113
112
|
def travel_to(date_or_time)
|
114
113
|
if block_given? && simple_stubs.stubbing(Time, :now)
|
115
|
-
travel_to_nested_block_call =
|
114
|
+
travel_to_nested_block_call = <<~MSG
|
116
115
|
|
117
116
|
Calling `travel_to` with a block, when we have previously already made a call to `travel_to`, can lead to confusing time stubbing.
|
118
117
|
|
@@ -159,7 +158,7 @@ module ActiveSupport
|
|
159
158
|
end
|
160
159
|
|
161
160
|
# Returns the current time back to its original state, by removing the stubs added by
|
162
|
-
# +travel+ and +
|
161
|
+
# +travel+, +travel_to+, and +freeze_time+.
|
163
162
|
#
|
164
163
|
# Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
|
165
164
|
# travel_to Time.zone.local(2004, 11, 24, 01, 04, 44)
|
@@ -169,6 +168,7 @@ module ActiveSupport
|
|
169
168
|
def travel_back
|
170
169
|
simple_stubs.unstub_all!
|
171
170
|
end
|
171
|
+
alias_method :unfreeze_time, :travel_back
|
172
172
|
|
173
173
|
# Calls +travel_to+ with +Time.now+.
|
174
174
|
#
|
@@ -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
|
@@ -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.
|
@@ -284,8 +286,10 @@ module ActiveSupport
|
|
284
286
|
alias_method :since, :+
|
285
287
|
alias_method :in, :+
|
286
288
|
|
287
|
-
#
|
288
|
-
# the
|
289
|
+
# 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.
|
289
293
|
#
|
290
294
|
# Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
|
291
295
|
# now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28 EST -05:00
|
@@ -300,6 +304,12 @@ module ActiveSupport
|
|
300
304
|
#
|
301
305
|
# now - 24.hours # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
|
302
306
|
# now - 1.day # => Sun, 02 Nov 2014 00:26:28 EDT -04:00
|
307
|
+
#
|
308
|
+
# If both the TimeWithZone object and the other value act like Time, a Float
|
309
|
+
# will be returned.
|
310
|
+
#
|
311
|
+
# Time.zone.now - 1.day.ago # => 86399.999967
|
312
|
+
#
|
303
313
|
def -(other)
|
304
314
|
if other.acts_like?(:time)
|
305
315
|
to_time - other.to_time
|
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
require "tzinfo"
|
4
4
|
require "concurrent/map"
|
5
|
-
require "active_support/core_ext/object/blank"
|
6
5
|
|
7
6
|
module ActiveSupport
|
8
7
|
# The TimeZone class serves as a wrapper around TZInfo::Timezone instances.
|
@@ -183,8 +182,9 @@ module ActiveSupport
|
|
183
182
|
"Samoa" => "Pacific/Apia"
|
184
183
|
}
|
185
184
|
|
186
|
-
UTC_OFFSET_WITH_COLON = "%s%02d:%02d"
|
187
|
-
UTC_OFFSET_WITHOUT_COLON = UTC_OFFSET_WITH_COLON.tr(":", "")
|
185
|
+
UTC_OFFSET_WITH_COLON = "%s%02d:%02d" # :nodoc:
|
186
|
+
UTC_OFFSET_WITHOUT_COLON = UTC_OFFSET_WITH_COLON.tr(":", "") # :nodoc:
|
187
|
+
private_constant :UTC_OFFSET_WITH_COLON, :UTC_OFFSET_WITHOUT_COLON
|
188
188
|
|
189
189
|
@lazy_zones_map = Concurrent::Map.new
|
190
190
|
@country_zones = Concurrent::Map.new
|
@@ -266,7 +266,7 @@ module ActiveSupport
|
|
266
266
|
private
|
267
267
|
def load_country_zones(code)
|
268
268
|
country = TZInfo::Country.get(code)
|
269
|
-
country.zone_identifiers.
|
269
|
+
country.zone_identifiers.flat_map do |tz_id|
|
270
270
|
if MAPPING.value?(tz_id)
|
271
271
|
MAPPING.inject([]) do |memo, (key, value)|
|
272
272
|
memo << self[key] if value == tz_id
|
@@ -275,7 +275,7 @@ module ActiveSupport
|
|
275
275
|
else
|
276
276
|
create(tz_id, nil, TZInfo::Timezone.new(tz_id))
|
277
277
|
end
|
278
|
-
end.
|
278
|
+
end.sort!
|
279
279
|
end
|
280
280
|
|
281
281
|
def zones_map
|
@@ -355,8 +355,13 @@ module ActiveSupport
|
|
355
355
|
# Time.zone = 'Hawaii' # => "Hawaii"
|
356
356
|
# Time.utc(2000).to_f # => 946684800.0
|
357
357
|
# Time.zone.at(946684800.0) # => Fri, 31 Dec 1999 14:00:00 HST -10:00
|
358
|
-
|
359
|
-
|
358
|
+
#
|
359
|
+
# A second argument can be supplied to specify sub-second precision.
|
360
|
+
#
|
361
|
+
# Time.zone = 'Hawaii' # => "Hawaii"
|
362
|
+
# Time.at(946684800, 123456.789).nsec # => 123456789
|
363
|
+
def at(*args)
|
364
|
+
Time.at(*args).utc.in_time_zone(self)
|
360
365
|
end
|
361
366
|
|
362
367
|
# Method for creating new ActiveSupport::TimeWithZone instance in time zone
|
@@ -18,7 +18,7 @@ module ActiveSupport
|
|
18
18
|
module XmlMini_JDOM #:nodoc:
|
19
19
|
extend self
|
20
20
|
|
21
|
-
CONTENT_KEY = "__content__"
|
21
|
+
CONTENT_KEY = "__content__"
|
22
22
|
|
23
23
|
NODE_TYPE_NAMES = %w{ATTRIBUTE_NODE CDATA_SECTION_NODE COMMENT_NODE DOCUMENT_FRAGMENT_NODE
|
24
24
|
DOCUMENT_NODE DOCUMENT_TYPE_NODE ELEMENT_NODE ENTITY_NODE ENTITY_REFERENCE_NODE NOTATION_NODE
|
@@ -169,7 +169,7 @@ module ActiveSupport
|
|
169
169
|
# element::
|
170
170
|
# XML element to be checked.
|
171
171
|
def empty_content?(element)
|
172
|
-
text = ""
|
172
|
+
text = +""
|
173
173
|
child_nodes = element.child_nodes
|
174
174
|
(0...child_nodes.length).each do |i|
|
175
175
|
item = child_nodes.item(i)
|
@@ -34,7 +34,7 @@ module LibXML #:nodoc:
|
|
34
34
|
end
|
35
35
|
|
36
36
|
module Node #:nodoc:
|
37
|
-
CONTENT_ROOT = "__content__"
|
37
|
+
CONTENT_ROOT = "__content__"
|
38
38
|
|
39
39
|
# Convert XML document to hash.
|
40
40
|
#
|
@@ -55,7 +55,7 @@ module LibXML #:nodoc:
|
|
55
55
|
if c.element?
|
56
56
|
c.to_hash(node_hash)
|
57
57
|
elsif c.text? || c.cdata?
|
58
|
-
node_hash[CONTENT_ROOT] ||= ""
|
58
|
+
node_hash[CONTENT_ROOT] ||= +""
|
59
59
|
node_hash[CONTENT_ROOT] << c.content
|
60
60
|
end
|
61
61
|
end
|
@@ -13,8 +13,8 @@ module ActiveSupport
|
|
13
13
|
class HashBuilder
|
14
14
|
include LibXML::XML::SaxParser::Callbacks
|
15
15
|
|
16
|
-
CONTENT_KEY = "__content__"
|
17
|
-
HASH_SIZE_KEY = "__hash_size__"
|
16
|
+
CONTENT_KEY = "__content__"
|
17
|
+
HASH_SIZE_KEY = "__hash_size__"
|
18
18
|
|
19
19
|
attr_reader :hash
|
20
20
|
|
@@ -23,7 +23,7 @@ module ActiveSupport
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def on_start_document
|
26
|
-
@hash = { CONTENT_KEY => ""
|
26
|
+
@hash = { CONTENT_KEY => +"" }
|
27
27
|
@hash_stack = [@hash]
|
28
28
|
end
|
29
29
|
|
@@ -33,7 +33,7 @@ module ActiveSupport
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def on_start_element(name, attrs = {})
|
36
|
-
new_hash = { CONTENT_KEY => ""
|
36
|
+
new_hash = { CONTENT_KEY => +"" }.merge!(attrs)
|
37
37
|
new_hash[HASH_SIZE_KEY] = new_hash.size + 1
|
38
38
|
|
39
39
|
case current_hash[name]
|
@@ -38,7 +38,7 @@ module ActiveSupport
|
|
38
38
|
end
|
39
39
|
|
40
40
|
module Node #:nodoc:
|
41
|
-
CONTENT_ROOT = "__content__"
|
41
|
+
CONTENT_ROOT = "__content__"
|
42
42
|
|
43
43
|
# Convert XML document to hash.
|
44
44
|
#
|
@@ -59,7 +59,7 @@ module ActiveSupport
|
|
59
59
|
if c.element?
|
60
60
|
c.to_hash(node_hash)
|
61
61
|
elsif c.text? || c.cdata?
|
62
|
-
node_hash[CONTENT_ROOT] ||= ""
|
62
|
+
node_hash[CONTENT_ROOT] ||= +""
|
63
63
|
node_hash[CONTENT_ROOT] << c.content
|
64
64
|
end
|
65
65
|
end
|
@@ -16,8 +16,8 @@ module ActiveSupport
|
|
16
16
|
# Class that will build the hash while the XML document
|
17
17
|
# is being parsed using SAX events.
|
18
18
|
class HashBuilder < Nokogiri::XML::SAX::Document
|
19
|
-
CONTENT_KEY = "__content__"
|
20
|
-
HASH_SIZE_KEY = "__hash_size__"
|
19
|
+
CONTENT_KEY = "__content__"
|
20
|
+
HASH_SIZE_KEY = "__hash_size__"
|
21
21
|
|
22
22
|
attr_reader :hash
|
23
23
|
|
@@ -39,7 +39,7 @@ module ActiveSupport
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def start_element(name, attrs = [])
|
42
|
-
new_hash = { CONTENT_KEY => ""
|
42
|
+
new_hash = { CONTENT_KEY => +"" }.merge!(Hash[attrs])
|
43
43
|
new_hash[HASH_SIZE_KEY] = new_hash.size + 1
|
44
44
|
|
45
45
|
case current_hash[name]
|
@@ -8,7 +8,7 @@ module ActiveSupport
|
|
8
8
|
module XmlMini_REXML #:nodoc:
|
9
9
|
extend self
|
10
10
|
|
11
|
-
CONTENT_KEY = "__content__"
|
11
|
+
CONTENT_KEY = "__content__"
|
12
12
|
|
13
13
|
# Parse an XML Document string or IO into a simple hash.
|
14
14
|
#
|
@@ -76,7 +76,7 @@ module ActiveSupport
|
|
76
76
|
hash
|
77
77
|
else
|
78
78
|
# must use value to prevent double-escaping
|
79
|
-
texts = ""
|
79
|
+
texts = +""
|
80
80
|
element.texts.each { |t| texts << t.value }
|
81
81
|
merge!(hash, CONTENT_KEY, texts)
|
82
82
|
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
require "time"
|
4
4
|
require "base64"
|
5
5
|
require "bigdecimal"
|
6
|
+
require "bigdecimal/util"
|
6
7
|
require "active_support/core_ext/module/delegation"
|
7
8
|
require "active_support/core_ext/string/inflections"
|
8
9
|
require "active_support/core_ext/date_time/calculations"
|
@@ -48,10 +49,6 @@ module ActiveSupport
|
|
48
49
|
"Array" => "array",
|
49
50
|
"Hash" => "hash"
|
50
51
|
}
|
51
|
-
|
52
|
-
# No need to map these on Ruby 2.4+
|
53
|
-
TYPE_NAMES["Fixnum"] = "integer" unless 0.class == Integer
|
54
|
-
TYPE_NAMES["Bignum"] = "integer" unless 0.class == Integer
|
55
52
|
end
|
56
53
|
|
57
54
|
FORMATTING = {
|
@@ -72,11 +69,7 @@ module ActiveSupport
|
|
72
69
|
"float" => Proc.new { |float| float.to_f },
|
73
70
|
"decimal" => Proc.new do |number|
|
74
71
|
if String === number
|
75
|
-
|
76
|
-
BigDecimal(number)
|
77
|
-
rescue ArgumentError
|
78
|
-
BigDecimal(number.to_f.to_s)
|
79
|
-
end
|
72
|
+
number.to_d
|
80
73
|
else
|
81
74
|
BigDecimal(number)
|
82
75
|
end
|
data/lib/active_support.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#--
|
4
|
-
# Copyright (c) 2005-
|
4
|
+
# Copyright (c) 2005-2019 David Heinemeier Hansson
|
5
5
|
#
|
6
6
|
# Permission is hereby granted, free of charge, to any person obtaining
|
7
7
|
# a copy of this software and associated documentation files (the
|