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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8177bcca0fd5895bbe28b19dc5fd04a810e2905f21f33924786a33a317c96207
4
- data.tar.gz: 7e441521285fe28230dadfb4c5c9d40564e376dd651ddae043190c5fdd3ee526
3
+ metadata.gz: 4b69678cbbd525cff55aa4cd08d1f3a785d69cac3e851e3cc2a168ef029163a3
4
+ data.tar.gz: 9da1ded3c41f766feee609adedc9706d4efb4cfd3701c6944f0e781986d578ef
5
5
  SHA512:
6
- metadata.gz: 57e0e401c952a13d1b96a8993bbee930132f2b63252ff7cd6646ceeeb5a3de886d1c36a8cdbc06e9add3e16e76bacd08cc8e32b58289fa01e9eabea4dad25581
7
- data.tar.gz: e56116c8325ab38f751b8497f8270544543e950f92624c755b5d3d7bb296b48ce4afa668e1b4daae546561ddfa344fd9c650c7114c9cd2c637a514f0ebd38c98
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 explictly if you want it ignored too.
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 = autoloads.delete(file)
12
- cpath = cpath(*cref)
11
+ cref = autoloads.delete(file)
13
12
 
14
13
  Zeitwerk::Registry.unregister_autoload(file)
15
14
 
16
- if cdef?(*cref)
17
- log("constant #{cpath} loaded from file #{file}") if logger
18
- to_unload[cpath] = [file, cref] if reloading_enabled?
19
- run_on_load_callbacks(cpath, cget(*cref), file) unless on_load_callbacks.empty?
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 #{cpath}, but didn't"
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
- crem(*cref)
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[cpath] = [file, cref] if reloading_enabled?
30
+ to_unload[cref.path] = [file, cref] if reloading_enabled?
32
31
 
33
- raise Zeitwerk::NameError.new(msg, cref.last)
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
- autovivified_module = cref[0].const_set(cref[1], Module.new)
57
- cpath = autovivified_module.name
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(autovivified_module)
67
+ on_namespace_loaded(implicit_namespace)
69
68
 
70
- run_on_load_callbacks(cpath, autovivified_module, dir) unless on_load_callbacks.empty?
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 cdef?(namespace, cname)
65
- namespace = cget(namespace, cname)
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 = cget(namespace, cname)
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
- cget(namespace, base_cname)
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
- until queue.empty?
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
- cget(*cref)
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, cget(namespace, cname)]
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
- next if !has_at_least_one_ruby_file?(abspath)
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
- # --- Constants ---------------------------------------------------------------------------------
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
@@ -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 parent class or module and constant
26
- # name.
25
+ # executed--- to their corresponding Zeitwerk::Cref object.
27
26
  #
28
- # "/Users/fxn/blog/app/models/user.rb" => [Object, :User],
29
- # "/Users/fxn/blog/app/models/hotel/pricing.rb" => [Hotel, :Pricing]
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, [Module, Symbol]]
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" => [".../admin/role.rb", [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
- # pair [Module, Symbol] is used to remove_const the constant from the class
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, [Module, Symbol]]]
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, (parent, cname)|
158
- if parent.autoload?(cname)
159
- unload_autoload(parent, cname)
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(parent, cname)
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, (parent, cname))|
170
+ to_unload.each do |cpath, (abspath, cref)|
170
171
  unless on_unload_callbacks.empty?
171
172
  begin
172
- value = cget(parent, cname)
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(parent, cname)
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
- until queue.empty?
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
- autoload_file(parent, cname_for(basename, abspath), abspath)
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
- autoload_subdir(parent, cname_for(basename, abspath), abspath)
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(parent, cname, subdir)
461
- if autoload_path = autoload_path_set_by_me_for?(parent, cname)
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(cpath)
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[cpath] << subdir
477
- elsif !cdef?(parent, cname)
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[cpath(parent, cname)] << subdir
480
- define_autoload(parent, cname, subdir)
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 #{cpath(parent, cname)} already exists, descending into #{subdir}") if logger
485
- define_autoloads_for_dir(subdir, cget(parent, cname))
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(parent, cname, file)
491
- if autoload_path = strict_autoload_path(parent, cname) || Registry.inception?(cpath(parent, cname))
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 cdef?(parent, cname)
500
+ elsif cref.defined?
505
501
  shadowed_files << file
506
- log("file #{file} is ignored because #{cpath(parent, cname)} is already defined") if logger
502
+ log("file #{file} is ignored because #{cref.path} is already defined") if logger
507
503
  else
508
- define_autoload(parent, cname, file)
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, parent: Module, cname: Symbol) -> void
516
- private def promote_namespace_from_implicit_to_explicit(dir:, file:, parent:, cname:)
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 #{cpath(parent, cname)} discarded, it is actually an explicit namespace defined in #{file}") if logger
516
+ log("earlier autoload for #{cref.path} discarded, it is actually an explicit namespace defined in #{file}") if logger
521
517
 
522
- define_autoload(parent, cname, file)
523
- register_explicit_namespace(cpath(parent, cname))
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(parent, cname, abspath)
528
- parent.autoload(cname, abspath)
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 #{cpath(parent, cname)}, to be loaded from #{abspath}")
528
+ log("autoload set for #{cref.path}, to be loaded from #{abspath}")
533
529
  else
534
- log("autoload set for #{cpath(parent, cname)}, to be autovivified from #{abspath}")
530
+ log("autoload set for #{cref.path}, to be autovivified from #{abspath}")
535
531
  end
536
532
  end
537
533
 
538
- autoloads[abspath] = [parent, cname]
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 parent.autoload?(cname)
543
- Registry.register_inception(cpath(parent, cname), abspath, self)
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?(parent, cname)
549
- if autoload_path = strict_autoload_path(parent, cname)
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?(cpath(parent, cname))
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(parent, cname)
594
- crem(parent, cname)
595
- log("autoload for #{cpath(parent, cname)} removed") if logger
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(parent, cname)
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
- crem(parent, cname)
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("#{cpath(parent, cname)} unloaded") if logger
603
+ log("#{cref.path} unloaded") if logger
608
604
  end
609
605
  end
610
606
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Zeitwerk
4
- VERSION = "2.6.15"
4
+ VERSION = "2.6.16"
5
5
  end
data/lib/zeitwerk.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  module Zeitwerk
4
4
  require_relative "zeitwerk/real_mod_name"
5
5
  require_relative "zeitwerk/internal"
6
+ require_relative "zeitwerk/cref"
6
7
  require_relative "zeitwerk/loader"
7
8
  require_relative "zeitwerk/gem_loader"
8
9
  require_relative "zeitwerk/registry"
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.15
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-05-26 00:00:00.000000000 Z
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.7
66
+ rubygems_version: 3.5.10
66
67
  signing_key:
67
68
  specification_version: 4
68
69
  summary: Efficient and thread-safe constant autoloader