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
@@ -6,6 +6,7 @@ require "active_support/time_with_zone"
|
|
6
6
|
require "active_support/core_ext/time/zones"
|
7
7
|
require "active_support/core_ext/date_and_time/calculations"
|
8
8
|
require "active_support/core_ext/date/calculations"
|
9
|
+
require "active_support/core_ext/module/remove_method"
|
9
10
|
|
10
11
|
class Time
|
11
12
|
include DateAndTime::Calculations
|
@@ -47,7 +48,9 @@ class Time
|
|
47
48
|
# Time.at can be called with a time or numerical value
|
48
49
|
time_or_number = args.first
|
49
50
|
|
50
|
-
if time_or_number.is_a?(ActiveSupport::TimeWithZone)
|
51
|
+
if time_or_number.is_a?(ActiveSupport::TimeWithZone)
|
52
|
+
at_without_coercion(time_or_number.to_r).getlocal
|
53
|
+
elsif time_or_number.is_a?(DateTime)
|
51
54
|
at_without_coercion(time_or_number.to_f).getlocal
|
52
55
|
else
|
53
56
|
at_without_coercion(time_or_number)
|
@@ -105,6 +108,21 @@ class Time
|
|
105
108
|
subsec
|
106
109
|
end
|
107
110
|
|
111
|
+
unless Time.method_defined?(:floor)
|
112
|
+
def floor(precision = 0)
|
113
|
+
change(nsec: 0) + subsec.floor(precision)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Restricted Ruby version due to a bug in `Time#ceil`
|
118
|
+
# See https://bugs.ruby-lang.org/issues/17025 for more details
|
119
|
+
if RUBY_VERSION <= "2.8"
|
120
|
+
remove_possible_method :ceil
|
121
|
+
def ceil(precision = 0)
|
122
|
+
change(nsec: 0) + subsec.ceil(precision)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
108
126
|
# Returns a new Time where one or more of the elements have been changed according
|
109
127
|
# to the +options+ parameter. The time options (<tt>:hour</tt>, <tt>:min</tt>,
|
110
128
|
# <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>) reset cascadingly, so if only
|
@@ -170,8 +188,7 @@ class Time
|
|
170
188
|
options[:hours] = options.fetch(:hours, 0) + 24 * partial_days
|
171
189
|
end
|
172
190
|
|
173
|
-
d = to_date.advance(options)
|
174
|
-
d = d.gregorian if d.julian?
|
191
|
+
d = to_date.gregorian.advance(options)
|
175
192
|
time_advanced_by_date = change(year: d.year, month: d.month, day: d.day)
|
176
193
|
seconds_to_advance = \
|
177
194
|
options.fetch(:seconds, 0) +
|
@@ -312,4 +329,34 @@ class Time
|
|
312
329
|
end
|
313
330
|
alias_method :eql_without_coercion, :eql?
|
314
331
|
alias_method :eql?, :eql_with_coercion
|
332
|
+
|
333
|
+
# Returns a new time the specified number of days ago.
|
334
|
+
def prev_day(days = 1)
|
335
|
+
advance(days: -days)
|
336
|
+
end
|
337
|
+
|
338
|
+
# Returns a new time the specified number of days in the future.
|
339
|
+
def next_day(days = 1)
|
340
|
+
advance(days: days)
|
341
|
+
end
|
342
|
+
|
343
|
+
# Returns a new time the specified number of months ago.
|
344
|
+
def prev_month(months = 1)
|
345
|
+
advance(months: -months)
|
346
|
+
end
|
347
|
+
|
348
|
+
# Returns a new time the specified number of months in the future.
|
349
|
+
def next_month(months = 1)
|
350
|
+
advance(months: months)
|
351
|
+
end
|
352
|
+
|
353
|
+
# Returns a new time the specified number of years ago.
|
354
|
+
def prev_year(years = 1)
|
355
|
+
advance(years: -years)
|
356
|
+
end
|
357
|
+
|
358
|
+
# Returns a new time the specified number of years in the future.
|
359
|
+
def next_year(years = 1)
|
360
|
+
advance(years: years)
|
361
|
+
end
|
315
362
|
end
|
@@ -1,10 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "uri"
|
4
|
-
str = "\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E" # Ni-ho-nn-go in UTF-8, means Japanese.
|
5
|
-
parser = URI::Parser.new
|
6
4
|
|
7
|
-
|
5
|
+
if RUBY_VERSION < "2.6.0"
|
8
6
|
require "active_support/core_ext/module/redefine_method"
|
9
7
|
URI::Parser.class_eval do
|
10
8
|
silence_redefinition_of_method :unescape
|
@@ -13,7 +11,7 @@ unless str == parser.unescape(parser.escape(str))
|
|
13
11
|
# YK: My initial experiments say yes, but let's be sure please
|
14
12
|
enc = str.encoding
|
15
13
|
enc = Encoding::UTF_8 if enc == Encoding::US_ASCII
|
16
|
-
str.gsub(escaped) { |match| [match[1, 2].hex].pack("C") }.force_encoding(enc)
|
14
|
+
str.dup.force_encoding(Encoding::ASCII_8BIT).gsub(escaped) { |match| [match[1, 2].hex].pack("C") }.force_encoding(enc)
|
17
15
|
end
|
18
16
|
end
|
19
17
|
end
|
@@ -21,7 +19,11 @@ end
|
|
21
19
|
module URI
|
22
20
|
class << self
|
23
21
|
def parser
|
24
|
-
|
22
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
23
|
+
URI.parser is deprecated and will be removed in Rails 6.2.
|
24
|
+
Use `URI::DEFAULT_PARSER` instead.
|
25
|
+
MSG
|
26
|
+
URI::DEFAULT_PARSER
|
25
27
|
end
|
26
28
|
end
|
27
29
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveSupport::CurrentAttributes::TestHelper # :nodoc:
|
4
|
+
def before_setup
|
5
|
+
ActiveSupport::CurrentAttributes.reset_all
|
6
|
+
super
|
7
|
+
end
|
8
|
+
|
9
|
+
def after_teardown
|
10
|
+
super
|
11
|
+
ActiveSupport::CurrentAttributes.reset_all
|
12
|
+
end
|
13
|
+
end
|
@@ -1,5 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/callbacks"
|
4
|
+
require "active_support/core_ext/enumerable"
|
5
|
+
|
3
6
|
module ActiveSupport
|
4
7
|
# Abstract super class that provides a thread-isolated attributes singleton, which resets automatically
|
5
8
|
# before and after each request. This allows you to keep all the per-request attributes easily
|
@@ -89,7 +92,7 @@ module ActiveSupport
|
|
89
92
|
class << self
|
90
93
|
# Returns singleton instance for this class in this thread. If none exists, one is created.
|
91
94
|
def instance
|
92
|
-
current_instances[
|
95
|
+
current_instances[current_instances_key] ||= new
|
93
96
|
end
|
94
97
|
|
95
98
|
# Declares one or more attributes that will be given both class and instance accessor methods.
|
@@ -117,10 +120,16 @@ module ActiveSupport
|
|
117
120
|
end
|
118
121
|
end
|
119
122
|
|
123
|
+
# Calls this block before #reset is called on the instance. Used for resetting external collaborators that depend on current values.
|
124
|
+
def before_reset(&block)
|
125
|
+
set_callback :reset, :before, &block
|
126
|
+
end
|
127
|
+
|
120
128
|
# Calls this block after #reset is called on the instance. Used for resetting external collaborators, like Time.zone.
|
121
129
|
def resets(&block)
|
122
130
|
set_callback :reset, :after, &block
|
123
131
|
end
|
132
|
+
alias_method :after_reset, :resets
|
124
133
|
|
125
134
|
delegate :set, :reset, to: :instance
|
126
135
|
|
@@ -142,6 +151,10 @@ module ActiveSupport
|
|
142
151
|
Thread.current[:current_attributes_instances] ||= {}
|
143
152
|
end
|
144
153
|
|
154
|
+
def current_instances_key
|
155
|
+
@current_instances_key ||= name.to_sym
|
156
|
+
end
|
157
|
+
|
145
158
|
def method_missing(name, *args, &block)
|
146
159
|
# Caches the method definition as a singleton method of the receiver.
|
147
160
|
#
|
@@ -189,7 +202,7 @@ module ActiveSupport
|
|
189
202
|
end
|
190
203
|
|
191
204
|
def compute_attributes(keys)
|
192
|
-
keys.
|
205
|
+
keys.index_with { |key| public_send(key) }
|
193
206
|
end
|
194
207
|
end
|
195
208
|
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "set"
|
4
|
+
require "active_support/core_ext/string/inflections"
|
5
|
+
|
6
|
+
module ActiveSupport
|
7
|
+
module Dependencies
|
8
|
+
module ZeitwerkIntegration # :nodoc: all
|
9
|
+
module Decorations
|
10
|
+
def clear
|
11
|
+
Dependencies.unload_interlock do
|
12
|
+
Rails.autoloaders.main.reload
|
13
|
+
rescue Zeitwerk::ReloadingDisabledError
|
14
|
+
raise "reloading is disabled because config.cache_classes is true"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def constantize(cpath)
|
19
|
+
ActiveSupport::Inflector.constantize(cpath)
|
20
|
+
end
|
21
|
+
|
22
|
+
def safe_constantize(cpath)
|
23
|
+
ActiveSupport::Inflector.safe_constantize(cpath)
|
24
|
+
end
|
25
|
+
|
26
|
+
def autoloaded_constants
|
27
|
+
Rails.autoloaders.main.unloadable_cpaths
|
28
|
+
end
|
29
|
+
|
30
|
+
def autoloaded?(object)
|
31
|
+
cpath = object.is_a?(Module) ? real_mod_name(object) : object.to_s
|
32
|
+
Rails.autoloaders.main.unloadable_cpath?(cpath)
|
33
|
+
end
|
34
|
+
|
35
|
+
def verbose=(verbose)
|
36
|
+
l = verbose ? logger || Rails.logger : nil
|
37
|
+
Rails.autoloaders.each { |autoloader| autoloader.logger = l }
|
38
|
+
end
|
39
|
+
|
40
|
+
def unhook!
|
41
|
+
:no_op
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
module RequireDependency
|
46
|
+
def require_dependency(filename)
|
47
|
+
filename = filename.to_path if filename.respond_to?(:to_path)
|
48
|
+
if abspath = ActiveSupport::Dependencies.search_for_file(filename)
|
49
|
+
require abspath
|
50
|
+
else
|
51
|
+
require filename
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
module Inflector
|
57
|
+
# Concurrent::Map is not needed. This is a private class, and overrides
|
58
|
+
# must be defined while the application boots.
|
59
|
+
@overrides = {}
|
60
|
+
|
61
|
+
def self.camelize(basename, _abspath)
|
62
|
+
@overrides[basename] || basename.camelize
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.inflect(overrides)
|
66
|
+
@overrides.merge!(overrides)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class << self
|
71
|
+
def take_over(enable_reloading:)
|
72
|
+
setup_autoloaders(enable_reloading)
|
73
|
+
freeze_paths
|
74
|
+
decorate_dependencies
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
def setup_autoloaders(enable_reloading)
|
79
|
+
Dependencies.autoload_paths.each do |autoload_path|
|
80
|
+
# Zeitwerk only accepts existing directories in `push_dir` to
|
81
|
+
# prevent misconfigurations.
|
82
|
+
next unless File.directory?(autoload_path)
|
83
|
+
|
84
|
+
autoloader = \
|
85
|
+
autoload_once?(autoload_path) ? Rails.autoloaders.once : Rails.autoloaders.main
|
86
|
+
|
87
|
+
autoloader.push_dir(autoload_path)
|
88
|
+
autoloader.do_not_eager_load(autoload_path) unless eager_load?(autoload_path)
|
89
|
+
end
|
90
|
+
|
91
|
+
Rails.autoloaders.main.enable_reloading if enable_reloading
|
92
|
+
Rails.autoloaders.each(&:setup)
|
93
|
+
end
|
94
|
+
|
95
|
+
def autoload_once?(autoload_path)
|
96
|
+
Dependencies.autoload_once_paths.include?(autoload_path)
|
97
|
+
end
|
98
|
+
|
99
|
+
def eager_load?(autoload_path)
|
100
|
+
Dependencies._eager_load_paths.member?(autoload_path)
|
101
|
+
end
|
102
|
+
|
103
|
+
def freeze_paths
|
104
|
+
Dependencies.autoload_paths.freeze
|
105
|
+
Dependencies.autoload_once_paths.freeze
|
106
|
+
Dependencies._eager_load_paths.freeze
|
107
|
+
end
|
108
|
+
|
109
|
+
def decorate_dependencies
|
110
|
+
Dependencies.unhook!
|
111
|
+
Dependencies.singleton_class.prepend(Decorations)
|
112
|
+
Object.prepend(RequireDependency)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -12,7 +12,6 @@ require "active_support/core_ext/object/blank"
|
|
12
12
|
require "active_support/core_ext/kernel/reporting"
|
13
13
|
require "active_support/core_ext/load_error"
|
14
14
|
require "active_support/core_ext/name_error"
|
15
|
-
require "active_support/core_ext/string/starts_ends_with"
|
16
15
|
require "active_support/dependencies/interlock"
|
17
16
|
require "active_support/inflector"
|
18
17
|
|
@@ -20,6 +19,9 @@ module ActiveSupport #:nodoc:
|
|
20
19
|
module Dependencies #:nodoc:
|
21
20
|
extend self
|
22
21
|
|
22
|
+
UNBOUND_METHOD_MODULE_NAME = Module.instance_method(:name)
|
23
|
+
private_constant :UNBOUND_METHOD_MODULE_NAME
|
24
|
+
|
23
25
|
mattr_accessor :interlock, default: Interlock.new
|
24
26
|
|
25
27
|
# :doc:
|
@@ -70,6 +72,11 @@ module ActiveSupport #:nodoc:
|
|
70
72
|
# only once. All directories in this set must also be present in +autoload_paths+.
|
71
73
|
mattr_accessor :autoload_once_paths, default: []
|
72
74
|
|
75
|
+
# This is a private set that collects all eager load paths during bootstrap.
|
76
|
+
# Useful for Zeitwerk integration. Its public interface is the config.* path
|
77
|
+
# accessors of each engine.
|
78
|
+
mattr_accessor :_eager_load_paths, default: Set.new
|
79
|
+
|
73
80
|
# An array of qualified constant names that have been loaded. Adding a name
|
74
81
|
# to this array will cause it to be unloaded the next time Dependencies are
|
75
82
|
# cleared.
|
@@ -79,6 +86,12 @@ module ActiveSupport #:nodoc:
|
|
79
86
|
# to allow arbitrary constants to be marked for unloading.
|
80
87
|
mattr_accessor :explicitly_unloadable_constants, default: []
|
81
88
|
|
89
|
+
# The logger used when tracing autoloads.
|
90
|
+
mattr_accessor :logger
|
91
|
+
|
92
|
+
# If true, trace autoloads with +logger.debug+.
|
93
|
+
mattr_accessor :verbose, default: false
|
94
|
+
|
82
95
|
# The WatchStack keeps a stack of the modules being watched as files are
|
83
96
|
# loaded. If a file in the process of being loaded (parent.rb) triggers the
|
84
97
|
# load of another file (child.rb) the stack will ensure that child.rb
|
@@ -97,6 +110,8 @@ module ActiveSupport #:nodoc:
|
|
97
110
|
# parent.rb then requires namespace/child.rb, the stack will look like
|
98
111
|
# [[Object], [Namespace]].
|
99
112
|
|
113
|
+
attr_reader :watching
|
114
|
+
|
100
115
|
def initialize
|
101
116
|
@watching = []
|
102
117
|
@stack = Hash.new { |h, k| h[k] = [] }
|
@@ -138,7 +153,7 @@ module ActiveSupport #:nodoc:
|
|
138
153
|
|
139
154
|
# Normalize the list of new constants, and add them to the list we will return
|
140
155
|
new_constants.each do |suffix|
|
141
|
-
constants << ([namespace, suffix] - ["Object"]).join("::"
|
156
|
+
constants << ([namespace, suffix] - ["Object"]).join("::")
|
142
157
|
end
|
143
158
|
end
|
144
159
|
constants
|
@@ -188,6 +203,11 @@ module ActiveSupport #:nodoc:
|
|
188
203
|
end
|
189
204
|
end
|
190
205
|
|
206
|
+
def self.include_into(base)
|
207
|
+
base.include(self)
|
208
|
+
append_features(base)
|
209
|
+
end
|
210
|
+
|
191
211
|
def const_missing(const_name)
|
192
212
|
from_mod = anonymous? ? guess_for_anonymous(const_name) : self
|
193
213
|
Dependencies.load_missing_constant(from_mod, const_name)
|
@@ -217,6 +237,21 @@ module ActiveSupport #:nodoc:
|
|
217
237
|
base.class_eval do
|
218
238
|
define_method(:load, Kernel.instance_method(:load))
|
219
239
|
private :load
|
240
|
+
|
241
|
+
define_method(:require, Kernel.instance_method(:require))
|
242
|
+
private :require
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
def self.include_into(base)
|
247
|
+
base.include(self)
|
248
|
+
|
249
|
+
if base.instance_method(:load).owner == base
|
250
|
+
base.remove_method(:load)
|
251
|
+
end
|
252
|
+
|
253
|
+
if base.instance_method(:require).owner == base
|
254
|
+
base.remove_method(:require)
|
220
255
|
end
|
221
256
|
end
|
222
257
|
|
@@ -224,15 +259,26 @@ module ActiveSupport #:nodoc:
|
|
224
259
|
Dependencies.require_or_load(file_name)
|
225
260
|
end
|
226
261
|
|
227
|
-
#
|
228
|
-
|
262
|
+
# :doc:
|
263
|
+
|
264
|
+
# <b>Warning:</b> This method is obsolete in +:zeitwerk+ mode. In
|
265
|
+
# +:zeitwerk+ mode semantics match Ruby's and you do not need to be
|
266
|
+
# defensive with load order. Just refer to classes and modules normally.
|
267
|
+
# If the constant name is dynamic, camelize if needed, and constantize.
|
268
|
+
#
|
269
|
+
# In +:classic+ mode, interprets a file using +mechanism+ and marks its
|
270
|
+
# defined constants as autoloaded. +file_name+ can be either a string or
|
229
271
|
# respond to <tt>to_path</tt>.
|
230
272
|
#
|
231
|
-
#
|
232
|
-
# defined at that point. A typical use case is to
|
233
|
-
# resolution deterministic for constants with the same
|
234
|
-
# different namespaces whose evaluation would depend on
|
235
|
-
# otherwise.
|
273
|
+
# In +:classic+ mode, use this method in code that absolutely needs a
|
274
|
+
# certain constant to be defined at that point. A typical use case is to
|
275
|
+
# make constant name resolution deterministic for constants with the same
|
276
|
+
# relative name in different namespaces whose evaluation would depend on
|
277
|
+
# load order otherwise.
|
278
|
+
#
|
279
|
+
# Engines that do not control the mode in which their parent application
|
280
|
+
# runs should call +require_dependency+ where needed in case the runtime
|
281
|
+
# mode is +:classic+.
|
236
282
|
def require_dependency(file_name, message = "No such file to load -- %s.rb")
|
237
283
|
file_name = file_name.to_path if file_name.respond_to?(:to_path)
|
238
284
|
unless file_name.is_a?(String)
|
@@ -242,9 +288,13 @@ module ActiveSupport #:nodoc:
|
|
242
288
|
Dependencies.depend_on(file_name, message)
|
243
289
|
end
|
244
290
|
|
291
|
+
# :nodoc:
|
292
|
+
|
245
293
|
def load_dependency(file)
|
246
294
|
if Dependencies.load? && Dependencies.constant_watch_stack.watching?
|
247
|
-
Dependencies.
|
295
|
+
descs = Dependencies.constant_watch_stack.watching.flatten.uniq
|
296
|
+
|
297
|
+
Dependencies.new_constants_in(*descs) { yield }
|
248
298
|
else
|
249
299
|
yield
|
250
300
|
end
|
@@ -271,7 +321,6 @@ module ActiveSupport #:nodoc:
|
|
271
321
|
end
|
272
322
|
|
273
323
|
private
|
274
|
-
|
275
324
|
def load(file, wrap = false)
|
276
325
|
result = false
|
277
326
|
load_dependency(file) { result = super }
|
@@ -307,9 +356,9 @@ module ActiveSupport #:nodoc:
|
|
307
356
|
end
|
308
357
|
|
309
358
|
def hook!
|
310
|
-
Object
|
311
|
-
Module
|
312
|
-
Exception.
|
359
|
+
Loadable.include_into(Object)
|
360
|
+
ModuleConstMissing.include_into(Module)
|
361
|
+
Exception.include(Blamable)
|
313
362
|
end
|
314
363
|
|
315
364
|
def unhook!
|
@@ -326,7 +375,12 @@ module ActiveSupport #:nodoc:
|
|
326
375
|
require_or_load(path || file_name)
|
327
376
|
rescue LoadError => load_error
|
328
377
|
if file_name = load_error.message[/ -- (.*?)(\.rb)?$/, 1]
|
329
|
-
load_error.
|
378
|
+
load_error_message = if load_error.respond_to?(:original_message)
|
379
|
+
load_error.original_message
|
380
|
+
else
|
381
|
+
load_error.message
|
382
|
+
end
|
383
|
+
load_error_message.replace(message % file_name)
|
330
384
|
load_error.copy_blame!(load_error)
|
331
385
|
end
|
332
386
|
raise
|
@@ -341,7 +395,7 @@ module ActiveSupport #:nodoc:
|
|
341
395
|
end
|
342
396
|
|
343
397
|
def require_or_load(file_name, const_path = nil)
|
344
|
-
file_name =
|
398
|
+
file_name = file_name.chomp(".rb")
|
345
399
|
expanded = File.expand_path(file_name)
|
346
400
|
return if loaded.include?(expanded)
|
347
401
|
|
@@ -391,7 +445,7 @@ module ActiveSupport #:nodoc:
|
|
391
445
|
# constant paths which would cause Dependencies to attempt to load this
|
392
446
|
# file.
|
393
447
|
def loadable_constants_for_path(path, bases = autoload_paths)
|
394
|
-
path =
|
448
|
+
path = path.chomp(".rb")
|
395
449
|
expanded_path = File.expand_path(path)
|
396
450
|
paths = []
|
397
451
|
|
@@ -400,7 +454,7 @@ module ActiveSupport #:nodoc:
|
|
400
454
|
next unless expanded_path.start_with?(expanded_root)
|
401
455
|
|
402
456
|
root_size = expanded_root.size
|
403
|
-
next if expanded_path[root_size] !=
|
457
|
+
next if expanded_path[root_size] != ?/
|
404
458
|
|
405
459
|
nesting = expanded_path[(root_size + 1)..-1]
|
406
460
|
paths << nesting.camelize unless nesting.blank?
|
@@ -412,7 +466,7 @@ module ActiveSupport #:nodoc:
|
|
412
466
|
|
413
467
|
# Search for a file in autoload_paths matching the provided suffix.
|
414
468
|
def search_for_file(path_suffix)
|
415
|
-
path_suffix
|
469
|
+
path_suffix += ".rb" unless path_suffix.end_with?(".rb")
|
416
470
|
|
417
471
|
autoload_paths.each do |root|
|
418
472
|
path = File.join(root, path_suffix)
|
@@ -432,9 +486,9 @@ module ActiveSupport #:nodoc:
|
|
432
486
|
end
|
433
487
|
|
434
488
|
def load_once_path?(path)
|
435
|
-
# to_s works around a ruby issue where String#
|
489
|
+
# to_s works around a ruby issue where String#start_with?(Pathname)
|
436
490
|
# will raise a TypeError: no implicit conversion of Pathname into String
|
437
|
-
autoload_once_paths.any? { |base| path.
|
491
|
+
autoload_once_paths.any? { |base| path.start_with?(base.to_s) }
|
438
492
|
end
|
439
493
|
|
440
494
|
# Attempt to autoload the provided module name by searching for a directory
|
@@ -446,6 +500,7 @@ module ActiveSupport #:nodoc:
|
|
446
500
|
return nil unless base_path = autoloadable_module?(path_suffix)
|
447
501
|
mod = Module.new
|
448
502
|
into.const_set const_name, mod
|
503
|
+
log("constant #{qualified_name} autoloaded (module autovivified from #{File.join(base_path, path_suffix)})")
|
449
504
|
autoloaded_constants << qualified_name unless autoload_once_paths.include?(base_path)
|
450
505
|
autoloaded_constants.uniq!
|
451
506
|
mod
|
@@ -483,30 +538,36 @@ module ActiveSupport #:nodoc:
|
|
483
538
|
# it is not possible to load the constant into from_mod, try its parent
|
484
539
|
# module using +const_missing+.
|
485
540
|
def load_missing_constant(from_mod, const_name)
|
486
|
-
|
541
|
+
from_mod_name = real_mod_name(from_mod)
|
542
|
+
unless qualified_const_defined?(from_mod_name) && Inflector.constantize(from_mod_name).equal?(from_mod)
|
487
543
|
raise ArgumentError, "A copy of #{from_mod} has been removed from the module tree but is still active!"
|
488
544
|
end
|
489
545
|
|
490
|
-
qualified_name = qualified_name_for
|
546
|
+
qualified_name = qualified_name_for(from_mod, const_name)
|
491
547
|
path_suffix = qualified_name.underscore
|
492
548
|
|
493
549
|
file_path = search_for_file(path_suffix)
|
494
550
|
|
495
551
|
if file_path
|
496
552
|
expanded = File.expand_path(file_path)
|
497
|
-
expanded.
|
553
|
+
expanded.delete_suffix!(".rb")
|
498
554
|
|
499
555
|
if loading.include?(expanded)
|
500
556
|
raise "Circular dependency detected while autoloading constant #{qualified_name}"
|
501
557
|
else
|
502
558
|
require_or_load(expanded, qualified_name)
|
503
|
-
|
504
|
-
|
559
|
+
|
560
|
+
if from_mod.const_defined?(const_name, false)
|
561
|
+
log("constant #{qualified_name} autoloaded from #{expanded}.rb")
|
562
|
+
return from_mod.const_get(const_name)
|
563
|
+
else
|
564
|
+
raise LoadError, "Unable to autoload constant #{qualified_name}, expected #{file_path} to define it"
|
565
|
+
end
|
505
566
|
end
|
506
567
|
elsif mod = autoload_module!(from_mod, const_name, qualified_name, path_suffix)
|
507
568
|
return mod
|
508
|
-
elsif (parent = from_mod.
|
509
|
-
! from_mod.
|
569
|
+
elsif (parent = from_mod.module_parent) && parent != from_mod &&
|
570
|
+
! from_mod.module_parents.any? { |p| p.const_defined?(const_name, false) }
|
510
571
|
# If our parents do not have a constant named +const_name+ then we are free
|
511
572
|
# to attempt to load upwards. If they do have such a constant, then this
|
512
573
|
# const_missing must be due to from_mod::const_name, which should not
|
@@ -537,8 +598,8 @@ module ActiveSupport #:nodoc:
|
|
537
598
|
end
|
538
599
|
end
|
539
600
|
|
540
|
-
name_error =
|
541
|
-
name_error.set_backtrace(caller.reject { |l| l.
|
601
|
+
name_error = uninitialized_constant(qualified_name, const_name, receiver: from_mod)
|
602
|
+
name_error.set_backtrace(caller.reject { |l| l.start_with? __FILE__ })
|
542
603
|
raise name_error
|
543
604
|
end
|
544
605
|
|
@@ -550,6 +611,7 @@ module ActiveSupport #:nodoc:
|
|
550
611
|
# as the environment will be in an inconsistent state, e.g. other constants
|
551
612
|
# may have already been unloaded and not accessible.
|
552
613
|
def remove_unloadable_constants!
|
614
|
+
log("removing unloadable constants")
|
553
615
|
autoloaded_constants.each { |const| remove_constant const }
|
554
616
|
autoloaded_constants.clear
|
555
617
|
Reference.clear!
|
@@ -613,7 +675,7 @@ module ActiveSupport #:nodoc:
|
|
613
675
|
|
614
676
|
# Determine if the given constant has been automatically loaded.
|
615
677
|
def autoloaded?(desc)
|
616
|
-
return false if desc.is_a?(Module) && desc.
|
678
|
+
return false if desc.is_a?(Module) && real_mod_name(desc).nil?
|
617
679
|
name = to_constant_name desc
|
618
680
|
return false unless qualified_const_defined?(name)
|
619
681
|
autoloaded_constants.include?(name)
|
@@ -666,10 +728,10 @@ module ActiveSupport #:nodoc:
|
|
666
728
|
# A module, class, symbol, or string may be provided.
|
667
729
|
def to_constant_name(desc) #:nodoc:
|
668
730
|
case desc
|
669
|
-
when String then desc.
|
731
|
+
when String then desc.delete_prefix("::")
|
670
732
|
when Symbol then desc.to_s
|
671
733
|
when Module
|
672
|
-
desc
|
734
|
+
real_mod_name(desc) ||
|
673
735
|
raise(ArgumentError, "Anonymous modules have no name to be referenced by")
|
674
736
|
else raise TypeError, "Not a valid constant descriptor: #{desc.inspect}"
|
675
737
|
end
|
@@ -677,7 +739,7 @@ module ActiveSupport #:nodoc:
|
|
677
739
|
|
678
740
|
def remove_constant(const) #:nodoc:
|
679
741
|
# Normalize ::Foo, ::Object::Foo, Object::Foo, Object::Object::Foo, etc. as Foo.
|
680
|
-
normalized = const.to_s.
|
742
|
+
normalized = const.to_s.delete_prefix("::")
|
681
743
|
normalized.sub!(/\A(Object::)+/, "")
|
682
744
|
|
683
745
|
constants = normalized.split("::")
|
@@ -687,7 +749,7 @@ module ActiveSupport #:nodoc:
|
|
687
749
|
file_path = search_for_file(const.underscore)
|
688
750
|
if file_path
|
689
751
|
expanded = File.expand_path(file_path)
|
690
|
-
expanded.
|
752
|
+
expanded.delete_suffix!(".rb")
|
691
753
|
loaded.delete(expanded)
|
692
754
|
end
|
693
755
|
|
@@ -739,6 +801,27 @@ module ActiveSupport #:nodoc:
|
|
739
801
|
# The constant is no longer reachable, just skip it.
|
740
802
|
end
|
741
803
|
end
|
804
|
+
|
805
|
+
def log(message)
|
806
|
+
logger.debug("autoloading: #{message}") if logger && verbose
|
807
|
+
end
|
808
|
+
|
809
|
+
private
|
810
|
+
if RUBY_VERSION < "2.6"
|
811
|
+
def uninitialized_constant(qualified_name, const_name, receiver:)
|
812
|
+
NameError.new("uninitialized constant #{qualified_name}", const_name)
|
813
|
+
end
|
814
|
+
else
|
815
|
+
def uninitialized_constant(qualified_name, const_name, receiver:)
|
816
|
+
NameError.new("uninitialized constant #{qualified_name}", const_name, receiver: receiver)
|
817
|
+
end
|
818
|
+
end
|
819
|
+
|
820
|
+
# Returns the original name of a class or module even if `name` has been
|
821
|
+
# overridden.
|
822
|
+
def real_mod_name(mod)
|
823
|
+
UNBOUND_METHOD_MODULE_NAME.bind(mod).call
|
824
|
+
end
|
742
825
|
end
|
743
826
|
end
|
744
827
|
|