zeitwerk 2.6.15 → 2.6.16
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/zeitwerk/cref.rb +99 -0
- data/lib/zeitwerk/loader/callbacks.rb +13 -14
- data/lib/zeitwerk/loader/eager_load.rb +7 -9
- data/lib/zeitwerk/loader/helpers.rb +7 -59
- data/lib/zeitwerk/loader.rb +58 -62
- data/lib/zeitwerk/version.rb +1 -1
- data/lib/zeitwerk.rb +1 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4b69678cbbd525cff55aa4cd08d1f3a785d69cac3e851e3cc2a168ef029163a3
|
4
|
+
data.tar.gz: 9da1ded3c41f766feee609adedc9706d4efb4cfd3701c6944f0e781986d578ef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 76f28b7d765b0209f489cb23f939143a6d1800e997e9a1722a0482aaf4e942f59eef26ec1e9e98a7e722710ba01c3de706f01a64594688310ca7908edb5c4de1
|
7
|
+
data.tar.gz: 2da1dfd280a4fb987f281094e45ce9c1797323680cd90f586c60660516995262aaeb4d38c55e8c330a5c879f5471567633ffe72298371c33a05b5cb6f3805285
|
data/README.md
CHANGED
@@ -1065,7 +1065,7 @@ However, sometimes it might still be convenient to tell Zeitwerk to completely i
|
|
1065
1065
|
|
1066
1066
|
You can ignore file names, directory names, and glob patterns. Glob patterns are expanded when they are added and again on each reload.
|
1067
1067
|
|
1068
|
-
There is an edge case related to nested root directories. Conceptually, root directories are independent source trees. If you ignore a parent of a nested root directory, the nested root directory is not affected. You need to ignore it
|
1068
|
+
There is an edge case related to nested root directories. Conceptually, root directories are independent source trees. If you ignore a parent of a nested root directory, the nested root directory is not affected. You need to ignore it explicitly if you want it ignored too.
|
1069
1069
|
|
1070
1070
|
Let's see some use cases.
|
1071
1071
|
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This private class encapsulates pairs (mod, cname).
|
4
|
+
#
|
5
|
+
# Objects represent the constant cname in the class or module object mod, and
|
6
|
+
# have API to manage them that encapsulates the constants API. Examples:
|
7
|
+
#
|
8
|
+
# cref.path
|
9
|
+
# cref.set(value)
|
10
|
+
# cref.get
|
11
|
+
#
|
12
|
+
# The constant may or may not exist in mod.
|
13
|
+
class Zeitwerk::Cref
|
14
|
+
include Zeitwerk::RealModName
|
15
|
+
|
16
|
+
# @sig Symbol
|
17
|
+
attr_reader :cname
|
18
|
+
|
19
|
+
# The type of the first argument is Module because Class < Module, class
|
20
|
+
# objects are also valid.
|
21
|
+
#
|
22
|
+
# @sig (Module, Symbol) -> void
|
23
|
+
def initialize(mod, cname)
|
24
|
+
@mod = mod
|
25
|
+
@cname = cname
|
26
|
+
@path = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
if Symbol.method_defined?(:name)
|
30
|
+
# Symbol#name was introduced in Ruby 3.0. It returns always the same
|
31
|
+
# frozen object, so we may save a few string allocations.
|
32
|
+
#
|
33
|
+
# @sig () -> String
|
34
|
+
def path
|
35
|
+
@path ||= Object.equal?(@mod) ? @cname.name : "#{real_mod_name(@mod)}::#{@cname.name}"
|
36
|
+
end
|
37
|
+
else
|
38
|
+
# @sig () -> String
|
39
|
+
def path
|
40
|
+
@path ||= Object.equal?(@mod) ? @cname.to_s : "#{real_mod_name(@mod)}::#{@cname}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# The autoload? predicate takes into account the ancestor chain of the
|
45
|
+
# receiver, like const_defined? and other methods in the constants API do.
|
46
|
+
#
|
47
|
+
# For example, given
|
48
|
+
#
|
49
|
+
# class A
|
50
|
+
# autoload :X, "x.rb"
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
# class B < A
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# B.autoload?(:X) returns "x.rb".
|
57
|
+
#
|
58
|
+
# We need a way to retrieve it ignoring ancestors.
|
59
|
+
#
|
60
|
+
# @sig () -> String?
|
61
|
+
if method(:autoload?).arity == 1
|
62
|
+
# @sig () -> String?
|
63
|
+
def autoload?
|
64
|
+
@mod.autoload?(@cname) if self.defined?
|
65
|
+
end
|
66
|
+
else
|
67
|
+
# @sig () -> String?
|
68
|
+
def autoload?
|
69
|
+
@mod.autoload?(@cname, false)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# @sig (String) -> bool
|
74
|
+
def autoload(abspath)
|
75
|
+
@mod.autoload(@cname, abspath)
|
76
|
+
end
|
77
|
+
|
78
|
+
# @sig () -> bool
|
79
|
+
def defined?
|
80
|
+
@mod.const_defined?(@cname, false)
|
81
|
+
end
|
82
|
+
|
83
|
+
# @sig (Object) -> Object
|
84
|
+
def set(value)
|
85
|
+
@mod.const_set(@cname, value)
|
86
|
+
end
|
87
|
+
|
88
|
+
# @raise [NameError]
|
89
|
+
# @sig () -> Object
|
90
|
+
def get
|
91
|
+
@mod.const_get(@cname, false)
|
92
|
+
end
|
93
|
+
|
94
|
+
# @raise [NameError]
|
95
|
+
# @sig () -> void
|
96
|
+
def remove
|
97
|
+
@mod.__send__(:remove_const, @cname)
|
98
|
+
end
|
99
|
+
end
|
@@ -8,29 +8,28 @@ module Zeitwerk::Loader::Callbacks
|
|
8
8
|
#
|
9
9
|
# @sig (String) -> void
|
10
10
|
internal def on_file_autoloaded(file)
|
11
|
-
cref
|
12
|
-
cpath = cpath(*cref)
|
11
|
+
cref = autoloads.delete(file)
|
13
12
|
|
14
13
|
Zeitwerk::Registry.unregister_autoload(file)
|
15
14
|
|
16
|
-
if
|
17
|
-
log("constant #{
|
18
|
-
to_unload[
|
19
|
-
run_on_load_callbacks(
|
15
|
+
if cref.defined?
|
16
|
+
log("constant #{cref.path} loaded from file #{file}") if logger
|
17
|
+
to_unload[cref.path] = [file, cref] if reloading_enabled?
|
18
|
+
run_on_load_callbacks(cref.path, cref.get, file) unless on_load_callbacks.empty?
|
20
19
|
else
|
21
|
-
msg = "expected file #{file} to define constant #{
|
20
|
+
msg = "expected file #{file} to define constant #{cref.path}, but didn't"
|
22
21
|
log(msg) if logger
|
23
22
|
|
24
23
|
# Ruby still keeps the autoload defined, but we remove it because the
|
25
24
|
# contract in Zeitwerk is more strict.
|
26
|
-
|
25
|
+
cref.remove
|
27
26
|
|
28
27
|
# Since the expected constant was not defined, there is nothing to unload.
|
29
28
|
# However, if the exception is rescued and reloading is enabled, we still
|
30
29
|
# need to deleted the file from $LOADED_FEATURES.
|
31
|
-
to_unload[
|
30
|
+
to_unload[cref.path] = [file, cref] if reloading_enabled?
|
32
31
|
|
33
|
-
raise Zeitwerk::NameError.new(msg, cref.
|
32
|
+
raise Zeitwerk::NameError.new(msg, cref.cname)
|
34
33
|
end
|
35
34
|
end
|
36
35
|
|
@@ -53,8 +52,8 @@ module Zeitwerk::Loader::Callbacks
|
|
53
52
|
# children, since t1 would have correctly deleted its namespace_dirs entry.
|
54
53
|
dirs_autoload_monitor.synchronize do
|
55
54
|
if cref = autoloads.delete(dir)
|
56
|
-
|
57
|
-
cpath =
|
55
|
+
implicit_namespace = cref.set(Module.new)
|
56
|
+
cpath = implicit_namespace.name
|
58
57
|
log("module #{cpath} autovivified from directory #{dir}") if logger
|
59
58
|
|
60
59
|
to_unload[cpath] = [dir, cref] if reloading_enabled?
|
@@ -65,9 +64,9 @@ module Zeitwerk::Loader::Callbacks
|
|
65
64
|
# these to be able to unregister later if eager loading.
|
66
65
|
autoloaded_dirs << dir
|
67
66
|
|
68
|
-
on_namespace_loaded(
|
67
|
+
on_namespace_loaded(implicit_namespace)
|
69
68
|
|
70
|
-
run_on_load_callbacks(cpath,
|
69
|
+
run_on_load_callbacks(cpath, implicit_namespace, dir) unless on_load_callbacks.empty?
|
71
70
|
end
|
72
71
|
end
|
73
72
|
end
|
@@ -61,8 +61,8 @@ module Zeitwerk::Loader::EagerLoad
|
|
61
61
|
cnames.reverse_each do |cname|
|
62
62
|
# Can happen if there are no Ruby files. This is not an error condition,
|
63
63
|
# the directory is actually managed. Could have Ruby files later.
|
64
|
-
return unless
|
65
|
-
namespace =
|
64
|
+
return unless namespace.const_defined?(cname, false)
|
65
|
+
namespace = namespace.const_get(cname, false)
|
66
66
|
end
|
67
67
|
|
68
68
|
# A shortcircuiting test depends on the invocation of this method. Please
|
@@ -145,12 +145,12 @@ module Zeitwerk::Loader::EagerLoad
|
|
145
145
|
|
146
146
|
namespace = root_namespace
|
147
147
|
cnames.reverse_each do |cname|
|
148
|
-
namespace =
|
148
|
+
namespace = namespace.const_get(cname, false)
|
149
149
|
end
|
150
150
|
|
151
151
|
raise Zeitwerk::Error.new("#{abspath} is shadowed") if shadowed_file?(abspath)
|
152
152
|
|
153
|
-
|
153
|
+
namespace.const_get(base_cname, false)
|
154
154
|
end
|
155
155
|
|
156
156
|
# The caller is responsible for making sure `namespace` is the namespace that
|
@@ -164,22 +164,20 @@ module Zeitwerk::Loader::EagerLoad
|
|
164
164
|
log("eager load directory #{dir} start") if logger
|
165
165
|
|
166
166
|
queue = [[dir, namespace]]
|
167
|
-
|
168
|
-
dir, namespace = queue.shift
|
169
|
-
|
167
|
+
while (dir, namespace = queue.shift)
|
170
168
|
ls(dir) do |basename, abspath, ftype|
|
171
169
|
next if honour_exclusions && eager_load_exclusions.member?(abspath)
|
172
170
|
|
173
171
|
if ftype == :file
|
174
172
|
if (cref = autoloads[abspath])
|
175
|
-
|
173
|
+
cref.get
|
176
174
|
end
|
177
175
|
else
|
178
176
|
if collapse?(abspath)
|
179
177
|
queue << [abspath, namespace]
|
180
178
|
else
|
181
179
|
cname = inflector.camelize(basename, abspath).to_sym
|
182
|
-
queue << [abspath,
|
180
|
+
queue << [abspath, namespace.const_get(cname, false)]
|
183
181
|
end
|
184
182
|
end
|
185
183
|
end
|
@@ -30,7 +30,12 @@ module Zeitwerk::Loader::Helpers
|
|
30
30
|
|
31
31
|
if dir?(abspath)
|
32
32
|
next if roots.key?(abspath)
|
33
|
-
|
33
|
+
|
34
|
+
if !has_at_least_one_ruby_file?(abspath)
|
35
|
+
log("directory #{abspath} is ignored because it has no Ruby files") if logger
|
36
|
+
next
|
37
|
+
end
|
38
|
+
|
34
39
|
ftype = :directory
|
35
40
|
else
|
36
41
|
next unless ruby?(abspath)
|
@@ -95,64 +100,7 @@ module Zeitwerk::Loader::Helpers
|
|
95
100
|
end
|
96
101
|
end
|
97
102
|
|
98
|
-
# ---
|
99
|
-
|
100
|
-
# The autoload? predicate takes into account the ancestor chain of the
|
101
|
-
# receiver, like const_defined? and other methods in the constants API do.
|
102
|
-
#
|
103
|
-
# For example, given
|
104
|
-
#
|
105
|
-
# class A
|
106
|
-
# autoload :X, "x.rb"
|
107
|
-
# end
|
108
|
-
#
|
109
|
-
# class B < A
|
110
|
-
# end
|
111
|
-
#
|
112
|
-
# B.autoload?(:X) returns "x.rb".
|
113
|
-
#
|
114
|
-
# We need a way to strictly check in parent ignoring ancestors.
|
115
|
-
#
|
116
|
-
# @sig (Module, Symbol) -> String?
|
117
|
-
if method(:autoload?).arity == 1
|
118
|
-
private def strict_autoload_path(parent, cname)
|
119
|
-
parent.autoload?(cname) if cdef?(parent, cname)
|
120
|
-
end
|
121
|
-
else
|
122
|
-
private def strict_autoload_path(parent, cname)
|
123
|
-
parent.autoload?(cname, false)
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
# @sig (Module, Symbol) -> String
|
128
|
-
if Symbol.method_defined?(:name)
|
129
|
-
# Symbol#name was introduced in Ruby 3.0. It returns always the same
|
130
|
-
# frozen object, so we may save a few string allocations.
|
131
|
-
private def cpath(parent, cname)
|
132
|
-
Object == parent ? cname.name : "#{real_mod_name(parent)}::#{cname.name}"
|
133
|
-
end
|
134
|
-
else
|
135
|
-
private def cpath(parent, cname)
|
136
|
-
Object == parent ? cname.to_s : "#{real_mod_name(parent)}::#{cname}"
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
# @sig (Module, Symbol) -> bool
|
141
|
-
private def cdef?(parent, cname)
|
142
|
-
parent.const_defined?(cname, false)
|
143
|
-
end
|
144
|
-
|
145
|
-
# @raise [NameError]
|
146
|
-
# @sig (Module, Symbol) -> Object
|
147
|
-
private def cget(parent, cname)
|
148
|
-
parent.const_get(cname, false)
|
149
|
-
end
|
150
|
-
|
151
|
-
# @raise [NameError]
|
152
|
-
# @sig (Module, Symbol) -> Object
|
153
|
-
private def crem(parent, cname)
|
154
|
-
parent.__send__(:remove_const, cname)
|
155
|
-
end
|
103
|
+
# --- Inflection --------------------------------------------------------------------------------
|
156
104
|
|
157
105
|
CNAME_VALIDATOR = Module.new
|
158
106
|
private_constant :CNAME_VALIDATOR
|
data/lib/zeitwerk/loader.rb
CHANGED
@@ -22,14 +22,13 @@ module Zeitwerk
|
|
22
22
|
private_constant :MUTEX
|
23
23
|
|
24
24
|
# Maps absolute paths for which an autoload has been set ---and not
|
25
|
-
# executed--- to their corresponding
|
26
|
-
# name.
|
25
|
+
# executed--- to their corresponding Zeitwerk::Cref object.
|
27
26
|
#
|
28
|
-
# "/Users/fxn/blog/app/models/user.rb" =>
|
29
|
-
# "/Users/fxn/blog/app/models/hotel/pricing.rb" =>
|
27
|
+
# "/Users/fxn/blog/app/models/user.rb" => #<Zeitwerk::Cref:... @mod=Object, @cname=:User, ...>,
|
28
|
+
# "/Users/fxn/blog/app/models/hotel/pricing.rb" => #<Zeitwerk::Cref:... @mod=Hotel, @cname=:Pricing, ...>,
|
30
29
|
# ...
|
31
30
|
#
|
32
|
-
# @sig Hash[String,
|
31
|
+
# @sig Hash[String, Zeitwerk::Cref]
|
33
32
|
attr_reader :autoloads
|
34
33
|
internal :autoloads
|
35
34
|
|
@@ -45,17 +44,19 @@ module Zeitwerk
|
|
45
44
|
|
46
45
|
# Stores metadata needed for unloading. Its entries look like this:
|
47
46
|
#
|
48
|
-
# "Admin::Role" => [
|
47
|
+
# "Admin::Role" => [
|
48
|
+
# ".../admin/role.rb",
|
49
|
+
# #<Zeitwerk::Cref:... @mod=Admin, @cname=:Role, ...>
|
50
|
+
# ]
|
49
51
|
#
|
50
52
|
# The cpath as key helps implementing unloadable_cpath? The file name is
|
51
53
|
# stored in order to be able to delete it from $LOADED_FEATURES, and the
|
52
|
-
#
|
53
|
-
# or module object.
|
54
|
+
# cref is used to remove the constant from the parent class or module.
|
54
55
|
#
|
55
56
|
# If reloading is enabled, this hash is filled as constants are autoloaded
|
56
57
|
# or eager loaded. Otherwise, the collection remains empty.
|
57
58
|
#
|
58
|
-
# @sig Hash[String, [String,
|
59
|
+
# @sig Hash[String, [String, Zeitwerk::Cref]]
|
59
60
|
attr_reader :to_unload
|
60
61
|
internal :to_unload
|
61
62
|
|
@@ -154,22 +155,22 @@ module Zeitwerk
|
|
154
155
|
# is enough.
|
155
156
|
unloaded_files = Set.new
|
156
157
|
|
157
|
-
autoloads.each do |abspath,
|
158
|
-
if
|
159
|
-
unload_autoload(
|
158
|
+
autoloads.each do |abspath, cref|
|
159
|
+
if cref.autoload?
|
160
|
+
unload_autoload(cref)
|
160
161
|
else
|
161
162
|
# Could happen if loaded with require_relative. That is unsupported,
|
162
163
|
# and the constant path would escape unloadable_cpath? This is just
|
163
164
|
# defensive code to clean things up as much as we are able to.
|
164
|
-
unload_cref(
|
165
|
+
unload_cref(cref)
|
165
166
|
unloaded_files.add(abspath) if ruby?(abspath)
|
166
167
|
end
|
167
168
|
end
|
168
169
|
|
169
|
-
to_unload.each do |cpath, (abspath,
|
170
|
+
to_unload.each do |cpath, (abspath, cref)|
|
170
171
|
unless on_unload_callbacks.empty?
|
171
172
|
begin
|
172
|
-
value =
|
173
|
+
value = cref.get
|
173
174
|
rescue ::NameError
|
174
175
|
# Perhaps the user deleted the constant by hand, or perhaps an
|
175
176
|
# autoload failed to define the expected constant but the user
|
@@ -179,7 +180,7 @@ module Zeitwerk
|
|
179
180
|
end
|
180
181
|
end
|
181
182
|
|
182
|
-
unload_cref(
|
183
|
+
unload_cref(cref)
|
183
184
|
unloaded_files.add(abspath) if ruby?(abspath)
|
184
185
|
end
|
185
186
|
|
@@ -240,8 +241,7 @@ module Zeitwerk
|
|
240
241
|
actual_roots.each do |root_dir, root_namespace|
|
241
242
|
queue = [[root_dir, real_mod_name(root_namespace)]]
|
242
243
|
|
243
|
-
|
244
|
-
dir, cpath = queue.shift
|
244
|
+
while (dir, cpath = queue.shift)
|
245
245
|
result[dir] = cpath
|
246
246
|
|
247
247
|
prefix = cpath == "Object" ? "" : cpath + "::"
|
@@ -445,21 +445,22 @@ module Zeitwerk
|
|
445
445
|
ls(dir) do |basename, abspath, ftype|
|
446
446
|
if ftype == :file
|
447
447
|
basename.delete_suffix!(".rb")
|
448
|
-
|
448
|
+
cref = Cref.new(parent, cname_for(basename, abspath))
|
449
|
+
autoload_file(cref, abspath)
|
449
450
|
else
|
450
451
|
if collapse?(abspath)
|
451
452
|
define_autoloads_for_dir(abspath, parent)
|
452
453
|
else
|
453
|
-
|
454
|
+
cref = Cref.new(parent, cname_for(basename, abspath))
|
455
|
+
autoload_subdir(cref, abspath)
|
454
456
|
end
|
455
457
|
end
|
456
458
|
end
|
457
459
|
end
|
458
460
|
|
459
461
|
# @sig (Module, Symbol, String) -> void
|
460
|
-
private def autoload_subdir(
|
461
|
-
if autoload_path = autoload_path_set_by_me_for?(
|
462
|
-
cpath = cpath(parent, cname)
|
462
|
+
private def autoload_subdir(cref, subdir)
|
463
|
+
if autoload_path = autoload_path_set_by_me_for?(cref)
|
463
464
|
if ruby?(autoload_path)
|
464
465
|
# Scanning visited a Ruby file first, and now a directory for the same
|
465
466
|
# constant has been found. This means we are dealing with an explicit
|
@@ -468,88 +469,83 @@ module Zeitwerk
|
|
468
469
|
# Registering is idempotent, and we have to keep the autoload pointing
|
469
470
|
# to the file. This may run again if more directories are found later
|
470
471
|
# on, no big deal.
|
471
|
-
register_explicit_namespace(
|
472
|
+
register_explicit_namespace(cref.path)
|
472
473
|
end
|
473
474
|
# If the existing autoload points to a file, it has to be preserved, if
|
474
475
|
# not, it is fine as it is. In either case, we do not need to override.
|
475
476
|
# Just remember the subdirectory conforms this namespace.
|
476
|
-
namespace_dirs[
|
477
|
-
elsif !
|
477
|
+
namespace_dirs[cref.path] << subdir
|
478
|
+
elsif !cref.defined?
|
478
479
|
# First time we find this namespace, set an autoload for it.
|
479
|
-
namespace_dirs[
|
480
|
-
define_autoload(
|
480
|
+
namespace_dirs[cref.path] << subdir
|
481
|
+
define_autoload(cref, subdir)
|
481
482
|
else
|
482
483
|
# For whatever reason the constant that corresponds to this namespace has
|
483
484
|
# already been defined, we have to recurse.
|
484
|
-
log("the namespace #{
|
485
|
-
define_autoloads_for_dir(subdir,
|
485
|
+
log("the namespace #{cref.path} already exists, descending into #{subdir}") if logger
|
486
|
+
define_autoloads_for_dir(subdir, cref.get)
|
486
487
|
end
|
487
488
|
end
|
488
489
|
|
489
490
|
# @sig (Module, Symbol, String) -> void
|
490
|
-
private def autoload_file(
|
491
|
-
if autoload_path =
|
491
|
+
private def autoload_file(cref, file)
|
492
|
+
if autoload_path = cref.autoload? || Registry.inception?(cref.path)
|
492
493
|
# First autoload for a Ruby file wins, just ignore subsequent ones.
|
493
494
|
if ruby?(autoload_path)
|
494
495
|
shadowed_files << file
|
495
496
|
log("file #{file} is ignored because #{autoload_path} has precedence") if logger
|
496
497
|
else
|
497
|
-
promote_namespace_from_implicit_to_explicit(
|
498
|
-
dir: autoload_path,
|
499
|
-
file: file,
|
500
|
-
parent: parent,
|
501
|
-
cname: cname
|
502
|
-
)
|
498
|
+
promote_namespace_from_implicit_to_explicit(dir: autoload_path, file: file, cref: cref)
|
503
499
|
end
|
504
|
-
elsif
|
500
|
+
elsif cref.defined?
|
505
501
|
shadowed_files << file
|
506
|
-
log("file #{file} is ignored because #{
|
502
|
+
log("file #{file} is ignored because #{cref.path} is already defined") if logger
|
507
503
|
else
|
508
|
-
define_autoload(
|
504
|
+
define_autoload(cref, file)
|
509
505
|
end
|
510
506
|
end
|
511
507
|
|
512
508
|
# `dir` is the directory that would have autovivified a namespace. `file` is
|
513
509
|
# the file where we've found the namespace is explicitly defined.
|
514
510
|
#
|
515
|
-
# @sig (dir: String, file: String,
|
516
|
-
private def promote_namespace_from_implicit_to_explicit(dir:, file:,
|
511
|
+
# @sig (dir: String, file: String, cref: Zeitwerk::Cref) -> void
|
512
|
+
private def promote_namespace_from_implicit_to_explicit(dir:, file:, cref:)
|
517
513
|
autoloads.delete(dir)
|
518
514
|
Registry.unregister_autoload(dir)
|
519
515
|
|
520
|
-
log("earlier autoload for #{
|
516
|
+
log("earlier autoload for #{cref.path} discarded, it is actually an explicit namespace defined in #{file}") if logger
|
521
517
|
|
522
|
-
define_autoload(
|
523
|
-
register_explicit_namespace(
|
518
|
+
define_autoload(cref, file)
|
519
|
+
register_explicit_namespace(cref.path)
|
524
520
|
end
|
525
521
|
|
526
522
|
# @sig (Module, Symbol, String) -> void
|
527
|
-
private def define_autoload(
|
528
|
-
|
523
|
+
private def define_autoload(cref, abspath)
|
524
|
+
cref.autoload(abspath)
|
529
525
|
|
530
526
|
if logger
|
531
527
|
if ruby?(abspath)
|
532
|
-
log("autoload set for #{
|
528
|
+
log("autoload set for #{cref.path}, to be loaded from #{abspath}")
|
533
529
|
else
|
534
|
-
log("autoload set for #{
|
530
|
+
log("autoload set for #{cref.path}, to be autovivified from #{abspath}")
|
535
531
|
end
|
536
532
|
end
|
537
533
|
|
538
|
-
autoloads[abspath] =
|
534
|
+
autoloads[abspath] = cref
|
539
535
|
Registry.register_autoload(self, abspath)
|
540
536
|
|
541
537
|
# See why in the documentation of Zeitwerk::Registry.inceptions.
|
542
|
-
unless
|
543
|
-
Registry.register_inception(
|
538
|
+
unless cref.autoload?
|
539
|
+
Registry.register_inception(cref.path, abspath, self)
|
544
540
|
end
|
545
541
|
end
|
546
542
|
|
547
543
|
# @sig (Module, Symbol) -> String?
|
548
|
-
private def autoload_path_set_by_me_for?(
|
549
|
-
if autoload_path =
|
544
|
+
private def autoload_path_set_by_me_for?(cref)
|
545
|
+
if autoload_path = cref.autoload?
|
550
546
|
autoload_path if autoloads.key?(autoload_path)
|
551
547
|
else
|
552
|
-
Registry.inception?(
|
548
|
+
Registry.inception?(cref.path)
|
553
549
|
end
|
554
550
|
end
|
555
551
|
|
@@ -590,21 +586,21 @@ module Zeitwerk
|
|
590
586
|
end
|
591
587
|
|
592
588
|
# @sig (Module, Symbol) -> void
|
593
|
-
private def unload_autoload(
|
594
|
-
|
595
|
-
log("autoload for #{
|
589
|
+
private def unload_autoload(cref)
|
590
|
+
cref.remove
|
591
|
+
log("autoload for #{cref.path} removed") if logger
|
596
592
|
end
|
597
593
|
|
598
594
|
# @sig (Module, Symbol) -> void
|
599
|
-
private def unload_cref(
|
595
|
+
private def unload_cref(cref)
|
600
596
|
# Let's optimistically remove_const. The way we use it, this is going to
|
601
597
|
# succeed always if all is good.
|
602
|
-
|
598
|
+
cref.remove
|
603
599
|
rescue ::NameError
|
604
600
|
# There are a few edge scenarios in which this may happen. If the constant
|
605
601
|
# is gone, that is OK, anyway.
|
606
602
|
else
|
607
|
-
log("#{
|
603
|
+
log("#{cref.path} unloaded") if logger
|
608
604
|
end
|
609
605
|
end
|
610
606
|
end
|
data/lib/zeitwerk/version.rb
CHANGED
data/lib/zeitwerk.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zeitwerk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.6.
|
4
|
+
version: 2.6.16
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Xavier Noria
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-06-15 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |2
|
14
14
|
Zeitwerk implements constant autoloading with Ruby semantics. Each gem
|
@@ -23,6 +23,7 @@ files:
|
|
23
23
|
- MIT-LICENSE
|
24
24
|
- README.md
|
25
25
|
- lib/zeitwerk.rb
|
26
|
+
- lib/zeitwerk/cref.rb
|
26
27
|
- lib/zeitwerk/error.rb
|
27
28
|
- lib/zeitwerk/explicit_namespace.rb
|
28
29
|
- lib/zeitwerk/gem_inflector.rb
|
@@ -62,7 +63,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
62
63
|
- !ruby/object:Gem::Version
|
63
64
|
version: '0'
|
64
65
|
requirements: []
|
65
|
-
rubygems_version: 3.5.
|
66
|
+
rubygems_version: 3.5.10
|
66
67
|
signing_key:
|
67
68
|
specification_version: 4
|
68
69
|
summary: Efficient and thread-safe constant autoloader
|